blob: ad4a10c1469b33d8d09083fa510056e9bd65158e [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};
43static const char *msc_subclass_strings[7] = {
44 "(none)",
45 "RBC",
46 "MMC-2",
47 "QIC-157",
48 "UFI",
49 "SFF-8070i",
50 "SCSI transparent"
51};
52enum {
53 msc_proto_cbi_wcomp = 0x0,
54 msc_proto_cbi_wocomp = 0x1,
55 msc_proto_bulk_only = 0x50
56};
57static const char *msc_protocol_strings[0x51] = {
58 "Control/Bulk/Interrupt protocol (with command completion interrupt)",
59 "Control/Bulk/Interrupt protocol (with no command completion interrupt)",
60 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
61 0, 0, 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 "Bulk-Only Transport"
66};
67
68
69static void
70usb_msc_destroy (usbdev_t *dev)
71{
Patrick Georgi4727c072008-10-16 19:20:51 +000072 if (usbdisk_remove)
73 usbdisk_remove (dev);
Patrick Georgid21f68b2008-09-02 16:06:22 +000074 free (dev->data);
75 dev->data = 0;
76}
77
78static void
79usb_msc_poll (usbdev_t *dev)
80{
81}
82
83const int DEV_RESET = 0xff;
84const int GET_MAX_LUN = 0xfe;
85
86const unsigned int cbw_signature = 0x43425355;
87const unsigned int csw_signature = 0x53425355;
88
89typedef struct {
90 unsigned int dCBWSignature;
91 unsigned int dCBWTag;
92 unsigned int dCBWDataTransferLength;
93 unsigned char bmCBWFlags;
94 unsigned long bCBWLUN:4;
95 unsigned long:4;
96 unsigned long bCBWCBLength:5;
97 unsigned long:3;
98 unsigned char CBWCB[31 - 15];
99} __attribute__ ((packed))
100 cbw_t;
101
102 typedef struct {
103 unsigned int dCSWSignature;
104 unsigned int dCSWTag;
105 unsigned int dCSWDataResidue;
106 unsigned char bCSWStatus;
107 } __attribute__ ((packed))
108 csw_t;
109
110 static void
111 reset_transport (usbdev_t *dev)
112{
113 dev_req_t dr;
114 memset (&dr, 0, sizeof (dr));
115 dr.bmRequestType = 0;
116 dr.data_dir = host_to_device;
117#ifndef QEMU
118 dr.req_type = class_type;
119 dr.req_recp = iface_recp;
120#endif
121 dr.bRequest = DEV_RESET;
122 dr.wValue = 0;
123 dr.wIndex = 0;
124 dr.wLength = 0;
125 dev->controller->control (dev, OUT, sizeof (dr), &dr, 0, 0);
126 clear_stall (MSC_INST (dev)->bulk_in);
127 clear_stall (MSC_INST (dev)->bulk_out);
128}
129
130/* device may stall this command, so beware! */
131static int
132get_max_luns (usbdev_t *dev)
133{
134 unsigned char luns = 75;
135 dev_req_t dr;
136 dr.bmRequestType = 0;
137 dr.data_dir = device_to_host;
138#ifndef QEMU
139 dr.req_type = class_type;
140 dr.req_recp = iface_recp;
141#endif
142 dr.bRequest = GET_MAX_LUN;
143 dr.wValue = 0;
144 dr.wIndex = 0;
145 dr.wLength = 1;
146 if (dev->controller->control (dev, IN, sizeof (dr), &dr, 1, &luns)) {
147 luns = 0; // assume only 1 lun if req fails
148 }
149 return luns;
150}
151
152int tag;
153int lun = 0;
154
155static void
156wrap_cbw (cbw_t *cbw, int datalen, cbw_direction dir, const u8 *cmd,
157 int cmdlen)
158{
159 memset (cbw, 0, sizeof (cbw_t));
160
161 cbw->dCBWSignature = cbw_signature;
162 cbw->dCBWTag = tag++;
163 cbw->bCBWLUN = lun; // static value per device
164
165 cbw->dCBWDataTransferLength = datalen;
166 cbw->bmCBWFlags = dir;
167 memcpy (cbw->CBWCB, cmd, sizeof (cbw->CBWCB));
168 cbw->bCBWCBLength = cmdlen;
169}
170
171static void
172get_csw (endpoint_t *ep, csw_t *csw)
173{
174 ep->dev->controller->bulk (ep, sizeof (csw_t), (u8 *) csw, 1);
175}
176
177static int
178execute_command (usbdev_t *dev, cbw_direction dir, const u8 *cb, int cblen,
179 u8 *buf, int buflen)
180{
181 cbw_t cbw;
182 csw_t csw;
183
184 int always_succeed = 0;
185 if ((cb[0] == 0x1b) && (cb[4] == 1)) { //start command, always succeed
186 always_succeed = 1;
187 }
188 wrap_cbw (&cbw, buflen, dir, cb, cblen);
189 if (dev->controller->
190 bulk (MSC_INST (dev)->bulk_out, sizeof (cbw), (u8 *) &cbw, 0)) {
191 clear_stall (MSC_INST (dev)->bulk_out);
192 return 1;
193 }
194 mdelay (10);
195 if (dir == cbw_direction_data_in) {
196 if (dev->controller->
197 bulk (MSC_INST (dev)->bulk_in, buflen, buf, 0)) {
198 clear_stall (MSC_INST (dev)->bulk_in);
199 return 1;
200 }
201 } else {
202 if (dev->controller->
203 bulk (MSC_INST (dev)->bulk_out, buflen, buf, 0)) {
204 clear_stall (MSC_INST (dev)->bulk_out);
205 return 1;
206 }
207 }
208 get_csw (MSC_INST (dev)->bulk_in, &csw);
209 if (always_succeed == 1) {
210 // return success, regardless of message
211 return 0;
212 }
213 if (csw.bCSWStatus == 2) {
214 // phase error, reset transport
215 reset_transport (dev);
216 return 1;
217 }
218 if (csw.bCSWStatus == 0) {
219 // no error, exit
220 return 0;
221 }
222 // error "check condition" or reserved error
223 return 1;
224}
225
226typedef struct {
227 unsigned char command; //0
228 unsigned char res1; //1
229 unsigned int block; //2-5
230 unsigned char res2; //6
231 unsigned short numblocks; //7-8
232 unsigned char res3; //9 - the block is 10 bytes long
233} __attribute__ ((packed)) cmdblock_t;
234
235typedef struct {
236 unsigned char command; //0
237 unsigned char res1; //1
238 unsigned char res2; //2
239 unsigned char res3; //3
240 unsigned char lun; //4
241 unsigned char res4; //5
242} __attribute__ ((packed)) cmdblock6_t;
243
244
245/**
246 * Reads or writes a number of sequential blocks on a USB storage device.
247 * As it uses the READ(10) SCSI-2 command, it's limited to storage devices
248 * of at most 2TB. It assumes sectors of 512 bytes.
249 *
250 * @param dev device to access
251 * @param start first sector to access
252 * @param n number of sectors to access
253 * @param dir direction of access: cbw_direction_data_in == read, cbw_direction_data_out == write
254 * @param buf buffer to read into or write from. Must be at least n*512 bytes
255 * @return 0 on success, 1 on failure
256 */
257int
258readwrite_blocks (usbdev_t *dev, int start, int n, cbw_direction dir, u8 *buf)
259{
260 cmdblock_t cb;
261 memset (&cb, 0, sizeof (cb));
262 if (dir == cbw_direction_data_in) {
263 // read
264 cb.command = 0x28;
265 } else {
266 // write
267 cb.command = 0x2a;
268 }
269 cb.block = ntohl (start);
270 cb.numblocks = ntohw (n);
271 return execute_command (dev, dir, (u8 *) &cb, sizeof (cb), buf,
272 n * 512);
273}
274
275static int
276test_unit_ready (usbdev_t *dev)
277{
278 cmdblock6_t cb;
279 memset (&cb, 0, sizeof (cb)); // full initialization for T-U-R
280 return execute_command (dev, cbw_direction_data_out, (u8 *) &cb,
281 sizeof (cb), 0, 0);
282}
283
284static int
285spin_up (usbdev_t *dev)
286{
287 cmdblock6_t cb;
288 memset (&cb, 0, sizeof (cb));
289 cb.command = 0x1b;
290 cb.lun = 1;
291 return execute_command (dev, cbw_direction_data_out, (u8 *) &cb,
292 sizeof (cb), 0, 0);
293}
294
295static void
296read_capacity (usbdev_t *dev)
297{
298 cmdblock_t cb;
299 memset (&cb, 0, sizeof (cb));
300 cb.command = 0x25; // read capacity
301 u8 buf[8];
Stefan Reinauerd233f362009-04-30 16:46:12 +0000302
303 printf ("Reading capacity of mass storage device.\n");
Patrick Georgid21f68b2008-09-02 16:06:22 +0000304 int count = 0;
305 while ((count++ < 20)
306 &&
307 (execute_command
308 (dev, cbw_direction_data_in, (u8 *) &cb, sizeof (cb), buf,
309 8) == 1));
310 if (count >= 20) {
Stefan Reinauerd233f362009-04-30 16:46:12 +0000311 // still not successful, assume 2tb in 512byte sectors, which is just the same garbage as any other number, but probably more usable.
312 printf ("Assuming 2TB in 512byte sectors as READ CAPACITY didn't answer.\n");
Patrick Georgid21f68b2008-09-02 16:06:22 +0000313 MSC_INST (dev)->numblocks = 0xffffffff;
314 MSC_INST (dev)->blocksize = 512;
315 } else {
316 MSC_INST (dev)->numblocks = ntohl (*(u32 *) buf) + 1;
317 MSC_INST (dev)->blocksize = ntohl (*(u32 *) (buf + 4));
318 }
319 printf (" has %d blocks sized %db\n", MSC_INST (dev)->numblocks,
320 MSC_INST (dev)->blocksize);
321}
322
323void
324usb_msc_init (usbdev_t *dev)
325{
326 int i, timeout;
327
328 dev->destroy = usb_msc_destroy;
329 dev->poll = usb_msc_poll;
330
331 configuration_descriptor_t *cd =
332 (configuration_descriptor_t *) dev->configuration;
333 interface_descriptor_t *interface =
334 (interface_descriptor_t *) (((char *) cd) + cd->bLength);
335
336 printf (" it uses %s command set\n",
337 msc_subclass_strings[interface->bInterfaceSubClass]);
338 printf (" it uses %s protocol\n",
339 msc_protocol_strings[interface->bInterfaceProtocol]);
340
341 if ((interface->bInterfaceProtocol != 0x50)
342 || (interface->bInterfaceSubClass != 6)) {
343 /* Other protocols, such as ATAPI don't seem to be very popular. looks like ATAPI would be really easy to add, if necessary. */
344 printf (" Only SCSI over Bulk is supported.\n");
345 return;
346 }
347
348 dev->data = malloc (sizeof (usbmsc_inst_t));
349 MSC_INST (dev)->bulk_in = 0;
350 MSC_INST (dev)->bulk_out = 0;
351
352 for (i = 1; i <= dev->num_endp; i++) {
353 if (dev->endpoints[i].endpoint == 0)
354 continue;
355 if (dev->endpoints[i].type != BULK)
356 continue;
357 if ((dev->endpoints[i].direction == IN)
358 && (MSC_INST (dev)->bulk_in == 0))
359 MSC_INST (dev)->bulk_in = &dev->endpoints[i];
360 if ((dev->endpoints[i].direction == OUT)
361 && (MSC_INST (dev)->bulk_out == 0))
362 MSC_INST (dev)->bulk_out = &dev->endpoints[i];
363 }
364
365 if (MSC_INST (dev)->bulk_in == 0)
366 fatal ("couldn't find bulk-in endpoint");
367 if (MSC_INST (dev)->bulk_out == 0)
368 fatal ("couldn't find bulk-out endpoint");
369 printf (" using endpoint %x as in, %x as out\n",
370 MSC_INST (dev)->bulk_in->endpoint,
371 MSC_INST (dev)->bulk_out->endpoint);
372
373 printf (" has %d luns\n", get_max_luns (dev) + 1);
374
375 printf (" Waiting for device to become ready... ");
376 timeout = 10;
377 while (test_unit_ready (dev) && --timeout) {
378 mdelay (100);
379 printf (".");
380 }
381 if (test_unit_ready (dev)) {
382 printf ("timeout. Device not ready. Still trying...\n");
383 } else {
384 printf ("ok.\n");
385 }
386
387 printf (" spin up");
388 for (i = 0; i < 30; i++) {
389 printf (".");
390 if (!spin_up (dev)) {
391 printf (" OK.");
392 break;
393 }
394 mdelay (100);
395 }
396 printf ("\n");
397
398 read_capacity (dev);
Patrick Georgi4727c072008-10-16 19:20:51 +0000399 if (usbdisk_create)
400 usbdisk_create (dev);
Patrick Georgid21f68b2008-09-02 16:06:22 +0000401}