USB: Delete mass storage driver

This was an attempt at providing support for flashing a
SPI flash device over USB, but it suffered from being
rather complex and large.  A simpler solution of bridging
SPI over USB directly and writing a SPI over USB driver
for flashrom is being used instead.

Signed-off-by: Anton Staaf <robotboy@chromium.org>

BRANCH=None
BUG=None
TEST=make buildall -j

Change-Id: I0d1ef8f17f5d6a4de46003096a8bff4a33b41cb7
Reviewed-on: https://chromium-review.googlesource.com/238763
Tested-by: Anton Staaf <robotboy@chromium.org>
Reviewed-by: David Schneider <dnschneid@chromium.org>
Reviewed-by: Vic Yang <victoryang@chromium.org>
Reviewed-by: Vincent Palatin <vpalatin@chromium.org>
Commit-Queue: Anton Staaf <robotboy@chromium.org>
Trybot-Ready: Anton Staaf <robotboy@chromium.org>
This commit is contained in:
Anton Staaf
2015-01-05 14:42:25 -08:00
committed by ChromeOS Commit Bot
parent 0825fdf352
commit b1f0a4ca4e
8 changed files with 0 additions and 1299 deletions

View File

@@ -18,8 +18,6 @@
/* Optional features */
#define CONFIG_STM_HWTIMER32
#define CONFIG_USB
#define CONFIG_USB_MS
#define CONFIG_USB_MS_BUFFER_SIZE SPI_FLASH_MAX_WRITE_SIZE
#define CONFIG_USB_POWER_DELIVERY
#define CONFIG_USB_PD_ALT_MODE
#define CONFIG_USB_PD_ALT_MODE_DFP

View File

@@ -19,5 +19,4 @@
#define CONFIG_TASK_LIST \
TASK_ALWAYS(HOOKS, hook_task, NULL, TASK_STACK_SIZE) \
TASK_ALWAYS(CONSOLE, console_task, NULL, LARGER_TASK_STACK_SIZE) \
TASK_ALWAYS(USB_MS, ms_task, NULL, TASK_STACK_SIZE) \
TASK_ALWAYS(PD, pd_task, NULL, TASK_STACK_SIZE)

View File

@@ -52,6 +52,5 @@ chip-$(CONFIG_USB)+=usb.o usb-$(CHIP_FAMILY).o usb_endpoints.o
chip-$(CONFIG_USB_CONSOLE)+=usb_console.o
chip-$(CONFIG_USB_GPIO)+=usb_gpio.o
chip-$(CONFIG_USB_HID)+=usb_hid.o
chip-$(CONFIG_USB_MS)+=usb_ms.o usb_ms_scsi.o
chip-$(CONFIG_USB_POWER_DELIVERY)+=usb_pd_phy.o
chip-$(CONFIG_USB_SPI)+=usb_spi.o

View File

