blob: ffb1c939162ad78704461164d48b0b2ea4961a04 [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
Stefan Reinauer8992e532013-05-02 16:16:41 -070030//#define USB_DEBUG
Gabe Black0af03d22012-03-19 03:06:46 -070031#include <endian.h>
Jordan Crouse29061a52008-09-11 17:29:00 +000032#include <usb/usb.h>
33#include <usb/usbmsc.h>
34#include <usb/usbdisk.h>
Patrick Georgid21f68b2008-09-02 16:06:22 +000035
36enum {
37 msc_subclass_rbc = 0x1,
38 msc_subclass_mmc2 = 0x2,
39 msc_subclass_qic157 = 0x3,
40 msc_subclass_ufi = 0x4,
41 msc_subclass_sff8070i = 0x5,
42 msc_subclass_scsitrans = 0x6
43};
Stefan Reinauerb56f2d02010-03-25 22:17:36 +000044
Patrick Georgid21f68b2008-09-02 16:06:22 +000045static const char *msc_subclass_strings[7] = {
46 "(none)",
47 "RBC",
48 "MMC-2",
49 "QIC-157",
50 "UFI",
51 "SFF-8070i",
52 "SCSI transparent"
53};
54enum {
55 msc_proto_cbi_wcomp = 0x0,
56 msc_proto_cbi_wocomp = 0x1,
57 msc_proto_bulk_only = 0x50
58};
59static const char *msc_protocol_strings[0x51] = {
60 "Control/Bulk/Interrupt protocol (with command completion interrupt)",
61 "Control/Bulk/Interrupt protocol (with no command completion interrupt)",
62 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 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
67 "Bulk-Only Transport"
68};
69
70
71static void
72usb_msc_destroy (usbdev_t *dev)
73{
Nico Huber445a3a02012-06-21 10:52:49 +020074 if (dev->data) {
75 if (MSC_INST (dev)->usbdisk_created && usbdisk_remove)
76 usbdisk_remove (dev);
77 free (dev->data);
78 }
Patrick Georgid21f68b2008-09-02 16:06:22 +000079 dev->data = 0;
80}
81
82static void
83usb_msc_poll (usbdev_t *dev)
84{
85}
86
87const int DEV_RESET = 0xff;
88const int GET_MAX_LUN = 0xfe;
89
90const unsigned int cbw_signature = 0x43425355;
91const unsigned int csw_signature = 0x53425355;
92
93typedef struct {
94 unsigned int dCBWSignature;
95 unsigned int dCBWTag;
96 unsigned int dCBWDataTransferLength;
97 unsigned char bmCBWFlags;
98 unsigned long bCBWLUN:4;
99 unsigned long:4;
100 unsigned long bCBWCBLength:5;
101 unsigned long:3;
102 unsigned char CBWCB[31 - 15];
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000103} __attribute__ ((packed)) cbw_t;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000104
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000105typedef struct {
106 unsigned int dCSWSignature;
107 unsigned int dCSWTag;
108 unsigned int dCSWDataResidue;
109 unsigned char bCSWStatus;
110} __attribute__ ((packed)) csw_t;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000111
Nico Huber79e1f2f2012-06-01 09:50:11 +0200112enum {
113 /*
114 * MSC commands can be
115 * successful,
116 * fail with proper response or
117 * fail totally, which results in detaching of the usb device.
118 * In the latter case the caller has to make sure, that he won't
119 * use the device any more.
120 */
121 MSC_COMMAND_OK = 0, MSC_COMMAND_FAIL, MSC_COMMAND_DETACHED
122};
123
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000124static int
125request_sense (usbdev_t *dev);
Aaron Durbina967f412013-06-06 16:14:21 -0500126static int
127request_sense_no_media (usbdev_t *dev);
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000128
Nico Huber79e1f2f2012-06-01 09:50:11 +0200129static int
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000130reset_transport (usbdev_t *dev)
Patrick Georgid21f68b2008-09-02 16:06:22 +0000131{
132 dev_req_t dr;
133 memset (&dr, 0, sizeof (dr));
134 dr.bmRequestType = 0;
135 dr.data_dir = host_to_device;
136#ifndef QEMU
137 dr.req_type = class_type;
138 dr.req_recp = iface_recp;
139#endif
140 dr.bRequest = DEV_RESET;
141 dr.wValue = 0;
142 dr.wIndex = 0;
143 dr.wLength = 0;
Nico Huber79e1f2f2012-06-01 09:50:11 +0200144
145 /* if any of these fails, detach device, as we are lost */
146 if (dev->controller->control (dev, OUT, sizeof (dr), &dr, 0, 0) ||
147 clear_stall (MSC_INST (dev)->bulk_in) ||
148 clear_stall (MSC_INST (dev)->bulk_out)) {
Dave Frodin6bf11cf2012-12-11 13:08:07 -0700149 usb_debug ("Detaching unresponsive device.\n");
Nico Huber79e1f2f2012-06-01 09:50:11 +0200150 usb_detach_device (dev->controller, dev->address);
151 return MSC_COMMAND_DETACHED;
152 }
153 /* return fail as we are only called in case of failure */
154 return MSC_COMMAND_FAIL;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000155}
156
157/* device may stall this command, so beware! */
158static int
159get_max_luns (usbdev_t *dev)
160{
161 unsigned char luns = 75;
162 dev_req_t dr;
163 dr.bmRequestType = 0;
164 dr.data_dir = device_to_host;
165#ifndef QEMU
166 dr.req_type = class_type;
167 dr.req_recp = iface_recp;
168#endif
169 dr.bRequest = GET_MAX_LUN;
170 dr.wValue = 0;
171 dr.wIndex = 0;
172 dr.wLength = 1;
173 if (dev->controller->control (dev, IN, sizeof (dr), &dr, 1, &luns)) {
174 luns = 0; // assume only 1 lun if req fails
175 }
176 return luns;
177}
178
Nico Huber43b9f322012-05-21 14:05:41 +0200179unsigned int tag;
180unsigned char lun = 0;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000181
182static void
183wrap_cbw (cbw_t *cbw, int datalen, cbw_direction dir, const u8 *cmd,
184 int cmdlen)
185{
186 memset (cbw, 0, sizeof (cbw_t));
187
188 cbw->dCBWSignature = cbw_signature;
Nico Huber43b9f322012-05-21 14:05:41 +0200189 cbw->dCBWTag = ++tag;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000190 cbw->bCBWLUN = lun; // static value per device
191
192 cbw->dCBWDataTransferLength = datalen;
193 cbw->bmCBWFlags = dir;
194 memcpy (cbw->CBWCB, cmd, sizeof (cbw->CBWCB));
195 cbw->bCBWCBLength = cmdlen;
196}
197
Nico Huber43b9f322012-05-21 14:05:41 +0200198static int
Patrick Georgid21f68b2008-09-02 16:06:22 +0000199get_csw (endpoint_t *ep, csw_t *csw)
200{
Nico Huber43b9f322012-05-21 14:05:41 +0200201 if (ep->dev->controller->bulk (ep, sizeof (csw_t), (u8 *) csw, 1)) {
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000202 clear_stall (ep);
Nico Huber43b9f322012-05-21 14:05:41 +0200203 if (ep->dev->controller->bulk
204 (ep, sizeof (csw_t), (u8 *) csw, 1)) {
Nico Huber79e1f2f2012-06-01 09:50:11 +0200205 return reset_transport (ep->dev);
Nico Huber43b9f322012-05-21 14:05:41 +0200206 }
207 }
208 if (csw->dCSWTag != tag) {
Nico Huber79e1f2f2012-06-01 09:50:11 +0200209 return reset_transport (ep->dev);
Nico Huber43b9f322012-05-21 14:05:41 +0200210 }
Nico Huber79e1f2f2012-06-01 09:50:11 +0200211 return MSC_COMMAND_OK;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000212}
213
214static int
215execute_command (usbdev_t *dev, cbw_direction dir, const u8 *cb, int cblen,
Nico Huber79e1f2f2012-06-01 09:50:11 +0200216 u8 *buf, int buflen, int residue_ok)
Patrick Georgid21f68b2008-09-02 16:06:22 +0000217{
218 cbw_t cbw;
219 csw_t csw;
220
221 int always_succeed = 0;
222 if ((cb[0] == 0x1b) && (cb[4] == 1)) { //start command, always succeed
223 always_succeed = 1;
224 }
225 wrap_cbw (&cbw, buflen, dir, cb, cblen);
226 if (dev->controller->
227 bulk (MSC_INST (dev)->bulk_out, sizeof (cbw), (u8 *) &cbw, 0)) {
Nico Huber79e1f2f2012-06-01 09:50:11 +0200228 return reset_transport (dev);
Patrick Georgid21f68b2008-09-02 16:06:22 +0000229 }
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000230 if (buflen > 0) {
231 if (dir == cbw_direction_data_in) {
232 if (dev->controller->
Nico Huberef88e102012-11-21 16:25:55 +0100233 bulk (MSC_INST (dev)->bulk_in, buflen, buf, 0))
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000234 clear_stall (MSC_INST (dev)->bulk_in);
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000235 } else {
236 if (dev->controller->
Nico Huberef88e102012-11-21 16:25:55 +0100237 bulk (MSC_INST (dev)->bulk_out, buflen, buf, 0))
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000238 clear_stall (MSC_INST (dev)->bulk_out);
Patrick Georgid21f68b2008-09-02 16:06:22 +0000239 }
240 }
Nico Huber79e1f2f2012-06-01 09:50:11 +0200241 int ret = get_csw (MSC_INST (dev)->bulk_in, &csw);
242 if (ret) {
243 return ret;
244 } else if (always_succeed == 1) {
245 /* return success, regardless of message */
246 return MSC_COMMAND_OK;
247 } else if (csw.bCSWStatus == 2) {
248 /* phase error, reset transport */
249 return reset_transport (dev);
250 } else if (csw.bCSWStatus == 0) {
251 if ((csw.dCSWDataResidue == 0) || residue_ok)
252 /* no error, exit */
253 return MSC_COMMAND_OK;
254 else
255 /* missed some bytes */
256 return MSC_COMMAND_FAIL;
257 } else {
258 if (cb[0] == 0x03)
259 /* requesting sense failed, that's bad */
260 return MSC_COMMAND_FAIL;
Aaron Durbina967f412013-06-06 16:14:21 -0500261 else if (cb[0] == 0)
262 /* If command was TEST UNIT READY determine if the
263 * device is of removable type indicating no media
264 * found. */
265 return request_sense_no_media (dev);
Nico Huber79e1f2f2012-06-01 09:50:11 +0200266 /* error "check condition" or reserved error */
267 ret = request_sense (dev);
268 /* return fail or the status of request_sense if it's worse */
269 return ret ? ret : MSC_COMMAND_FAIL;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000270 }
Patrick Georgid21f68b2008-09-02 16:06:22 +0000271}
272
273typedef struct {
274 unsigned char command; //0
275 unsigned char res1; //1
276 unsigned int block; //2-5
277 unsigned char res2; //6
278 unsigned short numblocks; //7-8
279 unsigned char res3; //9 - the block is 10 bytes long
280} __attribute__ ((packed)) cmdblock_t;
281
282typedef struct {
283 unsigned char command; //0
284 unsigned char res1; //1
285 unsigned char res2; //2
286 unsigned char res3; //3
287 unsigned char lun; //4
288 unsigned char res4; //5
289} __attribute__ ((packed)) cmdblock6_t;
290
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000291/**
292 * Like readwrite_blocks, but for soft-sectors of 512b size. Converts the
293 * start and count from 512b units.
294 * Start and count must be aligned so that they match the native
295 * sector size.
296 *
297 * @param dev device to access
298 * @param start first sector to access
299 * @param n number of sectors to access
300 * @param dir direction of access: cbw_direction_data_in == read, cbw_direction_data_out == write
301 * @param buf buffer to read into or write from. Must be at least n*512 bytes
302 * @return 0 on success, 1 on failure
303 */
304int
305readwrite_blocks_512 (usbdev_t *dev, int start, int n,
306 cbw_direction dir, u8 *buf)
307{
308 int blocksize_divider = MSC_INST(dev)->blocksize / 512;
309 return readwrite_blocks (dev, start / blocksize_divider,
310 n / blocksize_divider, dir, buf);
311}
Patrick Georgid21f68b2008-09-02 16:06:22 +0000312
313/**
314 * Reads or writes a number of sequential blocks on a USB storage device.
315 * As it uses the READ(10) SCSI-2 command, it's limited to storage devices
316 * of at most 2TB. It assumes sectors of 512 bytes.
317 *
318 * @param dev device to access
319 * @param start first sector to access
320 * @param n number of sectors to access
321 * @param dir direction of access: cbw_direction_data_in == read, cbw_direction_data_out == write
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000322 * @param buf buffer to read into or write from. Must be at least n*sectorsize bytes
Patrick Georgid21f68b2008-09-02 16:06:22 +0000323 * @return 0 on success, 1 on failure
324 */
325int
326readwrite_blocks (usbdev_t *dev, int start, int n, cbw_direction dir, u8 *buf)
327{
328 cmdblock_t cb;
329 memset (&cb, 0, sizeof (cb));
330 if (dir == cbw_direction_data_in) {
331 // read
332 cb.command = 0x28;
333 } else {
334 // write
335 cb.command = 0x2a;
336 }
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000337 cb.block = htonl (start);
338 cb.numblocks = htonw (n);
Stefan Reinauer14e22772010-04-27 06:56:47 +0000339
Patrick Georgid21f68b2008-09-02 16:06:22 +0000340 return execute_command (dev, dir, (u8 *) &cb, sizeof (cb), buf,
Nico Huber79e1f2f2012-06-01 09:50:11 +0200341 n * MSC_INST(dev)->blocksize, 0)
342 != MSC_COMMAND_OK ? 1 : 0;
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000343}
344
345/* Only request it, we don't interpret it.
346 On certain errors, that's necessary to get devices out of
347 a special state called "Contingent Allegiance Condition" */
348static int
349request_sense (usbdev_t *dev)
350{
351 u8 buf[19];
352 cmdblock6_t cb;
353 memset (&cb, 0, sizeof (cb));
354 cb.command = 0x3;
Stefan Reinauer14e22772010-04-27 06:56:47 +0000355
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000356 return execute_command (dev, cbw_direction_data_in, (u8 *) &cb,
Nico Huber79e1f2f2012-06-01 09:50:11 +0200357 sizeof (cb), buf, 19, 1);
Patrick Georgid21f68b2008-09-02 16:06:22 +0000358}
359
Aaron Durbina967f412013-06-06 16:14:21 -0500360static int request_sense_no_media(usbdev_t *dev)
361{
362 u8 buf[19];
363 int ret;
364 cmdblock6_t cb;
365 memset (&cb, 0, sizeof (cb));
366 cb.command = 0x3;
367
368 ret = execute_command (dev, cbw_direction_data_in, (u8 *) &cb,
369 sizeof (cb), buf, 19, 1);
370
371 if (ret)
372 return ret;
373
374 /* Check if sense key is set to NOT READY. */
375 if ((buf[2] & 0xf) != 2)
376 return MSC_COMMAND_FAIL;
377
378 /* Check if additional sense code is 0x3a. */
379 if (buf[12] != 0x3a)
380 return MSC_COMMAND_FAIL;
381
382 /* No media is present. Return MSC_COMMAND_DETACHED so as not to use
383 * this device any longer. */
384 usb_debug("Empty media found.\n");
385 return MSC_COMMAND_DETACHED;
386}
387
Patrick Georgid21f68b2008-09-02 16:06:22 +0000388static int
389test_unit_ready (usbdev_t *dev)
390{
391 cmdblock6_t cb;
392 memset (&cb, 0, sizeof (cb)); // full initialization for T-U-R
393 return execute_command (dev, cbw_direction_data_out, (u8 *) &cb,
Nico Huber79e1f2f2012-06-01 09:50:11 +0200394 sizeof (cb), 0, 0, 0);
Patrick Georgid21f68b2008-09-02 16:06:22 +0000395}
396
397static int
398spin_up (usbdev_t *dev)
399{
400 cmdblock6_t cb;
401 memset (&cb, 0, sizeof (cb));
402 cb.command = 0x1b;
403 cb.lun = 1;
404 return execute_command (dev, cbw_direction_data_out, (u8 *) &cb,
Nico Huber79e1f2f2012-06-01 09:50:11 +0200405 sizeof (cb), 0, 0, 0);
Patrick Georgid21f68b2008-09-02 16:06:22 +0000406}
407
Nico Huber79e1f2f2012-06-01 09:50:11 +0200408static int
Patrick Georgid21f68b2008-09-02 16:06:22 +0000409read_capacity (usbdev_t *dev)
410{
411 cmdblock_t cb;
412 memset (&cb, 0, sizeof (cb));
413 cb.command = 0x25; // read capacity
Gabe Black2c2c4fa2013-01-15 16:22:04 -0800414 u32 buf[2];
Stefan Reinauerd233f362009-04-30 16:46:12 +0000415
Gabe Black93ded592012-11-01 15:44:10 -0700416 usb_debug ("Reading capacity of mass storage device.\n");
Nico Huber79e1f2f2012-06-01 09:50:11 +0200417 int count = 0, ret;
418 while (count++ < 20) {
419 switch (ret = execute_command
420 (dev, cbw_direction_data_in, (u8 *) &cb,
Gabe Black2c2c4fa2013-01-15 16:22:04 -0800421 sizeof (cb), (u8 *)buf, 8, 0)) {
Nico Huber79e1f2f2012-06-01 09:50:11 +0200422 case MSC_COMMAND_OK:
423 break;
424 case MSC_COMMAND_FAIL:
425 continue;
426 default: /* if it's worse return */
427 return ret;
428 }
429 break;
430 }
Patrick Georgid21f68b2008-09-02 16:06:22 +0000431 if (count >= 20) {
Stefan Reinauerd233f362009-04-30 16:46:12 +0000432 // still not successful, assume 2tb in 512byte sectors, which is just the same garbage as any other number, but probably more usable.
Dave Frodin6bf11cf2012-12-11 13:08:07 -0700433 usb_debug (" assuming 2 TB with 512-byte sectors as READ CAPACITY didn't answer.\n");
Patrick Georgid21f68b2008-09-02 16:06:22 +0000434 MSC_INST (dev)->numblocks = 0xffffffff;
435 MSC_INST (dev)->blocksize = 512;
436 } else {
Gabe Black2c2c4fa2013-01-15 16:22:04 -0800437 MSC_INST (dev)->numblocks = ntohl(buf[0]) + 1;
438 MSC_INST (dev)->blocksize = ntohl(buf[1]);
Patrick Georgid21f68b2008-09-02 16:06:22 +0000439 }
Dave Frodin6bf11cf2012-12-11 13:08:07 -0700440 usb_debug (" %d %d-byte sectors (%d MB)\n", MSC_INST (dev)->numblocks,
Mathias Krausec4716b42011-06-08 15:36:55 +0200441 MSC_INST (dev)->blocksize,
Nico Huberc43e7362012-05-21 13:59:43 +0200442 /* round down high block counts to avoid integer overflow */
443 MSC_INST (dev)->numblocks > 1000000
444 ? (MSC_INST (dev)->numblocks / 1000) * MSC_INST (dev)->blocksize / 1000 :
Mathias Krausec4716b42011-06-08 15:36:55 +0200445 MSC_INST (dev)->numblocks * MSC_INST (dev)->blocksize / 1000 / 1000);
Nico Huber79e1f2f2012-06-01 09:50:11 +0200446 return MSC_COMMAND_OK;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000447}
448
449void
450usb_msc_init (usbdev_t *dev)
451{
452 int i, timeout;
453
Nico Huber445a3a02012-06-21 10:52:49 +0200454 /* init .data before setting .destroy */
455 dev->data = NULL;
456
Patrick Georgid21f68b2008-09-02 16:06:22 +0000457 dev->destroy = usb_msc_destroy;
458 dev->poll = usb_msc_poll;
459
460 configuration_descriptor_t *cd =
461 (configuration_descriptor_t *) dev->configuration;
462 interface_descriptor_t *interface =
463 (interface_descriptor_t *) (((char *) cd) + cd->bLength);
464
Gabe Black93ded592012-11-01 15:44:10 -0700465 usb_debug (" it uses %s command set\n",
Patrick Georgid21f68b2008-09-02 16:06:22 +0000466 msc_subclass_strings[interface->bInterfaceSubClass]);
Gabe Black93ded592012-11-01 15:44:10 -0700467 usb_debug (" it uses %s protocol\n",
Patrick Georgid21f68b2008-09-02 16:06:22 +0000468 msc_protocol_strings[interface->bInterfaceProtocol]);
469
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000470
471 if (interface->bInterfaceProtocol != 0x50) {
Dave Frodin6bf11cf2012-12-11 13:08:07 -0700472 usb_debug (" Protocol not supported.\n");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000473 return;
474 }
475
476 if ((interface->bInterfaceSubClass != 2) && // ATAPI 8020
477 (interface->bInterfaceSubClass != 5) && // ATAPI 8070
478 (interface->bInterfaceSubClass != 6)) { // SCSI
Patrick Georgid21f68b2008-09-02 16:06:22 +0000479 /* Other protocols, such as ATAPI don't seem to be very popular. looks like ATAPI would be really easy to add, if necessary. */
Dave Frodin6bf11cf2012-12-11 13:08:07 -0700480 usb_debug (" Interface SubClass not supported.\n");
Patrick Georgid21f68b2008-09-02 16:06:22 +0000481 return;
482 }
483
484 dev->data = malloc (sizeof (usbmsc_inst_t));
Stefan Reinauer5fe6e232009-07-31 11:39:55 +0000485 if (!dev->data)
Patrick Georgi2e768e72011-11-04 11:50:03 +0100486 fatal("Not enough memory for USB MSC device.\n");
Stefan Reinauer5fe6e232009-07-31 11:39:55 +0000487
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000488 MSC_INST (dev)->protocol = interface->bInterfaceSubClass;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000489 MSC_INST (dev)->bulk_in = 0;
490 MSC_INST (dev)->bulk_out = 0;
Nico Huber445a3a02012-06-21 10:52:49 +0200491 MSC_INST (dev)->usbdisk_created = 0;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000492
493 for (i = 1; i <= dev->num_endp; i++) {
494 if (dev->endpoints[i].endpoint == 0)
495 continue;
496 if (dev->endpoints[i].type != BULK)
497 continue;
498 if ((dev->endpoints[i].direction == IN)
499 && (MSC_INST (dev)->bulk_in == 0))
500 MSC_INST (dev)->bulk_in = &dev->endpoints[i];
501 if ((dev->endpoints[i].direction == OUT)
502 && (MSC_INST (dev)->bulk_out == 0))
503 MSC_INST (dev)->bulk_out = &dev->endpoints[i];
504 }
505
Nico Huber445a3a02012-06-21 10:52:49 +0200506 if (MSC_INST (dev)->bulk_in == 0) {
Dave Frodin6bf11cf2012-12-11 13:08:07 -0700507 usb_debug("couldn't find bulk-in endpoint");
Nico Huber445a3a02012-06-21 10:52:49 +0200508 return;
509 }
510 if (MSC_INST (dev)->bulk_out == 0) {
Dave Frodin6bf11cf2012-12-11 13:08:07 -0700511 usb_debug("couldn't find bulk-out endpoint");
Nico Huber445a3a02012-06-21 10:52:49 +0200512 return;
513 }
Gabe Black93ded592012-11-01 15:44:10 -0700514 usb_debug (" using endpoint %x as in, %x as out\n",
Patrick Georgid21f68b2008-09-02 16:06:22 +0000515 MSC_INST (dev)->bulk_in->endpoint,
516 MSC_INST (dev)->bulk_out->endpoint);
517
Gabe Black93ded592012-11-01 15:44:10 -0700518 usb_debug (" has %d luns\n", get_max_luns (dev) + 1);
Patrick Georgid21f68b2008-09-02 16:06:22 +0000519
Dave Frodin6bf11cf2012-12-11 13:08:07 -0700520 usb_debug (" Waiting for device to become ready...");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000521 timeout = 30 * 10; /* SCSI/ATA specs say we have to wait up to 30s. Ugh */
Nico Huber79e1f2f2012-06-01 09:50:11 +0200522 while (timeout--) {
523 switch (test_unit_ready (dev)) {
524 case MSC_COMMAND_OK:
525 break;
526 case MSC_COMMAND_FAIL:
527 mdelay (100);
528 if (!(timeout % 10))
Dave Frodin6bf11cf2012-12-11 13:08:07 -0700529 usb_debug (".");
Nico Huber79e1f2f2012-06-01 09:50:11 +0200530 continue;
531 default: /* if it's worse return */
532 return;
533 }
534 break;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000535 }
Nico Huber79e1f2f2012-06-01 09:50:11 +0200536 if (timeout < 0) {
Dave Frodin6bf11cf2012-12-11 13:08:07 -0700537 usb_debug ("timeout. Device not ready. Still trying...\n");
Patrick Georgid21f68b2008-09-02 16:06:22 +0000538 } else {
Dave Frodin6bf11cf2012-12-11 13:08:07 -0700539 usb_debug ("ok.\n");
Patrick Georgid21f68b2008-09-02 16:06:22 +0000540 }
541
Gabe Black93ded592012-11-01 15:44:10 -0700542 usb_debug (" spin up");
Patrick Georgid21f68b2008-09-02 16:06:22 +0000543 for (i = 0; i < 30; i++) {
Gabe Black93ded592012-11-01 15:44:10 -0700544 usb_debug (".");
Nico Huber79e1f2f2012-06-01 09:50:11 +0200545 switch (spin_up (dev)) {
546 case MSC_COMMAND_OK:
Gabe Black93ded592012-11-01 15:44:10 -0700547 usb_debug (" OK.");
Patrick Georgid21f68b2008-09-02 16:06:22 +0000548 break;
Nico Huber79e1f2f2012-06-01 09:50:11 +0200549 case MSC_COMMAND_FAIL:
550 mdelay (100);
551 continue;
552 default: /* if it's worse return */
553 return;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000554 }
Nico Huber79e1f2f2012-06-01 09:50:11 +0200555 break;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000556 }
Gabe Black93ded592012-11-01 15:44:10 -0700557 usb_debug ("\n");
Patrick Georgid21f68b2008-09-02 16:06:22 +0000558
Nico Huber445a3a02012-06-21 10:52:49 +0200559 if ((read_capacity (dev) == MSC_COMMAND_OK) && usbdisk_create) {
Patrick Georgi4727c072008-10-16 19:20:51 +0000560 usbdisk_create (dev);
Nico Huber445a3a02012-06-21 10:52:49 +0200561 MSC_INST (dev)->usbdisk_created = 1;
562 }
Patrick Georgid21f68b2008-09-02 16:06:22 +0000563}