+// SPDX-License-Identifier: GPL-2.0+
/*
* Most of this source has been derived from the Linux USB
* project:
*
* 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 <command.h>
#include <dm.h>
#include <errno.h>
-#include <inttypes.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>
};
#define US_DIRECTION(x) ((us_direction[x>>3] >> (x & 7)) & 1)
-static ccb usb_ccb __attribute__((aligned(ARCH_DMA_MINALIGN)));
+static struct scsi_cmd usb_ccb __aligned(ARCH_DMA_MINALIGN);
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
struct us_data;
-typedef int (*trans_cmnd)(ccb *cb, struct us_data *data);
+typedef int (*trans_cmnd)(struct scsi_cmd *cb, struct us_data *data);
typedef int (*trans_reset)(struct us_data *data);
struct us_data {
unsigned int irqpipe; /* pipe for release_irq */
unsigned char irqmaxp; /* max packed for irq Pipe */
unsigned char irqinterval; /* Intervall for IRQ Pipe */
- ccb *srb; /* current srb */
+ 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 */
};
-#ifdef CONFIG_USB_EHCI
-/*
- * 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.
- */
-#define USB_MAX_XFER_BLK 65535
-#else
-#define USB_MAX_XFER_BLK 20
-#endif
-
-#ifndef CONFIG_BLK
+#if !CONFIG_IS_ENABLED(BLK)
static struct us_data usb_stor[USB_MAX_STOR_DEV];
#endif
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,
#endif
void uhci_show_temp_int_td(void);
-#ifdef CONFIG_PARTITIONS
-struct blk_desc *usb_stor_get_dev(int index)
-{
-#ifdef CONFIG_BLK
- struct udevice *dev;
- int ret;
-
- ret = blk_get_device(IF_TYPE_USB, index, &dev);
- if (ret)
- return NULL;
- return dev_get_uclass_platdata(dev);
-#else
- return (index < usb_max_devs) ? &usb_dev_desc[index] : NULL;
-#endif
-}
-#endif
-
static void usb_show_progress(void)
{
debug(".");
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);
{
int lun, max_lun;
-#ifdef CONFIG_BLK
+#if CONFIG_IS_ENABLED(BLK)
struct us_data *data;
- char dev_name[30], *str;
int ret;
#else
int start;
#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
* is shared by all LUNs (block devices) attached to this mass storage
for (lun = 0; lun <= max_lun; lun++) {
struct blk_desc *blkdev;
struct udevice *dev;
+ char str[10];
- snprintf(dev_name, sizeof(dev_name), "%s.lun%d",
- udev->dev->name, lun);
- str = strdup(dev_name);
- if (!str)
- return -ENOMEM;
- ret = blk_create_device(udev->dev, "usb_storage_blk", str,
- IF_TYPE_USB, usb_max_devs, 512, 0, &dev);
+ 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);
if (ret) {
debug("Cannot bind driver\n");
return ret;
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 {
usb_max_devs = 0;
}
-#ifndef CONFIG_DM_USB
/*******************************************************************************
* scan the usb and reports device info
* to the user if mode = 1
*/
int usb_stor_scan(int mode)
{
- unsigned char i;
-
if (mode == 1)
printf(" scanning usb for storage devices... ");
+#if !CONFIG_IS_ENABLED(DM_USB)
+ unsigned char i;
+
usb_disable_asynch(1); /* asynch transfer not allowed */
usb_stor_reset();
} /* for */
usb_disable_asynch(0); /* asynch transfer allowed */
+#endif
printf("%d Storage Device(s) found\n", usb_max_devs);
if (usb_max_devs > 0)
return 0;
return -1;
}
-#endif
static int usb_stor_irq(struct usb_device *dev)
{
#ifdef DEBUG
-static void usb_show_srb(ccb *pccb)
+static void usb_show_srb(struct scsi_cmd *pccb)
{
int i;
printf("SRB: len %d datalen 0x%lX\n ", pccb->cmdlen, pccb->datalen);
* Set up the command for a BBB device. Note that the actual SCSI
* command is copied into cbw.CBWCDB.
*/
-static int usb_stor_BBB_comdat(ccb *srb, struct us_data *us)
+static int usb_stor_BBB_comdat(struct scsi_cmd *srb, struct us_data *us)
{
int result;
int actlen;
/* FIXME: we also need a CBI_command which sets up the completion
* interrupt, and waits for it
*/
-static int usb_stor_CB_comdat(ccb *srb, struct us_data *us)
+static int usb_stor_CB_comdat(struct scsi_cmd *srb, struct us_data *us)
{
int result = 0;
int dir_in, retry;
}
-static int usb_stor_CBI_get_status(ccb *srb, struct us_data *us)
+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)
/* clear a stall on an endpoint - special for BBB devices */
static int usb_stor_BBB_clear_endpt_stall(struct us_data *us, __u8 endpt)
{
- int result;
-
/* ENDPOINT_HALT = 0, so set value to 0 */
- result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev, 0),
- USB_REQ_CLEAR_FEATURE, USB_RECIP_ENDPOINT,
- 0, endpt, NULL, 0, USB_CNTL_TIMEOUT * 5);
- return result;
+ return usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev, 0),
+ USB_REQ_CLEAR_FEATURE, USB_RECIP_ENDPOINT, 0,
+ endpt, NULL, 0, USB_CNTL_TIMEOUT * 5);
}
-static int usb_stor_BBB_transport(ccb *srb, struct us_data *us)
+static int usb_stor_BBB_transport(struct scsi_cmd *srb, struct us_data *us)
{
int result, retry;
int dir_in;
return result;
}
-static int usb_stor_CB_transport(ccb *srb, struct us_data *us)
+static int usb_stor_CB_transport(struct scsi_cmd *srb, struct us_data *us)
{
int result, status;
- ccb *psrb;
- ccb reqsrb;
+ struct scsi_cmd *psrb;
+ struct scsi_cmd reqsrb;
int retry, notready;
psrb = &reqsrb;
return USB_STOR_TRANSPORT_FAILED;
}
+static void usb_stor_set_max_xfer_blk(struct usb_device *udev,
+ struct us_data *us)
+{
+ /*
+ * 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.
+ */
+ 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) && (size < blk * 512))
+ blk = size / 512;
+#endif
+
+ us->max_xfer_blk = blk;
+}
-static int usb_inquiry(ccb *srb, struct us_data *ss)
+static int usb_inquiry(struct scsi_cmd *srb, struct us_data *ss)
{
int retry, i;
retry = 5;
return 0;
}
-static int usb_request_sense(ccb *srb, struct us_data *ss)
+static int usb_request_sense(struct scsi_cmd *srb, struct us_data *ss)
{
char *ptr;
return 0;
}
-static int usb_test_unit_ready(ccb *srb, struct us_data *ss)
+static int usb_test_unit_ready(struct scsi_cmd *srb, struct us_data *ss)
{
int retries = 10;
return -1;
}
-static int usb_read_capacity(ccb *srb, struct us_data *ss)
+static int usb_read_capacity(struct scsi_cmd *srb, struct us_data *ss)
{
int retry;
/* XXX retries */
return -1;
}
-static int usb_read_10(ccb *srb, struct us_data *ss, unsigned long start,
- unsigned short blocks)
+static int usb_read_10(struct scsi_cmd *srb, struct us_data *ss,
+ unsigned long start, unsigned short blocks)
{
memset(&srb->cmd[0], 0, 12);
srb->cmd[0] = SCSI_READ10;
return ss->transport(srb, ss);
}
-static int usb_write_10(ccb *srb, struct us_data *ss, unsigned long start,
- unsigned short blocks)
+static int usb_write_10(struct scsi_cmd *srb, struct us_data *ss,
+ unsigned long start, unsigned short blocks)
{
memset(&srb->cmd[0], 0, 12);
srb->cmd[0] = SCSI_WRITE10;
}
#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
struct usb_device *udev;
struct us_data *ss;
int retry;
- ccb *srb = &usb_ccb;
-#ifdef CONFIG_BLK
+ struct scsi_cmd *srb = &usb_ccb;
+#if CONFIG_IS_ENABLED(BLK)
struct blk_desc *block_dev;
#endif
if (blkcnt == 0)
return 0;
/* Setup device */
-#ifdef CONFIG_BLK
+#if CONFIG_IS_ENABLED(BLK)
block_dev = dev_get_uclass_platdata(dev);
udev = dev_get_parent_priv(dev_get_parent(dev));
debug("\nusb_read: udev %d\n", block_dev->devnum);
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 */
retry = 2;
srb->pdata = (unsigned char *)buf_addr;
- if (blks > USB_MAX_XFER_BLK)
- smallblks = USB_MAX_XFER_BLK;
+ if (blks > ss->max_xfer_blk)
+ smallblks = ss->max_xfer_blk;
else
smallblks = (unsigned short) blks;
retry_it:
- if (smallblks == USB_MAX_XFER_BLK)
+ if (smallblks == ss->max_xfer_blk)
usb_show_progress();
srb->datalen = block_dev->blksz * smallblks;
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;
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 >= USB_MAX_XFER_BLK)
+ 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
struct usb_device *udev;
struct us_data *ss;
int retry;
- ccb *srb = &usb_ccb;
-#ifdef CONFIG_BLK
+ struct scsi_cmd *srb = &usb_ccb;
+#if CONFIG_IS_ENABLED(BLK)
struct blk_desc *block_dev;
#endif
return 0;
/* Setup device */
-#ifdef CONFIG_BLK
+#if CONFIG_IS_ENABLED(BLK)
block_dev = dev_get_uclass_platdata(dev);
udev = dev_get_parent_priv(dev_get_parent(dev));
debug("\nusb_read: udev %d\n", block_dev->devnum);
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
*/
retry = 2;
srb->pdata = (unsigned char *)buf_addr;
- if (blks > USB_MAX_XFER_BLK)
- smallblks = USB_MAX_XFER_BLK;
+ if (blks > ss->max_xfer_blk)
+ smallblks = ss->max_xfer_blk;
else
smallblks = (unsigned short) blks;
retry_it:
- if (smallblks == USB_MAX_XFER_BLK)
+ if (smallblks == ss->max_xfer_blk)
usb_show_progress();
srb->datalen = block_dev->blksz * smallblks;
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;
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 >= USB_MAX_XFER_BLK)
+ if (blkcnt >= ss->max_xfer_blk)
debug("\n");
return blkcnt;
ss->irqmaxp = usb_maxpacket(dev, ss->irqpipe);
dev->irq_handle = usb_stor_irq;
}
+
+ /* Set the maximum transfer size per host controller setting */
+ usb_stor_set_max_xfer_blk(dev, ss);
+
dev->privptr = (void *)ss;
return 1;
}
ALLOC_CACHE_ALIGN_BUFFER(u32, cap, 2);
ALLOC_CACHE_ALIGN_BUFFER(u8, usb_stor_buf, 36);
u32 capacity, blksz;
- ccb *pccb = &usb_ccb;
+ struct scsi_cmd *pccb = &usb_ccb;
pccb->pdata = usb_stor_buf;
" Request Sense returned %02X %02X %02X\n",
pccb->sense_buf[2], pccb->sense_buf[12],
pccb->sense_buf[13]);
- if (dev_desc->removable == 1) {
+ if (dev_desc->removable == 1)
dev_desc->type = perq;
- return 1;
- }
return 0;
}
pccb->pdata = (unsigned char *)cap;
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 */
return 1;
}
-#ifdef CONFIG_DM_USB
+#if CONFIG_IS_ENABLED(DM_USB)
static int usb_mass_storage_probe(struct udevice *dev)
{
.id = UCLASS_MASS_STORAGE,
.of_match = usb_mass_storage_ids,
.probe = usb_mass_storage_probe,
-#ifdef CONFIG_BLK
+#if CONFIG_IS_ENABLED(BLK)
.platdata_auto_alloc_size = sizeof(struct us_data),
#endif
};
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,