Isaac Christensen (isaac.christensen@se-eng.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/6636
-gerrit
commit 2f775137ac4649247165375a805081be37f58d5f Author: Duncan Laurie dlaurie@chromium.org Date: Thu Sep 12 13:27:15 2013 -0700
libpayload: usbmsc: Split transfers into 64KB chunks
Add a new function to split transfer requests into chunks of 64KB in order to be as compatible as possible with devices that choke when sent large transfer requests.
Change-Id: Id11990bd149af14af5535de4af47bda21d1ab51e Signed-off-by: Duncan Laurie dlaurie@chromium.org Reviewed-on: https://chromium-review.googlesource.com/169170 Reviewed-by: Julius Werner jwerner@chromium.org (cherry picked from commit 4c413b007aa23da830877127dd556c4c38b43042) Signed-off-by: Isaac Christensen isaac.christensen@se-eng.com --- payloads/libpayload/drivers/usb/usbmsc.c | 48 +++++++++++++++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-)
diff --git a/payloads/libpayload/drivers/usb/usbmsc.c b/payloads/libpayload/drivers/usb/usbmsc.c index 2d28fbd..0259b8d 100644 --- a/payloads/libpayload/drivers/usb/usbmsc.c +++ b/payloads/libpayload/drivers/usb/usbmsc.c @@ -125,6 +125,9 @@ usb_msc_destroy (usbdev_t *dev)
const int DEV_RESET = 0xff; const int GET_MAX_LUN = 0xfe; +/* Many USB3 devices do not work with large transfer requests. + * Limit the request size to 64KB chunks to ensure maximum compatibility. */ +const int MAX_CHUNK_BYTES = 1024 * 64;
const unsigned int cbw_signature = 0x43425355; const unsigned int csw_signature = 0x53425355; @@ -363,7 +366,7 @@ readwrite_blocks_512 (usbdev_t *dev, int start, int n, * @return 0 on success, 1 on failure */ int -readwrite_blocks (usbdev_t *dev, int start, int n, cbw_direction dir, u8 *buf) +readwrite_chunk (usbdev_t *dev, int start, int n, cbw_direction dir, u8 *buf) { cmdblock_t cb; memset (&cb, 0, sizeof (cb)); @@ -382,6 +385,49 @@ readwrite_blocks (usbdev_t *dev, int start, int n, cbw_direction dir, u8 *buf) != MSC_COMMAND_OK ? 1 : 0; }
+/** + * Reads or writes a number of sequential blocks on a USB storage device + * that is split into MAX_CHUNK_BYTES size requests. + * + * As it uses the READ(10) SCSI-2 command, it's limited to storage devices + * of at most 2TB. It assumes sectors of 512 bytes. + * + * @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*sectorsize bytes + * @return 0 on success, 1 on failure + */ +int +readwrite_blocks (usbdev_t *dev, int start, int n, cbw_direction dir, u8 *buf) +{ + int chunk_size = MAX_CHUNK_BYTES / MSC_INST(dev)->blocksize; + int chunk; + + /* Read as many full chunks as needed. */ + for (chunk = 0; chunk < (n / chunk_size); chunk++) { + if (readwrite_chunk (dev, start + (chunk * chunk_size), + chunk_size, dir, + buf + (chunk * MAX_CHUNK_BYTES)) + != MSC_COMMAND_OK) + return 1; + } + + /* Read any remaining partial chunk at the end. */ + if (n % chunk_size) { + if (readwrite_chunk (dev, start + (chunk * chunk_size), + n % chunk_size, dir, + buf + (chunk * MAX_CHUNK_BYTES)) + != MSC_COMMAND_OK) + return 1; + } + + return 0; +} + /* 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" */