From 4219f982ac9cabf4d1262716087319d1e559812a Mon Sep 17 00:00:00 2001 From: Wojciech Zajac Date: Thu, 26 Jun 2014 14:05:41 +0200 Subject: [PATCH] USB storage . Added REQUEST SENSE command for usb_storage . In case of mass storage opening error, SCSI sense structure is dumped to stdout. . Removed unused, optional commands defines. . Temporary fix for unusual USB sticks Change-Id: Ia8a38900a8a80bfcdd6adb146fd54c8387cd6bb1 --- minix/drivers/usb/usb_storage/scsi.c | 22 ++++ minix/drivers/usb/usb_storage/scsi.h | 19 ++-- minix/drivers/usb/usb_storage/usb_storage.c | 112 +++++++++++++++++++- 3 files changed, 138 insertions(+), 15 deletions(-) diff --git a/minix/drivers/usb/usb_storage/scsi.c b/minix/drivers/usb/usb_storage/scsi.c index 8ed74d419..128039f8b 100644 --- a/minix/drivers/usb/usb_storage/scsi.c +++ b/minix/drivers/usb/usb_storage/scsi.c @@ -20,6 +20,7 @@ static int create_read_capacity_scsi_cmd(mass_storage_cbw *); static int create_write_scsi_cmd(mass_storage_cbw *, scsi_transfer *); static int create_read_scsi_cmd(mass_storage_cbw *, scsi_transfer *); static int create_mode_sense_scsi_cmd(mass_storage_cbw *); +static int create_request_sense_scsi_cmd(mass_storage_cbw *); /*---------------------------* * defined functions * @@ -47,6 +48,8 @@ create_scsi_cmd(mass_storage_cbw * cbw, int cmd, scsi_transfer * info) return create_read_scsi_cmd(cbw, info); case SCSI_MODE_SENSE: return create_mode_sense_scsi_cmd(cbw); + case SCSI_REQUEST_SENSE: + return create_request_sense_scsi_cmd(cbw); default: MASS_MSG("Invalid SCSI command!"); return EXIT_FAILURE; @@ -175,6 +178,25 @@ create_mode_sense_scsi_cmd(mass_storage_cbw * cbw) } +/*===========================================================================* + * create_request_sense_scsi_cmd * + *===========================================================================*/ +static int +create_request_sense_scsi_cmd(mass_storage_cbw * cbw) +{ + MASS_DEBUG_DUMP; + + cbw->dCBWDataTransferLength = SCSI_REQUEST_SENSE_DATA_LEN; + cbw->bCBWFlags = CBW_FLAGS_IN; + cbw->bCDBLength = SCSI_REQUEST_SENSE_CMD_LEN; + + SCSI_SET_REQUEST_SENSE_OP_CODE(cbw->CBWCB); + SCSI_SET_REQUEST_SENSE_ALLOC(cbw->CBWCB, SCSI_REQUEST_SENSE_DATA_LEN); + + return EXIT_SUCCESS; +} + + /*===========================================================================* * check_inquiry_reply * *===========================================================================*/ diff --git a/minix/drivers/usb/usb_storage/scsi.h b/minix/drivers/usb/usb_storage/scsi.h index 91d28ef75..32a728b7c 100644 --- a/minix/drivers/usb/usb_storage/scsi.h +++ b/minix/drivers/usb/usb_storage/scsi.h @@ -27,25 +27,13 @@ #include "bulk.h" -#define SCSI_FORMAT_UNIT (0x04) #define SCSI_INQUIRY (0x12) -#define SCSI_START_STOP (0x1B) -#define SCSI_MODE_SELECT (0x55) #define SCSI_MODE_SENSE (0x5A) -#define SCSI_PREVENT_ALLOW (0x1E) #define SCSI_READ (0x28) -#define SCSI_READ_12 (0xA8) #define SCSI_READ_CAPACITY (0x25) -#define SCSI_READ_FORMAT_CAP (0x23) #define SCSI_REQUEST_SENSE (0x03) -#define SCSI_REZERO_UNIT (0x01) -#define SCSI_SEEK (0x2B) -#define SCSI_SEND_DIAGNOSTIC (0x1D) #define SCSI_TEST_UNIT_READY (0x00) -#define SCSI_VERIFY (0x2F) #define SCSI_WRITE (0x2A) -#define SCSI_WRITE_12 (0xAA) -#define SCSI_WRITE_VERIFY (0x2E) #define SCSI_INQUIRY_DATA_LEN (36) #define SCSI_INQUIRY_CMD_LEN (6) @@ -59,6 +47,9 @@ #define SCSI_READ_CAPACITY_DATA_LEN (8) #define SCSI_READ_CAPACITY_CMD_LEN (10) +#define SCSI_REQUEST_SENSE_DATA_LEN (18) +#define SCSI_REQUEST_SENSE_CMD_LEN (6) + #define SCSI_TEST_DATA_LEN (0) #define SCSI_TEST_CMD_LEN (6) @@ -117,6 +108,10 @@ #define SCSI_GET_READ_CAPACITY_LBA(x) SCSI_RD4((x), 0) #define SCSI_GET_READ_CAPACITY_BLEN(x) SCSI_RD4((x), 4) +#define SCSI_SET_REQUEST_SENSE_OP_CODE(x) SCSI_WR1((x), 0, \ + SCSI_REQUEST_SENSE) +#define SCSI_SET_REQUEST_SENSE_ALLOC(x, alloc) SCSI_WR1((x), 4, (alloc)) + #define SCSI_SET_TEST_OP_CODE(x) SCSI_WR1((x), 0, \ SCSI_TEST_UNIT_READY) diff --git a/minix/drivers/usb/usb_storage/usb_storage.c b/minix/drivers/usb/usb_storage/usb_storage.c index ecafdccba..2303bdad1 100644 --- a/minix/drivers/usb/usb_storage/usb_storage.c +++ b/minix/drivers/usb/usb_storage/usb_storage.c @@ -24,6 +24,7 @@ #include #include /* ULONG_MAX */ +#include /* nanosleep */ #include "common.h" #include "bulk.h" @@ -62,6 +63,7 @@ static void ddekit_usb_task(void *); /* Mass storage related prototypes */ static void mass_storage_task(void *); static int mass_storage_test(void); +static int mass_storage_check_error(void); static int mass_storage_try_first_open(void); static int mass_storage_transfer_restrictions(u64_t, unsigned long); static ssize_t mass_storage_write(unsigned long, endpoint_t, iovec_t *, @@ -96,6 +98,8 @@ static int mass_storage_parse_descriptors(char *, unsigned int, urb_ep_config *, /*---------------------------* * defined variables * *---------------------------*/ +#define MASS_PACKED __attribute__((__packed__)) + /* Mass Storage callback structure */ static struct blockdriver mass_storage = { .bdr_type = BLOCKDRIVER_TYPE_DISK, @@ -147,7 +151,11 @@ static unsigned char buffer[BUFFER_SIZE]; #define MAX_DESCRIPTORS_LEN 128 /* Maximum 'Test Unit Ready' command retries */ -#define MAX_TEST_RETRIES 3 +#define MAX_TEST_RETRIES 20 + +/* 'Test Unit Ready' failure delay time (in nanoseconds) */ +#define NEXT_TEST_DELAY 50000000 /* 50ms */ + /*---------------------------* * defined functions * @@ -590,22 +598,113 @@ mass_storage_test(void) { int repeat; + struct timespec test_wait; + MASS_DEBUG_DUMP; + /* Delay between consecutive test commands, in case of their failure */ + test_wait.tv_nsec = NEXT_TEST_DELAY; + test_wait.tv_sec = 0; + for (repeat = 0; repeat < MAX_TEST_RETRIES; repeat++) { /* SCSI TEST UNIT READY OUT stage */ if (mass_storage_send_scsi_cbw_out(SCSI_TEST_UNIT_READY, NULL)) - return EXIT_FAILURE; + return EIO; /* TODO: Only CSW failure should normally contribute to retry */ /* SCSI TEST UNIT READY IN stage */ if (EXIT_SUCCESS == mass_storage_send_scsi_csw_in()) return EXIT_SUCCESS; + + /* Check for errors */ + if (mass_storage_check_error()) + return EIO; + + /* Ignore potential signal interruption (no return value check), + * since it causes driver termination anyway */ + if (nanosleep(&test_wait, NULL)) + MASS_MSG("Calling nanosleep() failed"); } - return EXIT_FAILURE; + MASS_MSG("Try, ignoring TEST UNIT READY errors"); + return EXIT_SUCCESS; +} + + +/*===========================================================================* + * mass_storage_check_error * + *===========================================================================*/ +static int +mass_storage_check_error(void) +{ + /* SCSI sense structure for local use */ + typedef struct MASS_PACKED scsi_sense { + + uint8_t code : 7; + uint8_t valid : 1; + uint8_t obsolete : 8; + uint8_t sense : 4; + uint8_t reserved : 1; + uint8_t ili : 1; + uint8_t eom : 1; + uint8_t filemark : 1; + uint32_t information : 32; + uint8_t additional_len : 8; + uint32_t command_specific : 32; + uint8_t additional_code : 8; + uint8_t additional_qual : 8; + uint8_t unit_code : 8; + uint8_t key_specific1 : 7; + uint8_t sksv : 1; + uint16_t key_specific2 : 16; + } + scsi_sense; + + /* Sense variable to hold received data */ + scsi_sense sense; + + MASS_DEBUG_DUMP; + + /* TODO: This should become compile-time assert */ + assert(sizeof(sense) == SCSI_REQUEST_SENSE_DATA_LEN); + + /* SCSI REQUEST SENSE OUT stage */ + if (mass_storage_send_scsi_cbw_out(SCSI_REQUEST_SENSE, NULL)) + return EIO; + + /* SCSI REQUEST SENSE first IN stage */ + if (mass_storage_send_scsi_data_in(&sense, sizeof(sense))) + return EIO; + + /* SCSI REQUEST SENSE second IN stage */ + if (mass_storage_send_scsi_csw_in()) + return EIO; + + /* When any sense code is present something may have failed */ + if (sense.sense) { + MASS_MSG("SCSI sense: "); + MASS_MSG("code : %8X", sense.code ); + MASS_MSG("valid : %8X", sense.valid ); + MASS_MSG("obsolete : %8X", sense.obsolete ); + MASS_MSG("sense : %8X", sense.sense ); + MASS_MSG("reserved : %8X", sense.reserved ); + MASS_MSG("ili : %8X", sense.ili ); + MASS_MSG("eom : %8X", sense.eom ); + MASS_MSG("filemark : %8X", sense.filemark ); + MASS_MSG("information : %8X", sense.information ); + MASS_MSG("additional_len : %8X", sense.additional_len ); + MASS_MSG("command_specific : %8X", sense.command_specific); + MASS_MSG("additional_code : %8X", sense.additional_code ); + MASS_MSG("additional_qual : %8X", sense.additional_qual ); + MASS_MSG("unit_code : %8X", sense.unit_code ); + MASS_MSG("key_specific1 : %8X", sense.key_specific1 ); + MASS_MSG("sksv : %8X", sense.sksv ); + MASS_MSG("key_specific2 : %8X", sense.key_specific2 ); + } + + return EXIT_SUCCESS; } @@ -1072,6 +1171,11 @@ mass_storage_open(devminor_t minor, int UNUSED(access)) if ((r = mass_storage_try_first_open())) { MASS_MSG("Opening mass storage device" " for the first time failed"); + + /* TODO: This could be used in other places too */ + if (mass_storage_check_error()) + MASS_MSG("SCSI error check failed"); + return r; } @@ -1356,6 +1460,8 @@ mass_storage_part(devminor_t minor) /*===========================================================================* * mass_storage_geometry * *===========================================================================*/ +/* This command is optional for most mass storage devices + * It should rather be used with USB floppy disk reader */ #ifdef MASS_USE_GEOMETRY static void mass_storage_geometry(devminor_t minor, struct part_geom * part)