]> git.ipfire.org Git - thirdparty/u-boot.git/blobdiff - common/usb_storage.c
usb: kbd: Add probe quirk for Apple and Keychron keyboards
[thirdparty/u-boot.git] / common / usb_storage.c
index a91b1c0d2f925eed06881d14ab85afe398eac423..774d5bdf54b4be7d56bfe12b5aaf86cc2d5bf248 100644 (file)
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0+
 /*
  * Most of this source has been derived from the Linux USB
  * project:
@@ -17,8 +18,6 @@
  *
  * BBB support based on /sys/dev/usb/umass.c from
  * FreeBSD.
- *
- * SPDX-License-Identifier:    GPL-2.0+
  */
 
 /* Note:
 
 
 #include <common.h>
+#include <blk.h>
+#include <bootdev.h>
 #include <command.h>
 #include <dm.h>
 #include <errno.h>
-#include <inttypes.h>
+#include <log.h>
 #include <mapmem.h>
 #include <memalign.h>
 #include <asm/byteorder.h>
+#include <asm/cache.h>
 #include <asm/processor.h>
 #include <dm/device-internal.h>
 #include <dm/lists.h>
+#include <linux/delay.h>
 
 #include <part.h>
 #include <usb.h>
@@ -68,7 +71,7 @@ static __u32 CBWTag;
 
 static int usb_max_devs; /* number of highest available usb device */
 
-#ifndef CONFIG_BLK
+#if !CONFIG_IS_ENABLED(BLK)
 static struct blk_desc usb_dev_desc[USB_MAX_STOR_DEV];
 #endif
 
@@ -92,16 +95,17 @@ struct us_data {
        int             action;                 /* what to do */
        int             ip_wanted;              /* needed */
        int             *irq_handle;            /* for USB int requests */
-       unsigned int    irqpipe;                /* pipe for release_irq */
+       unsigned int    irqpipe;                /* pipe for release_irq */
        unsigned char   irqmaxp;                /* max packed for irq Pipe */
        unsigned char   irqinterval;            /* Intervall for IRQ Pipe */
        struct scsi_cmd *srb;                   /* current srb */
        trans_reset     transport_reset;        /* reset routine */
        trans_cmnd      transport;              /* transport routine */
        unsigned short  max_xfer_blk;           /* maximum transfer blocks */
+       bool            cmd12;                  /* use 12-byte commands (RBC/UFI) */
 };
 
-#ifndef CONFIG_BLK
+#if !CONFIG_IS_ENABLED(BLK)
 static struct us_data usb_stor[USB_MAX_STOR_DEV];
 #endif
 
@@ -113,7 +117,7 @@ int usb_stor_get_info(struct usb_device *dev, struct us_data *us,
                      struct blk_desc *dev_desc);
 int usb_storage_probe(struct usb_device *dev, unsigned int ifnum,
                      struct us_data *ss);