@@ -1,318 +0,0 @@
/* Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "clock.h"
#include "common.h"
#include "config.h"
#include "console.h"
#include "gpio.h"
#include "hooks.h"
#include "link_defs.h"
#include "registers.h"
#include "task.h"
#include "timer.h"
#include "util.h"
#include "usb.h"
#include "usb_ms.h"
#include "usb_ms_scsi.h"
/*
* Implements the USB Mass Storage Class specification using the
* Bulk-Only Transport (BBB) protocol with the transparent SCSI command set.
*/
/* Console output macros */
#define CPUTS(outstr) cputs(CC_USBMS, outstr)
#define CPRINTF(format, args...) cprintf(CC_USBMS, format, ## args)
/* Mass storage descriptors */
const struct usb_interface_descriptor USB_IFACE_DESC(USB_IFACE_MS) = {
.bLength = USB_DT_INTERFACE_SIZE,
.bDescriptorType = USB_DT_INTERFACE,
.bInterfaceNumber = USB_IFACE_MS,
.bAlternateSetting = 0,
.bNumEndpoints = 2,
.bInterfaceClass = USB_CLASS_MASS_STORAGE,
.bInterfaceSubClass = USB_MS_SUBCLASS_SCSI,
.bInterfaceProtocol = USB_MS_PROTOCOL_BBB,
.iInterface = 0,
};
const struct usb_endpoint_descriptor USB_EP_DESC(USB_IFACE_MS, USB_EP_MS_TX) = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = USB_DIR_IN | USB_EP_MS_TX,
.bmAttributes = 0x02 /* Bulk */,
.wMaxPacketSize = USB_MS_PACKET_SIZE,
.bInterval = 0,
};
const struct usb_endpoint_descriptor USB_EP_DESC(USB_IFACE_MS, USB_EP_MS_RX) = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = USB_EP_MS_RX,
.bmAttributes = 0x02 /* Bulk */,
.wMaxPacketSize = USB_MS_PACKET_SIZE,
.bInterval = 0,
};
/* USB mass storage state machine */
static enum usb_ms_state {
USB_MS_STATE_IDLE,
USB_MS_STATE_BUSY,
USB_MS_STATE_ERROR, /* received an invalid CBW */
USB_MS_STATE_PHASE_ERROR,
} ms_state = USB_MS_STATE_IDLE;
/* Hardware buffers for USB endpoints */
usb_uint ms_ep_tx[USB_MS_PACKET_SIZE] __usb_ram;
usb_uint ms_ep_rx[USB_MS_PACKET_SIZE] __usb_ram;
static void ms_tx_reset(void)
{
btable_ep[USB_EP_MS_TX].tx_addr = usb_sram_addr(ms_ep_tx);
btable_ep[USB_EP_MS_TX].tx_count = 0;
btable_ep[USB_EP_MS_TX].rx_count = 0;
STM32_USB_EP(USB_EP_MS_TX) =
(USB_EP_MS_TX << 0) /* Endpoint Address */ |
(2 << 4) /* TX NAK */ |
(0 << 9) /* Bulk EP */ |
(0 << 12) /* RX Disabled */;
ms_state = USB_MS_STATE_IDLE;
scsi_reset();
}
static void ms_rx_reset(void)
{
btable_ep[USB_EP_MS_RX].rx_addr = usb_sram_addr(ms_ep_rx);
btable_ep[USB_EP_MS_RX].rx_count = 0x8000 |
((USB_MS_PACKET_SIZE/32-1) << 10);
btable_ep[USB_EP_MS_RX].tx_count = 0;
STM32_USB_EP(USB_EP_MS_RX) =
(USB_EP_MS_RX << 0) /* Endpoint Address */ |
(0 << 4) /* TX Disabled */ |
(0 << 9) /* Bulk EP */ |
(3 << 12) /* RX VALID */;
ms_state = USB_MS_STATE_IDLE;
scsi_reset();
}
/*
* Construct and send a CSW.
*/
static void ms_send_csw(int ms_tag, int ms_xfer_len,
int scsi_rv, int scsi_xfer_len)
{
struct usb_ms_csw *resp = (struct usb_ms_csw *) ms_ep_tx;
/* construct CSW response */
resp->signature = UBS_MS_CSW_SIGNATURE;
resp->tag = ms_tag;
resp->data_residue = (ms_xfer_len > scsi_xfer_len) ?
(ms_xfer_len - scsi_xfer_len) :
(scsi_xfer_len - ms_xfer_len);
if (scsi_rv != SCSI_SENSE_HARDWARE_ERROR)
resp->status = (scsi_rv == SCSI_SENSE_NO_SENSE) ?
USB_MS_CSW_CMD_PASSED :
USB_MS_CSW_CMD_FAILED;
else {
ms_state = USB_MS_STATE_PHASE_ERROR;
resp->status = USB_MS_CSW_CMD_PHASE_ERR;
}
/* set CSW response length */
btable_ep[USB_EP_MS_TX].tx_count = USB_MS_CSW_LENGTH;
/* wait for data to be read */
STM32_TOGGLE_EP(USB_EP_MS_TX, EP_TX_MASK, EP_TX_VALID, 0);
}
/*
* Send data already in the output buffer.
*/
static void ms_send_data(int ms_xfer_len, int *scsi_xfer_len)
{
/* truncate if necessary */
if (btable_ep[USB_EP_MS_TX].tx_count > ms_xfer_len)
btable_ep[USB_EP_MS_TX].tx_count = ms_xfer_len;
/* increment sent data counter with actual length */
*scsi_xfer_len += btable_ep[USB_EP_MS_TX].tx_count;
/* wait for data to be read */
STM32_TOGGLE_EP(USB_EP_MS_TX, EP_TX_MASK, EP_TX_VALID, 0);
}
static void ms_tx(void)
{
task_set_event(TASK_ID_USB_MS, TASK_EVENT_CUSTOM(USB_MS_EVENT_TX), 0);
STM32_USB_EP(USB_EP_MS_TX) &= EP_MASK;
}
static void ms_rx(void)
{
task_set_event(TASK_ID_USB_MS, TASK_EVENT_CUSTOM(USB_MS_EVENT_RX), 0);
STM32_USB_EP(USB_EP_MS_RX) &= EP_MASK;
}
USB_DECLARE_EP(USB_EP_MS_TX, ms_tx, ms_tx, ms_tx_reset);
USB_DECLARE_EP(USB_EP_MS_RX, ms_rx, ms_rx, ms_rx_reset);
static int ms_iface_request(usb_uint *ep0_buf_rx, usb_uint *ep0_buf_tx)
{
uint16_t *req = (uint16_t *) ep0_buf_rx;
if ((req[0] & (USB_DIR_OUT | USB_RECIP_INTERFACE | USB_TYPE_CLASS)) !=
(USB_DIR_OUT | USB_RECIP_INTERFACE | USB_TYPE_CLASS))
return 1;
switch (req[0] >> 8) {
case USB_MS_REQ_RESET:
if (req[1] == 0 && req[2] == USB_IFACE_MS &&
req[3] == 0) {
ms_rx_reset();
}
break;
case USB_MS_REQ_GET_MAX_LUN:
if (req[1] == 0 && req[2] == USB_IFACE_MS &&
req[3] == 1) {
ep0_buf_tx[0] = SCSI_MAX_LUN;
btable_ep[0].tx_count = sizeof(uint8_t);
STM32_TOGGLE_EP(USB_EP_CONTROL, EP_TX_RX_MASK,
EP_TX_RX_VALID, 0);
}
break;
}
return 0;
}
USB_DECLARE_IFACE(USB_IFACE_MS, ms_iface_request);
void ms_task(void)
{
struct usb_ms_cbw *req = (struct usb_ms_cbw *) ms_ep_rx;
int scsi_rv, scsi_xfer_len = 0;
uint32_t ms_xfer_len = 0, ms_tag = 0;
uint8_t ms_dir = 0, evt;
while (1) {
/* wait for event or usb reset */
evt = (task_wait_event(-1) & 0xff);
switch (ms_state) {
case USB_MS_STATE_IDLE:
/* receiving data */
if (evt & USB_MS_EVENT_RX) {
/* CBW is not valid or meaningful */
if ((btable_ep[USB_EP_MS_RX].rx_count & 0x3ff)
!= USB_MS_CBW_LENGTH ||
req->signature
!= USB_MS_CBW_SIGNATURE ||
req->LUN & 0xf0 ||
req->length & 0xe0 ||
req->LUN > SCSI_MAX_LUN) {
ms_state = USB_MS_STATE_ERROR;
STM32_TOGGLE_EP(USB_EP_MS_TX,
EP_TX_MASK, EP_TX_STALL, 0);
STM32_TOGGLE_EP(USB_EP_MS_RX,
EP_RX_MASK, EP_RX_STALL, 0);
break;
}
/* have new packet */
ms_state = USB_MS_STATE_BUSY;
/* record packet details */
ms_tag = req->tag;
ms_xfer_len = req->data_transfer_length;
ms_dir = req->flags;
scsi_xfer_len = 0;
/* parse message and get next state */
scsi_rv = scsi_parse(req->command_block,
req->length);
if (scsi_rv == SCSI_STATUS_CONTINUE) {
if (ms_dir & USB_MS_CBW_DATA_IN)
/* send out data */
ms_send_data(ms_xfer_len,
&scsi_xfer_len);
else
/* receive more data */
STM32_TOGGLE_EP(USB_EP_MS_RX,
EP_RX_MASK, EP_RX_VALID, 0);
} else {
/* send message response */
ms_state = USB_MS_STATE_IDLE;
ms_send_csw(ms_tag, ms_xfer_len,
scsi_rv, scsi_xfer_len);
}
} else if (evt & USB_MS_EVENT_TX) {
/* just sent CSW, wait for next CBW */
STM32_TOGGLE_EP(USB_EP_MS_RX, EP_RX_MASK,
EP_RX_VALID, 0);
}
break;
case USB_MS_STATE_BUSY:
/* receiving data */
if (evt & USB_MS_EVENT_RX) {
/*
* received at least two CBW's in a row,
* go to error state
*/
if (ms_dir & USB_MS_CBW_DATA_IN) {
ms_state = USB_MS_STATE_ERROR;
STM32_TOGGLE_EP(USB_EP_MS_TX,
EP_TX_MASK, EP_TX_STALL, 0);
STM32_TOGGLE_EP(USB_EP_MS_RX,
EP_RX_MASK, EP_RX_STALL, 0);
break;
}
/* receive data */
scsi_xfer_len +=
(btable_ep[USB_EP_MS_RX].rx_count & 0x3ff);
scsi_rv = scsi_parse(NULL, 0);
if (scsi_rv != SCSI_STATUS_CONTINUE) {
ms_state = USB_MS_STATE_IDLE;
ms_send_csw(ms_tag, ms_xfer_len,
scsi_rv, scsi_xfer_len);
}
/* wait for more data */
STM32_TOGGLE_EP(USB_EP_MS_RX,
EP_RX_MASK, EP_RX_VALID, 0);
} else if (evt & USB_MS_EVENT_TX) {
/* reparse message and get next state */
scsi_rv = scsi_parse(req->command_block,
req->length);
if (scsi_rv == SCSI_STATUS_CONTINUE) {
ms_send_data(ms_xfer_len,
&scsi_xfer_len);
} else {
ms_state = USB_MS_STATE_IDLE;
ms_send_csw(ms_tag, ms_xfer_len,
scsi_rv, scsi_xfer_len);
}
}
break;
case USB_MS_STATE_ERROR:
/* maintain error state until reset recovery */
break;
case USB_MS_STATE_PHASE_ERROR:
CPUTS("phase error!\n");
STM32_TOGGLE_EP(USB_EP_MS_TX, EP_TX_MASK,
EP_TX_STALL, 0);
STM32_TOGGLE_EP(USB_EP_MS_RX, EP_RX_MASK,
EP_RX_STALL, 0);
break;
default:
break;
}
}
}

