Consumer USB disks usually have emulated 512 byte sectors at the
USB/SCSI level, which means SCSI Read/Write/Capacity 10 can only
handle up to 2TiB USB disks. Add support for the optional 16 byte
command variants to handle disks larger than that.

Disks smaller than 2 TiB should not be affected.

Tested with 2 different 4TiB disks as well as one 2TiB disk.

Signed-off-by: Ahmad Fatoum <[email protected]>
---
 drivers/usb/storage/usb.c | 94 +++++++++++++++++++++++++++++++++------
 include/scsi.h            |  5 +++
 2 files changed, 85 insertions(+), 14 deletions(-)

diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c
index 122af659820f..b417640186a2 100644
--- a/drivers/usb/storage/usb.c
+++ b/drivers/usb/storage/usb.c
@@ -157,6 +157,47 @@ static int usb_stor_test_unit_ready(struct us_blk_dev 
*usb_blkdev)
        return 0;
 }
 
+static int read_capacity_16(struct us_blk_dev *usb_blkdev)
+{
+       struct device_d *dev = &usb_blkdev->us->pusb_dev->dev;
+       unsigned char cmd[16];
+       const u8 datalen = 32;
+       u8 *data = xzalloc(datalen);
+       int ret;
+       sector_t lba;
+       unsigned sector_size;
+
+       memset(cmd, 0, 16);
+       cmd[0] = SERVICE_ACTION_IN_16;
+       cmd[1] = SAI_READ_CAPACITY_16;
+       cmd[13] = datalen;
+
+       ret = usb_stor_transport(usb_blkdev, cmd, sizeof(cmd), data, datalen,
+                                3, USB_STOR_NO_REQUEST_SENSE);
+
+       if (ret < 0) {
+               dev_warn(dev, "Read Capacity(16) failed\n");
+               return ret;
+       }
+
+       /* Note this is logical, not physical sector size */
+       sector_size = be32_to_cpup((u32 *)&data[8]);
+       lba = be64_to_cpup((u64 *)&data[0]);
+
+       dev_dbg(dev, "LBA (16) = 0x%llx w/ sector size = %u\n",
+               lba, sector_size);
+
+       if ((data[12] & 1) == 1) {
+               dev_warn(dev, "Protection unsupported\n");
+               return -ENOTSUPP;
+       }
+
+       usb_blkdev->blk.blockbits = SECTOR_SHIFT;
+       usb_blkdev->blk.num_blocks = lba + 1;
+
+       return sector_size;
+}
+
 static int read_capacity_10(struct us_blk_dev *usb_blkdev)
 {
        struct device_d *dev = &usb_blkdev->us->pusb_dev->dev;
@@ -174,7 +215,7 @@ static int read_capacity_10(struct us_blk_dev *usb_blkdev)
                                 3, USB_STOR_NO_REQUEST_SENSE);
 
        if (ret < 0) {
-               dev_dbg(dev, "Cannot read device capacity\n");
+               dev_warn(dev, "Read Capacity(10) failed\n");
                return ret;
        }
 
@@ -184,15 +225,6 @@ static int read_capacity_10(struct us_blk_dev *usb_blkdev)
        dev_dbg(dev, "LBA (10) = 0x%llx w/ sector size = %u\n",
                lba, sector_size);
 
-
-       if (lba == U32_MAX) {
-               lba = U32_MAX - 1;
-               dev_warn(dev,
-                        "Limiting device size due to 32 bit constraints\n");
-               /* To support LBA >= U32_MAX, a READ CAPACITY (16) should be 
issued instead */
-       }
-
-
        if (sector_size != SECTOR_SIZE)
                dev_warn(dev, "Support only %d bytes sectors\n", SECTOR_SIZE);
 
@@ -202,6 +234,20 @@ static int read_capacity_10(struct us_blk_dev *usb_blkdev)
        return SECTOR_SIZE;
 }
 
