xref: /haiku/src/add-ons/kernel/drivers/bus/scsi/scsi_raw.c (revision 1d9d47fc72028bb71b5f232a877231e59cfe2438)
1 /*
2  * Copyright 2002/03, Thomas Kurschel. All rights reserved.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 /*
7 	Part of Open SCSI raw driver.
8 
9 	We don't support particular file handles, instead we use
10 	file handle = device handle.
11 */
12 
13 
14 #include "scsi_raw.h"
15 #include <string.h>
16 #include <scsi.h>
17 #include <malloc.h>
18 #include <pnp_devfs.h>
19 #include <stdio.h>
20 
21 
22 device_manager_info *pnp;
23 
24 
25 static status_t
26 raw_open(void *device_cookie, uint32 flags, void **handle_cookie)
27 {
28 	*handle_cookie = device_cookie;
29 	return B_OK;
30 }
31 
32 
33 static status_t
34 raw_close(void *cookie)
35 {
36 	return B_OK;
37 }
38 
39 
40 static status_t
41 raw_free(void *cookie)
42 {
43 	return B_OK;
44 }
45 
46 
47 #if 0
48 static status_t
49 raw_control(void *cookie, uint32 op, void *data, size_t len)
50 {
51 	return B_OK;
52 }
53 #endif
54 
55 
56 static status_t
57 raw_read(void *cookie, off_t position, void *data, size_t *numBytes)
58 {
59 	return B_ERROR;
60 }
61 
62 
63 static status_t
64 raw_write(void *cookie, off_t position, const void *data, size_t *numBytes)
65 {
66 	return B_ERROR;
67 }
68 
69 
70 /** !!! keep this in sync with scsi_periph module !!! */
71 
72 static status_t
73 raw_command(raw_device_info *device, raw_device_command *cmd)
74 {
75 	scsi_ccb *request;
76 
77 	SHOW_FLOW0(3, "");
78 
79 	request = device->scsi->alloc_ccb(device->scsi_device);
80 	if (request == NULL)
81 		return B_NO_MEMORY;
82 
83 	request->flags = 0;
84 
85 	if (cmd->flags & B_RAW_DEVICE_DATA_IN)
86 		request->flags |= SCSI_DIR_IN;
87 	else
88 		request->flags |= SCSI_DIR_OUT;
89 
90 	request->data = cmd->data;
91 	request->sg_list = NULL;
92 	request->data_len = cmd->data_length;
93 	request->sort = -1;
94 	request->timeout = cmd->timeout;
95 
96 	memcpy(request->cdb, cmd->command, SCSI_MAX_CDB_SIZE);
97 	request->cdb_len = cmd->command_length;
98 
99 	device->scsi->sync_io(request);
100 
101 	// TBD: should we call standard error handler here, or may the
102 	// actions done there (like starting the unit) confuse the application?
103 
104 	cmd->cam_status = request->subsys_status;
105 	cmd->scsi_status = request->device_status;
106 
107 	if ((request->subsys_status & SCSI_AUTOSNS_VALID) != 0 && cmd->sense_data) {
108 		memcpy(cmd->sense_data, request->sense,
109 			min((int32)cmd->sense_data_length, SCSI_MAX_SENSE_SIZE - request->sense_resid));
110 	}
111 
112 	if ((cmd->flags & B_RAW_DEVICE_REPORT_RESIDUAL) != 0) {
113 		// this is a bit strange, see Be's sample code where I pinched this from;
114 		// normally, residual means "number of unused bytes left"
115 		// but here, we have to return "number of used bytes", which is the opposite
116 		cmd->data_length = cmd->data_length - request->data_resid;
117 		cmd->sense_data_length = SCSI_MAX_SENSE_SIZE - request->sense_resid;
118 	}
119 
120 	device->scsi->free_ccb(request);
121 	return B_OK;
122 }
123 
124 
125 static status_t
126 raw_ioctl(raw_device_info *device, int op, void *buffer, size_t length)
127 {
128 	status_t res;
129 
130 	switch (op) {
131 		case B_RAW_DEVICE_COMMAND:
132 			res = raw_command(device, buffer);
133 			break;
134 
135 		default:
136 			res = B_DEV_INVALID_IOCTL;
137 	}
138 
139 	SHOW_FLOW(4, "%x: %s", op, strerror(res));
140 
141 	return res;
142 }
143 
144 
145 static status_t
146 raw_init_device(device_node_handle node, void *user_cookie, void **cookie)
147 {
148 	raw_device_info *device;
149 	status_t res;
150 
151 	SHOW_FLOW0(3, "");
152 
153 	device = (raw_device_info *)calloc(1, sizeof(*device));
154 	if (device == NULL)
155 		return B_NO_MEMORY;
156 
157 	device->node = node;
158 
159 	// register it everywhere
160 	res = pnp->init_driver(pnp->get_parent(node), NULL,
161 			(driver_module_info **)&device->scsi, (void **)&device->scsi_device);
162 	if (res != B_OK)
163 		goto err;
164 
165 	SHOW_FLOW0(3, "done");
166 
167 	*cookie = device;
168 	return B_OK;
169 
170 err:
171 	free(device);
172 	return res;
173 }
174 
175 
176 static status_t
177 raw_uninit_device(raw_device_info *device)
178 {
179 	pnp->uninit_driver(pnp->get_parent(device->node));
180 	free(device);
181 
182 	return B_OK;
183 }
184 
185 
186 /**	called whenever a new SCSI device was added to system;
187  *	we register a devfs entry for every device
188  */
189 
190 static status_t
191 raw_device_added(device_node_handle node)
192 {
193 	uint8 path_id, target_id, target_lun;
194 	char name[100];
195 
196 	SHOW_FLOW0(3, "");
197 
198 	// compose name
199 	if (pnp->get_attr_uint8(node, SCSI_BUS_PATH_ID_ITEM, &path_id, true) != B_OK
200 		|| pnp->get_attr_uint8(node, SCSI_DEVICE_TARGET_ID_ITEM, &target_id, true) != B_OK
201 		|| pnp->get_attr_uint8(node, SCSI_DEVICE_TARGET_LUN_ITEM, &target_lun, true) != B_OK)
202 		return B_ERROR;
203 
204 	sprintf(name, "bus/scsi/%d/%d/%d/raw",
205 		path_id, target_id, target_lun);
206 
207 	SHOW_FLOW(3, "name=%s", name);
208 
209 	// ready to register
210 	{
211 		device_attr attrs[] = {
212 			{ B_DRIVER_MODULE, B_STRING_TYPE, { string: SCSI_RAW_MODULE_NAME }},
213 
214 			// default connection is used by peripheral drivers, and as we don't
215 			// want to kick them out, we use concurrent "raw" connection
216 			// (btw: this shows nicely that something goes wrong: one device
217 			// and two drivers means begging for trouble)
218 			{ PNP_DRIVER_CONNECTION, B_STRING_TYPE, { string: "raw" }},
219 
220 			// we want devfs on top of us (who wouldn't?)
221 			{ B_DRIVER_FIXED_CHILD, B_STRING_TYPE, { string: PNP_DEVFS_MODULE_NAME }},
222 			// tell which name we want to have in devfs
223 			{ PNP_DEVFS_FILENAME, B_STRING_TYPE, { string: name }},
224 			{ NULL }
225 		};
226 
227 		return pnp->register_device(node, attrs, NULL, &node);
228 	}
229 }
230 
231 
232 static status_t
233 std_ops(int32 op, ...)
234 {
235 	switch (op) {
236 		case B_MODULE_INIT:
237 		case B_MODULE_UNINIT:
238 			return B_OK;
239 
240 		default:
241 			return B_ERROR;
242 	}
243 }
244 
245 
246 module_dependency module_dependencies[] = {
247 	{ B_DEVICE_MANAGER_MODULE_NAME, (module_info **)&pnp },
248 	{}
249 };
250 
251 pnp_devfs_driver_info scsi_raw_module = {
252 	{
253 		{
254 			SCSI_RAW_MODULE_NAME,
255 			0,
256 			std_ops
257 		},
258 
259 		NULL,
260 		raw_device_added,
261 		raw_init_device,
262 		(status_t (*) (void *))raw_uninit_device,
263 		NULL
264 	},
265 
266 	(status_t (*)(void *, uint32, void **)) 		&raw_open,
267 	raw_close,
268 	raw_free,
269 	(status_t (*)(void *, uint32, void *, size_t))	&raw_ioctl,
270 
271 	raw_read,
272 	raw_write,
273 
274 	NULL,
275 	NULL,
276 
277 	NULL,
278 	NULL
279 };
280 
281 module_info *modules[] = {
282 	(module_info *)&scsi_raw_module,
283 	NULL
284 };
285