-#ifdef CONFIG_BLK
+#if CONFIG_IS_ENABLED(BLK)
 static unsigned long usb_stor_read(struct udevice *dev, lbaint_t blknr,
                                   lbaint_t blkcnt, void *buffer);
 static unsigned long usb_stor_write(struct udevice *dev, lbaint_t blknr,
@@ -138,13 +142,13 @@ static void usb_show_progress(void)
 int usb_stor_info(void)
 {
        int count = 0;
-#ifdef CONFIG_BLK
+#if CONFIG_IS_ENABLED(BLK)
        struct udevice *dev;
 
-       for (blk_first_device(IF_TYPE_USB, &dev);
+       for (blk_first_device(UCLASS_USB, &dev);
             dev;
             blk_next_device(&dev)) {
-               struct blk_desc *desc = dev_get_uclass_platdata(dev);
+               struct blk_desc *desc = dev_get_uclass_plat(dev);
 
                printf("  Device %d: ", desc->devnum);
                dev_print(desc);
@@ -188,7 +192,7 @@ static int usb_stor_probe_device(struct usb_device *udev)
 {
        int lun, max_lun;
 
-#ifdef CONFIG_BLK
+#if CONFIG_IS_ENABLED(BLK)
        struct us_data *data;
        int ret;
 #else
@@ -199,13 +203,13 @@ static int usb_stor_probe_device(struct usb_device *udev)
 #endif
 
        debug("\n\nProbing for storage\n");
-#ifdef CONFIG_BLK
+#if CONFIG_IS_ENABLED(BLK)
        /*
-        * We store the us_data in the mass storage device's platdata. It
+        * We store the us_data in the mass storage device's plat. It
         * is shared by all LUNs (block devices) attached to this mass storage
         * device.
         */
-       data = dev_get_platdata(udev->dev);
+       data = dev_get_plat(udev->dev);
        if (!usb_storage_probe(udev, 0, data))
                return 0;
        max_lun = usb_get_max_lun(data);
@@ -216,21 +220,19 @@ static int usb_stor_probe_device(struct usb_device *udev)
 
                snprintf(str, sizeof(str), "lun%d", lun);
                ret = blk_create_devicef(udev->dev, "usb_storage_blk", str,
-                                        IF_TYPE_USB, usb_max_devs, 512, 0,
-                                        &dev);
+                                        UCLASS_USB, usb_max_devs,
+                                        DEFAULT_BLKSZ, 0, &dev);
                if (ret) {
                        debug("Cannot bind driver\n");
                        return ret;
                }
 
-               blkdev = dev_get_uclass_platdata(dev);
+               blkdev = dev_get_uclass_plat(dev);
                blkdev->target = 0xff;
                blkdev->lun = lun;
 
                ret = usb_stor_get_info(udev, data, blkdev);
-               if (ret == 1)
-                       ret = blk_prepare_device(dev);
-               if (!ret) {
+               if (ret == 1) {
                        usb_max_devs++;
                        debug("%s: Found device %p\n", __func__, udev);
                } else {
@@ -238,6 +240,21 @@ static int usb_stor_probe_device(struct usb_device *udev)
                        ret = device_unbind(dev);
                        if (ret)
                                return ret;
+                       continue;
+               }
+
+               ret = blk_probe_or_unbind(dev);
+               if (ret)
+                       return ret;
+
+               ret = bootdev_setup_for_sibling_blk(dev, "usb_bootdev");
+               if (ret) {
+                       int ret2;
+
+                       ret2 = device_unbind(dev);
+                       if (ret2)
+                               return log_msg_ret("bootdev", ret2);
+                       return log_msg_ret("bootdev", ret);
                }
        }
 #else
@@ -264,7 +281,7 @@ static int usb_stor_probe_device(struct usb_device *udev)
 
                blkdev = &usb_dev_desc[usb_max_devs];
                memset(blkdev, '\0', sizeof(struct blk_desc));
-               blkdev->if_type = IF_TYPE_USB;
+               blkdev->uclass_id = UCLASS_USB;
                blkdev->devnum = usb_max_devs;
                blkdev->part_type = PART_TYPE_UNKNOWN;
                blkdev->target = 0xff;
@@ -303,7 +320,7 @@ int usb_stor_scan(int mode)
        if (mode == 1)
                printf("       scanning usb for storage devices... ");
 
-#ifndef CONFIG_DM_USB
+#if !CONFIG_IS_ENABLED(DM_USB)
        unsigned char i;
 
        usb_disable_asynch(1); /* asynch transfer not allowed */
@@ -343,7 +360,7 @@ static void usb_show_srb(struct scsi_cmd *pccb)
 {
        int i;
        printf("SRB: len %d datalen 0x%lX\n ", pccb->cmdlen, pccb->datalen);
-       for (i = 0; i < 12; i++)
+       for (i = 0; i < pccb->cmdlen; i++)
                printf("%02X ", pccb->cmd[i]);
        printf("\n");
 }
@@ -431,8 +448,8 @@ static int us_one_transfer(struct us_data *us, int pipe, char *buf, int length)
                                        return 0;
                                }
                                /* if our try counter reaches 0, bail out */
-                                       debug(" %ld, data %d\n",
-                                             us->pusb_dev->status, partial);
+                               debug(" %ld, data %d\n",
+                                     us->pusb_dev->status, partial);
                                if (!maxtry--)
                                                return result;
                        }
@@ -654,8 +671,8 @@ static int usb_stor_CBI_get_status(struct scsi_cmd *srb, struct us_data *us)
        int timeout;
 
        us->ip_wanted = 1;
-       submit_int_msg(us->pusb_dev, us->irqpipe,
-                       (void *) &us->ip_data, us->irqmaxp, us->irqinterval);
+       usb_int_msg(us->pusb_dev, us->irqpipe,
+                   (void *)&us->ip_data, us->irqmaxp, us->irqinterval, false);
        timeout = 1000;
        while (timeout--) {
                if (us->ip_wanted == 0)
@@ -882,7 +899,7 @@ do_retry:
        psrb->cmd[4] = 18;
        psrb->datalen = 18;
        psrb->pdata = &srb->sense_buf[0];
-       psrb->cmdlen = 12;
+       psrb->cmdlen = us->cmd12 ? 12 : 6;
        /* issue the command */
        result = usb_stor_CB_comdat(psrb, us);
        debug("auto request returned %d\n", result);
@@ -942,31 +959,32 @@ do_retry:
 static void usb_stor_set_max_xfer_blk(struct usb_device *udev,
                                      struct us_data *us)
 {
-       unsigned short blk;
-       size_t __maybe_unused size;
-       int __maybe_unused ret;
-
-#ifndef CONFIG_DM_USB
-#ifdef CONFIG_USB_EHCI_HCD
        /*
-        * The U-Boot EHCI driver can handle any transfer length as long as
-        * there is enough free heap space left, but the SCSI READ(10) and
-        * WRITE(10) commands are limited to 65535 blocks.
+        * Limit the total size of a transfer to 120 KB.
+        *
+        * Some devices are known to choke with anything larger. It seems like
+        * the problem stems from the fact that original IDE controllers had
+        * only an 8-bit register to hold the number of sectors in one transfer
+        * and even those couldn't handle a full 256 sectors.
+        *
+        * Because we want to make sure we interoperate with as many devices as
+        * possible, we will maintain a 240 sector transfer size limit for USB
+        * Mass Storage devices.
+        *
+        * Tests show that other operating have similar limits with Microsoft
+        * Windows 7 limiting transfers to 128 sectors for both USB2 and USB3
+        * and Apple Mac OS X 10.11 limiting transfers to 256 sectors for USB2
+        * and 2048 for USB3 devices.
         */
-       blk = USHRT_MAX;
-#else
-       blk = 20;
-#endif
-#else
+       unsigned short blk = 240;
+
+#if CONFIG_IS_ENABLED(DM_USB)
+       size_t size;
+       int ret;
+
        ret = usb_get_max_xfer_size(udev, (size_t *)&size);
-       if (ret < 0) {
-               /* unimplemented, let's use default 20 */
-               blk = 20;
-       } else {
-               if (size > USHRT_MAX * 512)
-                       size = USHRT_MAX * 512;
+       if ((ret >= 0) && (size < blk * 512))
                blk = size / 512;
-       }
 #endif
 
        us->max_xfer_blk = blk;
@@ -982,7 +1000,7 @@ static int usb_inquiry(struct scsi_cmd *srb, struct us_data *ss)
                srb->cmd[1] = srb->lun << 5;
                srb->cmd[4] = 36;
                srb->datalen = 36;
-               srb->cmdlen = 12;
+               srb->cmdlen = ss->cmd12 ? 12 : 6;
                i = ss->transport(srb, ss);
                debug("inquiry returns %d\n", i);
                if (i == 0)
@@ -1007,7 +1025,7 @@ static int usb_request_sense(struct scsi_cmd *srb, struct us_data *ss)
        srb->cmd[4] = 18;
        srb->datalen = 18;
        srb->pdata = &srb->sense_buf[0];
-       srb->cmdlen = 12;
+       srb->cmdlen = ss->cmd12 ? 12 : 6;
        ss->transport(srb, ss);
        debug("Request Sense returned %02X %02X %02X\n",
              srb->sense_buf[2], srb->sense_buf[12],
@@ -1025,7 +1043,7 @@ static int usb_test_unit_ready(struct scsi_cmd *srb, struct us_data *ss)
                srb->cmd[0] = SCSI_TST_U_RDY;
                srb->cmd[1] = srb->lun << 5;
                srb->datalen = 0;
-               srb->cmdlen = 12;
+               srb->cmdlen = ss->cmd12 ? 12 : 6;
                if (ss->transport(srb, ss) == USB_STOR_TRANSPORT_GOOD) {
                        ss->flags |= USB_READY;
                        return 0;
@@ -1057,7 +1075,7 @@ static int usb_read_capacity(struct scsi_cmd *srb, struct us_data *ss)
                srb->cmd[0] = SCSI_RD_CAPAC;
                srb->cmd[1] = srb->lun << 5;
                srb->datalen = 8;
-               srb->cmdlen = 12;
+               srb->cmdlen = ss->cmd12 ? 12 : 10;
                if (ss->transport(srb, ss) == USB_STOR_TRANSPORT_GOOD)
                        return 0;
        } while (retry--);
@@ -1077,7 +1095,7 @@ static int usb_read_10(struct scsi_cmd *srb, struct us_data *ss,
        srb->cmd[5] = ((unsigned char) (start)) & 0xff;
        srb->cmd[7] = ((unsigned char) (blocks >> 8)) & 0xff;
        srb->cmd[8] = (unsigned char) blocks & 0xff;
-       srb->cmdlen = 12;
+       srb->cmdlen = ss->cmd12 ? 12 : 10;
        debug("read10: start %lx blocks %x\n", start, blocks);
        return ss->transport(srb, ss);
 }
@@ -1094,7 +1112,7 @@ static int usb_write_10(struct scsi_cmd *srb, struct us_data *ss,
        srb->cmd[5] = ((unsigned char) (start)) & 0xff;
        srb->cmd[7] = ((unsigned char) (blocks >> 8)) & 0xff;
        srb->cmd[8] = (unsigned char) blocks & 0xff;
-       srb->cmdlen = 12;
+       srb->cmdlen = ss->cmd12 ? 12 : 10;
        debug("write10: start %lx blocks %x\n", start, blocks);
        return ss->transport(srb, ss);
 }
@@ -1123,7 +1141,7 @@ static void usb_bin_fixup(struct usb_device_descriptor descriptor,
 }
 #endif /* CONFIG_USB_BIN_FIXUP */
 
-#ifdef CONFIG_BLK
+#if CONFIG_IS_ENABLED(BLK)
 static unsigned long usb_stor_read(struct udevice *dev, lbaint_t blknr,
                                   lbaint_t blkcnt, void *buffer)
 #else
@@ -1138,15 +1156,15 @@ static unsigned long usb_stor_read(struct blk_desc *block_dev, lbaint_t blknr,
        struct us_data *ss;
        int retry;
        struct scsi_cmd *srb = &usb_ccb;
-#ifdef CONFIG_BLK
+#if CONFIG_IS_ENABLED(BLK)
        struct blk_desc *block_dev;
 #endif
 
        if (blkcnt == 0)
                return 0;
        /* Setup  device */
-#ifdef CONFIG_BLK
-       block_dev = dev_get_uclass_platdata(dev);
+#if CONFIG_IS_ENABLED(BLK)
+       block_dev = dev_get_uclass_plat(dev);
        udev = dev_get_parent_priv(dev_get_parent(dev));
        debug("\nusb_read: udev %d\n", block_dev->devnum);
 #else
@@ -1160,13 +1178,14 @@ static unsigned long usb_stor_read(struct blk_desc *block_dev, lbaint_t blknr,
        ss = (struct us_data *)udev->privptr;
 
        usb_disable_asynch(1); /* asynch transfer not allowed */
+       usb_lock_async(udev, 1);
        srb->lun = block_dev->lun;
        buf_addr = (uintptr_t)buffer;
        start = blknr;
        blks = blkcnt;
 
-       debug("\nusb_read: dev %d startblk " LBAF ", blccnt " LBAF " buffer %"
-             PRIxPTR "\n", block_dev->devnum, start, blks, buf_addr);
+       debug("\nusb_read: dev %d startblk " LBAF ", blccnt " LBAF " buffer %lx\n",
+             block_dev->devnum, start, blks, buf_addr);
 
        do {
                /* XXX need some comment here */
@@ -1183,6 +1202,7 @@ retry_it:
                srb->pdata = (unsigned char *)buf_addr;
                if (usb_read_10(srb, ss, start, smallblks)) {
                        debug("Read ERROR\n");
+                       ss->flags &= ~USB_READY;
                        usb_request_sense(srb, ss);
                        if (retry--)
                                goto retry_it;
@@ -1193,19 +1213,18 @@ retry_it:
                blks -= smallblks;
                buf_addr += srb->datalen;
        } while (blks != 0);
-       ss->flags &= ~USB_READY;
 
-       debug("usb_read: end startblk " LBAF
-             ", blccnt %x buffer %" PRIxPTR "\n",
+       debug("usb_read: end startblk " LBAF ", blccnt %x buffer %lx\n",
              start, smallblks, buf_addr);
 
+       usb_lock_async(udev, 0);
        usb_disable_asynch(0); /* asynch transfer allowed */
        if (blkcnt >= ss->max_xfer_blk)
                debug("\n");
        return blkcnt;
 }
 
-#ifdef CONFIG_BLK
+#if CONFIG_IS_ENABLED(BLK)
 static unsigned long usb_stor_write(struct udevice *dev, lbaint_t blknr,
                                    lbaint_t blkcnt, const void *buffer)
 #else
@@ -1220,7 +1239,7 @@ static unsigned long usb_stor_write(struct blk_desc *block_dev, lbaint_t blknr,
        struct us_data *ss;
        int retry;
        struct scsi_cmd *srb = &usb_ccb;
-#ifdef CONFIG_BLK
+#if CONFIG_IS_ENABLED(BLK)
        struct blk_desc *block_dev;
 #endif
 
@@ -1228,8 +1247,8 @@ static unsigned long usb_stor_write(struct blk_desc *block_dev, lbaint_t blknr,
                return 0;
 
        /* Setup  device */
-#ifdef CONFIG_BLK
-       block_dev = dev_get_uclass_platdata(dev);
+#if CONFIG_IS_ENABLED(BLK)
+       block_dev = dev_get_uclass_plat(dev);
        udev = dev_get_parent_priv(dev_get_parent(dev));
        debug("\nusb_read: udev %d\n", block_dev->devnum);
 #else
@@ -1243,14 +1262,15 @@ static unsigned long usb_stor_write(struct blk_desc *block_dev, lbaint_t blknr,
        ss = (struct us_data *)udev->privptr;
 
        usb_disable_asynch(1); /* asynch transfer not allowed */
+       usb_lock_async(udev, 1);
 
        srb->lun = block_dev->lun;
        buf_addr = (uintptr_t)buffer;
        start = blknr;
        blks = blkcnt;
 
-       debug("\nusb_write: dev %d startblk " LBAF ", blccnt " LBAF " buffer %"
-             PRIxPTR "\n", block_dev->devnum, start, blks, buf_addr);
+       debug("\nusb_write: dev %d startblk " LBAF ", blccnt " LBAF " buffer %lx\n",
+             block_dev->devnum, start, blks, buf_addr);
 
        do {
                /* If write fails retry for max retry count else
@@ -1269,6 +1289,7 @@ retry_it:
                srb->pdata = (unsigned char *)buf_addr;
                if (usb_write_10(srb, ss, start, smallblks)) {
                        debug("Write ERROR\n");
+                       ss->flags &= ~USB_READY;
                        usb_request_sense(srb, ss);
                        if (retry--)
                                goto retry_it;
@@ -1279,11 +1300,11 @@ retry_it:
                blks -= smallblks;
                buf_addr += srb->datalen;
        } while (blks != 0);
-       ss->flags &= ~USB_READY;
 
-       debug("usb_write: end startblk " LBAF ", blccnt %x buffer %"
-             PRIxPTR "\n", start, smallblks, buf_addr);
+       debug("usb_write: end startblk " LBAF ", blccnt %x buffer %lx\n",
+             start, smallblks, buf_addr);
 
+       usb_lock_async(udev, 0);
        usb_disable_asynch(0); /* asynch transfer allowed */
        if (blkcnt >= ss->max_xfer_blk)
                debug("\n");
@@ -1397,6 +1418,11 @@ int usb_storage_probe(struct usb_device *dev, unsigned int ifnum,
                printf("Sorry, protocol %d not yet supported.\n", ss->subclass);
                return 0;
        }
+
+       /* UFI uses 12-byte commands (like RBC, unlike SCSI) */
+       if (ss->subclass == US_SC_UFI)
+               ss->cmd12 = true;
+
        if (ss->ep_int) {
                /* we had found an interrupt endpoint, prepare irq pipe
                 * set up the IRQ pipe and handler
@@ -1474,10 +1500,10 @@ int usb_stor_get_info(struct usb_device *dev, struct us_data *ss,
        memset(pccb->pdata, 0, 8);
        if (usb_read_capacity(pccb, ss) != 0) {
                printf("READ_CAP ERROR\n");
+               ss->flags &= ~USB_READY;
                cap[0] = 2880;
                cap[1] = 0x200;
        }
-       ss->flags &= ~USB_READY;
        debug("Read Capacity returns: 0x%08x, 0x%08x\n", cap[0], cap[1]);
 #if 0
        if (cap[0] > (0x200000 * 10)) /* greater than 10 GByte */
@@ -1500,7 +1526,7 @@ int usb_stor_get_info(struct usb_device *dev, struct us_data *ss,
        return 1;
 }
 
-#ifdef CONFIG_DM_USB
+#if CONFIG_IS_ENABLED(DM_USB)
 
 static int usb_mass_storage_probe(struct udevice *dev)
 {
@@ -1524,8 +1550,8 @@ U_BOOT_DRIVER(usb_mass_storage) = {
        .id     = UCLASS_MASS_STORAGE,
        .of_match = usb_mass_storage_ids,
        .probe = usb_mass_storage_probe,
-#ifdef CONFIG_BLK
-       .platdata_auto_alloc_size       = sizeof(struct us_data),
+#if CONFIG_IS_ENABLED(BLK)
+       .plat_auto      = sizeof(struct us_data),
 #endif
 };
 
@@ -1545,7 +1571,7 @@ static const struct usb_device_id mass_storage_id_table[] = {
 U_BOOT_USB_DEVICE(usb_mass_storage, mass_storage_id_table);
 #endif
 
-#ifdef CONFIG_BLK
+#if CONFIG_IS_ENABLED(BLK)
 static const struct blk_ops usb_storage_ops = {
        .read   = usb_stor_read,
        .write  = usb_stor_write,
@@ -1558,8 +1584,8 @@ U_BOOT_DRIVER(usb_storage_blk) = {
 };
 #else
 U_BOOT_LEGACY_BLK(usb) = {
-       .if_typename    = "usb",
-       .if_type        = IF_TYPE_USB,
+       .uclass_idname  = "usb",
+       .uclass_id      = UCLASS_USB,
        .max_devs       = USB_MAX_STOR_DEV,
        .desc           = usb_dev_desc,
 };