usb: Add support for multiple-LUN mass storage devices
authorLudovic Courtès <ludo@gnu.org>
Tue, 5 Oct 2010 20:04:26 +0000 (22:04 +0200)
committerRemy Bohmer <linux@bohmer.net>
Wed, 13 Oct 2010 10:07:58 +0000 (12:07 +0200)
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>
common/usb_storage.c

index 76949b85c0f2793e4bccb4f1dbb63a04b259aed8..613c4f0f1f7e79a653ad6267a8341e7c30207f80 100644 (file)
@@ -204,6 +204,22 @@ int usb_stor_info(void)
        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,12 +257,21 @@ int usb_stor_scan(int mode)
                        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) {
@@ -882,6 +907,7 @@ static int usb_inquiry(ccb *srb, struct us_data *ss)
        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 @@ static int usb_request_sense(ccb *srb, struct us_data *ss)
        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 @@ static int usb_test_unit_ready(ccb *srb, struct us_data *ss)
        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 @@ static int usb_read_capacity(ccb *srb, struct us_data *ss)
        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 @@ static int usb_read_10(ccb *srb, struct us_data *ss, unsigned long start,
 {
        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 @@ static int usb_write_10(ccb *srb, struct us_data *ss, unsigned long start,
 {
        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;