xref: /haiku/src/add-ons/kernel/busses/scsi/usb/usb_scsi.c (revision 57bc65034a7781d7bb53a48f94d692346b641da1)
1 /**
2  *
3  * TODO: description
4  *
5  * This file is a part of USB SCSI CAM for Haiku.
6  * May be used under terms of the MIT License
7  *
8  * Author(s):
9  * 	Siarzhuk Zharski <imker@gmx.li>
10  *
11  *
12  */
13 /** Main part of USB SIM implementation */
14 
15 #include "usb_scsi.h"
16 
17 #include <KernelExport.h>
18 #include <module.h>
19 #include <malloc.h>
20 #include <strings.h>
21 #include <stdio.h>
22 #include <device_manager.h>
23 #include <bus/SCSI.h>
24 #include "device_info.h"
25 #include "settings.h"
26 #include "transform_procs.h"
27 #include "tracing.h"
28 #include "scsi_commands.h"
29 #include "proto_common.h"
30 #include "proto_bulk.h"
31 #include "proto_cbi.h"
32 #include "usb_defs.h"
33 #include "fake_device.h"
34 #include "sg_buffer.h"
35 
36 
37 #if 0
38 status_t device_added(const usb_device device, void **cookie);
39 
40 status_t device_removed(void *cookie);
41 
42 static long sim_action(CCB_HEADER *ccbh);
43 static long sim_init();
44 
45 #define SIM_VERSION 1
46 #define HBA_VERSION 1
47 
48 //#define ROUNDUP(size, seg) (((size) + (seg) - 1) & ~((seg) - 1))
49 
50 #define INQ_VENDOR_LEN		0x08
51 #define INQ_PRODUCT_LEN		0x10
52 #define INQ_REVISION_LEN	0x04
53 
54 #define TRANS_TIMEOUT		7500000
55 
56 static long path_id		= -1;
57 static int32 load_count	= 0;
58 
59 static char sim_vendor_name[]	= "Haiku";		/* who wrote this driver */
60 static char hba_vendor_name[]	= "USB";		/* who made the hardware */
61 static char controller_family[]	= "USB SCSI";	/* what family of products */
62 
63 struct usb_support_descriptor supported_devices[] = {
64 	{0, 0, 0, 0, 0}
65 };
66 
67 usb_device_info *usb_devices[MAX_DEVICES_COUNT];
68 /* main devices table locking semaphore */
69 sem_id usb_serial_lock = -1;
70 
71 usb_module_info *usb;
72 static cam_for_sim_module_info *cam;
73 
74 struct usb_notify_hooks notify_hooks = {
75 	device_added,
76 	device_removed
77 };
78 
79 /* function prototupes */
80 static status_t get_interface_properties(usb_interface_info *uii, uint32 *pproperties);
81 static status_t load_vendor_module(char **path, const char *path_mask, const char *prop, module_info **mi);
82 static status_t setup_transport_modules(usb_device_info *udi, usb_device_settings *uds);
83 static status_t setup_endpoints(usb_interface_info *uii, usb_device_info *udi);
84 static status_t allocate_resources(usb_device_info *udi);
85 static void 	release_resources(usb_device_info *udi);
86 static status_t xpt_scsi_io(CCB_SCSIIO *ccbio);
87 static status_t xpt_path_inquiry(CCB_PATHINQ *ccbp);
88 static status_t xpt_extended_path_inquiry(CCB_EXTENDED_PATHINQ *ccbep);
89 
90 /**
91 	\fn:match_device
92 	\param device:???
93 	\param uii:???
94 	\param pproperties:???
95 	\return:B_BAD_TYPE , B_ENTRY_NOT_FOUND, B_OK
96 
97 	??
98 */
99 status_t get_interface_properties(usb_interface_info *uii, uint32 *pproperties)
100 {
101 	status_t status = B_BAD_TYPE;
102 	if(uii->descr->interface_class == USB_DEV_CLASS_MASS){
103 		status = B_OK;
104 		switch(uii->descr->interface_subclass){
105 		case USB_DEV_SUBCLASS_RBC:		*pproperties |= CMDSET_RBC; break;
106 		case USB_DEV_SUBCLASS_UFI:		*pproperties |= CMDSET_UFI;	break;
107 		case USB_DEV_SUBCLASS_SFF8020I:
108 		case USB_DEV_SUBCLASS_SFF8070I: *pproperties |= CMDSET_ATAPI;	break;
109 		case USB_DEV_SUBCLASS_SCSI:		*pproperties |= CMDSET_SCSI;	break;
110 		case USB_DEV_SUBCLASS_QIC157:	*pproperties |= CMDSET_QIC157;	break;
111 		default:
112 			TRACE_ALWAYS("get_interface_properties:unknown USB subclass:%02x\n",
113 									 uii->descr->interface_subclass);
114 			/*status = B_ENTRY_NOT_FOUND;*/ /*B_BAD_TYPE assumed*/
115 			break;
116 		}
117 		switch(uii->descr->interface_protocol){
118 		case USB_DEV_PROTOCOL_CBI:	*pproperties |= PROTO_CBI;	break;
119 		case USB_DEV_PROTOCOL_CB:	*pproperties |= PROTO_CB;	break;
120 		case USB_DEV_PROTOCOL_BULK:	*pproperties |= PROTO_BULK_ONLY; break;
121 		default:
122 			TRACE_ALWAYS("get_interface_properties:unknown USB protocol:%02x\n",
123 									 uii->descr->interface_protocol);
124 			/*status = B_ENTRY_NOT_FOUND;*/ /*B_BAD_TYPE assumed*/
125 			break;
126 		}
127 		if(status == B_OK){
128 			TRACE("get_interface_properties: standard properties:%08x\n", *pproperties);
129 		}
130 	}
131 	return status;
132 }
133 /**
134 	\fn:
135 
136 */
137 status_t load_vendor_module(char **path, const char *path_mask,
138 							const char *prop, module_info **mi)
139 {
140 	status_t status = B_NO_MEMORY;
141 	int path_len = strlen(path_mask) + strlen(prop);
142 	*path = malloc(path_len);
143 	if(*path){
144 		sprintf(*path, path_mask, prop);
145 		status = get_module(*path, mi);
146 		if(status != B_OK)
147 			TRACE_ALWAYS("load_vendor_module:get_module(%s) failed:%08x\n", *path, status);
148 	} else {
149 		TRACE_ALWAYS("load_vendor_module:couldn't allocate %d bytes\n", path_len);
150 	}
151 	return status;
152 }
153 /**
154 	\fn:
155 
156 */
157 status_t setup_transport_modules(usb_device_info *udi,
158 									 usb_device_settings *uds)
159 {
160 	status_t status = B_OK;
161 	switch(PROTO(udi->properties)){
162 	case PROTO_BULK_ONLY:
163 		udi->protocol_m = &bulk_only_protocol_m;
164 		break;
165 	case PROTO_CB:
166 	case PROTO_CBI:
167 		udi->protocol_m = &cbi_protocol_m;
168 		break;
169 	case PROTO_VENDOR:{
170 			status = load_vendor_module(&udi->protocol_m_path,
171 										PROTOCOL_MODULE_MASK,
172 										uds->vendor_protocol,
173 										(module_info**)&udi->protocol_m);
174 		}break;
175 	default:
176 		TRACE_ALWAYS("setup_transport_modules: "
177 					 "transport %02x is not supported\n", PROTO(udi->properties));
178 		status = B_ENTRY_NOT_FOUND;
179 	}
180 	if(status == B_OK){
181 		switch(CMDSET(udi->properties)){
182 		case CMDSET_SCSI:
183 			udi->transform_m = &scsi_transform_m;
184 			break;
185 		case CMDSET_UFI:
186 			udi->transform_m = &ufi_transform_m;
187 			udi->properties |= FIX_FORCE_MS_TO_10; /* always use 10-byte request */
188 			break;
189 		case CMDSET_ATAPI:
190 			udi->transform_m = &atapi_transform_m;
191 			udi->properties |= FIX_FORCE_MS_TO_10; /* always use 10-byte request */
192 			break;
193 		case CMDSET_RBC:
194 			udi->transform_m = &rbc_transform_m;
195 			break;
196 		case CMDSET_QIC157:
197 			udi->transform_m = &qic157_transform_m;
198 			udi->properties |= FIX_FORCE_MS_TO_10; /* always use 10-byte request */
199 			break;
200 		case CMDSET_VENDOR:{
201 				status = load_vendor_module(&udi->transform_m_path,
202 										TRANSFORM_MODULE_MASK,
203 										uds->vendor_commandset,
204 										(module_info**)&udi->transform_m);
205 			}break;
206 		default:
207 			TRACE_ALWAYS("setup_transport_modules: "
208 						 "protocol %02x is not supported\n", CMDSET(udi->properties));
209 			status = B_ENTRY_NOT_FOUND;
210 		}
211 	}
212 	return status;
213 }
214 
215 static void
216 release_transport_modules(usb_device_info *udi)
217 {
218 	if(PROTO(udi->properties) == PROTO_VENDOR && 0 != udi->protocol_m_path){
219 		put_module(udi->protocol_m_path);
220 		udi->protocol_m = 0;
221 		free(udi->protocol_m_path);
222 	}
223 	if(CMDSET(udi->properties) == CMDSET_VENDOR && 0 != udi->transform_m_path){
224 		put_module(udi->transform_m_path);
225 		udi->transform_m = 0;
226 		free(udi->transform_m_path);
227 	}
228 }
229 
230 /**
231 	\fn:
232 */
233 status_t setup_endpoints(usb_interface_info *uii, usb_device_info *udi)
234 {
235 	status_t status = B_OK;
236 	int16 idx = 0;
237 	enum{ epIn = 0, epOut, epIntr, epCount };
238 	size_t epts[epCount] = { -1, -1, -1 };
239 	char	*epnames[epCount] = {"input", "output", "interrupt"};
240 	size_t ep = 0;
241 	for(; ep < uii->endpoint_count; ep++){
242 		usb_endpoint_descriptor *ed = uii->endpoint[ep].descr;
243 		TRACE("try endpoint:%d %x %x %x\n", ep, (int32)ed->attributes, (int32)ed->endpoint_address, uii->endpoint[ep].handle);
244 		if((ed->attributes & USB_EP_ATTR_MASK) == USB_EP_ATTR_BULK){
245 			if((ed->endpoint_address & USB_EP_ADDR_DIR_IN) == USB_EP_ADDR_DIR_IN){
246 				epts[epIn]	= ep;
247 			}else{
248 				epts[epOut] = ep;
249 			}
250 		}else{
251 			if((ed->attributes & USB_EP_ATTR_MASK) == USB_EP_ATTR_INTERRUPT)
252 				epts[epIntr] = ep;
253 		}
254 	}
255 	switch(PROTO(udi->properties)){
256 	case PROTO_CB:
257 	case PROTO_BULK_ONLY:
258 		if(epts[epIntr] == -1)
259 			epts[epIntr] = 0; /* not required for this transports - set it to default*/
260 		break;
261 	case PROTO_CBI:
262 	default:
263 	}
264 	for(idx = 0; idx < epCount; idx++){
265 		if(epts[idx] == -1 && PROTO(udi->properties) != PROTO_VENDOR){
266 			TRACE_ALWAYS("setup_endpoints: required %s endpoint not found. "
267 						 "ignore this interface\n", epnames[idx]);
268 			// DEBUG!!!!!!!!!!
269 			status = B_ERROR;
270 		}
271 	}
272 	if(status == B_OK){
273 		udi->pipe_in	= uii->endpoint[epts[epIn]].handle;
274 		udi->pipe_out	= uii->endpoint[epts[epOut]].handle;
275 		udi->pipe_intr	= uii->endpoint[epts[epIntr]].handle;
276 		//TRACE("setup_endpoints: input:%d output:%d "
277 		//		 "interrupt:%d\n", epts[epIn], epts[epOut], epts[epIntr]);
278 		TRACE("endpoint:%x %x %x\n", udi->pipe_in, udi->pipe_out, udi->pipe_intr);
279 	}
280 	return status;
281 }
282 /**
283 	\fn:create_device_info
284 	\param device:???
285 	\param ppudi:???
286 	\return:???
287 
288 	???
289 */
290 status_t allocate_resources(usb_device_info *udi)
291 {
292 	char name[32];
293 	status_t status = B_NO_MEMORY;
294 	uint16 dev = 0;
295 	acquire_sem(usb_serial_lock);
296 	for(; dev < MAX_DEVICES_COUNT; dev++){
297 		if(!usb_devices[dev])
298 			break;
299 	}
300 	if(dev < MAX_DEVICES_COUNT){
301 		usb_devices[dev] = udi;
302 		udi->lock_sem =
303 		udi->trans_sem = -1;
304 		sprintf(name, "usb_scsi lock_sem:%d", dev);
305 		if((udi->lock_sem = create_sem(0, name)) >= 0){
306 			sprintf(name, "usb_scsi trans_sem:%d", dev);
307 			if((udi->trans_sem = create_sem(0, name))>=0){
308 				udi->dev_num = dev;
309 				release_sem(udi->lock_sem);
310 				status = B_OK;
311 			}else
312 				status = udi->trans_sem;
313 		} else
314 			status = udi->lock_sem;
315 
316 		if(status != B_OK){
317 			TRACE_ALWAYS("allocate_resources:error:%s", strerror(status));
318 			if(udi->lock_sem >= 0)
319 				delete_sem(udi->lock_sem);
320 			if(udi->trans_sem >= 0)
321 				delete_sem(udi->trans_sem);
322 			usb_devices[dev] = NULL;
323 			free(udi);
324 		}
325 	}else{
326 		TRACE_ALWAYS("allocate_resources:reserved devices space exhausted."
327 								 "Unplug unnesesary devices or reconfigure this driver.\n");
328 	}
329 	release_sem(usb_serial_lock);
330 	return status;
331 }
332 /**
333 	\fn:
334 
335 */
336 void release_resources(usb_device_info *udi)
337 {
338 	release_transport_modules(udi);
339 	udi->usb_m = 0;
340 	(*usb->cancel_queued_transfers)(udi->pipe_in);
341 	(*usb->cancel_queued_transfers)(udi->pipe_out);
342 	delete_sem(udi->lock_sem);
343 	delete_sem(udi->trans_sem);
344 	acquire_sem(usb_serial_lock);
345 	usb_devices[udi->dev_num] = NULL;
346 	release_sem(usb_serial_lock);
347 }
348 /**
349 	\fn:device_added
350 	\param device:??
351 	\param cookie:??
352 	\return:??
353 
354 	??
355 */
356 status_t device_added(const usb_device device, void **cookie){
357 	status_t status = B_NO_MEMORY;
358 	const usb_configuration_info *uci = NULL;
359 	uint16 cfg = 0;
360 	bool b_found = false;
361 	bool b_has_extra_settings = false;
362 	const usb_device_descriptor *udd = (*usb->get_device_descriptor)(device);
363 	usb_device_info *udi = (usb_device_info *)malloc(sizeof(usb_device_info));
364 	TRACE("device_added: probing canidate: "
365 		"%04x/%04x %02d/%02d/%02d\n",
366 			udd->vendor_id, udd->product_id,
367 			udd->device_class,
368 			udd->device_subclass,
369 			udd->device_protocol);
370 	if(udi){
371 		status = B_NO_INIT;
372 		while(!b_found && (uci = (*usb->get_nth_configuration)(device, cfg++))){
373 			uint16 itf = 0;
374 			for(; itf < uci->interface_count && !b_found; itf++){
375 				usb_interface_list *ifl = &uci->interface[itf];
376 				uint16 alt = 0;
377 				for(; alt < ifl->alt_count; alt++){
378 					usb_interface_info *uii = &ifl->alt[alt];
379 					usb_device_settings ud_settings;
380 					memset(udi, 0, sizeof(usb_device_info));
381 					memset(&ud_settings, 0, sizeof(usb_device_settings));
382 					udi->device = device;
383 					udi->interface	= itf;
384 					b_has_extra_settings = lookup_device_settings(udd, &ud_settings);
385 					switch(get_interface_properties(uii, &udi->properties)){
386 					case B_BAD_TYPE: /* non-standard USB class*/
387 						if(!b_has_extra_settings){
388 							continue; /* skip to next interface */
389 						} /* no break - fall through */
390 					case B_OK:
391 						if(b_has_extra_settings){
392 							if(PROTO(ud_settings.properties) != PROTO_NONE){
393 								udi->properties &= ~PROTO_MASK;
394 								udi->properties |= PROTO(ud_settings.properties);
395 							}
396 							if(CMDSET(ud_settings.properties) != CMDSET_NONE){
397 								udi->properties &= ~CMDSET_MASK;
398 								udi->properties |= CMDSET(ud_settings.properties);
399 							}
400 							udi->properties |= ud_settings.properties & FIX_MASK;
401 							TRACE("device_added: properties merged:%08x\n", udi->properties);
402 						}
403 						if( B_OK == setup_transport_modules(udi, &ud_settings)){
404 							break;
405 						} /* else - no break - fall through */
406 					default:
407 						continue; /* skip to next interface */
408 					}
409 					if(alt != 0){ /*TODO: are we need this ???*/
410 						if((status = (*usb->set_alt_interface)(device, uii)) != B_OK){
411 							TRACE_ALWAYS("device_added:setting alt interface failed:%s",
412 												strerror(status));
413 							goto Failed;/* Break - is it right?*/
414 						}
415 					}
416 					if((*usb->get_configuration)(device) != uci){
417 						if((status = (*usb->set_configuration)(device, uci)) != B_OK){
418 								TRACE_ALWAYS("device_added:setting configuration failed:%08x uci: %08x\n",
419 											 (*usb->get_configuration)(device), uci);
420 							TRACE_ALWAYS("device_added:setting configuration failed:%s\n",
421 													strerror(status));
422 
423 							goto Failed;/* Break - is it right?*/
424 						}
425 					}
426 					if(B_OK != setup_endpoints(uii, udi)){
427 						continue; /* skip to next interface */
428 					}
429 					if((status = allocate_resources(udi)) == B_OK){
430 						udi->b_trace = b_log_protocol;
431 						udi->trace = usb_scsi_trace;
432 						udi->trace_bytes = usb_scsi_trace_bytes;
433 						udi->trans_timeout = TRANS_TIMEOUT;
434 						udi->usb_m = usb;
435 						udi->not_ready_luns = 0xff; /*assume all LUNs initially not ready */
436 						if((status = (*udi->protocol_m->init)(udi)) == B_OK){
437 							TRACE("device_added[%d]: SUCCESS! Enjoy using!\n", udi->dev_num);
438 							*cookie = udi;
439 							b_found = true; /* we have found something useful - time to go out! */
440 							break;					/* ... now break alternatives iteration.*/
441 						} else {
442 							release_resources(udi);
443 						}
444 					}
445 					/* go to next iteration - check all configurations for possible devices */
446 				}/* for(...) iterate interface alternates*/
447 			}/* for(...) iterate interfaces*/
448 		}/* while(...) iterate configurations */
449 		if(status == B_OK){
450 			(*cam->minfo.rescan)();
451 		} else {
452 			free(udi);
453 		}
454 	} /* if(udi){ */
455 	if(status != B_OK){
456 		TRACE("device_added: probing failed (%s) for: %04x/%04x\n",
457 				strerror(status), udd->vendor_id, udd->product_id);
458 	}
459 Failed:
460 	return status;
461 }
462 /**
463 	\fn:device_removed
464 	\param cookie:???
465 	\return:???
466 
467 	???
468 */
469 status_t device_removed(void *cookie)
470 {
471 	status_t status = B_OK;
472 	usb_device_info *udi = (usb_device_info *)cookie;
473 	acquire_sem(udi->lock_sem); /* wait for possible I/O operation complete */
474 	release_resources(udi);
475 	/* no corresponding call of release_sem(udi->lock_sem);
476 		 - semaphore was deleted in release_resources, any waiting thread
477 		   was failed with BAD_SEM_ID.
478 	*/
479 	TRACE_ALWAYS("device_removed[%d]:All The Best !!!\n", udi->dev_num);
480 	free(udi);
481 	(*cam->minfo.rescan)();
482 	return status;
483 }
484 /**
485 	\fn:sim_init
486 	\return: ???
487 
488 	called on SIM init
489 */
490 static long sim_init(void)
491 {
492 	status_t status = B_OK;
493 	TRACE("sim_init\n");
494 	return status;
495 }
496 
497 /**
498 */
499 static bool
500 pre_check_scsi_io_request(usb_device_info *udi, CCB_SCSIIO *ccbio,
501 												status_t *ret_status)
502 {
503 	int target_id	 = ccbio->cam_ch.cam_target_id;
504 	uint8 target_lun = ccbio->cam_ch.cam_target_lun;
505 	*ret_status 	 = B_OK;
506 	/* handle reserved device and luns entries */
507 	if(b_reservation_on && udi == NULL &&
508 		 target_id < reserved_devices &&
509 		 target_lun < reserved_luns)
510 	{
511 		*ret_status = fake_scsi_io(ccbio);
512 		return false;
513 	}
514 	/* no device for this target | LUN */
515 	if(udi == NULL || target_lun > udi->max_lun){
516 		ccbio->cam_ch.cam_status = CAM_DEV_NOT_THERE;
517 		*ret_status = B_DEV_BAD_DRIVE_NUM;
518 		return false;
519 	}
520 	/* check command length */
521 	if(ccbio->cam_cdb_len != 6	&&
522 		 ccbio->cam_cdb_len != 10 &&
523 		 ccbio->cam_cdb_len != 12)
524 	{
525 		TRACE("Bad SCSI command length:%d.Ignore\n", ccbio->cam_cdb_len);
526 		ccbio->cam_ch.cam_status = CAM_REQ_INVALID;
527 		*ret_status = B_BAD_VALUE;
528 		return false;
529 	}
530 	/* Clean up auto sense buffer.
531 		 To avoid misunderstanding in not ready luns logic detection.*/
532 	if(NULL == ccbio->cam_sense_ptr){
533 		memset(&udi->autosense_data, 0, sizeof(udi->autosense_data));
534 	} else {
535 		memset(ccbio->cam_sense_ptr, 0, ccbio->cam_sense_len);
536 	}
537 	return true;
538 }
539 /**
540 */
541 static bool
542 pre_handle_features(usb_device_info *udi, CCB_SCSIIO *ccbio,
543 					scsi_cmd_generic *command, sg_buffer *sgb,
544 											status_t *ret_status)
545 {
546 	uint8 target_lun = ccbio->cam_ch.cam_target_lun;
547 	*ret_status = B_OK;
548 	udi->trans_timeout = TRANS_TIMEOUT;
549 	switch(command->opcode){
550 	case MODE_SELECT_6:
551 	case MODE_SENSE_6:{
552 		bool b_select = (MODE_SELECT_6 == command->opcode);
553 		const char*cmd_name = b_select ? "MODE_SELECT" : "MODE_SENSE";
554 		if(udi->not_ready_luns & (1 << target_lun)){
555 			TRACE("pre_handle_features:%s_6 bypassed for LUN:%d\n", cmd_name, target_lun);
556 			goto set_REQ_INVALID_and_return;
557 		}
558 		if(HAS_FIXES(udi->properties, FIX_FORCE_MS_TO_10)){
559 			if( B_OK != realloc_sg_buffer(sgb, ccbio->cam_dxfer_len + 4)){ /* TODO: 4 - hardcoded? */
560 				TRACE_ALWAYS("pre_handle_features:error allocating %d bytes for %s_10\n",
561 								 ccbio->cam_dxfer_len + 4, cmd_name);
562 				goto set_REQ_INVALID_and_return;
563 			}
564 			if(b_select){
565 				sg_buffer sgb_sense_6;
566 				/*TODO: implemenet and try refragment_sg_buffer - to check handling of real scatter/gather!!*/
567 				if(B_OK != init_sg_buffer(&sgb_sense_6, ccbio)){
568 					/* In case of error TRACE-ing was already performed in sg_ functions */
569 					goto set_REQ_INVALID_and_return;
570 				}
571 				TRACE_MODE_SENSE_SGB("MODE SELECT 6:", &sgb_sense_6);
572 				if(B_OK != sg_memcpy(sgb, 1, &sgb_sense_6, 0, 3) ||
573 					 B_OK != sg_memcpy(sgb, 7, &sgb_sense_6, 3, 1) ||
574 					 B_OK != sg_memcpy(sgb, 8, &sgb_sense_6, 4, ccbio->cam_dxfer_len - sizeof(scsi_mode_param_header_6)))
575 				{
576 					/* In case of error TRACE-ing was already performed in sg_ functions */
577 					goto set_REQ_INVALID_and_return;
578 				}
579 				TRACE_MODE_SENSE_SGB("MODE SELECT 10:", sgb);
580 			}
581 		} /*else {
582 			if(b_select){ / * trace data if configured in settings * /
583 				TRACE_MODE_SENSE_DATA("MODE_SELECT:", ccbio->cam_data_ptr, ccbio->cam_dxfer_len);
584 			}
585 		}*/
586 	}break;
587 	case INQUIRY: /* fake INQUIRY request */
588 		if(HAS_FIXES(udi->properties, FIX_NO_INQUIRY)){
589 			fake_inquiry_request(udi, ccbio);
590 			goto set_REQ_CMP_and_return;
591 		} break;
592 	case TEST_UNIT_READY: /* fake INQUIRY request */
593 		if(HAS_FIXES(udi->properties, FIX_NO_TEST_UNIT)){
594 			goto set_REQ_CMP_and_return;
595 		} break;
596 	case PREVENT_ALLOW_MEDIA_REMOVAL: /* fake PREVENT_ALLOW_MEDIA_REMOVAL request */
597 		if(HAS_FIXES(udi->properties, FIX_NO_PREVENT_MEDIA)){
598 			goto set_REQ_CMP_and_return;
599 		} break;
600 	case FORMAT_UNIT:
601 		udi->trans_timeout = B_INFINITE_TIMEOUT;
602 		break;
603 	default: break;
604 	}
605 	return true;
606 
607 set_REQ_CMP_and_return:
608 	ccbio->cam_ch.cam_status = CAM_REQ_CMP;
609 	return false;//*ret_status = B_OK;
610 
611 set_REQ_INVALID_and_return:
612 	ccbio->cam_ch.cam_status = CAM_REQ_INVALID;
613 	*ret_status = B_BAD_VALUE;
614 	return false;
615 }
616 /**
617 */
618 static bool
619 post_handle_features(usb_device_info *udi, CCB_SCSIIO *ccbio,
620 					scsi_cmd_generic *command, sg_buffer *sgb,
621 												status_t *ret_status)
622 {
623 	bool b_cmd_ok = (ccbio->cam_ch.cam_status == CAM_REQ_CMP);
624 	uint8 target_lun = ccbio->cam_ch.cam_target_lun;
625 	switch(command->opcode){
626 	case READ_6:
627 	case WRITE_6:
628 #if 0
629 /* Disabled - single problem can switch to 6-bytes mode. If device doesn't
630 	 support 6-bytes command all goes totally wrong. That's bad. */
631 		if(!b_cmd_ok && !HAS_FEATURES(udi->descr.properties, PROP_FORCE_RW_TO_6)){
632 			TRACE("post_handle_features:READ(10)/WRITE(10) failed - retry 6-byte one\n");
633 			udi->descr.properties |= PROP_FORCE_RW_TO_6;
634 			ccbio->cam_scsi_status = SCSI_STATUS_OK; /* clear the scsi_status. */
635 			ccbio->cam_ch.cam_status = CAM_REQ_INPROG; /* set status in progress again. */
636 			b_retry = true; /* inform caller about retry */
637 		}
638 #endif
639 		break;
640 	case MODE_SENSE_6:
641 		if(!b_cmd_ok && !HAS_FIXES(udi->properties, FIX_FORCE_MS_TO_10)){
642 			TRACE("post_handle_features:MODE SENSE(6) failed - retry 10-byte one\n");
643 			udi->properties |= FIX_FORCE_MS_TO_10;
644 			ccbio->cam_scsi_status = SCSI_STATUS_OK; /* clear the scsi_status. */
645 			ccbio->cam_ch.cam_status = CAM_REQ_INPROG; /* set status in progress again. */
646 			return true; /* inform caller about retry */
647 		}	/* no break, - fallthrough! */
648 	case MODE_SELECT_6:{
649 		if(MODE_SENSE_6 == command->opcode){
650 			sg_buffer sgb_sense_6;
651 			if(B_OK != init_sg_buffer(&sgb_sense_6, ccbio)){
652 				TRACE_ALWAYS("post_hanlde_features: initialize sgb failed\n");
653 				goto set_REQ_INVALID_and_return;
654 			}
655 			/* convert sense information from 10-byte request result to 6-byte one */
656 			if(HAS_FIXES(udi->properties, FIX_FORCE_MS_TO_10)){
657 				uchar mode_data_len_msb = 0, block_descr_len_msb = 0;
658 				if( B_OK != sg_access_byte(sgb, 0, &mode_data_len_msb, false) ||
659 						B_OK != sg_access_byte(sgb, 6, &block_descr_len_msb, false) ||
660 							 0 != mode_data_len_msb || 0 != block_descr_len_msb)
661 				{
662 					/* In case of error TRACE-ing was already performed in sg_ functions */
663 					TRACE_ALWAYS("MODE_SENSE 10->6 conversion overflow: %d, %d\n",
664 								 mode_data_len_msb, block_descr_len_msb);
665 					goto set_REQ_INVALID_and_return;
666 				}
667 				TRACE_MODE_SENSE_SGB("MODE SENSE 10:", sgb);
668 				if( B_OK != sg_memcpy(&sgb_sense_6, 0, sgb, 1, 3) ||
669 						B_OK != sg_memcpy(&sgb_sense_6, 3, sgb, 7, 1) ||
670 						B_OK != sg_memcpy(&sgb_sense_6, 4, sgb, 8, ccbio->cam_dxfer_len - sizeof(scsi_mode_param_header_6)))
671 				{
672 					/* In case of error TRACE-ing was already performed in sg_ functions */
673 					TRACE_ALWAYS("MODE_SENSE 10->6 conversion failed\n");
674 					goto set_REQ_INVALID_and_return;
675 				}
676 			}
677 			/* set write-protected flag if required by user */
678 			if(HAS_FIXES(udi->properties, FIX_FORCE_READ_ONLY)){
679 				status_t status = B_OK;
680 				uchar device_spec_params = 0;
681 				if(B_OK == (status = sg_access_byte(sgb, 2, &device_spec_params, false))){
682 					device_spec_params |= 0x80;
683 					status = sg_access_byte(sgb, 2, &device_spec_params, true);
684 				}
685 				if(B_OK != status){
686 					TRACE_ALWAYS("MODE_SENSE set READ-ONLY mode failed. Writing ALLOWED!\n");
687 					/*goto set_req_invalid_and_return;*/ /* not urgent. do not fail processing...	*/
688 				}
689 			}
690 			TRACE_MODE_SENSE_SGB("MODE SENSE 6:", &sgb_sense_6);
691 		}
692 		if(HAS_FIXES(udi->properties, FIX_FORCE_MS_TO_10)){
693 			free_sg_buffer(sgb);
694 		}
695 	} break;
696 	case TEST_UNIT_READY: { /* set the not ready luns flag */
697 			scsi_sense_data *sense_data = (ccbio->cam_sense_ptr == NULL) ?
698 				&udi->autosense_data : (scsi_sense_data *)ccbio->cam_sense_ptr;
699 			if((sense_data->flags & SSD_KEY) == SSD_KEY_NOT_READY){
700 				udi->not_ready_luns |= (1 << target_lun);
701 			} else {
702 				udi->not_ready_luns &= ~(1 << target_lun);
703 			}
704 			usb_scsi_trace_bytes("NOT_READY_LUNS:", &udi->not_ready_luns, 1);
705 		} break;
706 	case READ_CAPACITY:{
707 		/*uint8 *bts = sgb->piov->iov_base;
708 		uint32 capacity = (bts[0]<<24) + (bts[1]<<16) + (bts[2]<<8) + (bts[3]);
709 		TRACE_ALWAYS("CAPAC:%d\n", capacity);
710 		//bts[3] -= 3;*/
711 		TRACE_CAPACITY("READ_CAPACITY:", sgb);
712 	} break;
713 	default: break;
714 	}
715 	return false; /* do not retry - all is OK */ //b_retry;
716 
717 set_REQ_INVALID_and_return:
718 	ccbio->cam_ch.cam_status = CAM_REQ_INVALID;
719 	*ret_status = B_BAD_VALUE;
720 	return false; /* do not retry - fatal error */
721 }
722 /**
723 	\fn:xpt_scsi_io
724 	\param ccbio: ????
725 	\return: ???
726 
727 	xpt_scsi_io - handle XPT_SCSI_IO sim action
728 */
729 status_t xpt_scsi_io(CCB_SCSIIO *ccbio)
730 {
731 	status_t status			= B_OK;
732 	usb_device_info *udi = usb_devices[ccbio->cam_ch.cam_target_id/*target_id*/];
733 	uint8 *cmd;
734 	sg_buffer sgb;
735 
736 	/* clear the scsi_status. It can come from system with some garbage value ...*/
737 	ccbio->cam_scsi_status = SCSI_STATUS_OK;
738 	/* check the request for correct parameters, valid targets, luns etc ... */
739 	if(false == pre_check_scsi_io_request(udi, ccbio, &status)){
740 		return status;
741 	}
742 
743 #if 0 /* activate if you need detailed logging of CCB_SCSI request*/
744 	usb_scsi_trace_CCB_SCSIIO(ccbio);
745 #endif
746 
747 
748 	/* acquire semaphore - avoid re-enters */
749 /*	if((status = acquire_sem_etc(udi->lock_sem, 1,
750 								B_RELATIVE_TIMEOUT,
751 								udi->trans_timeout)) != B_OK) */
752 //	TRACE_ALWAYS("sem before acq:%08x\n",udi->lock_sem);
753 	if((status = acquire_sem(udi->lock_sem)) != B_OK){
754 		/* disabled - CAM_BUSY flag is not recognized by BeOS ... :-(
755 		if(status == B_WOULD_BLOCK){
756 			TRACE("locked sema bypass OK\n");
757 			ccbio->cam_ch.cam_status = CAM_BUSY;
758 			return B_OK;
759 		}*/
760 		TRACE("xpt_scsi_io:acquire_sem_etc() failed:%08x\n", status);
761 		ccbio->cam_ch.cam_status = CAM_DEV_NOT_THERE;
762 		return B_DEV_BAD_DRIVE_NUM;
763 	}
764 	/* set the command data pointer */
765 	if(ccbio->cam_ch.cam_flags & CAM_CDB_POINTER){
766 		cmd = ccbio->cam_cdb_io.cam_cdb_ptr;
767 	}else{
768 		cmd = ccbio->cam_cdb_io.cam_cdb_bytes;
769 	}
770 	/* NOTE: using stack copy of sg_buffer sgb. It can be modified/freed in
771 					 *_handle_features() functions! Twice reallocation is also not awaited!
772 					 Note this on refactoring!!! */
773 	/*TODO returns!*/
774 	init_sg_buffer(&sgb, ccbio);
775 	do{ /* <-- will be repeated if 6-byte RW/MS commands failed */
776 		uint8 *rcmd;
777 		uint8 rcmdlen;
778 		uint32 transfer_len = 0;
779 		EDirection dir = eDirNone;
780 		/* handle various features for this device */
781 		if(!pre_handle_features(udi, ccbio, (scsi_cmd_generic *)cmd, &sgb, &status)){
782 			release_sem(udi->lock_sem);
783 			return status;
784 		}
785 		/* transform command as required by protocol */
786 		rcmd		= udi->scsi_command_buf;
787 		rcmdlen = sizeof(udi->scsi_command_buf);
788 		if((status = (*udi->transform_m->transform)(udi, cmd, ccbio->cam_cdb_len & 0x1f,
789 													 &rcmd, &rcmdlen)) != B_OK)
790 		{
791 			TRACE_ALWAYS("xpt_scsi_io: transform failed: %08x\n", status);
792 			ccbio->cam_ch.cam_status = CAM_REQ_INVALID;
793 			release_sem(udi->lock_sem);
794 			return B_BAD_VALUE;
795 		}
796 		/* set correct direction flag */
797 		switch(CAM_DIR_MASK & ccbio->cam_ch.cam_flags){
798 		case CAM_DIR_IN:	dir = eDirIn;	break;
799 		case CAM_DIR_OUT:	dir = eDirOut;	break;
800 		default:			dir = eDirNone;	break;
801 		}
802 
803 		TRACE_DATA_IO_SG(sgb.piov, sgb.count);
804 
805 		/*TODO: return!*/
806 		sg_buffer_len(&sgb, &transfer_len);
807 		/* transfer command to device. SCSI status will be handled in callback */
808 		(*udi->protocol_m->transfer)(udi, rcmd, rcmdlen, sgb.piov, sgb.count,
809 									 transfer_len/*ccbio->cam_dxfer_len*/,
810 										dir, ccbio, transfer_callback);
811 		/* perform some post-tranfer features handling
812 			 and automatic 6-10 bytes command support detection */
813 	} while(post_handle_features(udi, ccbio, (scsi_cmd_generic *)cmd, &sgb, &status));
814 	release_sem(udi->lock_sem);
815 	return status;
816 }
817 /**
818 	\fn:xpt_path_inquiry
819 	\param ccbp:
820 	\return:
821 
822 	xpt_path_inquiry - handle XPT_PATH_INQ sim action
823 */
824 status_t xpt_path_inquiry(CCB_PATHINQ *ccbp)
825 {
826 	status_t status			= B_OK;
827 
828 	ccbp->cam_version_num	= SIM_VERSION;
829 	ccbp->cam_target_sprt	= 0;
830 	ccbp->cam_hba_eng_cnt	= 0;
831 	memset (ccbp->cam_vuhba_flags, 0, VUHBA);
832 	ccbp->cam_sim_priv		= SIM_PRIV;
833 	ccbp->cam_async_flags	= 0;
834 	ccbp->cam_initiator_id	= CONTROLLER_SCSI_ID;
835 	ccbp->cam_hba_inquiry	= CONTROLLER_SCSI_BUS; /* Narrow SCSI bus */
836 	ccbp->cam_hba_misc		= PIM_NOINQUIRY;
837 	ccbp->cam_osd_usage		= 0;
838 	/* There should be special handling of path_id == 0xff
839 		 but looks like it's not used by BeOS now */
840 	/*ccbp->cam_hpath_id = path_id;*/
841 	strncpy(ccbp->cam_sim_vid, sim_vendor_name, SIM_ID);
842 	strncpy(ccbp->cam_hba_vid, hba_vendor_name, HBA_ID);
843 	ccbp->cam_ch.cam_status = CAM_REQ_CMP;
844 	return status;
845 }
846 /**
847 	\fn:xpt_extended_path_inquiry
848 	\param ccbep: ???
849 	\return:???
850 
851 	xpt_extended_path_inquiry - handle XPT_EXTENDED_PATH_INQ sim action
852 */
853 status_t xpt_extended_path_inquiry(CCB_EXTENDED_PATHINQ *ccbep)
854 {
855 	status_t status = B_OK;
856 	xpt_path_inquiry((CCB_PATHINQ *)ccbep);
857 	sprintf(ccbep->cam_sim_version, "%d.0", SIM_VERSION);
858 	sprintf(ccbep->cam_hba_version, "%d.0", HBA_VERSION);
859 	strncpy(ccbep->cam_controller_family, controller_family, FAM_ID);
860 	strncpy(ccbep->cam_controller_type, "USB-SCSI", TYPE_ID);
861 	return status;
862 }
863 /**
864 	\fn:sim_action
865 	\param ccbh: ????
866 	\return: ????
867 
868 	This fucntion performs SCSI interface module actions -
869 	calls corresponding xpt_* - functions.
870 */
871 static long sim_action(CCB_HEADER *ccbh)
872 {
873 	status_t status = B_ERROR;
874 	if(path_id != ccbh->cam_path_id){
875 		TRACE_ALWAYS("sim_action:path_id mismatch of func:%d:our:%d,requested:%d\n",
876 					 ccbh->cam_func_code, path_id, ccbh->cam_path_id);
877 		ccbh->cam_status = CAM_PATH_INVALID;
878 	} else {
879 		ccbh->cam_status = CAM_REQ_INPROG;
880 		switch(ccbh->cam_func_code){
881 			case XPT_SCSI_IO:
882 				status = xpt_scsi_io((CCB_SCSIIO *)ccbh);
883 				break;
884 			case XPT_PATH_INQ:
885 				status = xpt_path_inquiry((CCB_PATHINQ *)ccbh);
886 				break;
887 			case XPT_EXTENDED_PATH_INQ:
888 				status = xpt_extended_path_inquiry((CCB_EXTENDED_PATHINQ *)ccbh);
889 				break;
890 			default:
891 				TRACE_ALWAYS("sim_action: unsupported function: %x\n", ccbh->cam_func_code);
892 				ccbh->cam_status = CAM_REQ_INVALID;
893 				break;
894 		}
895 	}
896 	return status;
897 }
898 #endif
899 
900 /**
901 	\fn:std_ops
902 	\param op: operation to be performed on this module
903 	\param ...: possible additional arguments
904 	\return: B_OK on success, error status on failure
905 
906 	This function deals with standard module operations. Currently, the only
907 	two things that entails are initialization and uninitialization.
908 	- get the SCSI Bus Manager Module and USB Manager Module
909 	- put them when we're finished
910 */
std_ops(int32 op,...)911 static status_t std_ops(int32 op, ...)
912 {
913 	//int i;
914 	status_t status = B_OK;//B_ERROR;
915 	//CAM_SIM_ENTRY entry;
916 	switch(op) {
917 	case B_MODULE_INIT:
918 		TRACE_ALWAYS("std_ops: B_MODULE_INIT called!\n");
919 	/*	if(0 == atomic_add(&load_count, 1)){
920 			thread_info tinfo = {0}; */
921 			load_module_settings();
922 /*			get_thread_info(find_thread(0), &tinfo);
923 			if(!b_ignore_sysinit2 || (0 != strcmp(tinfo.name, "sysinit2"))){
924 				create_log();
925 				if(get_module(B_USB_MODULE_NAME, (module_info **)&usb) == B_OK){
926 					if(get_module(B_CAM_FOR_SIM_MODULE_NAME, (module_info **)&cam) == B_OK){
927 						for(i = 0; i < MAX_DEVICES_COUNT; i++)
928 							usb_devices[i] = NULL;
929 
930 						if((*usb->register_driver)(MODULE_NAME, supported_devices, B_COUNT_OF(supported_devices), "usb_dsk") == B_OK){
931 							if((*usb->install_notify)(MODULE_NAME, &notify_hooks) == B_OK){
932 								entry.sim_init = sim_init;
933 								entry.sim_action = sim_action;
934 								path_id =(*cam->xpt_bus_register)(&entry);
935 								usb_serial_lock = create_sem(1, MODULE_NAME"_devices_table_lock");
936 								status = B_OK;
937 								break;
938 							}
939 						}
940 						put_module(B_CAM_FOR_SIM_MODULE_NAME);
941 					}
942 					put_module(B_USB_MODULE_NAME);
943 				}
944 			} else {
945 				TRACE_ALWAYS("std_ops INIT call was ignored for thread:%s\n", tinfo.name);
946 			}
947 		} else {
948 			atomic_add(&load_count, -1);
949 		}*/
950 		break;
951 	case B_MODULE_UNINIT:
952 		TRACE_ALWAYS("std_ops: B_MODULE_UNINIT called!\n");
953 	/*	if(1 == atomic_add(&load_count, -1)){
954 			(*usb->uninstall_notify)(MODULE_NAME);
955 			status = B_OK;
956 			if(path_id != -1){
957 				(*cam->xpt_bus_deregister)(path_id);
958 				path_id = -1;
959 			}
960 			delete_sem(usb_serial_lock);
961 			put_module(B_USB_MODULE_NAME);
962 			put_module(B_CAM_FOR_SIM_MODULE_NAME);
963 		} else {
964 			atomic_add(&load_count, 1);
965 		}*/
966 		break;
967 	}
968 	return status;
969 }
970 
971 /**
972  * \fn:
973  * \param :
974  * \return:
975  *  TODO
976  */
977 static float
supports_device(device_node_handle parent,bool * _noConnection)978 supports_device(device_node_handle parent, bool *_noConnection)
979 {
980 	TRACE_ALWAYS("supports_device\n");
981 	return 0.f;
982 }
983 
984 /**
985  * \fn:
986  * \param :
987  * \return:
988  *  TODO
989  */
990 static status_t
register_device(device_node_handle parent)991 register_device(device_node_handle parent)
992 {
993 	TRACE_ALWAYS("register_device\n");
994 	return B_OK;
995 }
996 
997 /**
998  * \fn:
999  * \param :
1000  * \return:
1001  *  TODO
1002  */
1003 static status_t
init_module(device_node_handle node,void * user_cookie,void ** _cookie)1004 init_module(device_node_handle node, void *user_cookie, void **_cookie)
1005 {
1006 	TRACE_ALWAYS("inti_driver\n");
1007 	return B_OK;
1008 }
1009 
1010 /**
1011  * \fn:
1012  * \param :
1013  * \return:
1014  *  TODO
1015  */
1016 static status_t
uninit_module(void * cookie)1017 uninit_module(void *cookie)
1018 {
1019 	TRACE_ALWAYS("uninit_driver\n");
1020 	return B_OK;
1021 }
1022 
1023 /**
1024  * \fn:
1025  * \param :
1026  *  TODO
1027  */
1028 static void
device_removed(device_node_handle node,void * cookie)1029 device_removed(device_node_handle node, void *cookie)
1030 {
1031 	TRACE_ALWAYS("device_removed\n");
1032 }
1033 
1034 /**
1035  * \fn:
1036  * \param :
1037  *  TODO
1038  */
1039 static void
device_cleanup(device_node_handle node)1040 device_cleanup(device_node_handle node)
1041 {
1042 	TRACE_ALWAYS("device_cleanup\n");
1043 }
1044 
1045 /**
1046  * \fn:
1047  * \param :
1048  *  TODO
1049  */
1050 static void
get_supported_paths(const char *** _busses,const char *** _devices)1051 get_supported_paths(const char ***_busses, const char ***_devices)
1052 {
1053 	TRACE_ALWAYS("get_supported_path\n");
1054 }
1055 
1056 /**
1057  * \fn:
1058  * \param :
1059  *  TODO
1060  */
1061 static void
scsi_io(scsi_sim_cookie cookie,scsi_ccb * ccb)1062 scsi_io( scsi_sim_cookie cookie, scsi_ccb *ccb )
1063 {
1064 	TRACE_ALWAYS("scsi_io\n");
1065 }
1066 
1067 /**
1068  * \fn:
1069  * \param :
1070  * \return:
1071  *  TODO
1072  */
1073 static uchar
abort(scsi_sim_cookie cookie,scsi_ccb * ccb_to_abort)1074 abort( scsi_sim_cookie cookie, scsi_ccb *ccb_to_abort )
1075 {
1076 	TRACE_ALWAYS("scsi_sim\n");
1077 	return 0;
1078 }
1079 
1080 /**
1081  * \fn:
1082  * \param :
1083  * \return:
1084  *  TODO
1085  */
1086 static uchar
reset_device(scsi_sim_cookie cookie,uchar target_id,uchar target_lun)1087 reset_device( scsi_sim_cookie cookie, uchar target_id, uchar target_lun )
1088 {
1089 	TRACE_ALWAYS("supports_device\n");
1090 	return 0;
1091 }
1092 
1093 /**
1094  * \fn:
1095  * \param :
1096  * \return:
1097  *  TODO
1098  */
1099 static uchar
term_io(scsi_sim_cookie cookie,scsi_ccb * ccb_to_terminate)1100 term_io( scsi_sim_cookie cookie, scsi_ccb *ccb_to_terminate )
1101 {
1102 	TRACE_ALWAYS("term_io\n");
1103 	return 0;
1104 }
1105 
1106 /**
1107  * \fn:
1108  * \param :
1109  * \return:
1110  *  TODO
1111  */
1112 static uchar
path_inquiry(scsi_sim_cookie cookie,scsi_path_inquiry * inquiry_data)1113 path_inquiry( scsi_sim_cookie cookie, scsi_path_inquiry *inquiry_data )
1114 {
1115 	TRACE_ALWAYS("path_inquiry\n");
1116 	return 0;
1117 }
1118 
1119 /**
1120  * \fn:
1121  * \param :
1122  * \return:
1123  *  TODO
1124  */
1125 static uchar
scan_bus(scsi_sim_cookie cookie)1126 scan_bus( scsi_sim_cookie cookie )
1127 {
1128 	TRACE_ALWAYS("scan_bus\n");
1129 	return 0;
1130 }
1131 
1132 /**
1133  * \fn:
1134  * \param :
1135  * \return:
1136  *  TODO
1137  */
1138 static uchar
reset_bus(scsi_sim_cookie cookie)1139 reset_bus( scsi_sim_cookie cookie )
1140 {
1141 	TRACE_ALWAYS("reset_bus\n");
1142 	return 0;
1143 }
1144 
1145 /**
1146  * \fn:
1147  * \param :
1148  *  TODO
1149  */
1150 static void
get_restrictions(scsi_sim_cookie cookie,uchar target_id,bool * is_atapi,bool * no_autosense,uint32 * max_blocks)1151 get_restrictions(scsi_sim_cookie cookie, uchar target_id, bool *is_atapi, bool *no_autosense, uint32 *max_blocks )
1152 {
1153 	TRACE_ALWAYS("get_restrictions\n");
1154 }
1155 
1156 /**
1157  * \fn:
1158  * \param :
1159  * \return:
1160  *  TODO
1161  */
1162 static status_t
module_ioctl(scsi_sim_cookie cookie,uint8 targetID,uint32 op,void * buffer,size_t length)1163 module_ioctl(scsi_sim_cookie cookie, uint8 targetID, uint32 op, void *buffer, size_t length)
1164 {
1165 	TRACE_ALWAYS("ioctl\n");
1166 	return B_DEV_INVALID_IOCTL;
1167 }
1168 
1169 
1170 /**
1171 	Declare our module_info so we can be loaded as a kernel module
1172 */
1173 static scsi_sim_interface usb_scsi_sim = {
1174 	{	//driver_module_info
1175 		{ // module_info
1176 			"busses/scsi/usb/device_v1", // is device_v1 really required? or v1 is enough?
1177 			0,
1178 			&std_ops
1179 		},
1180 
1181 		supports_device,
1182 		register_device,
1183 
1184 		init_module,	// init_driver,
1185 		uninit_module,	// uninit_driver,
1186 
1187 		device_removed,
1188 		device_cleanup,
1189 
1190 		get_supported_paths,
1191 	},
1192 
1193 	scsi_io,
1194 	abort,
1195 	reset_device,
1196 	term_io,
1197 
1198 	path_inquiry,
1199 	scan_bus,
1200 	reset_bus,
1201 
1202 	get_restrictions,
1203 
1204 	module_ioctl //ioctl
1205 };
1206 
1207 /**
1208 	Export module_info-s list
1209 */
1210 _EXPORT module_info *modules[] = {
1211 	(module_info *) &usb_scsi_sim,
1212 	NULL
1213 };
1214 
1215