blob: 037ead3e37a8dea72ad8944055e5de11d7ecd61f [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
Aaron Durbin1c20e382013-06-07 12:31:21 -050070static void
71usb_msc_create_disk (usbdev_t *dev)
72{
73 if (usbdisk_create) {
74 usbdisk_create (dev);
75 MSC_INST (dev)->usbdisk_created = 1;
76 }
77}
78
79static void
80usb_msc_remove_disk (usbdev_t *dev)
81{
82 if (MSC_INST (dev)->usbdisk_created && usbdisk_remove)
83 usbdisk_remove (dev);
84}
Patrick Georgid21f68b2008-09-02 16:06:22 +000085
86static void
87usb_msc_destroy (usbdev_t *dev)
88{
Nico Huber445a3a02012-06-21 10:52:49 +020089 if (dev->data) {
Aaron Durbin1c20e382013-06-07 12:31:21 -050090 usb_msc_remove_disk (dev);
Nico Huber445a3a02012-06-21 10:52:49 +020091 free (dev->data);
92 }
Patrick Georgid21f68b2008-09-02 16:06:22 +000093 dev->data = 0;
94}
95
Patrick Georgid21f68b2008-09-02 16:06:22 +000096const int DEV_RESET = 0xff;
97const int GET_MAX_LUN = 0xfe;
Duncan Laurie3a65d852013-09-12 13:27:15 -070098/* Many USB3 devices do not work with large transfer requests.
99 * Limit the request size to 64KB chunks to ensure maximum compatibility. */
100const int MAX_CHUNK_BYTES = 1024 * 64;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000101
102const unsigned int cbw_signature = 0x43425355;
103const unsigned int csw_signature = 0x53425355;
104
105typedef struct {
106 unsigned int dCBWSignature;
107 unsigned int dCBWTag;
108 unsigned int dCBWDataTransferLength;
109 unsigned char bmCBWFlags;
110 unsigned long bCBWLUN:4;
111 unsigned long:4;
112 unsigned long bCBWCBLength:5;
113 unsigned long:3;
114 unsigned char CBWCB[31 - 15];
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000115} __attribute__ ((packed)) cbw_t;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000116
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000117typedef struct {
118 unsigned int dCSWSignature;
119 unsigned int dCSWTag;
120 unsigned int dCSWDataResidue;
121 unsigned char bCSWStatus;
122} __attribute__ ((packed)) csw_t;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000123
Nico Huber79e1f2f2012-06-01 09:50:11 +0200124enum {
125 /*
126 * MSC commands can be
127 * successful,
128 * fail with proper response or
Julius Wernerb59e8502013-09-25 13:54:57 -0700129 * fail totally, which results in detaching of the usb device
130 * and immediate cleanup of the usbdev_t structure.
Nico Huber79e1f2f2012-06-01 09:50:11 +0200131 * In the latter case the caller has to make sure, that he won't
132 * use the device any more.
133 */
134 MSC_COMMAND_OK = 0, MSC_COMMAND_FAIL, MSC_COMMAND_DETACHED
135};
136
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000137static int
138request_sense (usbdev_t *dev);
Aaron Durbina967f412013-06-06 16:14:21 -0500139static int
140request_sense_no_media (usbdev_t *dev);
Aaron Durbin1c20e382013-06-07 12:31:21 -0500141static void
142usb_msc_poll (usbdev_t *dev);
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000143
Nico Huber79e1f2f2012-06-01 09:50:11 +0200144static int
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000145reset_transport (usbdev_t *dev)
Patrick Georgid21f68b2008-09-02 16:06:22 +0000146{
147 dev_req_t dr;
148 memset (&dr, 0, sizeof (dr));
149 dr.bmRequestType = 0;
150 dr.data_dir = host_to_device;
151#ifndef QEMU
152 dr.req_type = class_type;
153 dr.req_recp = iface_recp;
154#endif
155 dr.bRequest = DEV_RESET;
156 dr.wValue = 0;
157 dr.wIndex = 0;
158 dr.wLength = 0;
Nico Huber79e1f2f2012-06-01 09:50:11 +0200159
160 /* if any of these fails, detach device, as we are lost */
Julius Wernere9738db2013-02-21 13:41:40 -0800161 if (dev->controller->control (dev, OUT, sizeof (dr), &dr, 0, 0) < 0 ||
Nico Huber79e1f2f2012-06-01 09:50:11 +0200162 clear_stall (MSC_INST (dev)->bulk_in) ||
163 clear_stall (MSC_INST (dev)->bulk_out)) {
Dave Frodin6bf11cf2012-12-11 13:08:07 -0700164 usb_debug ("Detaching unresponsive device.\n");
Nico Huber79e1f2f2012-06-01 09:50:11 +0200165 usb_detach_device (dev->controller, dev->address);
166 return MSC_COMMAND_DETACHED;
167 }
168 /* return fail as we are only called in case of failure */
169 return MSC_COMMAND_FAIL;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000170}
171
172/* device may stall this command, so beware! */
173static int
174get_max_luns (usbdev_t *dev)
175{
176 unsigned char luns = 75;
177 dev_req_t dr;
178 dr.bmRequestType = 0;
179 dr.data_dir = device_to_host;
180#ifndef QEMU
181 dr.req_type = class_type;
182 dr.req_recp = iface_recp;
183#endif
184 dr.bRequest = GET_MAX_LUN;
185 dr.wValue = 0;
186 dr.wIndex = 0;
187 dr.wLength = 1;
Julius Wernere9738db2013-02-21 13:41:40 -0800188 if (dev->controller->control (dev, IN, sizeof (dr), &dr, 1, &luns) < 0)
Patrick Georgid21f68b2008-09-02 16:06:22 +0000189 luns = 0; // assume only 1 lun if req fails
Patrick Georgid21f68b2008-09-02 16:06:22 +0000190 return luns;
191}
192
Nico Huber43b9f322012-05-21 14:05:41 +0200193unsigned int tag;
194unsigned char lun = 0;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000195
196static void
197wrap_cbw (cbw_t *cbw, int datalen, cbw_direction dir, const u8 *cmd,
198 int cmdlen)
199{
200 memset (cbw, 0, sizeof (cbw_t));
201
202 cbw->dCBWSignature = cbw_signature;
Nico Huber43b9f322012-05-21 14:05:41 +0200203 cbw->dCBWTag = ++tag;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000204 cbw->bCBWLUN = lun; // static value per device
205
206 cbw->dCBWDataTransferLength = datalen;
207 cbw->bmCBWFlags = dir;
208 memcpy (cbw->CBWCB, cmd, sizeof (cbw->CBWCB));
209 cbw->bCBWCBLength = cmdlen;
210}
211
Nico Huber43b9f322012-05-21 14:05:41 +0200212static int
Patrick Georgid21f68b2008-09-02 16:06:22 +0000213get_csw (endpoint_t *ep, csw_t *csw)
214{
Julius Wernere9738db2013-02-21 13:41:40 -0800215 if (ep->dev->controller->bulk (ep, sizeof (csw_t), (u8 *) csw, 1) < 0) {
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000216 clear_stall (ep);
Nico Huber43b9f322012-05-21 14:05:41 +0200217 if (ep->dev->controller->bulk
Julius Wernere9738db2013-02-21 13:41:40 -0800218 (ep, sizeof (csw_t), (u8 *) csw, 1) < 0) {
Nico Huber79e1f2f2012-06-01 09:50:11 +0200219 return reset_transport (ep->dev);
Nico Huber43b9f322012-05-21 14:05:41 +0200220 }
221 }
222 if (csw->dCSWTag != tag) {
Nico Huber79e1f2f2012-06-01 09:50:11 +0200223 return reset_transport (ep->dev);
Nico Huber43b9f322012-05-21 14:05:41 +0200224 }
Nico Huber79e1f2f2012-06-01 09:50:11 +0200225 return MSC_COMMAND_OK;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000226}
227
228static int
229execute_command (usbdev_t *dev, cbw_direction dir, const u8 *cb, int cblen,
Nico Huber79e1f2f2012-06-01 09:50:11 +0200230 u8 *buf, int buflen, int residue_ok)
Patrick Georgid21f68b2008-09-02 16:06:22 +0000231{
232 cbw_t cbw;
233 csw_t csw;
234
235 int always_succeed = 0;
236 if ((cb[0] == 0x1b) && (cb[4] == 1)) { //start command, always succeed
237 always_succeed = 1;
238 }
239 wrap_cbw (&cbw, buflen, dir, cb, cblen);
240 if (dev->controller->
Julius Wernere9738db2013-02-21 13:41:40 -0800241 bulk (MSC_INST (dev)->bulk_out, sizeof (cbw), (u8 *) &cbw, 0) < 0) {
Nico Huber79e1f2f2012-06-01 09:50:11 +0200242 return reset_transport (dev);
Patrick Georgid21f68b2008-09-02 16:06:22 +0000243 }
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000244 if (buflen > 0) {
245 if (dir == cbw_direction_data_in) {
246 if (dev->controller->
Julius Wernere9738db2013-02-21 13:41:40 -0800247 bulk (MSC_INST (dev)->bulk_in, buflen, buf, 0) < 0)
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000248 clear_stall (MSC_INST (dev)->bulk_in);
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000249 } else {
250 if (dev->controller->
Julius Wernere9738db2013-02-21 13:41:40 -0800251 bulk (MSC_INST (dev)->bulk_out, buflen, buf, 0) < 0)
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000252 clear_stall (MSC_INST (dev)->bulk_out);
Patrick Georgid21f68b2008-09-02 16:06:22 +0000253 }
254 }
Nico Huber79e1f2f2012-06-01 09:50:11 +0200255 int ret = get_csw (MSC_INST (dev)->bulk_in, &csw);
256 if (ret) {
257 return ret;
258 } else if (always_succeed == 1) {
259 /* return success, regardless of message */
260 return MSC_COMMAND_OK;
261 } else if (csw.bCSWStatus == 2) {
262 /* phase error, reset transport */
263 return reset_transport (dev);
264 } else if (csw.bCSWStatus == 0) {
265 if ((csw.dCSWDataResidue == 0) || residue_ok)
266 /* no error, exit */
267 return MSC_COMMAND_OK;
268 else
269 /* missed some bytes */
270 return MSC_COMMAND_FAIL;
271 } else {
272 if (cb[0] == 0x03)
273 /* requesting sense failed, that's bad */
274 return MSC_COMMAND_FAIL;
Aaron Durbina967f412013-06-06 16:14:21 -0500275 else if (cb[0] == 0)
276 /* If command was TEST UNIT READY determine if the
277 * device is of removable type indicating no media
278 * found. */
279 return request_sense_no_media (dev);
Nico Huber79e1f2f2012-06-01 09:50:11 +0200280 /* error "check condition" or reserved error */
281 ret = request_sense (dev);
282 /* return fail or the status of request_sense if it's worse */
283 return ret ? ret : MSC_COMMAND_FAIL;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000284 }
Patrick Georgid21f68b2008-09-02 16:06:22 +0000285}
286
287typedef struct {
288 unsigned char command; //0
289 unsigned char res1; //1
290 unsigned int block; //2-5
291 unsigned char res2; //6
292 unsigned short numblocks; //7-8
293 unsigned char res3; //9 - the block is 10 bytes long
294} __attribute__ ((packed)) cmdblock_t;
295
296typedef struct {
297 unsigned char command; //0
298 unsigned char res1; //1
299 unsigned char res2; //2
300 unsigned char res3; //3
301 unsigned char lun; //4
302 unsigned char res4; //5
303} __attribute__ ((packed)) cmdblock6_t;
304
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000305/**
306 * Like readwrite_blocks, but for soft-sectors of 512b size. Converts the
307 * start and count from 512b units.
308 * Start and count must be aligned so that they match the native
309 * sector size.
310 *
311 * @param dev device to access
312 * @param start first sector to access
313 * @param n number of sectors to access
314 * @param dir direction of access: cbw_direction_data_in == read, cbw_direction_data_out == write
315 * @param buf buffer to read into or write from. Must be at least n*512 bytes
316 * @return 0 on success, 1 on failure
317 */
318int
319readwrite_blocks_512 (usbdev_t *dev, int start, int n,
320 cbw_direction dir, u8 *buf)
321{
322 int blocksize_divider = MSC_INST(dev)->blocksize / 512;
323 return readwrite_blocks (dev, start / blocksize_divider,
324 n / blocksize_divider, dir, buf);
325}
Patrick Georgid21f68b2008-09-02 16:06:22 +0000326
327/**
328 * Reads or writes a number of sequential blocks on a USB storage device.
329 * As it uses the READ(10) SCSI-2 command, it's limited to storage devices
330 * of at most 2TB. It assumes sectors of 512 bytes.
331 *
332 * @param dev device to access
333 * @param start first sector to access
334 * @param n number of sectors to access
335 * @param dir direction of access: cbw_direction_data_in == read, cbw_direction_data_out == write
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000336 * @param buf buffer to read into or write from. Must be at least n*sectorsize bytes
Patrick Georgid21f68b2008-09-02 16:06:22 +0000337 * @return 0 on success, 1 on failure
338 */
Gabe Blacke8eb86f2013-09-18 05:37:20 -0700339static int
Duncan Laurie3a65d852013-09-12 13:27:15 -0700340readwrite_chunk (usbdev_t *dev, int start, int n, cbw_direction dir, u8 *buf)
Patrick Georgid21f68b2008-09-02 16:06:22 +0000341{
342 cmdblock_t cb;
343 memset (&cb, 0, sizeof (cb));
344 if (dir == cbw_direction_data_in) {
345 // read
346 cb.command = 0x28;
347 } else {
348 // write
349 cb.command = 0x2a;
350 }
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000351 cb.block = htonl (start);
352 cb.numblocks = htonw (n);
Stefan Reinauer14e22772010-04-27 06:56:47 +0000353
Patrick Georgid21f68b2008-09-02 16:06:22 +0000354 return execute_command (dev, dir, (u8 *) &cb, sizeof (cb), buf,
Nico Huber79e1f2f2012-06-01 09:50:11 +0200355 n * MSC_INST(dev)->blocksize, 0)
356 != MSC_COMMAND_OK ? 1 : 0;
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000357}
358
Duncan Laurie3a65d852013-09-12 13:27:15 -0700359/**
360 * Reads or writes a number of sequential blocks on a USB storage device
361 * that is split into MAX_CHUNK_BYTES size requests.
362 *
363 * As it uses the READ(10) SCSI-2 command, it's limited to storage devices
364 * of at most 2TB. It assumes sectors of 512 bytes.
365 *
366 * @param dev device to access
367 * @param start first sector to access
368 * @param n number of sectors to access
369 * @param dir direction of access: cbw_direction_data_in == read,
370 * cbw_direction_data_out == write
371 * @param buf buffer to read into or write from.
372 * Must be at least n*sectorsize bytes
373 * @return 0 on success, 1 on failure
374 */
375int
376readwrite_blocks (usbdev_t *dev, int start, int n, cbw_direction dir, u8 *buf)
377{
378 int chunk_size = MAX_CHUNK_BYTES / MSC_INST(dev)->blocksize;
379 int chunk;
380
381 /* Read as many full chunks as needed. */
382 for (chunk = 0; chunk < (n / chunk_size); chunk++) {
383 if (readwrite_chunk (dev, start + (chunk * chunk_size),
384 chunk_size, dir,
385 buf + (chunk * MAX_CHUNK_BYTES))
386 != MSC_COMMAND_OK)
387 return 1;
388 }
389
390 /* Read any remaining partial chunk at the end. */
391 if (n % chunk_size) {
392 if (readwrite_chunk (dev, start + (chunk * chunk_size),
393 n % chunk_size, dir,
394 buf + (chunk * MAX_CHUNK_BYTES))
395 != MSC_COMMAND_OK)
396 return 1;
397 }
398
399 return 0;
400}
401
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000402/* Only request it, we don't interpret it.
403 On certain errors, that's necessary to get devices out of
404 a special state called "Contingent Allegiance Condition" */
405static int
406request_sense (usbdev_t *dev)
407{
408 u8 buf[19];
409 cmdblock6_t cb;
410 memset (&cb, 0, sizeof (cb));
411 cb.command = 0x3;
Stefan Reinauer14e22772010-04-27 06:56:47 +0000412
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000413 return execute_command (dev, cbw_direction_data_in, (u8 *) &cb,
Nico Huber79e1f2f2012-06-01 09:50:11 +0200414 sizeof (cb), buf, 19, 1);
Patrick Georgid21f68b2008-09-02 16:06:22 +0000415}
416
Aaron Durbin1c20e382013-06-07 12:31:21 -0500417static int request_sense_no_media (usbdev_t *dev)
Aaron Durbina967f412013-06-06 16:14:21 -0500418{
419 u8 buf[19];
420 int ret;
421 cmdblock6_t cb;
422 memset (&cb, 0, sizeof (cb));
423 cb.command = 0x3;
424
425 ret = execute_command (dev, cbw_direction_data_in, (u8 *) &cb,
426 sizeof (cb), buf, 19, 1);
427
428 if (ret)
429 return ret;
430
431 /* Check if sense key is set to NOT READY. */
432 if ((buf[2] & 0xf) != 2)
433 return MSC_COMMAND_FAIL;
434
435 /* Check if additional sense code is 0x3a. */
436 if (buf[12] != 0x3a)
437 return MSC_COMMAND_FAIL;
438
Aaron Durbin1c20e382013-06-07 12:31:21 -0500439 /* No media is present. Return MSC_COMMAND_OK while marking the disk
440 * not ready. */
441 usb_debug ("Empty media found.\n");
Julius Wernerb59e8502013-09-25 13:54:57 -0700442 MSC_INST (dev)->ready = USB_MSC_NOT_READY;
Aaron Durbin1c20e382013-06-07 12:31:21 -0500443 return MSC_COMMAND_OK;
Aaron Durbina967f412013-06-06 16:14:21 -0500444}
445
Patrick Georgid21f68b2008-09-02 16:06:22 +0000446static int
447test_unit_ready (usbdev_t *dev)
448{
449 cmdblock6_t cb;
450 memset (&cb, 0, sizeof (cb)); // full initialization for T-U-R
451 return execute_command (dev, cbw_direction_data_out, (u8 *) &cb,
Nico Huber79e1f2f2012-06-01 09:50:11 +0200452 sizeof (cb), 0, 0, 0);
Patrick Georgid21f68b2008-09-02 16:06:22 +0000453}
454
455static int
456spin_up (usbdev_t *dev)
457{
458 cmdblock6_t cb;
459 memset (&cb, 0, sizeof (cb));
460 cb.command = 0x1b;
461 cb.lun = 1;
462 return execute_command (dev, cbw_direction_data_out, (u8 *) &cb,
Nico Huber79e1f2f2012-06-01 09:50:11 +0200463 sizeof (cb), 0, 0, 0);
Patrick Georgid21f68b2008-09-02 16:06:22 +0000464}
465
Nico Huber79e1f2f2012-06-01 09:50:11 +0200466static int
Patrick Georgid21f68b2008-09-02 16:06:22 +0000467read_capacity (usbdev_t *dev)
468{
469 cmdblock_t cb;
470 memset (&cb, 0, sizeof (cb));
471 cb.command = 0x25; // read capacity
Gabe Black2c2c4fa2013-01-15 16:22:04 -0800472 u32 buf[2];
Stefan Reinauerd233f362009-04-30 16:46:12 +0000473
Gabe Black93ded592012-11-01 15:44:10 -0700474 usb_debug ("Reading capacity of mass storage device.\n");
Nico Huber79e1f2f2012-06-01 09:50:11 +0200475 int count = 0, ret;
476 while (count++ < 20) {
477 switch (ret = execute_command
478 (dev, cbw_direction_data_in, (u8 *) &cb,
Gabe Black2c2c4fa2013-01-15 16:22:04 -0800479 sizeof (cb), (u8 *)buf, 8, 0)) {
Nico Huber79e1f2f2012-06-01 09:50:11 +0200480 case MSC_COMMAND_OK:
481 break;
482 case MSC_COMMAND_FAIL:
483 continue;
484 default: /* if it's worse return */
485 return ret;
486 }
487 break;
488 }
Patrick Georgid21f68b2008-09-02 16:06:22 +0000489 if (count >= 20) {
Stefan Reinauerd233f362009-04-30 16:46:12 +0000490 // 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 -0700491 usb_debug (" assuming 2 TB with 512-byte sectors as READ CAPACITY didn't answer.\n");
Patrick Georgid21f68b2008-09-02 16:06:22 +0000492 MSC_INST (dev)->numblocks = 0xffffffff;
493 MSC_INST (dev)->blocksize = 512;
494 } else {
Gabe Black2c2c4fa2013-01-15 16:22:04 -0800495 MSC_INST (dev)->numblocks = ntohl(buf[0]) + 1;
496 MSC_INST (dev)->blocksize = ntohl(buf[1]);
Patrick Georgid21f68b2008-09-02 16:06:22 +0000497 }
Dave Frodin6bf11cf2012-12-11 13:08:07 -0700498 usb_debug (" %d %d-byte sectors (%d MB)\n", MSC_INST (dev)->numblocks,
Mathias Krausec4716b42011-06-08 15:36:55 +0200499 MSC_INST (dev)->blocksize,
Nico Huberc43e7362012-05-21 13:59:43 +0200500 /* round down high block counts to avoid integer overflow */
501 MSC_INST (dev)->numblocks > 1000000
502 ? (MSC_INST (dev)->numblocks / 1000) * MSC_INST (dev)->blocksize / 1000 :
Mathias Krausec4716b42011-06-08 15:36:55 +0200503 MSC_INST (dev)->numblocks * MSC_INST (dev)->blocksize / 1000 / 1000);
Nico Huber79e1f2f2012-06-01 09:50:11 +0200504 return MSC_COMMAND_OK;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000505}
506
Julius Wernerb59e8502013-09-25 13:54:57 -0700507static int
Aaron Durbin1c20e382013-06-07 12:31:21 -0500508usb_msc_test_unit_ready (usbdev_t *dev)
509{
510 int i;
Shawn Nematbakhsh7ecc9122013-09-12 18:09:39 -0700511 time_t start_time_secs;
512 struct timeval tv;
Shawn Nematbakhshdf6d09d2013-09-12 18:23:09 -0700513 /* SCSI/ATA specs say we have to wait up to 30s, but most devices
514 * are ready much sooner. Use a 5 sec timeout to better accomodate
515 * devices which fail to respond. */
516 const int timeout_secs = 5;
Aaron Durbin1c20e382013-06-07 12:31:21 -0500517
518 usb_debug (" Waiting for device to become ready...");
519
520 /* Initially mark the device ready. */
Julius Wernerb59e8502013-09-25 13:54:57 -0700521 MSC_INST (dev)->ready = USB_MSC_READY;
Shawn Nematbakhsh7ecc9122013-09-12 18:09:39 -0700522 gettimeofday (&tv, NULL);
523 start_time_secs = tv.tv_sec;
Aaron Durbin1c20e382013-06-07 12:31:21 -0500524
Shawn Nematbakhsh7ecc9122013-09-12 18:09:39 -0700525 while (tv.tv_sec - start_time_secs < timeout_secs) {
Aaron Durbin1c20e382013-06-07 12:31:21 -0500526 switch (test_unit_ready (dev)) {
527 case MSC_COMMAND_OK:
528 break;
529 case MSC_COMMAND_FAIL:
530 mdelay (100);
Shawn Nematbakhsh7ecc9122013-09-12 18:09:39 -0700531 usb_debug (".");
532 gettimeofday (&tv, NULL);
Aaron Durbin1c20e382013-06-07 12:31:21 -0500533 continue;
534 default:
Julius Wernerb59e8502013-09-25 13:54:57 -0700535 /* Device detached, return immediately */
536 return USB_MSC_DETACHED;
Aaron Durbin1c20e382013-06-07 12:31:21 -0500537 }
538 break;
539 }
Shawn Nematbakhsh7ecc9122013-09-12 18:09:39 -0700540 if (!(tv.tv_sec - start_time_secs < timeout_secs)) {
Aaron Durbin1c20e382013-06-07 12:31:21 -0500541 usb_debug ("timeout. Device not ready.\n");
Julius Wernerb59e8502013-09-25 13:54:57 -0700542 MSC_INST (dev)->ready = USB_MSC_NOT_READY;
Aaron Durbin1c20e382013-06-07 12:31:21 -0500543 }
544
545 /* Don't bother spinning up the stroage device if the device is not
546 * ready. This can happen when empty card readers are present.
547 * Polling will pick it back up if readiness changes. */
Julius Wernerb59e8502013-09-25 13:54:57 -0700548 if (!MSC_INST (dev)->ready)
549 return MSC_INST (dev)->ready;
Aaron Durbin1c20e382013-06-07 12:31:21 -0500550
551 usb_debug ("ok.\n");
552
553 usb_debug (" spin up");
554 for (i = 0; i < 30; i++) {
555 usb_debug (".");
556 switch (spin_up (dev)) {
557 case MSC_COMMAND_OK:
558 usb_debug (" OK.");
559 break;
560 case MSC_COMMAND_FAIL:
561 mdelay (100);
562 continue;
563 default:
Julius Wernerb59e8502013-09-25 13:54:57 -0700564 /* Device detached, return immediately */
565 return USB_MSC_DETACHED;
Aaron Durbin1c20e382013-06-07 12:31:21 -0500566 }
567 break;
568 }
569 usb_debug ("\n");
570
Julius Wernerb59e8502013-09-25 13:54:57 -0700571 if (read_capacity (dev) == MSC_COMMAND_DETACHED)
572 return USB_MSC_DETACHED;
573
574 return MSC_INST (dev)->ready;
Aaron Durbin1c20e382013-06-07 12:31:21 -0500575}
576
Patrick Georgid21f68b2008-09-02 16:06:22 +0000577void
578usb_msc_init (usbdev_t *dev)
579{
Aaron Durbin1c20e382013-06-07 12:31:21 -0500580 int i;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000581
Nico Huber445a3a02012-06-21 10:52:49 +0200582 /* init .data before setting .destroy */
583 dev->data = NULL;
584
Patrick Georgid21f68b2008-09-02 16:06:22 +0000585 dev->destroy = usb_msc_destroy;
586 dev->poll = usb_msc_poll;
587
588 configuration_descriptor_t *cd =
589 (configuration_descriptor_t *) dev->configuration;
590 interface_descriptor_t *interface =
591 (interface_descriptor_t *) (((char *) cd) + cd->bLength);
592
Gabe Black93ded592012-11-01 15:44:10 -0700593 usb_debug (" it uses %s command set\n",
Patrick Georgid21f68b2008-09-02 16:06:22 +0000594 msc_subclass_strings[interface->bInterfaceSubClass]);
Gabe Black93ded592012-11-01 15:44:10 -0700595 usb_debug (" it uses %s protocol\n",
Patrick Georgid21f68b2008-09-02 16:06:22 +0000596 msc_protocol_strings[interface->bInterfaceProtocol]);
597
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000598
599 if (interface->bInterfaceProtocol != 0x50) {
Dave Frodin6bf11cf2012-12-11 13:08:07 -0700600 usb_debug (" Protocol not supported.\n");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000601 return;
602 }
603
604 if ((interface->bInterfaceSubClass != 2) && // ATAPI 8020
605 (interface->bInterfaceSubClass != 5) && // ATAPI 8070
606 (interface->bInterfaceSubClass != 6)) { // SCSI
Patrick Georgid21f68b2008-09-02 16:06:22 +0000607 /* 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 -0700608 usb_debug (" Interface SubClass not supported.\n");
Patrick Georgid21f68b2008-09-02 16:06:22 +0000609 return;
610 }
611
612 dev->data = malloc (sizeof (usbmsc_inst_t));
Stefan Reinauer5fe6e232009-07-31 11:39:55 +0000613 if (!dev->data)
Patrick Georgi2e768e72011-11-04 11:50:03 +0100614 fatal("Not enough memory for USB MSC device.\n");
Stefan Reinauer5fe6e232009-07-31 11:39:55 +0000615
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000616 MSC_INST (dev)->protocol = interface->bInterfaceSubClass;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000617 MSC_INST (dev)->bulk_in = 0;
618 MSC_INST (dev)->bulk_out = 0;
Nico Huber445a3a02012-06-21 10:52:49 +0200619 MSC_INST (dev)->usbdisk_created = 0;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000620
621 for (i = 1; i <= dev->num_endp; i++) {
622 if (dev->endpoints[i].endpoint == 0)
623 continue;
624 if (dev->endpoints[i].type != BULK)
625 continue;
626 if ((dev->endpoints[i].direction == IN)
627 && (MSC_INST (dev)->bulk_in == 0))
628 MSC_INST (dev)->bulk_in = &dev->endpoints[i];
629 if ((dev->endpoints[i].direction == OUT)
630 && (MSC_INST (dev)->bulk_out == 0))
631 MSC_INST (dev)->bulk_out = &dev->endpoints[i];
632 }
633
Nico Huber445a3a02012-06-21 10:52:49 +0200634 if (MSC_INST (dev)->bulk_in == 0) {
Dave Frodin6bf11cf2012-12-11 13:08:07 -0700635 usb_debug("couldn't find bulk-in endpoint");
Nico Huber445a3a02012-06-21 10:52:49 +0200636 return;
637 }
638 if (MSC_INST (dev)->bulk_out == 0) {
Dave Frodin6bf11cf2012-12-11 13:08:07 -0700639 usb_debug("couldn't find bulk-out endpoint");
Nico Huber445a3a02012-06-21 10:52:49 +0200640 return;
641 }
Gabe Black93ded592012-11-01 15:44:10 -0700642 usb_debug (" using endpoint %x as in, %x as out\n",
Patrick Georgid21f68b2008-09-02 16:06:22 +0000643 MSC_INST (dev)->bulk_in->endpoint,
644 MSC_INST (dev)->bulk_out->endpoint);
645
Gabe Black93ded592012-11-01 15:44:10 -0700646 usb_debug (" has %d luns\n", get_max_luns (dev) + 1);
Patrick Georgid21f68b2008-09-02 16:06:22 +0000647
Julius Wernerb59e8502013-09-25 13:54:57 -0700648 /* Test if unit is ready (nothing to do if it isn't). */
649 if (usb_msc_test_unit_ready (dev) != USB_MSC_READY)
Aaron Durbin1c20e382013-06-07 12:31:21 -0500650 return;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000651
Aaron Durbin1c20e382013-06-07 12:31:21 -0500652 /* Create the disk. */
653 usb_msc_create_disk (dev);
654}
655
656static void
657usb_msc_poll (usbdev_t *dev)
658{
Julius Wernerb59e8502013-09-25 13:54:57 -0700659 int prev_ready = MSC_INST (dev)->ready;
Aaron Durbin1c20e382013-06-07 12:31:21 -0500660
Julius Wernerb59e8502013-09-25 13:54:57 -0700661 if (usb_msc_test_unit_ready (dev) == USB_MSC_DETACHED)
Aaron Durbin1c20e382013-06-07 12:31:21 -0500662 return;
663
Julius Wernerb59e8502013-09-25 13:54:57 -0700664 if (!prev_ready && MSC_INST (dev)->ready) {
Aaron Durbin1c20e382013-06-07 12:31:21 -0500665 usb_debug ("usb msc: not ready -> ready\n");
666 usb_msc_create_disk (dev);
Julius Wernerb59e8502013-09-25 13:54:57 -0700667 } else if (prev_ready && !MSC_INST (dev)->ready) {
Aaron Durbin1c20e382013-06-07 12:31:21 -0500668 usb_debug ("usb msc: ready -> not ready\n");
669 usb_msc_remove_disk (dev);
Nico Huber445a3a02012-06-21 10:52:49 +0200670 }
Patrick Georgid21f68b2008-09-02 16:06:22 +0000671}