xref: /haiku/src/add-ons/kernel/drivers/bus/scsi/scsi_raw.c (revision 079eccf655ba39812b421ae1b87a727d41b50354)
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 if (cmd->data_length)
88 		request->flags |= SCSI_DIR_OUT;
89 	else
90 		request->flags |= SCSI_DIR_NONE;
91 
92 	request->data = cmd->data;
93 	request->sg_list = NULL;
94 	request->data_len = cmd->data_length;
95 	request->sort = -1;
96 	request->timeout = cmd->timeout;
97 
98 	memcpy(request->cdb, cmd->command, SCSI_MAX_CDB_SIZE);
99 	request->cdb_len = cmd->command_length;
100 
101 	device->scsi->sync_io(request);
102 
103 	// TBD: should we call standard error handler here, or may the
104 	// actions done there (like starting the unit) confuse the application?
105 
106 	cmd->cam_status = request->subsys_status;
107 	cmd->scsi_status = request->device_status;
108 
109 	if ((request->subsys_status & SCSI_AUTOSNS_VALID) != 0 && cmd->sense_data) {
110 		memcpy(cmd->sense_data, request->sense,
111 			min((int32)cmd->sense_data_length, SCSI_MAX_SENSE_SIZE - request->sense_resid));
112 	}
113 
114 	if ((cmd->flags & B_RAW_DEVICE_REPORT_RESIDUAL) != 0) {
115 		// this is a bit strange, see Be's sample code where I pinched this from;
116 		// normally, residual means "number of unused bytes left"
117 		// but here, we have to return "number of used bytes", which is the opposite
118 		cmd->data_length = cmd->data_length - request->data_resid;
119 		cmd->sense_data_length = SCSI_MAX_SENSE_SIZE - request->sense_resid;
120 	}
121 
122 	device->scsi->free_ccb(request);
123 	return B_OK;
124 }
125 
126 
127 static status_t
128 raw_ioctl(raw_device_info *device, int op, void *buffer, size_t length)
129 {
130 	status_t res;
131 
132 	switch (op) {
133 		case B_RAW_DEVICE_COMMAND:
134 			res = raw_command(device, buffer);
135 			break;
136 
137 		default:
138 			res = B_DEV_INVALID_IOCTL;
139 	}
140 
141 	SHOW_FLOW(4, "%x: %s", op, strerror(res));
142 
143 	return res;
144 }
145 
146 
147 static status_t
148 raw_init_device(device_node_handle node, void *user_cookie, void **cookie)
149 {
150 	raw_device_info *device;
151 	status_t res;
152 
153 	SHOW_FLOW0(3, "");
154 
155 	device = (raw_device_info *)calloc(1, sizeof(*device));
156 	if (device == NULL)
157 		return B_NO_MEMORY;
158 
159 	device->node = node;
160 
161 	// register it everywhere
162 	res = pnp->init_driver(pnp->get_parent(node), NULL,
163 			(driver_module_info **)&device->scsi, (void **)&device->scsi_device);
164 	if (res != B_OK)
165 		goto err;
166 
167 	SHOW_FLOW0(3, "done");
168 
169 	*cookie = device;
170 	return B_OK;
171 
172 err:
173 	free(device);
174 	return res;
175 }
176 
177 
178 static status_t
179 raw_uninit_device(raw_device_info *device)
180 {
181 	pnp->uninit_driver(pnp->get_parent(device->node));
182 	free(device);
183 
184 	return B_OK;
185 }
186 
187 
188 /**	called whenever a new SCSI device was added to system;
189  *	we register a devfs entry for every device
190  */
191 
192 static status_t
193 raw_device_added(device_node_handle node)
194 {
195 	uint8 path_id, target_id, target_lun;
196 	char name[100];
197 
198 	SHOW_FLOW0(3, "");
199 
200 	// compose name
201 	if (pnp->get_attr_uint8(node, SCSI_BUS_PATH_ID_ITEM, &path_id, true) != B_OK
202 		|| pnp->get_attr_uint8(node, SCSI_DEVICE_TARGET_ID_ITEM, &target_id, true) != B_OK
203 		|| pnp->get_attr_uint8(node, SCSI_DEVICE_TARGET_LUN_ITEM, &target_lun, true) != B_OK)
204 		return B_ERROR;
205 
206 	sprintf(name, "bus/scsi/%d/%d/%d/raw",
207 		path_id, target_id, target_lun);
208 
209 	SHOW_FLOW(3, "name=%s", name);
210 
211 	// ready to register
212 	{
213 		device_attr attrs[] = {
214 			{ B_DRIVER_MODULE, B_STRING_TYPE, { string: SCSI_RAW_MODULE_NAME }},
215 
216 			// default connection is used by peripheral drivers, and as we don't
217 			// want to kick them out, we use concurrent "raw" connection
218 			// (btw: this shows nicely that something goes wrong: one device
219 			// and two drivers means begging for trouble)
220 			{ PNP_DRIVER_CONNECTION, B_STRING_TYPE, { string: "raw" }},
221 
222 			// we want devfs on top of us (who wouldn't?)
223 			{ B_DRIVER_FIXED_CHILD, B_STRING_TYPE, { string: PNP_DEVFS_MODULE_NAME }},
224 			// tell which name we want to have in devfs
225 			{ PNP_DEVFS_FILENAME, B_STRING_TYPE, { string: name }},
226 			{ NULL }
227 		};
228 
229 		return pnp->register_device(node, attrs, NULL, &node);
230 	}
231 }
232 
233 
234 static status_t
235 std_ops(int32 op, ...)
236 {
237 	switch (op) {
238 		case B_MODULE_INIT:
239 		case B_MODULE_UNINIT:
240 			return B_OK;
241 
242 		default:
243 			return B_ERROR;
244 	}
245 }
246 
247 
248 module_dependency module_dependencies[] = {
249 	{ B_DEVICE_MANAGER_MODULE_NAME, (module_info **)&pnp },
250 	{}
251 };
252 
253 pnp_devfs_driver_info scsi_raw_module = {
254 	{
255 		{
256 			SCSI_RAW_MODULE_NAME,
257 			0,
258 			std_ops
259 		},
260 
261 		NULL,
262 		raw_device_added,
263 		raw_init_device,
264 		(status_t (*) (void *))raw_uninit_device,
265 		NULL
266 	},
267 
268 	(status_t (*)(void *, uint32, void **)) 		&raw_open,
269 	raw_close,
270 	raw_free,
271 	(status_t (*)(void *, uint32, void *, size_t))	&raw_ioctl,
272 
273 	raw_read,
274 	raw_write,
275 
276 	NULL,
277 	NULL,
278 
279 	NULL,
280 	NULL
281 };
282 
283 module_info *modules[] = {
284 	(module_info *)&scsi_raw_module,
285 	NULL
286 };
287