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, ¬ify_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