blob: f90acb174479524a0fefb98acde5555a9a676312 [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
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000109static int
110request_sense (usbdev_t *dev);
111
112static void
113reset_transport (usbdev_t *dev)
Patrick Georgid21f68b2008-09-02 16:06:22 +0000114{
115 dev_req_t dr;
116 memset (&dr, 0, sizeof (dr));
117 dr.bmRequestType = 0;
118 dr.data_dir = host_to_device;
119#ifndef QEMU
120 dr.req_type = class_type;
121 dr.req_recp = iface_recp;
122#endif
123 dr.bRequest = DEV_RESET;
124 dr.wValue = 0;
125 dr.wIndex = 0;
126 dr.wLength = 0;
127 dev->controller->control (dev, OUT, sizeof (dr), &dr, 0, 0);
128 clear_stall (MSC_INST (dev)->bulk_in);
129 clear_stall (MSC_INST (dev)->bulk_out);
130}
131
132/* device may stall this command, so beware! */
133static int
134get_max_luns (usbdev_t *dev)
135{
136 unsigned char luns = 75;
137 dev_req_t dr;
138 dr.bmRequestType = 0;
139 dr.data_dir = device_to_host;
140#ifndef QEMU
141 dr.req_type = class_type;
142 dr.req_recp = iface_recp;
143#endif
144 dr.bRequest = GET_MAX_LUN;
145 dr.wValue = 0;
146 dr.wIndex = 0;
147 dr.wLength = 1;
148 if (dev->controller->control (dev, IN, sizeof (dr), &dr, 1, &luns)) {
149 luns = 0; // assume only 1 lun if req fails
150 }
151 return luns;
152}
153
154int tag;
155int lun = 0;
156
157static void
158wrap_cbw (cbw_t *cbw, int datalen, cbw_direction dir, const u8 *cmd,
159 int cmdlen)
160{
161 memset (cbw, 0, sizeof (cbw_t));
162
163 cbw->dCBWSignature = cbw_signature;
164 cbw->dCBWTag = tag++;
165 cbw->bCBWLUN = lun; // static value per device
166
167 cbw->dCBWDataTransferLength = datalen;
168 cbw->bmCBWFlags = dir;
169 memcpy (cbw->CBWCB, cmd, sizeof (cbw->CBWCB));
170 cbw->bCBWCBLength = cmdlen;
171}
172
173static void
174get_csw (endpoint_t *ep, csw_t *csw)
175{
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000176 if (ep->dev->controller->bulk (ep, sizeof (csw_t), (u8 *) csw, 1))
177 clear_stall (ep);
Patrick Georgid21f68b2008-09-02 16:06:22 +0000178}
179
180static int
181execute_command (usbdev_t *dev, cbw_direction dir, const u8 *cb, int cblen,
182 u8 *buf, int buflen)
183{
184 cbw_t cbw;
185 csw_t csw;
186
187 int always_succeed = 0;
188 if ((cb[0] == 0x1b) && (cb[4] == 1)) { //start command, always succeed
189 always_succeed = 1;
190 }
191 wrap_cbw (&cbw, buflen, dir, cb, cblen);
192 if (dev->controller->
193 bulk (MSC_INST (dev)->bulk_out, sizeof (cbw), (u8 *) &cbw, 0)) {
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000194 reset_transport (dev);
Patrick Georgid21f68b2008-09-02 16:06:22 +0000195 return 1;
196 }
197 mdelay (10);
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000198 if (buflen > 0) {
199 if (dir == cbw_direction_data_in) {
200 if (dev->controller->
201 bulk (MSC_INST (dev)->bulk_in, buflen, buf, 0)) {
202 clear_stall (MSC_INST (dev)->bulk_in);
203 return 1;
204 }
205 } else {
206 if (dev->controller->
207 bulk (MSC_INST (dev)->bulk_out, buflen, buf, 0)) {
208 clear_stall (MSC_INST (dev)->bulk_out);
209 return 1;
210 }
Patrick Georgid21f68b2008-09-02 16:06:22 +0000211 }
212 }
213 get_csw (MSC_INST (dev)->bulk_in, &csw);
214 if (always_succeed == 1) {
215 // return success, regardless of message
216 return 0;
217 }
218 if (csw.bCSWStatus == 2) {
219 // phase error, reset transport
220 reset_transport (dev);
221 return 1;
222 }
223 if (csw.bCSWStatus == 0) {
224 // no error, exit
225 return 0;
226 }
227 // error "check condition" or reserved error
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000228 request_sense (dev);
Patrick Georgid21f68b2008-09-02 16:06:22 +0000229 return 1;
230}
231
232typedef struct {
233 unsigned char command; //0
234 unsigned char res1; //1
235 unsigned int block; //2-5
236 unsigned char res2; //6
237 unsigned short numblocks; //7-8
238 unsigned char res3; //9 - the block is 10 bytes long
239} __attribute__ ((packed)) cmdblock_t;
240
241typedef struct {
242 unsigned char command; //0
243 unsigned char res1; //1
244 unsigned char res2; //2
245 unsigned char res3; //3
246 unsigned char lun; //4
247 unsigned char res4; //5
248} __attribute__ ((packed)) cmdblock6_t;
249
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000250/**
251 * Like readwrite_blocks, but for soft-sectors of 512b size. Converts the
252 * start and count from 512b units.
253 * Start and count must be aligned so that they match the native
254 * sector size.
255 *
256 * @param dev device to access
257 * @param start first sector to access
258 * @param n number of sectors to access
259 * @param dir direction of access: cbw_direction_data_in == read, cbw_direction_data_out == write
260 * @param buf buffer to read into or write from. Must be at least n*512 bytes
261 * @return 0 on success, 1 on failure
262 */
263int
264readwrite_blocks_512 (usbdev_t *dev, int start, int n,
265 cbw_direction dir, u8 *buf)
266{
267 int blocksize_divider = MSC_INST(dev)->blocksize / 512;
268 return readwrite_blocks (dev, start / blocksize_divider,
269 n / blocksize_divider, dir, buf);
270}
Patrick Georgid21f68b2008-09-02 16:06:22 +0000271
272/**
273 * Reads or writes a number of sequential blocks on a USB storage device.
274 * As it uses the READ(10) SCSI-2 command, it's limited to storage devices
275 * of at most 2TB. It assumes sectors of 512 bytes.
276 *
277 * @param dev device to access
278 * @param start first sector to access
279 * @param n number of sectors to access
280 * @param dir direction of access: cbw_direction_data_in == read, cbw_direction_data_out == write
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000281 * @param buf buffer to read into or write from. Must be at least n*sectorsize bytes
Patrick Georgid21f68b2008-09-02 16:06:22 +0000282 * @return 0 on success, 1 on failure
283 */
284int
285readwrite_blocks (usbdev_t *dev, int start, int n, cbw_direction dir, u8 *buf)
286{
287 cmdblock_t cb;
288 memset (&cb, 0, sizeof (cb));
289 if (dir == cbw_direction_data_in) {
290 // read
291 cb.command = 0x28;
292 } else {
293 // write
294 cb.command = 0x2a;
295 }
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000296 cb.block = htonl (start);
297 cb.numblocks = htonw (n);
Stefan Reinauer14e22772010-04-27 06:56:47 +0000298
Patrick Georgid21f68b2008-09-02 16:06:22 +0000299 return execute_command (dev, dir, (u8 *) &cb, sizeof (cb), buf,
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000300 n * MSC_INST(dev)->blocksize);
301}
302
303/* Only request it, we don't interpret it.
304 On certain errors, that's necessary to get devices out of
305 a special state called "Contingent Allegiance Condition" */
306static int
307request_sense (usbdev_t *dev)
308{
309 u8 buf[19];
310 cmdblock6_t cb;
311 memset (&cb, 0, sizeof (cb));
312 cb.command = 0x3;
Stefan Reinauer14e22772010-04-27 06:56:47 +0000313
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000314 return execute_command (dev, cbw_direction_data_in, (u8 *) &cb,
315 sizeof (cb), buf, 19);
Patrick Georgid21f68b2008-09-02 16:06:22 +0000316}
317
318static int
319test_unit_ready (usbdev_t *dev)
320{
321 cmdblock6_t cb;
322 memset (&cb, 0, sizeof (cb)); // full initialization for T-U-R
323 return execute_command (dev, cbw_direction_data_out, (u8 *) &cb,
324 sizeof (cb), 0, 0);
325}
326
327static int
328spin_up (usbdev_t *dev)
329{
330 cmdblock6_t cb;
331 memset (&cb, 0, sizeof (cb));
332 cb.command = 0x1b;
333 cb.lun = 1;
334 return execute_command (dev, cbw_direction_data_out, (u8 *) &cb,
335 sizeof (cb), 0, 0);
336}
337
338static void
339read_capacity (usbdev_t *dev)
340{
341 cmdblock_t cb;
342 memset (&cb, 0, sizeof (cb));
343 cb.command = 0x25; // read capacity
344 u8 buf[8];
Stefan Reinauerd233f362009-04-30 16:46:12 +0000345
Mathias Krausec4716b42011-06-08 15:36:55 +0200346 debug ("Reading capacity of mass storage device.\n");
Patrick Georgid21f68b2008-09-02 16:06:22 +0000347 int count = 0;
348 while ((count++ < 20)
349 &&
350 (execute_command
351 (dev, cbw_direction_data_in, (u8 *) &cb, sizeof (cb), buf,
352 8) == 1));
353 if (count >= 20) {
Stefan Reinauerd233f362009-04-30 16:46:12 +0000354 // 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 +0200355 printf (" assuming 2 TB with 512-byte sectors as READ CAPACITY didn't answer.\n");
Patrick Georgid21f68b2008-09-02 16:06:22 +0000356 MSC_INST (dev)->numblocks = 0xffffffff;
357 MSC_INST (dev)->blocksize = 512;
358 } else {
359 MSC_INST (dev)->numblocks = ntohl (*(u32 *) buf) + 1;
360 MSC_INST (dev)->blocksize = ntohl (*(u32 *) (buf + 4));
361 }
Mathias Krausec4716b42011-06-08 15:36:55 +0200362 printf (" %d %d-byte sectors (%d MB)\n", MSC_INST (dev)->numblocks,
363 MSC_INST (dev)->blocksize,
364 MSC_INST (dev)->numblocks * MSC_INST (dev)->blocksize / 1000 / 1000);
Patrick Georgid21f68b2008-09-02 16:06:22 +0000365}
366
367void
368usb_msc_init (usbdev_t *dev)
369{
370 int i, timeout;
371
372 dev->destroy = usb_msc_destroy;
373 dev->poll = usb_msc_poll;
374
375 configuration_descriptor_t *cd =
376 (configuration_descriptor_t *) dev->configuration;
377 interface_descriptor_t *interface =
378 (interface_descriptor_t *) (((char *) cd) + cd->bLength);
379
Mathias Krausec4716b42011-06-08 15:36:55 +0200380 debug (" it uses %s command set\n",
Patrick Georgid21f68b2008-09-02 16:06:22 +0000381 msc_subclass_strings[interface->bInterfaceSubClass]);
Mathias Krausec4716b42011-06-08 15:36:55 +0200382 debug (" it uses %s protocol\n",
Patrick Georgid21f68b2008-09-02 16:06:22 +0000383 msc_protocol_strings[interface->bInterfaceProtocol]);
384
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000385
386 if (interface->bInterfaceProtocol != 0x50) {
387 printf (" Protocol not supported.\n");
388 return;
389 }
390
391 if ((interface->bInterfaceSubClass != 2) && // ATAPI 8020
392 (interface->bInterfaceSubClass != 5) && // ATAPI 8070
393 (interface->bInterfaceSubClass != 6)) { // SCSI
Patrick Georgid21f68b2008-09-02 16:06:22 +0000394 /* 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 +0000395 printf (" Interface SubClass not supported.\n");
Patrick Georgid21f68b2008-09-02 16:06:22 +0000396 return;
397 }
398
399 dev->data = malloc (sizeof (usbmsc_inst_t));
Stefan Reinauer5fe6e232009-07-31 11:39:55 +0000400 if (!dev->data)
Patrick Georgi2e768e72011-11-04 11:50:03 +0100401 fatal("Not enough memory for USB MSC device.\n");
Stefan Reinauer5fe6e232009-07-31 11:39:55 +0000402
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000403 MSC_INST (dev)->protocol = interface->bInterfaceSubClass;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000404 MSC_INST (dev)->bulk_in = 0;
405 MSC_INST (dev)->bulk_out = 0;
406
407 for (i = 1; i <= dev->num_endp; i++) {
408 if (dev->endpoints[i].endpoint == 0)
409 continue;
410 if (dev->endpoints[i].type != BULK)
411 continue;
412 if ((dev->endpoints[i].direction == IN)
413 && (MSC_INST (dev)->bulk_in == 0))
414 MSC_INST (dev)->bulk_in = &dev->endpoints[i];
415 if ((dev->endpoints[i].direction == OUT)
416 && (MSC_INST (dev)->bulk_out == 0))
417 MSC_INST (dev)->bulk_out = &dev->endpoints[i];
418 }
419
420 if (MSC_INST (dev)->bulk_in == 0)
421 fatal ("couldn't find bulk-in endpoint");
422 if (MSC_INST (dev)->bulk_out == 0)
423 fatal ("couldn't find bulk-out endpoint");
Mathias Krausec4716b42011-06-08 15:36:55 +0200424 debug (" using endpoint %x as in, %x as out\n",
Patrick Georgid21f68b2008-09-02 16:06:22 +0000425 MSC_INST (dev)->bulk_in->endpoint,
426 MSC_INST (dev)->bulk_out->endpoint);
427
Mathias Krausec4716b42011-06-08 15:36:55 +0200428 debug (" has %d luns\n", get_max_luns (dev) + 1);
Patrick Georgid21f68b2008-09-02 16:06:22 +0000429
Mathias Krausec4716b42011-06-08 15:36:55 +0200430 printf (" Waiting for device to become ready...");
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000431 timeout = 30 * 10; /* SCSI/ATA specs say we have to wait up to 30s. Ugh */
Patrick Georgid21f68b2008-09-02 16:06:22 +0000432 while (test_unit_ready (dev) && --timeout) {
433 mdelay (100);
Stefan Reinauer14e22772010-04-27 06:56:47 +0000434 if (!(timeout % 10))
Stefan Reinauerb56f2d02010-03-25 22:17:36 +0000435 printf (".");
Patrick Georgid21f68b2008-09-02 16:06:22 +0000436 }
437 if (test_unit_ready (dev)) {
438 printf ("timeout. Device not ready. Still trying...\n");
439 } else {
440 printf ("ok.\n");
441 }
442
Mathias Krausec4716b42011-06-08 15:36:55 +0200443 debug (" spin up");
Patrick Georgid21f68b2008-09-02 16:06:22 +0000444 for (i = 0; i < 30; i++) {
Mathias Krausec4716b42011-06-08 15:36:55 +0200445 debug (".");
Patrick Georgid21f68b2008-09-02 16:06:22 +0000446 if (!spin_up (dev)) {
Mathias Krausec4716b42011-06-08 15:36:55 +0200447 debug (" OK.");
Patrick Georgid21f68b2008-09-02 16:06:22 +0000448 break;
449 }
450 mdelay (100);
451 }
Mathias Krausec4716b42011-06-08 15:36:55 +0200452 debug ("\n");
Patrick Georgid21f68b2008-09-02 16:06:22 +0000453
454 read_capacity (dev);
Patrick Georgi4727c072008-10-16 19:20:51 +0000455 if (usbdisk_create)
456 usbdisk_create (dev);
Patrick Georgid21f68b2008-09-02 16:06:22 +0000457}