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