blob: ac331f1c1b09fab9fe4d68ad02760df5214d53a8 [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
Simon Glass655306c2020-05-10 11:39:58 -060034#include <blk.h>
Simon Glasse1917ef2022-04-24 23:31:23 -060035#include <bootdev.h>
wdenkaffae2b2002-08-17 09:36:01 +000036#include <command.h>
Simon Glassac9774e2015-03-25 12:22:16 -060037#include <dm.h>
Simon Glassdf7d34f2015-03-25 12:22:15 -060038#include <errno.h>
Simon Glass0f2af882020-05-10 11:40:05 -060039#include <log.h>
Simon Glass332a9b62015-03-25 12:22:14 -060040#include <mapmem.h>
Simon Glass2dd337a2015-09-02 17:24:58 -060041#include <memalign.h>
Christian Eggers4e0e8d02008-05-21 22:12:00 +020042#include <asm/byteorder.h>
Simon Glass274e0b02020-05-10 11:39:56 -060043#include <asm/cache.h>
wdenkaffae2b2002-08-17 09:36:01 +000044#include <asm/processor.h>
Simon Glassac9774e2015-03-25 12:22:16 -060045#include <dm/device-internal.h>
Simon Glass01f5be92016-02-29 15:25:58 -070046#include <dm/lists.h>
Simon Glassdbd79542020-05-10 11:40:11 -060047#include <linux/delay.h>
wdenkaffae2b2002-08-17 09:36:01 +000048
Grant Likelyffc2dd72007-02-20 09:04:34 +010049#include <part.h>
wdenkaffae2b2002-08-17 09:36:01 +000050#include <usb.h>
51
wdenk5f495752004-02-26 23:46:20 +000052#undef BBB_COMDAT_TRACE
53#undef BBB_XPORT_TRACE
wdenkaffae2b2002-08-17 09:36:01 +000054
wdenkaffae2b2002-08-17 09:36:01 +000055#include <scsi.h>
56/* direction table -- this indicates the direction of the data
57 * transfer for each command code -- a 1 indicates input
58 */
Mike Frysinger165522b2010-10-20 07:16:04 -040059static const unsigned char us_direction[256/8] = {
wdenkaffae2b2002-08-17 09:36:01 +000060 0x28, 0x81, 0x14, 0x14, 0x20, 0x01, 0x90, 0x77,
61 0x0C, 0x20, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00,
62 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01,
63 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
64};
65#define US_DIRECTION(x) ((us_direction[x>>3] >> (x & 7)) & 1)
66
Simon Glass5fb559d2017-06-14 21:28:30 -060067static struct scsi_cmd usb_ccb __aligned(ARCH_DMA_MINALIGN);
Michael Trimarchi956a4352008-12-10 15:52:06 +010068static __u32 CBWTag;
wdenkde887eb2003-09-10 18:20:28 +000069
Michael Trimarchi956a4352008-12-10 15:52:06 +010070static int usb_max_devs; /* number of highest available usb device */
wdenkaffae2b2002-08-17 09:36:01 +000071
Sven Schwermerc58ff202018-11-21 08:43:57 +010072#if !CONFIG_IS_ENABLED(BLK)
Simon Glasse3394752016-02-29 15:25:34 -070073static struct blk_desc usb_dev_desc[USB_MAX_STOR_DEV];
Simon Glass01f5be92016-02-29 15:25:58 -070074#endif
wdenkaffae2b2002-08-17 09:36:01 +000075
76struct us_data;
Simon Glass5fb559d2017-06-14 21:28:30 -060077typedef int (*trans_cmnd)(struct scsi_cmd *cb, struct us_data *data);
Michael Trimarchi956a4352008-12-10 15:52:06 +010078typedef int (*trans_reset)(struct us_data *data);
wdenkaffae2b2002-08-17 09:36:01 +000079
80struct us_data {
Michael Trimarchi956a4352008-12-10 15:52:06 +010081 struct usb_device *pusb_dev; /* this usb_device */
82
83 unsigned int flags; /* from filter initially */
Benoît Thébaudeaufbf909a2012-08-10 18:27:11 +020084# define USB_READY (1 << 0)
Michael Trimarchi956a4352008-12-10 15:52:06 +010085 unsigned char ifnum; /* interface number */
86 unsigned char ep_in; /* in endpoint */
87 unsigned char ep_out; /* out ....... */
88 unsigned char ep_int; /* interrupt . */
89 unsigned char subclass; /* as in overview */
90 unsigned char protocol; /* .............. */
91 unsigned char attention_done; /* force attn on first cmd */
92 unsigned short ip_data; /* interrupt data */
93 int action; /* what to do */
94 int ip_wanted; /* needed */
95 int *irq_handle; /* for USB int requests */
Wolfgang Denk62fb2b42021-09-27 17:42:39 +020096 unsigned int irqpipe; /* pipe for release_irq */
Michael Trimarchi956a4352008-12-10 15:52:06 +010097 unsigned char irqmaxp; /* max packed for irq Pipe */
98 unsigned char irqinterval; /* Intervall for IRQ Pipe */
Simon Glass5fb559d2017-06-14 21:28:30 -060099 struct scsi_cmd *srb; /* current srb */
Michael Trimarchi956a4352008-12-10 15:52:06 +0100100 trans_reset transport_reset; /* reset routine */
101 trans_cmnd transport; /* transport routine */
Bin Mengf6e373e2017-09-07 06:13:20 -0700102 unsigned short max_xfer_blk; /* maximum transfer blocks */
Hector Martin7b3d10d2023-10-29 16:23:30 +0900103 bool cmd12; /* use 12-byte commands (RBC/UFI) */
wdenkaffae2b2002-08-17 09:36:01 +0000104};
105
Sven Schwermerc58ff202018-11-21 08:43:57 +0100106#if !CONFIG_IS_ENABLED(BLK)
wdenkaffae2b2002-08-17 09:36:01 +0000107static struct us_data usb_stor[USB_MAX_STOR_DEV];
Simon Glass01f5be92016-02-29 15:25:58 -0700108#endif
wdenkaffae2b2002-08-17 09:36:01 +0000109
wdenk5f495752004-02-26 23:46:20 +0000110#define USB_STOR_TRANSPORT_GOOD 0
wdenkaffae2b2002-08-17 09:36:01 +0000111#define USB_STOR_TRANSPORT_FAILED -1
112#define USB_STOR_TRANSPORT_ERROR -2
113
Michael Trimarchi956a4352008-12-10 15:52:06 +0100114int usb_stor_get_info(struct usb_device *dev, struct us_data *us,
Simon Glasse3394752016-02-29 15:25:34 -0700115 struct blk_desc *dev_desc);
Michael Trimarchi956a4352008-12-10 15:52:06 +0100116int usb_storage_probe(struct usb_device *dev, unsigned int ifnum,
117 struct us_data *ss);
Sven Schwermerc58ff202018-11-21 08:43:57 +0100118#if CONFIG_IS_ENABLED(BLK)
Simon Glass01f5be92016-02-29 15:25:58 -0700119static unsigned long usb_stor_read(struct udevice *dev, lbaint_t blknr,
120 lbaint_t blkcnt, void *buffer);
121static unsigned long usb_stor_write(struct udevice *dev, lbaint_t blknr,
122 lbaint_t blkcnt, const void *buffer);
123#else
Simon Glasse3394752016-02-29 15:25:34 -0700124static unsigned long usb_stor_read(struct blk_desc *block_dev, lbaint_t blknr,
Stephen Warrene73f2962015-12-07 11:38:48 -0700125 lbaint_t blkcnt, void *buffer);
Simon Glasse3394752016-02-29 15:25:34 -0700126static unsigned long usb_stor_write(struct blk_desc *block_dev, lbaint_t blknr,
Stephen Warrene73f2962015-12-07 11:38:48 -0700127 lbaint_t blkcnt, const void *buffer);
Simon Glass01f5be92016-02-29 15:25:58 -0700128#endif
wdenkaffae2b2002-08-17 09:36:01 +0000129void uhci_show_temp_int_td(void);
130
Kim Phillipsb052b602012-10-29 13:34:32 +0000131static void usb_show_progress(void)
wdenkaffae2b2002-08-17 09:36:01 +0000132{
Wolfgang Denk660e9a42010-07-19 11:36:59 +0200133 debug(".");
wdenkaffae2b2002-08-17 09:36:01 +0000134}
135
Michael Trimarchi956a4352008-12-10 15:52:06 +0100136/*******************************************************************************
Wolfgang Denkc7a4f7d2005-07-21 11:57:57 +0200137 * show info on storage devices; 'usb start/init' must be invoked earlier
138 * as we only retrieve structures populated during devices initialization
139 */
Aras Vaichas7ede1862008-03-25 12:09:07 +1100140int usb_stor_info(void)
Wolfgang Denkc7a4f7d2005-07-21 11:57:57 +0200141{
Simon Glass99e598e2016-02-29 15:25:54 -0700142 int count = 0;
Sven Schwermerc58ff202018-11-21 08:43:57 +0100143#if CONFIG_IS_ENABLED(BLK)
Simon Glass01f5be92016-02-29 15:25:58 -0700144 struct udevice *dev;
145
Simon Glassdbfa32c2022-08-11 19:34:59 -0600146 for (blk_first_device(UCLASS_USB, &dev);
Simon Glass01f5be92016-02-29 15:25:58 -0700147 dev;
148 blk_next_device(&dev)) {
Simon Glass71fa5b42020-12-03 16:55:18 -0700149 struct blk_desc *desc = dev_get_uclass_plat(dev);
Simon Glass01f5be92016-02-29 15:25:58 -0700150
151 printf(" Device %d: ", desc->devnum);
152 dev_print(desc);
153 count++;
154 }
155#else
Wolfgang Denkc7a4f7d2005-07-21 11:57:57 +0200156 int i;
157
Aras Vaichas7ede1862008-03-25 12:09:07 +1100158 if (usb_max_devs > 0) {
Wolfgang Denkc7a4f7d2005-07-21 11:57:57 +0200159 for (i = 0; i < usb_max_devs; i++) {
Michael Trimarchi956a4352008-12-10 15:52:06 +0100160 printf(" Device %d: ", i);
Wolfgang Denkc7a4f7d2005-07-21 11:57:57 +0200161 dev_print(&usb_dev_desc[i]);
162 }
Markus Klotzbuecher8e2a4862008-03-26 18:26:43 +0100163 return 0;
Aras Vaichas7ede1862008-03-25 12:09:07 +1100164 }
Simon Glass01f5be92016-02-29 15:25:58 -0700165#endif
Simon Glass99e598e2016-02-29 15:25:54 -0700166 if (!count) {
167 printf("No storage devices, perhaps not 'usb start'ed..?\n");
168 return 1;
169 }
170
Simon Glass8c6c0742016-03-16 07:45:44 -0600171 return 0;
Wolfgang Denkc7a4f7d2005-07-21 11:57:57 +0200172}
173
Ludovic Courtès134396c2010-10-05 22:04:26 +0200174static unsigned int usb_get_max_lun(struct us_data *us)
175{
176 int len;
Puneet Saxena6c9bb602012-04-03 14:56:06 +0530177 ALLOC_CACHE_ALIGN_BUFFER(unsigned char, result, 1);
Ludovic Courtès134396c2010-10-05 22:04:26 +0200178 len = usb_control_msg(us->pusb_dev,
179 usb_rcvctrlpipe(us->pusb_dev, 0),
180 US_BBB_GET_MAX_LUN,
181 USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
182 0, us->ifnum,
Puneet Saxena6c9bb602012-04-03 14:56:06 +0530183 result, sizeof(char),
Ludovic Courtès134396c2010-10-05 22:04:26 +0200184 USB_CNTL_TIMEOUT * 5);
Vivek Gautamf94c95d2013-04-12 16:34:33 +0530185 debug("Get Max LUN -> len = %i, result = %i\n", len, (int) *result);
Puneet Saxena6c9bb602012-04-03 14:56:06 +0530186 return (len > 0) ? *result : 0;
Ludovic Courtès134396c2010-10-05 22:04:26 +0200187}
188
Simon Glass99e598e2016-02-29 15:25:54 -0700189static int usb_stor_probe_device(struct usb_device *udev)
Simon Glassdf7d34f2015-03-25 12:22:15 -0600190{
Simon Glass99e598e2016-02-29 15:25:54 -0700191 int lun, max_lun;
Simon Glass01f5be92016-02-29 15:25:58 -0700192
Sven Schwermerc58ff202018-11-21 08:43:57 +0100193#if CONFIG_IS_ENABLED(BLK)
Simon Glass01f5be92016-02-29 15:25:58 -0700194 struct us_data *data;
Simon Glass01f5be92016-02-29 15:25:58 -0700195 int ret;
196#else
Simon Glass99e598e2016-02-29 15:25:54 -0700197 int start;
198
199 if (udev == NULL)
Simon Glassdf7d34f2015-03-25 12:22:15 -0600200 return -ENOENT; /* no more devices available */
Simon Glass01f5be92016-02-29 15:25:58 -0700201#endif
Simon Glassdf7d34f2015-03-25 12:22:15 -0600202
Simon Glass01f5be92016-02-29 15:25:58 -0700203 debug("\n\nProbing for storage\n");
Sven Schwermerc58ff202018-11-21 08:43:57 +0100204#if CONFIG_IS_ENABLED(BLK)
Simon Glass01f5be92016-02-29 15:25:58 -0700205 /*
Simon Glass71fa5b42020-12-03 16:55:18 -0700206 * We store the us_data in the mass storage device's plat. It
Simon Glass01f5be92016-02-29 15:25:58 -0700207 * is shared by all LUNs (block devices) attached to this mass storage
208 * device.
209 */
Simon Glassfa20e932020-12-03 16:55:20 -0700210 data = dev_get_plat(udev->dev);
Simon Glass01f5be92016-02-29 15:25:58 -0700211 if (!usb_storage_probe(udev, 0, data))
212 return 0;
213 max_lun = usb_get_max_lun(data);
214 for (lun = 0; lun <= max_lun; lun++) {
215 struct blk_desc *blkdev;
216 struct udevice *dev;
Simon Glass966b6952016-05-01 11:36:29 -0600217 char str[10];
Simon Glass01f5be92016-02-29 15:25:58 -0700218
Simon Glass966b6952016-05-01 11:36:29 -0600219 snprintf(str, sizeof(str), "lun%d", lun);
220 ret = blk_create_devicef(udev->dev, "usb_storage_blk", str,
Bin Meng2294ecb2023-09-26 16:43:31 +0800221 UCLASS_USB, usb_max_devs,
222 DEFAULT_BLKSZ, 0, &dev);
Simon Glass01f5be92016-02-29 15:25:58 -0700223 if (ret) {
224 debug("Cannot bind driver\n");
225 return ret;
226 }
227
Simon Glass71fa5b42020-12-03 16:55:18 -0700228 blkdev = dev_get_uclass_plat(dev);
Simon Glass01f5be92016-02-29 15:25:58 -0700229 blkdev->target = 0xff;
230 blkdev->lun = lun;
231
232 ret = usb_stor_get_info(udev, data, blkdev);
Bin Mengcbc3da82018-10-15 02:21:07 -0700233 if (ret == 1) {
Simon Glass01f5be92016-02-29 15:25:58 -0700234 usb_max_devs++;
235 debug("%s: Found device %p\n", __func__, udev);
236 } else {
237 debug("usb_stor_get_info: Invalid device\n");
238 ret = device_unbind(dev);
239 if (ret)
240 return ret;
Janne Grunau96c2d112022-11-04 08:38:59 +0100241 continue;
Simon Glass01f5be92016-02-29 15:25:58 -0700242 }
AKASHI Takahirof9c3cc82022-03-08 20:36:40 +0900243
244 ret = blk_probe_or_unbind(dev);
245 if (ret)
246 return ret;
Simon Glasse1917ef2022-04-24 23:31:23 -0600247
Simon Glassb1d581d2023-07-30 11:15:14 -0600248 ret = bootdev_setup_for_sibling_blk(dev, "usb_bootdev");
Simon Glasse1917ef2022-04-24 23:31:23 -0600249 if (ret) {
250 int ret2;
251
252 ret2 = device_unbind(dev);
253 if (ret2)
254 return log_msg_ret("bootdev", ret2);
255 return log_msg_ret("bootdev", ret);
256 }
Simon Glass01f5be92016-02-29 15:25:58 -0700257 }
258#else
Simon Glass6d74d7c2016-02-29 15:25:53 -0700259 /* We don't have space to even probe if we hit the maximum */
260 if (usb_max_devs == USB_MAX_STOR_DEV) {
261 printf("max USB Storage Device reached: %d stopping\n",
262 usb_max_devs);
263 return -ENOSPC;
264 }
265
Simon Glass99e598e2016-02-29 15:25:54 -0700266 if (!usb_storage_probe(udev, 0, &usb_stor[usb_max_devs]))
267 return 0;
Simon Glassdf7d34f2015-03-25 12:22:15 -0600268
Simon Glass99e598e2016-02-29 15:25:54 -0700269 /*
270 * OK, it's a storage device. Iterate over its LUNs and populate
271 * usb_dev_desc'
272 */
273 start = usb_max_devs;
Simon Glassdf7d34f2015-03-25 12:22:15 -0600274
Simon Glass99e598e2016-02-29 15:25:54 -0700275 max_lun = usb_get_max_lun(&usb_stor[usb_max_devs]);
276 for (lun = 0; lun <= max_lun && usb_max_devs < USB_MAX_STOR_DEV;
277 lun++) {
278 struct blk_desc *blkdev;
Simon Glassdf7d34f2015-03-25 12:22:15 -0600279
Simon Glass99e598e2016-02-29 15:25:54 -0700280 blkdev = &usb_dev_desc[usb_max_devs];
281 memset(blkdev, '\0', sizeof(struct blk_desc));
Simon Glassfada3f92022-09-17 09:00:09 -0600282 blkdev->uclass_id = UCLASS_USB;
Simon Glass99e598e2016-02-29 15:25:54 -0700283 blkdev->devnum = usb_max_devs;
284 blkdev->part_type = PART_TYPE_UNKNOWN;
285 blkdev->target = 0xff;
286 blkdev->type = DEV_TYPE_UNKNOWN;
287 blkdev->block_read = usb_stor_read;
288 blkdev->block_write = usb_stor_write;
289 blkdev->lun = lun;
290 blkdev->priv = udev;
291
292 if (usb_stor_get_info(udev, &usb_stor[start],
293 &usb_dev_desc[usb_max_devs]) == 1) {
Simon Glass01f5be92016-02-29 15:25:58 -0700294 debug("partype: %d\n", blkdev->part_type);
295 part_init(blkdev);
296 debug("partype: %d\n", blkdev->part_type);
Simon Glass99e598e2016-02-29 15:25:54 -0700297 usb_max_devs++;
298 debug("%s: Found device %p\n", __func__, udev);
Simon Glassdf7d34f2015-03-25 12:22:15 -0600299 }
300 }
Simon Glass01f5be92016-02-29 15:25:58 -0700301#endif
Simon Glassdf7d34f2015-03-25 12:22:15 -0600302
Simon Glassdf7d34f2015-03-25 12:22:15 -0600303 return 0;
304}
305
306void usb_stor_reset(void)
307{
308 usb_max_devs = 0;
309}
310
Michael Trimarchi956a4352008-12-10 15:52:06 +0100311/*******************************************************************************
Wolfgang Denkc7a4f7d2005-07-21 11:57:57 +0200312 * scan the usb and reports device info
wdenkaffae2b2002-08-17 09:36:01 +0000313 * to the user if mode = 1
314 * returns current device or -1 if no
315 */
316int usb_stor_scan(int mode)
317{
Michael Trimarchi956a4352008-12-10 15:52:06 +0100318 if (mode == 1)
Lucas Stache6d33452012-09-26 00:14:36 +0200319 printf(" scanning usb for storage devices... ");
Michael Trimarchi956a4352008-12-10 15:52:06 +0100320
Sven Schwermer8a3cb9f12018-11-21 08:43:56 +0100321#if !CONFIG_IS_ENABLED(DM_USB)
Michal Simekcd8f86f2016-12-21 09:35:08 +0100322 unsigned char i;
323
wdenkaffae2b2002-08-17 09:36:01 +0000324 usb_disable_asynch(1); /* asynch transfer not allowed */
325
Simon Glassdf7d34f2015-03-25 12:22:15 -0600326 usb_stor_reset();
Michael Trimarchi956a4352008-12-10 15:52:06 +0100327 for (i = 0; i < USB_MAX_DEVICE; i++) {
Simon Glassdf7d34f2015-03-25 12:22:15 -0600328 struct usb_device *dev;
329
Michael Trimarchi956a4352008-12-10 15:52:06 +0100330 dev = usb_get_dev_index(i); /* get device */
Vivek Gautamf94c95d2013-04-12 16:34:33 +0530331 debug("i=%d\n", i);
Simon Glassdf7d34f2015-03-25 12:22:15 -0600332 if (usb_stor_probe_device(dev))
wdenkaffae2b2002-08-17 09:36:01 +0000333 break;
wdenkaffae2b2002-08-17 09:36:01 +0000334 } /* for */
Wolfgang Denkd06ce5d2005-08-02 17:06:17 +0200335
wdenkaffae2b2002-08-17 09:36:01 +0000336 usb_disable_asynch(0); /* asynch transfer allowed */
Michal Simekcd8f86f2016-12-21 09:35:08 +0100337#endif
Wolfgang Denkc7a4f7d2005-07-21 11:57:57 +0200338 printf("%d Storage Device(s) found\n", usb_max_devs);
Michael Trimarchi956a4352008-12-10 15:52:06 +0100339 if (usb_max_devs > 0)
wdenkaffae2b2002-08-17 09:36:01 +0000340 return 0;
Michael Trimarchi956a4352008-12-10 15:52:06 +0100341 return -1;
wdenkaffae2b2002-08-17 09:36:01 +0000342}
343
344static int usb_stor_irq(struct usb_device *dev)
345{
346 struct us_data *us;
Michael Trimarchi956a4352008-12-10 15:52:06 +0100347 us = (struct us_data *)dev->privptr;
wdenkaffae2b2002-08-17 09:36:01 +0000348
Michael Trimarchi956a4352008-12-10 15:52:06 +0100349 if (us->ip_wanted)
350 us->ip_wanted = 0;
wdenkaffae2b2002-08-17 09:36:01 +0000351 return 0;
352}
353
Vivek Gautamf94c95d2013-04-12 16:34:33 +0530354#ifdef DEBUG
wdenkaffae2b2002-08-17 09:36:01 +0000355
Simon Glass5fb559d2017-06-14 21:28:30 -0600356static void usb_show_srb(struct scsi_cmd *pccb)
wdenkaffae2b2002-08-17 09:36:01 +0000357{
358 int i;
Michael Trimarchi956a4352008-12-10 15:52:06 +0100359 printf("SRB: len %d datalen 0x%lX\n ", pccb->cmdlen, pccb->datalen);
Hector Martin7b3d10d2023-10-29 16:23:30 +0900360 for (i = 0; i < pccb->cmdlen; i++)
Michael Trimarchi956a4352008-12-10 15:52:06 +0100361 printf("%02X ", pccb->cmd[i]);
wdenkaffae2b2002-08-17 09:36:01 +0000362 printf("\n");
363}
364
365static void display_int_status(unsigned long tmp)
366{
367 printf("Status: %s %s %s %s %s %s %s\n",
368 (tmp & USB_ST_ACTIVE) ? "Active" : "",
369 (tmp & USB_ST_STALLED) ? "Stalled" : "",
370 (tmp & USB_ST_BUF_ERR) ? "Buffer Error" : "",
371 (tmp & USB_ST_BABBLE_DET) ? "Babble Det" : "",
372 (tmp & USB_ST_NAK_REC) ? "NAKed" : "",
373 (tmp & USB_ST_CRC_ERR) ? "CRC Error" : "",
374 (tmp & USB_ST_BIT_ERR) ? "Bitstuff Error" : "");
375}
376#endif
377/***********************************************************************
378 * Data transfer routines
379 ***********************************************************************/
380
381static int us_one_transfer(struct us_data *us, int pipe, char *buf, int length)
382{
383 int max_size;
384 int this_xfer;
385 int result;
386 int partial;
387 int maxtry;
388 int stat;
389
390 /* determine the maximum packet size for these transfers */
391 max_size = usb_maxpacket(us->pusb_dev, pipe) * 16;
392
393 /* while we have data left to transfer */
394 while (length) {
395
396 /* calculate how long this will be -- maximum or a remainder */
397 this_xfer = length > max_size ? max_size : length;
398 length -= this_xfer;
399
400 /* setup the retry counter */
401 maxtry = 10;
402
403 /* set up the transfer loop */
404 do {
405 /* transfer the data */
Simon Glass332a9b62015-03-25 12:22:14 -0600406 debug("Bulk xfer 0x%lx(%d) try #%d\n",
407 (ulong)map_to_sysmem(buf), this_xfer,
408 11 - maxtry);
wdenkaffae2b2002-08-17 09:36:01 +0000409 result = usb_bulk_msg(us->pusb_dev, pipe, buf,
Michael Trimarchi956a4352008-12-10 15:52:06 +0100410 this_xfer, &partial,
411 USB_CNTL_TIMEOUT * 5);
Vivek Gautamf94c95d2013-04-12 16:34:33 +0530412 debug("bulk_msg returned %d xferred %d/%d\n",
413 result, partial, this_xfer);
Michael Trimarchi956a4352008-12-10 15:52:06 +0100414 if (us->pusb_dev->status != 0) {
415 /* if we stall, we need to clear it before
416 * we go on
417 */
Vivek Gautamf94c95d2013-04-12 16:34:33 +0530418#ifdef DEBUG
wdenkaffae2b2002-08-17 09:36:01 +0000419 display_int_status(us->pusb_dev->status);
420#endif
421 if (us->pusb_dev->status & USB_ST_STALLED) {
Vivek Gautamf94c95d2013-04-12 16:34:33 +0530422 debug("stalled ->clearing endpoint" \
423 "halt for pipe 0x%x\n", pipe);
wdenkaffae2b2002-08-17 09:36:01 +0000424 stat = us->pusb_dev->status;
425 usb_clear_halt(us->pusb_dev, pipe);
Michael Trimarchi956a4352008-12-10 15:52:06 +0100426 us->pusb_dev->status = stat;
427 if (this_xfer == partial) {
Vivek Gautamf94c95d2013-04-12 16:34:33 +0530428 debug("bulk transferred" \
429 "with error %lX," \
430 " but data ok\n",
431 us->pusb_dev->status);
wdenkaffae2b2002-08-17 09:36:01 +0000432 return 0;
433 }
434 else
435 return result;
436 }
437 if (us->pusb_dev->status & USB_ST_NAK_REC) {
Vivek Gautamf94c95d2013-04-12 16:34:33 +0530438 debug("Device NAKed bulk_msg\n");
wdenkaffae2b2002-08-17 09:36:01 +0000439 return result;
440 }
Vivek Gautamf94c95d2013-04-12 16:34:33 +0530441 debug("bulk transferred with error");
Michael Trimarchi956a4352008-12-10 15:52:06 +0100442 if (this_xfer == partial) {
Vivek Gautamf94c95d2013-04-12 16:34:33 +0530443 debug(" %ld, but data ok\n",
444 us->pusb_dev->status);
wdenkaffae2b2002-08-17 09:36:01 +0000445 return 0;
446 }
447 /* if our try counter reaches 0, bail out */
Michal Simekcfd8a6e2020-12-01 14:02:58 +0100448 debug(" %ld, data %d\n",
449 us->pusb_dev->status, partial);
wdenkaffae2b2002-08-17 09:36:01 +0000450 if (!maxtry--)
451 return result;
452 }
453 /* update to show what data was transferred */
454 this_xfer -= partial;
455 buf += partial;
456 /* continue until this transfer is done */
Michael Trimarchi956a4352008-12-10 15:52:06 +0100457 } while (this_xfer);
wdenkaffae2b2002-08-17 09:36:01 +0000458 }
459
460 /* if we get here, we're done and successful */
461 return 0;
462}
463
wdenkde887eb2003-09-10 18:20:28 +0000464static int usb_stor_BBB_reset(struct us_data *us)
465{
466 int result;
467 unsigned int pipe;
468
469 /*
470 * Reset recovery (5.3.4 in Universal Serial Bus Mass Storage Class)
471 *
472 * For Reset Recovery the host shall issue in the following order:
473 * a) a Bulk-Only Mass Storage Reset
474 * b) a Clear Feature HALT to the Bulk-In endpoint
475 * c) a Clear Feature HALT to the Bulk-Out endpoint
476 *
477 * This is done in 3 steps.
478 *
479 * If the reset doesn't succeed, the device should be port reset.
480 *
481 * This comment stolen from FreeBSD's /sys/dev/usb/umass.c.
482 */
Vivek Gautamf94c95d2013-04-12 16:34:33 +0530483 debug("BBB_reset\n");
Michael Trimarchi956a4352008-12-10 15:52:06 +0100484 result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev, 0),
485 US_BBB_RESET,
486 USB_TYPE_CLASS | USB_RECIP_INTERFACE,
Kim Phillipsb052b602012-10-29 13:34:32 +0000487 0, us->ifnum, NULL, 0, USB_CNTL_TIMEOUT * 5);
Wolfgang Denkc7a4f7d2005-07-21 11:57:57 +0200488
Michael Trimarchi956a4352008-12-10 15:52:06 +0100489 if ((result < 0) && (us->pusb_dev->status & USB_ST_STALLED)) {
Vivek Gautamf94c95d2013-04-12 16:34:33 +0530490 debug("RESET:stall\n");
wdenkde887eb2003-09-10 18:20:28 +0000491 return -1;
492 }
Wolfgang Denkc7a4f7d2005-07-21 11:57:57 +0200493
wdenkde887eb2003-09-10 18:20:28 +0000494 /* long wait for reset */
Mike Frysinger60ce19a2012-03-05 13:47:00 +0000495 mdelay(150);
Vivek Gautamf94c95d2013-04-12 16:34:33 +0530496 debug("BBB_reset result %d: status %lX reset\n",
497 result, us->pusb_dev->status);
wdenkde887eb2003-09-10 18:20:28 +0000498 pipe = usb_rcvbulkpipe(us->pusb_dev, us->ep_in);
499 result = usb_clear_halt(us->pusb_dev, pipe);
500 /* long wait for reset */
Mike Frysinger60ce19a2012-03-05 13:47:00 +0000501 mdelay(150);
Vivek Gautamf94c95d2013-04-12 16:34:33 +0530502 debug("BBB_reset result %d: status %lX clearing IN endpoint\n",
503 result, us->pusb_dev->status);
wdenkde887eb2003-09-10 18:20:28 +0000504 /* long wait for reset */
505 pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out);
506 result = usb_clear_halt(us->pusb_dev, pipe);
Mike Frysinger60ce19a2012-03-05 13:47:00 +0000507 mdelay(150);
Vivek Gautamf94c95d2013-04-12 16:34:33 +0530508 debug("BBB_reset result %d: status %lX clearing OUT endpoint\n",
509 result, us->pusb_dev->status);
510 debug("BBB_reset done\n");
wdenkde887eb2003-09-10 18:20:28 +0000511 return 0;
512}
513
wdenkaffae2b2002-08-17 09:36:01 +0000514/* FIXME: this reset function doesn't really reset the port, and it
515 * should. Actually it should probably do what it's doing here, and
516 * reset the port physically
517 */
518static int usb_stor_CB_reset(struct us_data *us)
519{
520 unsigned char cmd[12];
521 int result;
522
Vivek Gautamf94c95d2013-04-12 16:34:33 +0530523 debug("CB_reset\n");
Michael Trimarchi956a4352008-12-10 15:52:06 +0100524 memset(cmd, 0xff, sizeof(cmd));
wdenkaffae2b2002-08-17 09:36:01 +0000525 cmd[0] = SCSI_SEND_DIAG;
526 cmd[1] = 4;
Michael Trimarchi956a4352008-12-10 15:52:06 +0100527 result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev, 0),
528 US_CBI_ADSC,
529 USB_TYPE_CLASS | USB_RECIP_INTERFACE,
530 0, us->ifnum, cmd, sizeof(cmd),
531 USB_CNTL_TIMEOUT * 5);
wdenkaffae2b2002-08-17 09:36:01 +0000532
533 /* long wait for reset */
Mike Frysinger60ce19a2012-03-05 13:47:00 +0000534 mdelay(1500);
Vivek Gautamf94c95d2013-04-12 16:34:33 +0530535 debug("CB_reset result %d: status %lX clearing endpoint halt\n",
536 result, us->pusb_dev->status);
wdenkaffae2b2002-08-17 09:36:01 +0000537 usb_clear_halt(us->pusb_dev, usb_rcvbulkpipe(us->pusb_dev, us->ep_in));
538 usb_clear_halt(us->pusb_dev, usb_rcvbulkpipe(us->pusb_dev, us->ep_out));
539
Vivek Gautamf94c95d2013-04-12 16:34:33 +0530540 debug("CB_reset done\n");
wdenkaffae2b2002-08-17 09:36:01 +0000541 return 0;
542}
543
wdenkde887eb2003-09-10 18:20:28 +0000544/*
545 * Set up the command for a BBB device. Note that the actual SCSI
546 * command is copied into cbw.CBWCDB.
547 */
Simon Glass5fb559d2017-06-14 21:28:30 -0600548static int usb_stor_BBB_comdat(struct scsi_cmd *srb, struct us_data *us)
wdenkde887eb2003-09-10 18:20:28 +0000549{
550 int result;
551 int actlen;
552 int dir_in;
553 unsigned int pipe;
Simon Glass6f414652015-03-25 12:22:11 -0600554 ALLOC_CACHE_ALIGN_BUFFER(struct umass_bbb_cbw, cbw, 1);
wdenkde887eb2003-09-10 18:20:28 +0000555
556 dir_in = US_DIRECTION(srb->cmd[0]);
557
558#ifdef BBB_COMDAT_TRACE
Vivek Gautam23cbd292013-04-12 16:34:34 +0530559 printf("dir %d lun %d cmdlen %d cmd %p datalen %lu pdata %p\n",
Michael Trimarchi956a4352008-12-10 15:52:06 +0100560 dir_in, srb->lun, srb->cmdlen, srb->cmd, srb->datalen,
561 srb->pdata);
wdenkde887eb2003-09-10 18:20:28 +0000562 if (srb->cmdlen) {
Michael Trimarchi956a4352008-12-10 15:52:06 +0100563 for (result = 0; result < srb->cmdlen; result++)
wdenkde887eb2003-09-10 18:20:28 +0000564 printf("cmd[%d] %#x ", result, srb->cmd[result]);
565 printf("\n");
566 }
567#endif
568 /* sanity checks */
569 if (!(srb->cmdlen <= CBWCDBLENGTH)) {
Vivek Gautamf94c95d2013-04-12 16:34:33 +0530570 debug("usb_stor_BBB_comdat:cmdlen too large\n");
wdenkde887eb2003-09-10 18:20:28 +0000571 return -1;
572 }
573
574 /* always OUT to the ep */
575 pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out);
576
Puneet Saxena6c9bb602012-04-03 14:56:06 +0530577 cbw->dCBWSignature = cpu_to_le32(CBWSIGNATURE);
578 cbw->dCBWTag = cpu_to_le32(CBWTag++);
579 cbw->dCBWDataTransferLength = cpu_to_le32(srb->datalen);
580 cbw->bCBWFlags = (dir_in ? CBWFLAGS_IN : CBWFLAGS_OUT);
581 cbw->bCBWLUN = srb->lun;
582 cbw->bCDBLength = srb->cmdlen;
wdenkde887eb2003-09-10 18:20:28 +0000583 /* copy the command data into the CBW command data buffer */
584 /* DST SRC LEN!!! */
Sergey Temerkhanov57236d52015-04-01 17:18:46 +0300585
Puneet Saxena6c9bb602012-04-03 14:56:06 +0530586 memcpy(cbw->CBWCDB, srb->cmd, srb->cmdlen);
587 result = usb_bulk_msg(us->pusb_dev, pipe, cbw, UMASS_BBB_CBW_SIZE,
Michael Trimarchi956a4352008-12-10 15:52:06 +0100588 &actlen, USB_CNTL_TIMEOUT * 5);
wdenkde887eb2003-09-10 18:20:28 +0000589 if (result < 0)
Vivek Gautamf94c95d2013-04-12 16:34:33 +0530590 debug("usb_stor_BBB_comdat:usb_bulk_msg error\n");
wdenkde887eb2003-09-10 18:20:28 +0000591 return result;
592}
593
wdenkaffae2b2002-08-17 09:36:01 +0000594/* FIXME: we also need a CBI_command which sets up the completion
595 * interrupt, and waits for it
596 */
Simon Glass5fb559d2017-06-14 21:28:30 -0600597static int usb_stor_CB_comdat(struct scsi_cmd *srb, struct us_data *us)
wdenkaffae2b2002-08-17 09:36:01 +0000598{
Wolfgang Denk7fb52662005-10-13 16:45:02 +0200599 int result = 0;
Michael Trimarchi956a4352008-12-10 15:52:06 +0100600 int dir_in, retry;
wdenkaffae2b2002-08-17 09:36:01 +0000601 unsigned int pipe;
602 unsigned long status;
603
Michael Trimarchi956a4352008-12-10 15:52:06 +0100604 retry = 5;
605 dir_in = US_DIRECTION(srb->cmd[0]);
wdenkaffae2b2002-08-17 09:36:01 +0000606
Michael Trimarchi956a4352008-12-10 15:52:06 +0100607 if (dir_in)
608 pipe = usb_rcvbulkpipe(us->pusb_dev, us->ep_in);
609 else
610 pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out);
611
612 while (retry--) {
Vivek Gautamf94c95d2013-04-12 16:34:33 +0530613 debug("CBI gets a command: Try %d\n", 5 - retry);
614#ifdef DEBUG
wdenkaffae2b2002-08-17 09:36:01 +0000615 usb_show_srb(srb);
616#endif
617 /* let's send the command via the control pipe */
Michael Trimarchi956a4352008-12-10 15:52:06 +0100618 result = usb_control_msg(us->pusb_dev,
619 usb_sndctrlpipe(us->pusb_dev , 0),
620 US_CBI_ADSC,
621 USB_TYPE_CLASS | USB_RECIP_INTERFACE,
wdenkaffae2b2002-08-17 09:36:01 +0000622 0, us->ifnum,
Michael Trimarchi956a4352008-12-10 15:52:06 +0100623 srb->cmd, srb->cmdlen,
624 USB_CNTL_TIMEOUT * 5);
Vivek Gautamf94c95d2013-04-12 16:34:33 +0530625 debug("CB_transport: control msg returned %d, status %lX\n",
626 result, us->pusb_dev->status);
wdenkaffae2b2002-08-17 09:36:01 +0000627 /* check the return code for the command */
628 if (result < 0) {
Michael Trimarchi956a4352008-12-10 15:52:06 +0100629 if (us->pusb_dev->status & USB_ST_STALLED) {
630 status = us->pusb_dev->status;
Vivek Gautamf94c95d2013-04-12 16:34:33 +0530631 debug(" stall during command found," \
632 " clear pipe\n");
Michael Trimarchi956a4352008-12-10 15:52:06 +0100633 usb_clear_halt(us->pusb_dev,
634 usb_sndctrlpipe(us->pusb_dev, 0));
635 us->pusb_dev->status = status;
wdenkaffae2b2002-08-17 09:36:01 +0000636 }
Vivek Gautamf94c95d2013-04-12 16:34:33 +0530637 debug(" error during command %02X" \
638 " Stat = %lX\n", srb->cmd[0],
639 us->pusb_dev->status);
wdenkaffae2b2002-08-17 09:36:01 +0000640 return result;
641 }
642 /* transfer the data payload for this command, if one exists*/
643
Vivek Gautamf94c95d2013-04-12 16:34:33 +0530644 debug("CB_transport: control msg returned %d," \
645 " direction is %s to go 0x%lx\n", result,
646 dir_in ? "IN" : "OUT", srb->datalen);
wdenkaffae2b2002-08-17 09:36:01 +0000647 if (srb->datalen) {
Michael Trimarchi956a4352008-12-10 15:52:06 +0100648 result = us_one_transfer(us, pipe, (char *)srb->pdata,
649 srb->datalen);
Vivek Gautamf94c95d2013-04-12 16:34:33 +0530650 debug("CBI attempted to transfer data," \
651 " result is %d status %lX, len %d\n",
652 result, us->pusb_dev->status,
653 us->pusb_dev->act_len);
Michael Trimarchi956a4352008-12-10 15:52:06 +0100654 if (!(us->pusb_dev->status & USB_ST_NAK_REC))
wdenkaffae2b2002-08-17 09:36:01 +0000655 break;
656 } /* if (srb->datalen) */
657 else
658 break;
659 }
660 /* return result */
661
662 return result;
663}
664
Simon Glass5fb559d2017-06-14 21:28:30 -0600665static int usb_stor_CBI_get_status(struct scsi_cmd *srb, struct us_data *us)
wdenkaffae2b2002-08-17 09:36:01 +0000666{
667 int timeout;
668
wdenk5f495752004-02-26 23:46:20 +0000669 us->ip_wanted = 1;
Michal Suchanek0089d212019-08-18 10:55:26 +0200670 usb_int_msg(us->pusb_dev, us->irqpipe,
Michal Suchanek1c95b9f2019-08-18 10:55:27 +0200671 (void *)&us->ip_data, us->irqmaxp, us->irqinterval, false);
wdenk5f495752004-02-26 23:46:20 +0000672 timeout = 1000;
673 while (timeout--) {
Sergey Temerkhanov57236d52015-04-01 17:18:46 +0300674 if (us->ip_wanted == 0)
wdenkaffae2b2002-08-17 09:36:01 +0000675 break;
Mike Frysinger60ce19a2012-03-05 13:47:00 +0000676 mdelay(10);
wdenkaffae2b2002-08-17 09:36:01 +0000677 }
678 if (us->ip_wanted) {
Michael Trimarchi956a4352008-12-10 15:52:06 +0100679 printf(" Did not get interrupt on CBI\n");
wdenkaffae2b2002-08-17 09:36:01 +0000680 us->ip_wanted = 0;
681 return USB_STOR_TRANSPORT_ERROR;
682 }
Vagrant Cascadian53d41e62016-03-15 12:16:39 -0700683 debug("Got interrupt data 0x%x, transferred %d status 0x%lX\n",
Vivek Gautamf94c95d2013-04-12 16:34:33 +0530684 us->ip_data, us->pusb_dev->irq_act_len,
685 us->pusb_dev->irq_status);
wdenkaffae2b2002-08-17 09:36:01 +0000686 /* UFI gives us ASC and ASCQ, like a request sense */
687 if (us->subclass == US_SC_UFI) {
688 if (srb->cmd[0] == SCSI_REQ_SENSE ||
689 srb->cmd[0] == SCSI_INQUIRY)
690 return USB_STOR_TRANSPORT_GOOD; /* Good */
wdenk5f495752004-02-26 23:46:20 +0000691 else if (us->ip_data)
692 return USB_STOR_TRANSPORT_FAILED;
wdenkaffae2b2002-08-17 09:36:01 +0000693 else
wdenk5f495752004-02-26 23:46:20 +0000694 return USB_STOR_TRANSPORT_GOOD;
wdenkaffae2b2002-08-17 09:36:01 +0000695 }
696 /* otherwise, we interpret the data normally */
697 switch (us->ip_data) {
wdenk5f495752004-02-26 23:46:20 +0000698 case 0x0001:
699 return USB_STOR_TRANSPORT_GOOD;
700 case 0x0002:
701 return USB_STOR_TRANSPORT_FAILED;
702 default:
703 return USB_STOR_TRANSPORT_ERROR;
704 } /* switch */
wdenkaffae2b2002-08-17 09:36:01 +0000705 return USB_STOR_TRANSPORT_ERROR;
706}
707
708#define USB_TRANSPORT_UNKNOWN_RETRY 5
709#define USB_TRANSPORT_NOT_READY_RETRY 10
710
wdenkde887eb2003-09-10 18:20:28 +0000711/* clear a stall on an endpoint - special for BBB devices */
Kim Phillipsb052b602012-10-29 13:34:32 +0000712static int usb_stor_BBB_clear_endpt_stall(struct us_data *us, __u8 endpt)
wdenkde887eb2003-09-10 18:20:28 +0000713{
wdenkde887eb2003-09-10 18:20:28 +0000714 /* ENDPOINT_HALT = 0, so set value to 0 */
Masahiro Yamada9b70df52016-09-06 22:17:35 +0900715 return usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev, 0),
716 USB_REQ_CLEAR_FEATURE, USB_RECIP_ENDPOINT, 0,
717 endpt, NULL, 0, USB_CNTL_TIMEOUT * 5);
wdenkde887eb2003-09-10 18:20:28 +0000718}
719
Simon Glass5fb559d2017-06-14 21:28:30 -0600720static int usb_stor_BBB_transport(struct scsi_cmd *srb, struct us_data *us)
wdenkde887eb2003-09-10 18:20:28 +0000721{
722 int result, retry;
723 int dir_in;
724 int actlen, data_actlen;
725 unsigned int pipe, pipein, pipeout;
Simon Glass6f414652015-03-25 12:22:11 -0600726 ALLOC_CACHE_ALIGN_BUFFER(struct umass_bbb_csw, csw, 1);
wdenkde887eb2003-09-10 18:20:28 +0000727#ifdef BBB_XPORT_TRACE
728 unsigned char *ptr;
729 int index;
730#endif
731
732 dir_in = US_DIRECTION(srb->cmd[0]);
733
734 /* COMMAND phase */
Vivek Gautamf94c95d2013-04-12 16:34:33 +0530735 debug("COMMAND phase\n");
wdenkde887eb2003-09-10 18:20:28 +0000736 result = usb_stor_BBB_comdat(srb, us);
737 if (result < 0) {
Vivek Gautamf94c95d2013-04-12 16:34:33 +0530738 debug("failed to send CBW status %ld\n",
739 us->pusb_dev->status);
wdenkde887eb2003-09-10 18:20:28 +0000740 usb_stor_BBB_reset(us);
741 return USB_STOR_TRANSPORT_FAILED;
742 }
Benoît Thébaudeaufbf909a2012-08-10 18:27:11 +0200743 if (!(us->flags & USB_READY))
744 mdelay(5);
wdenkde887eb2003-09-10 18:20:28 +0000745 pipein = usb_rcvbulkpipe(us->pusb_dev, us->ep_in);
746 pipeout = usb_sndbulkpipe(us->pusb_dev, us->ep_out);
747 /* DATA phase + error handling */
wdenkde887eb2003-09-10 18:20:28 +0000748 data_actlen = 0;
749 /* no data, go immediately to the STATUS phase */
750 if (srb->datalen == 0)
751 goto st;
Vivek Gautamf94c95d2013-04-12 16:34:33 +0530752 debug("DATA phase\n");
wdenkde887eb2003-09-10 18:20:28 +0000753 if (dir_in)
754 pipe = pipein;
755 else
756 pipe = pipeout;
Sergey Temerkhanov57236d52015-04-01 17:18:46 +0300757
Michael Trimarchi956a4352008-12-10 15:52:06 +0100758 result = usb_bulk_msg(us->pusb_dev, pipe, srb->pdata, srb->datalen,
759 &data_actlen, USB_CNTL_TIMEOUT * 5);
wdenkde887eb2003-09-10 18:20:28 +0000760 /* special handling of STALL in DATA phase */
Michael Trimarchi956a4352008-12-10 15:52:06 +0100761 if ((result < 0) && (us->pusb_dev->status & USB_ST_STALLED)) {
Vivek Gautamf94c95d2013-04-12 16:34:33 +0530762 debug("DATA:stall\n");
wdenkde887eb2003-09-10 18:20:28 +0000763 /* clear the STALL on the endpoint */
Michael Trimarchi956a4352008-12-10 15:52:06 +0100764 result = usb_stor_BBB_clear_endpt_stall(us,
765 dir_in ? us->ep_in : us->ep_out);
wdenkde887eb2003-09-10 18:20:28 +0000766 if (result >= 0)
767 /* continue on to STATUS phase */
768 goto st;
769 }
770 if (result < 0) {
Vivek Gautamf94c95d2013-04-12 16:34:33 +0530771 debug("usb_bulk_msg error status %ld\n",
772 us->pusb_dev->status);
wdenkde887eb2003-09-10 18:20:28 +0000773 usb_stor_BBB_reset(us);
774 return USB_STOR_TRANSPORT_FAILED;
775 }
776#ifdef BBB_XPORT_TRACE
777 for (index = 0; index < data_actlen; index++)
778 printf("pdata[%d] %#x ", index, srb->pdata[index]);
779 printf("\n");
780#endif
781 /* STATUS phase + error handling */
Michael Trimarchi956a4352008-12-10 15:52:06 +0100782st:
wdenkde887eb2003-09-10 18:20:28 +0000783 retry = 0;
Michael Trimarchi956a4352008-12-10 15:52:06 +0100784again:
Vivek Gautamf94c95d2013-04-12 16:34:33 +0530785 debug("STATUS phase\n");
Puneet Saxena6c9bb602012-04-03 14:56:06 +0530786 result = usb_bulk_msg(us->pusb_dev, pipein, csw, UMASS_BBB_CSW_SIZE,
Wolfgang Denkc7a4f7d2005-07-21 11:57:57 +0200787 &actlen, USB_CNTL_TIMEOUT*5);
788
wdenkde887eb2003-09-10 18:20:28 +0000789 /* special handling of STALL in STATUS phase */
Michael Trimarchi956a4352008-12-10 15:52:06 +0100790 if ((result < 0) && (retry < 1) &&
791 (us->pusb_dev->status & USB_ST_STALLED)) {
Vivek Gautamf94c95d2013-04-12 16:34:33 +0530792 debug("STATUS:stall\n");
wdenkde887eb2003-09-10 18:20:28 +0000793 /* clear the STALL on the endpoint */
794 result = usb_stor_BBB_clear_endpt_stall(us, us->ep_in);
795 if (result >= 0 && (retry++ < 1))
796 /* do a retry */
797 goto again;
798 }
799 if (result < 0) {
Vivek Gautamf94c95d2013-04-12 16:34:33 +0530800 debug("usb_bulk_msg error status %ld\n",
801 us->pusb_dev->status);
wdenkde887eb2003-09-10 18:20:28 +0000802 usb_stor_BBB_reset(us);
803 return USB_STOR_TRANSPORT_FAILED;
804 }
805#ifdef BBB_XPORT_TRACE
Puneet Saxena6c9bb602012-04-03 14:56:06 +0530806 ptr = (unsigned char *)csw;
wdenkde887eb2003-09-10 18:20:28 +0000807 for (index = 0; index < UMASS_BBB_CSW_SIZE; index++)
808 printf("ptr[%d] %#x ", index, ptr[index]);
809 printf("\n");
810#endif
811 /* misuse pipe to get the residue */
Puneet Saxena6c9bb602012-04-03 14:56:06 +0530812 pipe = le32_to_cpu(csw->dCSWDataResidue);
wdenkde887eb2003-09-10 18:20:28 +0000813 if (pipe == 0 && srb->datalen != 0 && srb->datalen - data_actlen != 0)
814 pipe = srb->datalen - data_actlen;
Puneet Saxena6c9bb602012-04-03 14:56:06 +0530815 if (CSWSIGNATURE != le32_to_cpu(csw->dCSWSignature)) {
Vivek Gautamf94c95d2013-04-12 16:34:33 +0530816 debug("!CSWSIGNATURE\n");
wdenkde887eb2003-09-10 18:20:28 +0000817 usb_stor_BBB_reset(us);
818 return USB_STOR_TRANSPORT_FAILED;
Puneet Saxena6c9bb602012-04-03 14:56:06 +0530819 } else if ((CBWTag - 1) != le32_to_cpu(csw->dCSWTag)) {
Vivek Gautamf94c95d2013-04-12 16:34:33 +0530820 debug("!Tag\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 (csw->bCSWStatus > CSWSTATUS_PHASE) {
Vivek Gautamf94c95d2013-04-12 16:34:33 +0530824 debug(">PHASE\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;
831 } else if (data_actlen > srb->datalen) {
Vivek Gautamf94c95d2013-04-12 16:34:33 +0530832 debug("transferred %dB instead of %ldB\n",
833 data_actlen, srb->datalen);
wdenkde887eb2003-09-10 18:20:28 +0000834 return USB_STOR_TRANSPORT_FAILED;
Puneet Saxena6c9bb602012-04-03 14:56:06 +0530835 } else if (csw->bCSWStatus == CSWSTATUS_FAILED) {
Vivek Gautamf94c95d2013-04-12 16:34:33 +0530836 debug("FAILED\n");
wdenkde887eb2003-09-10 18:20:28 +0000837 return USB_STOR_TRANSPORT_FAILED;
838 }
839
840 return result;
841}
842
Simon Glass5fb559d2017-06-14 21:28:30 -0600843static int usb_stor_CB_transport(struct scsi_cmd *srb, struct us_data *us)
wdenkaffae2b2002-08-17 09:36:01 +0000844{
Michael Trimarchi956a4352008-12-10 15:52:06 +0100845 int result, status;
Simon Glass5fb559d2017-06-14 21:28:30 -0600846 struct scsi_cmd *psrb;
847 struct scsi_cmd reqsrb;
Michael Trimarchi956a4352008-12-10 15:52:06 +0100848 int retry, notready;
wdenkaffae2b2002-08-17 09:36:01 +0000849
Wolfgang Denkdc770c72008-07-14 15:19:07 +0200850 psrb = &reqsrb;
Michael Trimarchi956a4352008-12-10 15:52:06 +0100851 status = USB_STOR_TRANSPORT_GOOD;
852 retry = 0;
853 notready = 0;
wdenkaffae2b2002-08-17 09:36:01 +0000854 /* issue the command */
855do_retry:
Michael Trimarchi956a4352008-12-10 15:52:06 +0100856 result = usb_stor_CB_comdat(srb, us);
Vivek Gautamf94c95d2013-04-12 16:34:33 +0530857 debug("command / Data returned %d, status %lX\n",
858 result, us->pusb_dev->status);
wdenkaffae2b2002-08-17 09:36:01 +0000859 /* if this is an CBI Protocol, get IRQ */
Michael Trimarchi956a4352008-12-10 15:52:06 +0100860 if (us->protocol == US_PR_CBI) {
861 status = usb_stor_CBI_get_status(srb, us);
wdenkaffae2b2002-08-17 09:36:01 +0000862 /* if the status is error, report it */
Michael Trimarchi956a4352008-12-10 15:52:06 +0100863 if (status == USB_STOR_TRANSPORT_ERROR) {
Vivek Gautamf94c95d2013-04-12 16:34:33 +0530864 debug(" USB CBI Command Error\n");
wdenkaffae2b2002-08-17 09:36:01 +0000865 return status;
866 }
Michael Trimarchi956a4352008-12-10 15:52:06 +0100867 srb->sense_buf[12] = (unsigned char)(us->ip_data >> 8);
868 srb->sense_buf[13] = (unsigned char)(us->ip_data & 0xff);
869 if (!us->ip_data) {
870 /* if the status is good, report it */
871 if (status == USB_STOR_TRANSPORT_GOOD) {
Vivek Gautamf94c95d2013-04-12 16:34:33 +0530872 debug(" USB CBI Command Good\n");
wdenkaffae2b2002-08-17 09:36:01 +0000873 return status;
874 }
875 }
876 }
877 /* do we have to issue an auto request? */
878 /* HERE we have to check the result */
Michael Trimarchi956a4352008-12-10 15:52:06 +0100879 if ((result < 0) && !(us->pusb_dev->status & USB_ST_STALLED)) {
Vivek Gautamf94c95d2013-04-12 16:34:33 +0530880 debug("ERROR %lX\n", us->pusb_dev->status);
wdenkaffae2b2002-08-17 09:36:01 +0000881 us->transport_reset(us);
882 return USB_STOR_TRANSPORT_ERROR;
883 }
Michael Trimarchi956a4352008-12-10 15:52:06 +0100884 if ((us->protocol == US_PR_CBI) &&
885 ((srb->cmd[0] == SCSI_REQ_SENSE) ||
886 (srb->cmd[0] == SCSI_INQUIRY))) {
887 /* do not issue an autorequest after request sense */
Vivek Gautamf94c95d2013-04-12 16:34:33 +0530888 debug("No auto request and good\n");
wdenkaffae2b2002-08-17 09:36:01 +0000889 return USB_STOR_TRANSPORT_GOOD;
890 }
891 /* issue an request_sense */
Michael Trimarchi956a4352008-12-10 15:52:06 +0100892 memset(&psrb->cmd[0], 0, 12);
893 psrb->cmd[0] = SCSI_REQ_SENSE;
894 psrb->cmd[1] = srb->lun << 5;
895 psrb->cmd[4] = 18;
896 psrb->datalen = 18;
Wolfgang Denkdc770c72008-07-14 15:19:07 +0200897 psrb->pdata = &srb->sense_buf[0];
Hector Martin7b3d10d2023-10-29 16:23:30 +0900898 psrb->cmdlen = us->cmd12 ? 12 : 6;
wdenkaffae2b2002-08-17 09:36:01 +0000899 /* issue the command */
Michael Trimarchi956a4352008-12-10 15:52:06 +0100900 result = usb_stor_CB_comdat(psrb, us);
Vivek Gautamf94c95d2013-04-12 16:34:33 +0530901 debug("auto request returned %d\n", result);
wdenkaffae2b2002-08-17 09:36:01 +0000902 /* if this is an CBI Protocol, get IRQ */
Michael Trimarchi956a4352008-12-10 15:52:06 +0100903 if (us->protocol == US_PR_CBI)
904 status = usb_stor_CBI_get_status(psrb, us);
905
906 if ((result < 0) && !(us->pusb_dev->status & USB_ST_STALLED)) {
Vivek Gautamf94c95d2013-04-12 16:34:33 +0530907 debug(" AUTO REQUEST ERROR %ld\n",
908 us->pusb_dev->status);
wdenkaffae2b2002-08-17 09:36:01 +0000909 return USB_STOR_TRANSPORT_ERROR;
910 }
Vivek Gautamf94c95d2013-04-12 16:34:33 +0530911 debug("autorequest returned 0x%02X 0x%02X 0x%02X 0x%02X\n",
912 srb->sense_buf[0], srb->sense_buf[2],
913 srb->sense_buf[12], srb->sense_buf[13]);
wdenkaffae2b2002-08-17 09:36:01 +0000914 /* Check the auto request result */
Michael Trimarchi956a4352008-12-10 15:52:06 +0100915 if ((srb->sense_buf[2] == 0) &&
916 (srb->sense_buf[12] == 0) &&
917 (srb->sense_buf[13] == 0)) {
918 /* ok, no sense */
wdenkaffae2b2002-08-17 09:36:01 +0000919 return USB_STOR_TRANSPORT_GOOD;
Michael Trimarchi956a4352008-12-10 15:52:06 +0100920 }
921
wdenkaffae2b2002-08-17 09:36:01 +0000922 /* Check the auto request result */
Michael Trimarchi956a4352008-12-10 15:52:06 +0100923 switch (srb->sense_buf[2]) {
924 case 0x01:
925 /* Recovered Error */
wdenkde887eb2003-09-10 18:20:28 +0000926 return USB_STOR_TRANSPORT_GOOD;
wdenk5f495752004-02-26 23:46:20 +0000927 break;
Michael Trimarchi956a4352008-12-10 15:52:06 +0100928 case 0x02:
929 /* Not Ready */
930 if (notready++ > USB_TRANSPORT_NOT_READY_RETRY) {
931 printf("cmd 0x%02X returned 0x%02X 0x%02X 0x%02X"
932 " 0x%02X (NOT READY)\n", srb->cmd[0],
933 srb->sense_buf[0], srb->sense_buf[2],
934 srb->sense_buf[12], srb->sense_buf[13]);
wdenkde887eb2003-09-10 18:20:28 +0000935 return USB_STOR_TRANSPORT_FAILED;
936 } else {
Mike Frysinger60ce19a2012-03-05 13:47:00 +0000937 mdelay(100);
wdenkde887eb2003-09-10 18:20:28 +0000938 goto do_retry;
939 }
940 break;
941 default:
Michael Trimarchi956a4352008-12-10 15:52:06 +0100942 if (retry++ > USB_TRANSPORT_UNKNOWN_RETRY) {
943 printf("cmd 0x%02X returned 0x%02X 0x%02X 0x%02X"
944 " 0x%02X\n", srb->cmd[0], srb->sense_buf[0],
945 srb->sense_buf[2], srb->sense_buf[12],
946 srb->sense_buf[13]);
wdenkde887eb2003-09-10 18:20:28 +0000947 return USB_STOR_TRANSPORT_FAILED;
Michael Trimarchi956a4352008-12-10 15:52:06 +0100948 } else
wdenkde887eb2003-09-10 18:20:28 +0000949 goto do_retry;
wdenkde887eb2003-09-10 18:20:28 +0000950 break;
wdenkaffae2b2002-08-17 09:36:01 +0000951 }
952 return USB_STOR_TRANSPORT_FAILED;
953}
954
Bin Meng9f447112017-09-07 06:13:21 -0700955static void usb_stor_set_max_xfer_blk(struct usb_device *udev,
956 struct us_data *us)
Bin Mengf6e373e2017-09-07 06:13:20 -0700957{
Bin Mengf6e373e2017-09-07 06:13:20 -0700958 /*
Marek Vasutcc93ffd2019-09-16 00:16:25 +0200959 * Limit the total size of a transfer to 120 KB.
960 *
961 * Some devices are known to choke with anything larger. It seems like
962 * the problem stems from the fact that original IDE controllers had
963 * only an 8-bit register to hold the number of sectors in one transfer
964 * and even those couldn't handle a full 256 sectors.
965 *
966 * Because we want to make sure we interoperate with as many devices as
967 * possible, we will maintain a 240 sector transfer size limit for USB
968 * Mass Storage devices.
969 *
970 * Tests show that other operating have similar limits with Microsoft
971 * Windows 7 limiting transfers to 128 sectors for both USB2 and USB3
972 * and Apple Mac OS X 10.11 limiting transfers to 256 sectors for USB2
973 * and 2048 for USB3 devices.
Bin Mengf6e373e2017-09-07 06:13:20 -0700974 */
Marek Vasutcc93ffd2019-09-16 00:16:25 +0200975 unsigned short blk = 240;
976
977#if CONFIG_IS_ENABLED(DM_USB)
978 size_t size;
979 int ret;
980
Bin Meng9f447112017-09-07 06:13:21 -0700981 ret = usb_get_max_xfer_size(udev, (size_t *)&size);
Marek Vasutcc93ffd2019-09-16 00:16:25 +0200982 if ((ret >= 0) && (size < blk * 512))
Bin Meng9f447112017-09-07 06:13:21 -0700983 blk = size / 512;
Bin Meng9f447112017-09-07 06:13:21 -0700984#endif
Bin Mengf6e373e2017-09-07 06:13:20 -0700985
986 us->max_xfer_blk = blk;
987}
wdenkaffae2b2002-08-17 09:36:01 +0000988
Simon Glass5fb559d2017-06-14 21:28:30 -0600989static int usb_inquiry(struct scsi_cmd *srb, struct us_data *ss)
wdenkaffae2b2002-08-17 09:36:01 +0000990{
Michael Trimarchi956a4352008-12-10 15:52:06 +0100991 int retry, i;
992 retry = 5;
wdenkaffae2b2002-08-17 09:36:01 +0000993 do {
Michael Trimarchi956a4352008-12-10 15:52:06 +0100994 memset(&srb->cmd[0], 0, 12);
995 srb->cmd[0] = SCSI_INQUIRY;
Ludovic Courtès134396c2010-10-05 22:04:26 +0200996 srb->cmd[1] = srb->lun << 5;
Michael Trimarchi956a4352008-12-10 15:52:06 +0100997 srb->cmd[4] = 36;
998 srb->datalen = 36;
Hector Martin7b3d10d2023-10-29 16:23:30 +0900999 srb->cmdlen = ss->cmd12 ? 12 : 6;
Michael Trimarchi956a4352008-12-10 15:52:06 +01001000 i = ss->transport(srb, ss);
Vivek Gautamf94c95d2013-04-12 16:34:33 +05301001 debug("inquiry returns %d\n", i);
Michael Trimarchi956a4352008-12-10 15:52:06 +01001002 if (i == 0)
wdenkaffae2b2002-08-17 09:36:01 +00001003 break;
Kim B. Heino3d42b8a2010-03-12 10:07:00 +02001004 } while (--retry);
wdenkde887eb2003-09-10 18:20:28 +00001005
Michael Trimarchi956a4352008-12-10 15:52:06 +01001006 if (!retry) {
wdenkaffae2b2002-08-17 09:36:01 +00001007 printf("error in inquiry\n");
1008 return -1;
1009 }
1010 return 0;
1011}
1012
Simon Glass5fb559d2017-06-14 21:28:30 -06001013static int usb_request_sense(struct scsi_cmd *srb, struct us_data *ss)
wdenkaffae2b2002-08-17 09:36:01 +00001014{
1015 char *ptr;
wdenk5f495752004-02-26 23:46:20 +00001016
Michael Trimarchi956a4352008-12-10 15:52:06 +01001017 ptr = (char *)srb->pdata;
1018 memset(&srb->cmd[0], 0, 12);
1019 srb->cmd[0] = SCSI_REQ_SENSE;
Ludovic Courtès134396c2010-10-05 22:04:26 +02001020 srb->cmd[1] = srb->lun << 5;
Michael Trimarchi956a4352008-12-10 15:52:06 +01001021 srb->cmd[4] = 18;
1022 srb->datalen = 18;
Wolfgang Denkdc770c72008-07-14 15:19:07 +02001023 srb->pdata = &srb->sense_buf[0];
Hector Martin7b3d10d2023-10-29 16:23:30 +09001024 srb->cmdlen = ss->cmd12 ? 12 : 6;
Michael Trimarchi956a4352008-12-10 15:52:06 +01001025 ss->transport(srb, ss);
Vivek Gautamf94c95d2013-04-12 16:34:33 +05301026 debug("Request Sense returned %02X %02X %02X\n",
1027 srb->sense_buf[2], srb->sense_buf[12],
1028 srb->sense_buf[13]);
Michael Trimarchi956a4352008-12-10 15:52:06 +01001029 srb->pdata = (uchar *)ptr;
wdenkaffae2b2002-08-17 09:36:01 +00001030 return 0;
1031}
1032
Simon Glass5fb559d2017-06-14 21:28:30 -06001033static int usb_test_unit_ready(struct scsi_cmd *srb, struct us_data *ss)
wdenkaffae2b2002-08-17 09:36:01 +00001034{
Wolfgang Denkc7a4f7d2005-07-21 11:57:57 +02001035 int retries = 10;
wdenkde887eb2003-09-10 18:20:28 +00001036
wdenkaffae2b2002-08-17 09:36:01 +00001037 do {
Michael Trimarchi956a4352008-12-10 15:52:06 +01001038 memset(&srb->cmd[0], 0, 12);
1039 srb->cmd[0] = SCSI_TST_U_RDY;
Ludovic Courtès134396c2010-10-05 22:04:26 +02001040 srb->cmd[1] = srb->lun << 5;
Michael Trimarchi956a4352008-12-10 15:52:06 +01001041 srb->datalen = 0;
Hector Martin7b3d10d2023-10-29 16:23:30 +09001042 srb->cmdlen = ss->cmd12 ? 12 : 6;
Benoît Thébaudeaufbf909a2012-08-10 18:27:11 +02001043 if (ss->transport(srb, ss) == USB_STOR_TRANSPORT_GOOD) {
1044 ss->flags |= USB_READY;
wdenkaffae2b2002-08-17 09:36:01 +00001045 return 0;
Benoît Thébaudeaufbf909a2012-08-10 18:27:11 +02001046 }
Michael Trimarchi956a4352008-12-10 15:52:06 +01001047 usb_request_sense(srb, ss);
Vincent Palatin976b3232012-12-12 17:55:29 -08001048 /*
1049 * Check the Key Code Qualifier, if it matches
1050 * "Not Ready - medium not present"
1051 * (the sense Key equals 0x2 and the ASC is 0x3a)
1052 * return immediately as the medium being absent won't change
1053 * unless there is a user action.
1054 */
1055 if ((srb->sense_buf[2] == 0x02) &&
1056 (srb->sense_buf[12] == 0x3a))
1057 return -1;
Mike Frysinger60ce19a2012-03-05 13:47:00 +00001058 mdelay(100);
Michael Trimarchi956a4352008-12-10 15:52:06 +01001059 } while (retries--);
wdenkde887eb2003-09-10 18:20:28 +00001060
wdenkaffae2b2002-08-17 09:36:01 +00001061 return -1;
1062}
1063
Simon Glass5fb559d2017-06-14 21:28:30 -06001064static int usb_read_capacity(struct scsi_cmd *srb, struct us_data *ss)
wdenkaffae2b2002-08-17 09:36:01 +00001065{
1066 int retry;
Michael Trimarchi956a4352008-12-10 15:52:06 +01001067 /* XXX retries */
1068 retry = 3;
wdenkaffae2b2002-08-17 09:36:01 +00001069 do {
Michael Trimarchi956a4352008-12-10 15:52:06 +01001070 memset(&srb->cmd[0], 0, 12);
1071 srb->cmd[0] = SCSI_RD_CAPAC;
Ludovic Courtès134396c2010-10-05 22:04:26 +02001072 srb->cmd[1] = srb->lun << 5;
Michael Trimarchi956a4352008-12-10 15:52:06 +01001073 srb->datalen = 8;
Hector Martin7b3d10d2023-10-29 16:23:30 +09001074 srb->cmdlen = ss->cmd12 ? 12 : 10;
Michael Trimarchi956a4352008-12-10 15:52:06 +01001075 if (ss->transport(srb, ss) == USB_STOR_TRANSPORT_GOOD)
wdenkaffae2b2002-08-17 09:36:01 +00001076 return 0;
Michael Trimarchi956a4352008-12-10 15:52:06 +01001077 } while (retry--);
wdenkde887eb2003-09-10 18:20:28 +00001078
wdenkaffae2b2002-08-17 09:36:01 +00001079 return -1;
1080}
1081
Simon Glass5fb559d2017-06-14 21:28:30 -06001082static int usb_read_10(struct scsi_cmd *srb, struct us_data *ss,
1083 unsigned long start, unsigned short blocks)
wdenkaffae2b2002-08-17 09:36:01 +00001084{
Michael Trimarchi956a4352008-12-10 15:52:06 +01001085 memset(&srb->cmd[0], 0, 12);
1086 srb->cmd[0] = SCSI_READ10;
Ludovic Courtès134396c2010-10-05 22:04:26 +02001087 srb->cmd[1] = srb->lun << 5;
Michael Trimarchi956a4352008-12-10 15:52:06 +01001088 srb->cmd[2] = ((unsigned char) (start >> 24)) & 0xff;
1089 srb->cmd[3] = ((unsigned char) (start >> 16)) & 0xff;
1090 srb->cmd[4] = ((unsigned char) (start >> 8)) & 0xff;
1091 srb->cmd[5] = ((unsigned char) (start)) & 0xff;
1092 srb->cmd[7] = ((unsigned char) (blocks >> 8)) & 0xff;
1093 srb->cmd[8] = (unsigned char) blocks & 0xff;
Hector Martin7b3d10d2023-10-29 16:23:30 +09001094 srb->cmdlen = ss->cmd12 ? 12 : 10;
Vivek Gautamf94c95d2013-04-12 16:34:33 +05301095 debug("read10: start %lx blocks %x\n", start, blocks);
Michael Trimarchi956a4352008-12-10 15:52:06 +01001096 return ss->transport(srb, ss);
wdenkaffae2b2002-08-17 09:36:01 +00001097}
1098
Simon Glass5fb559d2017-06-14 21:28:30 -06001099static int usb_write_10(struct scsi_cmd *srb, struct us_data *ss,
1100 unsigned long start, unsigned short blocks)
Mahavir Jaind43a0b82009-11-03 12:22:10 +05301101{
1102 memset(&srb->cmd[0], 0, 12);
1103 srb->cmd[0] = SCSI_WRITE10;
Ludovic Courtès134396c2010-10-05 22:04:26 +02001104 srb->cmd[1] = srb->lun << 5;
Mahavir Jaind43a0b82009-11-03 12:22:10 +05301105 srb->cmd[2] = ((unsigned char) (start >> 24)) & 0xff;
1106 srb->cmd[3] = ((unsigned char) (start >> 16)) & 0xff;
1107 srb->cmd[4] = ((unsigned char) (start >> 8)) & 0xff;
1108 srb->cmd[5] = ((unsigned char) (start)) & 0xff;
1109 srb->cmd[7] = ((unsigned char) (blocks >> 8)) & 0xff;
1110 srb->cmd[8] = (unsigned char) blocks & 0xff;
Hector Martin7b3d10d2023-10-29 16:23:30 +09001111 srb->cmdlen = ss->cmd12 ? 12 : 10;
Vivek Gautamf94c95d2013-04-12 16:34:33 +05301112 debug("write10: start %lx blocks %x\n", start, blocks);
Mahavir Jaind43a0b82009-11-03 12:22:10 +05301113 return ss->transport(srb, ss);
1114}
1115
Bartlomiej Sieka9d47ad42006-08-22 10:38:18 +02001116#ifdef CONFIG_USB_BIN_FIXUP
1117/*
1118 * Some USB storage devices queried for SCSI identification data respond with
1119 * binary strings, which if output to the console freeze the terminal. The
1120 * workaround is to modify the vendor and product strings read from such
1121 * device with proper values (as reported by 'usb info').
1122 *
1123 * Vendor and product length limits are taken from the definition of
Simon Glasse3394752016-02-29 15:25:34 -07001124 * struct blk_desc in include/part.h.
Bartlomiej Sieka9d47ad42006-08-22 10:38:18 +02001125 */
1126static void usb_bin_fixup(struct usb_device_descriptor descriptor,
1127 unsigned char vendor[],
1128 unsigned char product[]) {
1129 const unsigned char max_vendor_len = 40;
1130 const unsigned char max_product_len = 20;
1131 if (descriptor.idVendor == 0x0424 && descriptor.idProduct == 0x223a) {
Michael Trimarchi956a4352008-12-10 15:52:06 +01001132 strncpy((char *)vendor, "SMSC", max_vendor_len);
1133 strncpy((char *)product, "Flash Media Cntrller",
1134 max_product_len);
Bartlomiej Sieka9d47ad42006-08-22 10:38:18 +02001135 }
1136}
1137#endif /* CONFIG_USB_BIN_FIXUP */
1138
Sven Schwermerc58ff202018-11-21 08:43:57 +01001139#if CONFIG_IS_ENABLED(BLK)
Simon Glass01f5be92016-02-29 15:25:58 -07001140static unsigned long usb_stor_read(struct udevice *dev, lbaint_t blknr,
1141 lbaint_t blkcnt, void *buffer)
1142#else
Simon Glasse3394752016-02-29 15:25:34 -07001143static unsigned long usb_stor_read(struct blk_desc *block_dev, lbaint_t blknr,
Stephen Warrene73f2962015-12-07 11:38:48 -07001144 lbaint_t blkcnt, void *buffer)
Simon Glass01f5be92016-02-29 15:25:58 -07001145#endif
wdenkaffae2b2002-08-17 09:36:01 +00001146{
Gabe Black7d077682012-10-12 14:26:07 +00001147 lbaint_t start, blks;
1148 uintptr_t buf_addr;
wdenkaffae2b2002-08-17 09:36:01 +00001149 unsigned short smallblks;
Simon Glass99e598e2016-02-29 15:25:54 -07001150 struct usb_device *udev;
Kyle Moffett6540db02011-12-21 07:08:12 +00001151 struct us_data *ss;
Simon Glass5c3c91c2015-03-25 12:22:13 -06001152 int retry;
Simon Glass5fb559d2017-06-14 21:28:30 -06001153 struct scsi_cmd *srb = &usb_ccb;
Sven Schwermerc58ff202018-11-21 08:43:57 +01001154#if CONFIG_IS_ENABLED(BLK)
Simon Glass01f5be92016-02-29 15:25:58 -07001155 struct blk_desc *block_dev;
1156#endif
wdenk0e2874cb2004-03-02 14:05:39 +00001157
1158 if (blkcnt == 0)
1159 return 0;
Michael Trimarchi956a4352008-12-10 15:52:06 +01001160 /* Setup device */
Sven Schwermerc58ff202018-11-21 08:43:57 +01001161#if CONFIG_IS_ENABLED(BLK)
Simon Glass71fa5b42020-12-03 16:55:18 -07001162 block_dev = dev_get_uclass_plat(dev);
Simon Glass01f5be92016-02-29 15:25:58 -07001163 udev = dev_get_parent_priv(dev_get_parent(dev));
1164 debug("\nusb_read: udev %d\n", block_dev->devnum);
1165#else
Simon Glass99e598e2016-02-29 15:25:54 -07001166 debug("\nusb_read: udev %d\n", block_dev->devnum);
1167 udev = usb_dev_desc[block_dev->devnum].priv;
1168 if (!udev) {
Simon Glass5c3c91c2015-03-25 12:22:13 -06001169 debug("%s: No device\n", __func__);
1170 return 0;
wdenkaffae2b2002-08-17 09:36:01 +00001171 }
Simon Glass01f5be92016-02-29 15:25:58 -07001172#endif
Simon Glass99e598e2016-02-29 15:25:54 -07001173 ss = (struct us_data *)udev->privptr;
wdenkaffae2b2002-08-17 09:36:01 +00001174
1175 usb_disable_asynch(1); /* asynch transfer not allowed */
Marek Vasut118a9032020-04-06 14:29:44 +02001176 usb_lock_async(udev, 1);
Simon Glass99e598e2016-02-29 15:25:54 -07001177 srb->lun = block_dev->lun;
Sergey Temerkhanov57236d52015-04-01 17:18:46 +03001178 buf_addr = (uintptr_t)buffer;
Michael Trimarchi956a4352008-12-10 15:52:06 +01001179 start = blknr;
1180 blks = blkcnt;
Michael Trimarchi956a4352008-12-10 15:52:06 +01001181
Masahiro Yamadac7570a32018-08-06 20:47:40 +09001182 debug("\nusb_read: dev %d startblk " LBAF ", blccnt " LBAF " buffer %lx\n",
1183 block_dev->devnum, start, blks, buf_addr);
Michael Trimarchi956a4352008-12-10 15:52:06 +01001184
wdenkaffae2b2002-08-17 09:36:01 +00001185 do {
Michael Trimarchi956a4352008-12-10 15:52:06 +01001186 /* XXX need some comment here */
1187 retry = 2;
1188 srb->pdata = (unsigned char *)buf_addr;
Bin Mengf6e373e2017-09-07 06:13:20 -07001189 if (blks > ss->max_xfer_blk)
1190 smallblks = ss->max_xfer_blk;
Michael Trimarchi956a4352008-12-10 15:52:06 +01001191 else
1192 smallblks = (unsigned short) blks;
wdenkaffae2b2002-08-17 09:36:01 +00001193retry_it:
Bin Mengf6e373e2017-09-07 06:13:20 -07001194 if (smallblks == ss->max_xfer_blk)
wdenkaffae2b2002-08-17 09:36:01 +00001195 usb_show_progress();
Simon Glass99e598e2016-02-29 15:25:54 -07001196 srb->datalen = block_dev->blksz * smallblks;
Michael Trimarchi956a4352008-12-10 15:52:06 +01001197 srb->pdata = (unsigned char *)buf_addr;
Kyle Moffett6540db02011-12-21 07:08:12 +00001198 if (usb_read_10(srb, ss, start, smallblks)) {
Vivek Gautamf94c95d2013-04-12 16:34:33 +05301199 debug("Read ERROR\n");
Marek Vasut765e91a2019-10-05 19:18:38 +02001200 ss->flags &= ~USB_READY;
Kyle Moffett6540db02011-12-21 07:08:12 +00001201 usb_request_sense(srb, ss);
Michael Trimarchi956a4352008-12-10 15:52:06 +01001202 if (retry--)
wdenkaffae2b2002-08-17 09:36:01 +00001203 goto retry_it;
Michael Trimarchi956a4352008-12-10 15:52:06 +01001204 blkcnt -= blks;
wdenkaffae2b2002-08-17 09:36:01 +00001205 break;
1206 }
Michael Trimarchi956a4352008-12-10 15:52:06 +01001207 start += smallblks;
1208 blks -= smallblks;
1209 buf_addr += srb->datalen;
1210 } while (blks != 0);
1211
Masahiro Yamadac7570a32018-08-06 20:47:40 +09001212 debug("usb_read: end startblk " LBAF ", blccnt %x buffer %lx\n",
Vivek Gautamf94c95d2013-04-12 16:34:33 +05301213 start, smallblks, buf_addr);
Michael Trimarchi956a4352008-12-10 15:52:06 +01001214
Marek Vasut118a9032020-04-06 14:29:44 +02001215 usb_lock_async(udev, 0);
wdenkaffae2b2002-08-17 09:36:01 +00001216 usb_disable_asynch(0); /* asynch transfer allowed */
Bin Mengf6e373e2017-09-07 06:13:20 -07001217 if (blkcnt >= ss->max_xfer_blk)
Wolfgang Denk660e9a42010-07-19 11:36:59 +02001218 debug("\n");
Michael Trimarchi956a4352008-12-10 15:52:06 +01001219 return blkcnt;
wdenkaffae2b2002-08-17 09:36:01 +00001220}
1221
Sven Schwermerc58ff202018-11-21 08:43:57 +01001222#if CONFIG_IS_ENABLED(BLK)
Simon Glass01f5be92016-02-29 15:25:58 -07001223static unsigned long usb_stor_write(struct udevice *dev, lbaint_t blknr,
1224 lbaint_t blkcnt, const void *buffer)
1225#else
Simon Glasse3394752016-02-29 15:25:34 -07001226static unsigned long usb_stor_write(struct blk_desc *block_dev, lbaint_t blknr,
Stephen Warrene73f2962015-12-07 11:38:48 -07001227 lbaint_t blkcnt, const void *buffer)
Simon Glass01f5be92016-02-29 15:25:58 -07001228#endif
Mahavir Jaind43a0b82009-11-03 12:22:10 +05301229{
Gabe Black7d077682012-10-12 14:26:07 +00001230 lbaint_t start, blks;
1231 uintptr_t buf_addr;
Mahavir Jaind43a0b82009-11-03 12:22:10 +05301232 unsigned short smallblks;
Simon Glass99e598e2016-02-29 15:25:54 -07001233 struct usb_device *udev;
Kyle Moffett6540db02011-12-21 07:08:12 +00001234 struct us_data *ss;
Simon Glass5c3c91c2015-03-25 12:22:13 -06001235 int retry;
Simon Glass5fb559d2017-06-14 21:28:30 -06001236 struct scsi_cmd *srb = &usb_ccb;
Sven Schwermerc58ff202018-11-21 08:43:57 +01001237#if CONFIG_IS_ENABLED(BLK)
Simon Glass01f5be92016-02-29 15:25:58 -07001238 struct blk_desc *block_dev;
1239#endif
Mahavir Jaind43a0b82009-11-03 12:22:10 +05301240
1241 if (blkcnt == 0)
1242 return 0;
1243
Mahavir Jaind43a0b82009-11-03 12:22:10 +05301244 /* Setup device */
Sven Schwermerc58ff202018-11-21 08:43:57 +01001245#if CONFIG_IS_ENABLED(BLK)
Simon Glass71fa5b42020-12-03 16:55:18 -07001246 block_dev = dev_get_uclass_plat(dev);
Simon Glass01f5be92016-02-29 15:25:58 -07001247 udev = dev_get_parent_priv(dev_get_parent(dev));
1248 debug("\nusb_read: udev %d\n", block_dev->devnum);
1249#else
Simon Glass99e598e2016-02-29 15:25:54 -07001250 debug("\nusb_read: udev %d\n", block_dev->devnum);
1251 udev = usb_dev_desc[block_dev->devnum].priv;
1252 if (!udev) {
1253 debug("%s: No device\n", __func__);
Simon Glass5c3c91c2015-03-25 12:22:13 -06001254 return 0;
Simon Glass99e598e2016-02-29 15:25:54 -07001255 }
Simon Glass01f5be92016-02-29 15:25:58 -07001256#endif
Simon Glass99e598e2016-02-29 15:25:54 -07001257 ss = (struct us_data *)udev->privptr;
Mahavir Jaind43a0b82009-11-03 12:22:10 +05301258
1259 usb_disable_asynch(1); /* asynch transfer not allowed */
Marek Vasut118a9032020-04-06 14:29:44 +02001260 usb_lock_async(udev, 1);
Mahavir Jaind43a0b82009-11-03 12:22:10 +05301261
Simon Glass99e598e2016-02-29 15:25:54 -07001262 srb->lun = block_dev->lun;
Sergey Temerkhanov57236d52015-04-01 17:18:46 +03001263 buf_addr = (uintptr_t)buffer;
Mahavir Jaind43a0b82009-11-03 12:22:10 +05301264 start = blknr;
1265 blks = blkcnt;
Mahavir Jaind43a0b82009-11-03 12:22:10 +05301266
Masahiro Yamadac7570a32018-08-06 20:47:40 +09001267 debug("\nusb_write: dev %d startblk " LBAF ", blccnt " LBAF " buffer %lx\n",
1268 block_dev->devnum, start, blks, buf_addr);
Mahavir Jaind43a0b82009-11-03 12:22:10 +05301269
1270 do {
1271 /* If write fails retry for max retry count else
1272 * return with number of blocks written successfully.
1273 */
1274 retry = 2;
1275 srb->pdata = (unsigned char *)buf_addr;
Bin Mengf6e373e2017-09-07 06:13:20 -07001276 if (blks > ss->max_xfer_blk)
1277 smallblks = ss->max_xfer_blk;
Mahavir Jaind43a0b82009-11-03 12:22:10 +05301278 else
1279 smallblks = (unsigned short) blks;
1280retry_it:
Bin Mengf6e373e2017-09-07 06:13:20 -07001281 if (smallblks == ss->max_xfer_blk)
Mahavir Jaind43a0b82009-11-03 12:22:10 +05301282 usb_show_progress();
Simon Glass99e598e2016-02-29 15:25:54 -07001283 srb->datalen = block_dev->blksz * smallblks;
Mahavir Jaind43a0b82009-11-03 12:22:10 +05301284 srb->pdata = (unsigned char *)buf_addr;
Kyle Moffett6540db02011-12-21 07:08:12 +00001285 if (usb_write_10(srb, ss, start, smallblks)) {
Vivek Gautamf94c95d2013-04-12 16:34:33 +05301286 debug("Write ERROR\n");
Marek Vasut765e91a2019-10-05 19:18:38 +02001287 ss->flags &= ~USB_READY;
Kyle Moffett6540db02011-12-21 07:08:12 +00001288 usb_request_sense(srb, ss);
Mahavir Jaind43a0b82009-11-03 12:22:10 +05301289 if (retry--)
1290 goto retry_it;
1291 blkcnt -= blks;
1292 break;
1293 }
1294 start += smallblks;
1295 blks -= smallblks;
1296 buf_addr += srb->datalen;
1297 } while (blks != 0);
1298
Masahiro Yamadac7570a32018-08-06 20:47:40 +09001299 debug("usb_write: end startblk " LBAF ", blccnt %x buffer %lx\n",
1300 start, smallblks, buf_addr);
Mahavir Jaind43a0b82009-11-03 12:22:10 +05301301
Marek Vasut118a9032020-04-06 14:29:44 +02001302 usb_lock_async(udev, 0);
Mahavir Jaind43a0b82009-11-03 12:22:10 +05301303 usb_disable_asynch(0); /* asynch transfer allowed */
Bin Mengf6e373e2017-09-07 06:13:20 -07001304 if (blkcnt >= ss->max_xfer_blk)
Wolfgang Denk660e9a42010-07-19 11:36:59 +02001305 debug("\n");
Mahavir Jaind43a0b82009-11-03 12:22:10 +05301306 return blkcnt;
1307
1308}
wdenkaffae2b2002-08-17 09:36:01 +00001309
1310/* Probe to see if a new device is actually a Storage device */
Michael Trimarchi956a4352008-12-10 15:52:06 +01001311int usb_storage_probe(struct usb_device *dev, unsigned int ifnum,
1312 struct us_data *ss)
wdenkaffae2b2002-08-17 09:36:01 +00001313{
Tom Rix83b9e1d2009-10-31 12:37:38 -05001314 struct usb_interface *iface;
wdenkaffae2b2002-08-17 09:36:01 +00001315 int i;
Vivek Gautam23cbd292013-04-12 16:34:34 +05301316 struct usb_endpoint_descriptor *ep_desc;
wdenkaffae2b2002-08-17 09:36:01 +00001317 unsigned int flags = 0;
1318
wdenkaffae2b2002-08-17 09:36:01 +00001319 /* let's examine the device now */
1320 iface = &dev->config.if_desc[ifnum];
1321
wdenkaffae2b2002-08-17 09:36:01 +00001322 if (dev->descriptor.bDeviceClass != 0 ||
Tom Rix83b9e1d2009-10-31 12:37:38 -05001323 iface->desc.bInterfaceClass != USB_CLASS_MASS_STORAGE ||
1324 iface->desc.bInterfaceSubClass < US_SC_MIN ||
1325 iface->desc.bInterfaceSubClass > US_SC_MAX) {
Simon Glass78330d62015-03-25 12:22:12 -06001326 debug("Not mass storage\n");
wdenkaffae2b2002-08-17 09:36:01 +00001327 /* if it's not a mass storage, we go no further */
1328 return 0;
1329 }
1330
Wolfgang Denkc7a4f7d2005-07-21 11:57:57 +02001331 memset(ss, 0, sizeof(struct us_data));
1332
wdenkaffae2b2002-08-17 09:36:01 +00001333 /* At this point, we know we've got a live one */
Vivek Gautamf94c95d2013-04-12 16:34:33 +05301334 debug("\n\nUSB Mass Storage device detected\n");
wdenkaffae2b2002-08-17 09:36:01 +00001335
1336 /* Initialize the us_data structure with some useful info */
1337 ss->flags = flags;
1338 ss->ifnum = ifnum;
1339 ss->pusb_dev = dev;
1340 ss->attention_done = 0;
Tom Rinid83b89d2015-10-11 07:26:27 -04001341 ss->subclass = iface->desc.bInterfaceSubClass;
1342 ss->protocol = iface->desc.bInterfaceProtocol;
wdenkaffae2b2002-08-17 09:36:01 +00001343
1344 /* set the handler pointers based on the protocol */
Vivek Gautamf94c95d2013-04-12 16:34:33 +05301345 debug("Transport: ");
wdenkaffae2b2002-08-17 09:36:01 +00001346 switch (ss->protocol) {
1347 case US_PR_CB:
Vivek Gautamf94c95d2013-04-12 16:34:33 +05301348 debug("Control/Bulk\n");
wdenkaffae2b2002-08-17 09:36:01 +00001349 ss->transport = usb_stor_CB_transport;
1350 ss->transport_reset = usb_stor_CB_reset;
1351 break;
1352
1353 case US_PR_CBI:
Vivek Gautamf94c95d2013-04-12 16:34:33 +05301354 debug("Control/Bulk/Interrupt\n");
wdenkaffae2b2002-08-17 09:36:01 +00001355 ss->transport = usb_stor_CB_transport;
1356 ss->transport_reset = usb_stor_CB_reset;
1357 break;
wdenkde887eb2003-09-10 18:20:28 +00001358 case US_PR_BULK:
Vivek Gautamf94c95d2013-04-12 16:34:33 +05301359 debug("Bulk/Bulk/Bulk\n");
wdenkde887eb2003-09-10 18:20:28 +00001360 ss->transport = usb_stor_BBB_transport;
1361 ss->transport_reset = usb_stor_BBB_reset;
1362 break;
wdenkaffae2b2002-08-17 09:36:01 +00001363 default:
wdenk5f495752004-02-26 23:46:20 +00001364 printf("USB Storage Transport unknown / not yet implemented\n");
wdenkaffae2b2002-08-17 09:36:01 +00001365 return 0;
1366 break;
1367 }
1368
1369 /*
1370 * We are expecting a minimum of 2 endpoints - in and out (bulk).
1371 * An optional interrupt is OK (necessary for CBI protocol).
1372 * We will ignore any others.
1373 */
Tom Rix83b9e1d2009-10-31 12:37:38 -05001374 for (i = 0; i < iface->desc.bNumEndpoints; i++) {
Vivek Gautam23cbd292013-04-12 16:34:34 +05301375 ep_desc = &iface->ep_desc[i];
wdenkaffae2b2002-08-17 09:36:01 +00001376 /* is it an BULK endpoint? */
Vivek Gautam23cbd292013-04-12 16:34:34 +05301377 if ((ep_desc->bmAttributes &
Michael Trimarchi956a4352008-12-10 15:52:06 +01001378 USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK) {
Vivek Gautam23cbd292013-04-12 16:34:34 +05301379 if (ep_desc->bEndpointAddress & USB_DIR_IN)
1380 ss->ep_in = ep_desc->bEndpointAddress &
1381 USB_ENDPOINT_NUMBER_MASK;
wdenkaffae2b2002-08-17 09:36:01 +00001382 else
Michael Trimarchi956a4352008-12-10 15:52:06 +01001383 ss->ep_out =
Vivek Gautam23cbd292013-04-12 16:34:34 +05301384 ep_desc->bEndpointAddress &
wdenkaffae2b2002-08-17 09:36:01 +00001385 USB_ENDPOINT_NUMBER_MASK;
1386 }
1387
1388 /* is it an interrupt endpoint? */
Vivek Gautam23cbd292013-04-12 16:34:34 +05301389 if ((ep_desc->bmAttributes &
1390 USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT) {
1391 ss->ep_int = ep_desc->bEndpointAddress &
1392 USB_ENDPOINT_NUMBER_MASK;
1393 ss->irqinterval = ep_desc->bInterval;
wdenkaffae2b2002-08-17 09:36:01 +00001394 }
1395 }
Vivek Gautamf94c95d2013-04-12 16:34:33 +05301396 debug("Endpoints In %d Out %d Int %d\n",
1397 ss->ep_in, ss->ep_out, ss->ep_int);
wdenkaffae2b2002-08-17 09:36:01 +00001398
1399 /* Do some basic sanity checks, and bail if we find a problem */
Tom Rix83b9e1d2009-10-31 12:37:38 -05001400 if (usb_set_interface(dev, iface->desc.bInterfaceNumber, 0) ||
wdenkaffae2b2002-08-17 09:36:01 +00001401 !ss->ep_in || !ss->ep_out ||
1402 (ss->protocol == US_PR_CBI && ss->ep_int == 0)) {
Vivek Gautamf94c95d2013-04-12 16:34:33 +05301403 debug("Problems with device\n");
wdenkaffae2b2002-08-17 09:36:01 +00001404 return 0;
1405 }
1406 /* set class specific stuff */
wdenkde887eb2003-09-10 18:20:28 +00001407 /* We only handle certain protocols. Currently, these are
1408 * the only ones.
wdenk5f495752004-02-26 23:46:20 +00001409 * The SFF8070 accepts the requests used in u-boot
wdenkaffae2b2002-08-17 09:36:01 +00001410 */
wdenk5f495752004-02-26 23:46:20 +00001411 if (ss->subclass != US_SC_UFI && ss->subclass != US_SC_SCSI &&
1412 ss->subclass != US_SC_8070) {
Michael Trimarchi956a4352008-12-10 15:52:06 +01001413 printf("Sorry, protocol %d not yet supported.\n", ss->subclass);
wdenkaffae2b2002-08-17 09:36:01 +00001414 return 0;
1415 }
Hector Martin7b3d10d2023-10-29 16:23:30 +09001416
1417 /* UFI uses 12-byte commands (like RBC, unlike SCSI) */
1418 if (ss->subclass == US_SC_UFI)
1419 ss->cmd12 = true;
1420
Michael Trimarchi956a4352008-12-10 15:52:06 +01001421 if (ss->ep_int) {
1422 /* we had found an interrupt endpoint, prepare irq pipe
1423 * set up the IRQ pipe and handler
1424 */
wdenkaffae2b2002-08-17 09:36:01 +00001425 ss->irqinterval = (ss->irqinterval > 0) ? ss->irqinterval : 255;
1426 ss->irqpipe = usb_rcvintpipe(ss->pusb_dev, ss->ep_int);
1427 ss->irqmaxp = usb_maxpacket(dev, ss->irqpipe);
Michael Trimarchi956a4352008-12-10 15:52:06 +01001428 dev->irq_handle = usb_stor_irq;
wdenkaffae2b2002-08-17 09:36:01 +00001429 }
Bin Mengf6e373e2017-09-07 06:13:20 -07001430
1431 /* Set the maximum transfer size per host controller setting */
Bin Meng9f447112017-09-07 06:13:21 -07001432 usb_stor_set_max_xfer_blk(dev, ss);
Bin Mengf6e373e2017-09-07 06:13:20 -07001433
Michael Trimarchi956a4352008-12-10 15:52:06 +01001434 dev->privptr = (void *)ss;
wdenkaffae2b2002-08-17 09:36:01 +00001435 return 1;
1436}
1437
Michael Trimarchi956a4352008-12-10 15:52:06 +01001438int usb_stor_get_info(struct usb_device *dev, struct us_data *ss,
Simon Glasse3394752016-02-29 15:25:34 -07001439 struct blk_desc *dev_desc)
wdenkaffae2b2002-08-17 09:36:01 +00001440{
Michael Trimarchi956a4352008-12-10 15:52:06 +01001441 unsigned char perq, modi;
Sergey Temerkhanov57236d52015-04-01 17:18:46 +03001442 ALLOC_CACHE_ALIGN_BUFFER(u32, cap, 2);
1443 ALLOC_CACHE_ALIGN_BUFFER(u8, usb_stor_buf, 36);
1444 u32 capacity, blksz;
Simon Glass5fb559d2017-06-14 21:28:30 -06001445 struct scsi_cmd *pccb = &usb_ccb;
wdenkaffae2b2002-08-17 09:36:01 +00001446
Wolfgang Denkc7a4f7d2005-07-21 11:57:57 +02001447 pccb->pdata = usb_stor_buf;
1448
1449 dev_desc->target = dev->devnum;
1450 pccb->lun = dev_desc->lun;
Vivek Gautamf94c95d2013-04-12 16:34:33 +05301451 debug(" address %d\n", dev_desc->target);
wdenkaffae2b2002-08-17 09:36:01 +00001452
Simon Glass78330d62015-03-25 12:22:12 -06001453 if (usb_inquiry(pccb, ss)) {
1454 debug("%s: usb_inquiry() failed\n", __func__);
wdenkaffae2b2002-08-17 09:36:01 +00001455 return -1;
Simon Glass78330d62015-03-25 12:22:12 -06001456 }
Wolfgang Denkd06ce5d2005-08-02 17:06:17 +02001457
Wolfgang Denkc7a4f7d2005-07-21 11:57:57 +02001458 perq = usb_stor_buf[0];
1459 modi = usb_stor_buf[1];
Michael Trimarchi956a4352008-12-10 15:52:06 +01001460
Soeren Moche4828002014-11-08 07:02:14 +01001461 /*
1462 * Skip unknown devices (0x1f) and enclosure service devices (0x0d),
1463 * they would not respond to test_unit_ready .
1464 */
1465 if (((perq & 0x1f) == 0x1f) || ((perq & 0x1f) == 0x0d)) {
Simon Glass78330d62015-03-25 12:22:12 -06001466 debug("%s: unknown/unsupported device\n", __func__);
Michael Trimarchi956a4352008-12-10 15:52:06 +01001467 return 0;
wdenkaffae2b2002-08-17 09:36:01 +00001468 }
Michael Trimarchi956a4352008-12-10 15:52:06 +01001469 if ((modi&0x80) == 0x80) {
1470 /* drive is removable */
Wolfgang Denkc7a4f7d2005-07-21 11:57:57 +02001471 dev_desc->removable = 1;
wdenkaffae2b2002-08-17 09:36:01 +00001472 }
Sergey Temerkhanov57236d52015-04-01 17:18:46 +03001473 memcpy(dev_desc->vendor, (const void *)&usb_stor_buf[8], 8);
1474 memcpy(dev_desc->product, (const void *)&usb_stor_buf[16], 16);
1475 memcpy(dev_desc->revision, (const void *)&usb_stor_buf[32], 4);
Wolfgang Denkc7a4f7d2005-07-21 11:57:57 +02001476 dev_desc->vendor[8] = 0;
1477 dev_desc->product[16] = 0;
1478 dev_desc->revision[4] = 0;
Bartlomiej Sieka9d47ad42006-08-22 10:38:18 +02001479#ifdef CONFIG_USB_BIN_FIXUP
Michael Trimarchi956a4352008-12-10 15:52:06 +01001480 usb_bin_fixup(dev->descriptor, (uchar *)dev_desc->vendor,
1481 (uchar *)dev_desc->product);
Bartlomiej Sieka9d47ad42006-08-22 10:38:18 +02001482#endif /* CONFIG_USB_BIN_FIXUP */
Vivek Gautamf94c95d2013-04-12 16:34:33 +05301483 debug("ISO Vers %X, Response Data %X\n", usb_stor_buf[2],
1484 usb_stor_buf[3]);
Michael Trimarchi956a4352008-12-10 15:52:06 +01001485 if (usb_test_unit_ready(pccb, ss)) {
1486 printf("Device NOT ready\n"
1487 " Request Sense returned %02X %02X %02X\n",
1488 pccb->sense_buf[2], pccb->sense_buf[12],
1489 pccb->sense_buf[13]);
Troy Kisky17e45262017-04-10 18:23:11 -07001490 if (dev_desc->removable == 1)
Wolfgang Denkc7a4f7d2005-07-21 11:57:57 +02001491 dev_desc->type = perq;
Michael Trimarchi956a4352008-12-10 15:52:06 +01001492 return 0;
wdenkaffae2b2002-08-17 09:36:01 +00001493 }
Sergey Temerkhanov57236d52015-04-01 17:18:46 +03001494 pccb->pdata = (unsigned char *)cap;
Michael Trimarchi956a4352008-12-10 15:52:06 +01001495 memset(pccb->pdata, 0, 8);
1496 if (usb_read_capacity(pccb, ss) != 0) {
wdenkaffae2b2002-08-17 09:36:01 +00001497 printf("READ_CAP ERROR\n");
Marek Vasut765e91a2019-10-05 19:18:38 +02001498 ss->flags &= ~USB_READY;
Wolfgang Denkc7a4f7d2005-07-21 11:57:57 +02001499 cap[0] = 2880;
1500 cap[1] = 0x200;
wdenkaffae2b2002-08-17 09:36:01 +00001501 }
Sergey Temerkhanov57236d52015-04-01 17:18:46 +03001502 debug("Read Capacity returns: 0x%08x, 0x%08x\n", cap[0], cap[1]);
wdenkaffae2b2002-08-17 09:36:01 +00001503#if 0
Michael Trimarchi956a4352008-12-10 15:52:06 +01001504 if (cap[0] > (0x200000 * 10)) /* greater than 10 GByte */
1505 cap[0] >>= 16;
Sergey Temerkhanov57236d52015-04-01 17:18:46 +03001506
Christian Eggers4e0e8d02008-05-21 22:12:00 +02001507 cap[0] = cpu_to_be32(cap[0]);
1508 cap[1] = cpu_to_be32(cap[1]);
Sergey Temerkhanov57236d52015-04-01 17:18:46 +03001509#endif
1510
1511 capacity = be32_to_cpu(cap[0]) + 1;
1512 blksz = be32_to_cpu(cap[1]);
Christian Eggers4e0e8d02008-05-21 22:12:00 +02001513
Sergey Temerkhanov57236d52015-04-01 17:18:46 +03001514 debug("Capacity = 0x%08x, blocksz = 0x%08x\n", capacity, blksz);
1515 dev_desc->lba = capacity;
1516 dev_desc->blksz = blksz;
Egbert Eich2eec2ab2013-04-09 21:11:56 +00001517 dev_desc->log2blksz = LOG2(dev_desc->blksz);
Wolfgang Denkc7a4f7d2005-07-21 11:57:57 +02001518 dev_desc->type = perq;
Vivek Gautamf94c95d2013-04-12 16:34:33 +05301519 debug(" address %d\n", dev_desc->target);
wdenkaffae2b2002-08-17 09:36:01 +00001520
wdenkaffae2b2002-08-17 09:36:01 +00001521 return 1;
1522}
Simon Glassac9774e2015-03-25 12:22:16 -06001523
Sven Schwermer8a3cb9f12018-11-21 08:43:56 +01001524#if CONFIG_IS_ENABLED(DM_USB)
Simon Glassac9774e2015-03-25 12:22:16 -06001525
1526static int usb_mass_storage_probe(struct udevice *dev)
1527{
Simon Glassde44acf2015-09-28 23:32:01 -06001528 struct usb_device *udev = dev_get_parent_priv(dev);
Simon Glassac9774e2015-03-25 12:22:16 -06001529 int ret;
1530
1531 usb_disable_asynch(1); /* asynch transfer not allowed */
1532 ret = usb_stor_probe_device(udev);
1533 usb_disable_asynch(0); /* asynch transfer allowed */
1534
1535 return ret;
1536}
1537
1538static const struct udevice_id usb_mass_storage_ids[] = {
1539 { .compatible = "usb-mass-storage" },
1540 { }
1541};
1542
1543U_BOOT_DRIVER(usb_mass_storage) = {
1544 .name = "usb_mass_storage",
1545 .id = UCLASS_MASS_STORAGE,
1546 .of_match = usb_mass_storage_ids,
1547 .probe = usb_mass_storage_probe,
Sven Schwermerc58ff202018-11-21 08:43:57 +01001548#if CONFIG_IS_ENABLED(BLK)
Simon Glass71fa5b42020-12-03 16:55:18 -07001549 .plat_auto = sizeof(struct us_data),
Simon Glass01f5be92016-02-29 15:25:58 -07001550#endif
Simon Glassac9774e2015-03-25 12:22:16 -06001551};
1552
1553UCLASS_DRIVER(usb_mass_storage) = {
1554 .id = UCLASS_MASS_STORAGE,
1555 .name = "usb_mass_storage",
1556};
1557
1558static const struct usb_device_id mass_storage_id_table[] = {
1559 {
1560 .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS,
1561 .bInterfaceClass = USB_CLASS_MASS_STORAGE
1562 },
1563 { } /* Terminating entry */
1564};
1565
Simon Glass46952fb2015-07-06 16:47:51 -06001566U_BOOT_USB_DEVICE(usb_mass_storage, mass_storage_id_table);
Simon Glass01f5be92016-02-29 15:25:58 -07001567#endif
Simon Glassac9774e2015-03-25 12:22:16 -06001568
Sven Schwermerc58ff202018-11-21 08:43:57 +01001569#if CONFIG_IS_ENABLED(BLK)
Simon Glass01f5be92016-02-29 15:25:58 -07001570static const struct blk_ops usb_storage_ops = {
1571 .read = usb_stor_read,
1572 .write = usb_stor_write,
1573};
1574
1575U_BOOT_DRIVER(usb_storage_blk) = {
1576 .name = "usb_storage_blk",
1577 .id = UCLASS_BLK,
1578 .ops = &usb_storage_ops,
1579};
Simon Glassd3171412016-05-01 11:36:06 -06001580#else
1581U_BOOT_LEGACY_BLK(usb) = {
Simon Glassfada3f92022-09-17 09:00:09 -06001582 .uclass_idname = "usb",
1583 .uclass_id = UCLASS_USB,
Simon Glassd3171412016-05-01 11:36:06 -06001584 .max_devs = USB_MAX_STOR_DEV,
1585 .desc = usb_dev_desc,
1586};
Simon Glassac9774e2015-03-25 12:22:16 -06001587#endif