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>
diff --git a/common/usb_storage.c b/common/usb_storage.c
index 76949b8..613c4f0 100644
--- a/common/usb_storage.c
+++ b/common/usb_storage.c
@@ -204,6 +204,22 @@
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
* to the user if mode = 1
@@ -241,13 +257,22 @@
break; /* no more devices avaiable */
if (usb_storage_probe(dev, 0, &usb_stor[usb_max_devs])) {
- /* ok, it is a storage devices
- * get info and fill it in
+ /* OK, it's a storage device. Iterate over its LUNs
+ * and populate `usb_dev_desc'.
*/
- if (usb_stor_get_info(dev, &usb_stor[usb_max_devs],
- &usb_dev_desc[usb_max_devs]) == 1)
+ int lun, max_lun, start = usb_max_devs;
+
+ 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++;
}
+ }
+ }
/* if storage device */
if (usb_max_devs == USB_MAX_STOR_DEV) {
printf("max USB Storage Device reached: %d stopping\n",
@@ -882,6 +907,7 @@
do {
memset(&srb->cmd[0], 0, 12);
srb->cmd[0] = SCSI_INQUIRY;
+ srb->cmd[1] = srb->lun << 5;
srb->cmd[4] = 36;
srb->datalen = 36;
srb->cmdlen = 12;
@@ -905,6 +931,7 @@
ptr = (char *)srb->pdata;
memset(&srb->cmd[0], 0, 12);
srb->cmd[0] = SCSI_REQ_SENSE;
+ srb->cmd[1] = srb->lun << 5;
srb->cmd[4] = 18;
srb->datalen = 18;
srb->pdata = &srb->sense_buf[0];
@@ -924,6 +951,7 @@
do {
memset(&srb->cmd[0], 0, 12);
srb->cmd[0] = SCSI_TST_U_RDY;
+ srb->cmd[1] = srb->lun << 5;
srb->datalen = 0;
srb->cmdlen = 12;
if (ss->transport(srb, ss) == USB_STOR_TRANSPORT_GOOD)
@@ -943,6 +971,7 @@
do {
memset(&srb->cmd[0], 0, 12);
srb->cmd[0] = SCSI_RD_CAPAC;
+ srb->cmd[1] = srb->lun << 5;
srb->datalen = 8;
srb->cmdlen = 12;
if (ss->transport(srb, ss) == USB_STOR_TRANSPORT_GOOD)
@@ -957,6 +986,7 @@
{
memset(&srb->cmd[0], 0, 12);
srb->cmd[0] = SCSI_READ10;
+ srb->cmd[1] = srb->lun << 5;
srb->cmd[2] = ((unsigned char) (start >> 24)) & 0xff;
srb->cmd[3] = ((unsigned char) (start >> 16)) & 0xff;
srb->cmd[4] = ((unsigned char) (start >> 8)) & 0xff;
@@ -973,6 +1003,7 @@
{
memset(&srb->cmd[0], 0, 12);
srb->cmd[0] = SCSI_WRITE10;
+ srb->cmd[1] = srb->lun << 5;
srb->cmd[2] = ((unsigned char) (start >> 24)) & 0xff;
srb->cmd[3] = ((unsigned char) (start >> 16)) & 0xff;
srb->cmd[4] = ((unsigned char) (start >> 8)) & 0xff;