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