+static int usb_stor_io_16(struct us_blk_dev *usb_blkdev, u8 opcode,
+                         sector_t start, u8 *data, u16 blocks)
+{
+       u8 cmd[16];
+
+       memset(cmd, 0, sizeof(cmd));
+       cmd[0] = opcode;
+       put_unaligned_be64(start, &cmd[2]);
+       put_unaligned_be32(blocks, &cmd[10]);
+
+       return usb_stor_transport(usb_blkdev, cmd, sizeof(cmd), data,
+                                 blocks * SECTOR_SIZE, 10, 0);
+}
+
 static int usb_stor_io_10(struct us_blk_dev *usb_blkdev, u8 opcode,
                          sector_t start, u8 *data, u16 blocks)
 {
@@ -232,6 +278,7 @@ static int usb_stor_blk_io(struct block_device *disk_dev,
                                                   blk);
        struct us_data *us = pblk_dev->us;
        struct device_d *dev = &us->pusb_dev->dev;
+       int result;
 
        /* ensure unit ready */
        dev_dbg(dev, "Testing for unit ready\n");
@@ -248,13 +295,24 @@ static int usb_stor_blk_io(struct block_device *disk_dev,
        while (sector_count > 0) {
                u16 n = min_t(blkcnt_t, sector_count, US_MAX_IO_BLK);
 
-               if (usb_stor_io_10(pblk_dev,
-                                  read ? SCSI_READ10 : SCSI_WRITE10,
-                                  sector_start,
-                                  buffer, n)) {
+               if (disk_dev->num_blocks > 0xffffffff) {
+                       result = usb_stor_io_16(pblk_dev,
+                                               read ? SCSI_READ16 : 
SCSI_WRITE16,
+                                               sector_start,
+                                               buffer, n);
+               } else {
+
+                       result = usb_stor_io_10(pblk_dev,
+                                               read ? SCSI_READ10 : 
SCSI_WRITE10,
+                                               sector_start,
+                                               buffer, n);
+               }
+
+               if (result) {
                        dev_dbg(dev, "I/O error at sector %llu\n", 
sector_start);
                        break;
                }
+
                sector_start += n;
                sector_count -= n;
                buffer += n * SECTOR_SIZE;
@@ -320,6 +378,14 @@ static int usb_stor_init_blkdev(struct us_blk_dev 
*pblk_dev)
        if (result < 0)
                return result;
 
+       if (pblk_dev->blk.num_blocks > 0xffffffff) {
+               result = read_capacity_16(pblk_dev);
+               if (result < 0) {
+                       dev_notice(dev, "Using 0xffffffff as device size\n");
+                       pblk_dev->blk.num_blocks = 1 + (sector_t) 0xffffffff;
+               }
+       }
+
        dev_dbg(dev, "Capacity = 0x%llx, blockshift = 0x%x\n",
                 pblk_dev->blk.num_blocks, pblk_dev->blk.blockbits);
 
diff --git a/include/scsi.h b/include/scsi.h
index e2397489ead9..f84513b813e9 100644
--- a/include/scsi.h
+++ b/include/scsi.h
@@ -109,6 +109,7 @@
 #define SCSI_MED_REMOVL        0x1E            /* Prevent/Allow medium Removal 
(O) */
 #define SCSI_READ6     0x08            /* Read 6-byte (MANDATORY) */
 #define SCSI_READ10    0x28            /* Read 10-byte (MANDATORY) */
+#define SCSI_READ16    0x88            /* Read 16-byte (O) */
 #define SCSI_RD_CAPAC  0x25            /* Read Capacity (MANDATORY) */
 #define SCSI_RD_DEFECT 0x37            /* Read Defect Data (O) */
 #define SCSI_READ_LONG 0x3E            /* Read Long (O) */
@@ -128,10 +129,14 @@
 #define SCSI_VERIFY    0x2F            /* Verify (O) */
 #define SCSI_WRITE6    0x0A            /* Write 6-Byte (MANDATORY) */
 #define SCSI_WRITE10   0x2A            /* Write 10-Byte (MANDATORY) */
+#define SCSI_WRITE16   0x8A            /* Write 16-Byte (O) */
 #define SCSI_WRT_VERIFY        0x2E            /* Write and Verify (O) */
 #define SCSI_WRITE_LONG        0x3F            /* Write Long (O) */
 #define SCSI_WRITE_SAME        0x41            /* Write Same (O) */
 
+#define SERVICE_ACTION_IN_16   0x9e
+/* values for service action in */
+#define        SAI_READ_CAPACITY_16    0x10
 
 /****************************************************************************
  * decleration of functions which have to reside in the LowLevel Part Driver
-- 
2.29.2


_______________________________________________
barebox mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/barebox

Reply via email to