usb: Add support for multiple-LUN mass storage devices

This patch changes `usb_stor_scan' to scan all the LUNs of each mass
storage device.  It also fixes the various commands to correctly set
the LUN field.

Notably, it allows each LUN of GuruPlug's microSD card reader to be
accessed.

Signed-off-by: Ludovic Courtès <ludo@gnu.org>
Acked-by: Prafulla Wadaskar <prafulla@marvell.com>
This commit is contained in:
Ludovic Courtès 2010-10-05 22:04:26 +02:00 committed by Remy Bohmer
parent 98fae9707f
commit 99e9ed1f49

View file

@ -204,6 +204,22 @@ int usb_stor_info(void)
return 1; return 1;
} }
static unsigned int usb_get_max_lun(struct us_data *us)
{
int len;
unsigned char result;
len = usb_control_msg(us->pusb_dev,
usb_rcvctrlpipe(us->pusb_dev, 0),
US_BBB_GET_MAX_LUN,
USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
0, us->ifnum,
&result, sizeof(result),
USB_CNTL_TIMEOUT * 5);
USB_STOR_PRINTF("Get Max LUN -> len = %i, result = %i\n",
len, (int) result);
return (len > 0) ? result : 0;
}
/******************************************************************************* /*******************************************************************************
* scan the usb and reports device info * scan the usb and reports device info
* to the user if mode = 1 * to the user if mode = 1
@ -241,12 +257,21 @@ int usb_stor_scan(int mode)
break; /* no more devices avaiable */ break; /* no more devices avaiable */
if (usb_storage_probe(dev, 0, &usb_stor[usb_max_devs])) { if (usb_storage_probe(dev, 0, &usb_stor[usb_max_devs])) {
/* ok, it is a storage devices /* OK, it's a storage device. Iterate over its LUNs
* get info and fill it in * and populate `usb_dev_desc'.
*/ */
if (usb_stor_get_info(dev, &usb_stor[usb_max_devs], int lun, max_lun, start = usb_max_devs;
&usb_dev_desc[usb_max_devs]) == 1)
max_lun = usb_get_max_lun(&usb_stor[usb_max_devs]);
for (lun = 0;
lun <= max_lun && usb_max_devs < USB_MAX_STOR_DEV;
lun++) {
usb_dev_desc[usb_max_devs].lun = lun;
if (usb_stor_get_info(dev, &usb_stor[start],
&usb_dev_desc[usb_max_devs]) == 1) {
usb_max_devs++; usb_max_devs++;
}
}
} }
/* if storage device */ /* if storage device */
if (usb_max_devs == USB_MAX_STOR_DEV) { if (usb_max_devs == USB_MAX_STOR_DEV) {
@ -882,6 +907,7 @@ static int usb_inquiry(ccb *srb, struct us_data *ss)
do { do {
memset(&srb->cmd[0], 0, 12); memset(&srb->cmd[0], 0, 12);
srb->cmd[0] = SCSI_INQUIRY; srb->cmd[0] = SCSI_INQUIRY;
srb->cmd[1] = srb->lun << 5;
srb->cmd[4] = 36; srb->cmd[4] = 36;
srb->datalen = 36; srb->datalen = 36;
srb->cmdlen = 12; srb->cmdlen = 12;
@ -905,6 +931,7 @@ static int usb_request_sense(ccb *srb, struct us_data *ss)
ptr = (char *)srb->pdata; ptr = (char *)srb->pdata;
memset(&srb->cmd[0], 0, 12); memset(&srb->cmd[0], 0, 12);
srb->cmd[0] = SCSI_REQ_SENSE; srb->cmd[0] = SCSI_REQ_SENSE;
srb->cmd[1] = srb->lun << 5;
srb->cmd[4] = 18; srb->cmd[4] = 18;
srb->datalen = 18; srb->datalen = 18;
srb->pdata = &srb->sense_buf[0]; srb->pdata = &srb->sense_buf[0];
@ -924,6 +951,7 @@ static int usb_test_unit_ready(ccb *srb, struct us_data *ss)
do { do {
memset(&srb->cmd[0], 0, 12); memset(&srb->cmd[0], 0, 12);
srb->cmd[0] = SCSI_TST_U_RDY; srb->cmd[0] = SCSI_TST_U_RDY;
srb->cmd[1] = srb->lun << 5;
srb->datalen = 0; srb->datalen = 0;
srb->cmdlen = 12; srb->cmdlen = 12;
if (ss->transport(srb, ss) == USB_STOR_TRANSPORT_GOOD) if (ss->transport(srb, ss) == USB_STOR_TRANSPORT_GOOD)
@ -943,6 +971,7 @@ static int usb_read_capacity(ccb *srb, struct us_data *ss)
do { do {
memset(&srb->cmd[0], 0, 12); memset(&srb->cmd[0], 0, 12);
srb->cmd[0] = SCSI_RD_CAPAC; srb->cmd[0] = SCSI_RD_CAPAC;
srb->cmd[1] = srb->lun << 5;
srb->datalen = 8; srb->datalen = 8;
srb->cmdlen = 12; srb->cmdlen = 12;
if (ss->transport(srb, ss) == USB_STOR_TRANSPORT_GOOD) if (ss->transport(srb, ss) == USB_STOR_TRANSPORT_GOOD)
@ -957,6 +986,7 @@ static int usb_read_10(ccb *srb, struct us_data *ss, unsigned long start,
{ {
memset(&srb->cmd[0], 0, 12); memset(&srb->cmd[0], 0, 12);
srb->cmd[0] = SCSI_READ10; srb->cmd[0] = SCSI_READ10;
srb->cmd[1] = srb->lun << 5;
srb->cmd[2] = ((unsigned char) (start >> 24)) & 0xff; srb->cmd[2] = ((unsigned char) (start >> 24)) & 0xff;
srb->cmd[3] = ((unsigned char) (start >> 16)) & 0xff; srb->cmd[3] = ((unsigned char) (start >> 16)) & 0xff;
srb->cmd[4] = ((unsigned char) (start >> 8)) & 0xff; srb->cmd[4] = ((unsigned char) (start >> 8)) & 0xff;
@ -973,6 +1003,7 @@ static int usb_write_10(ccb *srb, struct us_data *ss, unsigned long start,
{ {
memset(&srb->cmd[0], 0, 12); memset(&srb->cmd[0], 0, 12);
srb->cmd[0] = SCSI_WRITE10; srb->cmd[0] = SCSI_WRITE10;
srb->cmd[1] = srb->lun << 5;
srb->cmd[2] = ((unsigned char) (start >> 24)) & 0xff; srb->cmd[2] = ((unsigned char) (start >> 24)) & 0xff;
srb->cmd[3] = ((unsigned char) (start >> 16)) & 0xff; srb->cmd[3] = ((unsigned char) (start >> 16)) & 0xff;
srb->cmd[4] = ((unsigned char) (start >> 8)) & 0xff; srb->cmd[4] = ((unsigned char) (start >> 8)) & 0xff;