diff --git a/build/jam/packages/Haiku b/build/jam/packages/Haiku index ba7e5c3792..765868de5c 100644 --- a/build/jam/packages/Haiku +++ b/build/jam/packages/Haiku @@ -73,7 +73,6 @@ AddDriversToPackage midi : $(SYSTEM_ADD_ONS_DRIVERS_MIDI) ; AddDriversToPackage bus : usb_raw fw_raw@x86 ; AddDriversToPackage disk floppy : pc_floppy@x86 ; AddDriversToPackage disk usb : usb_disk ; -AddDriversToPackage disk usb : usb_floppy ; AddDriversToPackage printer usb : usb_printer ; AddDriversToPackage disk virtual : nbd ; AddDriversToPackage dvb : cx23882 ; diff --git a/build/jam/packages/HaikuBootstrap b/build/jam/packages/HaikuBootstrap index 29524497f2..faefa0bad2 100644 --- a/build/jam/packages/HaikuBootstrap +++ b/build/jam/packages/HaikuBootstrap @@ -71,7 +71,6 @@ AddDriversToPackage midi : $(SYSTEM_ADD_ONS_DRIVERS_MIDI) ; AddDriversToPackage bus : usb_raw fw_raw@x86 ; AddDriversToPackage disk floppy : pc_floppy@x86 ; AddDriversToPackage disk usb : usb_disk ; -AddDriversToPackage disk usb : usb_floppy ; AddDriversToPackage printer usb : usb_printer ; AddDriversToPackage disk virtual : nbd ; AddDriversToPackage graphics : $(SYSTEM_ADD_ONS_DRIVERS_GRAPHICS) ; diff --git a/src/add-ons/kernel/drivers/disk/usb/Jamfile b/src/add-ons/kernel/drivers/disk/usb/Jamfile index 15974936a3..5a85aea58b 100644 --- a/src/add-ons/kernel/drivers/disk/usb/Jamfile +++ b/src/add-ons/kernel/drivers/disk/usb/Jamfile @@ -1,4 +1,3 @@ SubDir HAIKU_TOP src add-ons kernel drivers disk usb ; SubInclude HAIKU_TOP src add-ons kernel drivers disk usb usb_disk ; -SubInclude HAIKU_TOP src add-ons kernel drivers disk usb usb_floppy ; diff --git a/src/add-ons/kernel/drivers/disk/usb/usb_disk/usb_disk.cpp b/src/add-ons/kernel/drivers/disk/usb/usb_disk/usb_disk.cpp index db3a393189..3731e6b68a 100644 --- a/src/add-ons/kernel/drivers/disk/usb/usb_disk/usb_disk.cpp +++ b/src/add-ons/kernel/drivers/disk/usb/usb_disk/usb_disk.cpp @@ -397,6 +397,64 @@ const unsigned char kZipIcon[] = { 0x11, 0x20, 0x1e, 0x20 }; + +static const uint8 kFloppyIcon[] = { + 0x6e, 0x63, 0x69, 0x66, 0x0d, 0x03, 0x01, 0x00, 0x00, 0x01, 0x01, 0x00, + 0x00, 0x6a, 0x02, 0x00, 0x16, 0x02, 0x38, 0x6a, 0xad, 0x38, 0xeb, 0x7a, + 0xbb, 0x77, 0x73, 0x3a, 0xde, 0x88, 0x48, 0xce, 0xdc, 0x4a, 0x75, 0xed, + 0x00, 0x7a, 0xff, 0x4b, 0x02, 0x00, 0x16, 0x02, 0x38, 0x6a, 0xad, 0x38, + 0xeb, 0x7a, 0xbb, 0x77, 0x73, 0x3a, 0xde, 0x88, 0x48, 0xce, 0xdc, 0x4a, + 0x75, 0xed, 0x00, 0x8a, 0xff, 0x2c, 0x05, 0x7d, 0x02, 0x00, 0x16, 0x02, + 0x39, 0xc6, 0x30, 0x36, 0xa8, 0x1b, 0xb9, 0x51, 0xe6, 0x3c, 0x5b, 0xb3, + 0x4b, 0x4d, 0xa8, 0x4a, 0x1a, 0xa1, 0x00, 0x3a, 0xff, 0x5d, 0x02, 0x00, + 0x16, 0x02, 0xb7, 0x16, 0xa4, 0xba, 0x87, 0xfe, 0x3c, 0xb2, 0x07, 0xb9, + 0x49, 0xed, 0x48, 0x87, 0xd8, 0x4a, 0x1e, 0x62, 0x01, 0x75, 0xfe, 0xc4, + 0x02, 0x00, 0x16, 0x02, 0xb7, 0x16, 0xa4, 0xba, 0x87, 0xfe, 0x3c, 0xb2, + 0x07, 0xb9, 0x49, 0xed, 0x48, 0x87, 0xd8, 0x4a, 0x1e, 0x62, 0x00, 0x5c, + 0xfe, 0x9b, 0x02, 0x00, 0x16, 0x05, 0x36, 0xef, 0x60, 0x38, 0xe2, 0xe5, + 0xbd, 0x22, 0x41, 0x3b, 0x2f, 0xce, 0x4a, 0x0e, 0x78, 0x4a, 0x5a, 0x6c, + 0x00, 0xb8, 0x38, 0xe6, 0x77, 0xb8, 0xbd, 0xd2, 0xff, 0x93, 0x02, 0x00, + 0x16, 0x05, 0x34, 0x0a, 0x8f, 0x38, 0xd2, 0xa2, 0xba, 0xb4, 0xc5, 0x35, + 0xe9, 0xec, 0x49, 0xfd, 0x24, 0x4a, 0x64, 0x62, 0x00, 0xe1, 0x38, 0xff, + 0x75, 0xd7, 0xba, 0xf3, 0xfd, 0xd0, 0x02, 0x00, 0x16, 0x02, 0x36, 0x67, + 0xbe, 0x39, 0xdd, 0xbc, 0xbe, 0x50, 0x04, 0x3a, 0xe0, 0x9f, 0x4b, 0x85, + 0x01, 0x49, 0x2a, 0x3f, 0x00, 0xff, 0xff, 0xd8, 0x03, 0x38, 0x6d, 0xbe, + 0x02, 0x00, 0x16, 0x02, 0x3c, 0x40, 0xef, 0x3b, 0x82, 0xd1, 0xba, 0xeb, + 0x42, 0x3b, 0xbf, 0x4d, 0x4a, 0xa7, 0xce, 0x49, 0x5d, 0xc1, 0xff, 0x01, + 0x00, 0x4a, 0x12, 0x0a, 0x05, 0x44, 0x5a, 0x44, 0x40, 0x5e, 0x40, 0x5f, + 0x45, 0x49, 0x5a, 0x0a, 0x06, 0x45, 0x58, 0x5c, 0x42, 0x5c, 0x40, 0x3d, + 0x34, 0xb5, 0x6b, 0xc2, 0x2e, 0xb5, 0x63, 0xc3, 0xbb, 0x0a, 0x04, 0x44, + 0x58, 0x26, 0x4a, 0x26, 0x47, 0x44, 0x54, 0x0a, 0x04, 0x44, 0x59, 0x5c, + 0x42, 0x5c, 0x3e, 0x44, 0x54, 0x0a, 0x05, 0x44, 0x56, 0x5c, 0x40, 0x3d, + 0x34, 0xb5, 0x6b, 0xc2, 0x2e, 0xb5, 0x43, 0xc3, 0x3b, 0x0a, 0x04, 0x2a, + 0x4c, 0x3f, 0x56, 0x3f, 0x53, 0x2a, 0x4a, 0x0a, 0x04, 0x2a, 0x4b, 0x39, + 0x52, 0x39, 0x50, 0x2a, 0x4a, 0x0a, 0x04, 0x31, 0x42, 0x45, 0x4c, 0x3f, + 0x53, 0x2a, 0x4a, 0x0a, 0x04, 0x3f, 0x49, 0x38, 0x50, 0x2a, 0x4a, 0x31, + 0x43, 0x0a, 0x04, 0x3f, 0x36, 0x57, 0x3e, 0x49, 0x4b, 0x32, 0x40, 0x08, + 0x02, 0x3c, 0x3b, 0x4d, 0x43, 0x00, 0x02, 0x3b, 0x3b, 0x31, 0x36, 0x43, + 0x3f, 0x48, 0x3d, 0x3f, 0x36, 0xc4, 0x82, 0xbf, 0xc7, 0x00, 0x02, 0x3e, + 0x3c, 0xbc, 0x58, 0xbd, 0x93, 0x47, 0x3e, 0x45, 0x44, 0x3d, 0x43, 0x4d, + 0x45, 0x02, 0x04, 0x39, 0x3b, 0x39, 0x3d, 0x39, 0x39, 0x3c, 0x38, 0x3b, + 0x38, 0x3e, 0x38, 0x3e, 0x3a, 0x3f, 0x3a, 0x41, 0x37, 0x3c, 0x3d, 0x3c, + 0x42, 0x3c, 0x40, 0x02, 0x04, 0x46, 0x3c, 0x46, 0x3e, 0x46, 0x3a, 0x48, + 0x3a, 0x46, 0x3a, 0x4a, 0x3a, 0x4a, 0x3c, 0x4a, 0x3a, 0x4a, 0x3e, 0x48, + 0x3e, 0x4a, 0x3e, 0x46, 0x3e, 0x0a, 0x04, 0x45, 0x42, 0x42, 0x45, 0x45, + 0x47, 0x48, 0x44, 0x0a, 0x03, 0x4e, 0x43, 0x4d, 0x3f, 0x48, 0x44, 0x0a, + 0x04, 0x32, 0x4b, 0x36, 0x48, 0x32, 0x46, 0x2e, 0x4a, 0x0d, 0x0a, 0x01, + 0x01, 0x00, 0x20, 0x1e, 0x20, 0x0a, 0x00, 0x01, 0x01, 0x30, 0x1e, 0x20, + 0x01, 0x17, 0x84, 0x00, 0x04, 0x0a, 0x02, 0x01, 0x02, 0x20, 0x1e, 0x20, + 0x0a, 0x05, 0x01, 0x03, 0x20, 0x1e, 0x20, 0x0a, 0x06, 0x01, 0x04, 0x20, + 0x1e, 0x20, 0x0a, 0x03, 0x01, 0x05, 0x20, 0x1e, 0x20, 0x0a, 0x07, 0x01, + 0x07, 0x20, 0x1e, 0x20, 0x0a, 0x08, 0x01, 0x06, 0x20, 0x1e, 0x20, 0x0a, + 0x09, 0x01, 0x08, 0x20, 0x1e, 0x20, 0x0a, 0x0a, 0x01, 0x09, 0x20, 0x1e, + 0x20, 0x0a, 0x0c, 0x03, 0x0a, 0x0b, 0x0c, 0x1a, 0x40, 0x1d, 0x05, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x9d, 0xc9, 0xc2, 0x91, 0x98, 0x43, + 0x6d, 0xc2, 0x20, 0xff, 0x01, 0x17, 0x81, 0x00, 0x04, 0x0a, 0x0c, 0x04, + 0x0d, 0x0e, 0x0f, 0x10, 0x0a, 0x3f, 0xff, 0xbd, 0x34, 0xaf, 0xbc, 0xb4, + 0xe0, 0x2c, 0x3f, 0xbc, 0x62, 0x3e, 0x74, 0x62, 0x41, 0xfe, 0xe7, 0x20, + 0xff, 0x0a, 0x02, 0x01, 0x11, 0x20, 0x1e, 0x20 +}; + device_icon kKeyIconData = { (int32)sizeof(kDeviceIcon), (void *)kDeviceIcon }; device_icon kCDIconData = { (int32)sizeof(kCDIcon), (void *)kCDIcon }; device_icon kMSIconData = { (int32)sizeof(kMemoryStickIcon), @@ -404,6 +462,8 @@ device_icon kMSIconData = { (int32)sizeof(kMemoryStickIcon), device_icon kSDIconData = { (int32)sizeof(kSDIcon), (void *)kSDIcon }; device_icon kMobileIconData = { (int32)sizeof(kMobileIcon), (void *)kMobileIcon }; +device_icon kFloppyIconData = { (int32)sizeof(kFloppyIcon), + (void *)kFloppyIcon }; struct { @@ -422,7 +482,8 @@ struct { // { NULL, " SM Reader", &kSMIconData, "devices/drive-removable-media-flash" }, // match for my Kazam mobile phone // stupid thing says "MEDIATEK" " FLASH DISK " even for internal memory - { "MEDIATEK", NULL, &kMobileIconData, "devices/drive-removable-media-flash" }, + { "MEDIATEK", NULL, &kMobileIconData, + "devices/drive-removable-media-flash" }, { NULL, NULL, NULL, NULL } }; @@ -442,11 +503,11 @@ status_t usb_disk_transfer_data(disk_device *device, bool directionIn, void *data, size_t dataLength); status_t usb_disk_receive_csw(disk_device *device, usb_massbulk_command_status_wrapper *status); -status_t usb_disk_operation(device_lun *lun, uint8 operation, - uint8 opLength, uint32 logicalBlockAddress, - uint16 transferLength, void *data, size_t *dataLength, +status_t usb_disk_operation(device_lun *lun, uint8* operation, + size_t opLength, void *data, size_t *dataLength, bool directionIn, err_act *action = NULL); +status_t usb_disk_send_diagnostic(device_lun *lun); status_t usb_disk_request_sense(device_lun *lun, err_act *action); status_t usb_disk_mode_sense(device_lun *lun); status_t usb_disk_test_unit_ready(device_lun *lun, err_act *action = NULL); @@ -467,6 +528,7 @@ usb_disk_free_device_and_luns(disk_device *device) mutex_lock(&device->lock); mutex_destroy(&device->lock); delete_sem(device->notify); + delete_sem(device->interruptLock); for (uint8 i = 0; i < device->lun_count; i++) free(device->luns[i]); free(device->luns); @@ -517,6 +579,8 @@ usb_disk_reset_recovery(disk_device *device) usb_disk_mass_storage_reset(device); gUSBModule->clear_feature(device->bulk_in, USB_FEATURE_ENDPOINT_HALT); gUSBModule->clear_feature(device->bulk_out, USB_FEATURE_ENDPOINT_HALT); + if (device->is_ufi) + gUSBModule->clear_feature(device->interrupt, USB_FEATURE_ENDPOINT_HALT); } @@ -555,8 +619,48 @@ usb_disk_transfer_data(disk_device *device, bool directionIn, void *data, } +void +usb_disk_interrupt(void* cookie, int32 status, void* data, size_t length) +{ + disk_device* device = (disk_device*)cookie; + // We release the lock even if the interrupt is invalid. This way there + // is at least a chance for the driver to terminate properly. + release_sem(device->interruptLock); + + if (length != 2) { + TRACE_ALWAYS("interrupt of length %" B_PRIuSIZE "! (expected 2)\n", + length); + // In this case we do not reschedule the interrupt. This means the + // driver will be locked. The interrupt should perhaps be scheduled + // when starting a transfer instead. But getting there means something + // is really broken, so... + return; + } + + // Reschedule the interrupt for next time + gUSBModule->queue_interrupt(device->interrupt, device->interruptBuffer, 2, + usb_disk_interrupt, cookie); +} + + status_t -usb_disk_receive_csw(disk_device *device, +usb_disk_receive_csw_interrupt(disk_device *device, + interrupt_status_wrapper *status) +{ + TRACE("Waiting for result...\n"); + gUSBModule->queue_interrupt(device->interrupt, + device->interruptBuffer, 2, usb_disk_interrupt, device); + + acquire_sem(device->interruptLock); + + status->status = device->interruptBuffer[0]; + status->misc = device->interruptBuffer[1]; + + return B_OK; +} + +status_t +usb_disk_receive_csw_bulk(disk_device *device, usb_massbulk_command_status_wrapper *status) { status_t result = usb_disk_transfer_data(device, true, status, @@ -565,7 +669,7 @@ usb_disk_receive_csw(disk_device *device, return result; if (device->status != B_OK - || device->actual_length + || device->actual_length != sizeof(usb_massbulk_command_status_wrapper)) { // receiving the command status wrapper failed return B_ERROR; @@ -576,14 +680,91 @@ usb_disk_receive_csw(disk_device *device, status_t -usb_disk_operation(device_lun *lun, uint8 operation, uint8 opLength, - uint32 logicalBlockAddress, uint16 transferLength, void *data, - size_t *dataLength, bool directionIn, err_act *_action) +usb_disk_operation_interrupt(device_lun *lun, uint8* operation, + void *data, size_t *dataLength, bool directionIn, err_act *_action) { - TRACE("operation: lun: %u; op: %u; oplen: %u; lba: %" B_PRIu32 - "; tlen: %u; data: %p; dlen: %p (%lu); in: %c\n", - lun->logical_unit_number, operation, opLength, logicalBlockAddress, - transferLength, data, dataLength, dataLength ? *dataLength : 0, + TRACE("operation: lun: %u; op: 0x%x; data: %p; dlen: %p (%lu); in: %c\n", + lun->logical_unit_number, operation[0], data, dataLength, + dataLength ? *dataLength : 0, directionIn ? 'y' : 'n'); + + disk_device* device = lun->device; + + // Step 1 : send the SCSI operation as a class specific request + size_t actualLength = 12; + status_t result = gUSBModule->send_request(device->device, + USB_REQTYPE_CLASS | USB_REQTYPE_INTERFACE_OUT, 0 /*request*/, + 0/*value*/, device->interface/*index*/, 12, operation, &actualLength); + + if (result != B_OK || actualLength != 12) { + TRACE("Command stage: wrote %ld bytes (error: %s)\n", + actualLength, strerror(result)); + + // There was an error, we have to do a request sense to reset the device + if (operation[0] != SCSI_REQUEST_SENSE_6) { + usb_disk_request_sense(lun, _action); + } + return result; + } + + // Step 2 : data phase : send or receive data + size_t transferedData = 0; + if (data != NULL && dataLength != NULL && *dataLength > 0) { + // we have data to transfer in a data stage + result = usb_disk_transfer_data(device, directionIn, data, *dataLength); + if (result != B_OK) { + TRACE("Error %s in data phase\n", strerror(result)); + return result; + } + + transferedData = device->actual_length; + if (device->status != B_OK || transferedData != *dataLength) { + // sending or receiving of the data failed + if (device->status == B_DEV_STALLED) { + TRACE("stall while transfering data\n"); + gUSBModule->clear_feature(directionIn ? device->bulk_in + : device->bulk_out, USB_FEATURE_ENDPOINT_HALT); + } else { + TRACE_ALWAYS("sending or receiving of the data failed\n"); + usb_disk_reset_recovery(device); + return B_ERROR; + } + } + } + + // step 3 : wait for the device to send the interrupt ACK + if (operation[0] != SCSI_REQUEST_SENSE_6) { + interrupt_status_wrapper status; + result = usb_disk_receive_csw_interrupt(device, &status); + if (result != B_OK) { + // in case of a stall or error clear the stall and try again + TRACE("Error receiving interrupt: %s. Retrying...\n", + strerror(result)); + gUSBModule->clear_feature(device->bulk_in, + USB_FEATURE_ENDPOINT_HALT); + result = usb_disk_receive_csw_interrupt(device, &status); + } + + if (result != B_OK) { + TRACE_ALWAYS("receiving the command status interrupt failed\n"); + usb_disk_reset_recovery(device); + return result; + } + + // wait for the device to finish the operation. + result = usb_disk_request_sense(lun, _action); + } + return result; +} + + +status_t +usb_disk_operation_bulk(device_lun *lun, uint8* operation, + size_t operationLength, void *data, size_t *dataLength, bool directionIn, + err_act *_action) +{ + TRACE("operation: lun: %u; op: %u; data: %p; dlen: %p (%lu); in: %c\n", + lun->logical_unit_number, operation[0], + data, dataLength, dataLength ? *dataLength : 0, directionIn ? 'y' : 'n'); disk_device *device = lun->device; @@ -595,39 +776,9 @@ usb_disk_operation(device_lun *lun, uint8 operation, uint8 opLength, : USB_MASSBULK_CBW_DATA_OUTPUT); command.lun = lun->logical_unit_number; command.command_block_length - = device->is_atapi ? ATAPI_COMMAND_LENGTH : opLength; + = device->is_atapi ? ATAPI_COMMAND_LENGTH : operationLength; memset(command.command_block, 0, sizeof(command.command_block)); - - switch (opLength) { - case 6: - { - scsi_command_6 *commandBlock - = (scsi_command_6 *)command.command_block; - commandBlock->operation = operation; - commandBlock->lun = lun->logical_unit_number << 5; - commandBlock->allocation_length = (uint8)transferLength; - if (operation == SCSI_MODE_SENSE_6) { - // we hijack the lba argument to transport the desired page - commandBlock->reserved[1] = (uint8)logicalBlockAddress; - } - break; - } - - case 10: - { - scsi_command_10 *commandBlock - = (scsi_command_10 *)command.command_block; - commandBlock->operation = operation; - commandBlock->lun_flags = lun->logical_unit_number << 5; - commandBlock->logical_block_address = htonl(logicalBlockAddress); - commandBlock->transfer_length = htons(transferLength); - break; - } - - default: - TRACE_ALWAYS("unsupported operation length %d\n", opLength); - return B_BAD_VALUE; - } + memcpy(command.command_block, operation, operationLength); status_t result = usb_disk_transfer_data(device, false, &command, sizeof(usb_massbulk_command_block_wrapper)); @@ -668,11 +819,11 @@ usb_disk_operation(device_lun *lun, uint8 operation, uint8 opLength, } usb_massbulk_command_status_wrapper status; - result = usb_disk_receive_csw(device, &status); + result = usb_disk_receive_csw_bulk(device, &status); if (result != B_OK) { // in case of a stall or error clear the stall and try again gUSBModule->clear_feature(device->bulk_in, USB_FEATURE_ENDPOINT_HALT); - result = usb_disk_receive_csw(device, &status); + result = usb_disk_receive_csw_bulk(device, &status); } if (result != B_OK) { @@ -713,13 +864,13 @@ usb_disk_operation(device_lun *lun, uint8 operation, uint8 opLength, // the operation is complete and has succeeded return B_OK; } else { - if (operation == SCSI_REQUEST_SENSE_6) + if (operation[0] == SCSI_REQUEST_SENSE_6) return B_ERROR; // the operation is complete but has failed at the SCSI level - if (operation != SCSI_TEST_UNIT_READY_6) { + if (operation[0] != SCSI_TEST_UNIT_READY_6) { TRACE_ALWAYS("operation %#" B_PRIx8 - " failed at the SCSI level\n", operation); + " failed at the SCSI level\n", operation[0]); } result = usb_disk_request_sense(lun, _action); @@ -730,7 +881,8 @@ usb_disk_operation(device_lun *lun, uint8 operation, uint8 opLength, case USB_MASSBULK_CSW_STATUS_PHASE_ERROR: { // a protocol or device error occured - TRACE_ALWAYS("phase error in operation %#" B_PRIx8 "\n", operation); + TRACE_ALWAYS("phase error in operation %#" B_PRIx8 "\n", + operation[0]); usb_disk_reset_recovery(device); return B_ERROR; } @@ -746,18 +898,72 @@ usb_disk_operation(device_lun *lun, uint8 operation, uint8 opLength, } +status_t +usb_disk_operation(device_lun *lun, uint8* operation, size_t opLength, + void *data, size_t *dataLength, bool directionIn, err_act *_action) +{ + if (lun->device->is_ufi) { + return usb_disk_operation_interrupt(lun, operation, data, dataLength, + directionIn, _action); + } else { + return usb_disk_operation_bulk(lun, operation, opLength, + data, dataLength, directionIn, _action); + } +} + + // //#pragma mark - Helper/Convenience Functions // +status_t +usb_disk_send_diagnostic(device_lun *lun) +{ + uint8 commandBlock[12]; + memset(commandBlock, 0, sizeof(commandBlock)); + + commandBlock[0] = SCSI_SEND_DIAGNOSTIC; + commandBlock[1] = (lun->logical_unit_number << 5) | 4; + + status_t result = usb_disk_operation(lun, commandBlock, 6, NULL, + NULL, false); + + int retry = 100; + err_act action = err_act_ok; + while(result == B_DEV_NO_MEDIA && retry > 0) { + snooze(10000); + result = usb_disk_request_sense(lun, &action); + retry--; + } + + if (result != B_OK) + TRACE("Send Diagnostic failed: %s\n", strerror(result)); + return result; +} + + status_t usb_disk_request_sense(device_lun *lun, err_act *_action) { size_t dataLength = sizeof(scsi_request_sense_6_parameter); + uint8 commandBlock[12]; + memset(commandBlock, 0, sizeof(commandBlock)); + + commandBlock[0] = SCSI_REQUEST_SENSE_6; + commandBlock[1] = lun->logical_unit_number << 5; + commandBlock[2] = 0; // page code + commandBlock[4] = dataLength; + scsi_request_sense_6_parameter parameter; - status_t result = usb_disk_operation(lun, SCSI_REQUEST_SENSE_6, 6, 0, - dataLength, ¶meter, &dataLength, true); + status_t result = B_ERROR; + for (uint32 tries = 0; tries < 3; tries++) { + result = usb_disk_operation(lun, commandBlock, 6, ¶meter, + &dataLength, true); + if (result != B_TIMED_OUT) + break; + snooze(100000); + } if (result != B_OK) { TRACE_ALWAYS("getting request sense data failed: %s\n", strerror(result)); @@ -774,7 +980,8 @@ usb_disk_request_sense(device_lun *lun, err_act *_action) if (parameter.sense_key > SCSI_SENSE_KEY_NOT_READY && parameter.sense_key != SCSI_SENSE_KEY_UNIT_ATTENTION) { TRACE_ALWAYS("request_sense: key: 0x%02x; asc: 0x%02x; ascq: " - "0x%02x; %s\n", parameter.sense_key, parameter.additional_sense_code, + "0x%02x; %s\n", parameter.sense_key, + parameter.additional_sense_code, parameter.additional_sense_code_qualifier, label ? label : "(unknown)"); } @@ -807,10 +1014,19 @@ status_t usb_disk_mode_sense(device_lun *lun) { size_t dataLength = sizeof(scsi_mode_sense_6_parameter); + + uint8 commandBlock[12]; + memset(commandBlock, 0, sizeof(commandBlock)); + + commandBlock[0] = SCSI_MODE_SENSE_6; + commandBlock[1] = SCSI_MODE_PAGE_DEVICE_CONFIGURATION; + commandBlock[2] = 0; // Current values + commandBlock[3] = dataLength >> 8; + commandBlock[4] = dataLength; + scsi_mode_sense_6_parameter parameter; - status_t result = usb_disk_operation(lun, SCSI_MODE_SENSE_6, 6, - SCSI_MODE_PAGE_DEVICE_CONFIGURATION, dataLength, ¶meter, - &dataLength, true); + status_t result = usb_disk_operation(lun, commandBlock, 6, + ¶meter, &dataLength, true); if (result != B_OK) { TRACE_ALWAYS("getting mode sense data failed: %s\n", strerror(result)); return result; @@ -828,16 +1044,30 @@ status_t usb_disk_test_unit_ready(device_lun *lun, err_act *_action) { // if unsupported we assume the unit is fixed and therefore always ok - if (!lun->device->tur_supported) + if (lun->device->is_ufi || !lun->device->tur_supported) return B_OK; - status_t result; + status_t result = B_OK; + uint8 commandBlock[12]; + memset(commandBlock, 0, sizeof(commandBlock)); + if (lun->device->is_atapi) { - result = usb_disk_operation(lun, SCSI_START_STOP_UNIT_6, 6, 0, 1, - NULL, NULL, false, _action); + commandBlock[0] = SCSI_START_STOP_UNIT_6; + commandBlock[1] = lun->logical_unit_number << 5; + commandBlock[2] = 0; + commandBlock[3] = 0; + commandBlock[4] = 1; + + result = usb_disk_operation(lun, commandBlock, 6, NULL, NULL, false, + _action); } else { - result = usb_disk_operation(lun, SCSI_TEST_UNIT_READY_6, 6, 0, 0, - NULL, NULL, true, _action); + commandBlock[0] = SCSI_TEST_UNIT_READY_6; + commandBlock[1] = lun->logical_unit_number << 5; + commandBlock[2] = 0; + commandBlock[3] = 0; + commandBlock[4] = 0; + result = usb_disk_operation(lun, commandBlock, 6, NULL, NULL, true, + _action); } if (result == B_DEV_INVALID_IOCTL) { @@ -853,12 +1083,21 @@ status_t usb_disk_inquiry(device_lun *lun) { size_t dataLength = sizeof(scsi_inquiry_6_parameter); + + uint8 commandBlock[12]; + memset(commandBlock, 0, sizeof(commandBlock)); + + commandBlock[0] = SCSI_INQUIRY_6; + commandBlock[1] = lun->logical_unit_number << 5; + commandBlock[2] = 0; // page code + commandBlock[4] = dataLength; + scsi_inquiry_6_parameter parameter; status_t result = B_ERROR; err_act action = err_act_ok; for (uint32 tries = 0; tries < 3; tries++) { - result = usb_disk_operation(lun, SCSI_INQUIRY_6, 6, 0, dataLength, - ¶meter, &dataLength, true, &action); + result = usb_disk_operation(lun, commandBlock, 6, ¶meter, + &dataLength, true, &action); if (result == B_OK || (action != err_act_retry && action != err_act_many_retries)) { break; @@ -918,18 +1157,31 @@ usb_disk_update_capacity(device_lun *lun) status_t result = B_ERROR; err_act action = err_act_ok; + uint8 commandBlock[12]; + memset(commandBlock, 0, sizeof(commandBlock)); + + commandBlock[0] = SCSI_READ_CAPACITY_10; + commandBlock[1] = lun->logical_unit_number << 5; + // Retry reading the capacity up to three times. The first try might only // yield a unit attention telling us that the device or media status // changed, which is more or less expected if it is the first operation // on the device or the device only clears the unit atention for capacity // reads. - for (int32 i = 0; i < 3; i++) { - result = usb_disk_operation(lun, SCSI_READ_CAPACITY_10, 10, 0, 0, - ¶meter, &dataLength, true, &action); + for (int32 i = 0; i < 5; i++) { + result = usb_disk_operation(lun, commandBlock, 10, ¶meter, + &dataLength, true, &action); + if (result == B_OK || (action != err_act_retry && action != err_act_many_retries)) { break; } + + // In some cases, it's best to wait a little for the device to settle + // before retrying. + if (lun->device->is_ufi && (result == B_DEV_NO_MEDIA + || result == B_TIMED_OUT || result == B_DEV_STALLED)) + snooze(10000); } if (result != B_OK) { @@ -951,6 +1203,13 @@ usb_disk_update_capacity(device_lun *lun) status_t usb_disk_synchronize(device_lun *lun, bool force) { + if (lun->device->is_ufi) { + // UFI use interrupt because it runs all commands immediately, and + // tells us when its done. There is no cache involved in that case, + // so nothing to synchronize. + return B_UNSUPPORTED; + } + if (lun->device->sync_support == 0) { // this device reported an illegal request when syncing or repeatedly // returned an other error, it apparently does not support syncing... @@ -960,8 +1219,14 @@ usb_disk_synchronize(device_lun *lun, bool force) if (!lun->should_sync && !force) return B_OK; - status_t result = usb_disk_operation(lun, SCSI_SYNCHRONIZE_CACHE_10, 10, - 0, 0, NULL, NULL, false); + uint8 commandBlock[12]; + memset(commandBlock, 0, sizeof(commandBlock)); + + commandBlock[0] = SCSI_SYNCHRONIZE_CACHE_10; + commandBlock[1] = lun->logical_unit_number << 5; + + status_t result = usb_disk_operation(lun, commandBlock, 10, + NULL, NULL, false); if (result == B_OK) { lun->device->sync_support = SYNC_SUPPORT_RELOAD; @@ -1008,6 +1273,7 @@ usb_disk_device_added(usb_device newDevice, void **cookie) device->sync_support = SYNC_SUPPORT_RELOAD; device->tur_supported = true; device->is_atapi = false; + device->is_ufi = false; device->luns = NULL; // scan through the interfaces to find our bulk-only data interface @@ -1024,44 +1290,63 @@ usb_disk_device_added(usb_device newDevice, void **cookie) continue; if (interface->descr->interface_class == USB_MASS_STORAGE_DEVICE_CLASS - && (interface->descr->interface_subclass == 0x06 /* SCSI */ - || interface->descr->interface_subclass == 0x02 /* ATAPI */ - || interface->descr->interface_subclass == 0x05 /* ATAPI */) - && interface->descr->interface_protocol == 0x50 /* bulk-only */) { + && (((interface->descr->interface_subclass == 0x06 /* SCSI */ + || interface->descr->interface_subclass == 0x02 /* ATAPI */ + || interface->descr->interface_subclass == 0x05 /* ATAPI */) + && interface->descr->interface_protocol == 0x50 /* bulk-only */) + || (interface->descr->interface_subclass == 0x04 /* UFI */ + && interface->descr->interface_protocol == 0x00))) { bool hasIn = false; bool hasOut = false; + bool hasInt = false; for (size_t j = 0; j < interface->endpoint_count; j++) { usb_endpoint_info *endpoint = &interface->endpoint[j]; - if (endpoint == NULL - || endpoint->descr->attributes != USB_ENDPOINT_ATTR_BULK) + if (endpoint == NULL) continue; if (!hasIn && (endpoint->descr->endpoint_address - & USB_ENDPOINT_ADDR_DIR_IN) != 0) { + & USB_ENDPOINT_ADDR_DIR_IN) != 0 + && endpoint->descr->attributes == USB_ENDPOINT_ATTR_BULK) { device->bulk_in = endpoint->handle; hasIn = true; } else if (!hasOut && (endpoint->descr->endpoint_address - & USB_ENDPOINT_ADDR_DIR_IN) == 0) { + & USB_ENDPOINT_ADDR_DIR_IN) == 0 + && endpoint->descr->attributes == USB_ENDPOINT_ATTR_BULK) { device->bulk_out = endpoint->handle; hasOut = true; + } else if (!hasInt && (endpoint->descr->endpoint_address + & USB_ENDPOINT_ADDR_DIR_IN) + && endpoint->descr->attributes + == USB_ENDPOINT_ATTR_INTERRUPT) { + device->interrupt = endpoint->handle; + hasInt = true; } - if (hasIn && hasOut) + if (hasIn && hasOut && hasInt) break; } - if (!(hasIn && hasOut)) + if (!(hasIn && hasOut)) { + // Missing one of the required endpoints, try next interface continue; + } device->interface = interface->descr->interface_number; - device->is_atapi = interface->descr->interface_subclass != 0x06; + device->is_atapi = interface->descr->interface_subclass != 0x06 + && interface->descr->interface_subclass != 0x04; + device->is_ufi = interface->descr->interface_subclass == 0x04; + + if (device->is_ufi && !hasInt) { + // UFI without interrupt endpoint is not possible. + continue; + } break; } } if (device->interface == 0xff) { - TRACE_ALWAYS("no valid bulk-only interface found\n"); + TRACE_ALWAYS("no valid bulk-only or CBI interface found\n"); free(device); return B_ERROR; } @@ -1076,6 +1361,17 @@ usb_disk_device_added(usb_device newDevice, void **cookie) return result; } + if (device->is_ufi) { + device->interruptLock = create_sem(0, "usb_disk interrupt lock"); + if (device->interruptLock < B_OK) { + mutex_destroy(&device->lock); + delete_sem(device->notify); + status_t result = device->interruptLock; + free(device); + return result; + } + } + device->lun_count = usb_disk_get_max_lun(device) + 1; device->luns = (device_lun **)malloc(device->lun_count * sizeof(device_lun *)); @@ -1108,6 +1404,14 @@ usb_disk_device_added(usb_device newDevice, void **cookie) // initialize this lun result = usb_disk_inquiry(lun); + + if (device->is_ufi) { + // Reset the device + // If we don't do it all the other commands except inquiry and send + // diagnostics will be stalled. + result = usb_disk_send_diagnostic(lun); + } + err_act action = err_act_ok; for (uint32 tries = 0; tries < 8; tries++) { TRACE("usb lun %" B_PRIu8 " inquiry attempt %" B_PRIu32 " begin\n", @@ -1231,9 +1535,43 @@ static status_t usb_disk_block_read(device_lun *lun, uint32 blockPosition, uint16 blockCount, void *buffer, size_t *length) { - status_t result = usb_disk_operation(lun, SCSI_READ_10, 10, blockPosition, - blockCount, buffer, length, true); - return result; + uint8 commandBlock[12]; + memset(commandBlock, 0, sizeof(commandBlock)); + if (lun->device->is_ufi) { + commandBlock[0] = SCSI_READ_12; + commandBlock[1] = lun->logical_unit_number << 5; + commandBlock[2] = blockPosition >> 24; + commandBlock[3] = blockPosition >> 16; + commandBlock[4] = blockPosition >> 8; + commandBlock[5] = blockPosition; + commandBlock[6] = 0; // blockCount >> 24; + commandBlock[7] = 0; // blockCount >> 16; + commandBlock[8] = blockCount >> 8; + commandBlock[9] = blockCount; + + status_t result = B_OK; + for (int tries = 0; tries < 5; tries++) { + result = usb_disk_operation(lun, commandBlock, 12, buffer, length, + true); + if (result == B_OK) + break; + else + snooze(10000); + } + return result; + } else { + commandBlock[0] = SCSI_READ_10; + commandBlock[1] = 0; + commandBlock[2] = blockPosition >> 24; + commandBlock[3] = blockPosition >> 16; + commandBlock[4] = blockPosition >> 8; + commandBlock[5] = blockPosition; + commandBlock[7] = blockCount >> 8; + commandBlock[8] = blockCount; + status_t result = usb_disk_operation(lun, commandBlock, 10, + buffer, length, true); + return result; + } } @@ -1241,11 +1579,50 @@ static status_t usb_disk_block_write(device_lun *lun, uint32 blockPosition, uint16 blockCount, void *buffer, size_t *length) { - status_t result = usb_disk_operation(lun, SCSI_WRITE_10, 10, blockPosition, - blockCount, buffer, length, false); - if (result == B_OK) - lun->should_sync = true; - return result; + uint8 commandBlock[12]; + memset(commandBlock, 0, sizeof(commandBlock)); + + if (lun->device->is_ufi) { + commandBlock[0] = SCSI_WRITE_12; + commandBlock[1] = lun->logical_unit_number << 5; + commandBlock[2] = blockPosition >> 24; + commandBlock[3] = blockPosition >> 16; + commandBlock[4] = blockPosition >> 8; + commandBlock[5] = blockPosition; + commandBlock[6] = blockCount >> 24; + commandBlock[7] = blockCount >> 16; + commandBlock[8] = blockCount >> 8; + commandBlock[9] = blockCount; + + status_t result; + result = usb_disk_operation(lun, commandBlock, 12, buffer, length, + false); + + int retry = 10; + err_act action = err_act_ok; + while (result == B_DEV_NO_MEDIA && retry > 0) { + snooze(10000); + result = usb_disk_request_sense(lun, &action); + retry--; + } + + if (result == B_OK) + lun->should_sync = true; + return result; + } else { + commandBlock[0] = SCSI_WRITE_10; + commandBlock[2] = blockPosition >> 24; + commandBlock[3] = blockPosition >> 16; + commandBlock[4] = blockPosition >> 8; + commandBlock[5] = blockPosition; + commandBlock[7] = blockCount >> 8; + commandBlock[8] = blockCount; + status_t result = usb_disk_operation(lun, commandBlock, 10, + buffer, length, false); + if (result == B_OK) + lun->should_sync = true; + return result; + } } @@ -1403,6 +1780,19 @@ usb_disk_ioctl(void *cookie, uint32 op, void *buffer, size_t length) status_t result = B_DEV_INVALID_IOCTL; switch (op) { + case B_GET_DEVICE_SIZE: { + if (lun->media_changed) { + result = usb_disk_update_capacity(lun); + if (result != B_OK) + break; + } + + size_t size = lun->block_size * lun->block_count; + result = user_memcpy(buffer, &size, sizeof(size)); + + break; + } + case B_GET_MEDIA_STATUS: { err_act action = err_act_ok; @@ -1451,14 +1841,32 @@ usb_disk_ioctl(void *cookie, uint32 op, void *buffer, size_t length) break; case B_EJECT_DEVICE: - result = usb_disk_operation(lun, SCSI_START_STOP_UNIT_6, 6, 0, 2, - NULL, NULL, false); + { + uint8 commandBlock[12]; + memset(commandBlock, 0, sizeof(commandBlock)); + + commandBlock[0] = SCSI_START_STOP_UNIT_6; + commandBlock[1] = lun->logical_unit_number << 5; + commandBlock[4] = 2; + + result = usb_disk_operation(lun, commandBlock, 6, NULL, NULL, + false); break; + } case B_LOAD_MEDIA: - result = usb_disk_operation(lun, SCSI_START_STOP_UNIT_6, 6, 0, 3, - NULL, NULL, false); + { + uint8 commandBlock[12]; + memset(commandBlock, 0, sizeof(commandBlock)); + + commandBlock[0] = SCSI_START_STOP_UNIT_6; + commandBlock[1] = lun->logical_unit_number << 5; + commandBlock[4] = 3; + + result = usb_disk_operation(lun, commandBlock, 6, NULL, NULL, + false); break; + } case B_GET_ICON: // We don't support this legacy ioctl anymore, but the two other @@ -1471,6 +1879,10 @@ usb_disk_ioctl(void *cookie, uint32 op, void *buffer, size_t length) char vendor[sizeof(lun->vendor_name)+1]; char product[sizeof(lun->product_name)+1]; + if (device->is_ufi) { + iconName = "devices/drive-floppy-usb"; + } + switch (lun->device_type) { case B_CD: case B_OPTICAL: @@ -1509,27 +1921,34 @@ usb_disk_ioctl(void *cookie, uint32 op, void *buffer, size_t length) break; } - switch (lun->device_type) { - case B_CD: - case B_OPTICAL: - icon = &kCDIconData; - break; - case B_TAPE: // TODO - default: - snprintf(vendor, sizeof(vendor), "%.8s", - lun->vendor_name); - snprintf(product, sizeof(product), "%.16s", - lun->product_name); - for (int i = 0; kIconMatches[i].icon; i++) { - if (kIconMatches[i].vendor != NULL - && strstr(vendor, kIconMatches[i].vendor) == NULL) - continue; - if (kIconMatches[i].product != NULL - && strstr(product, kIconMatches[i].product) == NULL) - continue; - icon = kIconMatches[i].icon; - } - break; + if (device->is_ufi) { + // UFI is specific for floppy drives + icon = &kFloppyIconData; + } else { + switch (lun->device_type) { + case B_CD: + case B_OPTICAL: + icon = &kCDIconData; + break; + case B_TAPE: // TODO + default: + snprintf(vendor, sizeof(vendor), "%.8s", + lun->vendor_name); + snprintf(product, sizeof(product), "%.16s", + lun->product_name); + for (int i = 0; kIconMatches[i].icon; i++) { + if (kIconMatches[i].vendor != NULL + && strstr(vendor, + kIconMatches[i].vendor) == NULL) + continue; + if (kIconMatches[i].product != NULL + && strstr(product, + kIconMatches[i].product) == NULL) + continue; + icon = kIconMatches[i].icon; + } + break; + } } device_icon iconData; @@ -1704,7 +2123,8 @@ init_driver() static usb_support_descriptor supportedDevices[] = { { 0x08 /* mass storage */, 0x06 /* SCSI */, 0x50 /* bulk */, 0, 0 }, { 0x08 /* mass storage */, 0x02 /* ATAPI */, 0x50 /* bulk */, 0, 0 }, - { 0x08 /* mass storage */, 0x05 /* ATAPI */, 0x50 /* bulk */, 0, 0 } + { 0x08 /* mass storage */, 0x05 /* ATAPI */, 0x50 /* bulk */, 0, 0 }, + { 0x08 /* mass storage */, 0x04 /* UFI */, 0x00, 0, 0 } }; gDeviceList = NULL; @@ -1721,7 +2141,7 @@ init_driver() return result; } - gUSBModule->register_driver(DRIVER_NAME, supportedDevices, 3, NULL); + gUSBModule->register_driver(DRIVER_NAME, supportedDevices, 4, NULL); gUSBModule->install_notify(DRIVER_NAME, ¬ifyHooks); return B_OK; } diff --git a/src/add-ons/kernel/drivers/disk/usb/usb_disk/usb_disk.h b/src/add-ons/kernel/drivers/disk/usb/usb_disk/usb_disk.h index 85b2bf9878..8008032251 100644 --- a/src/add-ons/kernel/drivers/disk/usb/usb_disk/usb_disk.h +++ b/src/add-ons/kernel/drivers/disk/usb/usb_disk/usb_disk.h @@ -14,6 +14,8 @@ #include +#define REQUEST_MASS_STORAGE_RESET 0xff +#define REQUEST_GET_MAX_LUN 0xfe #define MAX_LOGICAL_UNIT_NUMBER 15 #define ATAPI_COMMAND_LENGTH 12 @@ -33,17 +35,23 @@ typedef struct disk_device_s { // device state usb_pipe bulk_in; usb_pipe bulk_out; + usb_pipe interrupt; uint8 interface; uint32 current_tag; uint8 sync_support; bool tur_supported; bool is_atapi; + bool is_ufi; // used to store callback information sem_id notify; status_t status; size_t actual_length; + // used to store interrupt result + unsigned char interruptBuffer[2]; + sem_id interruptLock; + // logical units of this device uint8 lun_count; device_lun **luns; @@ -72,4 +80,10 @@ struct device_lun_s { }; +typedef struct interrupt_status_wrapper_s { + uint8 status; + uint8 misc; +} _PACKED interrupt_status_wrapper; + + #endif // _USB_DISK_H_ diff --git a/src/add-ons/kernel/drivers/disk/usb/usb_disk/usb_disk_scsi.h b/src/add-ons/kernel/drivers/disk/usb/usb_disk/usb_disk_scsi.h index f5306a89ff..413e907793 100644 --- a/src/add-ons/kernel/drivers/disk/usb/usb_disk/usb_disk_scsi.h +++ b/src/add-ons/kernel/drivers/disk/usb/usb_disk/usb_disk_scsi.h @@ -15,10 +15,13 @@ typedef enum { SCSI_INQUIRY_6 = 0x12, SCSI_MODE_SENSE_6 = 0x1a, SCSI_START_STOP_UNIT_6 = 0x1b, + SCSI_SEND_DIAGNOSTIC = 0x1d, SCSI_READ_CAPACITY_10 = 0x25, SCSI_READ_10 = 0x28, SCSI_WRITE_10 = 0x2a, SCSI_SYNCHRONIZE_CACHE_10 = 0x35, + SCSI_READ_12 = 0xA8, + SCSI_WRITE_12 = 0xAA, } scsi_operations; // common command structures diff --git a/src/add-ons/kernel/drivers/disk/usb/usb_floppy/Jamfile b/src/add-ons/kernel/drivers/disk/usb/usb_floppy/Jamfile deleted file mode 100644 index 6a6fb515c2..0000000000 --- a/src/add-ons/kernel/drivers/disk/usb/usb_floppy/Jamfile +++ /dev/null @@ -1,8 +0,0 @@ -SubDir HAIKU_TOP src add-ons kernel drivers disk usb usb_floppy ; - -SubDirSysHdrs $(HAIKU_TOP) src add-ons kernel bus_managers usb ; -UsePrivateKernelHeaders ; - -KernelAddon usb_floppy : - usb_disk.cpp - ; diff --git a/src/add-ons/kernel/drivers/disk/usb/usb_floppy/usb_disk.cpp b/src/add-ons/kernel/drivers/disk/usb/usb_floppy/usb_disk.cpp deleted file mode 100644 index c0d9641ecc..0000000000 --- a/src/add-ons/kernel/drivers/disk/usb/usb_floppy/usb_disk.cpp +++ /dev/null @@ -1,1395 +0,0 @@ -/* - * Copyright 2008-2009, Haiku Inc. All rights reserved. - * Distributed under the terms of the MIT License. - * - * Authors: - * Michael Lotz - */ - -#include -#include -#include -#include -#include -#include -#include "usb_disk.h" -#include "usb_disk_scsi.h" - - -#define DRIVER_NAME "usb_floppy" -#define DEVICE_NAME_BASE "disk/ufi/" -#define DEVICE_NAME DEVICE_NAME_BASE "%" B_PRId32 "/%d/raw" - - -//#define TRACE_USB_DISK -#ifdef TRACE_USB_DISK -#define TRACE(x...) dprintf("\x1B[35m" DRIVER_NAME "\x1B[0m: " x) -#define TRACE_ALWAYS(x...) dprintf("\x1B[35m" DRIVER_NAME "\x1B[0m: " x) -#else -#define TRACE(x...) /* nothing */ -#define TRACE_ALWAYS(x...) dprintf("\x1B[35m" DRIVER_NAME "\x1B[0m: " x) -#endif - - -int32 api_version = B_CUR_DRIVER_API_VERSION; -static usb_module_info *gUSBModule = NULL; -static disk_device *gDeviceList = NULL; -static uint32 gDeviceCount = 0; -static uint32 gLunCount = 0; -static mutex gDeviceListLock; -static char **gDeviceNames = NULL; - -static const uint8 kDeviceIcon[] = { - 0x6e, 0x63, 0x69, 0x66, 0x0d, 0x03, 0x01, 0x00, 0x00, 0x01, 0x01, 0x00, - 0x00, 0x6a, 0x02, 0x00, 0x16, 0x02, 0x38, 0x6a, 0xad, 0x38, 0xeb, 0x7a, - 0xbb, 0x77, 0x73, 0x3a, 0xde, 0x88, 0x48, 0xce, 0xdc, 0x4a, 0x75, 0xed, - 0x00, 0x7a, 0xff, 0x4b, 0x02, 0x00, 0x16, 0x02, 0x38, 0x6a, 0xad, 0x38, - 0xeb, 0x7a, 0xbb, 0x77, 0x73, 0x3a, 0xde, 0x88, 0x48, 0xce, 0xdc, 0x4a, - 0x75, 0xed, 0x00, 0x8a, 0xff, 0x2c, 0x05, 0x7d, 0x02, 0x00, 0x16, 0x02, - 0x39, 0xc6, 0x30, 0x36, 0xa8, 0x1b, 0xb9, 0x51, 0xe6, 0x3c, 0x5b, 0xb3, - 0x4b, 0x4d, 0xa8, 0x4a, 0x1a, 0xa1, 0x00, 0x3a, 0xff, 0x5d, 0x02, 0x00, - 0x16, 0x02, 0xb7, 0x16, 0xa4, 0xba, 0x87, 0xfe, 0x3c, 0xb2, 0x07, 0xb9, - 0x49, 0xed, 0x48, 0x87, 0xd8, 0x4a, 0x1e, 0x62, 0x01, 0x75, 0xfe, 0xc4, - 0x02, 0x00, 0x16, 0x02, 0xb7, 0x16, 0xa4, 0xba, 0x87, 0xfe, 0x3c, 0xb2, - 0x07, 0xb9, 0x49, 0xed, 0x48, 0x87, 0xd8, 0x4a, 0x1e, 0x62, 0x00, 0x5c, - 0xfe, 0x9b, 0x02, 0x00, 0x16, 0x05, 0x36, 0xef, 0x60, 0x38, 0xe2, 0xe5, - 0xbd, 0x22, 0x41, 0x3b, 0x2f, 0xce, 0x4a, 0x0e, 0x78, 0x4a, 0x5a, 0x6c, - 0x00, 0xb8, 0x38, 0xe6, 0x77, 0xb8, 0xbd, 0xd2, 0xff, 0x93, 0x02, 0x00, - 0x16, 0x05, 0x34, 0x0a, 0x8f, 0x38, 0xd2, 0xa2, 0xba, 0xb4, 0xc5, 0x35, - 0xe9, 0xec, 0x49, 0xfd, 0x24, 0x4a, 0x64, 0x62, 0x00, 0xe1, 0x38, 0xff, - 0x75, 0xd7, 0xba, 0xf3, 0xfd, 0xd0, 0x02, 0x00, 0x16, 0x02, 0x36, 0x67, - 0xbe, 0x39, 0xdd, 0xbc, 0xbe, 0x50, 0x04, 0x3a, 0xe0, 0x9f, 0x4b, 0x85, - 0x01, 0x49, 0x2a, 0x3f, 0x00, 0xff, 0xff, 0xd8, 0x03, 0x38, 0x6d, 0xbe, - 0x02, 0x00, 0x16, 0x02, 0x3c, 0x40, 0xef, 0x3b, 0x82, 0xd1, 0xba, 0xeb, - 0x42, 0x3b, 0xbf, 0x4d, 0x4a, 0xa7, 0xce, 0x49, 0x5d, 0xc1, 0xff, 0x01, - 0x00, 0x4a, 0x12, 0x0a, 0x05, 0x44, 0x5a, 0x44, 0x40, 0x5e, 0x40, 0x5f, - 0x45, 0x49, 0x5a, 0x0a, 0x06, 0x45, 0x58, 0x5c, 0x42, 0x5c, 0x40, 0x3d, - 0x34, 0xb5, 0x6b, 0xc2, 0x2e, 0xb5, 0x63, 0xc3, 0xbb, 0x0a, 0x04, 0x44, - 0x58, 0x26, 0x4a, 0x26, 0x47, 0x44, 0x54, 0x0a, 0x04, 0x44, 0x59, 0x5c, - 0x42, 0x5c, 0x3e, 0x44, 0x54, 0x0a, 0x05, 0x44, 0x56, 0x5c, 0x40, 0x3d, - 0x34, 0xb5, 0x6b, 0xc2, 0x2e, 0xb5, 0x43, 0xc3, 0x3b, 0x0a, 0x04, 0x2a, - 0x4c, 0x3f, 0x56, 0x3f, 0x53, 0x2a, 0x4a, 0x0a, 0x04, 0x2a, 0x4b, 0x39, - 0x52, 0x39, 0x50, 0x2a, 0x4a, 0x0a, 0x04, 0x31, 0x42, 0x45, 0x4c, 0x3f, - 0x53, 0x2a, 0x4a, 0x0a, 0x04, 0x3f, 0x49, 0x38, 0x50, 0x2a, 0x4a, 0x31, - 0x43, 0x0a, 0x04, 0x3f, 0x36, 0x57, 0x3e, 0x49, 0x4b, 0x32, 0x40, 0x08, - 0x02, 0x3c, 0x3b, 0x4d, 0x43, 0x00, 0x02, 0x3b, 0x3b, 0x31, 0x36, 0x43, - 0x3f, 0x48, 0x3d, 0x3f, 0x36, 0xc4, 0x82, 0xbf, 0xc7, 0x00, 0x02, 0x3e, - 0x3c, 0xbc, 0x58, 0xbd, 0x93, 0x47, 0x3e, 0x45, 0x44, 0x3d, 0x43, 0x4d, - 0x45, 0x02, 0x04, 0x39, 0x3b, 0x39, 0x3d, 0x39, 0x39, 0x3c, 0x38, 0x3b, - 0x38, 0x3e, 0x38, 0x3e, 0x3a, 0x3f, 0x3a, 0x41, 0x37, 0x3c, 0x3d, 0x3c, - 0x42, 0x3c, 0x40, 0x02, 0x04, 0x46, 0x3c, 0x46, 0x3e, 0x46, 0x3a, 0x48, - 0x3a, 0x46, 0x3a, 0x4a, 0x3a, 0x4a, 0x3c, 0x4a, 0x3a, 0x4a, 0x3e, 0x48, - 0x3e, 0x4a, 0x3e, 0x46, 0x3e, 0x0a, 0x04, 0x45, 0x42, 0x42, 0x45, 0x45, - 0x47, 0x48, 0x44, 0x0a, 0x03, 0x4e, 0x43, 0x4d, 0x3f, 0x48, 0x44, 0x0a, - 0x04, 0x32, 0x4b, 0x36, 0x48, 0x32, 0x46, 0x2e, 0x4a, 0x0d, 0x0a, 0x01, - 0x01, 0x00, 0x20, 0x1e, 0x20, 0x0a, 0x00, 0x01, 0x01, 0x30, 0x1e, 0x20, - 0x01, 0x17, 0x84, 0x00, 0x04, 0x0a, 0x02, 0x01, 0x02, 0x20, 0x1e, 0x20, - 0x0a, 0x05, 0x01, 0x03, 0x20, 0x1e, 0x20, 0x0a, 0x06, 0x01, 0x04, 0x20, - 0x1e, 0x20, 0x0a, 0x03, 0x01, 0x05, 0x20, 0x1e, 0x20, 0x0a, 0x07, 0x01, - 0x07, 0x20, 0x1e, 0x20, 0x0a, 0x08, 0x01, 0x06, 0x20, 0x1e, 0x20, 0x0a, - 0x09, 0x01, 0x08, 0x20, 0x1e, 0x20, 0x0a, 0x0a, 0x01, 0x09, 0x20, 0x1e, - 0x20, 0x0a, 0x0c, 0x03, 0x0a, 0x0b, 0x0c, 0x1a, 0x40, 0x1d, 0x05, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x9d, 0xc9, 0xc2, 0x91, 0x98, 0x43, - 0x6d, 0xc2, 0x20, 0xff, 0x01, 0x17, 0x81, 0x00, 0x04, 0x0a, 0x0c, 0x04, - 0x0d, 0x0e, 0x0f, 0x10, 0x0a, 0x3f, 0xff, 0xbd, 0x34, 0xaf, 0xbc, 0xb4, - 0xe0, 0x2c, 0x3f, 0xbc, 0x62, 0x3e, 0x74, 0x62, 0x41, 0xfe, 0xe7, 0x20, - 0xff, 0x0a, 0x02, 0x01, 0x11, 0x20, 0x1e, 0x20 -}; - - -// -//#pragma mark - Forward Declarations -// - - -static void usb_disk_callback(void *cookie, status_t status, void *data, - size_t actualLength); - -status_t usb_disk_mass_storage_reset(disk_device *device); -uint8 usb_disk_get_max_lun(disk_device *device); -void usb_disk_reset_recovery(disk_device *device); -status_t usb_disk_transfer_data(disk_device *device, bool directionIn, - void *data, size_t dataLength); -status_t usb_disk_receive_csw(disk_device *device, - command_status_wrapper *status); -status_t usb_disk_operation(device_lun *lun, uint8* operation, - void *data, size_t *dataLength, - bool directionIn); - -status_t usb_disk_send_diagnostic(device_lun *lun); -status_t usb_disk_request_sense(device_lun *lun); -status_t usb_disk_mode_sense(device_lun *lun); -status_t usb_disk_test_unit_ready(device_lun *lun); -status_t usb_disk_inquiry(device_lun *lun); -status_t usb_disk_reset_capacity(device_lun *lun); -status_t usb_disk_update_capacity(device_lun *lun); -status_t usb_disk_synchronize(device_lun *lun, bool force); - - -// -//#pragma mark - Device Allocation Helper Functions -// - - -void -usb_disk_free_device_and_luns(disk_device *device) -{ - mutex_lock(&device->lock); - mutex_destroy(&device->lock); - delete_sem(device->notify); - delete_sem(device->interruptLock); - for (uint8 i = 0; i < device->lun_count; i++) - free(device->luns[i]); - free(device->luns); - free(device); -} - - -// -//#pragma mark - Bulk-only Mass Storage Functions -// - - -void -usb_disk_reset_recovery(disk_device *device) -{ - gUSBModule->clear_feature(device->bulk_in, USB_FEATURE_ENDPOINT_HALT); - gUSBModule->clear_feature(device->bulk_out, USB_FEATURE_ENDPOINT_HALT); - gUSBModule->clear_feature(device->interrupt, USB_FEATURE_ENDPOINT_HALT); -} - - -status_t -usb_disk_transfer_data(disk_device *device, bool directionIn, void *data, - size_t dataLength) -{ - status_t result = gUSBModule->queue_bulk(directionIn ? device->bulk_in - : device->bulk_out, data, dataLength, usb_disk_callback, device); - if (result != B_OK) { - TRACE_ALWAYS("failed to queue data transfer\n"); - return result; - } - - do { - result = acquire_sem_etc(device->notify, 1, B_RELATIVE_TIMEOUT, - 10 * 1000 * 1000); - if (result == B_TIMED_OUT) { - // Cancel the transfer and collect the sem that should now be - // released through the callback on cancel. Handling of device - // reset is done in usb_disk_operation() when it detects that - // the transfer failed. - gUSBModule->cancel_queued_transfers(directionIn ? device->bulk_in - : device->bulk_out); - acquire_sem_etc(device->notify, 1, B_RELATIVE_TIMEOUT, 0); - } - } while (result == B_INTERRUPTED); - - if (result != B_OK) { - TRACE_ALWAYS("acquire_sem failed while waiting for data transfer\n"); - return result; - } - - return B_OK; -} - - -void -usb_disk_interrupt(void* cookie, int32 status, void* data, size_t length) -{ - disk_device* dev = (disk_device*)cookie; - // We release the lock even if the interrupt is invalid. This way there - // is at least a chance for the driver to terminate properly. - release_sem(dev->interruptLock); - - if (length != 2) { - TRACE_ALWAYS("interrupt of length %" B_PRIuSIZE "! (expected 2)\n", - length); - // In this case we do not reschedule the interrupt. This means the - // driver will be locked. The interrupt should perhaps be scheduled - // when starting a transfer instead. But getting there means something - // is really broken, so... - return; - } - - // Reschedule the interrupt for next time - gUSBModule->queue_interrupt(dev->interrupt, dev->interruptBuffer, 2, - usb_disk_interrupt, cookie); -} - - -status_t -usb_disk_receive_csw(disk_device *device, command_status_wrapper *status) -{ - TRACE("Waiting for result...\n"); - gUSBModule->queue_interrupt(device->interrupt, - device->interruptBuffer, 2, usb_disk_interrupt, device); - - acquire_sem(device->interruptLock); - - status->status = device->interruptBuffer[0]; - status->misc = device->interruptBuffer[1]; - - return B_OK; -} - - -status_t -usb_disk_operation(device_lun *lun, uint8* operation, - void *data, size_t *dataLength, bool directionIn) -{ - // TODO: remove transferLength - TRACE("operation: lun: %u; op: 0x%x; data: %p; dlen: %p (%lu); in: %c\n", - lun->logical_unit_number, operation[0], data, dataLength, - dataLength ? *dataLength : 0, directionIn ? 'y' : 'n'); - - disk_device* device = lun->device; - - // Step 1 : send the SCSI operation as a class specific request - size_t actualLength = 12; - status_t result = gUSBModule->send_request(device->device, - USB_REQTYPE_CLASS | USB_REQTYPE_INTERFACE_OUT, 0 /*request*/, 0/*value*/, - device->interface/*index*/, 12, operation, &actualLength); - - if (result != B_OK || actualLength != 12) { - TRACE("Command stage: wrote %ld bytes (error: %s)\n", - actualLength, strerror(result)); - - // There was an error, we have to do a request sense to reset the device - if (operation[0] != SCSI_REQUEST_SENSE_6) { - usb_disk_request_sense(lun); - } - return result; - } - - // Step 2 : data phase : send or receive data - size_t transferedData = 0; - if (data != NULL && dataLength != NULL && *dataLength > 0) { - // we have data to transfer in a data stage - result = usb_disk_transfer_data(device, directionIn, data, *dataLength); - if (result != B_OK) { - TRACE("Error %s in data phase\n", strerror(result)); - return result; - } - - transferedData = device->actual_length; - if (device->status != B_OK || transferedData != *dataLength) { - // sending or receiving of the data failed - if (device->status == B_DEV_STALLED) { - TRACE("stall while transfering data\n"); - gUSBModule->clear_feature(directionIn ? device->bulk_in - : device->bulk_out, USB_FEATURE_ENDPOINT_HALT); - } else { - TRACE_ALWAYS("sending or receiving of the data failed\n"); - usb_disk_reset_recovery(device); - return B_ERROR; - } - } - } - - // step 3 : wait for the device to send the interrupt ACK - if (operation[0] != SCSI_REQUEST_SENSE_6) { - command_status_wrapper status; - result = usb_disk_receive_csw(device, &status); - if (result != B_OK) { - // in case of a stall or error clear the stall and try again - TRACE("Error receiving interrupt: %s. Retrying...\n", strerror(result)); - gUSBModule->clear_feature(device->bulk_in, USB_FEATURE_ENDPOINT_HALT); - result = usb_disk_receive_csw(device, &status); - } - - if (result != B_OK) { - TRACE_ALWAYS("receiving the command status interrupt failed\n"); - usb_disk_reset_recovery(device); - return result; - } - - // wait for the device to finish the operation. - result = usb_disk_request_sense(lun); - } - return result; -} - - -// -//#pragma mark - Helper/Convenience Functions -// - - -status_t -usb_disk_send_diagnostic(device_lun *lun) -{ - uint8 commandBlock[12]; - memset(commandBlock, 0, sizeof(commandBlock)); - - commandBlock[0] = SCSI_SEND_DIAGNOSTIC; - commandBlock[1] = (lun->logical_unit_number << 5) | 4; - - status_t result = usb_disk_operation(lun, commandBlock, NULL, - NULL, false); - - int retry = 100; - while(result == B_DEV_NO_MEDIA && retry > 0) { - snooze(10000); - result = usb_disk_request_sense(lun); - retry--; - } - - if (result != B_OK) - TRACE("Send Diagnostic failed: %s\n", strerror(result)); - return result; -} - - -status_t -usb_disk_request_sense(device_lun *lun) -{ - size_t dataLength = sizeof(scsi_request_sense_6_parameter); - uint8 commandBlock[12]; - memset(commandBlock, 0, sizeof(commandBlock)); - - commandBlock[0] = SCSI_REQUEST_SENSE_6; - commandBlock[1] = lun->logical_unit_number << 5; - commandBlock[2] = 0; // page code - commandBlock[4] = dataLength; - - scsi_request_sense_6_parameter parameter; - status_t result = usb_disk_operation(lun, commandBlock, ¶meter, - &dataLength, true); - if (result != B_OK) { - TRACE_ALWAYS("getting request sense data failed\n"); - return result; - } - - if (parameter.sense_key > SCSI_SENSE_KEY_NOT_READY - && parameter.sense_key != SCSI_SENSE_KEY_UNIT_ATTENTION) { - TRACE_ALWAYS("request_sense: key: 0x%02x; asc: 0x%02x; ascq: 0x%02x;\n", - parameter.sense_key, parameter.additional_sense_code, - parameter.additional_sense_code_qualifier); - } - - switch (parameter.sense_key) { - case SCSI_SENSE_KEY_NO_SENSE: - case SCSI_SENSE_KEY_RECOVERED_ERROR: - return B_OK; - - case SCSI_SENSE_KEY_HARDWARE_ERROR: - case SCSI_SENSE_KEY_MEDIUM_ERROR: - TRACE_ALWAYS("request_sense: media or hardware error\n"); - return B_DEV_UNREADABLE; - - case SCSI_SENSE_KEY_ILLEGAL_REQUEST: - TRACE_ALWAYS("request_sense: illegal request\n"); - return B_DEV_INVALID_IOCTL; - - case SCSI_SENSE_KEY_UNIT_ATTENTION: - if (parameter.additional_sense_code != SCSI_ASC_MEDIUM_NOT_PRESENT) { - TRACE_ALWAYS("request_sense: media changed\n"); - lun->media_changed = true; - lun->media_present = true; - return B_DEV_MEDIA_CHANGED; - } - // fall through - - case SCSI_SENSE_KEY_NOT_READY: - TRACE("request_sense: device not ready (asc 0x%02x ascq 0x%02x)\n", - parameter.additional_sense_code, - parameter.additional_sense_code_qualifier); - lun->media_present = false; - usb_disk_reset_capacity(lun); - return B_DEV_NO_MEDIA; - - case SCSI_SENSE_KEY_DATA_PROTECT: - TRACE_ALWAYS("request_sense: write protected\n"); - return B_READ_ONLY_DEVICE; - - case SCSI_SENSE_KEY_ABORTED_COMMAND: - TRACE_ALWAYS("request_sense: command aborted\n"); - return B_CANCELED; - } - - return B_ERROR; -} - - -status_t -usb_disk_mode_sense(device_lun *lun) -{ - size_t dataLength = sizeof(scsi_mode_sense_6_parameter); - - uint8 commandBlock[12]; - memset(commandBlock, 0, sizeof(commandBlock)); - - commandBlock[0] = SCSI_MODE_SENSE_6; - commandBlock[1] = lun->logical_unit_number << 5; - commandBlock[2] = 0; // Current values - commandBlock[7] = dataLength >> 8; - commandBlock[8] = dataLength; - - scsi_mode_sense_6_parameter parameter; - status_t result = usb_disk_operation(lun, commandBlock, - ¶meter, &dataLength, true); - if (result != B_OK) { - TRACE_ALWAYS("getting mode sense data failed\n"); - return result; - } - - lun->write_protected - = (parameter.device_specific & SCSI_DEVICE_SPECIFIC_WRITE_PROTECT) != 0; - TRACE_ALWAYS("write protected: %s\n", lun->write_protected ? "yes" : "no"); - return B_OK; -} - - -status_t -usb_disk_test_unit_ready(device_lun *lun) -{ - return B_OK; - - uint8 commandBlock[12]; - memset(commandBlock, 0, sizeof(commandBlock)); - - commandBlock[0] = SCSI_TEST_UNIT_READY_6; - commandBlock[1] = lun->logical_unit_number << 5; - - status_t result = usb_disk_operation(lun, commandBlock, NULL, NULL, false); - - return result; -} - - -status_t -usb_disk_inquiry(device_lun *lun) -{ - size_t dataLength = sizeof(scsi_inquiry_6_parameter); - - uint8 commandBlock[12]; - memset(commandBlock, 0, sizeof(commandBlock)); - - commandBlock[0] = SCSI_INQUIRY_6; - commandBlock[1] = lun->logical_unit_number << 5; - commandBlock[2] = 0; // page code - commandBlock[4] = dataLength; - - scsi_inquiry_6_parameter parameter; - status_t result = B_ERROR; - for (uint32 tries = 0; tries < 3; tries++) { - result = usb_disk_operation(lun, commandBlock, ¶meter, &dataLength, - true); - if (result == B_OK) - break; - } - if (result != B_OK) { - TRACE_ALWAYS("getting inquiry data failed\n"); - lun->device_type = B_DISK; - lun->removable = true; - return result; - } - - TRACE("peripherial_device_type 0x%02x\n", - parameter.peripherial_device_type); - TRACE("peripherial_qualifier 0x%02x\n", - parameter.peripherial_qualifier); - TRACE("removable_medium %s\n", - parameter.removable_medium ? "yes" : "no"); - TRACE("version 0x%02x\n", parameter.version); - TRACE("response_data_format 0x%02x\n", parameter.response_data_format); - TRACE_ALWAYS("vendor_identification \"%.8s\"\n", - parameter.vendor_identification); - TRACE_ALWAYS("product_identification \"%.16s\"\n", - parameter.product_identification); - TRACE_ALWAYS("product_revision_level \"%.4s\"\n", - parameter.product_revision_level); - - memcpy(lun->vendor_name, parameter.vendor_identification, - MIN(sizeof(lun->vendor_name), sizeof(parameter.vendor_identification))); - memcpy(lun->product_name, parameter.product_identification, - MIN(sizeof(lun->product_name), - sizeof(parameter.product_identification))); - memcpy(lun->product_revision, parameter.product_revision_level, - MIN(sizeof(lun->product_revision), - sizeof(parameter.product_revision_level))); - - lun->device_type = parameter.peripherial_device_type; /* 1:1 mapping */ - lun->removable = (parameter.removable_medium == 1); - return B_OK; -} - - -status_t -usb_disk_reset_capacity(device_lun *lun) -{ - lun->block_size = 512; - lun->block_count = 0; - return B_OK; -} - - -status_t -usb_disk_update_capacity(device_lun *lun) -{ - size_t dataLength = sizeof(scsi_read_capacity_10_parameter); - scsi_read_capacity_10_parameter parameter; - status_t result = B_ERROR; - - uint8 commandBlock[12]; - memset(commandBlock, 0, sizeof(commandBlock)); - - commandBlock[0] = SCSI_READ_CAPACITY_10; - commandBlock[1] = lun->logical_unit_number << 5; - - for (int tries = 0; tries < 5; tries++) { - result = usb_disk_operation(lun, commandBlock, ¶meter, &dataLength, - true); - if (result == B_DEV_NO_MEDIA || result == B_TIMED_OUT - || result == B_DEV_STALLED) - snooze(10000); - else - break; - } - - if (result != B_OK) { - TRACE_ALWAYS("failed to update capacity\n"); - lun->media_present = false; - lun->media_changed = false; - usb_disk_reset_capacity(lun); - return result; - } - - lun->media_present = true; - lun->media_changed = false; - lun->block_size = ntohl(parameter.logical_block_length); - lun->block_count = ntohl(parameter.last_logical_block_address) + 1; - return B_OK; -} - - -status_t -usb_disk_synchronize(device_lun *lun, bool force) -{ - return B_UNSUPPORTED; -} - - -// -//#pragma mark - Device Attach/Detach Notifications and Callback -// - - -static void -usb_disk_callback(void *cookie, status_t status, void *data, - size_t actualLength) -{ - //TRACE("callback()\n"); - disk_device *device = (disk_device *)cookie; - device->status = status; - device->actual_length = actualLength; - release_sem(device->notify); -} - - -static status_t -usb_disk_device_added(usb_device newDevice, void **cookie) -{ - TRACE("device_added(0x%08lx)\n", newDevice); - disk_device *device = (disk_device *)malloc(sizeof(disk_device)); - device->device = newDevice; - device->removed = false; - device->open_count = 0; - device->interface = 0xff; - device->current_tag = 0; - device->sync_support = SYNC_SUPPORT_RELOAD; - device->is_atapi = false; - device->luns = NULL; - - // scan through the interfaces to find our data interface - const usb_configuration_info *configuration - = gUSBModule->get_configuration(newDevice); - if (configuration == NULL) { - free(device); - return B_ERROR; - } - - for (size_t i = 0; i < configuration->interface_count; i++) { - usb_interface_info *interface = configuration->interface[i].active; - if (interface == NULL) - continue; - - if (interface->descr->interface_class == 0x08 /* mass storage */ - && interface->descr->interface_subclass == 0x04 /* UFI (floppy) */ - && interface->descr->interface_protocol == 0x00) { - - bool hasIn = false; - bool hasOut = false; - bool hasInt = false; - for (size_t j = 0; j < interface->endpoint_count; j++) { - usb_endpoint_info *endpoint = &interface->endpoint[j]; - if (endpoint == NULL) - continue; - - if (!hasIn && (endpoint->descr->endpoint_address - & USB_ENDPOINT_ADDR_DIR_IN) - && endpoint->descr->attributes == USB_ENDPOINT_ATTR_BULK) { - device->bulk_in = endpoint->handle; - hasIn = true; - } else if (!hasOut && (endpoint->descr->endpoint_address - & USB_ENDPOINT_ADDR_DIR_IN) == 0 - && endpoint->descr->attributes == USB_ENDPOINT_ATTR_BULK) { - device->bulk_out = endpoint->handle; - hasOut = true; - } else if (!hasInt && (endpoint->descr->endpoint_address - & USB_ENDPOINT_ADDR_DIR_IN) - && endpoint->descr->attributes - == USB_ENDPOINT_ATTR_INTERRUPT) { - // TODO:ensure there is only one interrupt endpoint and - // stop enumerating - device->interrupt = endpoint->handle; - hasInt = true; - } - - if (hasIn && hasOut && hasInt) - break; - } - - if (!(hasIn && hasOut && hasInt)) { - TRACE("in: %d, out: %d, int: %d\n", hasIn, hasOut, hasInt); - continue; - } - - device->interface = interface->descr->interface_number; - device->is_atapi = interface->descr->interface_subclass != 0x06; - break; - } - } - - if (device->interface == 0xff) { - TRACE_ALWAYS("no valid CBI interface found\n"); - free(device); - return B_ERROR; - } - - mutex_init(&device->lock, "usb_disk device lock"); - - status_t result = device->notify - = create_sem(0, "usb_disk callback notify"); - - if (result < B_OK) { - mutex_destroy(&device->lock); - free(device); - return result; - } - - result = device->interruptLock = create_sem(0, "usb_disk interrupt lock"); - if (result < B_OK) { - mutex_destroy(&device->lock); - free(device); - return result; - } - - // TODO: handle more than 1 unit - device->lun_count = 1; - device->luns = (device_lun **)malloc(device->lun_count - * sizeof(device_lun *)); - for (uint8 i = 0; i < device->lun_count; i++) - device->luns[i] = NULL; - - result = B_OK; - - TRACE_ALWAYS("device reports a lun count of %d\n", device->lun_count); - for (uint8 i = 0; i < device->lun_count; i++) { - // create the individual luns present on this device - device_lun *lun = (device_lun *)malloc(sizeof(device_lun)); - if (lun == NULL) { - result = B_NO_MEMORY; - break; - } - - device->luns[i] = lun; - lun->device = device; - lun->logical_unit_number = i; - lun->should_sync = false; - lun->media_present = true; - lun->media_changed = true; - usb_disk_reset_capacity(lun); - - // initialize this lun - result = usb_disk_inquiry(lun); - - // Reset the device - // If we don't do it all the other commands except inquiry and send - // diagnostics will be stalled. - result = usb_disk_send_diagnostic(lun); - for (uint32 tries = 0; tries < 3; tries++) { - status_t ready = usb_disk_test_unit_ready(lun); - if (ready == B_OK || ready == B_DEV_NO_MEDIA) { - if (ready == B_OK) { - if (lun->device_type == B_CD) - lun->write_protected = true; - // TODO: check for write protection; disabled since - // some devices lock up when getting the mode sense - else if (/*usb_disk_mode_sense(lun) != B_OK*/true) - lun->write_protected = false; - } - - break; - } - - snooze(10000); - } - - if (result != B_OK) - break; - } - - if (result != B_OK) { - TRACE_ALWAYS("failed to initialize logical units\n"); - usb_disk_free_device_and_luns(device); - return result; - } - - mutex_lock(&gDeviceListLock); - device->device_number = 0; - disk_device *other = gDeviceList; - while (other != NULL) { - if (other->device_number >= device->device_number) - device->device_number = other->device_number + 1; - - other = (disk_device *)other->link; - } - - device->link = (void *)gDeviceList; - gDeviceList = device; - gLunCount += device->lun_count; - for (uint8 i = 0; i < device->lun_count; i++) - sprintf(device->luns[i]->name, DEVICE_NAME, device->device_number, i); - mutex_unlock(&gDeviceListLock); - - TRACE("new device: 0x%08lx\n", (uint32)device); - *cookie = (void *)device; - return B_OK; -} - - -static status_t -usb_disk_device_removed(void *cookie) -{ - TRACE("device_removed(0x%08lx)\n", (uint32)cookie); - disk_device *device = (disk_device *)cookie; - - mutex_lock(&gDeviceListLock); - if (gDeviceList == device) { - gDeviceList = (disk_device *)device->link; - } else { - disk_device *element = gDeviceList; - while (element) { - if (element->link == device) { - element->link = device->link; - break; - } - - element = (disk_device *)element->link; - } - } - gLunCount -= device->lun_count; - gDeviceCount--; - - device->removed = true; - gUSBModule->cancel_queued_transfers(device->bulk_in); - gUSBModule->cancel_queued_transfers(device->bulk_out); - if (device->open_count == 0) - usb_disk_free_device_and_luns(device); - - mutex_unlock(&gDeviceListLock); - return B_OK; -} - - -// -//#pragma mark - Partial Buffer Functions -// - - -static bool -usb_disk_needs_partial_buffer(device_lun *lun, off_t position, size_t length, - uint32 &blockPosition, uint16 &blockCount) -{ - blockPosition = (uint32)(position / lun->block_size); - if ((off_t)blockPosition * lun->block_size != position) - return true; - - blockCount = (uint16)(length / lun->block_size); - if ((size_t)blockCount * lun->block_size != length) - return true; - - return false; -} - - -static status_t -usb_disk_block_read(device_lun *lun, uint32 blockPosition, uint16 blockCount, - void *buffer, size_t *length) -{ - uint8 commandBlock[12]; - memset(commandBlock, 0, sizeof(commandBlock)); - - commandBlock[0] = SCSI_READ_12; - commandBlock[1] = lun->logical_unit_number << 5; - commandBlock[2] = blockPosition >> 24; - commandBlock[3] = blockPosition >> 16; - commandBlock[4] = blockPosition >> 8; - commandBlock[5] = blockPosition; - commandBlock[6] = blockCount >> 24; - commandBlock[7] = blockCount >> 16; - commandBlock[8] = blockCount >> 8; - commandBlock[9] = blockCount; - - status_t result = B_OK; - for (int tries = 0; tries < 5; tries++) { - result = usb_disk_operation(lun, commandBlock, buffer, length, - true); - if (result == B_OK) - break; - else - snooze(10000); - } - return result; -} - - -static status_t -usb_disk_block_write(device_lun *lun, uint32 blockPosition, uint16 blockCount, - void *buffer, size_t *length) -{ - uint8 commandBlock[12]; - memset(commandBlock, 0, sizeof(commandBlock)); - - commandBlock[0] = SCSI_WRITE_12; - commandBlock[1] = lun->logical_unit_number << 5; - commandBlock[2] = blockPosition >> 24; - commandBlock[3] = blockPosition >> 16; - commandBlock[4] = blockPosition >> 8; - commandBlock[5] = blockPosition; - commandBlock[6] = blockCount >> 24; - commandBlock[7] = blockCount >> 16; - commandBlock[8] = blockCount >> 8; - commandBlock[9] = blockCount; - - status_t result; - result = usb_disk_operation(lun, commandBlock, buffer, length, - false); - - int retry = 10; - while (result == B_DEV_NO_MEDIA && retry > 0) { - snooze(10000); - result = usb_disk_request_sense(lun); - retry--; - } - - if (result == B_OK) - lun->should_sync = true; - return result; -} - - -static status_t -usb_disk_prepare_partial_buffer(device_lun *lun, off_t position, size_t length, - void *&partialBuffer, void *&blockBuffer, uint32 &blockPosition, - uint16 &blockCount) -{ - blockPosition = (uint32)(position / lun->block_size); - blockCount = (uint16)((uint32)((position + length + lun->block_size - 1) - / lun->block_size) - blockPosition); - size_t blockLength = blockCount * lun->block_size; - blockBuffer = malloc(blockLength); - if (blockBuffer == NULL) { - TRACE_ALWAYS("no memory to allocate partial buffer\n"); - return B_NO_MEMORY; - } - - status_t result = usb_disk_block_read(lun, blockPosition, blockCount, - blockBuffer, &blockLength); - if (result != B_OK) { - TRACE_ALWAYS("block read failed when filling partial buffer\n"); - free(blockBuffer); - return result; - } - - off_t offset = position - (blockPosition * lun->block_size); - partialBuffer = (uint8 *)blockBuffer + offset; - return B_OK; -} - - -// -//#pragma mark - Driver Hooks -// - - -static status_t -usb_disk_open(const char *name, uint32 flags, void **cookie) -{ - TRACE("open(%s)\n", name); - if (strncmp(name, DEVICE_NAME_BASE, strlen(DEVICE_NAME_BASE)) != 0) - return B_NAME_NOT_FOUND; - - int32 lastPart = 0; - size_t nameLength = strlen(name); - for (int32 i = nameLength - 1; i >= 0; i--) { - if (name[i] == '/') { - lastPart = i; - break; - } - } - - char rawName[nameLength + 4]; - strncpy(rawName, name, lastPart + 1); - rawName[lastPart + 1] = 0; - strcat(rawName, "raw"); - TRACE("opening raw device %s for %s\n", rawName, name); - - mutex_lock(&gDeviceListLock); - disk_device *device = gDeviceList; - while (device) { - for (uint8 i = 0; i < device->lun_count; i++) { - device_lun *lun = device->luns[i]; - if (strncmp(rawName, lun->name, 32) == 0) { - // found the matching device/lun - if (device->removed) { - mutex_unlock(&gDeviceListLock); - return B_ERROR; - } - - device->open_count++; - *cookie = lun; - mutex_unlock(&gDeviceListLock); - return B_OK; - } - } - - device = (disk_device *)device->link; - } - - mutex_unlock(&gDeviceListLock); - return B_NAME_NOT_FOUND; -} - - -static status_t -usb_disk_close(void *cookie) -{ - TRACE("close()\n"); - device_lun *lun = (device_lun *)cookie; - disk_device *device = lun->device; - - mutex_lock(&device->lock); - if (!device->removed) - usb_disk_synchronize(lun, false); - mutex_unlock(&device->lock); - - return B_OK; -} - - -static status_t -usb_disk_free(void *cookie) -{ - TRACE("free()\n"); - mutex_lock(&gDeviceListLock); - - device_lun *lun = (device_lun *)cookie; - disk_device *device = lun->device; - device->open_count--; - if (device->open_count == 0 && device->removed) { - // we can simply free the device here as it has been removed from - // the device list in the device removed notification hook - usb_disk_free_device_and_luns(device); - } - - mutex_unlock(&gDeviceListLock); - return B_OK; -} - - -static inline void -normalize_name(char *name, size_t nameLength) -{ - bool wasSpace = false; - size_t insertIndex = 0; - for (size_t i = 0; i < nameLength; i++) { - bool isSpace = name[i] == ' '; - if (isSpace && wasSpace) - continue; - - name[insertIndex++] = name[i]; - wasSpace = isSpace; - } - - if (insertIndex > 0 && name[insertIndex - 1] == ' ') - insertIndex--; - - name[insertIndex] = 0; -} - - -static status_t -usb_disk_ioctl(void *cookie, uint32 op, void *buffer, size_t length) -{ - device_lun *lun = (device_lun *)cookie; - disk_device *device = lun->device; - mutex_lock(&device->lock); - if (device->removed) { - mutex_unlock(&device->lock); - return B_DEV_NOT_READY; - } - - status_t result = B_DEV_INVALID_IOCTL; - switch (op) { - case B_GET_DEVICE_SIZE: { - if (lun->media_changed) { - result = usb_disk_update_capacity(lun); - if (result != B_OK) - break; - } - - size_t size = lun->block_size * lun->block_count; - result = user_memcpy(buffer, &size, sizeof(size)); - - break; - } - - case B_GET_MEDIA_STATUS: { - *(status_t *)buffer = usb_disk_test_unit_ready(lun); - TRACE("B_GET_MEDIA_STATUS: 0x%08lx\n", *(status_t *)buffer); - result = B_OK; - break; - } - - case B_GET_GEOMETRY: { - if (lun->media_changed) { - result = usb_disk_update_capacity(lun); - if (result != B_OK) - break; - } - - device_geometry *geometry = (device_geometry *)buffer; - geometry->bytes_per_sector = lun->block_size; - geometry->cylinder_count = lun->block_count; - geometry->sectors_per_track = geometry->head_count = 1; - geometry->device_type = lun->device_type; - geometry->removable = lun->removable; - geometry->read_only = lun->write_protected; - geometry->write_once = (lun->device_type == B_WORM); - TRACE("B_GET_GEOMETRY: %ld sectors at %ld bytes per sector\n", - geometry->cylinder_count, geometry->bytes_per_sector); - result = B_OK; - break; - } - - case B_FLUSH_DRIVE_CACHE: - TRACE("B_FLUSH_DRIVE_CACHE\n"); - result = usb_disk_synchronize(lun, true); - break; - - case B_EJECT_DEVICE: - { - uint8 commandBlock[12]; - memset(commandBlock, 0, sizeof(commandBlock)); - - commandBlock[0] = SCSI_START_STOP_UNIT_6; - commandBlock[1] = lun->logical_unit_number << 5; - commandBlock[4] = 2; - - result = usb_disk_operation(lun, commandBlock, NULL, NULL, false); - break; - } - - case B_LOAD_MEDIA: - { - uint8 commandBlock[12]; - memset(commandBlock, 0, sizeof(commandBlock)); - - commandBlock[0] = SCSI_START_STOP_UNIT_6; - commandBlock[1] = lun->logical_unit_number << 5; - commandBlock[4] = 3; - - result = usb_disk_operation(lun, commandBlock, NULL, NULL, false); - break; - } - - case B_GET_ICON: - // We don't support this legacy ioctl anymore, but the two other - // icon ioctls below instead. - break; - - case B_GET_ICON_NAME: - result = user_strlcpy((char *)buffer, - "devices/drive-removable-media-usb", B_FILE_NAME_LENGTH); - break; - - case B_GET_VECTOR_ICON: - { - if (length != sizeof(device_icon)) { - result = B_BAD_VALUE; - break; - } - - device_icon iconData; - if (user_memcpy(&iconData, buffer, sizeof(device_icon)) != B_OK) { - result = B_BAD_ADDRESS; - break; - } - - if (iconData.icon_size >= (int32)sizeof(kDeviceIcon)) { - if (user_memcpy(iconData.icon_data, kDeviceIcon, - sizeof(kDeviceIcon)) != B_OK) { - result = B_BAD_ADDRESS; - break; - } - } - - iconData.icon_size = sizeof(kDeviceIcon); - result = user_memcpy(buffer, &iconData, sizeof(device_icon)); - break; - } - - case B_GET_DEVICE_NAME: - { - size_t nameLength = sizeof(lun->vendor_name) - + sizeof(lun->product_name) + sizeof(lun->product_revision) + 3; - - char name[nameLength]; - snprintf(name, nameLength, "%.8s %.16s %.4s", lun->vendor_name, - lun->product_name, lun->product_revision); - - normalize_name(name, nameLength); - - result = user_strlcpy((char *)buffer, name, length); - if (result > 0) - result = B_OK; - - TRACE_ALWAYS("got device name: \"%s\" = %s\n", name, strerror(result)); - break; - } - - default: - TRACE_ALWAYS("unhandled ioctl %" B_PRIu32 "\n", op); - break; - } - - mutex_unlock(&device->lock); - return result; -} - - -static status_t -usb_disk_read(void *cookie, off_t position, void *buffer, size_t *length) -{ - if (buffer == NULL || length == NULL) - return B_BAD_VALUE; - - TRACE("read(%lld, %ld)\n", position, *length); - device_lun *lun = (device_lun *)cookie; - disk_device *device = lun->device; - mutex_lock(&device->lock); - if (device->removed) { - *length = 0; - mutex_unlock(&device->lock); - return B_DEV_NOT_READY; - } - - status_t result = B_ERROR; - uint32 blockPosition = 0; - uint16 blockCount = 0; - bool needsPartial = usb_disk_needs_partial_buffer(lun, position, *length, - blockPosition, blockCount); - if (needsPartial) { - void *partialBuffer = NULL; - void *blockBuffer = NULL; - result = usb_disk_prepare_partial_buffer(lun, position, *length, - partialBuffer, blockBuffer, blockPosition, blockCount); - if (result == B_OK) { - memcpy(buffer, partialBuffer, *length); - free(blockBuffer); - } - } else { - result = usb_disk_block_read(lun, blockPosition, blockCount, buffer, - length); - } - - mutex_unlock(&device->lock); - if (result == B_OK) { - TRACE("read successful with %ld bytes\n", *length); - return B_OK; - } - - *length = 0; - TRACE_ALWAYS("read fails with 0x%08" B_PRIx32 "\n", result); - return result; -} - - -static status_t -usb_disk_write(void *cookie, off_t position, const void *buffer, - size_t *length) -{ - if (buffer == NULL || length == NULL) - return B_BAD_VALUE; - - TRACE("write(%lld, %ld)\n", position, *length); - device_lun *lun = (device_lun *)cookie; - disk_device *device = lun->device; - mutex_lock(&device->lock); - if (device->removed) { - *length = 0; - mutex_unlock(&device->lock); - return B_DEV_NOT_READY; - } - - status_t result = B_ERROR; - uint32 blockPosition = 0; - uint16 blockCount = 0; - bool needsPartial = usb_disk_needs_partial_buffer(lun, position, - *length, blockPosition, blockCount); - if (needsPartial) { - void *partialBuffer = NULL; - void *blockBuffer = NULL; - result = usb_disk_prepare_partial_buffer(lun, position, *length, - partialBuffer, blockBuffer, blockPosition, blockCount); - if (result == B_OK) { - memcpy(partialBuffer, buffer, *length); - size_t blockLength = blockCount * lun->block_size; - result = usb_disk_block_write(lun, blockPosition, blockCount, - blockBuffer, &blockLength); - free(blockBuffer); - } - } else { - result = usb_disk_block_write(lun, blockPosition, blockCount, - (void *)buffer, length); - } - - mutex_unlock(&device->lock); - if (result == B_OK) { - TRACE("write successful with %ld bytes\n", *length); - return B_OK; - } - - *length = 0; - TRACE_ALWAYS("write fails with 0x%08" B_PRIx32 "\n", result); - return result; -} - - -// -//#pragma mark - Driver Entry Points -// - - -status_t -init_hardware() -{ - TRACE("init_hardware()\n"); - return B_OK; -} - - -status_t -init_driver() -{ - TRACE("init_driver()\n"); - static usb_notify_hooks notifyHooks = { - &usb_disk_device_added, - &usb_disk_device_removed - }; - - static usb_support_descriptor supportedDevices[] = { - { 0x08 /* mass storage */, 0x04 /* UFI */, 0x00, 0, 0 } - }; - - gDeviceList = NULL; - gDeviceCount = 0; - gLunCount = 0; - mutex_init(&gDeviceListLock, "usb_disk device list lock"); - - TRACE("trying module %s\n", B_USB_MODULE_NAME); - status_t result = get_module(B_USB_MODULE_NAME, - (module_info **)&gUSBModule); - if (result < B_OK) { - TRACE_ALWAYS("getting module failed 0x%08" B_PRIx32 "\n", result); - mutex_destroy(&gDeviceListLock); - return result; - } - - gUSBModule->register_driver(DRIVER_NAME, supportedDevices, 1, NULL); - gUSBModule->install_notify(DRIVER_NAME, ¬ifyHooks); - return B_OK; -} - - -void -uninit_driver() -{ - TRACE("uninit_driver()\n"); - gUSBModule->uninstall_notify(DRIVER_NAME); - mutex_lock(&gDeviceListLock); - - if (gDeviceNames) { - for (int32 i = 0; gDeviceNames[i]; i++) - free(gDeviceNames[i]); - free(gDeviceNames); - gDeviceNames = NULL; - } - - mutex_destroy(&gDeviceListLock); - put_module(B_USB_MODULE_NAME); -} - - -const char ** -publish_devices() -{ - TRACE("publish_devices()\n"); - if (gDeviceNames) { - for (int32 i = 0; gDeviceNames[i]; i++) - free(gDeviceNames[i]); - free(gDeviceNames); - gDeviceNames = NULL; - } - - gDeviceNames = (char **)malloc(sizeof(char *) * (gLunCount + 1)); - if (gDeviceNames == NULL) - return NULL; - - int32 index = 0; - mutex_lock(&gDeviceListLock); - disk_device *device = gDeviceList; - while (device) { - for (uint8 i = 0; i < device->lun_count; i++) - gDeviceNames[index++] = strdup(device->luns[i]->name); - - device = (disk_device *)device->link; - } - - gDeviceNames[index++] = NULL; - mutex_unlock(&gDeviceListLock); - return (const char **)gDeviceNames; -} - - -device_hooks * -find_device(const char *name) -{ - TRACE("find_device()\n"); - static device_hooks hooks = { - &usb_disk_open, - &usb_disk_close, - &usb_disk_free, - &usb_disk_ioctl, - &usb_disk_read, - &usb_disk_write, - NULL, - NULL, - NULL, - NULL - }; - - return &hooks; -} diff --git a/src/add-ons/kernel/drivers/disk/usb/usb_floppy/usb_disk.h b/src/add-ons/kernel/drivers/disk/usb/usb_floppy/usb_disk.h deleted file mode 100644 index edfe2f2ffb..0000000000 --- a/src/add-ons/kernel/drivers/disk/usb/usb_floppy/usb_disk.h +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright 2008, Haiku Inc. All rights reserved. - * Distributed under the terms of the MIT License. - * - * Authors: - * Michael Lotz - */ - -#ifndef _USB_DISK_H_ -#define _USB_DISK_H_ - -#include -#include - -#define REQUEST_MASS_STORAGE_RESET 0xff -#define REQUEST_GET_MAX_LUN 0xfe -#define MAX_LOGICAL_UNIT_NUMBER 15 -#define ATAPI_COMMAND_LENGTH 12 - -#define CBW_SIGNATURE 0x43425355 -#define CBW_DATA_OUTPUT 0x00 -#define CBW_DATA_INPUT 0x80 - -#define CSW_SIGNATURE 0x53425355 -#define CSW_STATUS_COMMAND_PASSED 0x00 -#define CSW_STATUS_COMMAND_FAILED 0x01 -#define CSW_STATUS_PHASE_ERROR 0x02 - -#define SYNC_SUPPORT_RELOAD 5 - -typedef struct device_lun_s device_lun; - -// holds common information about an attached device (pointed to by luns) -typedef struct disk_device_s { - usb_device device; - uint32 device_number; - bool removed; - uint32 open_count; - mutex lock; - void * link; - - // device state - usb_pipe bulk_in; - usb_pipe bulk_out; - usb_pipe interrupt; - uint8 interface; - uint32 current_tag; - uint8 sync_support; - bool is_atapi; - - // used to store callback information - sem_id notify; - status_t status; - size_t actual_length; - - // used to store interrupt result - unsigned char interruptBuffer[2]; - sem_id interruptLock; - - // logical units of this device - uint8 lun_count; - device_lun **luns; -} disk_device; - - -// represents a logical unit on the pointed to device - this gets published -struct device_lun_s { - disk_device *device; - char name[32]; - uint8 logical_unit_number; - bool should_sync; - - // device information through read capacity/inquiry - bool media_present; - bool media_changed; - uint32 block_count; - uint32 block_size; - uint8 device_type; - bool removable; - bool write_protected; - - char vendor_name[8]; - char product_name[16]; - char product_revision[4]; -}; - - -typedef struct command_block_wrapper_s { - uint32 signature; - uint32 tag; - uint32 data_transfer_length; - uint8 flags; - uint8 lun; - uint8 command_block_length; - uint8 command_block[16]; -} _PACKED command_block_wrapper; - - -typedef struct command_status_wrapper_s { - uint8 status; - uint8 misc; -} _PACKED command_status_wrapper; - -#endif // _USB_DISK_H_ diff --git a/src/add-ons/kernel/drivers/disk/usb/usb_floppy/usb_disk_scsi.h b/src/add-ons/kernel/drivers/disk/usb/usb_floppy/usb_disk_scsi.h deleted file mode 100644 index e46bd0e056..0000000000 --- a/src/add-ons/kernel/drivers/disk/usb/usb_floppy/usb_disk_scsi.h +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright 2008, Haiku Inc. All rights reserved. - * Distributed under the terms of the MIT License. - * - * Authors: - * Michael Lotz - */ - -#ifndef _USB_DISK_SCSI_H_ -#define _USB_DISK_SCSI_H_ - -typedef enum { - SCSI_TEST_UNIT_READY_6 = 0x00, - SCSI_REQUEST_SENSE_6 = 0x03, - SCSI_INQUIRY_6 = 0x12, - SCSI_MODE_SENSE_6 = 0x1a, - SCSI_START_STOP_UNIT_6 = 0x1b, - SCSI_SEND_DIAGNOSTIC = 0x1d, - SCSI_READ_CAPACITY_10 = 0x25, - SCSI_READ_12 = 0xA8, - SCSI_WRITE_12 = 0xAA, - SCSI_SYNCHRONIZE_CACHE_10 = 0x35, -} scsi_operations; - -// parameters = returned data -typedef struct scsi_request_sense_6_parameter_s { - uint8 error_code : 7; - uint8 valid : 1; - uint8 segment_number; - uint8 sense_key : 4; - uint8 unused_1 : 4; - uint32 information; - uint8 additional_sense_length; - uint32 command_specific_information; - uint8 additional_sense_code; - uint8 additional_sense_code_qualifier; - uint8 field_replacable_unit_code; - uint8 sense_key_specific[3]; -} _PACKED scsi_request_sense_6_parameter; - -typedef struct scsi_inquiry_6_parameter_s { - uint8 peripherial_device_type : 5; - uint8 peripherial_qualifier : 3; - uint8 reserved_1 : 7; - uint8 removable_medium : 1; - uint8 version; - uint8 response_data_format : 4; - uint8 unused_1 : 4; - uint8 additional_length; - uint8 unused_2[3]; - char vendor_identification[8]; - char product_identification[16]; - char product_revision_level[4]; -} _PACKED scsi_inquiry_6_parameter; - -typedef struct scsi_mode_sense_6_parameter_s { - uint8 data_length; - uint8 medium_type; - uint8 device_specific; - uint8 block_descriptor_length; - uint8 densitiy; - uint8 num_blocks[3]; - uint8 reserved; - uint8 block_length[3]; -} _PACKED scsi_mode_sense_6_parameter; - -typedef struct scsi_read_capacity_10_parameter_s { - uint32 last_logical_block_address; - uint32 logical_block_length; -} _PACKED scsi_read_capacity_10_parameter; - -// request sense keys/codes -typedef enum { - SCSI_SENSE_KEY_NO_SENSE = 0x00, - SCSI_SENSE_KEY_RECOVERED_ERROR = 0x01, - SCSI_SENSE_KEY_NOT_READY = 0x02, - SCSI_SENSE_KEY_MEDIUM_ERROR = 0x03, - SCSI_SENSE_KEY_HARDWARE_ERROR = 0x04, - SCSI_SENSE_KEY_ILLEGAL_REQUEST = 0x05, - SCSI_SENSE_KEY_UNIT_ATTENTION = 0x06, - SCSI_SENSE_KEY_DATA_PROTECT = 0x07, - SCSI_SENSE_KEY_ABORTED_COMMAND = 0x0b, -} scsi_sense_key; - -// request sense additional sense codes -#define SCSI_ASC_MEDIUM_NOT_PRESENT 0x3a - -// mode sense page code/parameter -#define SCSI_MODE_PAGE_DEVICE_CONFIGURATION 0x10 -#define SCSI_DEVICE_SPECIFIC_WRITE_PROTECT 0x80 - -#endif // _USB_DISK_SCSI_H_