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