blob: 541307be7d80798ad546b7fcbeeebd48f597db3d [file] [log] [blame]
/*
* Copyright (C) 2008 coresystems GmbH
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <endian.h>
#include <stdint.h>
#include <stdlib.h>
#include <usb/usb.h>
#include "base/die.h"
#include "base/time.h"
#include "drivers/blockdev/usbdisk.h"
#include "drivers/blockdev/usbmsc.h"
enum {
msc_subclass_rbc = 0x1,
msc_subclass_mmc2 = 0x2,
msc_subclass_qic157 = 0x3,
msc_subclass_ufi = 0x4,
msc_subclass_sff8070i = 0x5,
msc_subclass_scsitrans = 0x6
};
static const char *decode_subclass_desc(uint8_t subclass)
{
switch (subclass) {
case 0x0: return "(none)";
case 0x1: return "RBC";
case 0x2: return "MMC-2";
case 0x3: return "QIC-157";
case 0x4: return "UFI";
case 0x5: return "SFF-8070i";
case 0x6: return "SCSI transparent";
default: return NULL;
}
};
enum {
msc_proto_cbi_wcomp = 0x0,
msc_proto_cbi_wocomp = 0x1,
msc_proto_bulk_only = 0x50
};
static const char *decode_protocol_desc(uint8_t protocol)
{
switch (protocol) {
case 0x00:
return "Control/Bulk/Interrupt protocol "
"(with command completion interrupt)";
case 0x01:
return "Control/Bulk/Interrupt protocol "
"(with no command completion interrupt)";
case 0x51:
return "Bulk-Only Transport";
default:
return NULL;
}
};
static void usb_msc_create_disk(UsbDev *dev)
{
if (usbdisk_create) {
usbdisk_create(dev);
MSC_INST(dev)->usbdisk_created = 1;
}
}
static void usb_msc_remove_disk(UsbDev *dev)
{
if (MSC_INST(dev)->usbdisk_created && usbdisk_remove)
usbdisk_remove(dev);
}
static void usb_msc_destroy(UsbDev *dev)
{
if (dev->data) {
usb_msc_remove_disk(dev);
free(dev->data);
}
dev->data = 0;
}
// Many USB3 devices do not work with large transfer requests.
// Limit the request size to 64KB chunks to ensure maximum compatibility.
static const int MAX_CHUNK_BYTES = 1024 * 64;
typedef struct {
uint32_t dCBWSignature;
uint32_t dCBWTag;
uint32_t dCBWDataTransferLength;
uint8_t bmCBWFlags;
uint32_t bCBWLUN:4;
uint32_t:4;
uint32_t bCBWCBLength:5;
uint32_t:3;
uint8_t CBWCB[31 - 15];
} __attribute__((packed)) cbw_t;
typedef struct {
uint32_t dCSWSignature;
uint32_t dCSWTag;
uint32_t dCSWDataResidue;
uint8_t bCSWStatus;
} __attribute__((packed)) csw_t;
enum {
/*
* MSC commands can be
* successful,
* fail with proper response or
* fail totally, which results in detaching of the usb device
* and immediate cleanup of the UsbDev structure.
* In the latter case the caller has to make sure that they won't
* use the device any more.
*/
MSC_COMMAND_OK,
MSC_COMMAND_FAIL,
MSC_COMMAND_DETACHED
};
static int request_sense(UsbDev *dev);
static int request_sense_no_media(UsbDev *dev);
static void usb_msc_poll(UsbDev *dev);
static int reset_transport(UsbDev *dev)
{
UsbDevReq dr;
memset(&dr, 0, sizeof (dr));
dr.bmRequestType = 0;
dr.data_dir = UsbHostToDevice;
dr.req_type = UsbClassType;
dr.req_recp = UsbIfaceRecp;
dr.bRequest = 0xff; // Device reset.
dr.wValue = 0;
dr.wIndex = 0;
dr.wLength = 0;
// If any of these fails, detach device, as we are lost.
if (dev->controller->control(dev, UsbDirOut, sizeof(dr),
&dr, 0, 0) < 0 ||
usb_clear_stall(MSC_INST(dev)->bulk_in) ||
usb_clear_stall(MSC_INST(dev)->bulk_out)) {
usb_debug("Detaching unresponsive device.\n");
usb_detach_device(dev->controller, dev->address);
return MSC_COMMAND_DETACHED;
}
// Return fail as we are only called in case of failure.
return MSC_COMMAND_FAIL;
}
// Device may stall this command, so beware!
static void initialize_luns(UsbDev *dev)
{
usbmsc_inst_t *msc = MSC_INST(dev);
UsbDevReq dr;
dr.bmRequestType = 0;
dr.data_dir = UsbDeviceToHost;
dr.req_type = UsbClassType;
dr.req_recp = UsbIfaceRecp;
dr.bRequest = 0xfe; // Get the maximum LUN.
dr.wValue = 0;
dr.wIndex = 0;
dr.wLength = 1;
if (dev->controller->control(dev, UsbDirIn, sizeof(dr), &dr,
sizeof(msc->num_luns), &msc->num_luns) < 0)
msc->num_luns = 0; // Assume only 1 lun if req fails.
msc->num_luns++; // Get Max LUN returns number of last LUN.
msc->lun = 0;
}
static unsigned int usbmsc_tag;
static void wrap_cbw(cbw_t *cbw, int datalen, cbw_direction dir,
const uint8_t *cmd, int cmdlen, uint8_t lun)
{
memset(cbw, 0, sizeof(cbw_t));
// Commands are typically shorter, but we don't want overflows.
if (cmdlen > sizeof(cbw->CBWCB))
cmdlen = sizeof(cbw->CBWCB);
cbw->dCBWSignature = 0x43425355;
cbw->dCBWTag = ++usbmsc_tag;
cbw->bCBWLUN = lun;
cbw->dCBWDataTransferLength = datalen;
cbw->bmCBWFlags = dir;
memcpy(cbw->CBWCB, cmd, cmdlen);
cbw->bCBWCBLength = cmdlen;
}
static int get_csw(UsbEndpoint *ep, csw_t *csw)
{
if (ep->dev->controller->bulk(ep, sizeof(csw_t),
(uint8_t *)csw, 1) < 0) {
usb_clear_stall(ep);
if (ep->dev->controller->bulk(ep, sizeof(csw_t),
(uint8_t *)csw, 1) < 0)
return reset_transport(ep->dev);
}
if (csw->dCSWTag != usbmsc_tag)
return reset_transport(ep->dev);
return MSC_COMMAND_OK;
}
static int execute_command(UsbDev *dev, cbw_direction dir, const uint8_t *cb,
int cblen, uint8_t *buf, int buflen, int residue_ok)
{
cbw_t cbw;
csw_t csw;
int always_succeed = 0;
if ((cb[0] == 0x1b) && (cb[4] == 1)) // Start command, always succeed.
always_succeed = 1;
wrap_cbw(&cbw, buflen, dir, cb, cblen, MSC_INST(dev)->lun);
if (dev->controller->bulk(MSC_INST(dev)->bulk_out, sizeof(cbw),
(uint8_t *)&cbw, 0) < 0) {
return reset_transport(dev);
}
if (buflen > 0) {
if (dir == cbw_direction_data_in) {
if (dev->controller->bulk(MSC_INST(dev)->bulk_in,
buflen, buf, 0) < 0)
usb_clear_stall(MSC_INST(dev)->bulk_in);
} else {
if (dev->controller->bulk(MSC_INST(dev)->bulk_out,
buflen, buf, 0) < 0)
usb_clear_stall(MSC_INST (dev)->bulk_out);
}
}
int ret = get_csw(MSC_INST(dev)->bulk_in, &csw);
if (ret) {
return ret;
} else if (always_succeed == 1) {
// Return success, regardless of message.
return MSC_COMMAND_OK;
} else if (csw.bCSWStatus == 2) {
// Phase error, reset transport.
return reset_transport(dev);
} else if (csw.bCSWStatus == 0) {
if (csw.dCSWDataResidue == 0 || residue_ok)
// No error, exit.
return MSC_COMMAND_OK;
else
// Missed some bytes.
return MSC_COMMAND_FAIL;
} else {
if (cb[0] == 0x03) {
// Requesting sense failed, that's bad.
return MSC_COMMAND_FAIL;
} else if (cb[0] == 0) {
// If command was TEST UNIT READY, determine if the
// device is of removable type indicating no media
// found.
return request_sense_no_media(dev);
}
// Error "check condition" or reserved error.
ret = request_sense(dev);
// Return fail or the status of request_sense if it's worse.
return ret ? ret : MSC_COMMAND_FAIL;
}
}
typedef struct {
uint8_t command; //0
uint8_t res1; //1
uint32_t block; //2-5
uint8_t res2; //6
uint16_t numblocks; //7-8
uint8_t control; //9 - the block is 10 bytes long
} __attribute__ ((packed)) cmdblock_t;
typedef struct {
uint8_t command; //0
uint8_t res1; //1
uint8_t res2; //2
uint8_t res3; //3
union { //4
struct {
uint32_t start:1; // for START STOP UNIT
uint32_t:7;
};
uint8_t length; // for REQUEST SENSE
};
uint8_t control; //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 *dev, int start, int n,
cbw_direction dir, uint8_t *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.
* 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
*/
static int readwrite_chunk(UsbDev *dev, int start, int n,
cbw_direction dir, uint8_t *buf)
{
enum {
READ_COMMAND = 0x28,
WRITE_COMMAND = 0x2a
};
cmdblock_t cb;
memset(&cb, 0, sizeof (cb));
if (dir == cbw_direction_data_in)
cb.command = READ_COMMAND;
else
cb.command = WRITE_COMMAND;
cb.block = htonl(start);
cb.numblocks = htonw(n);
return execute_command(dev, dir, (uint8_t *)&cb, sizeof(cb), buf,
n * MSC_INST(dev)->blocksize, 0)
!= 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 *dev, int start, int n,
cbw_direction dir, uint8_t *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".
static int request_sense(UsbDev *dev)
{
uint8_t buf[19];
cmdblock6_t cb;
memset(&cb, 0, sizeof (cb));
cb.command = 0x3;
cb.length = sizeof(buf);
return execute_command(dev, cbw_direction_data_in, (uint8_t *)&cb,
sizeof(cb), buf, sizeof(buf), 1);
}
static int request_sense_no_media(UsbDev *dev)
{
uint8_t buf[19];
int ret;
cmdblock6_t cb;
memset(&cb, 0, sizeof(cb));
cb.command = 0x3;
cb.length = sizeof(buf);
ret = execute_command(dev, cbw_direction_data_in, (uint8_t *)&cb,
sizeof(cb), buf, sizeof(buf), 1);
if (ret)
return ret;
// Check if sense key is set to NOT READY.
if ((buf[2] & 0xf) != 2)
return MSC_COMMAND_FAIL;
// Check if additional sense code is 0x3a.
if (buf[12] != 0x3a)
return MSC_COMMAND_FAIL;
// No media is present. Return MSC_COMMAND_OK while marking the disk
// not ready.
usb_debug("Empty media found.\n");
MSC_INST(dev)->ready = USB_MSC_NOT_READY;
return MSC_COMMAND_OK;
}
static int test_unit_ready(UsbDev *dev)
{
cmdblock6_t cb;
memset(&cb, 0, sizeof (cb)); // Full initialization for T-U-R.
return execute_command(dev, cbw_direction_data_out, (uint8_t *)&cb,
sizeof(cb), 0, 0, 0);
}
static int spin_up(UsbDev *dev)
{
cmdblock6_t cb;
memset(&cb, 0, sizeof(cb));
cb.command = 0x1b;
cb.start = 1;
return execute_command(dev, cbw_direction_data_out, (uint8_t *)&cb,
sizeof(cb), 0, 0, 0);
}
static int read_capacity(UsbDev *dev)
{
cmdblock_t cb;
memset(&cb, 0, sizeof (cb));
cb.command = 0x25; // Read capacity
uint32_t buf[2];
usb_debug("Reading capacity of mass storage device.\n");
int count = 0, ret;
while (count++ < 20) {
switch (ret = execute_command(dev, cbw_direction_data_in,
(uint8_t *)&cb, sizeof(cb),
(uint8_t *)buf, 8, 0)) {
case MSC_COMMAND_OK:
break;
case MSC_COMMAND_FAIL:
continue;
default: // If it's worse, return.
return ret;
}
break;
}
if (count >= 20) {
// Still not successful, assume 2tb in 512byte sectors, which
// is just the same garbage as any other number, but probably
// more usable.
usb_debug(" 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(buf[0]) + 1;
MSC_INST(dev)->blocksize = ntohl(buf[1]);
}
usb_debug(" %d %d-byte sectors (%d MB)\n", MSC_INST(dev)->numblocks,
MSC_INST(dev)->blocksize,
// Round down high block counts to avoid integer overflow.
MSC_INST(dev)->numblocks > 1000000 ?
((MSC_INST(dev)->numblocks / 1000) *
MSC_INST(dev)->blocksize / 1000) :
(MSC_INST(dev)->numblocks *
MSC_INST(dev)->blocksize / 1000 / 1000));
return MSC_COMMAND_OK;
}
static int usb_msc_test_unit_ready(UsbDev *dev)
{
// SCSI/ATA specs say we have to wait up to 30s, but most devices
// are ready much sooner. Use a 5 sec timeout to better accomodate
// devices which fail to respond.
const int timeout_secs = 5;
usb_debug(" Waiting for device to become ready...");
// Initially mark the device ready.
MSC_INST(dev)->ready = USB_MSC_READY;
uint64_t start_time = time_us(0);
while (1) {
if (time_us(start_time) > timeout_secs * 1000000) {
usb_debug("timeout. Device not ready.\n");
MSC_INST(dev)->ready = USB_MSC_NOT_READY;
// Don't bother spinning up the stroage device if the
// device is not ready. This can happen when empty
// card readers are present. Polling will pick it
// back up if readiness changes.
return 0;
}
switch (test_unit_ready(dev)) {
case MSC_COMMAND_OK:
break;
case MSC_COMMAND_FAIL:
mdelay(100);
usb_debug(".");
continue;
default:
// Device detached, return immediately.
return USB_MSC_DETACHED;
}
break;
}
usb_debug("ok.\n");
usb_debug(" spin up");
for (int i = 0; i < 30; i++) {
usb_debug(".");
switch (spin_up(dev)) {
case MSC_COMMAND_OK:
usb_debug(" OK.");
break;
case MSC_COMMAND_FAIL:
mdelay(100);
continue;
default:
// Device detached, return immediately.
return USB_MSC_DETACHED;
}
break;
}
usb_debug("\n");
if (read_capacity(dev) == MSC_COMMAND_DETACHED)
return USB_MSC_DETACHED;
return MSC_INST(dev)->ready;
}
void usb_msc_init(UsbDev *dev)
{
int i;
// Init .data before setting .destroy.
dev->data = NULL;
dev->destroy = usb_msc_destroy;
dev->poll = usb_msc_poll;
UsbConfigurationDescriptor *cd =
(UsbConfigurationDescriptor *)dev->configuration;
UsbInterfaceDescriptor *interface =
(UsbInterfaceDescriptor *)(((uint8_t *)cd) + cd->bLength);
usb_debug(" it uses %s command set\n",
decode_subclass_desc(interface->bInterfaceSubClass));
usb_debug(" it uses %s protocol\n",
decode_protocol_desc(interface->bInterfaceProtocol));
if (interface->bInterfaceProtocol != 0x50) {
usb_debug(" Protocol not supported.\n");
usb_detach_device(dev->controller, dev->address);
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.
usb_debug(" Interface SubClass not supported.\n");
usb_detach_device(dev->controller, dev->address);
return;
}
dev->data = malloc(sizeof (usbmsc_inst_t));
if (!dev->data)
die("Not enough memory for USB MSC device.\n");
MSC_INST(dev)->bulk_in = 0;
MSC_INST(dev)->bulk_out = 0;
MSC_INST(dev)->usbdisk_created = 0;
for (i = 1; i <= dev->num_endp; i++) {
if (dev->endpoints[i].endpoint == 0)
continue;
if (dev->endpoints[i].type != UsbEndpTypeBulk)
continue;
if ((dev->endpoints[i].direction == UsbDirIn) &&
(MSC_INST(dev)->bulk_in == 0))
MSC_INST(dev)->bulk_in = &dev->endpoints[i];
if ((dev->endpoints[i].direction == UsbDirOut) &&
(MSC_INST(dev)->bulk_out == 0))
MSC_INST(dev)->bulk_out = &dev->endpoints[i];
}
if (MSC_INST(dev)->bulk_in == 0) {
usb_debug("couldn't find bulk-in endpoint.\n");
usb_detach_device(dev->controller, dev->address);
return;
}
if (MSC_INST(dev)->bulk_out == 0) {
usb_debug("couldn't find bulk-out endpoint.\n");
usb_detach_device(dev->controller, dev->address);
return;
}
usb_debug(" using endpoint %x as in, %x as out\n",
MSC_INST(dev)->bulk_in->endpoint,
MSC_INST(dev)->bulk_out->endpoint);
// Some sticks need a little more time to get ready after SET_CONFIG.
udelay(50);
initialize_luns(dev);
usb_debug(" has %d luns\n", MSC_INST(dev)->num_luns);
// Test if unit is ready (nothing to do if it isn't).
if (usb_msc_test_unit_ready(dev) != USB_MSC_READY)
return;
// Create the disk.
usb_msc_create_disk(dev);
}
static void usb_msc_poll(UsbDev *dev)
{
usbmsc_inst_t *msc = MSC_INST(dev);
int prev_ready = msc->ready;
if (usb_msc_test_unit_ready(dev) == USB_MSC_DETACHED)
return;
if (!prev_ready && msc->ready) {
usb_debug("usb msc: not ready -> ready (lun %d)\n", msc->lun);
usb_msc_create_disk(dev);
} else if (prev_ready && !msc->ready) {
usb_debug("usb msc: ready -> not ready (lun %d)\n", msc->lun);
usb_msc_remove_disk(dev);
} else if (!prev_ready && !msc->ready) {
uint8_t new_lun = (msc->lun + 1) % msc->num_luns;
usb_debug("usb msc: not ready (lun %d) -> lun %d\n", msc->lun,
new_lun);
msc->lun = new_lun;
}
}