xref: /openbmc/u-boot/common/usb_storage.c (revision 9450ab2b)
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