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 */ 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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