- reduced memory requirements a lot (from >100kb/controller to
[coreboot.git] / payloads / libpayload / drivers / usb / usbmsc.c
1 /*
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/usb.h>
32 #include <usb/usbmsc.h>
33 #include <usb/usbdisk.h>
34
35 enum {
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 };
43 static 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 };
52 enum {
53         msc_proto_cbi_wcomp = 0x0,
54         msc_proto_cbi_wocomp = 0x1,
55         msc_proto_bulk_only = 0x50
56 };
57 static 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
69 static void
70 usb_msc_destroy (usbdev_t *dev)
71 {
72         if (usbdisk_remove)
73                 usbdisk_remove (dev);
74         free (dev->data);
75         dev->data = 0;
76 }
77
78 static void
79 usb_msc_poll (usbdev_t *dev)
80 {
81 }
82
83 const int DEV_RESET = 0xff;
84 const int GET_MAX_LUN = 0xfe;
85
86 const unsigned int cbw_signature = 0x43425355;
87 const unsigned int csw_signature = 0x53425355;
88
89 typedef 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! */
131 static int
132 get_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
152 int tag;
153 int lun = 0;
154
155 static void
156 wrap_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
171 static void
172 get_csw (endpoint_t *ep, csw_t *csw)
173 {
174         ep->dev->controller->bulk (ep, sizeof (csw_t), (u8 *) csw, 1);
175 }
176
177 static int
178 execute_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
226 typedef 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
235 typedef 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  */
257 int
258 readwrite_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
275 static int
276 test_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
284 static int
285 spin_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
295 static void
296 read_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];
302         int count = 0;
303         while ((count++ < 20)
304                &&
305                (execute_command
306                 (dev, cbw_direction_data_in, (u8 *) &cb, sizeof (cb), buf,
307                  8) == 1));
308         if (count >= 20) {
309                 // still not successful, assume 2tb in 512byte sectors, which is just the same garbage as any other number, but probably reasonable.
310                 printf ("assuming 2TB in 512byte sectors as READ CAPACITY didn't answer.\n");
311                 MSC_INST (dev)->numblocks = 0xffffffff;
312                 MSC_INST (dev)->blocksize = 512;
313         } else {
314                 MSC_INST (dev)->numblocks = ntohl (*(u32 *) buf) + 1;
315                 MSC_INST (dev)->blocksize = ntohl (*(u32 *) (buf + 4));
316         }
317         printf ("  has %d blocks sized %db\n", MSC_INST (dev)->numblocks,
318                 MSC_INST (dev)->blocksize);
319 }
320
321 void
322 usb_msc_init (usbdev_t *dev)
323 {
324         int i, timeout;
325
326         dev->destroy = usb_msc_destroy;
327         dev->poll = usb_msc_poll;
328
329         configuration_descriptor_t *cd =
330                 (configuration_descriptor_t *) dev->configuration;
331         interface_descriptor_t *interface =
332                 (interface_descriptor_t *) (((char *) cd) + cd->bLength);
333
334         printf ("  it uses %s command set\n",
335                 msc_subclass_strings[interface->bInterfaceSubClass]);
336         printf ("  it uses %s protocol\n",
337                 msc_protocol_strings[interface->bInterfaceProtocol]);
338
339         if ((interface->bInterfaceProtocol != 0x50)
340             || (interface->bInterfaceSubClass != 6)) {
341                 /* Other protocols, such as ATAPI don't seem to be very popular. looks like ATAPI would be really easy to add, if necessary. */
342                 printf ("  Only SCSI over Bulk is supported.\n");
343                 return;
344         }
345
346         dev->data = malloc (sizeof (usbmsc_inst_t));
347         MSC_INST (dev)->bulk_in = 0;
348         MSC_INST (dev)->bulk_out = 0;
349
350         for (i = 1; i <= dev->num_endp; i++) {
351                 if (dev->endpoints[i].endpoint == 0)
352                         continue;
353                 if (dev->endpoints[i].type != BULK)
354                         continue;
355                 if ((dev->endpoints[i].direction == IN)
356                     && (MSC_INST (dev)->bulk_in == 0))
357                         MSC_INST (dev)->bulk_in = &dev->endpoints[i];
358                 if ((dev->endpoints[i].direction == OUT)
359                     && (MSC_INST (dev)->bulk_out == 0))
360                         MSC_INST (dev)->bulk_out = &dev->endpoints[i];
361         }
362
363         if (MSC_INST (dev)->bulk_in == 0)
364                 fatal ("couldn't find bulk-in endpoint");
365         if (MSC_INST (dev)->bulk_out == 0)
366                 fatal ("couldn't find bulk-out endpoint");
367         printf ("  using endpoint %x as in, %x as out\n",
368                 MSC_INST (dev)->bulk_in->endpoint,
369                 MSC_INST (dev)->bulk_out->endpoint);
370
371         printf ("  has %d luns\n", get_max_luns (dev) + 1);
372
373         printf ("  Waiting for device to become ready... ");
374         timeout = 10;
375         while (test_unit_ready (dev) && --timeout) {
376                 mdelay (100);
377                 printf (".");
378         }
379         if (test_unit_ready (dev)) {
380                 printf ("timeout. Device not ready. Still trying...\n");
381         } else {
382                 printf ("ok.\n");
383         }
384
385         printf ("  spin up");
386         for (i = 0; i < 30; i++) {
387                 printf (".");
388                 if (!spin_up (dev)) {
389                         printf (" OK.");
390                         break;
391                 }
392                 mdelay (100);
393         }
394         printf ("\n");
395
396         read_capacity (dev);
397         if (usbdisk_create)
398                 usbdisk_create (dev);
399 }