blob: 774d5bdf54b4be7d56bfe12b5aaf86cc2d5bf248 [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
wdenkaffae2b2002-08-17 09:36:01 +00002/*
Wolfgang Denk6a3d6b02005-08-04 01:14:12 +02003 * Most of this source has been derived from the Linux USB
4 * project:
5 * (c) 1999-2002 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
6 * (c) 2000 David L. Brown, Jr. (usb-storage@davidb.org)
7 * (c) 1999 Michael Gee (michael@linuxspecific.com)
8 * (c) 2000 Yggdrasil Computing, Inc.
9 *
10 *
11 * Adapted for U-Boot:
12 * (C) Copyright 2001 Denis Peter, MPL AG Switzerland
Simon Glassac9774e2015-03-25 12:22:16 -060013 * Driver model conversion:
14 * (C) Copyright 2015 Google, Inc
wdenkaffae2b2002-08-17 09:36:01 +000015 *
wdenkde887eb2003-09-10 18:20:28 +000016 * For BBB support (C) Copyright 2003
Detlev Zundelf1b3f2b2009-05-13 10:54:10 +020017 * Gary Jennejohn, DENX Software Engineering <garyj@denx.de>
wdenkde887eb2003-09-10 18:20:28 +000018 *
Wolfgang Denk6a3d6b02005-08-04 01:14:12 +020019 * BBB support based on /sys/dev/usb/umass.c from
wdenkde887eb2003-09-10 18:20:28 +000020 * FreeBSD.
wdenkaffae2b2002-08-17 09:36:01 +000021 */
22
23/* Note:
24 * Currently only the CBI transport protocoll has been implemented, and it
25 * is only tested with a TEAC USB Floppy. Other Massstorages with CBI or CB
26 * transport protocoll may work as well.
27 */
wdenkde887eb2003-09-10 18:20:28 +000028/*
29 * New Note:
30 * Support for USB Mass Storage Devices (BBB) has been added. It has
31 * only been tested with USB memory sticks.
wdenkde887eb2003-09-10 18:20:28 +000032 */
wdenkaffae2b2002-08-17 09:36:01 +000033
34
wdenkaffae2b2002-08-17 09:36:01 +000035#include <common.h>
Simon Glass655306c2020-05-10 11:39:58 -060036#include <blk.h>
Simon Glasse1917ef2022-04-24 23:31:23 -060037#include <bootdev.h>
wdenkaffae2b2002-08-17 09:36:01 +000038#include <command.h>
Simon Glassac9774e2015-03-25 12:22:16 -060039#include <dm.h>
Simon Glassdf7d34f2015-03-25 12:22:15 -060040#include <errno.h>
Simon Glass0f2af882020-05-10 11:40:05 -060041#include <log.h>
Simon Glass332a9b62015-03-25 12:22:14 -060042#include <mapmem.h>
Simon Glass2dd337a2015-09-02 17:24:58 -060043#include <memalign.h>
Christian Eggers4e0e8d02008-05-21 22:12:00 +020044#include <asm/byteorder.h>
Simon Glass274e0b02020-05-10 11:39:56 -060045#include <asm/cache.h>
wdenkaffae2b2002-08-17 09:36:01 +000046#include <asm/processor.h>
Simon Glassac9774e2015-03-25 12:22:16 -060047#include <dm/device-internal.h>
Simon Glass01f5be92016-02-29 15:25:58 -070048#include <dm/lists.h>
Simon Glassdbd79542020-05-10 11:40:11 -060049#include <linux/delay.h>
wdenkaffae2b2002-08-17 09:36:01 +000050
Grant Likelyffc2dd72007-02-20 09:04:34 +010051#include <part.h>
wdenkaffae2b2002-08-17 09:36:01 +000052#include <usb.h>
53
wdenk5f495752004-02-26 23:46:20 +000054#undef BBB_COMDAT_TRACE
55#undef BBB_XPORT_TRACE
wdenkaffae2b2002-08-17 09:36:01 +000056
wdenkaffae2b2002-08-17 09:36:01 +000057#include <scsi.h>
58/* direction table -- this indicates the direction of the data
59 * transfer for each command code -- a 1 indicates input
60 */
Mike Frysinger165522b2010-10-20 07:16:04 -040061static const unsigned char us_direction[256/8] = {
wdenkaffae2b2002-08-17 09:36:01 +000062 0x28, 0x81, 0x14, 0x14, 0x20, 0x01, 0x90, 0x77,
63 0x0C, 0x20, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00,
64 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01,
65 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
66};
67#define US_DIRECTION(x) ((us_direction[x>>3] >> (x & 7)) & 1)
68
Simon Glass5fb559d2017-06-14 21:28:30 -060069static struct scsi_cmd usb_ccb __aligned(ARCH_DMA_MINALIGN);
Michael Trimarchi956a4352008-12-10 15:52:06 +010070static __u32 CBWTag;
wdenkde887eb2003-09-10 18:20:28 +000071
Michael Trimarchi956a4352008-12-10 15:52:06 +010072static int usb_max_devs; /* number of highest available usb device */
wdenkaffae2b2002-08-17 09:36:01 +000073
Sven Schwermerc58ff202018-11-21 08:43:57 +010074#if !CONFIG_IS_ENABLED(BLK)
Simon Glasse3394752016-02-29 15:25:34 -070075static struct blk_desc usb_dev_desc[USB_MAX_STOR_DEV];
Simon Glass01f5be92016-02-29 15:25:58 -070076#endif
wdenkaffae2b2002-08-17 09:36:01 +000077
78struct us_data;
Simon Glass5fb559d2017-06-14 21:28:30 -060079typedef int (*trans_cmnd)(struct scsi_cmd *cb, struct us_data *data);
Michael Trimarchi956a4352008-12-10 15:52:06 +010080typedef int (*trans_reset)(struct us_data *data);
wdenkaffae2b2002-08-17 09:36:01 +000081
82struct us_data {
Michael Trimarchi956a4352008-12-10 15:52:06 +010083 struct usb_device *pusb_dev; /* this usb_device */
84
85 unsigned int flags; /* from filter initially */
Benoît Thébaudeaufbf909a2012-08-10 18:27:11 +020086# define USB_READY (1 << 0)
Michael Trimarchi956a4352008-12-10 15:52:06 +010087 unsigned char ifnum; /* interface number */
88 unsigned char ep_in; /* in endpoint */
89 unsigned char ep_out; /* out ....... */
90 unsigned char ep_int; /* interrupt . */
91 unsigned char subclass; /* as in overview */
92 unsigned char protocol; /* .............. */
93 unsigned char attention_done; /* force attn on first cmd */
94 unsigned short ip_data; /* interrupt data */
95 int action; /* what to do */
96 int ip_wanted; /* needed */
97 int *irq_handle; /* for USB int requests */
Wolfgang Denk62fb2b42021-09-27 17:42:39 +020098 unsigned int irqpipe; /* pipe for release_irq */
Michael Trimarchi956a4352008-12-10 15:52:06 +010099 unsigned char irqmaxp; /* max packed for irq Pipe */
100 unsigned char irqinterval; /* Intervall for IRQ Pipe */
Simon Glass5fb559d2017-06-14 21:28:30 -0600101 struct scsi_cmd *srb; /* current srb */
Michael Trimarchi956a4352008-12-10 15:52:06 +0100102 trans_reset transport_reset; /* reset routine */
103 trans_cmnd transport; /* transport routine */
Bin Mengf6e373e2017-09-07 06:13:20 -0700104 unsigned short max_xfer_blk; /* maximum transfer blocks */
Hector Martin7b3d10d2023-10-29 16:23:30 +0900105 bool cmd12; /* use 12-byte commands (RBC/UFI) */
wdenkaffae2b2002-08-17 09:36:01 +0000106};
107
Sven Schwermerc58ff202018-11-21 08:43:57 +0100108#if !CONFIG_IS_ENABLED(BLK)
wdenkaffae2b2002-08-17 09:36:01 +0000109static struct us_data usb_stor[USB_MAX_STOR_DEV];
Simon Glass01f5be92016-02-29 15:25:58 -0700110#endif
wdenkaffae2b2002-08-17 09:36:01 +0000111
wdenk5f495752004-02-26 23:46:20 +0000112#define USB_STOR_TRANSPORT_GOOD 0
wdenkaffae2b2002-08-17 09:36:01 +0000113#define USB_STOR_TRANSPORT_FAILED -1
114#define USB_STOR_TRANSPORT_ERROR -2
115
Michael Trimarchi956a4352008-12-10 15:52:06 +0100116int usb_stor_get_info(struct usb_device *dev, struct us_data *us,
Simon Glasse3394752016-02-29 15:25:34 -0700117 struct blk_desc *dev_desc);
Michael Trimarchi956a4352008-12-10 15:52:06 +0100118int usb_storage_probe(struct usb_device *dev, unsigned int ifnum,
119 struct us_data *ss);
Sven Schwermerc58ff202018-11-21 08:43:57 +0100120#if CONFIG_IS_ENABLED(BLK)
Simon Glass01f5be92016-02-29 15:25:58 -0700121static unsigned long usb_stor_read(struct udevice *dev, lbaint_t blknr,
122 lbaint_t blkcnt, void *buffer);
123static unsigned long usb_stor_write(struct udevice *dev, lbaint_t blknr,
124 lbaint_t blkcnt, const void *buffer);
125#else
Simon Glasse3394752016-02-29 15:25:34 -0700126static unsigned long usb_stor_read(struct blk_desc *block_dev, lbaint_t blknr,
Stephen Warrene73f2962015-12-07 11:38:48 -0700127 lbaint_t blkcnt, void *buffer);
Simon Glasse3394752016-02-29 15:25:34 -0700128static unsigned long usb_stor_write(struct blk_desc *block_dev, lbaint_t blknr,
Stephen Warrene73f2962015-12-07 11:38:48 -0700129 lbaint_t blkcnt, const void *buffer);
Simon Glass01f5be92016-02-29 15:25:58 -0700130#endif
wdenkaffae2b2002-08-17 09:36:01 +0000131void uhci_show_temp_int_td(void);
132
Kim Phillipsb052b602012-10-29 13:34:32 +0000133static void usb_show_progress(void)
wdenkaffae2b2002-08-17 09:36:01 +0000134{
Wolfgang Denk660e9a42010-07-19 11:36:59 +0200135 debug(".");
wdenkaffae2b2002-08-17 09:36:01 +0000136}
137
Michael Trimarchi956a4352008-12-10 15:52:06 +0100138/*******************************************************************************
Wolfgang Denkc7a4f7d2005-07-21 11:57:57 +0200139 * show info on storage devices; 'usb start/init' must be invoked earlier
140 * as we only retrieve structures populated during devices initialization
141 */
Aras Vaichas7ede1862008-03-25 12:09:07 +1100142int usb_stor_info(void)
Wolfgang Denkc7a4f7d2005-07-21 11:57:57 +0200143{
Simon Glass99e598e2016-02-29 15:25:54 -0700144 int count = 0;
Sven Schwermerc58ff202018-11-21 08:43:57 +0100145#if CONFIG_IS_ENABLED(BLK)
Simon Glass01f5be92016-02-29 15:25:58 -0700146 struct udevice *dev;
147
Simon Glassdbfa32c2022-08-11 19:34:59 -0600148 for (blk_first_device(UCLASS_USB, &dev);
Simon Glass01f5be92016-02-29 15:25:58 -0700149 dev;
150 blk_next_device(&dev)) {
Simon Glass71fa5b42020-12-03 16:55:18 -0700151 struct blk_desc *desc = dev_get_uclass_plat(dev);
Simon Glass01f5be92016-02-29 15:25:58 -0700152
153 printf(" Device %d: ", desc->devnum);
154 dev_print(desc);
155 count++;
156 }
157#else
Wolfgang Denkc7a4f7d2005-07-21 11:57:57 +0200158 int i;
159
Aras Vaichas7ede1862008-03-25 12:09:07 +1100160 if (usb_max_devs > 0) {
Wolfgang Denkc7a4f7d2005-07-21 11:57:57 +0200161 for (i = 0; i < usb_max_devs; i++) {
Michael Trimarchi956a4352008-12-10 15:52:06 +0100162 printf(" Device %d: ", i);
Wolfgang Denkc7a4f7d2005-07-21 11:57:57 +0200163 dev_print(&usb_dev_desc[i]);
164 }
Markus Klotzbuecher8e2a4862008-03-26 18:26:43 +0100165 return 0;
Aras Vaichas7ede1862008-03-25 12:09:07 +1100166 }
Simon Glass01f5be92016-02-29 15:25:58 -0700167#endif
Simon Glass99e598e2016-02-29 15:25:54 -0700168 if (!count) {
169 printf("No storage devices, perhaps not 'usb start'ed..?\n");
170 return 1;
171 }
172
Simon Glass8c6c0742016-03-16 07:45:44 -0600173 return 0;
Wolfgang Denkc7a4f7d2005-07-21 11:57:57 +0200174}
175
Ludovic Courtès134396c2010-10-05 22:04:26 +0200176static unsigned int usb_get_max_lun(struct us_data *us)
177{
178 int len;
Puneet Saxena6c9bb602012-04-03 14:56:06 +0530179 ALLOC_CACHE_ALIGN_BUFFER(unsigned char, result, 1);
Ludovic Courtès134396c2010-10-05 22:04:26 +0200180 len = usb_control_msg(us->pusb_dev,
181 usb_rcvctrlpipe(us->pusb_dev, 0),
182 US_BBB_GET_MAX_LUN,
183 USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
184 0, us->ifnum,
Puneet Saxena6c9bb602012-04-03 14:56:06 +0530185 result, sizeof(char),
Ludovic Courtès134396c2010-10-05 22:04:26 +0200186 USB_CNTL_TIMEOUT * 5);
Vivek Gautamf94c95d2013-04-12 16:34:33 +0530187 debug("Get Max LUN -> len = %i, result = %i\n", len, (int) *result);
Puneet Saxena6c9bb602012-04-03 14:56:06 +0530188 return (len > 0) ? *result : 0;
Ludovic Courtès134396c2010-10-05 22:04:26 +0200189}
190
Simon Glass99e598e2016-02-29 15:25:54 -0700191static int usb_stor_probe_device(struct usb_device *udev)
Simon Glassdf7d34f2015-03-25 12:22:15 -0600192{
Simon Glass99e598e2016-02-29 15:25:54 -0700193 int lun, max_lun;
Simon Glass01f5be92016-02-29 15:25:58 -0700194
Sven Schwermerc58ff202018-11-21 08:43:57 +0100195#if CONFIG_IS_ENABLED(BLK)
Simon Glass01f5be92016-02-29 15:25:58 -0700196 struct us_data *data;
Simon Glass01f5be92016-02-29 15:25:58 -0700197 int ret;
198#else
Simon Glass99e598e2016-02-29 15:25:54 -0700199 int start;
200
201 if (udev == NULL)
Simon Glassdf7d34f2015-03-25 12:22:15 -0600202 return -ENOENT; /* no more devices available */
Simon Glass01f5be92016-02-29 15:25:58 -0700203#endif
Simon Glassdf7d34f2015-03-25 12:22:15 -0600204
Simon Glass01f5be92016-02-29 15:25:58 -0700205 debug("\n\nProbing for storage\n");
Sven Schwermerc58ff202018-11-21 08:43:57 +0100206#if CONFIG_IS_ENABLED(BLK)
Simon Glass01f5be92016-02-29 15:25:58 -0700207 /*
Simon Glass71fa5b42020-12-03 16:55:18 -0700208 * We store the us_data in the mass storage device's plat. It
Simon Glass01f5be92016-02-29 15:25:58 -0700209 * is shared by all LUNs (block devices) attached to this mass storage
210 * device.
211 */
Simon Glassfa20e932020-12-03 16:55:20 -0700212 data = dev_get_plat(udev->dev);
Simon Glass01f5be92016-02-29 15:25:58 -0700213 if (!usb_storage_probe(udev, 0, data))
214 return 0;
215 max_lun = usb_get_max_lun(data);
216 for (lun = 0; lun <= max_lun; lun++) {
217 struct blk_desc *blkdev;
218 struct udevice *dev;
Simon Glass966b6952016-05-01 11:36:29 -0600219 char str[10];
Simon Glass01f5be92016-02-29 15:25:58 -0700220
Simon Glass966b6952016-05-01 11:36:29 -0600221 snprintf(str, sizeof(str), "lun%d", lun);
222 ret = blk_create_devicef(udev->dev, "usb_storage_blk", str,
Bin Meng2294ecb2023-09-26 16:43:31 +0800223 UCLASS_USB, usb_max_devs,
224 DEFAULT_BLKSZ, 0, &dev);
Simon Glass01f5be92016-02-29 15:25:58 -0700225 if (ret) {
226 debug("Cannot bind driver\n");
227 return ret;
228 }
229
Simon Glass71fa5b42020-12-03 16:55:18 -0700230 blkdev = dev_get_uclass_plat(dev);
Simon Glass01f5be92016-02-29 15:25:58 -0700231 blkdev->target = 0xff;
232 blkdev->lun = lun;
233
234 ret = usb_stor_get_info(udev, data, blkdev);
Bin Mengcbc3da82018-10-15 02:21:07 -0700235 if (ret == 1) {
Simon Glass01f5be92016-02-29 15:25:58 -0700236 usb_max_devs++;
237 debug("%s: Found device %p\n", __func__, udev);
238 } else {
239 debug("usb_stor_get_info: Invalid device\n");
240 ret = device_unbind(dev);
241 if (ret)
242 return ret;
Janne Grunau96c2d112022-11-04 08:38:59 +0100243 continue;
Simon Glass01f5be92016-02-29 15:25:58 -0700244 }
AKASHI Takahirof9c3cc82022-03-08 20:36:40 +0900245
246 ret = blk_probe_or_unbind(dev);
247 if (ret)
248 return ret;
Simon Glasse1917ef2022-04-24 23:31:23 -0600249
Simon Glassb1d581d2023-07-30 11:15:14 -0600250 ret = bootdev_setup_for_sibling_blk(dev, "usb_bootdev");
Simon Glasse1917ef2022-04-24 23:31:23 -0600251 if (ret) {
252 int ret2;
253
254 ret2 = device_unbind(dev);
255 if (ret2)
256 return log_msg_ret("bootdev", ret2);
257 return log_msg_ret("bootdev", ret);
258 }
Simon Glass01f5be92016-02-29 15:25:58 -0700259 }
260#else
Simon Glass6d74d7c2016-02-29 15:25:53 -0700261 /* We don't have space to even probe if we hit the maximum */
262 if (usb_max_devs == USB_MAX_STOR_DEV) {
263 printf("max USB Storage Device reached: %d stopping\n",
264 usb_max_devs);
265 return -ENOSPC;
266 }
267
Simon Glass99e598e2016-02-29 15:25:54 -0700268 if (!usb_storage_probe(udev, 0, &usb_stor[usb_max_devs]))
269 return 0;
Simon Glassdf7d34f2015-03-25 12:22:15 -0600270
Simon Glass99e598e2016-02-29 15:25:54 -0700271 /*
272 * OK, it's a storage device. Iterate over its LUNs and populate
273 * usb_dev_desc'
274 */
275 start = usb_max_devs;
Simon Glassdf7d34f2015-03-25 12:22:15 -0600276
Simon Glass99e598e2016-02-29 15:25:54 -0700277 max_lun = usb_get_max_lun(&usb_stor[usb_max_devs]);
278 for (lun = 0; lun <= max_lun && usb_max_devs < USB_MAX_STOR_DEV;
279 lun++) {
280 struct blk_desc *blkdev;
Simon Glassdf7d34f2015-03-25 12:22:15 -0600281
Simon Glass99e598e2016-02-29 15:25:54 -0700282 blkdev = &usb_dev_desc[usb_max_devs];
283 memset(blkdev, '\0', sizeof(struct blk_desc));
Simon Glassfada3f92022-09-17 09:00:09 -0600284 blkdev->uclass_id = UCLASS_USB;
Simon Glass99e598e2016-02-29 15:25:54 -0700285 blkdev->devnum = usb_max_devs;
286 blkdev->part_type = PART_TYPE_UNKNOWN;
287 blkdev->target = 0xff;
288 blkdev->type = DEV_TYPE_UNKNOWN;
289 blkdev->block_read = usb_stor_read;
290 blkdev->block_write = usb_stor_write;
291 blkdev->lun = lun;
292 blkdev->priv = udev;
293
294 if (usb_stor_get_info(udev, &usb_stor[start],
295 &usb_dev_desc[usb_max_devs]) == 1) {
Simon Glass01f5be92016-02-29 15:25:58 -0700296 debug("partype: %d\n", blkdev->part_type);
297 part_init(blkdev);
298 debug("partype: %d\n", blkdev->part_type);
Simon Glass99e598e2016-02-29 15:25:54 -0700299 usb_max_devs++;
300 debug("%s: Found device %p\n", __func__, udev);
Simon Glassdf7d34f2015-03-25 12:22:15 -0600301 }
302 }
Simon Glass01f5be92016-02-29 15:25:58 -0700303#endif
Simon Glassdf7d34f2015-03-25 12:22:15 -0600304
Simon Glassdf7d34f2015-03-25 12:22:15 -0600305 return 0;
306}
307
308void usb_stor_reset(void)
309{
310 usb_max_devs = 0;
311}
312
Michael Trimarchi956a4352008-12-10 15:52:06 +0100313/*******************************************************************************
Wolfgang Denkc7a4f7d2005-07-21 11:57:57 +0200314 * scan the usb and reports device info
wdenkaffae2b2002-08-17 09:36:01 +0000315 * to the user if mode = 1
316 * returns current device or -1 if no
317 */
318int usb_stor_scan(int mode)
319{
Michael Trimarchi956a4352008-12-10 15:52:06 +0100320 if (mode == 1)
Lucas Stache6d33452012-09-26 00:14:36 +0200321 printf(" scanning usb for storage devices... ");
Michael Trimarchi956a4352008-12-10 15:52:06 +0100322
Sven Schwermer8a3cb9f12018-11-21 08:43:56 +0100323#if !CONFIG_IS_ENABLED(DM_USB)
Michal Simekcd8f86f2016-12-21 09:35:08 +0100324 unsigned char i;
325
wdenkaffae2b2002-08-17 09:36:01 +0000326 usb_disable_asynch(1); /* asynch transfer not allowed */
327
Simon Glassdf7d34f2015-03-25 12:22:15 -0600328 usb_stor_reset();
Michael Trimarchi956a4352008-12-10 15:52:06 +0100329 for (i = 0; i < USB_MAX_DEVICE; i++) {
Simon Glassdf7d34f2015-03-25 12:22:15 -0600330 struct usb_device *dev;
331
Michael Trimarchi956a4352008-12-10 15:52:06 +0100332 dev = usb_get_dev_index(i); /* get device */
Vivek Gautamf94c95d2013-04-12 16:34:33 +0530333 debug("i=%d\n", i);
Simon Glassdf7d34f2015-03-25 12:22:15 -0600334 if (usb_stor_probe_device(dev))
wdenkaffae2b2002-08-17 09:36:01 +0000335 break;
wdenkaffae2b2002-08-17 09:36:01 +0000336 } /* for */
Wolfgang Denkd06ce5d2005-08-02 17:06:17 +0200337
wdenkaffae2b2002-08-17 09:36:01 +0000338 usb_disable_asynch(0); /* asynch transfer allowed */
Michal Simekcd8f86f2016-12-21 09:35:08 +0100339#endif
Wolfgang Denkc7a4f7d2005-07-21 11:57:57 +0200340 printf("%d Storage Device(s) found\n", usb_max_devs);
Michael Trimarchi956a4352008-12-10 15:52:06 +0100341 if (usb_max_devs > 0)
wdenkaffae2b2002-08-17 09:36:01 +0000342 return 0;
Michael Trimarchi956a4352008-12-10 15:52:06 +0100343 return -1;
wdenkaffae2b2002-08-17 09:36:01 +0000344}
345
346static int usb_stor_irq(struct usb_device *dev)
347{
348 struct us_data *us;
Michael Trimarchi956a4352008-12-10 15:52:06 +0100349 us = (struct us_data *)dev->privptr;
wdenkaffae2b2002-08-17 09:36:01 +0000350
Michael Trimarchi956a4352008-12-10 15:52:06 +0100351 if (us->ip_wanted)
352 us->ip_wanted = 0;
wdenkaffae2b2002-08-17 09:36:01 +0000353 return 0;
354}
355
356
Vivek Gautamf94c95d2013-04-12 16:34:33 +0530357#ifdef DEBUG
wdenkaffae2b2002-08-17 09:36:01 +0000358
Simon Glass5fb559d2017-06-14 21:28:30 -0600359static void usb_show_srb(struct scsi_cmd *pccb)
wdenkaffae2b2002-08-17 09:36:01 +0000360{
361 int i;
Michael Trimarchi956a4352008-12-10 15:52:06 +0100362 printf("SRB: len %d datalen 0x%lX\n ", pccb->cmdlen, pccb->datalen);
Hector Martin7b3d10d2023-10-29 16:23:30 +0900363 for (i = 0; i < pccb->cmdlen; i++)
Michael Trimarchi956a4352008-12-10 15:52:06 +0100364 printf("%02X ", pccb->cmd[i]);
wdenkaffae2b2002-08-17 09:36:01 +0000365 printf("\n");
366}
367
368static void display_int_status(unsigned long tmp)
369{
370 printf("Status: %s %s %s %s %s %s %s\n",
371 (tmp & USB_ST_ACTIVE) ? "Active" : "",
372 (tmp & USB_ST_STALLED) ? "Stalled" : "",
373 (tmp & USB_ST_BUF_ERR) ? "Buffer Error" : "",
374 (tmp & USB_ST_BABBLE_DET) ? "Babble Det" : "",
375 (tmp & USB_ST_NAK_REC) ? "NAKed" : "",
376 (tmp & USB_ST_CRC_ERR) ? "CRC Error" : "",
377 (tmp & USB_ST_BIT_ERR) ? "Bitstuff Error" : "");
378}
379#endif
380/***********************************************************************
381 * Data transfer routines
382 ***********************************************************************/
383
384static int us_one_transfer(struct us_data *us, int pipe, char *buf, int length)
385{
386 int max_size;
387 int this_xfer;
388 int result;
389 int partial;
390 int maxtry;
391 int stat;
392
393 /* determine the maximum packet size for these transfers */
394 max_size = usb_maxpacket(us->pusb_dev, pipe) * 16;
395
396 /* while we have data left to transfer */
397 while (length) {
398
399 /* calculate how long this will be -- maximum or a remainder */
400 this_xfer = length > max_size ? max_size : length;
401 length -= this_xfer;
402
403 /* setup the retry counter */
404 maxtry = 10;
405
406 /* set up the transfer loop */
407 do {
408 /* transfer the data */
Simon Glass332a9b62015-03-25 12:22:14 -0600409 debug("Bulk xfer 0x%lx(%d) try #%d\n",
410 (ulong)map_to_sysmem(buf), this_xfer,
411 11 - maxtry);
wdenkaffae2b2002-08-17 09:36:01 +0000412 result = usb_bulk_msg(us->pusb_dev, pipe, buf,
Michael Trimarchi956a4352008-12-10 15:52:06 +0100413 this_xfer, &partial,
414 USB_CNTL_TIMEOUT * 5);
Vivek Gautamf94c95d2013-04-12 16:34:33 +0530415 debug("bulk_msg returned %d xferred %d/%d\n",
416 result, partial, this_xfer);
Michael Trimarchi956a4352008-12-10 15:52:06 +0100417 if (us->pusb_dev->status != 0) {
418 /* if we stall, we need to clear it before
419 * we go on
420 */
Vivek Gautamf94c95d2013-04-12 16:34:33 +0530421#ifdef DEBUG
wdenkaffae2b2002-08-17 09:36:01 +0000422 display_int_status(us->pusb_dev->status);
423#endif
424 if (us->pusb_dev->status & USB_ST_STALLED) {
Vivek Gautamf94c95d2013-04-12 16:34:33 +0530425 debug("stalled ->clearing endpoint" \
426 "halt for pipe 0x%x\n", pipe);
wdenkaffae2b2002-08-17 09:36:01 +0000427 stat = us->pusb_dev->status;
428 usb_clear_halt(us->pusb_dev, pipe);
Michael Trimarchi956a4352008-12-10 15:52:06 +0100429 us->pusb_dev->status = stat;
430 if (this_xfer == partial) {
Vivek Gautamf94c95d2013-04-12 16:34:33 +0530431 debug("bulk transferred" \
432 "with error %lX," \
433 " but data ok\n",
434 us->pusb_dev->status);
wdenkaffae2b2002-08-17 09:36:01 +0000435 return 0;
436 }
437 else
438 return result;
439 }
440 if (us->pusb_dev->status & USB_ST_NAK_REC) {
Vivek Gautamf94c95d2013-04-12 16:34:33 +0530441 debug("Device NAKed bulk_msg\n");
wdenkaffae2b2002-08-17 09:36:01 +0000442 return result;
443 }
Vivek Gautamf94c95d2013-04-12 16:34:33 +0530444 debug("bulk transferred with error");
Michael Trimarchi956a4352008-12-10 15:52:06 +0100445 if (this_xfer == partial) {
Vivek Gautamf94c95d2013-04-12 16:34:33 +0530446 debug(" %ld, but data ok\n",
447 us->pusb_dev->status);
wdenkaffae2b2002-08-17 09:36:01 +0000448 return 0;
449 }
450 /* if our try counter reaches 0, bail out */
Michal Simekcfd8a6e2020-12-01 14:02:58 +0100451 debug(" %ld, data %d\n",
452 us->pusb_dev->status, partial);
wdenkaffae2b2002-08-17 09:36:01 +0000453 if (!maxtry--)
454 return result;
455 }
456 /* update to show what data was transferred */
457 this_xfer -= partial;
458 buf += partial;
459 /* continue until this transfer is done */
Michael Trimarchi956a4352008-12-10 15:52:06 +0100460 } while (this_xfer);
wdenkaffae2b2002-08-17 09:36:01 +0000461 }
462
463 /* if we get here, we're done and successful */
464 return 0;
465}
466
wdenkde887eb2003-09-10 18:20:28 +0000467static int usb_stor_BBB_reset(struct us_data *us)
468{
469 int result;
470 unsigned int pipe;
471
472 /*
473 * Reset recovery (5.3.4 in Universal Serial Bus Mass Storage Class)
474 *
475 * For Reset Recovery the host shall issue in the following order:
476 * a) a Bulk-Only Mass Storage Reset
477 * b) a Clear Feature HALT to the Bulk-In endpoint
478 * c) a Clear Feature HALT to the Bulk-Out endpoint
479 *
480 * This is done in 3 steps.
481 *
482 * If the reset doesn't succeed, the device should be port reset.
483 *
484 * This comment stolen from FreeBSD's /sys/dev/usb/umass.c.
485 */
Vivek Gautamf94c95d2013-04-12 16:34:33 +0530486 debug("BBB_reset\n");
Michael Trimarchi956a4352008-12-10 15:52:06 +0100487 result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev, 0),
488 US_BBB_RESET,
489 USB_TYPE_CLASS | USB_RECIP_INTERFACE,
Kim Phillipsb052b602012-10-29 13:34:32 +0000490 0, us->ifnum, NULL, 0, USB_CNTL_TIMEOUT * 5);
Wolfgang Denkc7a4f7d2005-07-21 11:57:57 +0200491
Michael Trimarchi956a4352008-12-10 15:52:06 +0100492 if ((result < 0) && (us->pusb_dev->status & USB_ST_STALLED)) {
Vivek Gautamf94c95d2013-04-12 16:34:33 +0530493 debug("RESET:stall\n");
wdenkde887eb2003-09-10 18:20:28 +0000494 return -1;
495 }
Wolfgang Denkc7a4f7d2005-07-21 11:57:57 +0200496
wdenkde887eb2003-09-10 18:20:28 +0000497 /* long wait for reset */
Mike Frysinger60ce19a2012-03-05 13:47:00 +0000498 mdelay(150);
Vivek Gautamf94c95d2013-04-12 16:34:33 +0530499 debug("BBB_reset result %d: status %lX reset\n",
500 result, us->pusb_dev->status);
wdenkde887eb2003-09-10 18:20:28 +0000501 pipe = usb_rcvbulkpipe(us->pusb_dev, us->ep_in);
502 result = usb_clear_halt(us->pusb_dev, pipe);
503 /* long wait for reset */
Mike Frysinger60ce19a2012-03-05 13:47:00 +0000504 mdelay(150);
Vivek Gautamf94c95d2013-04-12 16:34:33 +0530505 debug("BBB_reset result %d: status %lX clearing IN endpoint\n",
506 result, us->pusb_dev->status);
wdenkde887eb2003-09-10 18:20:28 +0000507 /* long wait for reset */
508 pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out);
509 result = usb_clear_halt(us->pusb_dev, pipe);
Mike Frysinger60ce19a2012-03-05 13:47:00 +0000510 mdelay(150);
Vivek Gautamf94c95d2013-04-12 16:34:33 +0530511 debug("BBB_reset result %d: status %lX clearing OUT endpoint\n",
512 result, us->pusb_dev->status);
513 debug("BBB_reset done\n");
wdenkde887eb2003-09-10 18:20:28 +0000514 return 0;
515}
516
wdenkaffae2b2002-08-17 09:36:01 +0000517/* FIXME: this reset function doesn't really reset the port, and it
518 * should. Actually it should probably do what it's doing here, and
519 * reset the port physically
520 */
521static int usb_stor_CB_reset(struct us_data *us)
522{
523 unsigned char cmd[12];
524 int result;
525
Vivek Gautamf94c95d2013-04-12 16:34:33 +0530526 debug("CB_reset\n");
Michael Trimarchi956a4352008-12-10 15:52:06 +0100527 memset(cmd, 0xff, sizeof(cmd));
wdenkaffae2b2002-08-17 09:36:01 +0000528 cmd[0] = SCSI_SEND_DIAG;
529 cmd[1] = 4;
Michael Trimarchi956a4352008-12-10 15:52:06 +0100530 result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev, 0),
531 US_CBI_ADSC,
532 USB_TYPE_CLASS | USB_RECIP_INTERFACE,
533 0, us->ifnum, cmd, sizeof(cmd),
534 USB_CNTL_TIMEOUT * 5);
wdenkaffae2b2002-08-17 09:36:01 +0000535
536 /* long wait for reset */
Mike Frysinger60ce19a2012-03-05 13:47:00 +0000537 mdelay(1500);
Vivek Gautamf94c95d2013-04-12 16:34:33 +0530538 debug("CB_reset result %d: status %lX clearing endpoint halt\n",
539 result, us->pusb_dev->status);
wdenkaffae2b2002-08-17 09:36:01 +0000540 usb_clear_halt(us->pusb_dev, usb_rcvbulkpipe(us->pusb_dev, us->ep_in));
541 usb_clear_halt(us->pusb_dev, usb_rcvbulkpipe(us->pusb_dev, us->ep_out));
542
Vivek Gautamf94c95d2013-04-12 16:34:33 +0530543 debug("CB_reset done\n");
wdenkaffae2b2002-08-17 09:36:01 +0000544 return 0;
545}
546
wdenkde887eb2003-09-10 18:20:28 +0000547/*
548 * Set up the command for a BBB device. Note that the actual SCSI
549 * command is copied into cbw.CBWCDB.
550 */
Simon Glass5fb559d2017-06-14 21:28:30 -0600551static int usb_stor_BBB_comdat(struct scsi_cmd *srb, struct us_data *us)
wdenkde887eb2003-09-10 18:20:28 +0000552{
553 int result;
554 int actlen;
555 int dir_in;
556 unsigned int pipe;
Simon Glass6f414652015-03-25 12:22:11 -0600557 ALLOC_CACHE_ALIGN_BUFFER(struct umass_bbb_cbw, cbw, 1);
wdenkde887eb2003-09-10 18:20:28 +0000558
559 dir_in = US_DIRECTION(srb->cmd[0]);
560
561#ifdef BBB_COMDAT_TRACE
Vivek Gautam23cbd292013-04-12 16:34:34 +0530562 printf("dir %d lun %d cmdlen %d cmd %p datalen %lu pdata %p\n",
Michael Trimarchi956a4352008-12-10 15:52:06 +0100563 dir_in, srb->lun, srb->cmdlen, srb->cmd, srb->datalen,
564 srb->pdata);
wdenkde887eb2003-09-10 18:20:28 +0000565 if (srb->cmdlen) {
Michael Trimarchi956a4352008-12-10 15:52:06 +0100566 for (result = 0; result < srb->cmdlen; result++)
wdenkde887eb2003-09-10 18:20:28 +0000567 printf("cmd[%d] %#x ", result, srb->cmd[result]);
568 printf("\n");
569 }
570#endif
571 /* sanity checks */
572 if (!(srb->cmdlen <= CBWCDBLENGTH)) {
Vivek Gautamf94c95d2013-04-12 16:34:33 +0530573 debug("usb_stor_BBB_comdat:cmdlen too large\n");
wdenkde887eb2003-09-10 18:20:28 +0000574 return -1;
575 }
576
577 /* always OUT to the ep */
578 pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out);
579
Puneet Saxena6c9bb602012-04-03 14:56:06 +0530580 cbw->dCBWSignature = cpu_to_le32(CBWSIGNATURE);
581 cbw->dCBWTag = cpu_to_le32(CBWTag++);
582 cbw->dCBWDataTransferLength = cpu_to_le32(srb->datalen);
583 cbw->bCBWFlags = (dir_in ? CBWFLAGS_IN : CBWFLAGS_OUT);
584 cbw->bCBWLUN = srb->lun;
585 cbw->bCDBLength = srb->cmdlen;
wdenkde887eb2003-09-10 18:20:28 +0000586 /* copy the command data into the CBW command data buffer */
587 /* DST SRC LEN!!! */
Sergey Temerkhanov57236d52015-04-01 17:18:46 +0300588
Puneet Saxena6c9bb602012-04-03 14:56:06 +0530589 memcpy(cbw->CBWCDB, srb->cmd, srb->cmdlen);
590 result = usb_bulk_msg(us->pusb_dev, pipe, cbw, UMASS_BBB_CBW_SIZE,
Michael Trimarchi956a4352008-12-10 15:52:06 +0100591 &actlen, USB_CNTL_TIMEOUT * 5);
wdenkde887eb2003-09-10 18:20:28 +0000592 if (result < 0)
Vivek Gautamf94c95d2013-04-12 16:34:33 +0530593 debug("usb_stor_BBB_comdat:usb_bulk_msg error\n");
wdenkde887eb2003-09-10 18:20:28 +0000594 return result;
595}
596
wdenkaffae2b2002-08-17 09:36:01 +0000597/* FIXME: we also need a CBI_command which sets up the completion
598 * interrupt, and waits for it
599 */
Simon Glass5fb559d2017-06-14 21:28:30 -0600600static int usb_stor_CB_comdat(struct scsi_cmd *srb, struct us_data *us)
wdenkaffae2b2002-08-17 09:36:01 +0000601{
Wolfgang Denk7fb52662005-10-13 16:45:02 +0200602 int result = 0;
Michael Trimarchi956a4352008-12-10 15:52:06 +0100603 int dir_in, retry;
wdenkaffae2b2002-08-17 09:36:01 +0000604 unsigned int pipe;
605 unsigned long status;
606
Michael Trimarchi956a4352008-12-10 15:52:06 +0100607 retry = 5;
608 dir_in = US_DIRECTION(srb->cmd[0]);
wdenkaffae2b2002-08-17 09:36:01 +0000609
Michael Trimarchi956a4352008-12-10 15:52:06 +0100610 if (dir_in)
611 pipe = usb_rcvbulkpipe(us->pusb_dev, us->ep_in);
612 else
613 pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out);
614
615 while (retry--) {
Vivek Gautamf94c95d2013-04-12 16:34:33 +0530616 debug("CBI gets a command: Try %d\n", 5 - retry);
617#ifdef DEBUG
wdenkaffae2b2002-08-17 09:36:01 +0000618 usb_show_srb(srb);
619#endif
620 /* let's send the command via the control pipe */
Michael Trimarchi956a4352008-12-10 15:52:06 +0100621 result = usb_control_msg(us->pusb_dev,
622 usb_sndctrlpipe(us->pusb_dev , 0),
623 US_CBI_ADSC,
624 USB_TYPE_CLASS | USB_RECIP_INTERFACE,
wdenkaffae2b2002-08-17 09:36:01 +0000625 0, us->ifnum,
Michael Trimarchi956a4352008-12-10 15:52:06 +0100626 srb->cmd, srb->cmdlen,
627 USB_CNTL_TIMEOUT * 5);
Vivek Gautamf94c95d2013-04-12 16:34:33 +0530628 debug("CB_transport: control msg returned %d, status %lX\n",
629 result, us->pusb_dev->status);
wdenkaffae2b2002-08-17 09:36:01 +0000630 /* check the return code for the command */
631 if (result < 0) {
Michael Trimarchi956a4352008-12-10 15:52:06 +0100632 if (us->pusb_dev->status & USB_ST_STALLED) {
633 status = us->pusb_dev->status;
Vivek Gautamf94c95d2013-04-12 16:34:33 +0530634 debug(" stall during command found," \
635 " clear pipe\n");
Michael Trimarchi956a4352008-12-10 15:52:06 +0100636 usb_clear_halt(us->pusb_dev,
637 usb_sndctrlpipe(us->pusb_dev, 0));
638 us->pusb_dev->status = status;
wdenkaffae2b2002-08-17 09:36:01 +0000639 }
Vivek Gautamf94c95d2013-04-12 16:34:33 +0530640 debug(" error during command %02X" \
641 " Stat = %lX\n", srb->cmd[0],
642 us->pusb_dev->status);
wdenkaffae2b2002-08-17 09:36:01 +0000643 return result;
644 }
645 /* transfer the data payload for this command, if one exists*/
646
Vivek Gautamf94c95d2013-04-12 16:34:33 +0530647 debug("CB_transport: control msg returned %d," \
648 " direction is %s to go 0x%lx\n", result,
649 dir_in ? "IN" : "OUT", srb->datalen);
wdenkaffae2b2002-08-17 09:36:01 +0000650 if (srb->datalen) {
Michael Trimarchi956a4352008-12-10 15:52:06 +0100651 result = us_one_transfer(us, pipe, (char *)srb->pdata,
652 srb->datalen);
Vivek Gautamf94c95d2013-04-12 16:34:33 +0530653 debug("CBI attempted to transfer data," \
654 " result is %d status %lX, len %d\n",
655 result, us->pusb_dev->status,
656 us->pusb_dev->act_len);
Michael Trimarchi956a4352008-12-10 15:52:06 +0100657 if (!(us->pusb_dev->status & USB_ST_NAK_REC))
wdenkaffae2b2002-08-17 09:36:01 +0000658 break;
659 } /* if (srb->datalen) */
660 else
661 break;
662 }
663 /* return result */
664
665 return result;
666}
667
668
Simon Glass5fb559d2017-06-14 21:28:30 -0600669static int usb_stor_CBI_get_status(struct scsi_cmd *srb, struct us_data *us)
wdenkaffae2b2002-08-17 09:36:01 +0000670{
671 int timeout;
672
wdenk5f495752004-02-26 23:46:20 +0000673 us->ip_wanted = 1;
Michal Suchanek0089d212019-08-18 10:55:26 +0200674 usb_int_msg(us->pusb_dev, us->irqpipe,
Michal Suchanek1c95b9f2019-08-18 10:55:27 +0200675 (void *)&us->ip_data, us->irqmaxp, us->irqinterval, false);
wdenk5f495752004-02-26 23:46:20 +0000676 timeout = 1000;
677 while (timeout--) {
Sergey Temerkhanov57236d52015-04-01 17:18:46 +0300678 if (us->ip_wanted == 0)
wdenkaffae2b2002-08-17 09:36:01 +0000679 break;
Mike Frysinger60ce19a2012-03-05 13:47:00 +0000680 mdelay(10);
wdenkaffae2b2002-08-17 09:36:01 +0000681 }
682 if (us->ip_wanted) {
Michael Trimarchi956a4352008-12-10 15:52:06 +0100683 printf(" Did not get interrupt on CBI\n");
wdenkaffae2b2002-08-17 09:36:01 +0000684 us->ip_wanted = 0;
685 return USB_STOR_TRANSPORT_ERROR;
686 }
Vagrant Cascadian53d41e62016-03-15 12:16:39 -0700687 debug("Got interrupt data 0x%x, transferred %d status 0x%lX\n",
Vivek Gautamf94c95d2013-04-12 16:34:33 +0530688 us->ip_data, us->pusb_dev->irq_act_len,
689 us->pusb_dev->irq_status);
wdenkaffae2b2002-08-17 09:36:01 +0000690 /* UFI gives us ASC and ASCQ, like a request sense */
691 if (us->subclass == US_SC_UFI) {
692 if (srb->cmd[0] == SCSI_REQ_SENSE ||
693 srb->cmd[0] == SCSI_INQUIRY)
694 return USB_STOR_TRANSPORT_GOOD; /* Good */
wdenk5f495752004-02-26 23:46:20 +0000695 else if (us->ip_data)
696 return USB_STOR_TRANSPORT_FAILED;
wdenkaffae2b2002-08-17 09:36:01 +0000697 else
wdenk5f495752004-02-26 23:46:20 +0000698 return USB_STOR_TRANSPORT_GOOD;
wdenkaffae2b2002-08-17 09:36:01 +0000699 }
700 /* otherwise, we interpret the data normally */
701 switch (us->ip_data) {
wdenk5f495752004-02-26 23:46:20 +0000702 case 0x0001:
703 return USB_STOR_TRANSPORT_GOOD;
704 case 0x0002:
705 return USB_STOR_TRANSPORT_FAILED;
706 default:
707 return USB_STOR_TRANSPORT_ERROR;
708 } /* switch */
wdenkaffae2b2002-08-17 09:36:01 +0000709 return USB_STOR_TRANSPORT_ERROR;
710}
711
712#define USB_TRANSPORT_UNKNOWN_RETRY 5
713#define USB_TRANSPORT_NOT_READY_RETRY 10
714
wdenkde887eb2003-09-10 18:20:28 +0000715/* clear a stall on an endpoint - special for BBB devices */
Kim Phillipsb052b602012-10-29 13:34:32 +0000716static int usb_stor_BBB_clear_endpt_stall(struct us_data *us, __u8 endpt)
wdenkde887eb2003-09-10 18:20:28 +0000717{
wdenkde887eb2003-09-10 18:20:28 +0000718 /* ENDPOINT_HALT = 0, so set value to 0 */
Masahiro Yamada9b70df52016-09-06 22:17:35 +0900719 return usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev, 0),
720 USB_REQ_CLEAR_FEATURE, USB_RECIP_ENDPOINT, 0,
721 endpt, NULL, 0, USB_CNTL_TIMEOUT * 5);
wdenkde887eb2003-09-10 18:20:28 +0000722}
723
Simon Glass5fb559d2017-06-14 21:28:30 -0600724static int usb_stor_BBB_transport(struct scsi_cmd *srb, struct us_data *us)
wdenkde887eb2003-09-10 18:20:28 +0000725{
726 int result, retry;
727 int dir_in;
728 int actlen, data_actlen;
729 unsigned int pipe, pipein, pipeout;
Simon Glass6f414652015-03-25 12:22:11 -0600730 ALLOC_CACHE_ALIGN_BUFFER(struct umass_bbb_csw, csw, 1);
wdenkde887eb2003-09-10 18:20:28 +0000731#ifdef BBB_XPORT_TRACE
732 unsigned char *ptr;
733 int index;
734#endif
735
736 dir_in = US_DIRECTION(srb->cmd[0]);
737
738 /* COMMAND phase */
Vivek Gautamf94c95d2013-04-12 16:34:33 +0530739 debug("COMMAND phase\n");
wdenkde887eb2003-09-10 18:20:28 +0000740 result = usb_stor_BBB_comdat(srb, us);
741 if (result < 0) {
Vivek Gautamf94c95d2013-04-12 16:34:33 +0530742 debug("failed to send CBW status %ld\n",
743 us->pusb_dev->status);
wdenkde887eb2003-09-10 18:20:28 +0000744 usb_stor_BBB_reset(us);
745 return USB_STOR_TRANSPORT_FAILED;
746 }
Benoît Thébaudeaufbf909a2012-08-10 18:27:11 +0200747 if (!(us->flags & USB_READY))
748 mdelay(5);
wdenkde887eb2003-09-10 18:20:28 +0000749 pipein = usb_rcvbulkpipe(us->pusb_dev, us->ep_in);
750 pipeout = usb_sndbulkpipe(us->pusb_dev, us->ep_out);
751 /* DATA phase + error handling */
wdenkde887eb2003-09-10 18:20:28 +0000752 data_actlen = 0;
753 /* no data, go immediately to the STATUS phase */
754 if (srb->datalen == 0)
755 goto st;
Vivek Gautamf94c95d2013-04-12 16:34:33 +0530756 debug("DATA phase\n");
wdenkde887eb2003-09-10 18:20:28 +0000757 if (dir_in)
758 pipe = pipein;
759 else
760 pipe = pipeout;
Sergey Temerkhanov57236d52015-04-01 17:18:46 +0300761
Michael Trimarchi956a4352008-12-10 15:52:06 +0100762 result = usb_bulk_msg(us->pusb_dev, pipe, srb->pdata, srb->datalen,
763 &data_actlen, USB_CNTL_TIMEOUT * 5);
wdenkde887eb2003-09-10 18:20:28 +0000764 /* special handling of STALL in DATA phase */
Michael Trimarchi956a4352008-12-10 15:52:06 +0100765 if ((result < 0) && (us->pusb_dev->status & USB_ST_STALLED)) {
Vivek Gautamf94c95d2013-04-12 16:34:33 +0530766 debug("DATA:stall\n");
wdenkde887eb2003-09-10 18:20:28 +0000767 /* clear the STALL on the endpoint */
Michael Trimarchi956a4352008-12-10 15:52:06 +0100768 result = usb_stor_BBB_clear_endpt_stall(us,
769 dir_in ? us->ep_in : us->ep_out);
wdenkde887eb2003-09-10 18:20:28 +0000770 if (result >= 0)
771 /* continue on to STATUS phase */
772 goto st;
773 }
774 if (result < 0) {
Vivek Gautamf94c95d2013-04-12 16:34:33 +0530775 debug("usb_bulk_msg error status %ld\n",
776 us->pusb_dev->status);
wdenkde887eb2003-09-10 18:20:28 +0000777 usb_stor_BBB_reset(us);
778 return USB_STOR_TRANSPORT_FAILED;
779 }
780#ifdef BBB_XPORT_TRACE
781 for (index = 0; index < data_actlen; index++)
782 printf("pdata[%d] %#x ", index, srb->pdata[index]);
783 printf("\n");
784#endif
785 /* STATUS phase + error handling */
Michael Trimarchi956a4352008-12-10 15:52:06 +0100786st:
wdenkde887eb2003-09-10 18:20:28 +0000787 retry = 0;
Michael Trimarchi956a4352008-12-10 15:52:06 +0100788again:
Vivek Gautamf94c95d2013-04-12 16:34:33 +0530789 debug("STATUS phase\n");
Puneet Saxena6c9bb602012-04-03 14:56:06 +0530790 result = usb_bulk_msg(us->pusb_dev, pipein, csw, UMASS_BBB_CSW_SIZE,
Wolfgang Denkc7a4f7d2005-07-21 11:57:57 +0200791 &actlen, USB_CNTL_TIMEOUT*5);
792
wdenkde887eb2003-09-10 18:20:28 +0000793 /* special handling of STALL in STATUS phase */
Michael Trimarchi956a4352008-12-10 15:52:06 +0100794 if ((result < 0) && (retry < 1) &&
795 (us->pusb_dev->status & USB_ST_STALLED)) {
Vivek Gautamf94c95d2013-04-12 16:34:33 +0530796 debug("STATUS:stall\n");
wdenkde887eb2003-09-10 18:20:28 +0000797 /* clear the STALL on the endpoint */
798 result = usb_stor_BBB_clear_endpt_stall(us, us->ep_in);
799 if (result >= 0 && (retry++ < 1))
800 /* do a retry */
801 goto again;
802 }
803 if (result < 0) {
Vivek Gautamf94c95d2013-04-12 16:34:33 +0530804 debug("usb_bulk_msg error status %ld\n",
805 us->pusb_dev->status);
wdenkde887eb2003-09-10 18:20:28 +0000806 usb_stor_BBB_reset(us);
807 return USB_STOR_TRANSPORT_FAILED;
808 }
809#ifdef BBB_XPORT_TRACE
Puneet Saxena6c9bb602012-04-03 14:56:06 +0530810 ptr = (unsigned char *)csw;
wdenkde887eb2003-09-10 18:20:28 +0000811 for (index = 0; index < UMASS_BBB_CSW_SIZE; index++)
812 printf("ptr[%d] %#x ", index, ptr[index]);
813 printf("\n");
814#endif
815 /* misuse pipe to get the residue */
Puneet Saxena6c9bb602012-04-03 14:56:06 +0530816 pipe = le32_to_cpu(csw->dCSWDataResidue);
wdenkde887eb2003-09-10 18:20:28 +0000817 if (pipe == 0 && srb->datalen != 0 && srb->datalen - data_actlen != 0)
818 pipe = srb->datalen - data_actlen;
Puneet Saxena6c9bb602012-04-03 14:56:06 +0530819 if (CSWSIGNATURE != le32_to_cpu(csw->dCSWSignature)) {
Vivek Gautamf94c95d2013-04-12 16:34:33 +0530820 debug("!CSWSIGNATURE\n");
wdenkde887eb2003-09-10 18:20:28 +0000821 usb_stor_BBB_reset(us);
822 return USB_STOR_TRANSPORT_FAILED;
Puneet Saxena6c9bb602012-04-03 14:56:06 +0530823 } else if ((CBWTag - 1) != le32_to_cpu(csw->dCSWTag)) {
Vivek Gautamf94c95d2013-04-12 16:34:33 +0530824 debug("!Tag\n");
wdenkde887eb2003-09-10 18:20:28 +0000825 usb_stor_BBB_reset(us);
826 return USB_STOR_TRANSPORT_FAILED;
Puneet Saxena6c9bb602012-04-03 14:56:06 +0530827 } else if (csw->bCSWStatus > CSWSTATUS_PHASE) {
Vivek Gautamf94c95d2013-04-12 16:34:33 +0530828 debug(">PHASE\n");
wdenkde887eb2003-09-10 18:20:28 +0000829 usb_stor_BBB_reset(us);
830 return USB_STOR_TRANSPORT_FAILED;
Puneet Saxena6c9bb602012-04-03 14:56:06 +0530831 } else if (csw->bCSWStatus == CSWSTATUS_PHASE) {
Vivek Gautamf94c95d2013-04-12 16:34:33 +0530832 debug("=PHASE\n");
wdenkde887eb2003-09-10 18:20:28 +0000833 usb_stor_BBB_reset(us);
834 return USB_STOR_TRANSPORT_FAILED;
835 } else if (data_actlen > srb->datalen) {
Vivek Gautamf94c95d2013-04-12 16:34:33 +0530836 debug("transferred %dB instead of %ldB\n",
837 data_actlen, srb->datalen);
wdenkde887eb2003-09-10 18:20:28 +0000838 return USB_STOR_TRANSPORT_FAILED;
Puneet Saxena6c9bb602012-04-03 14:56:06 +0530839 } else if (csw->bCSWStatus == CSWSTATUS_FAILED) {
Vivek Gautamf94c95d2013-04-12 16:34:33 +0530840 debug("FAILED\n");
wdenkde887eb2003-09-10 18:20:28 +0000841 return USB_STOR_TRANSPORT_FAILED;
842 }
843
844 return result;
845}
846
Simon Glass5fb559d2017-06-14 21:28:30 -0600847static int usb_stor_CB_transport(struct scsi_cmd *srb, struct us_data *us)
wdenkaffae2b2002-08-17 09:36:01 +0000848{
Michael Trimarchi956a4352008-12-10 15:52:06 +0100849 int result, status;
Simon Glass5fb559d2017-06-14 21:28:30 -0600850 struct scsi_cmd *psrb;
851 struct scsi_cmd reqsrb;
Michael Trimarchi956a4352008-12-10 15:52:06 +0100852 int retry, notready;
wdenkaffae2b2002-08-17 09:36:01 +0000853
Wolfgang Denkdc770c72008-07-14 15:19:07 +0200854 psrb = &reqsrb;
Michael Trimarchi956a4352008-12-10 15:52:06 +0100855 status = USB_STOR_TRANSPORT_GOOD;
856 retry = 0;
857 notready = 0;
wdenkaffae2b2002-08-17 09:36:01 +0000858 /* issue the command */
859do_retry:
Michael Trimarchi956a4352008-12-10 15:52:06 +0100860 result = usb_stor_CB_comdat(srb, us);
Vivek Gautamf94c95d2013-04-12 16:34:33 +0530861 debug("command / Data returned %d, status %lX\n",
862 result, us->pusb_dev->status);
wdenkaffae2b2002-08-17 09:36:01 +0000863 /* if this is an CBI Protocol, get IRQ */
Michael Trimarchi956a4352008-12-10 15:52:06 +0100864 if (us->protocol == US_PR_CBI) {
865 status = usb_stor_CBI_get_status(srb, us);
wdenkaffae2b2002-08-17 09:36:01 +0000866 /* if the status is error, report it */
Michael Trimarchi956a4352008-12-10 15:52:06 +0100867 if (status == USB_STOR_TRANSPORT_ERROR) {
Vivek Gautamf94c95d2013-04-12 16:34:33 +0530868 debug(" USB CBI Command Error\n");
wdenkaffae2b2002-08-17 09:36:01 +0000869 return status;
870 }
Michael Trimarchi956a4352008-12-10 15:52:06 +0100871 srb->sense_buf[12] = (unsigned char)(us->ip_data >> 8);
872 srb->sense_buf[13] = (unsigned char)(us->ip_data & 0xff);
873 if (!us->ip_data) {
874 /* if the status is good, report it */
875 if (status == USB_STOR_TRANSPORT_GOOD) {
Vivek Gautamf94c95d2013-04-12 16:34:33 +0530876 debug(" USB CBI Command Good\n");
wdenkaffae2b2002-08-17 09:36:01 +0000877 return status;
878 }
879 }
880 }
881 /* do we have to issue an auto request? */
882 /* HERE we have to check the result */
Michael Trimarchi956a4352008-12-10 15:52:06 +0100883 if ((result < 0) && !(us->pusb_dev->status & USB_ST_STALLED)) {
Vivek Gautamf94c95d2013-04-12 16:34:33 +0530884 debug("ERROR %lX\n", us->pusb_dev->status);
wdenkaffae2b2002-08-17 09:36:01 +0000885 us->transport_reset(us);
886 return USB_STOR_TRANSPORT_ERROR;
887 }
Michael Trimarchi956a4352008-12-10 15:52:06 +0100888 if ((us->protocol == US_PR_CBI) &&
889 ((srb->cmd[0] == SCSI_REQ_SENSE) ||
890 (srb->cmd[0] == SCSI_INQUIRY))) {
891 /* do not issue an autorequest after request sense */
Vivek Gautamf94c95d2013-04-12 16:34:33 +0530892 debug("No auto request and good\n");
wdenkaffae2b2002-08-17 09:36:01 +0000893 return USB_STOR_TRANSPORT_GOOD;
894 }
895 /* issue an request_sense */
Michael Trimarchi956a4352008-12-10 15:52:06 +0100896 memset(&psrb->cmd[0], 0, 12);
897 psrb->cmd[0] = SCSI_REQ_SENSE;
898 psrb->cmd[1] = srb->lun << 5;
899 psrb->cmd[4] = 18;
900 psrb->datalen = 18;
Wolfgang Denkdc770c72008-07-14 15:19:07 +0200901 psrb->pdata = &srb->sense_buf[0];
Hector Martin7b3d10d2023-10-29 16:23:30 +0900902 psrb->cmdlen = us->cmd12 ? 12 : 6;
wdenkaffae2b2002-08-17 09:36:01 +0000903 /* issue the command */
Michael Trimarchi956a4352008-12-10 15:52:06 +0100904 result = usb_stor_CB_comdat(psrb, us);
Vivek Gautamf94c95d2013-04-12 16:34:33 +0530905 debug("auto request returned %d\n", result);
wdenkaffae2b2002-08-17 09:36:01 +0000906 /* if this is an CBI Protocol, get IRQ */
Michael Trimarchi956a4352008-12-10 15:52:06 +0100907 if (us->protocol == US_PR_CBI)
908 status = usb_stor_CBI_get_status(psrb, us);
909
910 if ((result < 0) && !(us->pusb_dev->status & USB_ST_STALLED)) {
Vivek Gautamf94c95d2013-04-12 16:34:33 +0530911 debug(" AUTO REQUEST ERROR %ld\n",
912 us->pusb_dev->status);
wdenkaffae2b2002-08-17 09:36:01 +0000913 return USB_STOR_TRANSPORT_ERROR;
914 }
Vivek Gautamf94c95d2013-04-12 16:34:33 +0530915 debug("autorequest returned 0x%02X 0x%02X 0x%02X 0x%02X\n",
916 srb->sense_buf[0], srb->sense_buf[2],
917 srb->sense_buf[12], srb->sense_buf[13]);
wdenkaffae2b2002-08-17 09:36:01 +0000918 /* Check the auto request result */
Michael Trimarchi956a4352008-12-10 15:52:06 +0100919 if ((srb->sense_buf[2] == 0) &&
920 (srb->sense_buf[12] == 0) &&
921 (srb->sense_buf[13] == 0)) {
922 /* ok, no sense */
wdenkaffae2b2002-08-17 09:36:01 +0000923 return USB_STOR_TRANSPORT_GOOD;
Michael Trimarchi956a4352008-12-10 15:52:06 +0100924 }
925
wdenkaffae2b2002-08-17 09:36:01 +0000926 /* Check the auto request result */
Michael Trimarchi956a4352008-12-10 15:52:06 +0100927 switch (srb->sense_buf[2]) {
928 case 0x01:
929 /* Recovered Error */
wdenkde887eb2003-09-10 18:20:28 +0000930 return USB_STOR_TRANSPORT_GOOD;
wdenk5f495752004-02-26 23:46:20 +0000931 break;
Michael Trimarchi956a4352008-12-10 15:52:06 +0100932 case 0x02:
933 /* Not Ready */
934 if (notready++ > USB_TRANSPORT_NOT_READY_RETRY) {
935 printf("cmd 0x%02X returned 0x%02X 0x%02X 0x%02X"
936 " 0x%02X (NOT READY)\n", srb->cmd[0],
937 srb->sense_buf[0], srb->sense_buf[2],
938 srb->sense_buf[12], srb->sense_buf[13]);
wdenkde887eb2003-09-10 18:20:28 +0000939 return USB_STOR_TRANSPORT_FAILED;
940 } else {
Mike Frysinger60ce19a2012-03-05 13:47:00 +0000941 mdelay(100);
wdenkde887eb2003-09-10 18:20:28 +0000942 goto do_retry;
943 }
944 break;
945 default:
Michael Trimarchi956a4352008-12-10 15:52:06 +0100946 if (retry++ > USB_TRANSPORT_UNKNOWN_RETRY) {
947 printf("cmd 0x%02X returned 0x%02X 0x%02X 0x%02X"
948 " 0x%02X\n", srb->cmd[0], srb->sense_buf[0],
949 srb->sense_buf[2], srb->sense_buf[12],
950 srb->sense_buf[13]);
wdenkde887eb2003-09-10 18:20:28 +0000951 return USB_STOR_TRANSPORT_FAILED;
Michael Trimarchi956a4352008-12-10 15:52:06 +0100952 } else
wdenkde887eb2003-09-10 18:20:28 +0000953 goto do_retry;
wdenkde887eb2003-09-10 18:20:28 +0000954 break;
wdenkaffae2b2002-08-17 09:36:01 +0000955 }
956 return USB_STOR_TRANSPORT_FAILED;
957}
958
Bin Meng9f447112017-09-07 06:13:21 -0700959static void usb_stor_set_max_xfer_blk(struct usb_device *udev,
960 struct us_data *us)
Bin Mengf6e373e2017-09-07 06:13:20 -0700961{
Bin Mengf6e373e2017-09-07 06:13:20 -0700962 /*
Marek Vasutcc93ffd2019-09-16 00:16:25 +0200963 * Limit the total size of a transfer to 120 KB.
964 *
965 * Some devices are known to choke with anything larger. It seems like
966 * the problem stems from the fact that original IDE controllers had
967 * only an 8-bit register to hold the number of sectors in one transfer
968 * and even those couldn't handle a full 256 sectors.
969 *
970 * Because we want to make sure we interoperate with as many devices as
971 * possible, we will maintain a 240 sector transfer size limit for USB
972 * Mass Storage devices.
973 *
974 * Tests show that other operating have similar limits with Microsoft
975 * Windows 7 limiting transfers to 128 sectors for both USB2 and USB3
976 * and Apple Mac OS X 10.11 limiting transfers to 256 sectors for USB2
977 * and 2048 for USB3 devices.
Bin Mengf6e373e2017-09-07 06:13:20 -0700978 */
Marek Vasutcc93ffd2019-09-16 00:16:25 +0200979 unsigned short blk = 240;
980
981#if CONFIG_IS_ENABLED(DM_USB)
982 size_t size;
983 int ret;
984
Bin Meng9f447112017-09-07 06:13:21 -0700985 ret = usb_get_max_xfer_size(udev, (size_t *)&size);
Marek Vasutcc93ffd2019-09-16 00:16:25 +0200986 if ((ret >= 0) && (size < blk * 512))
Bin Meng9f447112017-09-07 06:13:21 -0700987 blk = size / 512;
Bin Meng9f447112017-09-07 06:13:21 -0700988#endif
Bin Mengf6e373e2017-09-07 06:13:20 -0700989
990 us->max_xfer_blk = blk;
991}
wdenkaffae2b2002-08-17 09:36:01 +0000992
Simon Glass5fb559d2017-06-14 21:28:30 -0600993static int usb_inquiry(struct scsi_cmd *srb, struct us_data *ss)
wdenkaffae2b2002-08-17 09:36:01 +0000994{
Michael Trimarchi956a4352008-12-10 15:52:06 +0100995 int retry, i;
996 retry = 5;
wdenkaffae2b2002-08-17 09:36:01 +0000997 do {
Michael Trimarchi956a4352008-12-10 15:52:06 +0100998 memset(&srb->cmd[0], 0, 12);
999 srb->cmd[0] = SCSI_INQUIRY;
Ludovic Courtès134396c2010-10-05 22:04:26 +02001000 srb->cmd[1] = srb->lun << 5;
Michael Trimarchi956a4352008-12-10 15:52:06 +01001001 srb->cmd[4] = 36;
1002 srb->datalen = 36;
Hector Martin7b3d10d2023-10-29 16:23:30 +09001003 srb->cmdlen = ss->cmd12 ? 12 : 6;
Michael Trimarchi956a4352008-12-10 15:52:06 +01001004 i = ss->transport(srb, ss);
Vivek Gautamf94c95d2013-04-12 16:34:33 +05301005 debug("inquiry returns %d\n", i);
Michael Trimarchi956a4352008-12-10 15:52:06 +01001006 if (i == 0)
wdenkaffae2b2002-08-17 09:36:01 +00001007 break;
Kim B. Heino3d42b8a2010-03-12 10:07:00 +02001008 } while (--retry);
wdenkde887eb2003-09-10 18:20:28 +00001009
Michael Trimarchi956a4352008-12-10 15:52:06 +01001010 if (!retry) {
wdenkaffae2b2002-08-17 09:36:01 +00001011 printf("error in inquiry\n");
1012 return -1;
1013 }
1014 return 0;
1015}
1016
Simon Glass5fb559d2017-06-14 21:28:30 -06001017static int usb_request_sense(struct scsi_cmd *srb, struct us_data *ss)
wdenkaffae2b2002-08-17 09:36:01 +00001018{
1019 char *ptr;
wdenk5f495752004-02-26 23:46:20 +00001020
Michael Trimarchi956a4352008-12-10 15:52:06 +01001021 ptr = (char *)srb->pdata;
1022 memset(&srb->cmd[0], 0, 12);
1023 srb->cmd[0] = SCSI_REQ_SENSE;
Ludovic Courtès134396c2010-10-05 22:04:26 +02001024 srb->cmd[1] = srb->lun << 5;
Michael Trimarchi956a4352008-12-10 15:52:06 +01001025 srb->cmd[4] = 18;
1026 srb->datalen = 18;
Wolfgang Denkdc770c72008-07-14 15:19:07 +02001027 srb->pdata = &srb->sense_buf[0];
Hector Martin7b3d10d2023-10-29 16:23:30 +09001028 srb->cmdlen = ss->cmd12 ? 12 : 6;
Michael Trimarchi956a4352008-12-10 15:52:06 +01001029 ss->transport(srb, ss);
Vivek Gautamf94c95d2013-04-12 16:34:33 +05301030 debug("Request Sense returned %02X %02X %02X\n",
1031 srb->sense_buf[2], srb->sense_buf[12],
1032 srb->sense_buf[13]);
Michael Trimarchi956a4352008-12-10 15:52:06 +01001033 srb->pdata = (uchar *)ptr;
wdenkaffae2b2002-08-17 09:36:01 +00001034 return 0;
1035}
1036
Simon Glass5fb559d2017-06-14 21:28:30 -06001037static int usb_test_unit_ready(struct scsi_cmd *srb, struct us_data *ss)
wdenkaffae2b2002-08-17 09:36:01 +00001038{
Wolfgang Denkc7a4f7d2005-07-21 11:57:57 +02001039 int retries = 10;
wdenkde887eb2003-09-10 18:20:28 +00001040
wdenkaffae2b2002-08-17 09:36:01 +00001041 do {
Michael Trimarchi956a4352008-12-10 15:52:06 +01001042 memset(&srb->cmd[0], 0, 12);
1043 srb->cmd[0] = SCSI_TST_U_RDY;
Ludovic Courtès134396c2010-10-05 22:04:26 +02001044 srb->cmd[1] = srb->lun << 5;
Michael Trimarchi956a4352008-12-10 15:52:06 +01001045 srb->datalen = 0;
Hector Martin7b3d10d2023-10-29 16:23:30 +09001046 srb->cmdlen = ss->cmd12 ? 12 : 6;
Benoît Thébaudeaufbf909a2012-08-10 18:27:11 +02001047 if (ss->transport(srb, ss) == USB_STOR_TRANSPORT_GOOD) {
1048 ss->flags |= USB_READY;
wdenkaffae2b2002-08-17 09:36:01 +00001049 return 0;
Benoît Thébaudeaufbf909a2012-08-10 18:27:11 +02001050 }
Michael Trimarchi956a4352008-12-10 15:52:06 +01001051 usb_request_sense(srb, ss);
Vincent Palatin976b3232012-12-12 17:55:29 -08001052 /*
1053 * Check the Key Code Qualifier, if it matches
1054 * "Not Ready - medium not present"
1055 * (the sense Key equals 0x2 and the ASC is 0x3a)
1056 * return immediately as the medium being absent won't change
1057 * unless there is a user action.
1058 */
1059 if ((srb->sense_buf[2] == 0x02) &&
1060 (srb->sense_buf[12] == 0x3a))
1061 return -1;
Mike Frysinger60ce19a2012-03-05 13:47:00 +00001062 mdelay(100);
Michael Trimarchi956a4352008-12-10 15:52:06 +01001063 } while (retries--);
wdenkde887eb2003-09-10 18:20:28 +00001064
wdenkaffae2b2002-08-17 09:36:01 +00001065 return -1;
1066}
1067
Simon Glass5fb559d2017-06-14 21:28:30 -06001068static int usb_read_capacity(struct scsi_cmd *srb, struct us_data *ss)
wdenkaffae2b2002-08-17 09:36:01 +00001069{
1070 int retry;
Michael Trimarchi956a4352008-12-10 15:52:06 +01001071 /* XXX retries */
1072 retry = 3;
wdenkaffae2b2002-08-17 09:36:01 +00001073 do {
Michael Trimarchi956a4352008-12-10 15:52:06 +01001074 memset(&srb->cmd[0], 0, 12);
1075 srb->cmd[0] = SCSI_RD_CAPAC;
Ludovic Courtès134396c2010-10-05 22:04:26 +02001076 srb->cmd[1] = srb->lun << 5;
Michael Trimarchi956a4352008-12-10 15:52:06 +01001077 srb->datalen = 8;
Hector Martin7b3d10d2023-10-29 16:23:30 +09001078 srb->cmdlen = ss->cmd12 ? 12 : 10;
Michael Trimarchi956a4352008-12-10 15:52:06 +01001079 if (ss->transport(srb, ss) == USB_STOR_TRANSPORT_GOOD)
wdenkaffae2b2002-08-17 09:36:01 +00001080 return 0;
Michael Trimarchi956a4352008-12-10 15:52:06 +01001081 } while (retry--);
wdenkde887eb2003-09-10 18:20:28 +00001082
wdenkaffae2b2002-08-17 09:36:01 +00001083 return -1;
1084}
1085
Simon Glass5fb559d2017-06-14 21:28:30 -06001086static int usb_read_10(struct scsi_cmd *srb, struct us_data *ss,
1087 unsigned long start, unsigned short blocks)
wdenkaffae2b2002-08-17 09:36:01 +00001088{
Michael Trimarchi956a4352008-12-10 15:52:06 +01001089 memset(&srb->cmd[0], 0, 12);
1090 srb->cmd[0] = SCSI_READ10;
Ludovic Courtès134396c2010-10-05 22:04:26 +02001091 srb->cmd[1] = srb->lun << 5;
Michael Trimarchi956a4352008-12-10 15:52:06 +01001092 srb->cmd[2] = ((unsigned char) (start >> 24)) & 0xff;
1093 srb->cmd[3] = ((unsigned char) (start >> 16)) & 0xff;
1094 srb->cmd[4] = ((unsigned char) (start >> 8)) & 0xff;
1095 srb->cmd[5] = ((unsigned char) (start)) & 0xff;
1096 srb->cmd[7] = ((unsigned char) (blocks >> 8)) & 0xff;
1097 srb->cmd[8] = (unsigned char) blocks & 0xff;
Hector Martin7b3d10d2023-10-29 16:23:30 +09001098 srb->cmdlen = ss->cmd12 ? 12 : 10;
Vivek Gautamf94c95d2013-04-12 16:34:33 +05301099 debug("read10: start %lx blocks %x\n", start, blocks);
Michael Trimarchi956a4352008-12-10 15:52:06 +01001100 return ss->transport(srb, ss);
wdenkaffae2b2002-08-17 09:36:01 +00001101}
1102
Simon Glass5fb559d2017-06-14 21:28:30 -06001103static int usb_write_10(struct scsi_cmd *srb, struct us_data *ss,
1104 unsigned long start, unsigned short blocks)
Mahavir Jaind43a0b82009-11-03 12:22:10 +05301105{
1106 memset(&srb->cmd[0], 0, 12);
1107 srb->cmd[0] = SCSI_WRITE10;
Ludovic Courtès134396c2010-10-05 22:04:26 +02001108 srb->cmd[1] = srb->lun << 5;
Mahavir Jaind43a0b82009-11-03 12:22:10 +05301109 srb->cmd[2] = ((unsigned char) (start >> 24)) & 0xff;
1110 srb->cmd[3] = ((unsigned char) (start >> 16)) & 0xff;
1111 srb->cmd[4] = ((unsigned char) (start >> 8)) & 0xff;
1112 srb->cmd[5] = ((unsigned char) (start)) & 0xff;
1113 srb->cmd[7] = ((unsigned char) (blocks >> 8)) & 0xff;
1114 srb->cmd[8] = (unsigned char) blocks & 0xff;
Hector Martin7b3d10d2023-10-29 16:23:30 +09001115 srb->cmdlen = ss->cmd12 ? 12 : 10;
Vivek Gautamf94c95d2013-04-12 16:34:33 +05301116 debug("write10: start %lx blocks %x\n", start, blocks);
Mahavir Jaind43a0b82009-11-03 12:22:10 +05301117 return ss->transport(srb, ss);
1118}
1119
wdenkaffae2b2002-08-17 09:36:01 +00001120
Bartlomiej Sieka9d47ad42006-08-22 10:38:18 +02001121#ifdef CONFIG_USB_BIN_FIXUP
1122/*
1123 * Some USB storage devices queried for SCSI identification data respond with
1124 * binary strings, which if output to the console freeze the terminal. The
1125 * workaround is to modify the vendor and product strings read from such
1126 * device with proper values (as reported by 'usb info').
1127 *
1128 * Vendor and product length limits are taken from the definition of
Simon Glasse3394752016-02-29 15:25:34 -07001129 * struct blk_desc in include/part.h.
Bartlomiej Sieka9d47ad42006-08-22 10:38:18 +02001130 */
1131static void usb_bin_fixup(struct usb_device_descriptor descriptor,
1132 unsigned char vendor[],
1133 unsigned char product[]) {
1134 const unsigned char max_vendor_len = 40;
1135 const unsigned char max_product_len = 20;
1136 if (descriptor.idVendor == 0x0424 && descriptor.idProduct == 0x223a) {
Michael Trimarchi956a4352008-12-10 15:52:06 +01001137 strncpy((char *)vendor, "SMSC", max_vendor_len);
1138 strncpy((char *)product, "Flash Media Cntrller",
1139 max_product_len);
Bartlomiej Sieka9d47ad42006-08-22 10:38:18 +02001140 }
1141}
1142#endif /* CONFIG_USB_BIN_FIXUP */
1143
Sven Schwermerc58ff202018-11-21 08:43:57 +01001144#if CONFIG_IS_ENABLED(BLK)
Simon Glass01f5be92016-02-29 15:25:58 -07001145static unsigned long usb_stor_read(struct udevice *dev, lbaint_t blknr,
1146 lbaint_t blkcnt, void *buffer)
1147#else
Simon Glasse3394752016-02-29 15:25:34 -07001148static unsigned long usb_stor_read(struct blk_desc *block_dev, lbaint_t blknr,
Stephen Warrene73f2962015-12-07 11:38:48 -07001149 lbaint_t blkcnt, void *buffer)
Simon Glass01f5be92016-02-29 15:25:58 -07001150#endif
wdenkaffae2b2002-08-17 09:36:01 +00001151{
Gabe Black7d077682012-10-12 14:26:07 +00001152 lbaint_t start, blks;
1153 uintptr_t buf_addr;
wdenkaffae2b2002-08-17 09:36:01 +00001154 unsigned short smallblks;
Simon Glass99e598e2016-02-29 15:25:54 -07001155 struct usb_device *udev;
Kyle Moffett6540db02011-12-21 07:08:12 +00001156 struct us_data *ss;
Simon Glass5c3c91c2015-03-25 12:22:13 -06001157 int retry;
Simon Glass5fb559d2017-06-14 21:28:30 -06001158 struct scsi_cmd *srb = &usb_ccb;
Sven Schwermerc58ff202018-11-21 08:43:57 +01001159#if CONFIG_IS_ENABLED(BLK)
Simon Glass01f5be92016-02-29 15:25:58 -07001160 struct blk_desc *block_dev;
1161#endif
wdenk0e2874cb2004-03-02 14:05:39 +00001162
1163 if (blkcnt == 0)
1164 return 0;
Michael Trimarchi956a4352008-12-10 15:52:06 +01001165 /* Setup device */
Sven Schwermerc58ff202018-11-21 08:43:57 +01001166#if CONFIG_IS_ENABLED(BLK)
Simon Glass71fa5b42020-12-03 16:55:18 -07001167 block_dev = dev_get_uclass_plat(dev);
Simon Glass01f5be92016-02-29 15:25:58 -07001168 udev = dev_get_parent_priv(dev_get_parent(dev));
1169 debug("\nusb_read: udev %d\n", block_dev->devnum);
1170#else
Simon Glass99e598e2016-02-29 15:25:54 -07001171 debug("\nusb_read: udev %d\n", block_dev->devnum);
1172 udev = usb_dev_desc[block_dev->devnum].priv;
1173 if (!udev) {
Simon Glass5c3c91c2015-03-25 12:22:13 -06001174 debug("%s: No device\n", __func__);
1175 return 0;
wdenkaffae2b2002-08-17 09:36:01 +00001176 }
Simon Glass01f5be92016-02-29 15:25:58 -07001177#endif
Simon Glass99e598e2016-02-29 15:25:54 -07001178 ss = (struct us_data *)udev->privptr;
wdenkaffae2b2002-08-17 09:36:01 +00001179
1180 usb_disable_asynch(1); /* asynch transfer not allowed */
Marek Vasut118a9032020-04-06 14:29:44 +02001181 usb_lock_async(udev, 1);
Simon Glass99e598e2016-02-29 15:25:54 -07001182 srb->lun = block_dev->lun;
Sergey Temerkhanov57236d52015-04-01 17:18:46 +03001183 buf_addr = (uintptr_t)buffer;
Michael Trimarchi956a4352008-12-10 15:52:06 +01001184 start = blknr;
1185 blks = blkcnt;
Michael Trimarchi956a4352008-12-10 15:52:06 +01001186
Masahiro Yamadac7570a32018-08-06 20:47:40 +09001187 debug("\nusb_read: dev %d startblk " LBAF ", blccnt " LBAF " buffer %lx\n",
1188 block_dev->devnum, start, blks, buf_addr);
Michael Trimarchi956a4352008-12-10 15:52:06 +01001189
wdenkaffae2b2002-08-17 09:36:01 +00001190 do {
Michael Trimarchi956a4352008-12-10 15:52:06 +01001191 /* XXX need some comment here */
1192 retry = 2;
1193 srb->pdata = (unsigned char *)buf_addr;
Bin Mengf6e373e2017-09-07 06:13:20 -07001194 if (blks > ss->max_xfer_blk)
1195 smallblks = ss->max_xfer_blk;
Michael Trimarchi956a4352008-12-10 15:52:06 +01001196 else
1197 smallblks = (unsigned short) blks;
wdenkaffae2b2002-08-17 09:36:01 +00001198retry_it:
Bin Mengf6e373e2017-09-07 06:13:20 -07001199 if (smallblks == ss->max_xfer_blk)
wdenkaffae2b2002-08-17 09:36:01 +00001200 usb_show_progress();
Simon Glass99e598e2016-02-29 15:25:54 -07001201 srb->datalen = block_dev->blksz * smallblks;
Michael Trimarchi956a4352008-12-10 15:52:06 +01001202 srb->pdata = (unsigned char *)buf_addr;
Kyle Moffett6540db02011-12-21 07:08:12 +00001203 if (usb_read_10(srb, ss, start, smallblks)) {
Vivek Gautamf94c95d2013-04-12 16:34:33 +05301204 debug("Read ERROR\n");
Marek Vasut765e91a2019-10-05 19:18:38 +02001205 ss->flags &= ~USB_READY;
Kyle Moffett6540db02011-12-21 07:08:12 +00001206 usb_request_sense(srb, ss);
Michael Trimarchi956a4352008-12-10 15:52:06 +01001207 if (retry--)
wdenkaffae2b2002-08-17 09:36:01 +00001208 goto retry_it;
Michael Trimarchi956a4352008-12-10 15:52:06 +01001209 blkcnt -= blks;
wdenkaffae2b2002-08-17 09:36:01 +00001210 break;
1211 }
Michael Trimarchi956a4352008-12-10 15:52:06 +01001212 start += smallblks;
1213 blks -= smallblks;
1214 buf_addr += srb->datalen;
1215 } while (blks != 0);
1216
Masahiro Yamadac7570a32018-08-06 20:47:40 +09001217 debug("usb_read: end startblk " LBAF ", blccnt %x buffer %lx\n",
Vivek Gautamf94c95d2013-04-12 16:34:33 +05301218 start, smallblks, buf_addr);
Michael Trimarchi956a4352008-12-10 15:52:06 +01001219
Marek Vasut118a9032020-04-06 14:29:44 +02001220 usb_lock_async(udev, 0);
wdenkaffae2b2002-08-17 09:36:01 +00001221 usb_disable_asynch(0); /* asynch transfer allowed */
Bin Mengf6e373e2017-09-07 06:13:20 -07001222 if (blkcnt >= ss->max_xfer_blk)
Wolfgang Denk660e9a42010-07-19 11:36:59 +02001223 debug("\n");
Michael Trimarchi956a4352008-12-10 15:52:06 +01001224 return blkcnt;
wdenkaffae2b2002-08-17 09:36:01 +00001225}
1226
Sven Schwermerc58ff202018-11-21 08:43:57 +01001227#if CONFIG_IS_ENABLED(BLK)
Simon Glass01f5be92016-02-29 15:25:58 -07001228static unsigned long usb_stor_write(struct udevice *dev, lbaint_t blknr,
1229 lbaint_t blkcnt, const void *buffer)
1230#else
Simon Glasse3394752016-02-29 15:25:34 -07001231static unsigned long usb_stor_write(struct blk_desc *block_dev, lbaint_t blknr,
Stephen Warrene73f2962015-12-07 11:38:48 -07001232 lbaint_t blkcnt, const void *buffer)
Simon Glass01f5be92016-02-29 15:25:58 -07001233#endif
Mahavir Jaind43a0b82009-11-03 12:22:10 +05301234{
Gabe Black7d077682012-10-12 14:26:07 +00001235 lbaint_t start, blks;
1236 uintptr_t buf_addr;
Mahavir Jaind43a0b82009-11-03 12:22:10 +05301237 unsigned short smallblks;
Simon Glass99e598e2016-02-29 15:25:54 -07001238 struct usb_device *udev;
Kyle Moffett6540db02011-12-21 07:08:12 +00001239 struct us_data *ss;
Simon Glass5c3c91c2015-03-25 12:22:13 -06001240 int retry;
Simon Glass5fb559d2017-06-14 21:28:30 -06001241 struct scsi_cmd *srb = &usb_ccb;
Sven Schwermerc58ff202018-11-21 08:43:57 +01001242#if CONFIG_IS_ENABLED(BLK)
Simon Glass01f5be92016-02-29 15:25:58 -07001243 struct blk_desc *block_dev;
1244#endif
Mahavir Jaind43a0b82009-11-03 12:22:10 +05301245
1246 if (blkcnt == 0)
1247 return 0;
1248
Mahavir Jaind43a0b82009-11-03 12:22:10 +05301249 /* Setup device */
Sven Schwermerc58ff202018-11-21 08:43:57 +01001250#if CONFIG_IS_ENABLED(BLK)
Simon Glass71fa5b42020-12-03 16:55:18 -07001251 block_dev = dev_get_uclass_plat(dev);
Simon Glass01f5be92016-02-29 15:25:58 -07001252 udev = dev_get_parent_priv(dev_get_parent(dev));
1253 debug("\nusb_read: udev %d\n", block_dev->devnum);
1254#else
Simon Glass99e598e2016-02-29 15:25:54 -07001255 debug("\nusb_read: udev %d\n", block_dev->devnum);
1256 udev = usb_dev_desc[block_dev->devnum].priv;
1257 if (!udev) {
1258 debug("%s: No device\n", __func__);
Simon Glass5c3c91c2015-03-25 12:22:13 -06001259 return 0;
Simon Glass99e598e2016-02-29 15:25:54 -07001260 }
Simon Glass01f5be92016-02-29 15:25:58 -07001261#endif
Simon Glass99e598e2016-02-29 15:25:54 -07001262 ss = (struct us_data *)udev->privptr;
Mahavir Jaind43a0b82009-11-03 12:22:10 +05301263
1264 usb_disable_asynch(1); /* asynch transfer not allowed */
Marek Vasut118a9032020-04-06 14:29:44 +02001265 usb_lock_async(udev, 1);
Mahavir Jaind43a0b82009-11-03 12:22:10 +05301266
Simon Glass99e598e2016-02-29 15:25:54 -07001267 srb->lun = block_dev->lun;
Sergey Temerkhanov57236d52015-04-01 17:18:46 +03001268 buf_addr = (uintptr_t)buffer;
Mahavir Jaind43a0b82009-11-03 12:22:10 +05301269 start = blknr;
1270 blks = blkcnt;
Mahavir Jaind43a0b82009-11-03 12:22:10 +05301271
Masahiro Yamadac7570a32018-08-06 20:47:40 +09001272 debug("\nusb_write: dev %d startblk " LBAF ", blccnt " LBAF " buffer %lx\n",
1273 block_dev->devnum, start, blks, buf_addr);
Mahavir Jaind43a0b82009-11-03 12:22:10 +05301274
1275 do {
1276 /* If write fails retry for max retry count else
1277 * return with number of blocks written successfully.
1278 */
1279 retry = 2;
1280 srb->pdata = (unsigned char *)buf_addr;
Bin Mengf6e373e2017-09-07 06:13:20 -07001281 if (blks > ss->max_xfer_blk)
1282 smallblks = ss->max_xfer_blk;
Mahavir Jaind43a0b82009-11-03 12:22:10 +05301283 else
1284 smallblks = (unsigned short) blks;
1285retry_it:
Bin Mengf6e373e2017-09-07 06:13:20 -07001286 if (smallblks == ss->max_xfer_blk)
Mahavir Jaind43a0b82009-11-03 12:22:10 +05301287 usb_show_progress();
Simon Glass99e598e2016-02-29 15:25:54 -07001288 srb->datalen = block_dev->blksz * smallblks;
Mahavir Jaind43a0b82009-11-03 12:22:10 +05301289 srb->pdata = (unsigned char *)buf_addr;
Kyle Moffett6540db02011-12-21 07:08:12 +00001290 if (usb_write_10(srb, ss, start, smallblks)) {
Vivek Gautamf94c95d2013-04-12 16:34:33 +05301291 debug("Write ERROR\n");
Marek Vasut765e91a2019-10-05 19:18:38 +02001292 ss->flags &= ~USB_READY;
Kyle Moffett6540db02011-12-21 07:08:12 +00001293 usb_request_sense(srb, ss);
Mahavir Jaind43a0b82009-11-03 12:22:10 +05301294 if (retry--)
1295 goto retry_it;
1296 blkcnt -= blks;
1297 break;
1298 }
1299 start += smallblks;
1300 blks -= smallblks;
1301 buf_addr += srb->datalen;
1302 } while (blks != 0);
1303
Masahiro Yamadac7570a32018-08-06 20:47:40 +09001304 debug("usb_write: end startblk " LBAF ", blccnt %x buffer %lx\n",
1305 start, smallblks, buf_addr);
Mahavir Jaind43a0b82009-11-03 12:22:10 +05301306
Marek Vasut118a9032020-04-06 14:29:44 +02001307 usb_lock_async(udev, 0);
Mahavir Jaind43a0b82009-11-03 12:22:10 +05301308 usb_disable_asynch(0); /* asynch transfer allowed */
Bin Mengf6e373e2017-09-07 06:13:20 -07001309 if (blkcnt >= ss->max_xfer_blk)
Wolfgang Denk660e9a42010-07-19 11:36:59 +02001310 debug("\n");
Mahavir Jaind43a0b82009-11-03 12:22:10 +05301311 return blkcnt;
1312
1313}
wdenkaffae2b2002-08-17 09:36:01 +00001314
1315/* Probe to see if a new device is actually a Storage device */
Michael Trimarchi956a4352008-12-10 15:52:06 +01001316int usb_storage_probe(struct usb_device *dev, unsigned int ifnum,
1317 struct us_data *ss)
wdenkaffae2b2002-08-17 09:36:01 +00001318{
Tom Rix83b9e1d2009-10-31 12:37:38 -05001319 struct usb_interface *iface;
wdenkaffae2b2002-08-17 09:36:01 +00001320 int i;
Vivek Gautam23cbd292013-04-12 16:34:34 +05301321 struct usb_endpoint_descriptor *ep_desc;
wdenkaffae2b2002-08-17 09:36:01 +00001322 unsigned int flags = 0;
1323
wdenkaffae2b2002-08-17 09:36:01 +00001324 /* let's examine the device now */
1325 iface = &dev->config.if_desc[ifnum];
1326
wdenkaffae2b2002-08-17 09:36:01 +00001327 if (dev->descriptor.bDeviceClass != 0 ||
Tom Rix83b9e1d2009-10-31 12:37:38 -05001328 iface->desc.bInterfaceClass != USB_CLASS_MASS_STORAGE ||
1329 iface->desc.bInterfaceSubClass < US_SC_MIN ||
1330 iface->desc.bInterfaceSubClass > US_SC_MAX) {
Simon Glass78330d62015-03-25 12:22:12 -06001331 debug("Not mass storage\n");
wdenkaffae2b2002-08-17 09:36:01 +00001332 /* if it's not a mass storage, we go no further */
1333 return 0;
1334 }
1335
Wolfgang Denkc7a4f7d2005-07-21 11:57:57 +02001336 memset(ss, 0, sizeof(struct us_data));
1337
wdenkaffae2b2002-08-17 09:36:01 +00001338 /* At this point, we know we've got a live one */
Vivek Gautamf94c95d2013-04-12 16:34:33 +05301339 debug("\n\nUSB Mass Storage device detected\n");
wdenkaffae2b2002-08-17 09:36:01 +00001340
1341 /* Initialize the us_data structure with some useful info */
1342 ss->flags = flags;
1343 ss->ifnum = ifnum;
1344 ss->pusb_dev = dev;
1345 ss->attention_done = 0;
Tom Rinid83b89d2015-10-11 07:26:27 -04001346 ss->subclass = iface->desc.bInterfaceSubClass;
1347 ss->protocol = iface->desc.bInterfaceProtocol;
wdenkaffae2b2002-08-17 09:36:01 +00001348
1349 /* set the handler pointers based on the protocol */
Vivek Gautamf94c95d2013-04-12 16:34:33 +05301350 debug("Transport: ");
wdenkaffae2b2002-08-17 09:36:01 +00001351 switch (ss->protocol) {
1352 case US_PR_CB:
Vivek Gautamf94c95d2013-04-12 16:34:33 +05301353 debug("Control/Bulk\n");
wdenkaffae2b2002-08-17 09:36:01 +00001354 ss->transport = usb_stor_CB_transport;
1355 ss->transport_reset = usb_stor_CB_reset;
1356 break;
1357
1358 case US_PR_CBI:
Vivek Gautamf94c95d2013-04-12 16:34:33 +05301359 debug("Control/Bulk/Interrupt\n");
wdenkaffae2b2002-08-17 09:36:01 +00001360 ss->transport = usb_stor_CB_transport;
1361 ss->transport_reset = usb_stor_CB_reset;
1362 break;
wdenkde887eb2003-09-10 18:20:28 +00001363 case US_PR_BULK:
Vivek Gautamf94c95d2013-04-12 16:34:33 +05301364 debug("Bulk/Bulk/Bulk\n");
wdenkde887eb2003-09-10 18:20:28 +00001365 ss->transport = usb_stor_BBB_transport;
1366 ss->transport_reset = usb_stor_BBB_reset;
1367 break;
wdenkaffae2b2002-08-17 09:36:01 +00001368 default:
wdenk5f495752004-02-26 23:46:20 +00001369 printf("USB Storage Transport unknown / not yet implemented\n");
wdenkaffae2b2002-08-17 09:36:01 +00001370 return 0;
1371 break;
1372 }
1373
1374 /*
1375 * We are expecting a minimum of 2 endpoints - in and out (bulk).
1376 * An optional interrupt is OK (necessary for CBI protocol).
1377 * We will ignore any others.
1378 */
Tom Rix83b9e1d2009-10-31 12:37:38 -05001379 for (i = 0; i < iface->desc.bNumEndpoints; i++) {
Vivek Gautam23cbd292013-04-12 16:34:34 +05301380 ep_desc = &iface->ep_desc[i];
wdenkaffae2b2002-08-17 09:36:01 +00001381 /* is it an BULK endpoint? */
Vivek Gautam23cbd292013-04-12 16:34:34 +05301382 if ((ep_desc->bmAttributes &
Michael Trimarchi956a4352008-12-10 15:52:06 +01001383 USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK) {
Vivek Gautam23cbd292013-04-12 16:34:34 +05301384 if (ep_desc->bEndpointAddress & USB_DIR_IN)
1385 ss->ep_in = ep_desc->bEndpointAddress &
1386 USB_ENDPOINT_NUMBER_MASK;
wdenkaffae2b2002-08-17 09:36:01 +00001387 else
Michael Trimarchi956a4352008-12-10 15:52:06 +01001388 ss->ep_out =
Vivek Gautam23cbd292013-04-12 16:34:34 +05301389 ep_desc->bEndpointAddress &
wdenkaffae2b2002-08-17 09:36:01 +00001390 USB_ENDPOINT_NUMBER_MASK;
1391 }
1392
1393 /* is it an interrupt endpoint? */
Vivek Gautam23cbd292013-04-12 16:34:34 +05301394 if ((ep_desc->bmAttributes &
1395 USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT) {
1396 ss->ep_int = ep_desc->bEndpointAddress &
1397 USB_ENDPOINT_NUMBER_MASK;
1398 ss->irqinterval = ep_desc->bInterval;
wdenkaffae2b2002-08-17 09:36:01 +00001399 }
1400 }
Vivek Gautamf94c95d2013-04-12 16:34:33 +05301401 debug("Endpoints In %d Out %d Int %d\n",
1402 ss->ep_in, ss->ep_out, ss->ep_int);
wdenkaffae2b2002-08-17 09:36:01 +00001403
1404 /* Do some basic sanity checks, and bail if we find a problem */
Tom Rix83b9e1d2009-10-31 12:37:38 -05001405 if (usb_set_interface(dev, iface->desc.bInterfaceNumber, 0) ||
wdenkaffae2b2002-08-17 09:36:01 +00001406 !ss->ep_in || !ss->ep_out ||
1407 (ss->protocol == US_PR_CBI && ss->ep_int == 0)) {
Vivek Gautamf94c95d2013-04-12 16:34:33 +05301408 debug("Problems with device\n");
wdenkaffae2b2002-08-17 09:36:01 +00001409 return 0;
1410 }
1411 /* set class specific stuff */
wdenkde887eb2003-09-10 18:20:28 +00001412 /* We only handle certain protocols. Currently, these are
1413 * the only ones.
wdenk5f495752004-02-26 23:46:20 +00001414 * The SFF8070 accepts the requests used in u-boot
wdenkaffae2b2002-08-17 09:36:01 +00001415 */
wdenk5f495752004-02-26 23:46:20 +00001416 if (ss->subclass != US_SC_UFI && ss->subclass != US_SC_SCSI &&
1417 ss->subclass != US_SC_8070) {
Michael Trimarchi956a4352008-12-10 15:52:06 +01001418 printf("Sorry, protocol %d not yet supported.\n", ss->subclass);
wdenkaffae2b2002-08-17 09:36:01 +00001419 return 0;
1420 }
Hector Martin7b3d10d2023-10-29 16:23:30 +09001421
1422 /* UFI uses 12-byte commands (like RBC, unlike SCSI) */
1423 if (ss->subclass == US_SC_UFI)
1424 ss->cmd12 = true;
1425
Michael Trimarchi956a4352008-12-10 15:52:06 +01001426 if (ss->ep_int) {
1427 /* we had found an interrupt endpoint, prepare irq pipe
1428 * set up the IRQ pipe and handler
1429 */
wdenkaffae2b2002-08-17 09:36:01 +00001430 ss->irqinterval = (ss->irqinterval > 0) ? ss->irqinterval : 255;
1431 ss->irqpipe = usb_rcvintpipe(ss->pusb_dev, ss->ep_int);
1432 ss->irqmaxp = usb_maxpacket(dev, ss->irqpipe);
Michael Trimarchi956a4352008-12-10 15:52:06 +01001433 dev->irq_handle = usb_stor_irq;
wdenkaffae2b2002-08-17 09:36:01 +00001434 }
Bin Mengf6e373e2017-09-07 06:13:20 -07001435
1436 /* Set the maximum transfer size per host controller setting */
Bin Meng9f447112017-09-07 06:13:21 -07001437 usb_stor_set_max_xfer_blk(dev, ss);
Bin Mengf6e373e2017-09-07 06:13:20 -07001438
Michael Trimarchi956a4352008-12-10 15:52:06 +01001439 dev->privptr = (void *)ss;
wdenkaffae2b2002-08-17 09:36:01 +00001440 return 1;
1441}
1442
Michael Trimarchi956a4352008-12-10 15:52:06 +01001443int usb_stor_get_info(struct usb_device *dev, struct us_data *ss,
Simon Glasse3394752016-02-29 15:25:34 -07001444 struct blk_desc *dev_desc)
wdenkaffae2b2002-08-17 09:36:01 +00001445{
Michael Trimarchi956a4352008-12-10 15:52:06 +01001446 unsigned char perq, modi;
Sergey Temerkhanov57236d52015-04-01 17:18:46 +03001447 ALLOC_CACHE_ALIGN_BUFFER(u32, cap, 2);
1448 ALLOC_CACHE_ALIGN_BUFFER(u8, usb_stor_buf, 36);
1449 u32 capacity, blksz;
Simon Glass5fb559d2017-06-14 21:28:30 -06001450 struct scsi_cmd *pccb = &usb_ccb;
wdenkaffae2b2002-08-17 09:36:01 +00001451
Wolfgang Denkc7a4f7d2005-07-21 11:57:57 +02001452 pccb->pdata = usb_stor_buf;
1453
1454 dev_desc->target = dev->devnum;
1455 pccb->lun = dev_desc->lun;
Vivek Gautamf94c95d2013-04-12 16:34:33 +05301456 debug(" address %d\n", dev_desc->target);
wdenkaffae2b2002-08-17 09:36:01 +00001457
Simon Glass78330d62015-03-25 12:22:12 -06001458 if (usb_inquiry(pccb, ss)) {
1459 debug("%s: usb_inquiry() failed\n", __func__);
wdenkaffae2b2002-08-17 09:36:01 +00001460 return -1;
Simon Glass78330d62015-03-25 12:22:12 -06001461 }
Wolfgang Denkd06ce5d2005-08-02 17:06:17 +02001462
Wolfgang Denkc7a4f7d2005-07-21 11:57:57 +02001463 perq = usb_stor_buf[0];
1464 modi = usb_stor_buf[1];
Michael Trimarchi956a4352008-12-10 15:52:06 +01001465
Soeren Moche4828002014-11-08 07:02:14 +01001466 /*
1467 * Skip unknown devices (0x1f) and enclosure service devices (0x0d),
1468 * they would not respond to test_unit_ready .
1469 */
1470 if (((perq & 0x1f) == 0x1f) || ((perq & 0x1f) == 0x0d)) {
Simon Glass78330d62015-03-25 12:22:12 -06001471 debug("%s: unknown/unsupported device\n", __func__);
Michael Trimarchi956a4352008-12-10 15:52:06 +01001472 return 0;
wdenkaffae2b2002-08-17 09:36:01 +00001473 }
Michael Trimarchi956a4352008-12-10 15:52:06 +01001474 if ((modi&0x80) == 0x80) {
1475 /* drive is removable */
Wolfgang Denkc7a4f7d2005-07-21 11:57:57 +02001476 dev_desc->removable = 1;
wdenkaffae2b2002-08-17 09:36:01 +00001477 }
Sergey Temerkhanov57236d52015-04-01 17:18:46 +03001478 memcpy(dev_desc->vendor, (const void *)&usb_stor_buf[8], 8);
1479 memcpy(dev_desc->product, (const void *)&usb_stor_buf[16], 16);
1480 memcpy(dev_desc->revision, (const void *)&usb_stor_buf[32], 4);
Wolfgang Denkc7a4f7d2005-07-21 11:57:57 +02001481 dev_desc->vendor[8] = 0;
1482 dev_desc->product[16] = 0;
1483 dev_desc->revision[4] = 0;
Bartlomiej Sieka9d47ad42006-08-22 10:38:18 +02001484#ifdef CONFIG_USB_BIN_FIXUP
Michael Trimarchi956a4352008-12-10 15:52:06 +01001485 usb_bin_fixup(dev->descriptor, (uchar *)dev_desc->vendor,
1486 (uchar *)dev_desc->product);
Bartlomiej Sieka9d47ad42006-08-22 10:38:18 +02001487#endif /* CONFIG_USB_BIN_FIXUP */
Vivek Gautamf94c95d2013-04-12 16:34:33 +05301488 debug("ISO Vers %X, Response Data %X\n", usb_stor_buf[2],
1489 usb_stor_buf[3]);
Michael Trimarchi956a4352008-12-10 15:52:06 +01001490 if (usb_test_unit_ready(pccb, ss)) {
1491 printf("Device NOT ready\n"
1492 " Request Sense returned %02X %02X %02X\n",
1493 pccb->sense_buf[2], pccb->sense_buf[12],
1494 pccb->sense_buf[13]);
Troy Kisky17e45262017-04-10 18:23:11 -07001495 if (dev_desc->removable == 1)
Wolfgang Denkc7a4f7d2005-07-21 11:57:57 +02001496 dev_desc->type = perq;
Michael Trimarchi956a4352008-12-10 15:52:06 +01001497 return 0;
wdenkaffae2b2002-08-17 09:36:01 +00001498 }
Sergey Temerkhanov57236d52015-04-01 17:18:46 +03001499 pccb->pdata = (unsigned char *)cap;
Michael Trimarchi956a4352008-12-10 15:52:06 +01001500 memset(pccb->pdata, 0, 8);
1501 if (usb_read_capacity(pccb, ss) != 0) {
wdenkaffae2b2002-08-17 09:36:01 +00001502 printf("READ_CAP ERROR\n");
Marek Vasut765e91a2019-10-05 19:18:38 +02001503 ss->flags &= ~USB_READY;
Wolfgang Denkc7a4f7d2005-07-21 11:57:57 +02001504 cap[0] = 2880;
1505 cap[1] = 0x200;
wdenkaffae2b2002-08-17 09:36:01 +00001506 }
Sergey Temerkhanov57236d52015-04-01 17:18:46 +03001507 debug("Read Capacity returns: 0x%08x, 0x%08x\n", cap[0], cap[1]);
wdenkaffae2b2002-08-17 09:36:01 +00001508#if 0
Michael Trimarchi956a4352008-12-10 15:52:06 +01001509 if (cap[0] > (0x200000 * 10)) /* greater than 10 GByte */
1510 cap[0] >>= 16;
Sergey Temerkhanov57236d52015-04-01 17:18:46 +03001511
Christian Eggers4e0e8d02008-05-21 22:12:00 +02001512 cap[0] = cpu_to_be32(cap[0]);
1513 cap[1] = cpu_to_be32(cap[1]);
Sergey Temerkhanov57236d52015-04-01 17:18:46 +03001514#endif
1515
1516 capacity = be32_to_cpu(cap[0]) + 1;
1517 blksz = be32_to_cpu(cap[1]);
Christian Eggers4e0e8d02008-05-21 22:12:00 +02001518
Sergey Temerkhanov57236d52015-04-01 17:18:46 +03001519 debug("Capacity = 0x%08x, blocksz = 0x%08x\n", capacity, blksz);
1520 dev_desc->lba = capacity;
1521 dev_desc->blksz = blksz;
Egbert Eich2eec2ab2013-04-09 21:11:56 +00001522 dev_desc->log2blksz = LOG2(dev_desc->blksz);
Wolfgang Denkc7a4f7d2005-07-21 11:57:57 +02001523 dev_desc->type = perq;
Vivek Gautamf94c95d2013-04-12 16:34:33 +05301524 debug(" address %d\n", dev_desc->target);
wdenkaffae2b2002-08-17 09:36:01 +00001525
wdenkaffae2b2002-08-17 09:36:01 +00001526 return 1;
1527}
Simon Glassac9774e2015-03-25 12:22:16 -06001528
Sven Schwermer8a3cb9f12018-11-21 08:43:56 +01001529#if CONFIG_IS_ENABLED(DM_USB)
Simon Glassac9774e2015-03-25 12:22:16 -06001530
1531static int usb_mass_storage_probe(struct udevice *dev)
1532{
Simon Glassde44acf2015-09-28 23:32:01 -06001533 struct usb_device *udev = dev_get_parent_priv(dev);
Simon Glassac9774e2015-03-25 12:22:16 -06001534 int ret;
1535
1536 usb_disable_asynch(1); /* asynch transfer not allowed */
1537 ret = usb_stor_probe_device(udev);
1538 usb_disable_asynch(0); /* asynch transfer allowed */
1539
1540 return ret;
1541}
1542
1543static const struct udevice_id usb_mass_storage_ids[] = {
1544 { .compatible = "usb-mass-storage" },
1545 { }
1546};
1547
1548U_BOOT_DRIVER(usb_mass_storage) = {
1549 .name = "usb_mass_storage",
1550 .id = UCLASS_MASS_STORAGE,
1551 .of_match = usb_mass_storage_ids,
1552 .probe = usb_mass_storage_probe,
Sven Schwermerc58ff202018-11-21 08:43:57 +01001553#if CONFIG_IS_ENABLED(BLK)
Simon Glass71fa5b42020-12-03 16:55:18 -07001554 .plat_auto = sizeof(struct us_data),
Simon Glass01f5be92016-02-29 15:25:58 -07001555#endif
Simon Glassac9774e2015-03-25 12:22:16 -06001556};
1557
1558UCLASS_DRIVER(usb_mass_storage) = {
1559 .id = UCLASS_MASS_STORAGE,
1560 .name = "usb_mass_storage",
1561};
1562
1563static const struct usb_device_id mass_storage_id_table[] = {
1564 {
1565 .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS,
1566 .bInterfaceClass = USB_CLASS_MASS_STORAGE
1567 },
1568 { } /* Terminating entry */
1569};
1570
Simon Glass46952fb2015-07-06 16:47:51 -06001571U_BOOT_USB_DEVICE(usb_mass_storage, mass_storage_id_table);
Simon Glass01f5be92016-02-29 15:25:58 -07001572#endif
Simon Glassac9774e2015-03-25 12:22:16 -06001573
Sven Schwermerc58ff202018-11-21 08:43:57 +01001574#if CONFIG_IS_ENABLED(BLK)
Simon Glass01f5be92016-02-29 15:25:58 -07001575static const struct blk_ops usb_storage_ops = {
1576 .read = usb_stor_read,
1577 .write = usb_stor_write,
1578};
1579
1580U_BOOT_DRIVER(usb_storage_blk) = {
1581 .name = "usb_storage_blk",
1582 .id = UCLASS_BLK,
1583 .ops = &usb_storage_ops,
1584};
Simon Glassd3171412016-05-01 11:36:06 -06001585#else
1586U_BOOT_LEGACY_BLK(usb) = {
Simon Glassfada3f92022-09-17 09:00:09 -06001587 .uclass_idname = "usb",
1588 .uclass_id = UCLASS_USB,
Simon Glassd3171412016-05-01 11:36:06 -06001589 .max_devs = USB_MAX_STOR_DEV,
1590 .desc = usb_dev_desc,
1591};
Simon Glassac9774e2015-03-25 12:22:16 -06001592#endif