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
This commit is contained in:
Wojciech Zajac 2014-06-26 14:05:41 +02:00 committed by Ben Gras
parent 61df9b64d1
commit 4219f982ac
3 changed files with 138 additions and 15 deletions

View File

@ -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_write_scsi_cmd(mass_storage_cbw *, scsi_transfer *);
static int create_read_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_mode_sense_scsi_cmd(mass_storage_cbw *);
static int create_request_sense_scsi_cmd(mass_storage_cbw *);
/*---------------------------* /*---------------------------*
* defined functions * * 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); return create_read_scsi_cmd(cbw, info);
case SCSI_MODE_SENSE: case SCSI_MODE_SENSE:
return create_mode_sense_scsi_cmd(cbw); return create_mode_sense_scsi_cmd(cbw);
case SCSI_REQUEST_SENSE:
return create_request_sense_scsi_cmd(cbw);
default: default:
MASS_MSG("Invalid SCSI command!"); MASS_MSG("Invalid SCSI command!");
return EXIT_FAILURE; 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 * * check_inquiry_reply *
*===========================================================================*/ *===========================================================================*/

View File

@ -27,25 +27,13 @@
#include "bulk.h" #include "bulk.h"
#define SCSI_FORMAT_UNIT (0x04)
#define SCSI_INQUIRY (0x12) #define SCSI_INQUIRY (0x12)
#define SCSI_START_STOP (0x1B)
#define SCSI_MODE_SELECT (0x55)
#define SCSI_MODE_SENSE (0x5A) #define SCSI_MODE_SENSE (0x5A)
#define SCSI_PREVENT_ALLOW (0x1E)
#define SCSI_READ (0x28) #define SCSI_READ (0x28)
#define SCSI_READ_12 (0xA8)
#define SCSI_READ_CAPACITY (0x25) #define SCSI_READ_CAPACITY (0x25)
#define SCSI_READ_FORMAT_CAP (0x23)
#define SCSI_REQUEST_SENSE (0x03) #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_TEST_UNIT_READY (0x00)
#define SCSI_VERIFY (0x2F)
#define SCSI_WRITE (0x2A) #define SCSI_WRITE (0x2A)
#define SCSI_WRITE_12 (0xAA)
#define SCSI_WRITE_VERIFY (0x2E)
#define SCSI_INQUIRY_DATA_LEN (36) #define SCSI_INQUIRY_DATA_LEN (36)
#define SCSI_INQUIRY_CMD_LEN (6) #define SCSI_INQUIRY_CMD_LEN (6)
@ -59,6 +47,9 @@
#define SCSI_READ_CAPACITY_DATA_LEN (8) #define SCSI_READ_CAPACITY_DATA_LEN (8)
#define SCSI_READ_CAPACITY_CMD_LEN (10) #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_DATA_LEN (0)
#define SCSI_TEST_CMD_LEN (6) #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_LBA(x) SCSI_RD4((x), 0)
#define SCSI_GET_READ_CAPACITY_BLEN(x) SCSI_RD4((x), 4) #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, \ #define SCSI_SET_TEST_OP_CODE(x) SCSI_WR1((x), 0, \
SCSI_TEST_UNIT_READY) SCSI_TEST_UNIT_READY)

View File

@ -24,6 +24,7 @@
#include <assert.h> #include <assert.h>
#include <limits.h> /* ULONG_MAX */ #include <limits.h> /* ULONG_MAX */
#include <time.h> /* nanosleep */
#include "common.h" #include "common.h"
#include "bulk.h" #include "bulk.h"
@ -62,6 +63,7 @@ static void ddekit_usb_task(void *);
/* Mass storage related prototypes */ /* Mass storage related prototypes */
static void mass_storage_task(void *); static void mass_storage_task(void *);
static int mass_storage_test(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_try_first_open(void);
static int mass_storage_transfer_restrictions(u64_t, unsigned long); static int mass_storage_transfer_restrictions(u64_t, unsigned long);
static ssize_t mass_storage_write(unsigned long, endpoint_t, iovec_t *, 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 * * defined variables *
*---------------------------*/ *---------------------------*/
#define MASS_PACKED __attribute__((__packed__))
/* Mass Storage callback structure */ /* Mass Storage callback structure */
static struct blockdriver mass_storage = { static struct blockdriver mass_storage = {
.bdr_type = BLOCKDRIVER_TYPE_DISK, .bdr_type = BLOCKDRIVER_TYPE_DISK,
@ -147,7 +151,11 @@ static unsigned char buffer[BUFFER_SIZE];
#define MAX_DESCRIPTORS_LEN 128 #define MAX_DESCRIPTORS_LEN 128
/* Maximum 'Test Unit Ready' command retries */ /* 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 * * defined functions *
@ -590,22 +598,113 @@ mass_storage_test(void)
{ {
int repeat; int repeat;
struct timespec test_wait;
MASS_DEBUG_DUMP; 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++) { for (repeat = 0; repeat < MAX_TEST_RETRIES; repeat++) {
/* SCSI TEST UNIT READY OUT stage */ /* SCSI TEST UNIT READY OUT stage */
if (mass_storage_send_scsi_cbw_out(SCSI_TEST_UNIT_READY, NULL)) 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 */ /* TODO: Only CSW failure should normally contribute to retry */
/* SCSI TEST UNIT READY IN stage */ /* SCSI TEST UNIT READY IN stage */
if (EXIT_SUCCESS == mass_storage_send_scsi_csw_in()) if (EXIT_SUCCESS == mass_storage_send_scsi_csw_in())
return EXIT_SUCCESS; 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())) { if ((r = mass_storage_try_first_open())) {
MASS_MSG("Opening mass storage device" MASS_MSG("Opening mass storage device"
" for the first time failed"); " 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; return r;
} }
@ -1356,6 +1460,8 @@ mass_storage_part(devminor_t minor)
/*===========================================================================* /*===========================================================================*
* mass_storage_geometry * * 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 #ifdef MASS_USE_GEOMETRY
static void static void
mass_storage_geometry(devminor_t minor, struct part_geom * part) mass_storage_geometry(devminor_t minor, struct part_geom * part)