183d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+
2affae2bfSwdenk /*
3460c322fSWolfgang Denk * Most of this source has been derived from the Linux USB
4460c322fSWolfgang Denk * project:
5460c322fSWolfgang Denk * (c) 1999-2002 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
6460c322fSWolfgang Denk * (c) 2000 David L. Brown, Jr. (usb-storage@davidb.org)
7460c322fSWolfgang Denk * (c) 1999 Michael Gee (michael@linuxspecific.com)
8460c322fSWolfgang Denk * (c) 2000 Yggdrasil Computing, Inc.
9460c322fSWolfgang Denk *
10460c322fSWolfgang Denk *
11460c322fSWolfgang Denk * Adapted for U-Boot:
12460c322fSWolfgang Denk * (C) Copyright 2001 Denis Peter, MPL AG Switzerland
13acf277afSSimon Glass * Driver model conversion:
14acf277afSSimon Glass * (C) Copyright 2015 Google, Inc
15affae2bfSwdenk *
16149dded2Swdenk * For BBB support (C) Copyright 2003
17792a09ebSDetlev Zundel * Gary Jennejohn, DENX Software Engineering <garyj@denx.de>
18149dded2Swdenk *
19460c322fSWolfgang Denk * BBB support based on /sys/dev/usb/umass.c from
20149dded2Swdenk * FreeBSD.
21affae2bfSwdenk */
22affae2bfSwdenk
23affae2bfSwdenk /* Note:
24affae2bfSwdenk * Currently only the CBI transport protocoll has been implemented, and it
25affae2bfSwdenk * is only tested with a TEAC USB Floppy. Other Massstorages with CBI or CB
26affae2bfSwdenk * transport protocoll may work as well.
27affae2bfSwdenk */
28149dded2Swdenk /*
29149dded2Swdenk * New Note:
30149dded2Swdenk * Support for USB Mass Storage Devices (BBB) has been added. It has
31149dded2Swdenk * only been tested with USB memory sticks.
32149dded2Swdenk */
33affae2bfSwdenk
34affae2bfSwdenk
35affae2bfSwdenk #include <common.h>
36affae2bfSwdenk #include <command.h>
37acf277afSSimon Glass #include <dm.h>
3891557579SSimon Glass #include <errno.h>
3905108132SSimon Glass #include <mapmem.h>
40cf92e05cSSimon Glass #include <memalign.h>
41c918261cSChristian Eggers #include <asm/byteorder.h>
42affae2bfSwdenk #include <asm/processor.h>
43acf277afSSimon Glass #include <dm/device-internal.h>
4407b2b78cSSimon Glass #include <dm/lists.h>
45affae2bfSwdenk
46735dd97bSGrant Likely #include <part.h>
47affae2bfSwdenk #include <usb.h>
48affae2bfSwdenk
4980885a9dSwdenk #undef BBB_COMDAT_TRACE
5080885a9dSwdenk #undef BBB_XPORT_TRACE
51affae2bfSwdenk
52affae2bfSwdenk #include <scsi.h>
53affae2bfSwdenk /* direction table -- this indicates the direction of the data
54affae2bfSwdenk * transfer for each command code -- a 1 indicates input
55affae2bfSwdenk */
562ff12285SMike Frysinger static const unsigned char us_direction[256/8] = {
57affae2bfSwdenk 0x28, 0x81, 0x14, 0x14, 0x20, 0x01, 0x90, 0x77,
58affae2bfSwdenk 0x0C, 0x20, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00,
59affae2bfSwdenk 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01,
60affae2bfSwdenk 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
61affae2bfSwdenk };
62affae2bfSwdenk #define US_DIRECTION(x) ((us_direction[x>>3] >> (x & 7)) & 1)
63affae2bfSwdenk
64b9560ad6SSimon Glass static struct scsi_cmd usb_ccb __aligned(ARCH_DMA_MINALIGN);
65a0cb3fc3SMichael Trimarchi static __u32 CBWTag;
66149dded2Swdenk
67a0cb3fc3SMichael Trimarchi static int usb_max_devs; /* number of highest available usb device */
68affae2bfSwdenk
69*1af9bfd3SSven Schwermer #if !CONFIG_IS_ENABLED(BLK)
704101f687SSimon Glass static struct blk_desc usb_dev_desc[USB_MAX_STOR_DEV];
7107b2b78cSSimon Glass #endif
72affae2bfSwdenk
73affae2bfSwdenk struct us_data;
74b9560ad6SSimon Glass typedef int (*trans_cmnd)(struct scsi_cmd *cb, struct us_data *data);
75a0cb3fc3SMichael Trimarchi typedef int (*trans_reset)(struct us_data *data);
76affae2bfSwdenk
77affae2bfSwdenk struct us_data {
78affae2bfSwdenk struct usb_device *pusb_dev; /* this usb_device */
79a0cb3fc3SMichael Trimarchi
80affae2bfSwdenk unsigned int flags; /* from filter initially */
813e8581bbSBenoît Thébaudeau # define USB_READY (1 << 0)
82affae2bfSwdenk unsigned char ifnum; /* interface number */
83affae2bfSwdenk unsigned char ep_in; /* in endpoint */
84affae2bfSwdenk unsigned char ep_out; /* out ....... */
85affae2bfSwdenk unsigned char ep_int; /* interrupt . */
86affae2bfSwdenk unsigned char subclass; /* as in overview */
87affae2bfSwdenk unsigned char protocol; /* .............. */
88affae2bfSwdenk unsigned char attention_done; /* force attn on first cmd */
89affae2bfSwdenk unsigned short ip_data; /* interrupt data */
90affae2bfSwdenk int action; /* what to do */
91affae2bfSwdenk int ip_wanted; /* needed */
92affae2bfSwdenk int *irq_handle; /* for USB int requests */
93affae2bfSwdenk unsigned int irqpipe; /* pipe for release_irq */
94affae2bfSwdenk unsigned char irqmaxp; /* max packed for irq Pipe */
95affae2bfSwdenk unsigned char irqinterval; /* Intervall for IRQ Pipe */
96b9560ad6SSimon Glass struct scsi_cmd *srb; /* current srb */
97affae2bfSwdenk trans_reset transport_reset; /* reset routine */
98affae2bfSwdenk trans_cmnd transport; /* transport routine */
996158d0b4SBin Meng unsigned short max_xfer_blk; /* maximum transfer blocks */
100affae2bfSwdenk };
101affae2bfSwdenk
102*1af9bfd3SSven Schwermer #if !CONFIG_IS_ENABLED(BLK)
103affae2bfSwdenk static struct us_data usb_stor[USB_MAX_STOR_DEV];
10407b2b78cSSimon Glass #endif
105affae2bfSwdenk
106affae2bfSwdenk #define USB_STOR_TRANSPORT_GOOD 0
107affae2bfSwdenk #define USB_STOR_TRANSPORT_FAILED -1
108affae2bfSwdenk #define USB_STOR_TRANSPORT_ERROR -2
109affae2bfSwdenk
110a0cb3fc3SMichael Trimarchi int usb_stor_get_info(struct usb_device *dev, struct us_data *us,
1114101f687SSimon Glass struct blk_desc *dev_desc);
112a0cb3fc3SMichael Trimarchi int usb_storage_probe(struct usb_device *dev, unsigned int ifnum,
113a0cb3fc3SMichael Trimarchi struct us_data *ss);
114*1af9bfd3SSven Schwermer #if CONFIG_IS_ENABLED(BLK)
11507b2b78cSSimon Glass static unsigned long usb_stor_read(struct udevice *dev, lbaint_t blknr,
11607b2b78cSSimon Glass lbaint_t blkcnt, void *buffer);
11707b2b78cSSimon Glass static unsigned long usb_stor_write(struct udevice *dev, lbaint_t blknr,
11807b2b78cSSimon Glass lbaint_t blkcnt, const void *buffer);
11907b2b78cSSimon Glass #else
1204101f687SSimon Glass static unsigned long usb_stor_read(struct blk_desc *block_dev, lbaint_t blknr,
121e81e79edSGabe Black lbaint_t blkcnt, void *buffer);
1224101f687SSimon Glass static unsigned long usb_stor_write(struct blk_desc *block_dev, lbaint_t blknr,
123e81e79edSGabe Black lbaint_t blkcnt, const void *buffer);
12407b2b78cSSimon Glass #endif
125affae2bfSwdenk void uhci_show_temp_int_td(void);
126affae2bfSwdenk
usb_show_progress(void)127199adb60SKim Phillips static void usb_show_progress(void)
128affae2bfSwdenk {
129226fa9bbSWolfgang Denk debug(".");
130affae2bfSwdenk }
131affae2bfSwdenk
132a0cb3fc3SMichael Trimarchi /*******************************************************************************
1339c998aa8SWolfgang Denk * show info on storage devices; 'usb start/init' must be invoked earlier
1349c998aa8SWolfgang Denk * as we only retrieve structures populated during devices initialization
1359c998aa8SWolfgang Denk */
usb_stor_info(void)136f6b44e0eSAras Vaichas int usb_stor_info(void)
1379c998aa8SWolfgang Denk {
1389807c3b7SSimon Glass int count = 0;
139*1af9bfd3SSven Schwermer #if CONFIG_IS_ENABLED(BLK)
14007b2b78cSSimon Glass struct udevice *dev;
14107b2b78cSSimon Glass
14207b2b78cSSimon Glass for (blk_first_device(IF_TYPE_USB, &dev);
14307b2b78cSSimon Glass dev;
14407b2b78cSSimon Glass blk_next_device(&dev)) {
14507b2b78cSSimon Glass struct blk_desc *desc = dev_get_uclass_platdata(dev);
14607b2b78cSSimon Glass
14707b2b78cSSimon Glass printf(" Device %d: ", desc->devnum);
14807b2b78cSSimon Glass dev_print(desc);
14907b2b78cSSimon Glass count++;
15007b2b78cSSimon Glass }
15107b2b78cSSimon Glass #else
1529c998aa8SWolfgang Denk int i;
1539c998aa8SWolfgang Denk
154f6b44e0eSAras Vaichas if (usb_max_devs > 0) {
1559c998aa8SWolfgang Denk for (i = 0; i < usb_max_devs; i++) {
1569c998aa8SWolfgang Denk printf(" Device %d: ", i);
1579c998aa8SWolfgang Denk dev_print(&usb_dev_desc[i]);
158b9e749e9SMarkus Klotzbuecher }
159f6b44e0eSAras Vaichas return 0;
1609c998aa8SWolfgang Denk }
16107b2b78cSSimon Glass #endif
1629807c3b7SSimon Glass if (!count) {
1639c998aa8SWolfgang Denk printf("No storage devices, perhaps not 'usb start'ed..?\n");
164f6b44e0eSAras Vaichas return 1;
165f6b44e0eSAras Vaichas }
1669c998aa8SWolfgang Denk
167b94fc851SSimon Glass return 0;
1689807c3b7SSimon Glass }
1699807c3b7SSimon Glass
usb_get_max_lun(struct us_data * us)17099e9ed1fSLudovic Courtès static unsigned int usb_get_max_lun(struct us_data *us)
17199e9ed1fSLudovic Courtès {
17299e9ed1fSLudovic Courtès int len;
173f5766139SPuneet Saxena ALLOC_CACHE_ALIGN_BUFFER(unsigned char, result, 1);
17499e9ed1fSLudovic Courtès len = usb_control_msg(us->pusb_dev,
17599e9ed1fSLudovic Courtès usb_rcvctrlpipe(us->pusb_dev, 0),
17699e9ed1fSLudovic Courtès US_BBB_GET_MAX_LUN,
17799e9ed1fSLudovic Courtès USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
17899e9ed1fSLudovic Courtès 0, us->ifnum,
179f5766139SPuneet Saxena result, sizeof(char),
18099e9ed1fSLudovic Courtès USB_CNTL_TIMEOUT * 5);
181ceb4972aSVivek Gautam debug("Get Max LUN -> len = %i, result = %i\n", len, (int) *result);
182f5766139SPuneet Saxena return (len > 0) ? *result : 0;
18399e9ed1fSLudovic Courtès }
18499e9ed1fSLudovic Courtès
usb_stor_probe_device(struct usb_device * udev)1859807c3b7SSimon Glass static int usb_stor_probe_device(struct usb_device *udev)
186affae2bfSwdenk {
1879807c3b7SSimon Glass int lun, max_lun;
18807b2b78cSSimon Glass
189*1af9bfd3SSven Schwermer #if CONFIG_IS_ENABLED(BLK)
19007b2b78cSSimon Glass struct us_data *data;
19107b2b78cSSimon Glass int ret;
19207b2b78cSSimon Glass #else
1939807c3b7SSimon Glass int start;
1949807c3b7SSimon Glass
1959807c3b7SSimon Glass if (udev == NULL)
19691557579SSimon Glass return -ENOENT; /* no more devices available */
19707b2b78cSSimon Glass #endif
198a0cb3fc3SMichael Trimarchi
19907b2b78cSSimon Glass debug("\n\nProbing for storage\n");
200*1af9bfd3SSven Schwermer #if CONFIG_IS_ENABLED(BLK)
20107b2b78cSSimon Glass /*
20207b2b78cSSimon Glass * We store the us_data in the mass storage device's platdata. It
20307b2b78cSSimon Glass * is shared by all LUNs (block devices) attached to this mass storage
20407b2b78cSSimon Glass * device.
20507b2b78cSSimon Glass */
20607b2b78cSSimon Glass data = dev_get_platdata(udev->dev);
20707b2b78cSSimon Glass if (!usb_storage_probe(udev, 0, data))
20807b2b78cSSimon Glass return 0;
20907b2b78cSSimon Glass max_lun = usb_get_max_lun(data);
21007b2b78cSSimon Glass for (lun = 0; lun <= max_lun; lun++) {
21107b2b78cSSimon Glass struct blk_desc *blkdev;
21207b2b78cSSimon Glass struct udevice *dev;
2139107c973SSimon Glass char str[10];
21407b2b78cSSimon Glass
2159107c973SSimon Glass snprintf(str, sizeof(str), "lun%d", lun);
2169107c973SSimon Glass ret = blk_create_devicef(udev->dev, "usb_storage_blk", str,
2179107c973SSimon Glass IF_TYPE_USB, usb_max_devs, 512, 0,
2189107c973SSimon Glass &dev);
21907b2b78cSSimon Glass if (ret) {
22007b2b78cSSimon Glass debug("Cannot bind driver\n");
22107b2b78cSSimon Glass return ret;
22207b2b78cSSimon Glass }
22307b2b78cSSimon Glass
22407b2b78cSSimon Glass blkdev = dev_get_uclass_platdata(dev);
22507b2b78cSSimon Glass blkdev->target = 0xff;
22607b2b78cSSimon Glass blkdev->lun = lun;
22707b2b78cSSimon Glass
22807b2b78cSSimon Glass ret = usb_stor_get_info(udev, data, blkdev);
229d0851c89SBin Meng if (ret == 1) {
23007b2b78cSSimon Glass usb_max_devs++;
23107b2b78cSSimon Glass debug("%s: Found device %p\n", __func__, udev);
23207b2b78cSSimon Glass } else {
23307b2b78cSSimon Glass debug("usb_stor_get_info: Invalid device\n");
23407b2b78cSSimon Glass ret = device_unbind(dev);
23507b2b78cSSimon Glass if (ret)
23607b2b78cSSimon Glass return ret;
23707b2b78cSSimon Glass }
23807b2b78cSSimon Glass }
23907b2b78cSSimon Glass #else
240c89e79d4SSimon Glass /* We don't have space to even probe if we hit the maximum */
241c89e79d4SSimon Glass if (usb_max_devs == USB_MAX_STOR_DEV) {
242c89e79d4SSimon Glass printf("max USB Storage Device reached: %d stopping\n",
243c89e79d4SSimon Glass usb_max_devs);
244c89e79d4SSimon Glass return -ENOSPC;
245c89e79d4SSimon Glass }
246c89e79d4SSimon Glass
2479807c3b7SSimon Glass if (!usb_storage_probe(udev, 0, &usb_stor[usb_max_devs]))
2489807c3b7SSimon Glass return 0;
2499807c3b7SSimon Glass
2509807c3b7SSimon Glass /*
2519807c3b7SSimon Glass * OK, it's a storage device. Iterate over its LUNs and populate
2529807c3b7SSimon Glass * usb_dev_desc'
2537fc2c1eaSSimon Glass */
2549807c3b7SSimon Glass start = usb_max_devs;
25599e9ed1fSLudovic Courtès
2567fc2c1eaSSimon Glass max_lun = usb_get_max_lun(&usb_stor[usb_max_devs]);
2579807c3b7SSimon Glass for (lun = 0; lun <= max_lun && usb_max_devs < USB_MAX_STOR_DEV;
2587fc2c1eaSSimon Glass lun++) {
2594101f687SSimon Glass struct blk_desc *blkdev;
26091557579SSimon Glass
26191557579SSimon Glass blkdev = &usb_dev_desc[usb_max_devs];
2624101f687SSimon Glass memset(blkdev, '\0', sizeof(struct blk_desc));
26391557579SSimon Glass blkdev->if_type = IF_TYPE_USB;
264bcce53d0SSimon Glass blkdev->devnum = usb_max_devs;
26591557579SSimon Glass blkdev->part_type = PART_TYPE_UNKNOWN;
26691557579SSimon Glass blkdev->target = 0xff;
26791557579SSimon Glass blkdev->type = DEV_TYPE_UNKNOWN;
26891557579SSimon Glass blkdev->block_read = usb_stor_read;
26991557579SSimon Glass blkdev->block_write = usb_stor_write;
27091557579SSimon Glass blkdev->lun = lun;
2719807c3b7SSimon Glass blkdev->priv = udev;
27291557579SSimon Glass
2739807c3b7SSimon Glass if (usb_stor_get_info(udev, &usb_stor[start],
2749807c3b7SSimon Glass &usb_dev_desc[usb_max_devs]) == 1) {
27507b2b78cSSimon Glass debug("partype: %d\n", blkdev->part_type);
27607b2b78cSSimon Glass part_init(blkdev);
27707b2b78cSSimon Glass debug("partype: %d\n", blkdev->part_type);
2787fc2c1eaSSimon Glass usb_max_devs++;
2799807c3b7SSimon Glass debug("%s: Found device %p\n", __func__, udev);
2807fc2c1eaSSimon Glass }
2817fc2c1eaSSimon Glass }
28207b2b78cSSimon Glass #endif
28391557579SSimon Glass
28491557579SSimon Glass return 0;
28591557579SSimon Glass }
28691557579SSimon Glass
usb_stor_reset(void)28791557579SSimon Glass void usb_stor_reset(void)
28891557579SSimon Glass {
28991557579SSimon Glass usb_max_devs = 0;
29091557579SSimon Glass }
29191557579SSimon Glass
29291557579SSimon Glass /*******************************************************************************
29391557579SSimon Glass * scan the usb and reports device info
29491557579SSimon Glass * to the user if mode = 1
29591557579SSimon Glass * returns current device or -1 if no
29691557579SSimon Glass */
usb_stor_scan(int mode)29791557579SSimon Glass int usb_stor_scan(int mode)
29891557579SSimon Glass {
29991557579SSimon Glass if (mode == 1)
30091557579SSimon Glass printf(" scanning usb for storage devices... ");
30191557579SSimon Glass
302fd09c205SSven Schwermer #if !CONFIG_IS_ENABLED(DM_USB)
303b984700cSMichal Simek unsigned char i;
304b984700cSMichal Simek
30591557579SSimon Glass usb_disable_asynch(1); /* asynch transfer not allowed */
30691557579SSimon Glass
30791557579SSimon Glass usb_stor_reset();
30891557579SSimon Glass for (i = 0; i < USB_MAX_DEVICE; i++) {
30991557579SSimon Glass struct usb_device *dev;
31091557579SSimon Glass
31191557579SSimon Glass dev = usb_get_dev_index(i); /* get device */
31291557579SSimon Glass debug("i=%d\n", i);
31391557579SSimon Glass if (usb_stor_probe_device(dev))
31491557579SSimon Glass break;
315affae2bfSwdenk } /* for */
3169c998aa8SWolfgang Denk
317affae2bfSwdenk usb_disable_asynch(0); /* asynch transfer allowed */
318b984700cSMichal Simek #endif
3199c998aa8SWolfgang Denk printf("%d Storage Device(s) found\n", usb_max_devs);
320affae2bfSwdenk if (usb_max_devs > 0)
321affae2bfSwdenk return 0;
322affae2bfSwdenk return -1;
323affae2bfSwdenk }
324affae2bfSwdenk
usb_stor_irq(struct usb_device * dev)325affae2bfSwdenk static int usb_stor_irq(struct usb_device *dev)
326affae2bfSwdenk {
327affae2bfSwdenk struct us_data *us;
328affae2bfSwdenk us = (struct us_data *)dev->privptr;
329affae2bfSwdenk
330a0cb3fc3SMichael Trimarchi if (us->ip_wanted)
331affae2bfSwdenk us->ip_wanted = 0;
332affae2bfSwdenk return 0;
333affae2bfSwdenk }
334affae2bfSwdenk
335affae2bfSwdenk
336ceb4972aSVivek Gautam #ifdef DEBUG
337affae2bfSwdenk
usb_show_srb(struct scsi_cmd * pccb)338b9560ad6SSimon Glass static void usb_show_srb(struct scsi_cmd *pccb)
339affae2bfSwdenk {
340affae2bfSwdenk int i;
341affae2bfSwdenk printf("SRB: len %d datalen 0x%lX\n ", pccb->cmdlen, pccb->datalen);
342a0cb3fc3SMichael Trimarchi for (i = 0; i < 12; i++)
343affae2bfSwdenk printf("%02X ", pccb->cmd[i]);
344affae2bfSwdenk printf("\n");
345affae2bfSwdenk }
346affae2bfSwdenk
display_int_status(unsigned long tmp)347affae2bfSwdenk static void display_int_status(unsigned long tmp)
348affae2bfSwdenk {
349affae2bfSwdenk printf("Status: %s %s %s %s %s %s %s\n",
350affae2bfSwdenk (tmp & USB_ST_ACTIVE) ? "Active" : "",
351affae2bfSwdenk (tmp & USB_ST_STALLED) ? "Stalled" : "",
352affae2bfSwdenk (tmp & USB_ST_BUF_ERR) ? "Buffer Error" : "",
353affae2bfSwdenk (tmp & USB_ST_BABBLE_DET) ? "Babble Det" : "",
354affae2bfSwdenk (tmp & USB_ST_NAK_REC) ? "NAKed" : "",
355affae2bfSwdenk (tmp & USB_ST_CRC_ERR) ? "CRC Error" : "",
356affae2bfSwdenk (tmp & USB_ST_BIT_ERR) ? "Bitstuff Error" : "");
357affae2bfSwdenk }
358affae2bfSwdenk #endif
359affae2bfSwdenk /***********************************************************************
360affae2bfSwdenk * Data transfer routines
361affae2bfSwdenk ***********************************************************************/
362affae2bfSwdenk
us_one_transfer(struct us_data * us,int pipe,char * buf,int length)363affae2bfSwdenk static int us_one_transfer(struct us_data *us, int pipe, char *buf, int length)
364affae2bfSwdenk {
365affae2bfSwdenk int max_size;
366affae2bfSwdenk int this_xfer;
367affae2bfSwdenk int result;
368affae2bfSwdenk int partial;
369affae2bfSwdenk int maxtry;
370affae2bfSwdenk int stat;
371affae2bfSwdenk
372affae2bfSwdenk /* determine the maximum packet size for these transfers */
373affae2bfSwdenk max_size = usb_maxpacket(us->pusb_dev, pipe) * 16;
374affae2bfSwdenk
375affae2bfSwdenk /* while we have data left to transfer */
376affae2bfSwdenk while (length) {
377affae2bfSwdenk
378affae2bfSwdenk /* calculate how long this will be -- maximum or a remainder */
379affae2bfSwdenk this_xfer = length > max_size ? max_size : length;
380affae2bfSwdenk length -= this_xfer;
381affae2bfSwdenk
382affae2bfSwdenk /* setup the retry counter */
383affae2bfSwdenk maxtry = 10;
384affae2bfSwdenk
385affae2bfSwdenk /* set up the transfer loop */
386affae2bfSwdenk do {
387affae2bfSwdenk /* transfer the data */
38805108132SSimon Glass debug("Bulk xfer 0x%lx(%d) try #%d\n",
38905108132SSimon Glass (ulong)map_to_sysmem(buf), this_xfer,
39005108132SSimon Glass 11 - maxtry);
391affae2bfSwdenk result = usb_bulk_msg(us->pusb_dev, pipe, buf,
392a0cb3fc3SMichael Trimarchi this_xfer, &partial,
393a0cb3fc3SMichael Trimarchi USB_CNTL_TIMEOUT * 5);
394ceb4972aSVivek Gautam debug("bulk_msg returned %d xferred %d/%d\n",
395affae2bfSwdenk result, partial, this_xfer);
396affae2bfSwdenk if (us->pusb_dev->status != 0) {
397a0cb3fc3SMichael Trimarchi /* if we stall, we need to clear it before
398a0cb3fc3SMichael Trimarchi * we go on
399a0cb3fc3SMichael Trimarchi */
400ceb4972aSVivek Gautam #ifdef DEBUG
401affae2bfSwdenk display_int_status(us->pusb_dev->status);
402affae2bfSwdenk #endif
403affae2bfSwdenk if (us->pusb_dev->status & USB_ST_STALLED) {
404ceb4972aSVivek Gautam debug("stalled ->clearing endpoint" \
405ceb4972aSVivek Gautam "halt for pipe 0x%x\n", pipe);
406affae2bfSwdenk stat = us->pusb_dev->status;
407affae2bfSwdenk usb_clear_halt(us->pusb_dev, pipe);
408affae2bfSwdenk us->pusb_dev->status = stat;
409affae2bfSwdenk if (this_xfer == partial) {
410ceb4972aSVivek Gautam debug("bulk transferred" \
411ceb4972aSVivek Gautam "with error %lX," \
412ceb4972aSVivek Gautam " but data ok\n",
413ceb4972aSVivek Gautam us->pusb_dev->status);
414affae2bfSwdenk return 0;
415affae2bfSwdenk }
416affae2bfSwdenk else
417affae2bfSwdenk return result;
418affae2bfSwdenk }
419affae2bfSwdenk if (us->pusb_dev->status & USB_ST_NAK_REC) {
420ceb4972aSVivek Gautam debug("Device NAKed bulk_msg\n");
421affae2bfSwdenk return result;
422affae2bfSwdenk }
423ceb4972aSVivek Gautam debug("bulk transferred with error");
424affae2bfSwdenk if (this_xfer == partial) {
425ceb4972aSVivek Gautam debug(" %ld, but data ok\n",
426a0cb3fc3SMichael Trimarchi us->pusb_dev->status);
427affae2bfSwdenk return 0;
428affae2bfSwdenk }
429affae2bfSwdenk /* if our try counter reaches 0, bail out */
430ceb4972aSVivek Gautam debug(" %ld, data %d\n",
431a0cb3fc3SMichael Trimarchi us->pusb_dev->status, partial);
432affae2bfSwdenk if (!maxtry--)
433affae2bfSwdenk return result;
434affae2bfSwdenk }
435affae2bfSwdenk /* update to show what data was transferred */
436affae2bfSwdenk this_xfer -= partial;
437affae2bfSwdenk buf += partial;
438affae2bfSwdenk /* continue until this transfer is done */
439affae2bfSwdenk } while (this_xfer);
440affae2bfSwdenk }
441affae2bfSwdenk
442affae2bfSwdenk /* if we get here, we're done and successful */
443affae2bfSwdenk return 0;
444affae2bfSwdenk }
445affae2bfSwdenk
usb_stor_BBB_reset(struct us_data * us)446149dded2Swdenk static int usb_stor_BBB_reset(struct us_data *us)
447149dded2Swdenk {
448149dded2Swdenk int result;
449149dded2Swdenk unsigned int pipe;
450149dded2Swdenk
451149dded2Swdenk /*
452149dded2Swdenk * Reset recovery (5.3.4 in Universal Serial Bus Mass Storage Class)
453149dded2Swdenk *
454149dded2Swdenk * For Reset Recovery the host shall issue in the following order:
455149dded2Swdenk * a) a Bulk-Only Mass Storage Reset
456149dded2Swdenk * b) a Clear Feature HALT to the Bulk-In endpoint
457149dded2Swdenk * c) a Clear Feature HALT to the Bulk-Out endpoint
458149dded2Swdenk *
459149dded2Swdenk * This is done in 3 steps.
460149dded2Swdenk *
461149dded2Swdenk * If the reset doesn't succeed, the device should be port reset.
462149dded2Swdenk *
463149dded2Swdenk * This comment stolen from FreeBSD's /sys/dev/usb/umass.c.
464149dded2Swdenk */
465ceb4972aSVivek Gautam debug("BBB_reset\n");
466149dded2Swdenk result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev, 0),
467a0cb3fc3SMichael Trimarchi US_BBB_RESET,
468a0cb3fc3SMichael Trimarchi USB_TYPE_CLASS | USB_RECIP_INTERFACE,
469199adb60SKim Phillips 0, us->ifnum, NULL, 0, USB_CNTL_TIMEOUT * 5);
4709c998aa8SWolfgang Denk
471a0cb3fc3SMichael Trimarchi if ((result < 0) && (us->pusb_dev->status & USB_ST_STALLED)) {
472ceb4972aSVivek Gautam debug("RESET:stall\n");
473149dded2Swdenk return -1;
474149dded2Swdenk }
4759c998aa8SWolfgang Denk
476149dded2Swdenk /* long wait for reset */
4775b84dd67SMike Frysinger mdelay(150);
478ceb4972aSVivek Gautam debug("BBB_reset result %d: status %lX reset\n",
479ceb4972aSVivek Gautam result, us->pusb_dev->status);
480149dded2Swdenk pipe = usb_rcvbulkpipe(us->pusb_dev, us->ep_in);
481149dded2Swdenk result = usb_clear_halt(us->pusb_dev, pipe);
482149dded2Swdenk /* long wait for reset */
4835b84dd67SMike Frysinger mdelay(150);
484ceb4972aSVivek Gautam debug("BBB_reset result %d: status %lX clearing IN endpoint\n",
485a0cb3fc3SMichael Trimarchi result, us->pusb_dev->status);
486149dded2Swdenk /* long wait for reset */
487149dded2Swdenk pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out);
488149dded2Swdenk result = usb_clear_halt(us->pusb_dev, pipe);
4895b84dd67SMike Frysinger mdelay(150);
490ceb4972aSVivek Gautam debug("BBB_reset result %d: status %lX clearing OUT endpoint\n",
491ceb4972aSVivek Gautam result, us->pusb_dev->status);
492ceb4972aSVivek Gautam debug("BBB_reset done\n");
493149dded2Swdenk return 0;
494149dded2Swdenk }
495149dded2Swdenk
496affae2bfSwdenk /* FIXME: this reset function doesn't really reset the port, and it
497affae2bfSwdenk * should. Actually it should probably do what it's doing here, and
498affae2bfSwdenk * reset the port physically
499affae2bfSwdenk */
usb_stor_CB_reset(struct us_data * us)500affae2bfSwdenk static int usb_stor_CB_reset(struct us_data *us)
501affae2bfSwdenk {
502affae2bfSwdenk unsigned char cmd[12];
503affae2bfSwdenk int result;
504affae2bfSwdenk
505ceb4972aSVivek Gautam debug("CB_reset\n");
506a0cb3fc3SMichael Trimarchi memset(cmd, 0xff, sizeof(cmd));
507affae2bfSwdenk cmd[0] = SCSI_SEND_DIAG;
508affae2bfSwdenk cmd[1] = 4;
509affae2bfSwdenk result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev, 0),
510a0cb3fc3SMichael Trimarchi US_CBI_ADSC,
511a0cb3fc3SMichael Trimarchi USB_TYPE_CLASS | USB_RECIP_INTERFACE,
512a0cb3fc3SMichael Trimarchi 0, us->ifnum, cmd, sizeof(cmd),
513a0cb3fc3SMichael Trimarchi USB_CNTL_TIMEOUT * 5);
514affae2bfSwdenk
515affae2bfSwdenk /* long wait for reset */
5165b84dd67SMike Frysinger mdelay(1500);
517ceb4972aSVivek Gautam debug("CB_reset result %d: status %lX clearing endpoint halt\n",
518ceb4972aSVivek Gautam result, us->pusb_dev->status);
519affae2bfSwdenk usb_clear_halt(us->pusb_dev, usb_rcvbulkpipe(us->pusb_dev, us->ep_in));
520affae2bfSwdenk usb_clear_halt(us->pusb_dev, usb_rcvbulkpipe(us->pusb_dev, us->ep_out));
521affae2bfSwdenk
522ceb4972aSVivek Gautam debug("CB_reset done\n");
523affae2bfSwdenk return 0;
524affae2bfSwdenk }
525affae2bfSwdenk
526149dded2Swdenk /*
527149dded2Swdenk * Set up the command for a BBB device. Note that the actual SCSI
528149dded2Swdenk * command is copied into cbw.CBWCDB.
529149dded2Swdenk */
usb_stor_BBB_comdat(struct scsi_cmd * srb,struct us_data * us)530b9560ad6SSimon Glass static int usb_stor_BBB_comdat(struct scsi_cmd *srb, struct us_data *us)
531149dded2Swdenk {
532149dded2Swdenk int result;
533149dded2Swdenk int actlen;
534149dded2Swdenk int dir_in;
535149dded2Swdenk unsigned int pipe;
5362e17c87eSSimon Glass ALLOC_CACHE_ALIGN_BUFFER(struct umass_bbb_cbw, cbw, 1);
537149dded2Swdenk
538149dded2Swdenk dir_in = US_DIRECTION(srb->cmd[0]);
539149dded2Swdenk
540149dded2Swdenk #ifdef BBB_COMDAT_TRACE
541605bd75aSVivek Gautam printf("dir %d lun %d cmdlen %d cmd %p datalen %lu pdata %p\n",
542a0cb3fc3SMichael Trimarchi dir_in, srb->lun, srb->cmdlen, srb->cmd, srb->datalen,
543a0cb3fc3SMichael Trimarchi srb->pdata);
544149dded2Swdenk if (srb->cmdlen) {
545149dded2Swdenk for (result = 0; result < srb->cmdlen; result++)
546149dded2Swdenk printf("cmd[%d] %#x ", result, srb->cmd[result]);
547149dded2Swdenk printf("\n");
548149dded2Swdenk }
549149dded2Swdenk #endif
550149dded2Swdenk /* sanity checks */
551149dded2Swdenk if (!(srb->cmdlen <= CBWCDBLENGTH)) {
552ceb4972aSVivek Gautam debug("usb_stor_BBB_comdat:cmdlen too large\n");
553149dded2Swdenk return -1;
554149dded2Swdenk }
555149dded2Swdenk
556149dded2Swdenk /* always OUT to the ep */
557149dded2Swdenk pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out);
558149dded2Swdenk
559f5766139SPuneet Saxena cbw->dCBWSignature = cpu_to_le32(CBWSIGNATURE);
560f5766139SPuneet Saxena cbw->dCBWTag = cpu_to_le32(CBWTag++);
561f5766139SPuneet Saxena cbw->dCBWDataTransferLength = cpu_to_le32(srb->datalen);
562f5766139SPuneet Saxena cbw->bCBWFlags = (dir_in ? CBWFLAGS_IN : CBWFLAGS_OUT);
563f5766139SPuneet Saxena cbw->bCBWLUN = srb->lun;
564f5766139SPuneet Saxena cbw->bCDBLength = srb->cmdlen;
565149dded2Swdenk /* copy the command data into the CBW command data buffer */
566149dded2Swdenk /* DST SRC LEN!!! */
567f6570871SSergey Temerkhanov
568f5766139SPuneet Saxena memcpy(cbw->CBWCDB, srb->cmd, srb->cmdlen);
569f5766139SPuneet Saxena result = usb_bulk_msg(us->pusb_dev, pipe, cbw, UMASS_BBB_CBW_SIZE,
570a0cb3fc3SMichael Trimarchi &actlen, USB_CNTL_TIMEOUT * 5);
571149dded2Swdenk if (result < 0)
572ceb4972aSVivek Gautam debug("usb_stor_BBB_comdat:usb_bulk_msg error\n");
573149dded2Swdenk return result;
574149dded2Swdenk }
575149dded2Swdenk
576affae2bfSwdenk /* FIXME: we also need a CBI_command which sets up the completion
577affae2bfSwdenk * interrupt, and waits for it
578affae2bfSwdenk */
usb_stor_CB_comdat(struct scsi_cmd * srb,struct us_data * us)579b9560ad6SSimon Glass static int usb_stor_CB_comdat(struct scsi_cmd *srb, struct us_data *us)
580affae2bfSwdenk {
58177ddac94SWolfgang Denk int result = 0;
582affae2bfSwdenk int dir_in, retry;
583affae2bfSwdenk unsigned int pipe;
584affae2bfSwdenk unsigned long status;
585affae2bfSwdenk
586affae2bfSwdenk retry = 5;
587affae2bfSwdenk dir_in = US_DIRECTION(srb->cmd[0]);
588affae2bfSwdenk
589affae2bfSwdenk if (dir_in)
590affae2bfSwdenk pipe = usb_rcvbulkpipe(us->pusb_dev, us->ep_in);
591affae2bfSwdenk else
592affae2bfSwdenk pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out);
593a0cb3fc3SMichael Trimarchi
594affae2bfSwdenk while (retry--) {
595ceb4972aSVivek Gautam debug("CBI gets a command: Try %d\n", 5 - retry);
596ceb4972aSVivek Gautam #ifdef DEBUG
597affae2bfSwdenk usb_show_srb(srb);
598affae2bfSwdenk #endif
599affae2bfSwdenk /* let's send the command via the control pipe */
600a0cb3fc3SMichael Trimarchi result = usb_control_msg(us->pusb_dev,
601a0cb3fc3SMichael Trimarchi usb_sndctrlpipe(us->pusb_dev , 0),
602a0cb3fc3SMichael Trimarchi US_CBI_ADSC,
603a0cb3fc3SMichael Trimarchi USB_TYPE_CLASS | USB_RECIP_INTERFACE,
604affae2bfSwdenk 0, us->ifnum,
605a0cb3fc3SMichael Trimarchi srb->cmd, srb->cmdlen,
606a0cb3fc3SMichael Trimarchi USB_CNTL_TIMEOUT * 5);
607ceb4972aSVivek Gautam debug("CB_transport: control msg returned %d, status %lX\n",
608ceb4972aSVivek Gautam result, us->pusb_dev->status);
609affae2bfSwdenk /* check the return code for the command */
610affae2bfSwdenk if (result < 0) {
611affae2bfSwdenk if (us->pusb_dev->status & USB_ST_STALLED) {
612affae2bfSwdenk status = us->pusb_dev->status;
613ceb4972aSVivek Gautam debug(" stall during command found," \
614a0cb3fc3SMichael Trimarchi " clear pipe\n");
615a0cb3fc3SMichael Trimarchi usb_clear_halt(us->pusb_dev,
616a0cb3fc3SMichael Trimarchi usb_sndctrlpipe(us->pusb_dev, 0));
617affae2bfSwdenk us->pusb_dev->status = status;
618affae2bfSwdenk }
619ceb4972aSVivek Gautam debug(" error during command %02X" \
6204b210e8bSMarek Vasut " Stat = %lX\n", srb->cmd[0],
621a0cb3fc3SMichael Trimarchi us->pusb_dev->status);
622affae2bfSwdenk return result;
623affae2bfSwdenk }
624affae2bfSwdenk /* transfer the data payload for this command, if one exists*/
625affae2bfSwdenk
626ceb4972aSVivek Gautam debug("CB_transport: control msg returned %d," \
627a0cb3fc3SMichael Trimarchi " direction is %s to go 0x%lx\n", result,
628a0cb3fc3SMichael Trimarchi dir_in ? "IN" : "OUT", srb->datalen);
629affae2bfSwdenk if (srb->datalen) {
630a0cb3fc3SMichael Trimarchi result = us_one_transfer(us, pipe, (char *)srb->pdata,
631a0cb3fc3SMichael Trimarchi srb->datalen);
632ceb4972aSVivek Gautam debug("CBI attempted to transfer data," \
633a0cb3fc3SMichael Trimarchi " result is %d status %lX, len %d\n",
634a0cb3fc3SMichael Trimarchi result, us->pusb_dev->status,
635a0cb3fc3SMichael Trimarchi us->pusb_dev->act_len);
636affae2bfSwdenk if (!(us->pusb_dev->status & USB_ST_NAK_REC))
637affae2bfSwdenk break;
638affae2bfSwdenk } /* if (srb->datalen) */
639affae2bfSwdenk else
640affae2bfSwdenk break;
641affae2bfSwdenk }
642affae2bfSwdenk /* return result */
643affae2bfSwdenk
644affae2bfSwdenk return result;
645affae2bfSwdenk }
646affae2bfSwdenk
647affae2bfSwdenk
usb_stor_CBI_get_status(struct scsi_cmd * srb,struct us_data * us)648b9560ad6SSimon Glass static int usb_stor_CBI_get_status(struct scsi_cmd *srb, struct us_data *us)
649affae2bfSwdenk {
650affae2bfSwdenk int timeout;
651affae2bfSwdenk
652affae2bfSwdenk us->ip_wanted = 1;
653affae2bfSwdenk submit_int_msg(us->pusb_dev, us->irqpipe,
654affae2bfSwdenk (void *) &us->ip_data, us->irqmaxp, us->irqinterval);
655affae2bfSwdenk timeout = 1000;
656affae2bfSwdenk while (timeout--) {
657f6570871SSergey Temerkhanov if (us->ip_wanted == 0)
658affae2bfSwdenk break;
6595b84dd67SMike Frysinger mdelay(10);
660affae2bfSwdenk }
661affae2bfSwdenk if (us->ip_wanted) {
662affae2bfSwdenk printf(" Did not get interrupt on CBI\n");
663affae2bfSwdenk us->ip_wanted = 0;
664affae2bfSwdenk return USB_STOR_TRANSPORT_ERROR;
665affae2bfSwdenk }
666a6f70a3dSVagrant Cascadian debug("Got interrupt data 0x%x, transferred %d status 0x%lX\n",
66780885a9dSwdenk us->ip_data, us->pusb_dev->irq_act_len,
66880885a9dSwdenk us->pusb_dev->irq_status);
669affae2bfSwdenk /* UFI gives us ASC and ASCQ, like a request sense */
670affae2bfSwdenk if (us->subclass == US_SC_UFI) {
671affae2bfSwdenk if (srb->cmd[0] == SCSI_REQ_SENSE ||
672affae2bfSwdenk srb->cmd[0] == SCSI_INQUIRY)
673affae2bfSwdenk return USB_STOR_TRANSPORT_GOOD; /* Good */
67480885a9dSwdenk else if (us->ip_data)
675affae2bfSwdenk return USB_STOR_TRANSPORT_FAILED;
676affae2bfSwdenk else
677affae2bfSwdenk return USB_STOR_TRANSPORT_GOOD;
678affae2bfSwdenk }
679affae2bfSwdenk /* otherwise, we interpret the data normally */
680affae2bfSwdenk switch (us->ip_data) {
681affae2bfSwdenk case 0x0001:
682affae2bfSwdenk return USB_STOR_TRANSPORT_GOOD;
683affae2bfSwdenk case 0x0002:
684affae2bfSwdenk return USB_STOR_TRANSPORT_FAILED;
685affae2bfSwdenk default:
686affae2bfSwdenk return USB_STOR_TRANSPORT_ERROR;
687affae2bfSwdenk } /* switch */
688affae2bfSwdenk return USB_STOR_TRANSPORT_ERROR;
689affae2bfSwdenk }
690affae2bfSwdenk
691affae2bfSwdenk #define USB_TRANSPORT_UNKNOWN_RETRY 5
692affae2bfSwdenk #define USB_TRANSPORT_NOT_READY_RETRY 10
693affae2bfSwdenk
694149dded2Swdenk /* clear a stall on an endpoint - special for BBB devices */
usb_stor_BBB_clear_endpt_stall(struct us_data * us,__u8 endpt)695199adb60SKim Phillips static int usb_stor_BBB_clear_endpt_stall(struct us_data *us, __u8 endpt)
696149dded2Swdenk {
697149dded2Swdenk /* ENDPOINT_HALT = 0, so set value to 0 */
6988319aeb1SMasahiro Yamada return usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev, 0),
6998319aeb1SMasahiro Yamada USB_REQ_CLEAR_FEATURE, USB_RECIP_ENDPOINT, 0,
7008319aeb1SMasahiro Yamada endpt, NULL, 0, USB_CNTL_TIMEOUT * 5);
701149dded2Swdenk }
702149dded2Swdenk
usb_stor_BBB_transport(struct scsi_cmd * srb,struct us_data * us)703b9560ad6SSimon Glass static int usb_stor_BBB_transport(struct scsi_cmd *srb, struct us_data *us)
704149dded2Swdenk {
705149dded2Swdenk int result, retry;
706149dded2Swdenk int dir_in;
707149dded2Swdenk int actlen, data_actlen;
708149dded2Swdenk unsigned int pipe, pipein, pipeout;
7092e17c87eSSimon Glass ALLOC_CACHE_ALIGN_BUFFER(struct umass_bbb_csw, csw, 1);
710149dded2Swdenk #ifdef BBB_XPORT_TRACE
711149dded2Swdenk unsigned char *ptr;
712149dded2Swdenk int index;
713149dded2Swdenk #endif
714149dded2Swdenk
715149dded2Swdenk dir_in = US_DIRECTION(srb->cmd[0]);
716149dded2Swdenk
717149dded2Swdenk /* COMMAND phase */
718ceb4972aSVivek Gautam debug("COMMAND phase\n");
719149dded2Swdenk result = usb_stor_BBB_comdat(srb, us);
720149dded2Swdenk if (result < 0) {
721ceb4972aSVivek Gautam debug("failed to send CBW status %ld\n",
722149dded2Swdenk us->pusb_dev->status);
723149dded2Swdenk usb_stor_BBB_reset(us);
724149dded2Swdenk return USB_STOR_TRANSPORT_FAILED;
725149dded2Swdenk }
7263e8581bbSBenoît Thébaudeau if (!(us->flags & USB_READY))
7275b84dd67SMike Frysinger mdelay(5);
728149dded2Swdenk pipein = usb_rcvbulkpipe(us->pusb_dev, us->ep_in);
729149dded2Swdenk pipeout = usb_sndbulkpipe(us->pusb_dev, us->ep_out);
730149dded2Swdenk /* DATA phase + error handling */
731149dded2Swdenk data_actlen = 0;
732149dded2Swdenk /* no data, go immediately to the STATUS phase */
733149dded2Swdenk if (srb->datalen == 0)
734149dded2Swdenk goto st;
735ceb4972aSVivek Gautam debug("DATA phase\n");
736149dded2Swdenk if (dir_in)
737149dded2Swdenk pipe = pipein;
738149dded2Swdenk else
739149dded2Swdenk pipe = pipeout;
740f6570871SSergey Temerkhanov
741a0cb3fc3SMichael Trimarchi result = usb_bulk_msg(us->pusb_dev, pipe, srb->pdata, srb->datalen,
742a0cb3fc3SMichael Trimarchi &data_actlen, USB_CNTL_TIMEOUT * 5);
743149dded2Swdenk /* special handling of STALL in DATA phase */
744149dded2Swdenk if ((result < 0) && (us->pusb_dev->status & USB_ST_STALLED)) {
745ceb4972aSVivek Gautam debug("DATA:stall\n");
746149dded2Swdenk /* clear the STALL on the endpoint */
747a0cb3fc3SMichael Trimarchi result = usb_stor_BBB_clear_endpt_stall(us,
748a0cb3fc3SMichael Trimarchi dir_in ? us->ep_in : us->ep_out);
749149dded2Swdenk if (result >= 0)
750149dded2Swdenk /* continue on to STATUS phase */
751149dded2Swdenk goto st;
752149dded2Swdenk }
753149dded2Swdenk if (result < 0) {
754ceb4972aSVivek Gautam debug("usb_bulk_msg error status %ld\n",
755149dded2Swdenk us->pusb_dev->status);
756149dded2Swdenk usb_stor_BBB_reset(us);
757149dded2Swdenk return USB_STOR_TRANSPORT_FAILED;
758149dded2Swdenk }
759149dded2Swdenk #ifdef BBB_XPORT_TRACE
760149dded2Swdenk for (index = 0; index < data_actlen; index++)
761149dded2Swdenk printf("pdata[%d] %#x ", index, srb->pdata[index]);
762149dded2Swdenk printf("\n");
763149dded2Swdenk #endif
764149dded2Swdenk /* STATUS phase + error handling */
765149dded2Swdenk st:
766149dded2Swdenk retry = 0;
767149dded2Swdenk again:
768ceb4972aSVivek Gautam debug("STATUS phase\n");
769f5766139SPuneet Saxena result = usb_bulk_msg(us->pusb_dev, pipein, csw, UMASS_BBB_CSW_SIZE,
7709c998aa8SWolfgang Denk &actlen, USB_CNTL_TIMEOUT*5);
7719c998aa8SWolfgang Denk
772149dded2Swdenk /* special handling of STALL in STATUS phase */
773a0cb3fc3SMichael Trimarchi if ((result < 0) && (retry < 1) &&
774a0cb3fc3SMichael Trimarchi (us->pusb_dev->status & USB_ST_STALLED)) {
775ceb4972aSVivek Gautam debug("STATUS:stall\n");
776149dded2Swdenk /* clear the STALL on the endpoint */
777149dded2Swdenk result = usb_stor_BBB_clear_endpt_stall(us, us->ep_in);
778149dded2Swdenk if (result >= 0 && (retry++ < 1))
779149dded2Swdenk /* do a retry */
780149dded2Swdenk goto again;
781149dded2Swdenk }
782149dded2Swdenk if (result < 0) {
783ceb4972aSVivek Gautam debug("usb_bulk_msg error status %ld\n",
784149dded2Swdenk us->pusb_dev->status);
785149dded2Swdenk usb_stor_BBB_reset(us);
786149dded2Swdenk return USB_STOR_TRANSPORT_FAILED;
787149dded2Swdenk }
788149dded2Swdenk #ifdef BBB_XPORT_TRACE
789f5766139SPuneet Saxena ptr = (unsigned char *)csw;
790149dded2Swdenk for (index = 0; index < UMASS_BBB_CSW_SIZE; index++)
791149dded2Swdenk printf("ptr[%d] %#x ", index, ptr[index]);
792149dded2Swdenk printf("\n");
793149dded2Swdenk #endif
794149dded2Swdenk /* misuse pipe to get the residue */
795f5766139SPuneet Saxena pipe = le32_to_cpu(csw->dCSWDataResidue);
796149dded2Swdenk if (pipe == 0 && srb->datalen != 0 && srb->datalen - data_actlen != 0)
797149dded2Swdenk pipe = srb->datalen - data_actlen;
798f5766139SPuneet Saxena if (CSWSIGNATURE != le32_to_cpu(csw->dCSWSignature)) {
799ceb4972aSVivek Gautam debug("!CSWSIGNATURE\n");
800149dded2Swdenk usb_stor_BBB_reset(us);
801149dded2Swdenk return USB_STOR_TRANSPORT_FAILED;
802f5766139SPuneet Saxena } else if ((CBWTag - 1) != le32_to_cpu(csw->dCSWTag)) {
803ceb4972aSVivek Gautam debug("!Tag\n");
804149dded2Swdenk usb_stor_BBB_reset(us);
805149dded2Swdenk return USB_STOR_TRANSPORT_FAILED;
806f5766139SPuneet Saxena } else if (csw->bCSWStatus > CSWSTATUS_PHASE) {
807ceb4972aSVivek Gautam debug(">PHASE\n");
808149dded2Swdenk usb_stor_BBB_reset(us);
809149dded2Swdenk return USB_STOR_TRANSPORT_FAILED;
810f5766139SPuneet Saxena } else if (csw->bCSWStatus == CSWSTATUS_PHASE) {
811ceb4972aSVivek Gautam debug("=PHASE\n");
812149dded2Swdenk usb_stor_BBB_reset(us);
813149dded2Swdenk return USB_STOR_TRANSPORT_FAILED;
814149dded2Swdenk } else if (data_actlen > srb->datalen) {
815ceb4972aSVivek Gautam debug("transferred %dB instead of %ldB\n",
816149dded2Swdenk data_actlen, srb->datalen);
817149dded2Swdenk return USB_STOR_TRANSPORT_FAILED;
818f5766139SPuneet Saxena } else if (csw->bCSWStatus == CSWSTATUS_FAILED) {
819ceb4972aSVivek Gautam debug("FAILED\n");
820149dded2Swdenk return USB_STOR_TRANSPORT_FAILED;
821149dded2Swdenk }
822149dded2Swdenk
823149dded2Swdenk return result;
824149dded2Swdenk }
825149dded2Swdenk
usb_stor_CB_transport(struct scsi_cmd * srb,struct us_data * us)826b9560ad6SSimon Glass static int usb_stor_CB_transport(struct scsi_cmd *srb, struct us_data *us)
827affae2bfSwdenk {
828affae2bfSwdenk int result, status;
829b9560ad6SSimon Glass struct scsi_cmd *psrb;
830b9560ad6SSimon Glass struct scsi_cmd reqsrb;
831affae2bfSwdenk int retry, notready;
832affae2bfSwdenk
833affae2bfSwdenk psrb = &reqsrb;
834affae2bfSwdenk status = USB_STOR_TRANSPORT_GOOD;
835affae2bfSwdenk retry = 0;
836affae2bfSwdenk notready = 0;
837affae2bfSwdenk /* issue the command */
838affae2bfSwdenk do_retry:
839affae2bfSwdenk result = usb_stor_CB_comdat(srb, us);
840ceb4972aSVivek Gautam debug("command / Data returned %d, status %lX\n",
841a0cb3fc3SMichael Trimarchi result, us->pusb_dev->status);
842affae2bfSwdenk /* if this is an CBI Protocol, get IRQ */
843affae2bfSwdenk if (us->protocol == US_PR_CBI) {
844affae2bfSwdenk status = usb_stor_CBI_get_status(srb, us);
845affae2bfSwdenk /* if the status is error, report it */
846affae2bfSwdenk if (status == USB_STOR_TRANSPORT_ERROR) {
847ceb4972aSVivek Gautam debug(" USB CBI Command Error\n");
848affae2bfSwdenk return status;
849affae2bfSwdenk }
850affae2bfSwdenk srb->sense_buf[12] = (unsigned char)(us->ip_data >> 8);
851affae2bfSwdenk srb->sense_buf[13] = (unsigned char)(us->ip_data & 0xff);
852affae2bfSwdenk if (!us->ip_data) {
853affae2bfSwdenk /* if the status is good, report it */
854affae2bfSwdenk if (status == USB_STOR_TRANSPORT_GOOD) {
855ceb4972aSVivek Gautam debug(" USB CBI Command Good\n");
856affae2bfSwdenk return status;
857affae2bfSwdenk }
858affae2bfSwdenk }
859affae2bfSwdenk }
860affae2bfSwdenk /* do we have to issue an auto request? */
861affae2bfSwdenk /* HERE we have to check the result */
862affae2bfSwdenk if ((result < 0) && !(us->pusb_dev->status & USB_ST_STALLED)) {
863ceb4972aSVivek Gautam debug("ERROR %lX\n", us->pusb_dev->status);
864affae2bfSwdenk us->transport_reset(us);
865affae2bfSwdenk return USB_STOR_TRANSPORT_ERROR;
866affae2bfSwdenk }
867affae2bfSwdenk if ((us->protocol == US_PR_CBI) &&
868affae2bfSwdenk ((srb->cmd[0] == SCSI_REQ_SENSE) ||
869a0cb3fc3SMichael Trimarchi (srb->cmd[0] == SCSI_INQUIRY))) {
870a0cb3fc3SMichael Trimarchi /* do not issue an autorequest after request sense */
871ceb4972aSVivek Gautam debug("No auto request and good\n");
872affae2bfSwdenk return USB_STOR_TRANSPORT_GOOD;
873affae2bfSwdenk }
874affae2bfSwdenk /* issue an request_sense */
875affae2bfSwdenk memset(&psrb->cmd[0], 0, 12);
876affae2bfSwdenk psrb->cmd[0] = SCSI_REQ_SENSE;
877affae2bfSwdenk psrb->cmd[1] = srb->lun << 5;
878affae2bfSwdenk psrb->cmd[4] = 18;
879affae2bfSwdenk psrb->datalen = 18;
880affae2bfSwdenk psrb->pdata = &srb->sense_buf[0];
881affae2bfSwdenk psrb->cmdlen = 12;
882affae2bfSwdenk /* issue the command */
883affae2bfSwdenk result = usb_stor_CB_comdat(psrb, us);
884ceb4972aSVivek Gautam debug("auto request returned %d\n", result);
885affae2bfSwdenk /* if this is an CBI Protocol, get IRQ */
886a0cb3fc3SMichael Trimarchi if (us->protocol == US_PR_CBI)
887affae2bfSwdenk status = usb_stor_CBI_get_status(psrb, us);
888a0cb3fc3SMichael Trimarchi
889affae2bfSwdenk if ((result < 0) && !(us->pusb_dev->status & USB_ST_STALLED)) {
890ceb4972aSVivek Gautam debug(" AUTO REQUEST ERROR %ld\n",
891a0cb3fc3SMichael Trimarchi us->pusb_dev->status);
892affae2bfSwdenk return USB_STOR_TRANSPORT_ERROR;
893affae2bfSwdenk }
894ceb4972aSVivek Gautam debug("autorequest returned 0x%02X 0x%02X 0x%02X 0x%02X\n",
895a0cb3fc3SMichael Trimarchi srb->sense_buf[0], srb->sense_buf[2],
896a0cb3fc3SMichael Trimarchi srb->sense_buf[12], srb->sense_buf[13]);
897affae2bfSwdenk /* Check the auto request result */
898affae2bfSwdenk if ((srb->sense_buf[2] == 0) &&
899affae2bfSwdenk (srb->sense_buf[12] == 0) &&
900a0cb3fc3SMichael Trimarchi (srb->sense_buf[13] == 0)) {
901a0cb3fc3SMichael Trimarchi /* ok, no sense */
902affae2bfSwdenk return USB_STOR_TRANSPORT_GOOD;
903a0cb3fc3SMichael Trimarchi }
904a0cb3fc3SMichael Trimarchi
905affae2bfSwdenk /* Check the auto request result */
906affae2bfSwdenk switch (srb->sense_buf[2]) {
907a0cb3fc3SMichael Trimarchi case 0x01:
908a0cb3fc3SMichael Trimarchi /* Recovered Error */
909affae2bfSwdenk return USB_STOR_TRANSPORT_GOOD;
910affae2bfSwdenk break;
911a0cb3fc3SMichael Trimarchi case 0x02:
912a0cb3fc3SMichael Trimarchi /* Not Ready */
913affae2bfSwdenk if (notready++ > USB_TRANSPORT_NOT_READY_RETRY) {
914a0cb3fc3SMichael Trimarchi printf("cmd 0x%02X returned 0x%02X 0x%02X 0x%02X"
915a0cb3fc3SMichael Trimarchi " 0x%02X (NOT READY)\n", srb->cmd[0],
916a0cb3fc3SMichael Trimarchi srb->sense_buf[0], srb->sense_buf[2],
917a0cb3fc3SMichael Trimarchi srb->sense_buf[12], srb->sense_buf[13]);
918affae2bfSwdenk return USB_STOR_TRANSPORT_FAILED;
919149dded2Swdenk } else {
9205b84dd67SMike Frysinger mdelay(100);
921affae2bfSwdenk goto do_retry;
922affae2bfSwdenk }
923affae2bfSwdenk break;
924affae2bfSwdenk default:
925affae2bfSwdenk if (retry++ > USB_TRANSPORT_UNKNOWN_RETRY) {
926a0cb3fc3SMichael Trimarchi printf("cmd 0x%02X returned 0x%02X 0x%02X 0x%02X"
927a0cb3fc3SMichael Trimarchi " 0x%02X\n", srb->cmd[0], srb->sense_buf[0],
928a0cb3fc3SMichael Trimarchi srb->sense_buf[2], srb->sense_buf[12],
929a0cb3fc3SMichael Trimarchi srb->sense_buf[13]);
930affae2bfSwdenk return USB_STOR_TRANSPORT_FAILED;
931a0cb3fc3SMichael Trimarchi } else
932affae2bfSwdenk goto do_retry;
933affae2bfSwdenk break;
934affae2bfSwdenk }
935affae2bfSwdenk return USB_STOR_TRANSPORT_FAILED;
936affae2bfSwdenk }
937affae2bfSwdenk
usb_stor_set_max_xfer_blk(struct usb_device * udev,struct us_data * us)938ea7fad91SBin Meng static void usb_stor_set_max_xfer_blk(struct usb_device *udev,
939ea7fad91SBin Meng struct us_data *us)
9406158d0b4SBin Meng {
9416158d0b4SBin Meng unsigned short blk;
942ea7fad91SBin Meng size_t __maybe_unused size;
943ea7fad91SBin Meng int __maybe_unused ret;
9446158d0b4SBin Meng
945fd09c205SSven Schwermer #if !CONFIG_IS_ENABLED(DM_USB)
9466158d0b4SBin Meng #ifdef CONFIG_USB_EHCI_HCD
9476158d0b4SBin Meng /*
9486158d0b4SBin Meng * The U-Boot EHCI driver can handle any transfer length as long as
9496158d0b4SBin Meng * there is enough free heap space left, but the SCSI READ(10) and
9506158d0b4SBin Meng * WRITE(10) commands are limited to 65535 blocks.
9516158d0b4SBin Meng */
9526158d0b4SBin Meng blk = USHRT_MAX;
9536158d0b4SBin Meng #else
9546158d0b4SBin Meng blk = 20;
9556158d0b4SBin Meng #endif
956ea7fad91SBin Meng #else
957ea7fad91SBin Meng ret = usb_get_max_xfer_size(udev, (size_t *)&size);
958ea7fad91SBin Meng if (ret < 0) {
959ea7fad91SBin Meng /* unimplemented, let's use default 20 */
960ea7fad91SBin Meng blk = 20;
961ea7fad91SBin Meng } else {
962ea7fad91SBin Meng if (size > USHRT_MAX * 512)
96372ac8f3fSBin Meng size = USHRT_MAX * 512;
964ea7fad91SBin Meng blk = size / 512;
965ea7fad91SBin Meng }
966ea7fad91SBin Meng #endif
9676158d0b4SBin Meng
9686158d0b4SBin Meng us->max_xfer_blk = blk;
9696158d0b4SBin Meng }
970affae2bfSwdenk
usb_inquiry(struct scsi_cmd * srb,struct us_data * ss)971b9560ad6SSimon Glass static int usb_inquiry(struct scsi_cmd *srb, struct us_data *ss)
972affae2bfSwdenk {
973affae2bfSwdenk int retry, i;
9749c998aa8SWolfgang Denk retry = 5;
975affae2bfSwdenk do {
976affae2bfSwdenk memset(&srb->cmd[0], 0, 12);
977affae2bfSwdenk srb->cmd[0] = SCSI_INQUIRY;
97899e9ed1fSLudovic Courtès srb->cmd[1] = srb->lun << 5;
979affae2bfSwdenk srb->cmd[4] = 36;
980affae2bfSwdenk srb->datalen = 36;
981affae2bfSwdenk srb->cmdlen = 12;
982affae2bfSwdenk i = ss->transport(srb, ss);
983ceb4972aSVivek Gautam debug("inquiry returns %d\n", i);
984affae2bfSwdenk if (i == 0)
985affae2bfSwdenk break;
986fac71cc4SKim B. Heino } while (--retry);
987149dded2Swdenk
988affae2bfSwdenk if (!retry) {
989affae2bfSwdenk printf("error in inquiry\n");
990affae2bfSwdenk return -1;
991affae2bfSwdenk }
992affae2bfSwdenk return 0;
993affae2bfSwdenk }
994affae2bfSwdenk
usb_request_sense(struct scsi_cmd * srb,struct us_data * ss)995b9560ad6SSimon Glass static int usb_request_sense(struct scsi_cmd *srb, struct us_data *ss)
996affae2bfSwdenk {
997affae2bfSwdenk char *ptr;
99880885a9dSwdenk
99977ddac94SWolfgang Denk ptr = (char *)srb->pdata;
1000affae2bfSwdenk memset(&srb->cmd[0], 0, 12);
1001affae2bfSwdenk srb->cmd[0] = SCSI_REQ_SENSE;
100299e9ed1fSLudovic Courtès srb->cmd[1] = srb->lun << 5;
1003affae2bfSwdenk srb->cmd[4] = 18;
1004affae2bfSwdenk srb->datalen = 18;
1005affae2bfSwdenk srb->pdata = &srb->sense_buf[0];
1006affae2bfSwdenk srb->cmdlen = 12;
1007affae2bfSwdenk ss->transport(srb, ss);
1008ceb4972aSVivek Gautam debug("Request Sense returned %02X %02X %02X\n",
1009a0cb3fc3SMichael Trimarchi srb->sense_buf[2], srb->sense_buf[12],
1010a0cb3fc3SMichael Trimarchi srb->sense_buf[13]);
101177ddac94SWolfgang Denk srb->pdata = (uchar *)ptr;
1012affae2bfSwdenk return 0;
1013affae2bfSwdenk }
1014affae2bfSwdenk
usb_test_unit_ready(struct scsi_cmd * srb,struct us_data * ss)1015b9560ad6SSimon Glass static int usb_test_unit_ready(struct scsi_cmd *srb, struct us_data *ss)
1016affae2bfSwdenk {
1017affae2bfSwdenk int retries = 10;
1018149dded2Swdenk
1019affae2bfSwdenk do {
1020affae2bfSwdenk memset(&srb->cmd[0], 0, 12);
1021affae2bfSwdenk srb->cmd[0] = SCSI_TST_U_RDY;
102299e9ed1fSLudovic Courtès srb->cmd[1] = srb->lun << 5;
1023affae2bfSwdenk srb->datalen = 0;
1024affae2bfSwdenk srb->cmdlen = 12;
10253e8581bbSBenoît Thébaudeau if (ss->transport(srb, ss) == USB_STOR_TRANSPORT_GOOD) {
10263e8581bbSBenoît Thébaudeau ss->flags |= USB_READY;
1027affae2bfSwdenk return 0;
10283e8581bbSBenoît Thébaudeau }
102980885a9dSwdenk usb_request_sense(srb, ss);
10308b57e2f0SVincent Palatin /*
10318b57e2f0SVincent Palatin * Check the Key Code Qualifier, if it matches
10328b57e2f0SVincent Palatin * "Not Ready - medium not present"
10338b57e2f0SVincent Palatin * (the sense Key equals 0x2 and the ASC is 0x3a)
10348b57e2f0SVincent Palatin * return immediately as the medium being absent won't change
10358b57e2f0SVincent Palatin * unless there is a user action.
10368b57e2f0SVincent Palatin */
10378b57e2f0SVincent Palatin if ((srb->sense_buf[2] == 0x02) &&
10388b57e2f0SVincent Palatin (srb->sense_buf[12] == 0x3a))
10398b57e2f0SVincent Palatin return -1;
10405b84dd67SMike Frysinger mdelay(100);
1041affae2bfSwdenk } while (retries--);
1042149dded2Swdenk
1043affae2bfSwdenk return -1;
1044affae2bfSwdenk }
1045affae2bfSwdenk
usb_read_capacity(struct scsi_cmd * srb,struct us_data * ss)1046b9560ad6SSimon Glass static int usb_read_capacity(struct scsi_cmd *srb, struct us_data *ss)
1047affae2bfSwdenk {
1048affae2bfSwdenk int retry;
1049a0cb3fc3SMichael Trimarchi /* XXX retries */
1050a0cb3fc3SMichael Trimarchi retry = 3;
1051affae2bfSwdenk do {
1052affae2bfSwdenk memset(&srb->cmd[0], 0, 12);
1053affae2bfSwdenk srb->cmd[0] = SCSI_RD_CAPAC;
105499e9ed1fSLudovic Courtès srb->cmd[1] = srb->lun << 5;
1055affae2bfSwdenk srb->datalen = 8;
1056affae2bfSwdenk srb->cmdlen = 12;
1057a0cb3fc3SMichael Trimarchi if (ss->transport(srb, ss) == USB_STOR_TRANSPORT_GOOD)
1058affae2bfSwdenk return 0;
1059affae2bfSwdenk } while (retry--);
1060149dded2Swdenk
1061affae2bfSwdenk return -1;
1062affae2bfSwdenk }
1063affae2bfSwdenk
usb_read_10(struct scsi_cmd * srb,struct us_data * ss,unsigned long start,unsigned short blocks)1064b9560ad6SSimon Glass static int usb_read_10(struct scsi_cmd *srb, struct us_data *ss,
1065b9560ad6SSimon Glass unsigned long start, unsigned short blocks)
1066affae2bfSwdenk {
1067affae2bfSwdenk memset(&srb->cmd[0], 0, 12);
1068affae2bfSwdenk srb->cmd[0] = SCSI_READ10;
106999e9ed1fSLudovic Courtès srb->cmd[1] = srb->lun << 5;
1070affae2bfSwdenk srb->cmd[2] = ((unsigned char) (start >> 24)) & 0xff;
1071affae2bfSwdenk srb->cmd[3] = ((unsigned char) (start >> 16)) & 0xff;
1072affae2bfSwdenk srb->cmd[4] = ((unsigned char) (start >> 8)) & 0xff;
1073affae2bfSwdenk srb->cmd[5] = ((unsigned char) (start)) & 0xff;
1074affae2bfSwdenk srb->cmd[7] = ((unsigned char) (blocks >> 8)) & 0xff;
1075affae2bfSwdenk srb->cmd[8] = (unsigned char) blocks & 0xff;
1076affae2bfSwdenk srb->cmdlen = 12;
1077ceb4972aSVivek Gautam debug("read10: start %lx blocks %x\n", start, blocks);
1078affae2bfSwdenk return ss->transport(srb, ss);
1079affae2bfSwdenk }
1080affae2bfSwdenk
usb_write_10(struct scsi_cmd * srb,struct us_data * ss,unsigned long start,unsigned short blocks)1081b9560ad6SSimon Glass static int usb_write_10(struct scsi_cmd *srb, struct us_data *ss,
1082b9560ad6SSimon Glass unsigned long start, unsigned short blocks)
1083127e1084SMahavir Jain {
1084127e1084SMahavir Jain memset(&srb->cmd[0], 0, 12);
1085127e1084SMahavir Jain srb->cmd[0] = SCSI_WRITE10;
108699e9ed1fSLudovic Courtès srb->cmd[1] = srb->lun << 5;
1087127e1084SMahavir Jain srb->cmd[2] = ((unsigned char) (start >> 24)) & 0xff;
1088127e1084SMahavir Jain srb->cmd[3] = ((unsigned char) (start >> 16)) & 0xff;
1089127e1084SMahavir Jain srb->cmd[4] = ((unsigned char) (start >> 8)) & 0xff;
1090127e1084SMahavir Jain srb->cmd[5] = ((unsigned char) (start)) & 0xff;
1091127e1084SMahavir Jain srb->cmd[7] = ((unsigned char) (blocks >> 8)) & 0xff;
1092127e1084SMahavir Jain srb->cmd[8] = (unsigned char) blocks & 0xff;
1093127e1084SMahavir Jain srb->cmdlen = 12;
1094ceb4972aSVivek Gautam debug("write10: start %lx blocks %x\n", start, blocks);
1095127e1084SMahavir Jain return ss->transport(srb, ss);
1096127e1084SMahavir Jain }
1097127e1084SMahavir Jain
1098affae2bfSwdenk
1099ddde6b7cSBartlomiej Sieka #ifdef CONFIG_USB_BIN_FIXUP
1100ddde6b7cSBartlomiej Sieka /*
1101ddde6b7cSBartlomiej Sieka * Some USB storage devices queried for SCSI identification data respond with
1102ddde6b7cSBartlomiej Sieka * binary strings, which if output to the console freeze the terminal. The
1103ddde6b7cSBartlomiej Sieka * workaround is to modify the vendor and product strings read from such
1104ddde6b7cSBartlomiej Sieka * device with proper values (as reported by 'usb info').
1105ddde6b7cSBartlomiej Sieka *
1106ddde6b7cSBartlomiej Sieka * Vendor and product length limits are taken from the definition of
11074101f687SSimon Glass * struct blk_desc in include/part.h.
1108ddde6b7cSBartlomiej Sieka */
usb_bin_fixup(struct usb_device_descriptor descriptor,unsigned char vendor[],unsigned char product[])1109ddde6b7cSBartlomiej Sieka static void usb_bin_fixup(struct usb_device_descriptor descriptor,
1110ddde6b7cSBartlomiej Sieka unsigned char vendor[],
1111ddde6b7cSBartlomiej Sieka unsigned char product[]) {
1112ddde6b7cSBartlomiej Sieka const unsigned char max_vendor_len = 40;
1113ddde6b7cSBartlomiej Sieka const unsigned char max_product_len = 20;
1114ddde6b7cSBartlomiej Sieka if (descriptor.idVendor == 0x0424 && descriptor.idProduct == 0x223a) {
111573652699SWolfgang Denk strncpy((char *)vendor, "SMSC", max_vendor_len);
1116a0cb3fc3SMichael Trimarchi strncpy((char *)product, "Flash Media Cntrller",
1117a0cb3fc3SMichael Trimarchi max_product_len);
1118ddde6b7cSBartlomiej Sieka }
1119ddde6b7cSBartlomiej Sieka }
1120ddde6b7cSBartlomiej Sieka #endif /* CONFIG_USB_BIN_FIXUP */
1121ddde6b7cSBartlomiej Sieka
1122*1af9bfd3SSven Schwermer #if CONFIG_IS_ENABLED(BLK)
usb_stor_read(struct udevice * dev,lbaint_t blknr,lbaint_t blkcnt,void * buffer)112307b2b78cSSimon Glass static unsigned long usb_stor_read(struct udevice *dev, lbaint_t blknr,
112407b2b78cSSimon Glass lbaint_t blkcnt, void *buffer)
112507b2b78cSSimon Glass #else
11264101f687SSimon Glass static unsigned long usb_stor_read(struct blk_desc *block_dev, lbaint_t blknr,
1127e81e79edSGabe Black lbaint_t blkcnt, void *buffer)
112807b2b78cSSimon Glass #endif
1129affae2bfSwdenk {
1130e81e79edSGabe Black lbaint_t start, blks;
1131e81e79edSGabe Black uintptr_t buf_addr;
1132affae2bfSwdenk unsigned short smallblks;
11339807c3b7SSimon Glass struct usb_device *udev;
11345dd95cf9SKyle Moffett struct us_data *ss;
113584073b6fSSimon Glass int retry;
1136b9560ad6SSimon Glass struct scsi_cmd *srb = &usb_ccb;
1137*1af9bfd3SSven Schwermer #if CONFIG_IS_ENABLED(BLK)
113807b2b78cSSimon Glass struct blk_desc *block_dev;
113907b2b78cSSimon Glass #endif
1140f8d813e3Swdenk
1141f8d813e3Swdenk if (blkcnt == 0)
1142f8d813e3Swdenk return 0;
1143a0cb3fc3SMichael Trimarchi /* Setup device */
1144*1af9bfd3SSven Schwermer #if CONFIG_IS_ENABLED(BLK)
114507b2b78cSSimon Glass block_dev = dev_get_uclass_platdata(dev);
114607b2b78cSSimon Glass udev = dev_get_parent_priv(dev_get_parent(dev));
114707b2b78cSSimon Glass debug("\nusb_read: udev %d\n", block_dev->devnum);
114807b2b78cSSimon Glass #else
11499807c3b7SSimon Glass debug("\nusb_read: udev %d\n", block_dev->devnum);
11509807c3b7SSimon Glass udev = usb_dev_desc[block_dev->devnum].priv;
11519807c3b7SSimon Glass if (!udev) {
115284073b6fSSimon Glass debug("%s: No device\n", __func__);
1153affae2bfSwdenk return 0;
1154affae2bfSwdenk }
115507b2b78cSSimon Glass #endif
11569807c3b7SSimon Glass ss = (struct us_data *)udev->privptr;
1157affae2bfSwdenk
1158affae2bfSwdenk usb_disable_asynch(1); /* asynch transfer not allowed */
11599807c3b7SSimon Glass srb->lun = block_dev->lun;
1160f6570871SSergey Temerkhanov buf_addr = (uintptr_t)buffer;
1161affae2bfSwdenk start = blknr;
1162affae2bfSwdenk blks = blkcnt;
1163a0cb3fc3SMichael Trimarchi
1164dee37fc9SMasahiro Yamada debug("\nusb_read: dev %d startblk " LBAF ", blccnt " LBAF " buffer %lx\n",
1165dee37fc9SMasahiro Yamada block_dev->devnum, start, blks, buf_addr);
1166a0cb3fc3SMichael Trimarchi
1167affae2bfSwdenk do {
1168a0cb3fc3SMichael Trimarchi /* XXX need some comment here */
1169affae2bfSwdenk retry = 2;
1170affae2bfSwdenk srb->pdata = (unsigned char *)buf_addr;
11716158d0b4SBin Meng if (blks > ss->max_xfer_blk)
11726158d0b4SBin Meng smallblks = ss->max_xfer_blk;
1173a0cb3fc3SMichael Trimarchi else
1174affae2bfSwdenk smallblks = (unsigned short) blks;
1175affae2bfSwdenk retry_it:
11766158d0b4SBin Meng if (smallblks == ss->max_xfer_blk)
1177affae2bfSwdenk usb_show_progress();
11789807c3b7SSimon Glass srb->datalen = block_dev->blksz * smallblks;
1179affae2bfSwdenk srb->pdata = (unsigned char *)buf_addr;
11805dd95cf9SKyle Moffett if (usb_read_10(srb, ss, start, smallblks)) {
1181ceb4972aSVivek Gautam debug("Read ERROR\n");
11825dd95cf9SKyle Moffett usb_request_sense(srb, ss);
1183affae2bfSwdenk if (retry--)
1184affae2bfSwdenk goto retry_it;
1185affae2bfSwdenk blkcnt -= blks;
1186affae2bfSwdenk break;
1187affae2bfSwdenk }
1188affae2bfSwdenk start += smallblks;
1189affae2bfSwdenk blks -= smallblks;
1190affae2bfSwdenk buf_addr += srb->datalen;
1191affae2bfSwdenk } while (blks != 0);
11923e8581bbSBenoît Thébaudeau ss->flags &= ~USB_READY;
1193a0cb3fc3SMichael Trimarchi
1194dee37fc9SMasahiro Yamada debug("usb_read: end startblk " LBAF ", blccnt %x buffer %lx\n",
1195a0cb3fc3SMichael Trimarchi start, smallblks, buf_addr);
1196a0cb3fc3SMichael Trimarchi
1197affae2bfSwdenk usb_disable_asynch(0); /* asynch transfer allowed */
11986158d0b4SBin Meng if (blkcnt >= ss->max_xfer_blk)
1199226fa9bbSWolfgang Denk debug("\n");
1200a0cb3fc3SMichael Trimarchi return blkcnt;
1201affae2bfSwdenk }
1202affae2bfSwdenk
1203*1af9bfd3SSven Schwermer #if CONFIG_IS_ENABLED(BLK)
usb_stor_write(struct udevice * dev,lbaint_t blknr,lbaint_t blkcnt,const void * buffer)120407b2b78cSSimon Glass static unsigned long usb_stor_write(struct udevice *dev, lbaint_t blknr,
120507b2b78cSSimon Glass lbaint_t blkcnt, const void *buffer)
120607b2b78cSSimon Glass #else
12074101f687SSimon Glass static unsigned long usb_stor_write(struct blk_desc *block_dev, lbaint_t blknr,
1208e81e79edSGabe Black lbaint_t blkcnt, const void *buffer)
120907b2b78cSSimon Glass #endif
1210127e1084SMahavir Jain {
1211e81e79edSGabe Black lbaint_t start, blks;
1212e81e79edSGabe Black uintptr_t buf_addr;
1213127e1084SMahavir Jain unsigned short smallblks;
12149807c3b7SSimon Glass struct usb_device *udev;
12155dd95cf9SKyle Moffett struct us_data *ss;
121684073b6fSSimon Glass int retry;
1217b9560ad6SSimon Glass struct scsi_cmd *srb = &usb_ccb;
1218*1af9bfd3SSven Schwermer #if CONFIG_IS_ENABLED(BLK)
121907b2b78cSSimon Glass struct blk_desc *block_dev;
122007b2b78cSSimon Glass #endif
1221127e1084SMahavir Jain
1222127e1084SMahavir Jain if (blkcnt == 0)
1223127e1084SMahavir Jain return 0;
1224127e1084SMahavir Jain
1225127e1084SMahavir Jain /* Setup device */
1226*1af9bfd3SSven Schwermer #if CONFIG_IS_ENABLED(BLK)
122707b2b78cSSimon Glass block_dev = dev_get_uclass_platdata(dev);
122807b2b78cSSimon Glass udev = dev_get_parent_priv(dev_get_parent(dev));
122907b2b78cSSimon Glass debug("\nusb_read: udev %d\n", block_dev->devnum);
123007b2b78cSSimon Glass #else
12319807c3b7SSimon Glass debug("\nusb_read: udev %d\n", block_dev->devnum);
12329807c3b7SSimon Glass udev = usb_dev_desc[block_dev->devnum].priv;
12339807c3b7SSimon Glass if (!udev) {
12349807c3b7SSimon Glass debug("%s: No device\n", __func__);
1235127e1084SMahavir Jain return 0;
12369807c3b7SSimon Glass }
123707b2b78cSSimon Glass #endif
12389807c3b7SSimon Glass ss = (struct us_data *)udev->privptr;
1239127e1084SMahavir Jain
1240127e1084SMahavir Jain usb_disable_asynch(1); /* asynch transfer not allowed */
1241127e1084SMahavir Jain
12429807c3b7SSimon Glass srb->lun = block_dev->lun;
1243f6570871SSergey Temerkhanov buf_addr = (uintptr_t)buffer;
1244127e1084SMahavir Jain start = blknr;
1245127e1084SMahavir Jain blks = blkcnt;
1246127e1084SMahavir Jain
1247dee37fc9SMasahiro Yamada debug("\nusb_write: dev %d startblk " LBAF ", blccnt " LBAF " buffer %lx\n",
1248dee37fc9SMasahiro Yamada block_dev->devnum, start, blks, buf_addr);
1249127e1084SMahavir Jain
1250127e1084SMahavir Jain do {
1251127e1084SMahavir Jain /* If write fails retry for max retry count else
1252127e1084SMahavir Jain * return with number of blocks written successfully.
1253127e1084SMahavir Jain */
1254127e1084SMahavir Jain retry = 2;
1255127e1084SMahavir Jain srb->pdata = (unsigned char *)buf_addr;
12566158d0b4SBin Meng if (blks > ss->max_xfer_blk)
12576158d0b4SBin Meng smallblks = ss->max_xfer_blk;
1258127e1084SMahavir Jain else
1259127e1084SMahavir Jain smallblks = (unsigned short) blks;
1260127e1084SMahavir Jain retry_it:
12616158d0b4SBin Meng if (smallblks == ss->max_xfer_blk)
1262127e1084SMahavir Jain usb_show_progress();
12639807c3b7SSimon Glass srb->datalen = block_dev->blksz * smallblks;
1264127e1084SMahavir Jain srb->pdata = (unsigned char *)buf_addr;
12655dd95cf9SKyle Moffett if (usb_write_10(srb, ss, start, smallblks)) {
1266ceb4972aSVivek Gautam debug("Write ERROR\n");
12675dd95cf9SKyle Moffett usb_request_sense(srb, ss);
1268127e1084SMahavir Jain if (retry--)
1269127e1084SMahavir Jain goto retry_it;
1270127e1084SMahavir Jain blkcnt -= blks;
1271127e1084SMahavir Jain break;
1272127e1084SMahavir Jain }
1273127e1084SMahavir Jain start += smallblks;
1274127e1084SMahavir Jain blks -= smallblks;
1275127e1084SMahavir Jain buf_addr += srb->datalen;
1276127e1084SMahavir Jain } while (blks != 0);
12773e8581bbSBenoît Thébaudeau ss->flags &= ~USB_READY;
1278127e1084SMahavir Jain
1279dee37fc9SMasahiro Yamada debug("usb_write: end startblk " LBAF ", blccnt %x buffer %lx\n",
1280dee37fc9SMasahiro Yamada start, smallblks, buf_addr);
1281127e1084SMahavir Jain
1282127e1084SMahavir Jain usb_disable_asynch(0); /* asynch transfer allowed */
12836158d0b4SBin Meng if (blkcnt >= ss->max_xfer_blk)
1284226fa9bbSWolfgang Denk debug("\n");
1285127e1084SMahavir Jain return blkcnt;
1286127e1084SMahavir Jain
1287127e1084SMahavir Jain }
1288affae2bfSwdenk
1289affae2bfSwdenk /* Probe to see if a new device is actually a Storage device */
usb_storage_probe(struct usb_device * dev,unsigned int ifnum,struct us_data * ss)1290a0cb3fc3SMichael Trimarchi int usb_storage_probe(struct usb_device *dev, unsigned int ifnum,
1291a0cb3fc3SMichael Trimarchi struct us_data *ss)
1292affae2bfSwdenk {
12938f8bd565STom Rix struct usb_interface *iface;
1294affae2bfSwdenk int i;
1295605bd75aSVivek Gautam struct usb_endpoint_descriptor *ep_desc;
1296affae2bfSwdenk unsigned int flags = 0;
1297affae2bfSwdenk
1298affae2bfSwdenk /* let's examine the device now */
1299affae2bfSwdenk iface = &dev->config.if_desc[ifnum];
1300affae2bfSwdenk
1301affae2bfSwdenk if (dev->descriptor.bDeviceClass != 0 ||
13028f8bd565STom Rix iface->desc.bInterfaceClass != USB_CLASS_MASS_STORAGE ||
13038f8bd565STom Rix iface->desc.bInterfaceSubClass < US_SC_MIN ||
13048f8bd565STom Rix iface->desc.bInterfaceSubClass > US_SC_MAX) {
13051d5827a1SSimon Glass debug("Not mass storage\n");
1306affae2bfSwdenk /* if it's not a mass storage, we go no further */
1307affae2bfSwdenk return 0;
1308affae2bfSwdenk }
1309affae2bfSwdenk
13109c998aa8SWolfgang Denk memset(ss, 0, sizeof(struct us_data));
13119c998aa8SWolfgang Denk
1312affae2bfSwdenk /* At this point, we know we've got a live one */
1313ceb4972aSVivek Gautam debug("\n\nUSB Mass Storage device detected\n");
1314affae2bfSwdenk
1315affae2bfSwdenk /* Initialize the us_data structure with some useful info */
1316affae2bfSwdenk ss->flags = flags;
1317affae2bfSwdenk ss->ifnum = ifnum;
1318affae2bfSwdenk ss->pusb_dev = dev;
1319affae2bfSwdenk ss->attention_done = 0;
13208f8bd565STom Rix ss->subclass = iface->desc.bInterfaceSubClass;
13218f8bd565STom Rix ss->protocol = iface->desc.bInterfaceProtocol;
1322affae2bfSwdenk
1323affae2bfSwdenk /* set the handler pointers based on the protocol */
1324ceb4972aSVivek Gautam debug("Transport: ");
1325affae2bfSwdenk switch (ss->protocol) {
1326affae2bfSwdenk case US_PR_CB:
1327ceb4972aSVivek Gautam debug("Control/Bulk\n");
1328affae2bfSwdenk ss->transport = usb_stor_CB_transport;
1329affae2bfSwdenk ss->transport_reset = usb_stor_CB_reset;
1330affae2bfSwdenk break;
1331affae2bfSwdenk
1332affae2bfSwdenk case US_PR_CBI:
1333ceb4972aSVivek Gautam debug("Control/Bulk/Interrupt\n");
1334affae2bfSwdenk ss->transport = usb_stor_CB_transport;
1335affae2bfSwdenk ss->transport_reset = usb_stor_CB_reset;
1336affae2bfSwdenk break;
1337149dded2Swdenk case US_PR_BULK:
1338ceb4972aSVivek Gautam debug("Bulk/Bulk/Bulk\n");
1339149dded2Swdenk ss->transport = usb_stor_BBB_transport;
1340149dded2Swdenk ss->transport_reset = usb_stor_BBB_reset;
1341149dded2Swdenk break;
1342affae2bfSwdenk default:
134380885a9dSwdenk printf("USB Storage Transport unknown / not yet implemented\n");
1344affae2bfSwdenk return 0;
1345affae2bfSwdenk break;
1346affae2bfSwdenk }
1347affae2bfSwdenk
1348affae2bfSwdenk /*
1349affae2bfSwdenk * We are expecting a minimum of 2 endpoints - in and out (bulk).
1350affae2bfSwdenk * An optional interrupt is OK (necessary for CBI protocol).
1351affae2bfSwdenk * We will ignore any others.
1352affae2bfSwdenk */
13538f8bd565STom Rix for (i = 0; i < iface->desc.bNumEndpoints; i++) {
1354605bd75aSVivek Gautam ep_desc = &iface->ep_desc[i];
1355affae2bfSwdenk /* is it an BULK endpoint? */
1356605bd75aSVivek Gautam if ((ep_desc->bmAttributes &
1357a0cb3fc3SMichael Trimarchi USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK) {
1358605bd75aSVivek Gautam if (ep_desc->bEndpointAddress & USB_DIR_IN)
1359605bd75aSVivek Gautam ss->ep_in = ep_desc->bEndpointAddress &
1360affae2bfSwdenk USB_ENDPOINT_NUMBER_MASK;
1361affae2bfSwdenk else
1362a0cb3fc3SMichael Trimarchi ss->ep_out =
1363605bd75aSVivek Gautam ep_desc->bEndpointAddress &
1364affae2bfSwdenk USB_ENDPOINT_NUMBER_MASK;
1365affae2bfSwdenk }
1366affae2bfSwdenk
1367affae2bfSwdenk /* is it an interrupt endpoint? */
1368605bd75aSVivek Gautam if ((ep_desc->bmAttributes &
1369a0cb3fc3SMichael Trimarchi USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT) {
1370605bd75aSVivek Gautam ss->ep_int = ep_desc->bEndpointAddress &
1371affae2bfSwdenk USB_ENDPOINT_NUMBER_MASK;
1372605bd75aSVivek Gautam ss->irqinterval = ep_desc->bInterval;
1373affae2bfSwdenk }
1374affae2bfSwdenk }
1375ceb4972aSVivek Gautam debug("Endpoints In %d Out %d Int %d\n",
1376affae2bfSwdenk ss->ep_in, ss->ep_out, ss->ep_int);
1377affae2bfSwdenk
1378affae2bfSwdenk /* Do some basic sanity checks, and bail if we find a problem */
13798f8bd565STom Rix if (usb_set_interface(dev, iface->desc.bInterfaceNumber, 0) ||
1380affae2bfSwdenk !ss->ep_in || !ss->ep_out ||
1381affae2bfSwdenk (ss->protocol == US_PR_CBI && ss->ep_int == 0)) {
1382ceb4972aSVivek Gautam debug("Problems with device\n");
1383affae2bfSwdenk return 0;
1384affae2bfSwdenk }
1385affae2bfSwdenk /* set class specific stuff */
1386149dded2Swdenk /* We only handle certain protocols. Currently, these are
1387149dded2Swdenk * the only ones.
138880885a9dSwdenk * The SFF8070 accepts the requests used in u-boot
1389affae2bfSwdenk */
139080885a9dSwdenk if (ss->subclass != US_SC_UFI && ss->subclass != US_SC_SCSI &&
139180885a9dSwdenk ss->subclass != US_SC_8070) {
1392affae2bfSwdenk printf("Sorry, protocol %d not yet supported.\n", ss->subclass);
1393affae2bfSwdenk return 0;
1394affae2bfSwdenk }
1395a0cb3fc3SMichael Trimarchi if (ss->ep_int) {
1396a0cb3fc3SMichael Trimarchi /* we had found an interrupt endpoint, prepare irq pipe
1397a0cb3fc3SMichael Trimarchi * set up the IRQ pipe and handler
1398a0cb3fc3SMichael Trimarchi */
1399affae2bfSwdenk ss->irqinterval = (ss->irqinterval > 0) ? ss->irqinterval : 255;
1400affae2bfSwdenk ss->irqpipe = usb_rcvintpipe(ss->pusb_dev, ss->ep_int);
1401affae2bfSwdenk ss->irqmaxp = usb_maxpacket(dev, ss->irqpipe);
1402affae2bfSwdenk dev->irq_handle = usb_stor_irq;
1403affae2bfSwdenk }
14046158d0b4SBin Meng
14056158d0b4SBin Meng /* Set the maximum transfer size per host controller setting */
1406ea7fad91SBin Meng usb_stor_set_max_xfer_blk(dev, ss);
14076158d0b4SBin Meng
1408a43278a4Swdenk dev->privptr = (void *)ss;
1409affae2bfSwdenk return 1;
1410affae2bfSwdenk }
1411affae2bfSwdenk
usb_stor_get_info(struct usb_device * dev,struct us_data * ss,struct blk_desc * dev_desc)1412a0cb3fc3SMichael Trimarchi int usb_stor_get_info(struct usb_device *dev, struct us_data *ss,
14134101f687SSimon Glass struct blk_desc *dev_desc)
1414affae2bfSwdenk {
1415affae2bfSwdenk unsigned char perq, modi;
1416f6570871SSergey Temerkhanov ALLOC_CACHE_ALIGN_BUFFER(u32, cap, 2);
1417f6570871SSergey Temerkhanov ALLOC_CACHE_ALIGN_BUFFER(u8, usb_stor_buf, 36);
1418f6570871SSergey Temerkhanov u32 capacity, blksz;
1419b9560ad6SSimon Glass struct scsi_cmd *pccb = &usb_ccb;
1420affae2bfSwdenk
1421affae2bfSwdenk pccb->pdata = usb_stor_buf;
1422affae2bfSwdenk
1423affae2bfSwdenk dev_desc->target = dev->devnum;
1424affae2bfSwdenk pccb->lun = dev_desc->lun;
1425ceb4972aSVivek Gautam debug(" address %d\n", dev_desc->target);
1426affae2bfSwdenk
14271d5827a1SSimon Glass if (usb_inquiry(pccb, ss)) {
14281d5827a1SSimon Glass debug("%s: usb_inquiry() failed\n", __func__);
1429affae2bfSwdenk return -1;
14301d5827a1SSimon Glass }
14319c998aa8SWolfgang Denk
1432affae2bfSwdenk perq = usb_stor_buf[0];
1433affae2bfSwdenk modi = usb_stor_buf[1];
1434a0cb3fc3SMichael Trimarchi
14356a559bbeSSoeren Moch /*
14366a559bbeSSoeren Moch * Skip unknown devices (0x1f) and enclosure service devices (0x0d),
14376a559bbeSSoeren Moch * they would not respond to test_unit_ready .
14386a559bbeSSoeren Moch */
14396a559bbeSSoeren Moch if (((perq & 0x1f) == 0x1f) || ((perq & 0x1f) == 0x0d)) {
14401d5827a1SSimon Glass debug("%s: unknown/unsupported device\n", __func__);
1441a0cb3fc3SMichael Trimarchi return 0;
1442affae2bfSwdenk }
1443a0cb3fc3SMichael Trimarchi if ((modi&0x80) == 0x80) {
1444a0cb3fc3SMichael Trimarchi /* drive is removable */
1445affae2bfSwdenk dev_desc->removable = 1;
1446affae2bfSwdenk }
1447f6570871SSergey Temerkhanov memcpy(dev_desc->vendor, (const void *)&usb_stor_buf[8], 8);
1448f6570871SSergey Temerkhanov memcpy(dev_desc->product, (const void *)&usb_stor_buf[16], 16);
1449f6570871SSergey Temerkhanov memcpy(dev_desc->revision, (const void *)&usb_stor_buf[32], 4);
1450affae2bfSwdenk dev_desc->vendor[8] = 0;
1451affae2bfSwdenk dev_desc->product[16] = 0;
1452affae2bfSwdenk dev_desc->revision[4] = 0;
1453ddde6b7cSBartlomiej Sieka #ifdef CONFIG_USB_BIN_FIXUP
1454a0cb3fc3SMichael Trimarchi usb_bin_fixup(dev->descriptor, (uchar *)dev_desc->vendor,
1455a0cb3fc3SMichael Trimarchi (uchar *)dev_desc->product);
1456ddde6b7cSBartlomiej Sieka #endif /* CONFIG_USB_BIN_FIXUP */
1457ceb4972aSVivek Gautam debug("ISO Vers %X, Response Data %X\n", usb_stor_buf[2],
1458a0cb3fc3SMichael Trimarchi usb_stor_buf[3]);
1459affae2bfSwdenk if (usb_test_unit_ready(pccb, ss)) {
1460a0cb3fc3SMichael Trimarchi printf("Device NOT ready\n"
1461a0cb3fc3SMichael Trimarchi " Request Sense returned %02X %02X %02X\n",
1462a0cb3fc3SMichael Trimarchi pccb->sense_buf[2], pccb->sense_buf[12],
1463a0cb3fc3SMichael Trimarchi pccb->sense_buf[13]);
14641e5eca7dSTroy Kisky if (dev_desc->removable == 1)
1465affae2bfSwdenk dev_desc->type = perq;
1466affae2bfSwdenk return 0;
1467affae2bfSwdenk }
1468f6570871SSergey Temerkhanov pccb->pdata = (unsigned char *)cap;
1469affae2bfSwdenk memset(pccb->pdata, 0, 8);
1470affae2bfSwdenk if (usb_read_capacity(pccb, ss) != 0) {
1471affae2bfSwdenk printf("READ_CAP ERROR\n");
1472affae2bfSwdenk cap[0] = 2880;
1473affae2bfSwdenk cap[1] = 0x200;
1474affae2bfSwdenk }
14753e8581bbSBenoît Thébaudeau ss->flags &= ~USB_READY;
1476f6570871SSergey Temerkhanov debug("Read Capacity returns: 0x%08x, 0x%08x\n", cap[0], cap[1]);
1477affae2bfSwdenk #if 0
1478affae2bfSwdenk if (cap[0] > (0x200000 * 10)) /* greater than 10 GByte */
1479affae2bfSwdenk cap[0] >>= 16;
1480f6570871SSergey Temerkhanov
1481c918261cSChristian Eggers cap[0] = cpu_to_be32(cap[0]);
1482c918261cSChristian Eggers cap[1] = cpu_to_be32(cap[1]);
1483f6570871SSergey Temerkhanov #endif
1484c918261cSChristian Eggers
1485f6570871SSergey Temerkhanov capacity = be32_to_cpu(cap[0]) + 1;
1486f6570871SSergey Temerkhanov blksz = be32_to_cpu(cap[1]);
1487f6570871SSergey Temerkhanov
1488f6570871SSergey Temerkhanov debug("Capacity = 0x%08x, blocksz = 0x%08x\n", capacity, blksz);
1489f6570871SSergey Temerkhanov dev_desc->lba = capacity;
1490f6570871SSergey Temerkhanov dev_desc->blksz = blksz;
14910472fbfdSEgbert Eich dev_desc->log2blksz = LOG2(dev_desc->blksz);
1492affae2bfSwdenk dev_desc->type = perq;
1493ceb4972aSVivek Gautam debug(" address %d\n", dev_desc->target);
1494affae2bfSwdenk
1495affae2bfSwdenk return 1;
1496affae2bfSwdenk }
1497acf277afSSimon Glass
1498fd09c205SSven Schwermer #if CONFIG_IS_ENABLED(DM_USB)
1499acf277afSSimon Glass
usb_mass_storage_probe(struct udevice * dev)1500acf277afSSimon Glass static int usb_mass_storage_probe(struct udevice *dev)
1501acf277afSSimon Glass {
1502bcbe3d15SSimon Glass struct usb_device *udev = dev_get_parent_priv(dev);
1503acf277afSSimon Glass int ret;
1504acf277afSSimon Glass
1505acf277afSSimon Glass usb_disable_asynch(1); /* asynch transfer not allowed */
1506acf277afSSimon Glass ret = usb_stor_probe_device(udev);
1507acf277afSSimon Glass usb_disable_asynch(0); /* asynch transfer allowed */
1508acf277afSSimon Glass
1509acf277afSSimon Glass return ret;
1510acf277afSSimon Glass }
1511acf277afSSimon Glass
1512acf277afSSimon Glass static const struct udevice_id usb_mass_storage_ids[] = {
1513acf277afSSimon Glass { .compatible = "usb-mass-storage" },
1514acf277afSSimon Glass { }
1515acf277afSSimon Glass };
1516acf277afSSimon Glass
1517acf277afSSimon Glass U_BOOT_DRIVER(usb_mass_storage) = {
1518acf277afSSimon Glass .name = "usb_mass_storage",
1519acf277afSSimon Glass .id = UCLASS_MASS_STORAGE,
1520acf277afSSimon Glass .of_match = usb_mass_storage_ids,
1521acf277afSSimon Glass .probe = usb_mass_storage_probe,
1522*1af9bfd3SSven Schwermer #if CONFIG_IS_ENABLED(BLK)
152307b2b78cSSimon Glass .platdata_auto_alloc_size = sizeof(struct us_data),
152407b2b78cSSimon Glass #endif
1525acf277afSSimon Glass };
1526acf277afSSimon Glass
1527acf277afSSimon Glass UCLASS_DRIVER(usb_mass_storage) = {
1528acf277afSSimon Glass .id = UCLASS_MASS_STORAGE,
1529acf277afSSimon Glass .name = "usb_mass_storage",
1530acf277afSSimon Glass };
1531acf277afSSimon Glass
1532acf277afSSimon Glass static const struct usb_device_id mass_storage_id_table[] = {
1533acf277afSSimon Glass {
1534acf277afSSimon Glass .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS,
1535acf277afSSimon Glass .bInterfaceClass = USB_CLASS_MASS_STORAGE
1536acf277afSSimon Glass },
1537acf277afSSimon Glass { } /* Terminating entry */
1538acf277afSSimon Glass };
1539acf277afSSimon Glass
1540abb59cffSSimon Glass U_BOOT_USB_DEVICE(usb_mass_storage, mass_storage_id_table);
154107b2b78cSSimon Glass #endif
1542acf277afSSimon Glass
1543*1af9bfd3SSven Schwermer #if CONFIG_IS_ENABLED(BLK)
154407b2b78cSSimon Glass static const struct blk_ops usb_storage_ops = {
154507b2b78cSSimon Glass .read = usb_stor_read,
154607b2b78cSSimon Glass .write = usb_stor_write,
154707b2b78cSSimon Glass };
154807b2b78cSSimon Glass
154907b2b78cSSimon Glass U_BOOT_DRIVER(usb_storage_blk) = {
155007b2b78cSSimon Glass .name = "usb_storage_blk",
155107b2b78cSSimon Glass .id = UCLASS_BLK,
155207b2b78cSSimon Glass .ops = &usb_storage_ops,
155307b2b78cSSimon Glass };
1554c0543bf6SSimon Glass #else
1555c0543bf6SSimon Glass U_BOOT_LEGACY_BLK(usb) = {
1556c0543bf6SSimon Glass .if_typename = "usb",
1557c0543bf6SSimon Glass .if_type = IF_TYPE_USB,
1558c0543bf6SSimon Glass .max_devs = USB_MAX_STOR_DEV,
1559c0543bf6SSimon Glass .desc = usb_dev_desc,
1560c0543bf6SSimon Glass };
1561acf277afSSimon Glass #endif
1562