From a380bc25131132eaafceca992acc027690fbaf55 Mon Sep 17 00:00:00 2001 From: Michael Lotz Date: Fri, 4 Apr 2008 22:51:29 +0000 Subject: [PATCH] * Add support for devices with multiple LUNs * A device now has one or more LUNs which are used for LUN specific functions * Adapted these LUN specific functions to the new design and also change the (un-)publishing accordingly * Handle "no media" cases more correctly * Output some interesting device infos also with tracing disabled * Add some more helpful debug output here and there Devices that provide multiple logical units (like those n in 1 card readers) should now be usable with usb_disk too. Also we don't fail when a device is attached which currently does not contain a media. Instead handle media changes correctly so inserting a media works as expected. Note that hot-unplugging and media removal still does not quite work right at the devfs or disk device manager level and easily crashes the system. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@24799 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- .../drivers/disk/usb/usb_disk/usb_disk.cpp | 369 +++++++++++------- .../drivers/disk/usb/usb_disk/usb_disk.h | 34 +- 2 files changed, 251 insertions(+), 152 deletions(-) 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 24dd1e5545..84bd530139 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 @@ -18,7 +18,7 @@ #define DRIVER_NAME "usb_disk" #define DEVICE_NAME_BASE "disk/usb/" -#define DEVICE_NAME DEVICE_NAME_BASE"%ld/%ld/raw" +#define DEVICE_NAME DEVICE_NAME_BASE"%ld/%d/raw" //#define TRACE_USB_DISK @@ -35,6 +35,7 @@ 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 benaphore gDeviceListLock; static char **gDeviceNames = NULL; @@ -54,16 +55,35 @@ 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(disk_device *device, uint8 operation, +status_t usb_disk_operation(device_lun *lun, uint8 operation, uint8 opLength, uint32 logicalBlockAddress, uint16 transferLength, void *data, uint32 *dataLength, bool directionIn); -status_t usb_disk_request_sense(disk_device *device); -status_t usb_disk_test_unit_ready(disk_device *device); -status_t usb_disk_inquiry(disk_device *device); -status_t usb_disk_update_capacity(disk_device *device); -status_t usb_disk_synchronize(disk_device *device, bool force); +status_t usb_disk_request_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) +{ + benaphore_lock(&device->lock); + benaphore_destroy(&device->lock); + delete_sem(device->notify); + for (uint8 i = 0; i < device->lun_count; i++) + free(device->luns[i]); + free(device->luns); + free(device); +} // @@ -92,8 +112,8 @@ usb_disk_get_max_lun(disk_device *device) 1, &result, &actualLength) != B_OK || actualLength != 1) return 0; - if (result > 15) { - // invalid count, only up to 15 LUNs are possible + if (result > MAX_LOGICAL_UNIT_NUMBER) { + // invalid max lun return 0; } @@ -152,16 +172,17 @@ usb_disk_receive_csw(disk_device *device, command_status_wrapper *status) status_t -usb_disk_operation(disk_device *device, uint8 operation, uint8 opLength, +usb_disk_operation(device_lun *lun, uint8 operation, uint8 opLength, uint32 logicalBlockAddress, uint16 transferLength, void *data, uint32 *dataLength, bool directionIn) { + disk_device *device = lun->device; command_block_wrapper command; command.signature = CBW_SIGNATURE; command.tag = device->current_tag++; command.data_transfer_length = (dataLength != NULL ? *dataLength : 0); command.flags = (directionIn ? CBW_DATA_INPUT : CBW_DATA_OUTPUT); - command.lun = device->lun; + command.lun = lun->logical_unit_number; command.command_block_length = opLength; memset(command.command_block, 0, sizeof(command.command_block)); @@ -169,7 +190,7 @@ usb_disk_operation(disk_device *device, uint8 operation, uint8 opLength, case 6: { scsi_command_6 *commandBlock = (scsi_command_6 *)command.command_block; commandBlock->operation = operation; - commandBlock->lun = device->lun << 5; + commandBlock->lun = lun->logical_unit_number << 5; commandBlock->allocation_length = (uint8)transferLength; break; } @@ -177,7 +198,7 @@ usb_disk_operation(disk_device *device, uint8 operation, uint8 opLength, case 10: { scsi_command_10 *commandBlock = (scsi_command_10 *)command.command_block; commandBlock->operation = operation; - commandBlock->lun_flags = device->lun << 5; + commandBlock->lun_flags = lun->logical_unit_number << 5; commandBlock->logical_block_address = htonl(logicalBlockAddress); commandBlock->transfer_length = htons(transferLength); break; @@ -252,16 +273,18 @@ usb_disk_operation(disk_device *device, uint8 operation, uint8 opLength, result = B_OK; } else { // the operation is complete but has failed at the SCSI level - TRACE_ALWAYS("operation failed at the SCSI level\n"); - usb_disk_request_sense(device); - result = B_ERROR; + TRACE_ALWAYS("operation 0x%02x failed at the SCSI level\n", + operation); + result = usb_disk_request_sense(lun); + if (result == B_OK) + result = B_ERROR; } break; } case CSW_STATUS_PHASE_ERROR: { // a protocol or device error occured - TRACE_ALWAYS("phase error in operation\n"); + TRACE_ALWAYS("phase error in operation 0x%02x\n", operation); usb_disk_reset_recovery(device); if (dataLength != NULL) *dataLength = 0; @@ -279,18 +302,18 @@ usb_disk_operation(disk_device *device, uint8 operation, uint8 opLength, status_t -usb_disk_request_sense(disk_device *device) +usb_disk_request_sense(device_lun *lun) { uint32 dataLength = sizeof(scsi_request_sense_6_parameter); scsi_request_sense_6_parameter parameter; - status_t result = usb_disk_operation(device, SCSI_REQUEST_SENSE_6, 6, 0, + status_t result = usb_disk_operation(lun, SCSI_REQUEST_SENSE_6, 6, 0, dataLength, ¶meter, &dataLength, true); if (result != B_OK) { TRACE_ALWAYS("getting request sense data failed\n"); return result; } - if (parameter.sense_key >= 2) { + if (parameter.sense_key > SCSI_SENSE_KEY_NOT_READY) { 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); @@ -302,20 +325,26 @@ usb_disk_request_sense(disk_device *device) return B_OK; case SCSI_SENSE_KEY_NOT_READY: - TRACE_ALWAYS("request_sense: device not ready\n"); - return B_DEV_NOT_READY; - - case SCSI_SENSE_KEY_MEDIUM_ERROR: - case SCSI_SENSE_KEY_HARDWARE_ERROR: - TRACE_ALWAYS("request_sense: no media or hardware error\n"); + 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_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: TRACE_ALWAYS("request_sense: media changed\n"); + lun->media_changed = true; + lun->media_present = true; return B_DEV_MEDIA_CHANGED; case SCSI_SENSE_KEY_DATA_PROTECT: @@ -332,71 +361,85 @@ usb_disk_request_sense(disk_device *device) status_t -usb_disk_test_unit_ready(disk_device *device) +usb_disk_test_unit_ready(device_lun *lun) { - status_t result = usb_disk_operation(device, SCSI_TEST_UNIT_READY_6, 6, 0, - 0, NULL, NULL, true); - if (result == B_OK) - return B_OK; - - return usb_disk_request_sense(device); + return usb_disk_operation(lun, SCSI_TEST_UNIT_READY_6, 6, 0, 0, NULL, NULL, + true); } status_t -usb_disk_inquiry(disk_device *device) +usb_disk_inquiry(device_lun *lun) { uint32 dataLength = sizeof(scsi_inquiry_6_parameter); scsi_inquiry_6_parameter parameter; - status_t result = usb_disk_operation(device, SCSI_INQUIRY_6, 6, 0, - dataLength, ¶meter, &dataLength, true); + status_t result = B_ERROR; + for (uint32 tries = 0; tries < 3; tries++) { + result = usb_disk_operation(lun, SCSI_INQUIRY_6, 6, 0, dataLength, + ¶meter, &dataLength, true); + if (result == B_OK) + break; + } if (result != B_OK) { TRACE_ALWAYS("getting inquiry data failed\n"); - device->removable = true; + 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("vendor_identification... \"%.8s\"\n", parameter.vendor_identification); - TRACE("product_identification.. \"%.16s\"\n", parameter.product_identification); - TRACE("product_revision_level.. \"%.4s\"\n", parameter.product_revision_level); - device->device_type = parameter.peripherial_device_type; /* 1:1 mapping */ - device->removable = (parameter.removable_medium == 1); + 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); + lun->device_type = parameter.peripherial_device_type; /* 1:1 mapping */ + lun->removable = (parameter.removable_medium == 1); return B_OK; } status_t -usb_disk_update_capacity(disk_device *device) +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) { uint32 dataLength = sizeof(scsi_read_capacity_10_parameter); scsi_read_capacity_10_parameter parameter; - status_t result = usb_disk_operation(device, SCSI_READ_CAPACITY_10, 10, 0, - 0, ¶meter, &dataLength, true); + status_t result = usb_disk_operation(lun, SCSI_READ_CAPACITY_10, 10, 0, 0, + ¶meter, &dataLength, true); if (result != B_OK) { TRACE_ALWAYS("failed to update capacity\n"); - device->block_size = 1; - device->block_count = 0; + lun->media_present = false; + lun->media_changed = false; + usb_disk_reset_capacity(lun); return result; } - device->block_size = ntohl(parameter.logical_block_length); - device->block_count = ntohl(parameter.last_logical_block_address) + 1; + 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(disk_device *device, bool force) +usb_disk_synchronize(device_lun *lun, bool force) { - if (device->should_sync || force) { - status_t result = usb_disk_operation(device, SCSI_SYNCHRONIZE_CACHE_10, + if (lun->should_sync || force) { + status_t result = usb_disk_operation(lun, SCSI_SYNCHRONIZE_CACHE_10, 10, 0, 0, NULL, NULL, false); - device->should_sync = false; + lun->should_sync = false; return result; } @@ -415,7 +458,6 @@ usb_disk_callback(void *cookie, status_t status, void *data, { //TRACE("callback()\n"); disk_device *device = (disk_device *)cookie; - device->status = status; device->actual_length = actualLength; release_sem(device->notify); @@ -432,8 +474,7 @@ usb_disk_device_added(usb_device newDevice, void **cookie) device->open_count = 0; device->interface = 0xff; device->current_tag = 0; - device->should_sync = false; - device->lun = 0; + device->luns = NULL; // scan through the interfaces to find our bulk-only data interface const usb_configuration_info *configuration = gUSBModule->get_configuration(newDevice); @@ -483,6 +524,7 @@ usb_disk_device_added(usb_device newDevice, void **cookie) if (device->interface == 0xff) { TRACE_ALWAYS("no valid bulk-only interface found\n"); + free(device); return B_ERROR; } @@ -496,33 +538,58 @@ usb_disk_device_added(usb_device newDevice, void **cookie) if (device->notify < B_OK) { benaphore_destroy(&device->lock); free(device); - return B_NO_MORE_SEMS; + return device->notify; } - result = usb_disk_inquiry(device); - for (uint32 tries = 0; tries < 3; tries++) { - if (usb_disk_test_unit_ready(device) == B_OK) + device->lun_count = usb_disk_get_max_lun(device) + 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; + + 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); + 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) + break; + snooze(10000); + } + + if (result != B_OK) break; - snooze(10000); } - if (result != B_OK || usb_disk_update_capacity(device) != B_OK) { - TRACE_ALWAYS("failed to read device data\n"); - delete_sem(device->notify); - benaphore_destroy(&device->lock); - free(device); - return B_ERROR; + if (result != B_OK) { + TRACE_ALWAYS("failed to initialize logical units\n"); + usb_disk_free_device_and_luns(device); + return result; } benaphore_lock(&gDeviceListLock); device->link = (void *)gDeviceList; gDeviceList = device; uint32 deviceNumber = gDeviceCount++; - - // ToDo: find out about LUNs and publish those too - //uint8 maxLun = usb_disk_get_max_lun(device); - //TRACE("device has max lun %d\n", maxLun); - sprintf(device->name, DEVICE_NAME, deviceNumber, 0L); + gLunCount += device->lun_count; + for (uint8 i = 0; i < device->lun_count; i++) + sprintf(device->luns[i]->name, DEVICE_NAME, deviceNumber, i); benaphore_unlock(&gDeviceListLock); TRACE("new device: 0x%08lx\n", (uint32)device); @@ -551,18 +618,14 @@ usb_disk_device_removed(void *cookie) element = (disk_device *)element->link; } } + gLunCount -= device->lun_count; gDeviceCount--; benaphore_unlock(&gDeviceListLock); device->device = 0; device->removed = true; - if (device->open_count == 0) { - benaphore_lock(&device->lock); - benaphore_destroy(&device->lock); - delete_sem(device->notify); - free(device); - } - + if (device->open_count == 0) + usb_disk_free_device_and_luns(device); return B_OK; } @@ -573,15 +636,15 @@ usb_disk_device_removed(void *cookie) static bool -usb_disk_needs_partial_buffer(disk_device *device, off_t position, - size_t length, uint32 &blockPosition, uint16 &blockCount) +usb_disk_needs_partial_buffer(device_lun *lun, off_t position, size_t length, + uint32 &blockPosition, uint16 &blockCount) { - blockPosition = (uint32)(position / device->block_size); - if ((off_t)blockPosition * device->block_size != position) + blockPosition = (uint32)(position / lun->block_size); + if ((off_t)blockPosition * lun->block_size != position) return true; - blockCount = (uint16)(length / device->block_size); - if ((size_t)blockCount * device->block_size != length) + blockCount = (uint16)(length / lun->block_size); + if ((size_t)blockCount * lun->block_size != length) return true; return false; @@ -589,43 +652,43 @@ usb_disk_needs_partial_buffer(disk_device *device, off_t position, static status_t -usb_disk_block_read(disk_device *device, uint32 blockPosition, - uint16 blockCount, void *buffer, size_t *length) +usb_disk_block_read(device_lun *lun, uint32 blockPosition, uint16 blockCount, + void *buffer, size_t *length) { - status_t result = usb_disk_operation(device, SCSI_READ_10, 10, - blockPosition, blockCount, buffer, length, true); + status_t result = usb_disk_operation(lun, SCSI_READ_10, 10, blockPosition, + blockCount, buffer, length, true); return result; } static status_t -usb_disk_block_write(disk_device *device, uint32 blockPosition, - uint16 blockCount, void *buffer, size_t *length) +usb_disk_block_write(device_lun *lun, uint32 blockPosition, uint16 blockCount, + void *buffer, size_t *length) { - status_t result = usb_disk_operation(device, SCSI_WRITE_10, 10, - blockPosition, blockCount, buffer, length, false); + status_t result = usb_disk_operation(lun, SCSI_WRITE_10, 10, blockPosition, + blockCount, buffer, length, false); if (result == B_OK) - device->should_sync = true; + lun->should_sync = true; return result; } static status_t -usb_disk_prepare_partial_buffer(disk_device *device, off_t position, - size_t length, void *&partialBuffer, void *&blockBuffer, - uint32 &blockPosition, uint16 &blockCount) +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 / device->block_size); - blockCount = (uint16)((uint32)((position + length + device->block_size - 1) - / device->block_size) - blockPosition); - size_t blockLength = blockCount * device->block_size; + 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(device, blockPosition, blockCount, + 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"); @@ -633,7 +696,7 @@ usb_disk_prepare_partial_buffer(disk_device *device, off_t position, return result; } - off_t offset = position - (blockPosition * device->block_size); + off_t offset = position - (blockPosition * lun->block_size); partialBuffer = (uint8 *)blockBuffer + offset; return B_OK; } @@ -667,11 +730,18 @@ usb_disk_open(const char *name, uint32 flags, void **cookie) benaphore_lock(&gDeviceListLock); disk_device *device = gDeviceList; while (device) { - if (!device->removed && strncmp(rawName, device->name, 32) == 0) { - device->open_count++; - *cookie = device; - benaphore_unlock(&gDeviceListLock); - return B_OK; + 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) + return B_ERROR; + + device->open_count++; + *cookie = lun; + benaphore_unlock(&gDeviceListLock); + return B_OK; + } } device = (disk_device *)device->link; @@ -686,8 +756,8 @@ static status_t usb_disk_close(void *cookie) { TRACE("close()\n"); - disk_device *device = (disk_device *)cookie; - usb_disk_synchronize(device, false); + device_lun *lun = (device_lun *)cookie; + usb_disk_synchronize(lun, false); return B_OK; } @@ -698,13 +768,13 @@ usb_disk_free(void *cookie) TRACE("free()\n"); benaphore_lock(&gDeviceListLock); - disk_device *device = (disk_device *)cookie; + device_lun *lun = (device_lun *)cookie; + disk_device *device = lun->device; device->open_count--; if (device->removed && device->open_count == 0) { - benaphore_lock(&device->lock); - benaphore_destroy(&device->lock); - delete_sem(device->notify); - free(device); + // 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); } benaphore_unlock(&gDeviceListLock); @@ -715,7 +785,8 @@ usb_disk_free(void *cookie) static status_t usb_disk_ioctl(void *cookie, uint32 op, void *buffer, size_t length) { - disk_device *device = (disk_device *)cookie; + device_lun *lun = (device_lun *)cookie; + disk_device *device = lun->device; if (device->removed) return B_DEV_NOT_READY; @@ -724,21 +795,27 @@ usb_disk_ioctl(void *cookie, uint32 op, void *buffer, size_t length) switch (op) { case B_GET_MEDIA_STATUS: { - *(status_t *)buffer = usb_disk_test_unit_ready(device); + *(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 = device->block_size; - geometry->cylinder_count = device->block_count; + geometry->bytes_per_sector = lun->block_size; + geometry->cylinder_count = lun->block_count; geometry->sectors_per_track = geometry->head_count = 1; - geometry->device_type = device->device_type; - geometry->removable = device->removable; - geometry->read_only = (device->device_type == B_CD); - geometry->write_once = (device->device_type == B_WORM); + geometry->device_type = lun->device_type; + geometry->removable = lun->removable; + geometry->read_only = (lun->device_type == B_CD); + 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; @@ -746,7 +823,8 @@ usb_disk_ioctl(void *cookie, uint32 op, void *buffer, size_t length) } case B_FLUSH_DRIVE_CACHE: - usb_disk_synchronize(device, true); + TRACE("B_FLUSH_DRIVE_CACHE\n"); + usb_disk_synchronize(lun, true); break; default: @@ -763,7 +841,8 @@ static status_t usb_disk_read(void *cookie, off_t position, void *buffer, size_t *length) { TRACE("read(%lld, %ld)\n", position, *length); - disk_device *device = (disk_device *)cookie; + device_lun *lun = (device_lun *)cookie; + disk_device *device = lun->device; if (device->removed) { *length = 0; return B_DEV_NOT_READY; @@ -776,20 +855,20 @@ usb_disk_read(void *cookie, off_t position, void *buffer, size_t *length) status_t result = B_ERROR; uint32 blockPosition = 0; uint16 blockCount = 0; - bool needsPartial = usb_disk_needs_partial_buffer(device, position, - *length, blockPosition, blockCount); + 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(device, position, *length, + 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(device, blockPosition, blockCount, - buffer, length); + result = usb_disk_block_read(lun, blockPosition, blockCount, buffer, + length); } benaphore_unlock(&device->lock); @@ -809,7 +888,8 @@ usb_disk_write(void *cookie, off_t position, const void *buffer, size_t *length) { TRACE("write(%lld, %ld)\n", position, *length); - disk_device *device = (disk_device *)cookie; + device_lun *lun = (device_lun *)cookie; + disk_device *device = lun->device; if (device->removed) { *length = 0; return B_DEV_NOT_READY; @@ -822,22 +902,22 @@ usb_disk_write(void *cookie, off_t position, const void *buffer, status_t result = B_ERROR; uint32 blockPosition = 0; uint16 blockCount = 0; - bool needsPartial = usb_disk_needs_partial_buffer(device, position, + 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(device, position, *length, + 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 * device->block_size; - result = usb_disk_block_write(device, blockPosition, blockCount, + 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(device, blockPosition, blockCount, + result = usb_disk_block_write(lun, blockPosition, blockCount, (void *)buffer, length); } @@ -881,6 +961,7 @@ init_driver() gDeviceList = NULL; gDeviceCount = 0; + gLunCount = 0; status_t result = benaphore_init(&gDeviceListLock, "usb_disk device list lock"); if (result < B_OK) { TRACE("failed to create device list lock\n"); @@ -931,7 +1012,7 @@ publish_devices() gDeviceNames = NULL; } - gDeviceNames = (char **)malloc(sizeof(char *) * (gDeviceCount + 1)); + gDeviceNames = (char **)malloc(sizeof(char *) * (gLunCount + 1)); if (gDeviceNames == NULL) return NULL; @@ -939,7 +1020,9 @@ publish_devices() benaphore_lock(&gDeviceListLock); disk_device *device = gDeviceList; while (device) { - gDeviceNames[index++] = strdup(device->name); + for (uint8 i = 0; i < device->lun_count; i++) + gDeviceNames[index++] = strdup(device->luns[i]->name); + device = (disk_device *)device->link; } 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 3ea6dec11b..c57909cf74 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,7 @@ #define REQUEST_MASS_STORAGE_RESET 0xff #define REQUEST_GET_MAX_LUN 0xfe +#define MAX_LOGICAL_UNIT_NUMBER 15 #define CBW_SIGNATURE 0x43425355 #define CBW_DATA_OUTPUT 0x00 @@ -24,12 +25,14 @@ #define CSW_STATUS_COMMAND_FAILED 0x01 #define CSW_STATUS_PHASE_ERROR 0x02 +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; bool removed; uint32 open_count; benaphore lock; - char name[32]; void * link; // device state @@ -37,22 +40,35 @@ typedef struct disk_device_s { usb_pipe bulk_out; uint8 interface; uint32 current_tag; - bool should_sync; - uint8 lun; - - // device information through read capacity/inquiry - uint32 block_count; - uint32 block_size; - uint8 device_type; - bool removable; // used to store callback information sem_id notify; status_t status; size_t actual_length; + + // 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; +}; + + typedef struct command_block_wrapper_s { uint32 signature; uint32 tag;