View File

@@ -1,795 +0,0 @@
/* Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "clock.h"
#include "common.h"
#include "config.h"
#include "console.h"
#include "gpio.h"
#include "hooks.h"
#include "link_defs.h"
#include "registers.h"
#include "task.h"
#include "timer.h"
#include "spi.h"
#include "spi_flash.h"
#include "util.h"
#include "usb.h"
#include "usb_ms.h"
#include "usb_ms_scsi.h"
/*
* Implements the SCSI-3 Block Commands (SBC-3) standard for
* Direct Access Block Devices with respect to the
* SCSI Primary Commands - 4 (SPC-4) standard.
*
* Note: Not all SPC-4 mandatory commands implemented; only LUN 0 supported.
*/
/* Command operation codes */
#define SCSI_INQUIRY 0x12
#define SCSI_MODE_SENSE6 0x1a
#define SCSI_READ10 0x28
#define SCSI_READ_CAPACITY10 0x25
#define SCSI_READ_FORMAT_CAPACITIES 0x23
#define SCSI_REPORT_LUNS 0xa0
#define SCSI_REQUEST_SENSE 0x03
#define SCSI_START_STOP_UNIT 0x1b
#define SCSI_SYNCHRONIZE_CACHE10 0x35
#define SCSI_TEST_UNIT_READY 0x00
#define SCSI_WRITE10 0x2a
#define SCSI_STANDARD_INQUIRY_SIZE 62
/* Standard inquiry response */
static const uint8_t scsi_standard_inquiry[] = {
0x00, /* Peripheral Qualifier | Peripheral Device Type (SBC-3) */
(1 << 7), /* RMB | LU_CONG | Reserved */
0x06, /* Version (SPC-4) */
0x02, /* Reserved | Reserved | NormACA | HiSup | Response Data Format */
(SCSI_STANDARD_INQUIRY_SIZE - 5), /* Additional Length */
0x00, /* SCCS | ACC | TPGS | 3PC | Reserved | Protect */
0x00, /* Obsolete | EncServ | VS | MultiP |
Obsolete | Reserved | Reserved | Addr16 */
0x00, /* Obsolete | Reserved | WBUS16 | Syncs |
Obsolete | Reserved | CmdQue | VS */
'G', 'O', 'O', 'G', 'L', 'E', '\0', '\0', /* Vendor ID */
'S', 'P', 'I', 'F', 'l', 'a', 's', 'h', /* Product ID */
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', /* Lot Number */
'1', '.', '0' , '0', /* Product Revision Level */
'\0', '\0', '\0', '\0', /* Vendor Specific */
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', /* Vendor Specific */
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', /* Vendor Specific */
0x00, /* Reserved | Clocking | QAS | IUS */
0x00, /* Reserved */
SCSI_VERSION_SBC3, /* Version 1 */
SCSI_VERSION_SPC4, /* Version 2 */
};
BUILD_ASSERT(sizeof(scsi_standard_inquiry) == SCSI_STANDARD_INQUIRY_SIZE);
#define SCSI_VPD_SUPPORTED_PAGES_SIZE 7
/* Vital product data (VPD) response for supported VPD pages */
static const uint8_t scsi_vpd_supported_pages[] = {
0x00, /* Peripheral Qualifier | Peripheral Device Type (SBC-3) */
SCSI_VPD_CODE_SUPPORTED_PAGES, /* Page Code */
0x00, /* Page Length */
(SCSI_VPD_SUPPORTED_PAGES_SIZE - 4), /* Page Length */
SCSI_VPD_CODE_SUPPORTED_PAGES, /* Supported VPD Pages */
SCSI_VPD_CODE_SERIAL_NUMBER, /* Serial Number Page */
SCSI_VPD_CODE_DEVICE_ID, /* Device ID Page */
};
BUILD_ASSERT(sizeof(scsi_vpd_supported_pages) == SCSI_VPD_SUPPORTED_PAGES_SIZE);
#define SCSI_VPD_SERIAL_NUMBER_SIZE 17
/* Vital product data (VPD) response for serial number page */
static const uint8_t scsi_vpd_serial_number[] = {
0x00, /* Peripheral Qualifier | Peripheral Device Type (SBC-3) */
SCSI_VPD_CODE_SERIAL_NUMBER, /* Page Code */
0x00, /* Page Length */
(SCSI_VPD_SERIAL_NUMBER_SIZE - 4), /* Page Length */
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', /* Serial Number */
'\0', '\0', '\0', '\0', /* Serial Number */
'\0', /* Serial Number */
};
BUILD_ASSERT(sizeof(scsi_vpd_serial_number) == SCSI_VPD_SERIAL_NUMBER_SIZE);
#define SCSI_VPD_DESIGNATOR_LENGTH 21
#define SCSI_VPD_DEVICE_ID_SIZE (SCSI_VPD_DESIGNATOR_LENGTH + 4)
/* Vital product data (VPD) response for device ID page */
static const uint8_t scsi_vpd_device_id[] = {
0x00, /* Peripheral Qualifier | Peripheral Device Type (SBC-3) */
SCSI_VPD_CODE_DEVICE_ID, /* Page Code */
0x00, /* Designation Descriptor Length */
(SCSI_VPD_DEVICE_ID_SIZE - 3), /* Designation Descriptor Length */
0x02, /* Protocol Identifier | Code Set (ASCII) */
0x01, /* PIV | Reserved | Association | Designator Type (T10) */
0x00, /* Reserved */
(SCSI_VPD_DESIGNATOR_LENGTH - 3), /* Designator Length */
'G', 'O', 'O', 'G', 'L', 'E', '\0', '\0', /* Vendor ID */
'S', 'P', 'I', 'F', 'l', 'a', 's', 'h', /* Vendor Specific ID */
'\0', /* Vendor Specific ID */
};
BUILD_ASSERT(sizeof(scsi_vpd_device_id) == SCSI_VPD_DEVICE_ID_SIZE);
/* Capacity list response for read format capacities */
static const struct scsi_capacity_list_response scsi_capacity_list = {
.header = 0x08, /* Reserved | List Length */
/* Number of Blocks */
.blocks = (CONFIG_SPI_FLASH_SIZE / SCSI_BLOCK_SIZE_BYTES),
/* Reserved | Descriptor Code | Block Length */
.block_length = (0x02 << 24) | SCSI_BLOCK_SIZE_BYTES,
};
/* Current state of SCSI state machine */
static enum usb_ms_scsi_state state = USB_MS_SCSI_STATE_IDLE;
static int buffer;
static int offset;
static int bytes;
static uint8_t op;
/* Current sense key */
static struct scsi_sense_entry scsi_sense_data;
/* Local buffer for caching */
static uint8_t temp_buf[CONFIG_USB_MS_BUFFER_SIZE];
static void scsi_sense_code(uint8_t sense, uint16_t code)
{
scsi_sense_data.key = sense;
scsi_sense_data.ASC = SCSI_SENSE_CODE_ASC(code);
scsi_sense_data.ASCQ = SCSI_SENSE_CODE_ASCQ(code);
}
static int scsi_verify_cdb6(uint8_t *block, uint8_t in_len)
{
/* message too short */
if (in_len < SCSI_CDB6_SIZE) {
scsi_sense_code(SCSI_SENSE_ILLEGAL_REQUEST,
SCSI_SENSE_CODE_NONE);
return -1;
}
/* NACA bit not supported */
if (block[5] & 0x4) {
scsi_sense_code(SCSI_SENSE_ILLEGAL_REQUEST,
SCSI_SENSE_CODE_INVALID_FIELD_IN_CDB);
return -1;
}
return 0;
}
static int scsi_verify_cdb10(uint8_t *block, uint8_t in_len)
{
/* message too short */
if (in_len < SCSI_CDB10_SIZE) {
scsi_sense_code(SCSI_SENSE_ILLEGAL_REQUEST,
SCSI_SENSE_CODE_NONE);
return -1;
}
/* NACA bit not supported */
if (block[9] & 0x4) {
scsi_sense_code(SCSI_SENSE_ILLEGAL_REQUEST,
SCSI_SENSE_CODE_INVALID_FIELD_IN_CDB);
return -1;
}
return 0;
}
/*
* Required by SPC-4.
*/
static void scsi_inquiry(uint8_t *block, uint8_t in_len)
{
if (state == USB_MS_SCSI_STATE_PARSE) {
state = USB_MS_SCSI_STATE_DATA_OUT;
/* terminate if fail to verify */
if (scsi_verify_cdb6(block, in_len))
return;
/* EVPD bit set */
if (block[1] & 0x1) {
/* lookup VPD page */
switch (block[2]) {
case SCSI_VPD_CODE_SUPPORTED_PAGES:
/* return supported pages */
memcpy_usbram(ms_ep_tx,
scsi_vpd_supported_pages,
sizeof(scsi_vpd_supported_pages));
/* truncate response */
btable_ep[USB_EP_MS_TX].tx_count =
MIN(block[3] << 8 | block[4],
sizeof(scsi_vpd_supported_pages));
break;
case SCSI_VPD_CODE_SERIAL_NUMBER:
/* return serial number response */
memcpy_usbram(ms_ep_tx,
scsi_vpd_serial_number,
sizeof(scsi_vpd_serial_number));
/* copy STM32 LOT_NUM for serial number */
memcpy(temp_buf,
((uint8_t *) STM32_UNIQUE_ID) + 4 + 1,
7 * sizeof(uint8_t));
/* copy STM32 WAF_NUM for serial number */
temp_buf[7] = ((uint8_t *) STM32_UNIQUE_ID)[4];
/* copy STM32 UID for serial number */
memcpy(temp_buf + 8,
((uint8_t *) STM32_UNIQUE_ID),
4 * sizeof(uint8_t));
/* copy actual serial number */
memcpy_usbram((usb_uint *)
(((uint8_t *) ms_ep_tx) + 4),
temp_buf,
12 * sizeof(uint8_t));
/* truncate response */
btable_ep[USB_EP_MS_TX].tx_count =
MIN(block[3] << 8 | block[4],
sizeof(scsi_vpd_serial_number));
break;
case SCSI_VPD_CODE_DEVICE_ID:
/* return device id */
memcpy_usbram(ms_ep_tx,
scsi_vpd_device_id,
sizeof(scsi_vpd_device_id));
/* truncate response */
btable_ep[USB_EP_MS_TX].tx_count =
MIN(block[3] << 8 | block[4],
sizeof(scsi_vpd_device_id));
break;
default:
/* not supported */
return scsi_sense_code(
SCSI_SENSE_ILLEGAL_REQUEST,
SCSI_SENSE_CODE_INVALID_FIELD_IN_CDB);
break;
}
/* EVPD not set but page code set */
} else if (block[2]) {
return scsi_sense_code(
SCSI_SENSE_ILLEGAL_REQUEST,
SCSI_SENSE_CODE_INVALID_FIELD_IN_CDB);
} else {
/* return standard inquiry data */
memcpy_usbram(ms_ep_tx, scsi_standard_inquiry,
sizeof(scsi_standard_inquiry));
/* copy STM32 LOT_NUM for vendor specific id */
memcpy_usbram((usb_uint *)
(((uint8_t *) ms_ep_tx) + 24),
((uint8_t *) STM32_UNIQUE_ID) + 4 + 1,
7 * sizeof(uint8_t));
/* truncate response */
btable_ep[USB_EP_MS_TX].tx_count =
MIN(block[3] << 8 | block[4],
sizeof(scsi_standard_inquiry));
}
} else if (state == USB_MS_SCSI_STATE_DATA_OUT)
state = USB_MS_SCSI_STATE_REPLY;
return scsi_sense_code(SCSI_SENSE_NO_SENSE,
SCSI_SENSE_CODE_NONE);
}
static void scsi_mode_sense6(uint8_t *block, uint8_t in_len)
{
uint8_t response[4];
if (state == USB_MS_SCSI_STATE_PARSE) {
state = USB_MS_SCSI_STATE_DATA_OUT;
/* terminate if fail to verify */
if (scsi_verify_cdb6(block, in_len))
return;
/* response exceeds allocation length */
if (block[4] < sizeof(response))
return scsi_sense_code(SCSI_SENSE_ILLEGAL_REQUEST,
SCSI_SENSE_CODE_INVALID_FIELD_IN_CDB);
memset(response, 0, sizeof(response));
/* set WP bit if necessary */
response[2] = spi_flash_check_protect(0,
CONFIG_SPI_FLASH_SIZE) ?
(1 << 7) : 0;
memcpy_usbram(ms_ep_tx, (uint8_t *) response,
sizeof(response));
btable_ep[USB_EP_MS_TX].tx_count = sizeof(response);
} else if (state == USB_MS_SCSI_STATE_DATA_OUT)
state = USB_MS_SCSI_STATE_REPLY;
return scsi_sense_code(SCSI_SENSE_NO_SENSE,
SCSI_SENSE_CODE_NONE);
}
/*
* Required by SPC-4.
*/
static void scsi_read10(uint8_t *block, uint8_t in_len)
{
int rv;
int read_len;
if (state == USB_MS_SCSI_STATE_PARSE) {
state = USB_MS_SCSI_STATE_DATA_OUT;
/* terminate if fail to verify */
if (scsi_verify_cdb10(block, in_len))
return;
/* RELADR bit not supported */
if (block[1] & 0x1)
return scsi_sense_code(SCSI_SENSE_ILLEGAL_REQUEST,
SCSI_SENSE_CODE_INVALID_FIELD_IN_CDB);
offset = SCSI_BLOCK_SIZE_BYTES *
(block[2] << 24 | block[3] << 16
| block[4] << 8 | block[5]);
bytes = SCSI_BLOCK_SIZE_BYTES *
(block[7] << 8 | block[8]);
/* Wait for any previous operation to complete */
rv = spi_flash_wait();
if (rv == EC_ERROR_TIMEOUT)
return scsi_sense_code(
SCSI_SENSE_HARDWARE_ERROR,
SCSI_SENSE_CODE_TIMEOUT);
}
if (state == USB_MS_SCSI_STATE_DATA_OUT) {
/* nothing left to read */
if (!bytes) {
state = USB_MS_SCSI_STATE_REPLY;
return scsi_sense_code(SCSI_SENSE_NO_SENSE,
SCSI_SENSE_CODE_NONE);
}
/* read in multiples of USB_MS_PACKET_SIZE, then bytes */
read_len = MIN(bytes, USB_MS_PACKET_SIZE);
rv = spi_flash_read(temp_buf, offset, read_len);
/* invalid address */
if (rv == EC_ERROR_INVAL)
return scsi_sense_code(SCSI_SENSE_ILLEGAL_REQUEST,
SCSI_SENSE_CODE_LBA_OUT_OF_RANGE);
else if (rv != EC_SUCCESS)
return scsi_sense_code(SCSI_SENSE_HARDWARE_ERROR,
SCSI_SENSE_CODE_UNRECOVERED_READ_ERROR);
/* temp buffer for chip addressing issues */
memcpy_usbram(ms_ep_tx, temp_buf, read_len);
offset += read_len;
bytes -= read_len;
btable_ep[USB_EP_MS_TX].tx_count = read_len;
}
return scsi_sense_code(SCSI_SENSE_NO_SENSE,
SCSI_SENSE_CODE_NONE);
}
/*
* Required by SPC-4.
*/
static void scsi_read_capacity10(uint8_t *block, uint8_t in_len)
{
uint32_t response[2];
if (state == USB_MS_SCSI_STATE_PARSE) {
state = USB_MS_SCSI_STATE_DATA_OUT;
/* terminate if fail to verify */
if (scsi_verify_cdb10(block, in_len))
return;
/* RELADR bit not supported */
if (block[1] & 0x1)
return scsi_sense_code(SCSI_SENSE_ILLEGAL_REQUEST,
SCSI_SENSE_CODE_INVALID_FIELD_IN_CDB);
/* PMI bit or LBA not supported */
if (block[2] | block[3] | block[4] |
block[5] | (block[8] & 0x1))
return scsi_sense_code(SCSI_SENSE_ILLEGAL_REQUEST,
SCSI_SENSE_CODE_INVALID_FIELD_IN_CDB);
/* compute LBA and block size, send in big endian */
response[0] = __builtin_bswap32((CONFIG_SPI_FLASH_SIZE /
SCSI_BLOCK_SIZE_BYTES) - 1);
response[1] = __builtin_bswap32(SCSI_BLOCK_SIZE_BYTES);
memcpy_usbram(ms_ep_tx, (uint8_t *) response,
sizeof(response));
btable_ep[USB_EP_MS_TX].tx_count = sizeof(response);
} else if (state == USB_MS_SCSI_STATE_DATA_OUT)
state = USB_MS_SCSI_STATE_REPLY;
return scsi_sense_code(SCSI_SENSE_NO_SENSE,
SCSI_SENSE_CODE_NONE);
}
/*
* Used by UFI. Required by Windows XP.
*/
static void scsi_read_format_capacities(uint8_t *block, uint8_t in_len)
{
if (state == USB_MS_SCSI_STATE_PARSE) {
state = USB_MS_SCSI_STATE_DATA_OUT;
/* terminate if fail to verify */
if (scsi_verify_cdb10(block, in_len))
return;
memcpy_usbram(ms_ep_tx, (uint8_t *) &scsi_capacity_list,
sizeof(scsi_capacity_list));
btable_ep[USB_EP_MS_TX].tx_count = sizeof(scsi_capacity_list);
} else if (state == USB_MS_SCSI_STATE_DATA_OUT)
state = USB_MS_SCSI_STATE_REPLY;
return scsi_sense_code(SCSI_SENSE_NO_SENSE,
SCSI_SENSE_CODE_NONE);
}
/*
* Required by SPC-4.
*/
static void scsi_report_luns(uint8_t *block, uint8_t in_len)
{
uint32_t response[16];
if (state == USB_MS_SCSI_STATE_PARSE) {
state = USB_MS_SCSI_STATE_DATA_OUT;
/* terminate if fail to verify */
if (scsi_verify_cdb6(block, in_len))
return;
/* response exceeds allocation length */
if ((block[3] << 8 | block[4]) < sizeof(response))
return scsi_sense_code(SCSI_SENSE_ILLEGAL_REQUEST,
SCSI_SENSE_CODE_INVALID_FIELD_IN_CDB);
memset(response, 0, sizeof(response));
/* one LUN in the list */
response[3] = 1;
/* return response */
memcpy_usbram(ms_ep_tx, (uint8_t *) response,
sizeof(response));
btable_ep[USB_EP_MS_TX].tx_count = sizeof(response);
} else if (state == USB_MS_SCSI_STATE_DATA_OUT)
state = USB_MS_SCSI_STATE_REPLY;
return scsi_sense_code(SCSI_SENSE_NO_SENSE, SCSI_SENSE_CODE_NONE);
}
/*
* Required by SPC-4.
*/
static void scsi_request_sense(uint8_t *block, uint8_t in_len)
{
uint8_t response[18];
if (state == USB_MS_SCSI_STATE_PARSE) {
state = USB_MS_SCSI_STATE_DATA_OUT;
/* terminate if fail to verify */
if (scsi_verify_cdb6(block, in_len))
return;
/* response exceeds allocation length */
if (block[4] < sizeof(response))
return scsi_sense_code(SCSI_SENSE_ILLEGAL_REQUEST,
SCSI_SENSE_CODE_INVALID_FIELD_IN_CDB);
memset(response, 0, sizeof(response));
/* Valid | Response Code */
response[0] = SCSI_SENSE_RESPONSE_CURRENT;
/* Filemark | EOM | ILI | SDAT_OVFL | Sense Key */
response[2] = scsi_sense_data.key;
/* Additional Sense Length */
response[7] = ARRAY_SIZE(response) - 7;
/* Additional Sense Code */
response[12] = scsi_sense_data.ASC;
/* Additional Sense Code Qualifier */
response[13] = scsi_sense_data.ASCQ;
/* return fixed format sense data */
memcpy_usbram(ms_ep_tx, response, sizeof(response));
btable_ep[USB_EP_MS_TX].tx_count = sizeof(response);
} else if (state == USB_MS_SCSI_STATE_DATA_OUT)
state = USB_MS_SCSI_STATE_REPLY;
return scsi_sense_code(SCSI_SENSE_NO_SENSE, SCSI_SENSE_CODE_NONE);
}
static void scsi_start_stop_unit(uint8_t *block, uint8_t in_len)
{
state = USB_MS_SCSI_STATE_REPLY;
/* terminate if fail to verify */
if (scsi_verify_cdb6(block, in_len))
return;
/* do nothing */
return scsi_sense_code(SCSI_SENSE_NO_SENSE, SCSI_SENSE_CODE_NONE);
}
static void scsi_synchronize_cache10(uint8_t *block, uint8_t in_len)
{
state = USB_MS_SCSI_STATE_REPLY;
/* terminate if fail to verify */
if (scsi_verify_cdb10(block, in_len))
return;
/* nothing to synchronize, return success */
return scsi_sense_code(SCSI_SENSE_NO_SENSE, SCSI_SENSE_CODE_NONE);
}
/*
* Required by SPC-4.
*/
static void scsi_test_unit_ready(uint8_t *block, uint8_t in_len)
{
state = USB_MS_SCSI_STATE_REPLY;
/* terminate if fail to verify */
if (scsi_verify_cdb6(block, in_len))
return;
if (spi_enable(1))
return scsi_sense_code(SCSI_SENSE_NOT_READY,
SCSI_SENSE_CODE_NOT_READY);
return scsi_sense_code(SCSI_SENSE_NO_SENSE, SCSI_SENSE_CODE_NONE);
}
/*
* Required by SPC-4.
*/
static void scsi_write10(uint8_t *block, uint8_t in_len)
{
int rv;
int write_len;
if (state == USB_MS_SCSI_STATE_PARSE) {
state = USB_MS_SCSI_STATE_DATA_IN;
/* terminate if fail to verify */
if (scsi_verify_cdb10(block, in_len))
return;
/* RELADR bit not supported */
if (block[1] & 0x1)
return scsi_sense_code(SCSI_SENSE_ILLEGAL_REQUEST,
SCSI_SENSE_CODE_INVALID_FIELD_IN_CDB);
buffer = 0;
offset = SCSI_BLOCK_SIZE_BYTES *
(block[2] << 24 | block[3] << 16 |
block[4] << 8 | block[5]);
bytes = SCSI_BLOCK_SIZE_BYTES * (block[7] << 8 | block[8]);
/* Chip has protection */
if (spi_flash_check_protect(offset, bytes))
return scsi_sense_code(SCSI_SENSE_DATA_PROTECT,
SCSI_SENSE_CODE_WRITE_PROTECTED);
/* Wait for any previous operation to complete */
rv = spi_flash_wait();
if (rv == EC_ERROR_TIMEOUT)
return scsi_sense_code(
SCSI_SENSE_HARDWARE_ERROR,
SCSI_SENSE_CODE_TIMEOUT);
rv = spi_flash_erase(offset, bytes);
/* invalid address */
if (rv == EC_ERROR_INVAL)
return scsi_sense_code(SCSI_SENSE_ILLEGAL_REQUEST,
SCSI_SENSE_CODE_LBA_OUT_OF_RANGE);
else if (rv != EC_SUCCESS)
return scsi_sense_code(SCSI_SENSE_HARDWARE_ERROR,
SCSI_SENSE_CODE_UNRECOVERED_READ_ERROR);
} else if (state == USB_MS_SCSI_STATE_DATA_IN) {
/* write whatever was received */
write_len = MIN(bytes,
btable_ep[USB_EP_MS_RX].rx_count & 0x3ff);
ASSERT(write_len <= SPI_FLASH_MAX_WRITE_SIZE);
#if CONFIG_USB_MS_BUFFER_SIZE != USB_MS_PACKET_SIZE
/* perform write only when local buffer is over full */
if (buffer + write_len > CONFIG_USB_MS_BUFFER_SIZE) {
/* Wait for previous operation to complete */
rv = spi_flash_wait();
if (rv == EC_ERROR_TIMEOUT)
return scsi_sense_code(
SCSI_SENSE_HARDWARE_ERROR,
SCSI_SENSE_CODE_TIMEOUT);
rv = spi_flash_write(offset,
CONFIG_USB_MS_BUFFER_SIZE, temp_buf);
if (rv == EC_ERROR_INVAL)
return scsi_sense_code(
SCSI_SENSE_ILLEGAL_REQUEST,
SCSI_SENSE_CODE_LBA_OUT_OF_RANGE);
else if (rv != EC_SUCCESS)
return scsi_sense_code(
SCSI_SENSE_HARDWARE_ERROR,
SCSI_SENSE_CODE_UNRECOVERED_READ_ERROR);
offset += buffer;
bytes -= buffer;
buffer = 0;
}
/* copy data to local buffer */
memcpy(temp_buf + buffer, (uint8_t *) ms_ep_rx, write_len);
buffer += write_len;
/* on last write */
if (bytes == buffer) {
/* Wait for previous operation to complete */
rv = spi_flash_wait();
if (rv == EC_ERROR_TIMEOUT)
return scsi_sense_code(
SCSI_SENSE_HARDWARE_ERROR,
SCSI_SENSE_CODE_TIMEOUT);
rv = spi_flash_write(offset, buffer, temp_buf);
if (rv == EC_ERROR_INVAL)
return scsi_sense_code(
SCSI_SENSE_ILLEGAL_REQUEST,
SCSI_SENSE_CODE_LBA_OUT_OF_RANGE);
else if (rv == EC_ERROR_ACCESS_DENIED)
return scsi_sense_code(SCSI_SENSE_DATA_PROTECT,
SCSI_SENSE_CODE_WRITE_PROTECTED);
else if (rv != EC_SUCCESS)
return scsi_sense_code(
SCSI_SENSE_HARDWARE_ERROR,
SCSI_SENSE_CODE_UNRECOVERED_READ_ERROR);
/* Wait for last write to complete */
rv = spi_flash_wait();
if (rv == EC_ERROR_TIMEOUT)
return scsi_sense_code(
SCSI_SENSE_HARDWARE_ERROR,
SCSI_SENSE_CODE_TIMEOUT);
offset += buffer;
bytes -= buffer;
buffer = 0;
/* received too much data */
} else if (bytes < buffer)
return scsi_sense_code(SCSI_SENSE_ILLEGAL_REQUEST,
SCSI_SENSE_CODE_LBA_OUT_OF_RANGE);
#else
memcpy(temp_buf, (uint8_t *) ms_ep_rx, write_len);
/* Wait for previous operation to complete */
rv = spi_flash_wait();
if (rv == EC_ERROR_TIMEOUT)
return scsi_sense_code(
SCSI_SENSE_HARDWARE_ERROR,
SCSI_SENSE_CODE_TIMEOUT);
rv = spi_flash_write(offset, write_len, temp_buf);
if (rv == EC_ERROR_INVAL)
return scsi_sense_code(
SCSI_SENSE_ILLEGAL_REQUEST,
SCSI_SENSE_CODE_LBA_OUT_OF_RANGE);
else if (rv == EC_ERROR_ACCESS_DENIED)
return scsi_sense_code(SCSI_SENSE_DATA_PROTECT,
SCSI_SENSE_CODE_WRITE_PROTECTED);
else if (rv != EC_SUCCESS)
return scsi_sense_code(
SCSI_SENSE_HARDWARE_ERROR,
SCSI_SENSE_CODE_UNRECOVERED_READ_ERROR);
offset += write_len;
bytes -= write_len;
#endif
/* nothing left to write */
if (!bytes)
state = USB_MS_SCSI_STATE_REPLY;
}
return scsi_sense_code(SCSI_SENSE_NO_SENSE, SCSI_SENSE_CODE_NONE);
}
void scsi_reset(void)
{
op = 0;
offset = 0;
bytes = 0;
buffer = 0;
state = USB_MS_SCSI_STATE_IDLE;
/* set status to success by default */
scsi_sense_code(SCSI_SENSE_NO_SENSE, SCSI_SENSE_CODE_NONE);
}
int scsi_parse(uint8_t *block, uint8_t in_len)
{
/* set new operation */
if (state == USB_MS_SCSI_STATE_IDLE) {
state = USB_MS_SCSI_STATE_PARSE;
op = block[0];
}
/* skip operation if sending reply */
if (state != USB_MS_SCSI_STATE_REPLY) {
switch (op) {
case SCSI_INQUIRY:
scsi_inquiry(block, in_len);
break;
case SCSI_MODE_SENSE6:
scsi_mode_sense6(block, in_len);
break;
case SCSI_READ10:
scsi_read10(block, in_len);
break;
case SCSI_READ_CAPACITY10:
scsi_read_capacity10(block, in_len);
break;
case SCSI_READ_FORMAT_CAPACITIES:
scsi_read_format_capacities(block, in_len);
break;
case SCSI_REPORT_LUNS:
scsi_report_luns(block, in_len);
break;
case SCSI_REQUEST_SENSE:
scsi_request_sense(block, in_len);
break;
case SCSI_START_STOP_UNIT:
scsi_start_stop_unit(block, in_len);
break;
case SCSI_SYNCHRONIZE_CACHE10:
scsi_synchronize_cache10(block, in_len);
break;
case SCSI_TEST_UNIT_READY:
scsi_test_unit_ready(block, in_len);
break;
case SCSI_WRITE10:
scsi_write10(block, in_len);
break;
default:
state = USB_MS_SCSI_STATE_REPLY;
scsi_sense_code(SCSI_SENSE_ILLEGAL_REQUEST,
SCSI_SENSE_CODE_INVALID_COMMAND_OPERATION_CODE);
break;
}
}
/* error during data rx/tx */
if (((state == USB_MS_SCSI_STATE_DATA_OUT) ||
(state == USB_MS_SCSI_STATE_DATA_IN)) &&
scsi_sense_data.key) {
btable_ep[USB_EP_MS_TX].tx_count = 0;
state = USB_MS_SCSI_STATE_REPLY;
return SCSI_STATUS_CONTINUE;
}
/* done sending data */
if (state == USB_MS_SCSI_STATE_REPLY) {
state = USB_MS_SCSI_STATE_IDLE;
return scsi_sense_data.key;
}
/* still sending/receiving data and no error has occurred */
return SCSI_STATUS_CONTINUE;
}

