blob: d1e33022c33284281f75c522f650c7a040d05a00 [file] [log] [blame]
Patrick Georgid21f68b2008-09-02 16:06:22 +00001/*
2 * This file is part of the libpayload project.
3 *
4 * Copyright (C) 2008 coresystems GmbH
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30#include <arch/endian.h>
Jordan Crouse29061a52008-09-11 17:29:00 +000031#include <usb/usb.h>
32#include <usb/usbmsc.h>
33#include <usb/usbdisk.h>
Patrick Georgid21f68b2008-09-02 16:06:22 +000034
35enum {
36 msc_subclass_rbc = 0x1,
37 msc_subclass_mmc2 = 0x2,
38 msc_subclass_qic157 = 0x3,
39 msc_subclass_ufi = 0x4,
40 msc_subclass_sff8070i = 0x5,
41 msc_subclass_scsitrans = 0x6
42};
Stefan Reinauerb56f2d02010-03-25 22:17:36 +000043
Patrick Georgid21f68b2008-09-02 16:06:22 +000044static const char *msc_subclass_strings[7] = {
45 "(none)",
46 "RBC",
47 "MMC-2",
48 "QIC-157",
49 "UFI",
50 "SFF-8070i",
51 "SCSI transparent"
52};
53enum {
54 msc_proto_cbi_wcomp = 0x0,
55 msc_proto_cbi_wocomp = 0x1,
56 msc_proto_bulk_only = 0x50
57};
58static const char *msc_protocol_strings[0x51] = {
59 "Control/Bulk/Interrupt protocol (with command completion interrupt)",
60 "Control/Bulk/Interrupt protocol (with no command completion interrupt)",
61 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
62 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
63 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
64 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
65 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
66 "Bulk-Only Transport"
67};
68
69
70static void
71usb_msc_destroy (usbdev_t *dev)
72{
Patrick Georgi4727c072008-10-16 19:20:51 +000073 if (usbdisk_remove)
74 usbdisk_remove (dev);
Patrick Georgid21f68b2008-09-02 16:06:22 +000075 free (dev->data);
76 dev->data = 0;
77}
78
79static void
80usb_msc_poll (usbdev_t *dev)
81{
82}
83
84const int DEV_RESET = 0xff;
85const int GET_MAX_LUN = 0xfe;
86
87const unsigned int cbw_signature = 0x43425355;
88const unsigned int csw_signature = 0x53425355;
89
90typedef struct {
91 unsigned int dCBWSignature;
92 unsigned int dCBWTag;
93 unsigned int dCBWDataTransferLength;
94 unsigned char bmCBWFlags;
95 unsigned long bCBWLUN:4;
96 unsigned long:4;
97 unsigned long bCBWCBLength:5;
98 unsigned long:3;
99 unsigned char CBWCB[31 - 15];
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000100} __attribute__ ((packed)) cbw_t;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000101
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000102typedef struct {
103 unsigned int dCSWSignature;
104 unsigned int dCSWTag;
105 unsigned int dCSWDataResidue;
106 unsigned char bCSWStatus;
107} __attribute__ ((packed)) csw_t;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000108
Nico Huber79e1f2f2012-06-01 09:50:11 +0200109enum {
110 /*
111 * MSC commands can be
112 * successful,
113 * fail with proper response or
114 * fail totally, which results in detaching of the usb device.
115 * In the latter case the caller has to make sure, that he won't
116 * use the device any more.
117 */
118 MSC_COMMAND_OK = 0, MSC_COMMAND_FAIL, MSC_COMMAND_DETACHED
119};
120
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000121static int
122request_sense (usbdev_t *dev);
123
Nico Huber79e1f2f2012-06-01 09:50:11 +0200124static int
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000125reset_transport (usbdev_t *dev)
Patrick Georgid21f68b2008-09-02 16:06:22 +0000126{
127 dev_req_t dr;
128 memset (&dr, 0, sizeof (dr));
129 dr.bmRequestType = 0;
130 dr.data_dir = host_to_device;
131#ifndef QEMU
132 dr.req_type = class_type;
133 dr.req_recp = iface_recp;
134#endif
135 dr.bRequest = DEV_RESET;
136 dr.wValue = 0;
137 dr.wIndex = 0;
138 dr.wLength = 0;
Nico Huber79e1f2f2012-06-01 09:50:11 +0200139
140 /* if any of these fails, detach device, as we are lost */
141 if (dev->controller->control (dev, OUT, sizeof (dr), &dr, 0, 0) ||
142 clear_stall (MSC_INST (dev)->bulk_in) ||
143 clear_stall (MSC_INST (dev)->bulk_out)) {
144 printf ("Detaching unresponsive device.\n");
145 usb_detach_device (dev->controller, dev->address);
146 return MSC_COMMAND_DETACHED;
147 }
148 /* return fail as we are only called in case of failure */
149 return MSC_COMMAND_FAIL;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000150}
151
152/* device may stall this command, so beware! */
153static int
154get_max_luns (usbdev_t *dev)
155{
156 unsigned char luns = 75;
157 dev_req_t dr;
158 dr.bmRequestType = 0;
159 dr.data_dir = device_to_host;
160#ifndef QEMU
161 dr.req_type = class_type;
162 dr.req_recp = iface_recp;
163#endif
164 dr.bRequest = GET_MAX_LUN;
165 dr.wValue = 0;
166 dr.wIndex = 0;
167 dr.wLength = 1;
168 if (dev->controller->control (dev, IN, sizeof (dr), &dr, 1, &luns)) {
169 luns = 0; // assume only 1 lun if req fails
170 }
171 return luns;
172}
173
Nico Huber43b9f322012-05-21 14:05:41 +0200174unsigned int tag;
175unsigned char lun = 0;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000176
177static void
178wrap_cbw (cbw_t *cbw, int datalen, cbw_direction dir, const u8 *cmd,
179 int cmdlen)
180{
181 memset (cbw, 0, sizeof (cbw_t));
182
183 cbw->dCBWSignature = cbw_signature;
Nico Huber43b9f322012-05-21 14:05:41 +0200184 cbw->dCBWTag = ++tag;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000185 cbw->bCBWLUN = lun; // static value per device
186
187 cbw->dCBWDataTransferLength = datalen;
188 cbw->bmCBWFlags = dir;
189 memcpy (cbw->CBWCB, cmd, sizeof (cbw->CBWCB));
190 cbw->bCBWCBLength = cmdlen;
191}
192
Nico Huber43b9f322012-05-21 14:05:41 +0200193static int
Patrick Georgid21f68b2008-09-02 16:06:22 +0000194get_csw (endpoint_t *ep, csw_t *csw)
195{
Nico Huber43b9f322012-05-21 14:05:41 +0200196 if (ep->dev->controller->bulk (ep, sizeof (csw_t), (u8 *) csw, 1)) {
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000197 clear_stall (ep);
Nico Huber43b9f322012-05-21 14:05:41 +0200198 if (ep->dev->controller->bulk
199 (ep, sizeof (csw_t), (u8 *) csw, 1)) {
Nico Huber79e1f2f2012-06-01 09:50:11 +0200200 return reset_transport (ep->dev);
Nico Huber43b9f322012-05-21 14:05:41 +0200201 }
202 }
203 if (csw->dCSWTag != tag) {
Nico Huber79e1f2f2012-06-01 09:50:11 +0200204 return reset_transport (ep->dev);
Nico Huber43b9f322012-05-21 14:05:41 +0200205 }
Nico Huber79e1f2f2012-06-01 09:50:11 +0200206 return MSC_COMMAND_OK;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000207}
208
209static int
210execute_command (usbdev_t *dev, cbw_direction dir, const u8 *cb, int cblen,
Nico Huber79e1f2f2012-06-01 09:50:11 +0200211 u8 *buf, int buflen, int residue_ok)
Patrick Georgid21f68b2008-09-02 16:06:22 +0000212{
213 cbw_t cbw;
214 csw_t csw;
215
216 int always_succeed = 0;
217 if ((cb[0] == 0x1b) && (cb[4] == 1)) { //start command, always succeed
218 always_succeed = 1;
219 }
220 wrap_cbw (&cbw, buflen, dir, cb, cblen);
221 if (dev->controller->
222 bulk (MSC_INST (dev)->bulk_out, sizeof (cbw), (u8 *) &cbw, 0)) {
Nico Huber79e1f2f2012-06-01 09:50:11 +0200223 return reset_transport (dev);
Patrick Georgid21f68b2008-09-02 16:06:22 +0000224 }
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000225 if (buflen > 0) {
226 if (dir == cbw_direction_data_in) {
227 if (dev->controller->
228 bulk (MSC_INST (dev)->bulk_in, buflen, buf, 0)) {
229 clear_stall (MSC_INST (dev)->bulk_in);
Nico Huber79e1f2f2012-06-01 09:50:11 +0200230 return MSC_COMMAND_FAIL;
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000231 }
232 } else {
233 if (dev->controller->
234 bulk (MSC_INST (dev)->bulk_out, buflen, buf, 0)) {
235 clear_stall (MSC_INST (dev)->bulk_out);
Nico Huber79e1f2f2012-06-01 09:50:11 +0200236 return MSC_COMMAND_FAIL;
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000237 }
Patrick Georgid21f68b2008-09-02 16:06:22 +0000238 }
239 }
Nico Huber79e1f2f2012-06-01 09:50:11 +0200240 int ret = get_csw (MSC_INST (dev)->bulk_in, &csw);
241 if (ret) {
242 return ret;
243 } else if (always_succeed == 1) {
244 /* return success, regardless of message */
245 return MSC_COMMAND_OK;
246 } else if (csw.bCSWStatus == 2) {
247 /* phase error, reset transport */
248 return reset_transport (dev);
249 } else if (csw.bCSWStatus == 0) {
250 if ((csw.dCSWDataResidue == 0) || residue_ok)
251 /* no error, exit */
252 return MSC_COMMAND_OK;
253 else
254 /* missed some bytes */
255 return MSC_COMMAND_FAIL;
256 } else {
257 if (cb[0] == 0x03)
258 /* requesting sense failed, that's bad */
259 return MSC_COMMAND_FAIL;
260 /* error "check condition" or reserved error */
261 ret = request_sense (dev);
262 /* return fail or the status of request_sense if it's worse */
263 return ret ? ret : MSC_COMMAND_FAIL;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000264 }
Patrick Georgid21f68b2008-09-02 16:06:22 +0000265}
266
267typedef struct {
268 unsigned char command; //0
269 unsigned char res1; //1
270 unsigned int block; //2-5
271 unsigned char res2; //6
272 unsigned short numblocks; //7-8
273 unsigned char res3; //9 - the block is 10 bytes long
274} __attribute__ ((packed)) cmdblock_t;
275
276typedef struct {
277 unsigned char command; //0
278 unsigned char res1; //1
279 unsigned char res2; //2
280 unsigned char res3; //3
281 unsigned char lun; //4
282 unsigned char res4; //5
283} __attribute__ ((packed)) cmdblock6_t;
284
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000285/**
286 * Like readwrite_blocks, but for soft-sectors of 512b size. Converts the
287 * start and count from 512b units.
288 * Start and count must be aligned so that they match the native
289 * sector size.
290 *
291 * @param dev device to access
292 * @param start first sector to access
293 * @param n number of sectors to access
294 * @param dir direction of access: cbw_direction_data_in == read, cbw_direction_data_out == write
295 * @param buf buffer to read into or write from. Must be at least n*512 bytes
296 * @return 0 on success, 1 on failure
297 */
298int
299readwrite_blocks_512 (usbdev_t *dev, int start, int n,
300 cbw_direction dir, u8 *buf)
301{
302 int blocksize_divider = MSC_INST(dev)->blocksize / 512;
303 return readwrite_blocks (dev, start / blocksize_divider,
304 n / blocksize_divider, dir, buf);
305}
Patrick Georgid21f68b2008-09-02 16:06:22 +0000306
307/**
308 * Reads or writes a number of sequential blocks on a USB storage device.
309 * As it uses the READ(10) SCSI-2 command, it's limited to storage devices
310 * of at most 2TB. It assumes sectors of 512 bytes.
311 *
312 * @param dev device to access
313 * @param start first sector to access
314 * @param n number of sectors to access
315 * @param dir direction of access: cbw_direction_data_in == read, cbw_direction_data_out == write
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000316 * @param buf buffer to read into or write from. Must be at least n*sectorsize bytes
Patrick Georgid21f68b2008-09-02 16:06:22 +0000317 * @return 0 on success, 1 on failure
318 */
319int
320readwrite_blocks (usbdev_t *dev, int start, int n, cbw_direction dir, u8 *buf)
321{
322 cmdblock_t cb;
323 memset (&cb, 0, sizeof (cb));
324 if (dir == cbw_direction_data_in) {
325 // read
326 cb.command = 0x28;
327 } else {
328 // write
329 cb.command = 0x2a;
330 }
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000331 cb.block = htonl (start);
332 cb.numblocks = htonw (n);
Stefan Reinauer14e22772010-04-27 06:56:47 +0000333
Patrick Georgid21f68b2008-09-02 16:06:22 +0000334 return execute_command (dev, dir, (u8 *) &cb, sizeof (cb), buf,
Nico Huber79e1f2f2012-06-01 09:50:11 +0200335 n * MSC_INST(dev)->blocksize, 0)
336 != MSC_COMMAND_OK ? 1 : 0;
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000337}
338
339/* Only request it, we don't interpret it.
340 On certain errors, that's necessary to get devices out of
341 a special state called "Contingent Allegiance Condition" */
342static int
343request_sense (usbdev_t *dev)
344{
345 u8 buf[19];
346 cmdblock6_t cb;
347 memset (&cb, 0, sizeof (cb));
348 cb.command = 0x3;
Stefan Reinauer14e22772010-04-27 06:56:47 +0000349
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000350 return execute_command (dev, cbw_direction_data_in, (u8 *) &cb,
Nico Huber79e1f2f2012-06-01 09:50:11 +0200351 sizeof (cb), buf, 19, 1);
Patrick Georgid21f68b2008-09-02 16:06:22 +0000352}
353
354static int
355test_unit_ready (usbdev_t *dev)
356{
357 cmdblock6_t cb;
358 memset (&cb, 0, sizeof (cb)); // full initialization for T-U-R
359 return execute_command (dev, cbw_direction_data_out, (u8 *) &cb,
Nico Huber79e1f2f2012-06-01 09:50:11 +0200360 sizeof (cb), 0, 0, 0);
Patrick Georgid21f68b2008-09-02 16:06:22 +0000361}
362
363static int
364spin_up (usbdev_t *dev)
365{
366 cmdblock6_t cb;
367 memset (&cb, 0, sizeof (cb));
368 cb.command = 0x1b;
369 cb.lun = 1;
370 return execute_command (dev, cbw_direction_data_out, (u8 *) &cb,
Nico Huber79e1f2f2012-06-01 09:50:11 +0200371 sizeof (cb), 0, 0, 0);
Patrick Georgid21f68b2008-09-02 16:06:22 +0000372}
373
Nico Huber79e1f2f2012-06-01 09:50:11 +0200374static int
Patrick Georgid21f68b2008-09-02 16:06:22 +0000375read_capacity (usbdev_t *dev)
376{
377 cmdblock_t cb;
378 memset (&cb, 0, sizeof (cb));
379 cb.command = 0x25; // read capacity
380 u8 buf[8];
Stefan Reinauerd233f362009-04-30 16:46:12 +0000381
Mathias Krausec4716b42011-06-08 15:36:55 +0200382 debug ("Reading capacity of mass storage device.\n");
Nico Huber79e1f2f2012-06-01 09:50:11 +0200383 int count = 0, ret;
384 while (count++ < 20) {
385 switch (ret = execute_command
386 (dev, cbw_direction_data_in, (u8 *) &cb,
387 sizeof (cb), buf, 8, 0)) {
388 case MSC_COMMAND_OK:
389 break;
390 case MSC_COMMAND_FAIL:
391 continue;
392 default: /* if it's worse return */
393 return ret;
394 }
395 break;
396 }
Patrick Georgid21f68b2008-09-02 16:06:22 +0000397 if (count >= 20) {
Stefan Reinauerd233f362009-04-30 16:46:12 +0000398 // still not successful, assume 2tb in 512byte sectors, which is just the same garbage as any other number, but probably more usable.
Mathias Krausec4716b42011-06-08 15:36:55 +0200399 printf (" assuming 2 TB with 512-byte sectors as READ CAPACITY didn't answer.\n");
Patrick Georgid21f68b2008-09-02 16:06:22 +0000400 MSC_INST (dev)->numblocks = 0xffffffff;
401 MSC_INST (dev)->blocksize = 512;
402 } else {
403 MSC_INST (dev)->numblocks = ntohl (*(u32 *) buf) + 1;
404 MSC_INST (dev)->blocksize = ntohl (*(u32 *) (buf + 4));
405 }
Mathias Krausec4716b42011-06-08 15:36:55 +0200406 printf (" %d %d-byte sectors (%d MB)\n", MSC_INST (dev)->numblocks,
407 MSC_INST (dev)->blocksize,
Nico Huberc43e7362012-05-21 13:59:43 +0200408 /* round down high block counts to avoid integer overflow */
409 MSC_INST (dev)->numblocks > 1000000
410 ? (MSC_INST (dev)->numblocks / 1000) * MSC_INST (dev)->blocksize / 1000 :
Mathias Krausec4716b42011-06-08 15:36:55 +0200411 MSC_INST (dev)->numblocks * MSC_INST (dev)->blocksize / 1000 / 1000);
Nico Huber79e1f2f2012-06-01 09:50:11 +0200412 return MSC_COMMAND_OK;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000413}
414
415void
416usb_msc_init (usbdev_t *dev)
417{
418 int i, timeout;
419
420 dev->destroy = usb_msc_destroy;
421 dev->poll = usb_msc_poll;
422
423 configuration_descriptor_t *cd =
424 (configuration_descriptor_t *) dev->configuration;
425 interface_descriptor_t *interface =
426 (interface_descriptor_t *) (((char *) cd) + cd->bLength);
427
Mathias Krausec4716b42011-06-08 15:36:55 +0200428 debug (" it uses %s command set\n",
Patrick Georgid21f68b2008-09-02 16:06:22 +0000429 msc_subclass_strings[interface->bInterfaceSubClass]);
Mathias Krausec4716b42011-06-08 15:36:55 +0200430 debug (" it uses %s protocol\n",
Patrick Georgid21f68b2008-09-02 16:06:22 +0000431 msc_protocol_strings[interface->bInterfaceProtocol]);
432
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000433
434 if (interface->bInterfaceProtocol != 0x50) {
435 printf (" Protocol not supported.\n");
436 return;
437 }
438
439 if ((interface->bInterfaceSubClass != 2) && // ATAPI 8020
440 (interface->bInterfaceSubClass != 5) && // ATAPI 8070
441 (interface->bInterfaceSubClass != 6)) { // SCSI
Patrick Georgid21f68b2008-09-02 16:06:22 +0000442 /* Other protocols, such as ATAPI don't seem to be very popular. looks like ATAPI would be really easy to add, if necessary. */
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000443 printf (" Interface SubClass not supported.\n");
Patrick Georgid21f68b2008-09-02 16:06:22 +0000444 return;
445 }
446
447 dev->data = malloc (sizeof (usbmsc_inst_t));
Stefan Reinauer5fe6e232009-07-31 11:39:55 +0000448 if (!dev->data)
Patrick Georgi2e768e72011-11-04 11:50:03 +0100449 fatal("Not enough memory for USB MSC device.\n");
Stefan Reinauer5fe6e232009-07-31 11:39:55 +0000450
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000451 MSC_INST (dev)->protocol = interface->bInterfaceSubClass;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000452 MSC_INST (dev)->bulk_in = 0;
453 MSC_INST (dev)->bulk_out = 0;
454
455 for (i = 1; i <= dev->num_endp; i++) {
456 if (dev->endpoints[i].endpoint == 0)
457 continue;
458 if (dev->endpoints[i].type != BULK)
459 continue;
460 if ((dev->endpoints[i].direction == IN)
461 && (MSC_INST (dev)->bulk_in == 0))
462 MSC_INST (dev)->bulk_in = &dev->endpoints[i];
463 if ((dev->endpoints[i].direction == OUT)
464 && (MSC_INST (dev)->bulk_out == 0))
465 MSC_INST (dev)->bulk_out = &dev->endpoints[i];
466 }
467
468 if (MSC_INST (dev)->bulk_in == 0)
469 fatal ("couldn't find bulk-in endpoint");
470 if (MSC_INST (dev)->bulk_out == 0)
471 fatal ("couldn't find bulk-out endpoint");
Mathias Krausec4716b42011-06-08 15:36:55 +0200472 debug (" using endpoint %x as in, %x as out\n",
Patrick Georgid21f68b2008-09-02 16:06:22 +0000473 MSC_INST (dev)->bulk_in->endpoint,
474 MSC_INST (dev)->bulk_out->endpoint);
475
Mathias Krausec4716b42011-06-08 15:36:55 +0200476 debug (" has %d luns\n", get_max_luns (dev) + 1);
Patrick Georgid21f68b2008-09-02 16:06:22 +0000477
Mathias Krausec4716b42011-06-08 15:36:55 +0200478 printf (" Waiting for device to become ready...");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000479 timeout = 30 * 10; /* SCSI/ATA specs say we have to wait up to 30s. Ugh */
Nico Huber79e1f2f2012-06-01 09:50:11 +0200480 while (timeout--) {
481 switch (test_unit_ready (dev)) {
482 case MSC_COMMAND_OK:
483 break;
484 case MSC_COMMAND_FAIL:
485 mdelay (100);
486 if (!(timeout % 10))
487 printf (".");
488 continue;
489 default: /* if it's worse return */
490 return;
491 }
492 break;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000493 }
Nico Huber79e1f2f2012-06-01 09:50:11 +0200494 if (timeout < 0) {
Patrick Georgid21f68b2008-09-02 16:06:22 +0000495 printf ("timeout. Device not ready. Still trying...\n");
496 } else {
497 printf ("ok.\n");
498 }
499
Mathias Krausec4716b42011-06-08 15:36:55 +0200500 debug (" spin up");
Patrick Georgid21f68b2008-09-02 16:06:22 +0000501 for (i = 0; i < 30; i++) {
Mathias Krausec4716b42011-06-08 15:36:55 +0200502 debug (".");
Nico Huber79e1f2f2012-06-01 09:50:11 +0200503 switch (spin_up (dev)) {
504 case MSC_COMMAND_OK:
Mathias Krausec4716b42011-06-08 15:36:55 +0200505 debug (" OK.");
Patrick Georgid21f68b2008-09-02 16:06:22 +0000506 break;
Nico Huber79e1f2f2012-06-01 09:50:11 +0200507 case MSC_COMMAND_FAIL:
508 mdelay (100);
509 continue;
510 default: /* if it's worse return */
511 return;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000512 }
Nico Huber79e1f2f2012-06-01 09:50:11 +0200513 break;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000514 }
Mathias Krausec4716b42011-06-08 15:36:55 +0200515 debug ("\n");
Patrick Georgid21f68b2008-09-02 16:06:22 +0000516
Nico Huber79e1f2f2012-06-01 09:50:11 +0200517 if ((read_capacity (dev) == MSC_COMMAND_OK) && usbdisk_create)
Patrick Georgi4727c072008-10-16 19:20:51 +0000518 usbdisk_create (dev);
Patrick Georgid21f68b2008-09-02 16:06:22 +0000519}