libpayload: Reduce verbosity in USB stack
[coreboot.git] / payloads / libpayload / drivers / usb / usbmsc.c
index cbef585e24a05d54bd1a5069546111e9af44fd05..729bf9117128d0a598854c8f135a4f810ff540b2 100644 (file)
@@ -28,9 +28,9 @@
  */
 
 #include <arch/endian.h>
-#include "usb.h"
-#include "usbmsc.h"
-#include "usbdisk.h"
+#include <usb/usb.h>
+#include <usb/usbmsc.h>
+#include <usb/usbdisk.h>
 
 enum {
        msc_subclass_rbc = 0x1,
@@ -40,6 +40,7 @@ enum {
        msc_subclass_sff8070i = 0x5,
        msc_subclass_scsitrans = 0x6
 };
+
 static const char *msc_subclass_strings[7] = {
        "(none)",
        "RBC",
@@ -69,7 +70,8 @@ static const char *msc_protocol_strings[0x51] = {
 static void
 usb_msc_destroy (usbdev_t *dev)
 {
-       usbdisk_remove (dev);
+       if (usbdisk_remove)
+               usbdisk_remove (dev);
        free (dev->data);
        dev->data = 0;
 }
@@ -95,19 +97,20 @@ typedef struct {
        unsigned long bCBWCBLength:5;
        unsigned long:3;
        unsigned char CBWCB[31 - 15];
-} __attribute__ ((packed))
-     cbw_t;
-
-     typedef struct {
-            unsigned int dCSWSignature;
-            unsigned int dCSWTag;
-            unsigned int dCSWDataResidue;
-            unsigned char bCSWStatus;
-     } __attribute__ ((packed))
-     csw_t;
-
-     static void
-       reset_transport (usbdev_t *dev)
+} __attribute__ ((packed)) cbw_t;
+
+typedef struct {
+       unsigned int dCSWSignature;
+       unsigned int dCSWTag;
+       unsigned int dCSWDataResidue;
+       unsigned char bCSWStatus;
+} __attribute__ ((packed)) csw_t;
+
+static int
+request_sense (usbdev_t *dev);
+
+static void
+reset_transport (usbdev_t *dev)
 {
        dev_req_t dr;
        memset (&dr, 0, sizeof (dr));
@@ -170,7 +173,8 @@ wrap_cbw (cbw_t *cbw, int datalen, cbw_direction dir, const u8 *cmd,
 static void
 get_csw (endpoint_t *ep, csw_t *csw)
 {
-       ep->dev->controller->bulk (ep, sizeof (csw_t), (u8 *) csw, 1);
+       if (ep->dev->controller->bulk (ep, sizeof (csw_t), (u8 *) csw, 1))
+               clear_stall (ep);
 }
 
 static int
@@ -187,21 +191,23 @@ execute_command (usbdev_t *dev, cbw_direction dir, const u8 *cb, int cblen,
        wrap_cbw (&cbw, buflen, dir, cb, cblen);
        if (dev->controller->
            bulk (MSC_INST (dev)->bulk_out, sizeof (cbw), (u8 *) &cbw, 0)) {
-               clear_stall (MSC_INST (dev)->bulk_out);
+               reset_transport (dev);
                return 1;
        }
        mdelay (10);
-       if (dir == cbw_direction_data_in) {
-               if (dev->controller->
-                   bulk (MSC_INST (dev)->bulk_in, buflen, buf, 0)) {
-                       clear_stall (MSC_INST (dev)->bulk_in);
-                       return 1;
-               }
-       } else {
-               if (dev->controller->
-                   bulk (MSC_INST (dev)->bulk_out, buflen, buf, 0)) {
-                       clear_stall (MSC_INST (dev)->bulk_out);
-                       return 1;
+       if (buflen > 0) {
+               if (dir == cbw_direction_data_in) {
+                       if (dev->controller->
+                           bulk (MSC_INST (dev)->bulk_in, buflen, buf, 0)) {
+                               clear_stall (MSC_INST (dev)->bulk_in);
+                               return 1;
+                       }
+               } else {
+                       if (dev->controller->
+                           bulk (MSC_INST (dev)->bulk_out, buflen, buf, 0)) {
+                               clear_stall (MSC_INST (dev)->bulk_out);
+                               return 1;
+                       }
                }
        }
        get_csw (MSC_INST (dev)->bulk_in, &csw);
@@ -219,6 +225,7 @@ execute_command (usbdev_t *dev, cbw_direction dir, const u8 *cb, int cblen,
                return 0;
        }
        // error "check condition" or reserved error
+       request_sense (dev);
        return 1;
 }
 
@@ -240,6 +247,27 @@ typedef struct {
        unsigned char res4;     //5
 } __attribute__ ((packed)) cmdblock6_t;
 
+/**
+ * Like readwrite_blocks, but for soft-sectors of 512b size. Converts the
+ * start and count from 512b units.
+ * Start and count must be aligned so that they match the native
+ * sector size.
+ *
+ * @param dev device to access
+ * @param start first sector to access
+ * @param n number of sectors to access
+ * @param dir direction of access: cbw_direction_data_in == read, cbw_direction_data_out == write
+ * @param buf buffer to read into or write from. Must be at least n*512 bytes
+ * @return 0 on success, 1 on failure
+ */
+int
+readwrite_blocks_512 (usbdev_t *dev, int start, int n,
+       cbw_direction dir, u8 *buf)
+{
+       int blocksize_divider = MSC_INST(dev)->blocksize / 512;
+       return readwrite_blocks (dev, start / blocksize_divider,
+               n / blocksize_divider, dir, buf);
+}
 
 /**
  * Reads or writes a number of sequential blocks on a USB storage device.
@@ -250,7 +278,7 @@ typedef struct {
  * @param start first sector to access
  * @param n number of sectors to access
  * @param dir direction of access: cbw_direction_data_in == read, cbw_direction_data_out == write
- * @param buf buffer to read into or write from. Must be at least n*512 bytes
+ * @param buf buffer to read into or write from. Must be at least n*sectorsize bytes
  * @return 0 on success, 1 on failure
  */
 int
@@ -265,10 +293,26 @@ readwrite_blocks (usbdev_t *dev, int start, int n, cbw_direction dir, u8 *buf)
                // write
                cb.command = 0x2a;
        }
-       cb.block = ntohl (start);
-       cb.numblocks = ntohw (n);
+       cb.block = htonl (start);
+       cb.numblocks = htonw (n);
+
        return execute_command (dev, dir, (u8 *) &cb, sizeof (cb), buf,
-                               n * 512);
+                               n * MSC_INST(dev)->blocksize);
+}
+
+/* Only request it, we don't interpret it.
+   On certain errors, that's necessary to get devices out of
+   a special state called "Contingent Allegiance Condition" */
+static int
+request_sense (usbdev_t *dev)
+{
+       u8 buf[19];
+       cmdblock6_t cb;
+       memset (&cb, 0, sizeof (cb));
+       cb.command = 0x3;
+
+       return execute_command (dev, cbw_direction_data_in, (u8 *) &cb,
+                               sizeof (cb), buf, 19);
 }
 
 static int
@@ -298,6 +342,8 @@ read_capacity (usbdev_t *dev)
        memset (&cb, 0, sizeof (cb));
        cb.command = 0x25;      // read capacity
        u8 buf[8];
+
+       debug ("Reading capacity of mass storage device.\n");
        int count = 0;
        while ((count++ < 20)
               &&
@@ -305,16 +351,17 @@ read_capacity (usbdev_t *dev)
                (dev, cbw_direction_data_in, (u8 *) &cb, sizeof (cb), buf,
                 8) == 1));
        if (count >= 20) {
-               // still not successful, assume 2tb in 512byte sectors, which is just the same garbage as any other number, but probably reasonable.
-               printf ("assuming 2TB in 512byte sectors as READ CAPACITY didn't answer.\n");
+               // still not successful, assume 2tb in 512byte sectors, which is just the same garbage as any other number, but probably more usable.
+               printf ("  assuming 2 TB with 512-byte sectors as READ CAPACITY didn't answer.\n");
                MSC_INST (dev)->numblocks = 0xffffffff;
                MSC_INST (dev)->blocksize = 512;
        } else {
                MSC_INST (dev)->numblocks = ntohl (*(u32 *) buf) + 1;
                MSC_INST (dev)->blocksize = ntohl (*(u32 *) (buf + 4));
        }
-       printf ("  has %d blocks sized %db\n", MSC_INST (dev)->numblocks,
-               MSC_INST (dev)->blocksize);
+       printf ("  %d %d-byte sectors (%d MB)\n", MSC_INST (dev)->numblocks,
+               MSC_INST (dev)->blocksize,
+               MSC_INST (dev)->numblocks * MSC_INST (dev)->blocksize / 1000 / 1000);
 }
 
 void
@@ -330,19 +377,30 @@ usb_msc_init (usbdev_t *dev)
        interface_descriptor_t *interface =
                (interface_descriptor_t *) (((char *) cd) + cd->bLength);
 
-       printf ("  it uses %s command set\n",
+       debug ("  it uses %s command set\n",
                msc_subclass_strings[interface->bInterfaceSubClass]);
-       printf ("  it uses %s protocol\n",
+       debug ("  it uses %s protocol\n",
                msc_protocol_strings[interface->bInterfaceProtocol]);
 
-       if ((interface->bInterfaceProtocol != 0x50)
-           || (interface->bInterfaceSubClass != 6)) {
+
+       if (interface->bInterfaceProtocol != 0x50) {
+               printf ("  Protocol not supported.\n");
+               return;
+       }
+
+       if ((interface->bInterfaceSubClass != 2) &&     // ATAPI 8020
+               (interface->bInterfaceSubClass != 5) && // ATAPI 8070
+               (interface->bInterfaceSubClass != 6)) { // SCSI
                /* Other protocols, such as ATAPI don't seem to be very popular. looks like ATAPI would be really easy to add, if necessary. */
-               printf ("  Only SCSI over Bulk is supported.\n");
+               printf ("  Interface SubClass not supported.\n");
                return;
        }
 
        dev->data = malloc (sizeof (usbmsc_inst_t));
+       if (!dev->data)
+               usb_fatal ("Not enough memory for USB MSC device.\n");
+
+       MSC_INST (dev)->protocol = interface->bInterfaceSubClass;
        MSC_INST (dev)->bulk_in = 0;
        MSC_INST (dev)->bulk_out = 0;
 
@@ -363,17 +421,18 @@ usb_msc_init (usbdev_t *dev)
                fatal ("couldn't find bulk-in endpoint");
        if (MSC_INST (dev)->bulk_out == 0)
                fatal ("couldn't find bulk-out endpoint");
-       printf ("  using endpoint %x as in, %x as out\n",
+       debug ("  using endpoint %x as in, %x as out\n",
                MSC_INST (dev)->bulk_in->endpoint,
                MSC_INST (dev)->bulk_out->endpoint);
 
-       printf ("  has %d luns\n", get_max_luns (dev) + 1);
+       debug ("  has %d luns\n", get_max_luns (dev) + 1);
 
-       printf ("  Waiting for device to become ready... ");
-       timeout = 10;
+       printf ("  Waiting for device to become ready...");
+       timeout = 30 * 10; /* SCSI/ATA specs say we have to wait up to 30s. Ugh */
        while (test_unit_ready (dev) && --timeout) {
                mdelay (100);
-               printf (".");
+               if (!(timeout % 10))
+                       printf (".");
        }
        if (test_unit_ready (dev)) {
                printf ("timeout. Device not ready. Still trying...\n");
@@ -381,17 +440,18 @@ usb_msc_init (usbdev_t *dev)
                printf ("ok.\n");
        }
 
-       printf ("  spin up");
+       debug ("  spin up");
        for (i = 0; i < 30; i++) {
-               printf (".");
+               debug (".");
                if (!spin_up (dev)) {
-                       printf (" OK.");
+                       debug (" OK.");
                        break;
                }
                mdelay (100);
        }
-       printf ("\n");
+       debug ("\n");
 
        read_capacity (dev);
-       usbdisk_create (dev);
+       if (usbdisk_create)
+               usbdisk_create (dev);
 }