View File

@@ -1189,15 +1189,6 @@
/* USB Device version of product */
#undef CONFIG_USB_BCD_DEV
/*****************************************************************************/
/* USB interfaces config */
/* USB mass storage interface */
#undef CONFIG_USB_MS
/* USB mass storage local buffer size */
#undef CONFIG_USB_MS_BUFFER_SIZE
/*****************************************************************************/
/* Compile chip support for the USB device controller */

View File

@@ -1,63 +0,0 @@
/* Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*
* USB mass storage definitions.
*/
#ifndef USB_MS_H
#define USB_MS_H
#define USB_MS_SUBCLASS_RBC 0x01
#define USB_MS_SUBCLASS_MMC5 0x02
#define USB_MS_SUBCLASS_UFI 0x04
#define USB_MS_SUBCLASS_SCSI 0x06
#define USB_MS_SUBCLASS_LSDFS 0x07
#define USB_MS_SUBCLASS_IEEE1667 0x08
#define USB_MS_PROTOCOL_CBI_INTERRUPT 0x00
#define USB_MS_PROTOCOL_CBI 0x01
#define USB_MS_PROTOCOL_BBB 0x50
#define USB_MS_PROTOCOL_UAS 0x62
#define USB_MS_PACKET_SIZE (USB_MAX_PACKET_SIZE)
/* USB Mass Storage Command Block Wrapper */
struct usb_ms_cbw {
uint32_t signature;
uint32_t tag;
uint32_t data_transfer_length;
uint8_t flags;
uint8_t LUN;
uint8_t length;
uint8_t command_block[16];
} __packed;
#define USB_MS_CBW_LENGTH 31
#define USB_MS_CBW_SIGNATURE 0x43425355
#define USB_MS_CBW_DATA_IN (1 << 7)
/* USB Mass Storage Command Status Wrapper */
struct usb_ms_csw {
uint32_t signature;
uint32_t tag;
uint32_t data_residue;
uint8_t status;
} __packed;
#define USB_MS_CSW_LENGTH 13
#define UBS_MS_CSW_SIGNATURE 0x53425355
#define USB_MS_CSW_CMD_PASSED 0x0
#define USB_MS_CSW_CMD_FAILED 0x1
#define USB_MS_CSW_CMD_PHASE_ERR 0x2
#define USB_MS_REQ_RESET 0xff
#define USB_MS_REQ_GET_MAX_LUN 0xfe
#define USB_MS_EVENT_TX (1 << 0)
#define USB_MS_EVENT_RX (1 << 1)
/* Maximum number of supported LUN's, defined in SCSI file */
extern const uint8_t max_lun;
#endif /* USB_MS_H */

