From ac0a97298599d31d45e83b47234b453328d3613f Mon Sep 17 00:00:00 2001 From: Michael Lotz Date: Thu, 9 Apr 2009 20:47:10 +0000 Subject: [PATCH] Adding mode sense command to retrieve the write protected status. Doesn't work yet, so not enabled for now. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@30082 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- .../drivers/disk/usb/usb_disk/usb_disk.cpp | 37 ++++++++++++++++++- .../drivers/disk/usb/usb_disk/usb_disk.h | 1 + .../drivers/disk/usb/usb_disk/usb_disk_scsi.h | 16 ++++++++ 3 files changed, 52 insertions(+), 2 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 8a56fb3e32..8a17b250a3 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 @@ -134,6 +134,7 @@ status_t usb_disk_operation(device_lun *lun, uint8 operation, bool directionIn); 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); @@ -280,6 +281,10 @@ usb_disk_operation(device_lun *lun, uint8 operation, uint8 opLength, 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; } @@ -464,6 +469,26 @@ usb_disk_request_sense(device_lun *lun) } +status_t +usb_disk_mode_sense(device_lun *lun) +{ + uint32 dataLength = sizeof(scsi_mode_sense_6_parameter); + 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); + 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) { @@ -699,8 +724,16 @@ usb_disk_device_added(usb_device newDevice, void **cookie) 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) + if (ready == B_OK || ready == B_DEV_NO_MEDIA) { + if (ready == B_OK) { + // TODO: check for write protection + //if (usb_disk_mode_sense(lun) != B_OK) + lun->write_protected = false; + } + break; + } + snooze(10000); } @@ -956,7 +989,7 @@ usb_disk_ioctl(void *cookie, uint32 op, void *buffer, size_t length) geometry->sectors_per_track = geometry->head_count = 1; geometry->device_type = lun->device_type; geometry->removable = lun->removable; - geometry->read_only = (lun->device_type == B_CD); + 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); 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 37dc81bdea..307f3bbd68 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 @@ -69,6 +69,7 @@ struct device_lun_s { uint32 block_size; uint8 device_type; bool removable; + bool write_protected; }; 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 066a6ba762..c204468025 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 @@ -13,6 +13,7 @@ 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_READ_CAPACITY_10 = 0x25, SCSI_READ_10 = 0x28, @@ -69,6 +70,17 @@ typedef struct scsi_inquiry_6_parameter_s { 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; @@ -87,4 +99,8 @@ typedef enum { SCSI_SENSE_KEY_ABORTED_COMMAND = 0x0b, } scsi_sense_key; +// mode sense page code/parameter +#define SCSI_MODE_PAGE_DEVICE_CONFIGURATION 0x10 +#define SCSI_DEVICE_SPECIFIC_WRITE_PROTECT 0x80 + #endif // _USB_DISK_SCSI_H_