View File

@@ -1,110 +0,0 @@
/* Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*
* SCSI definitions.
*/
#ifndef USB_MS_SCSI_H
#define USB_MS_SCSI_H
#define SCSI_MAX_LUN 0
/* Status values */
#define SCSI_STATUS_GOOD 0x00
#define SCSI_STATUS_CHECK_CONDITION 0x02
#define SCSI_STATUS_CONDITION_MET 0x04
#define SCSI_STATUS_BUSY 0x08
#define SCSI_STATUS_RESERVATION_CONFLICT 0x18
#define SCSI_STATUS_TASK_SET_FULL 0x28
#define SCSI_STATUS_ACA_ACTIVE 0x30
#define SCSI_STATUS_TASK_ABORTED 0x40
/* Not part of standard, indicates operation not complete*/
#define SCSI_STATUS_CONTINUE 0xFF
/* Sense key values */
#define SCSI_SENSE_NO_SENSE 0x0
#define SCSI_SENSE_RECOVERED_ERROR 0x1
#define SCSI_SENSE_NOT_READY 0x2
#define SCSI_SENSE_MEDIUM_ERROR 0x3
#define SCSI_SENSE_HARDWARE_ERROR 0x4
#define SCSI_SENSE_ILLEGAL_REQUEST 0x5
#define SCSI_SENSE_UNIT_ATTENTION 0x6
#define SCSI_SENSE_DATA_PROTECT 0x7
#define SCSI_SENSE_BLANK_CHECK 0x8
#define SCSI_SENSE_VENDOR_SPECIFIC 0x9
#define SCSI_SENSE_COPY_ABORTED 0xa
#define SCSI_SENSE_ABORTED_COMMAND 0xb
#define SCSI_SENSE_VOLUME_OVERFLOW 0xd
#define SCSI_SENSE_MISCOMPARE 0xe
#define SCSI_SENSE_COMPLETED 0xf
/* Additional sense code (ASC) and additional sense code qualifier (ASCQ)
* fields. Stored as ASC | ACSQ */
#define SCSI_SENSE_CODE_NONE ((0x00 << 4) | 0x00)
#define SCSI_SENSE_CODE_INVALID_COMMAND_OPERATION_CODE ((0x20 << 4) | 0x00)
#define SCSI_SENSE_CODE_INVALID_FIELD_IN_CDB ((0x24 << 4) | 0x00)
#define SCSI_SENSE_CODE_UNRECOVERED_READ_ERROR ((0x11 << 4) | 0x00)
#define SCSI_SENSE_CODE_NOT_READY ((0x04 << 4) | 0x00)
#define SCSI_SENSE_CODE_COMMAND_TO_LUN_FAILED ((0x6e << 4) | 0x00)
#define SCSI_SENSE_CODE_LBA_OUT_OF_RANGE ((0x21 << 4) | 0x00)
#define SCSI_SENSE_CODE_WRITE_PROTECTED ((0x27 << 4) | 0x00)
#define SCSI_SENSE_CODE_TIMEOUT ((0x3e) | 0x02)
#define SCSI_SENSE_CODE_ASC(x) ((x & 0xf0) >> 8)
#define SCSI_SENSE_CODE_ASCQ(x) (x & 0x0f)
/* Version descriptor values */
#define SCSI_VERSION_SBC3 0x04, 0xc0
#define SCSI_VERSION_SPC4 0x04, 0x60
/* Vital product data page codes */
#define SCSI_VPD_CODE_SUPPORTED_PAGES 0x00
#define SCSI_VPD_CODE_SERIAL_NUMBER 0x80
#define SCSI_VPD_CODE_DEVICE_ID 0x83
/* Mode pages */
#define SCSI_MODE_PAGE_ALL 0x3f
/* Response values for fixed-format sense data */
#define SCSI_SENSE_RESPONSE_CURRENT 0x70
#define SCSI_SENSE_RESPONSE_DEFERRED 0x71
/* Size of various SCSI data structures */
#define SCSI_CDB6_SIZE 6
#define SCSI_CDB10_SIZE 10
#define SCSI_CDB12_SIZE 12
/* Block size for LBA addressing */
#define SCSI_BLOCK_SIZE_BYTES (4 * 1024)
/* USB mass storage SCSI state machine */
enum usb_ms_scsi_state {
USB_MS_SCSI_STATE_IDLE,
USB_MS_SCSI_STATE_PARSE,
USB_MS_SCSI_STATE_DATA_IN,
USB_MS_SCSI_STATE_DATA_OUT,
USB_MS_SCSI_STATE_REPLY,
};
/* Structure defining sense key entry */
struct scsi_sense_entry {
uint8_t key; /* Sense Key */
uint8_t ASC; /* Additional Sense Code */
uint8_t ASCQ; /* Additional Sense Qualifier */
};
/* Structure defining read format capacities response */
struct scsi_capacity_list_response {
uint32_t header; /* Reserved | List Length */
uint32_t blocks; /* Number of Blocks */
uint32_t block_length; /* Reserved | Descriptor Code | Block Length */
};
/* USB endpoint buffers */
extern usb_uint ms_ep_tx[USB_MS_PACKET_SIZE] __usb_ram;
extern usb_uint ms_ep_rx[USB_MS_PACKET_SIZE] __usb_ram;
int scsi_parse(uint8_t *block, uint8_t length);
void scsi_reset(void);
#endif /* USB_MS_SCSI_H */