|
|
|
|
@@ -85,14 +85,7 @@ static uint32_t current_byte_read;
|
|
|
|
|
|
|
|
|
|
static void usbd_msc_reset(void)
|
|
|
|
|
{
|
|
|
|
|
uint8_t *buf = NULL;
|
|
|
|
|
|
|
|
|
|
buf = usbd_msc_cfg.block_buffer;
|
|
|
|
|
|
|
|
|
|
memset((uint8_t *)&usbd_msc_cfg, 0, sizeof(struct usbd_msc_cfg_priv));
|
|
|
|
|
|
|
|
|
|
usbd_msc_get_cap(0, &usbd_msc_cfg.scsi_blk_nbr, &usbd_msc_cfg.scsi_blk_size);
|
|
|
|
|
usbd_msc_cfg.block_buffer = buf;
|
|
|
|
|
usbd_msc_cfg.stage = MSC_READ_CBW;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
@@ -112,24 +105,10 @@ static int msc_storage_class_request_handler(struct usb_setup_packet *setup, uin
|
|
|
|
|
|
|
|
|
|
switch (setup->bRequest) {
|
|
|
|
|
case MSC_REQUEST_RESET:
|
|
|
|
|
USB_LOG_DBG("MSC_REQUEST_RESET\r\n");
|
|
|
|
|
|
|
|
|
|
if (setup->wLength) {
|
|
|
|
|
USB_LOG_WRN("Invalid length\r\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
usbd_msc_reset();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case MSC_REQUEST_GET_MAX_LUN:
|
|
|
|
|
USB_LOG_DBG("MSC_REQUEST_GET_MAX_LUN\r\n");
|
|
|
|
|
|
|
|
|
|
if (setup->wLength != 1) {
|
|
|
|
|
USB_LOG_WRN("Invalid length\r\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*data = (uint8_t *)(&usbd_msc_cfg.max_lun);
|
|
|
|
|
*len = 1;
|
|
|
|
|
break;
|
|
|
|
|
@@ -142,15 +121,32 @@ static int msc_storage_class_request_handler(struct usb_setup_packet *setup, uin
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void msc_storage_notify_handler(uint8_t event, void *arg)
|
|
|
|
|
{
|
|
|
|
|
switch (event) {
|
|
|
|
|
case USBD_EVENT_RESET:
|
|
|
|
|
usbd_msc_reset();
|
|
|
|
|
break;
|
|
|
|
|
case USBD_EVENT_CONFIGURED:
|
|
|
|
|
USB_LOG_DBG("Start reading cbw\r\n");
|
|
|
|
|
usbd_ep_start_read(mass_ep_data[MSD_OUT_EP_IDX].ep_addr, (uint8_t *)&usbd_msc_cfg.cbw, USB_SIZEOF_MSC_CBW);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void usbd_msc_bot_abort(void)
|
|
|
|
|
{
|
|
|
|
|
if ((usbd_msc_cfg.cbw.bmFlags == 0) && (usbd_msc_cfg.cbw.dDataLength != 0)) {
|
|
|
|
|
usbd_ep_set_stall(mass_ep_data[MSD_OUT_EP_IDX].ep_addr);
|
|
|
|
|
}
|
|
|
|
|
usbd_ep_set_stall(mass_ep_data[MSD_IN_EP_IDX].ep_addr);
|
|
|
|
|
usbd_ep_start_read(mass_ep_data[0].ep_addr, (uint8_t *)&usbd_msc_cfg.cbw, USB_SIZEOF_MSC_CBW);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void sendCSW(uint8_t CSW_Status)
|
|
|
|
|
static void usbd_msc_send_csw(uint8_t CSW_Status)
|
|
|
|
|
{
|
|
|
|
|
usbd_msc_cfg.csw.dSignature = MSC_CSW_Signature;
|
|
|
|
|
usbd_msc_cfg.csw.bStatus = CSW_Status;
|
|
|
|
|
@@ -160,13 +156,11 @@ static void sendCSW(uint8_t CSW_Status)
|
|
|
|
|
*/
|
|
|
|
|
usbd_msc_cfg.stage = MSC_WAIT_CSW;
|
|
|
|
|
|
|
|
|
|
if (usbd_ep_write(mass_ep_data[MSD_IN_EP_IDX].ep_addr, (uint8_t *)&usbd_msc_cfg.csw,
|
|
|
|
|
sizeof(struct CSW), NULL) != 0) {
|
|
|
|
|
USB_LOG_ERR("usb write failure\r\n");
|
|
|
|
|
}
|
|
|
|
|
USB_LOG_DBG("Send csw\r\n");
|
|
|
|
|
usbd_ep_start_write(mass_ep_data[MSD_IN_EP_IDX].ep_addr, (uint8_t *)&usbd_msc_cfg.csw, sizeof(struct CSW));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void sendLastData(uint8_t *buffer, uint8_t size)
|
|
|
|
|
static void usbd_msc_send_info(uint8_t *buffer, uint8_t size)
|
|
|
|
|
{
|
|
|
|
|
size = MIN(size, usbd_msc_cfg.cbw.dDataLength);
|
|
|
|
|
|
|
|
|
|
@@ -175,31 +169,14 @@ static void sendLastData(uint8_t *buffer, uint8_t size)
|
|
|
|
|
*/
|
|
|
|
|
usbd_msc_cfg.stage = MSC_SEND_CSW;
|
|
|
|
|
|
|
|
|
|
if (usbd_ep_write(mass_ep_data[MSD_IN_EP_IDX].ep_addr, buffer, size, NULL) != 0) {
|
|
|
|
|
USB_LOG_ERR("USB write failed\r\n");
|
|
|
|
|
}
|
|
|
|
|
usbd_ep_start_write(mass_ep_data[MSD_IN_EP_IDX].ep_addr, buffer, size);
|
|
|
|
|
|
|
|
|
|
usbd_msc_cfg.csw.dDataResidue -= size;
|
|
|
|
|
usbd_msc_cfg.csw.bStatus = CSW_STATUS_CMD_PASSED;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief SCSI COMMAND
|
|
|
|
|
*/
|
|
|
|
|
static bool SCSI_testUnitReady(uint8_t **data, uint32_t *len);
|
|
|
|
|
static bool SCSI_requestSense(uint8_t **data, uint32_t *len);
|
|
|
|
|
static bool SCSI_inquiry(uint8_t **data, uint32_t *len);
|
|
|
|
|
static bool SCSI_startStopUnit(uint8_t **data, uint32_t *len);
|
|
|
|
|
static bool SCSI_preventAllowMediaRemoval(uint8_t **data, uint32_t *len);
|
|
|
|
|
static bool SCSI_modeSense6(uint8_t **data, uint32_t *len);
|
|
|
|
|
static bool SCSI_modeSense10(uint8_t **data, uint32_t *len);
|
|
|
|
|
static bool SCSI_readFormatCapacity(uint8_t **data, uint32_t *len);
|
|
|
|
|
static bool SCSI_readCapacity10(uint8_t **data, uint32_t *len);
|
|
|
|
|
static bool SCSI_read10(uint8_t **data, uint32_t *len);
|
|
|
|
|
static bool SCSI_read12(uint8_t **data, uint32_t *len);
|
|
|
|
|
static bool SCSI_write10(uint8_t **data, uint32_t *len);
|
|
|
|
|
static bool SCSI_write12(uint8_t **data, uint32_t *len);
|
|
|
|
|
static bool SCSI_verify10(uint8_t **data, uint32_t *len);
|
|
|
|
|
static bool SCSI_processWrite(uint32_t nbytes);
|
|
|
|
|
static bool SCSI_processRead(void);
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief SCSI_SetSenseData
|
|
|
|
|
@@ -216,258 +193,10 @@ static void SCSI_SetSenseData(uint32_t KCQ)
|
|
|
|
|
usbd_msc_cfg.ASQ = (uint8_t)(KCQ);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifdef CONFIG_USBDEV_MSC_THREAD
|
|
|
|
|
static void usbd_msc_thread_memory_read_done(void)
|
|
|
|
|
{
|
|
|
|
|
size_t flags;
|
|
|
|
|
uint32_t transfer_len;
|
|
|
|
|
uint32_t offset;
|
|
|
|
|
|
|
|
|
|
USB_LOG_DBG("read addr:%d\r\n", usbd_msc_cfg.scsi_blk_addr);
|
|
|
|
|
|
|
|
|
|
flags = usb_osal_enter_critical_section();
|
|
|
|
|
|
|
|
|
|
transfer_len = MIN(usbd_msc_cfg.scsi_blk_len, MASS_STORAGE_BULK_EP_MPS);
|
|
|
|
|
offset = usbd_msc_cfg.scsi_blk_addr % usbd_msc_cfg.scsi_blk_size;
|
|
|
|
|
|
|
|
|
|
usbd_msc_cfg.scsi_blk_addr += transfer_len;
|
|
|
|
|
usbd_msc_cfg.scsi_blk_len -= transfer_len;
|
|
|
|
|
usbd_msc_cfg.csw.dDataResidue -= transfer_len;
|
|
|
|
|
|
|
|
|
|
if (usbd_msc_cfg.scsi_blk_len == 0) {
|
|
|
|
|
usbd_msc_cfg.stage = MSC_SEND_CSW;
|
|
|
|
|
}
|
|
|
|
|
usb_osal_leave_critical_section(flags);
|
|
|
|
|
|
|
|
|
|
usbd_ep_write(mass_ep_data[MSD_IN_EP_IDX].ep_addr,
|
|
|
|
|
&usbd_msc_cfg.block_buffer[offset], transfer_len, NULL);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
static bool SCSI_processRead(void)
|
|
|
|
|
{
|
|
|
|
|
uint32_t transfer_len;
|
|
|
|
|
|
|
|
|
|
USB_LOG_DBG("read addr:%d\r\n", usbd_msc_cfg.scsi_blk_addr);
|
|
|
|
|
|
|
|
|
|
transfer_len = MIN(usbd_msc_cfg.scsi_blk_len, MASS_STORAGE_BULK_EP_MPS);
|
|
|
|
|
|
|
|
|
|
/* we read an entire block */
|
|
|
|
|
if (!(usbd_msc_cfg.scsi_blk_addr % usbd_msc_cfg.scsi_blk_size)) {
|
|
|
|
|
#ifdef CONFIG_USBDEV_MSC_THREAD
|
|
|
|
|
thread_op = MSC_THREAD_OP_READ_MEM;
|
|
|
|
|
usb_osal_sem_give(msc_sem);
|
|
|
|
|
return true;
|
|
|
|
|
#else
|
|
|
|
|
if (usbd_msc_sector_read((usbd_msc_cfg.scsi_blk_addr / usbd_msc_cfg.scsi_blk_size), usbd_msc_cfg.block_buffer, usbd_msc_cfg.scsi_blk_size) != 0) {
|
|
|
|
|
SCSI_SetSenseData(SCSI_KCQHE_UREINRESERVEDAREA);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
usbd_ep_write(mass_ep_data[MSD_IN_EP_IDX].ep_addr,
|
|
|
|
|
&usbd_msc_cfg.block_buffer[usbd_msc_cfg.scsi_blk_addr % usbd_msc_cfg.scsi_blk_size], transfer_len, NULL);
|
|
|
|
|
|
|
|
|
|
usbd_msc_cfg.scsi_blk_addr += transfer_len;
|
|
|
|
|
usbd_msc_cfg.scsi_blk_len -= transfer_len;
|
|
|
|
|
usbd_msc_cfg.csw.dDataResidue -= transfer_len;
|
|
|
|
|
|
|
|
|
|
if (usbd_msc_cfg.scsi_blk_len == 0) {
|
|
|
|
|
usbd_msc_cfg.stage = MSC_SEND_CSW;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifdef CONFIG_USBDEV_MSC_THREAD
|
|
|
|
|
static void usbd_msc_thread_memory_write_done()
|
|
|
|
|
{
|
|
|
|
|
size_t flags;
|
|
|
|
|
uint32_t bytes_read;
|
|
|
|
|
USB_LOG_DBG("write addr:%d\r\n", usbd_msc_cfg.scsi_blk_addr);
|
|
|
|
|
|
|
|
|
|
flags = usb_osal_enter_critical_section();
|
|
|
|
|
|
|
|
|
|
bytes_read = current_byte_read;
|
|
|
|
|
|
|
|
|
|
usbd_msc_cfg.scsi_blk_addr += bytes_read;
|
|
|
|
|
usbd_msc_cfg.scsi_blk_len -= bytes_read;
|
|
|
|
|
usbd_msc_cfg.csw.dDataResidue -= bytes_read;
|
|
|
|
|
|
|
|
|
|
usb_osal_leave_critical_section(flags);
|
|
|
|
|
|
|
|
|
|
thread_op = MSC_THREAD_OP_WRITE_DONE;
|
|
|
|
|
/*set ep ack to recv next data*/
|
|
|
|
|
usbd_ep_read(mass_ep_data[MSD_OUT_EP_IDX].ep_addr, NULL, 0, NULL);
|
|
|
|
|
|
|
|
|
|
if (usbd_msc_cfg.scsi_blk_len == 0) {
|
|
|
|
|
sendCSW(CSW_STATUS_CMD_PASSED);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
static bool SCSI_processWrite()
|
|
|
|
|
{
|
|
|
|
|
uint32_t bytes_read;
|
|
|
|
|
USB_LOG_DBG("write addr:%d\r\n", usbd_msc_cfg.scsi_blk_addr);
|
|
|
|
|
|
|
|
|
|
/* we fill an array in RAM of 1 block before writing it in memory */
|
|
|
|
|
usbd_ep_read(mass_ep_data[MSD_OUT_EP_IDX].ep_addr, &usbd_msc_cfg.block_buffer[usbd_msc_cfg.scsi_blk_addr % usbd_msc_cfg.scsi_blk_size], MASS_STORAGE_BULK_EP_MPS,
|
|
|
|
|
&bytes_read);
|
|
|
|
|
|
|
|
|
|
/* if the array is filled, write it in memory */
|
|
|
|
|
if ((usbd_msc_cfg.scsi_blk_addr % usbd_msc_cfg.scsi_blk_size) + bytes_read >= usbd_msc_cfg.scsi_blk_size) {
|
|
|
|
|
#ifdef CONFIG_USBDEV_MSC_THREAD
|
|
|
|
|
thread_op = MSC_THREAD_OP_WRITE_MEM;
|
|
|
|
|
current_byte_read = bytes_read;
|
|
|
|
|
usb_osal_sem_give(msc_sem);
|
|
|
|
|
return true;
|
|
|
|
|
#else
|
|
|
|
|
if (usbd_msc_sector_write((usbd_msc_cfg.scsi_blk_addr / usbd_msc_cfg.scsi_blk_size), usbd_msc_cfg.block_buffer, usbd_msc_cfg.scsi_blk_size) != 0) {
|
|
|
|
|
SCSI_SetSenseData(SCSI_KCQHE_WRITEFAULT);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
usbd_msc_cfg.scsi_blk_addr += bytes_read;
|
|
|
|
|
usbd_msc_cfg.scsi_blk_len -= bytes_read;
|
|
|
|
|
usbd_msc_cfg.csw.dDataResidue -= bytes_read;
|
|
|
|
|
|
|
|
|
|
if (usbd_msc_cfg.scsi_blk_len == 0) {
|
|
|
|
|
sendCSW(CSW_STATUS_CMD_PASSED);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool SCSI_processVerify()
|
|
|
|
|
{
|
|
|
|
|
#if 0
|
|
|
|
|
uint32_t bytes_read;
|
|
|
|
|
uint8_t out_buffer[MASS_STORAGE_BULK_EP_MPS];
|
|
|
|
|
|
|
|
|
|
USB_LOG_DBG("verify addr:%d\r\n", usbd_msc_cfg.scsi_blk_addr);
|
|
|
|
|
|
|
|
|
|
/* we fill an array in RAM of 1 block before writing it in memory */
|
|
|
|
|
usbd_ep_read(mass_ep_data[MSD_OUT_EP_IDX].ep_addr, out_buffer, MASS_STORAGE_BULK_EP_MPS,
|
|
|
|
|
&bytes_read);
|
|
|
|
|
|
|
|
|
|
/* we read an entire block */
|
|
|
|
|
if (!(usbd_msc_cfg.scsi_blk_addr % usbd_msc_cfg.scsi_blk_size)) {
|
|
|
|
|
if (usbd_msc_sector_read((usbd_msc_cfg.scsi_blk_addr / usbd_msc_cfg.scsi_blk_size), usbd_msc_cfg.block_buffer, usbd_msc_cfg.scsi_blk_size) != 0) {
|
|
|
|
|
SCSI_SetSenseData(SCSI_KCQHE_UREINRESERVEDAREA);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* info are in RAM -> no need to re-read memory */
|
|
|
|
|
for (uint16_t i = 0U; i < bytes_read; i++) {
|
|
|
|
|
if (usbd_msc_cfg.block_buffer[usbd_msc_cfg.scsi_blk_addr % usbd_msc_cfg.scsi_blk_size + i] != out_buffer[i]) {
|
|
|
|
|
USB_LOG_DBG("Mismatch sector %d offset %d",
|
|
|
|
|
usbd_msc_cfg.scsi_blk_addr / usbd_msc_cfg.scsi_blk_size, i);
|
|
|
|
|
memOK = false;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
usbd_msc_cfg.scsi_blk_addr += bytes_read;
|
|
|
|
|
usbd_msc_cfg.scsi_blk_len -= bytes_read;
|
|
|
|
|
usbd_msc_cfg.csw.dDataResidue -= bytes_read;
|
|
|
|
|
|
|
|
|
|
if (usbd_msc_cfg.scsi_blk_len == 0) {
|
|
|
|
|
sendCSW(CSW_STATUS_CMD_PASSED);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool SCSI_CBWDecode()
|
|
|
|
|
{
|
|
|
|
|
uint8_t *buf2send = usbd_msc_cfg.block_buffer;
|
|
|
|
|
uint32_t len2send = 0;
|
|
|
|
|
uint32_t bytes_read;
|
|
|
|
|
bool ret = false;
|
|
|
|
|
|
|
|
|
|
usbd_ep_read(mass_ep_data[MSD_OUT_EP_IDX].ep_addr, (uint8_t *)&usbd_msc_cfg.cbw, USB_SIZEOF_MSC_CBW,
|
|
|
|
|
&bytes_read);
|
|
|
|
|
|
|
|
|
|
if (bytes_read != sizeof(struct CBW)) {
|
|
|
|
|
USB_LOG_ERR("size != sizeof(cbw)\r\n");
|
|
|
|
|
SCSI_SetSenseData(SCSI_KCQIR_INVALIDCOMMAND);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
usbd_msc_cfg.csw.dTag = usbd_msc_cfg.cbw.dTag;
|
|
|
|
|
usbd_msc_cfg.csw.dDataResidue = usbd_msc_cfg.cbw.dDataLength;
|
|
|
|
|
|
|
|
|
|
if ((usbd_msc_cfg.cbw.bLUN > 1) || (usbd_msc_cfg.cbw.dSignature != MSC_CBW_Signature) || (usbd_msc_cfg.cbw.bCBLength < 1) || (usbd_msc_cfg.cbw.bCBLength > 16)) {
|
|
|
|
|
SCSI_SetSenseData(SCSI_KCQIR_INVALIDCOMMAND);
|
|
|
|
|
return false;
|
|
|
|
|
} else {
|
|
|
|
|
switch (usbd_msc_cfg.cbw.CB[0]) {
|
|
|
|
|
case SCSI_CMD_TESTUNITREADY:
|
|
|
|
|
ret = SCSI_testUnitReady(&buf2send, &len2send);
|
|
|
|
|
break;
|
|
|
|
|
case SCSI_CMD_REQUESTSENSE:
|
|
|
|
|
ret = SCSI_requestSense(&buf2send, &len2send);
|
|
|
|
|
break;
|
|
|
|
|
case SCSI_CMD_INQUIRY:
|
|
|
|
|
ret = SCSI_inquiry(&buf2send, &len2send);
|
|
|
|
|
break;
|
|
|
|
|
case SCSI_CMD_STARTSTOPUNIT:
|
|
|
|
|
ret = SCSI_startStopUnit(&buf2send, &len2send);
|
|
|
|
|
break;
|
|
|
|
|
case SCSI_CMD_PREVENTMEDIAREMOVAL:
|
|
|
|
|
ret = SCSI_preventAllowMediaRemoval(&buf2send, &len2send);
|
|
|
|
|
break;
|
|
|
|
|
case SCSI_CMD_MODESENSE6:
|
|
|
|
|
ret = SCSI_modeSense6(&buf2send, &len2send);
|
|
|
|
|
break;
|
|
|
|
|
case SCSI_CMD_MODESENSE10:
|
|
|
|
|
ret = SCSI_modeSense10(&buf2send, &len2send);
|
|
|
|
|
break;
|
|
|
|
|
case SCSI_CMD_READFORMATCAPACITIES:
|
|
|
|
|
ret = SCSI_readFormatCapacity(&buf2send, &len2send);
|
|
|
|
|
break;
|
|
|
|
|
case SCSI_CMD_READCAPACITY10:
|
|
|
|
|
ret = SCSI_readCapacity10(&buf2send, &len2send);
|
|
|
|
|
break;
|
|
|
|
|
case SCSI_CMD_READ10:
|
|
|
|
|
ret = SCSI_read10(NULL, 0);
|
|
|
|
|
break;
|
|
|
|
|
case SCSI_CMD_READ12:
|
|
|
|
|
ret = SCSI_read12(NULL, 0);
|
|
|
|
|
break;
|
|
|
|
|
case SCSI_CMD_WRITE10:
|
|
|
|
|
ret = SCSI_write10(NULL, 0);
|
|
|
|
|
break;
|
|
|
|
|
case SCSI_CMD_WRITE12:
|
|
|
|
|
ret = SCSI_write12(NULL, 0);
|
|
|
|
|
break;
|
|
|
|
|
case SCSI_CMD_VERIFY10:
|
|
|
|
|
ret = SCSI_verify10(NULL, 0);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
SCSI_SetSenseData(SCSI_KCQIR_INVALIDCOMMAND);
|
|
|
|
|
USB_LOG_WRN("unsupported cmd:0x%02x\r\n", usbd_msc_cfg.cbw.CB[0]);
|
|
|
|
|
ret = false;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (ret) {
|
|
|
|
|
if (usbd_msc_cfg.stage == MSC_READ_CBW) {
|
|
|
|
|
if (len2send) {
|
|
|
|
|
sendLastData(buf2send, len2send);
|
|
|
|
|
} else {
|
|
|
|
|
sendCSW(CSW_STATUS_CMD_PASSED);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
/**
|
|
|
|
|
* @brief SCSI Command list
|
|
|
|
|
*
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
static bool SCSI_testUnitReady(uint8_t **data, uint32_t *len)
|
|
|
|
|
{
|
|
|
|
|
@@ -871,6 +600,7 @@ static bool SCSI_write10(uint8_t **data, uint32_t *len)
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
usbd_msc_cfg.stage = MSC_DATA_OUT;
|
|
|
|
|
usbd_ep_start_read(mass_ep_data[MSD_OUT_EP_IDX].ep_addr, &usbd_msc_cfg.block_buffer[usbd_msc_cfg.scsi_blk_addr % usbd_msc_cfg.scsi_blk_size], usbd_msc_cfg.scsi_blk_size);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -904,6 +634,7 @@ static bool SCSI_write12(uint8_t **data, uint32_t *len)
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
usbd_msc_cfg.stage = MSC_DATA_OUT;
|
|
|
|
|
usbd_ep_start_read(mass_ep_data[MSD_OUT_EP_IDX].ep_addr, &usbd_msc_cfg.block_buffer[usbd_msc_cfg.scsi_blk_addr % usbd_msc_cfg.scsi_blk_size], MASS_STORAGE_BULK_EP_MPS);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -952,30 +683,222 @@ static bool SCSI_verify10(uint8_t **data, uint32_t *len)
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void mass_storage_bulk_out(uint8_t ep)
|
|
|
|
|
#ifdef CONFIG_USBDEV_MSC_THREAD
|
|
|
|
|
static void usbd_msc_thread_memory_read_done(void)
|
|
|
|
|
{
|
|
|
|
|
size_t flags;
|
|
|
|
|
uint32_t transfer_len;
|
|
|
|
|
|
|
|
|
|
flags = usb_osal_enter_critical_section();
|
|
|
|
|
|
|
|
|
|
transfer_len = MIN(usbd_msc_cfg.scsi_blk_len, usbd_msc_cfg.scsi_blk_size);
|
|
|
|
|
|
|
|
|
|
usbd_ep_start_write(mass_ep_data[MSD_IN_EP_IDX].ep_addr,
|
|
|
|
|
&usbd_msc_cfg.block_buffer[usbd_msc_cfg.scsi_blk_addr % usbd_msc_cfg.scsi_blk_size], transfer_len);
|
|
|
|
|
|
|
|
|
|
usbd_msc_cfg.scsi_blk_addr += transfer_len;
|
|
|
|
|
usbd_msc_cfg.scsi_blk_len -= transfer_len;
|
|
|
|
|
usbd_msc_cfg.csw.dDataResidue -= transfer_len;
|
|
|
|
|
|
|
|
|
|
if (usbd_msc_cfg.scsi_blk_len == 0) {
|
|
|
|
|
usbd_msc_cfg.stage = MSC_SEND_CSW;
|
|
|
|
|
}
|
|
|
|
|
usb_osal_leave_critical_section(flags);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
static bool SCSI_processRead(void)
|
|
|
|
|
{
|
|
|
|
|
uint32_t transfer_len;
|
|
|
|
|
|
|
|
|
|
USB_LOG_DBG("read addr:%d\r\n", usbd_msc_cfg.scsi_blk_addr);
|
|
|
|
|
|
|
|
|
|
transfer_len = MIN(usbd_msc_cfg.scsi_blk_len, usbd_msc_cfg.scsi_blk_size);
|
|
|
|
|
|
|
|
|
|
/* we read an entire block */
|
|
|
|
|
if (!(usbd_msc_cfg.scsi_blk_addr % usbd_msc_cfg.scsi_blk_size)) {
|
|
|
|
|
#ifdef CONFIG_USBDEV_MSC_THREAD
|
|
|
|
|
thread_op = MSC_THREAD_OP_READ_MEM;
|
|
|
|
|
usb_osal_sem_give(msc_sem);
|
|
|
|
|
return true;
|
|
|
|
|
#else
|
|
|
|
|
if (usbd_msc_sector_read((usbd_msc_cfg.scsi_blk_addr / usbd_msc_cfg.scsi_blk_size), usbd_msc_cfg.block_buffer, usbd_msc_cfg.scsi_blk_size) != 0) {
|
|
|
|
|
SCSI_SetSenseData(SCSI_KCQHE_UREINRESERVEDAREA);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
usbd_ep_start_write(mass_ep_data[MSD_IN_EP_IDX].ep_addr,
|
|
|
|
|
&usbd_msc_cfg.block_buffer[usbd_msc_cfg.scsi_blk_addr % usbd_msc_cfg.scsi_blk_size], transfer_len);
|
|
|
|
|
|
|
|
|
|
usbd_msc_cfg.scsi_blk_addr += transfer_len;
|
|
|
|
|
usbd_msc_cfg.scsi_blk_len -= transfer_len;
|
|
|
|
|
usbd_msc_cfg.csw.dDataResidue -= transfer_len;
|
|
|
|
|
|
|
|
|
|
if (usbd_msc_cfg.scsi_blk_len == 0) {
|
|
|
|
|
usbd_msc_cfg.stage = MSC_SEND_CSW;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifdef CONFIG_USBDEV_MSC_THREAD
|
|
|
|
|
static void usbd_msc_thread_memory_write_done()
|
|
|
|
|
{
|
|
|
|
|
size_t flags;
|
|
|
|
|
uint32_t nbytes;
|
|
|
|
|
|
|
|
|
|
flags = usb_osal_enter_critical_section();
|
|
|
|
|
|
|
|
|
|
nbytes = current_byte_read;
|
|
|
|
|
|
|
|
|
|
usbd_msc_cfg.scsi_blk_addr += nbytes;
|
|
|
|
|
usbd_msc_cfg.scsi_blk_len -= nbytes;
|
|
|
|
|
usbd_msc_cfg.csw.dDataResidue -= nbytes;
|
|
|
|
|
|
|
|
|
|
if (usbd_msc_cfg.scsi_blk_len == 0) {
|
|
|
|
|
usbd_msc_send_csw(CSW_STATUS_CMD_PASSED);
|
|
|
|
|
} else {
|
|
|
|
|
usbd_ep_start_read(mass_ep_data[MSD_OUT_EP_IDX].ep_addr, &usbd_msc_cfg.block_buffer[usbd_msc_cfg.scsi_blk_addr % usbd_msc_cfg.scsi_blk_size], MASS_STORAGE_BULK_EP_MPS);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
usb_osal_leave_critical_section(flags);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
static bool SCSI_processWrite(uint32_t nbytes)
|
|
|
|
|
{
|
|
|
|
|
USB_LOG_DBG("write addr:%d\r\n", usbd_msc_cfg.scsi_blk_addr);
|
|
|
|
|
|
|
|
|
|
/* if the array is filled, write it in memory */
|
|
|
|
|
if ((usbd_msc_cfg.scsi_blk_addr % usbd_msc_cfg.scsi_blk_size) + nbytes >= usbd_msc_cfg.scsi_blk_size) {
|
|
|
|
|
#ifdef CONFIG_USBDEV_MSC_THREAD
|
|
|
|
|
thread_op = MSC_THREAD_OP_WRITE_MEM;
|
|
|
|
|
current_byte_read = nbytes;
|
|
|
|
|
usb_osal_sem_give(msc_sem);
|
|
|
|
|
return true;
|
|
|
|
|
#else
|
|
|
|
|
if (usbd_msc_sector_write((usbd_msc_cfg.scsi_blk_addr / usbd_msc_cfg.scsi_blk_size), usbd_msc_cfg.block_buffer, usbd_msc_cfg.scsi_blk_size) != 0) {
|
|
|
|
|
SCSI_SetSenseData(SCSI_KCQHE_WRITEFAULT);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
usbd_msc_cfg.scsi_blk_addr += nbytes;
|
|
|
|
|
usbd_msc_cfg.scsi_blk_len -= nbytes;
|
|
|
|
|
usbd_msc_cfg.csw.dDataResidue -= nbytes;
|
|
|
|
|
|
|
|
|
|
if (usbd_msc_cfg.scsi_blk_len == 0) {
|
|
|
|
|
usbd_msc_send_csw(CSW_STATUS_CMD_PASSED);
|
|
|
|
|
} else {
|
|
|
|
|
usbd_ep_start_read(mass_ep_data[MSD_OUT_EP_IDX].ep_addr, &usbd_msc_cfg.block_buffer[usbd_msc_cfg.scsi_blk_addr % usbd_msc_cfg.scsi_blk_size], usbd_msc_cfg.scsi_blk_size);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool SCSI_CBWDecode(uint32_t nbytes)
|
|
|
|
|
{
|
|
|
|
|
uint8_t *buf2send = usbd_msc_cfg.block_buffer;
|
|
|
|
|
uint32_t len2send = 0;
|
|
|
|
|
bool ret = false;
|
|
|
|
|
|
|
|
|
|
if (nbytes != sizeof(struct CBW)) {
|
|
|
|
|
USB_LOG_ERR("size != sizeof(cbw)\r\n");
|
|
|
|
|
SCSI_SetSenseData(SCSI_KCQIR_INVALIDCOMMAND);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
usbd_msc_cfg.csw.dTag = usbd_msc_cfg.cbw.dTag;
|
|
|
|
|
usbd_msc_cfg.csw.dDataResidue = usbd_msc_cfg.cbw.dDataLength;
|
|
|
|
|
|
|
|
|
|
if ((usbd_msc_cfg.cbw.bLUN > 1) || (usbd_msc_cfg.cbw.dSignature != MSC_CBW_Signature) || (usbd_msc_cfg.cbw.bCBLength < 1) || (usbd_msc_cfg.cbw.bCBLength > 16)) {
|
|
|
|
|
SCSI_SetSenseData(SCSI_KCQIR_INVALIDCOMMAND);
|
|
|
|
|
return false;
|
|
|
|
|
} else {
|
|
|
|
|
USB_LOG_DBG("Decode CB:0x%02x\r\n",usbd_msc_cfg.cbw.CB[0]);
|
|
|
|
|
switch (usbd_msc_cfg.cbw.CB[0]) {
|
|
|
|
|
case SCSI_CMD_TESTUNITREADY:
|
|
|
|
|
ret = SCSI_testUnitReady(&buf2send, &len2send);
|
|
|
|
|
break;
|
|
|
|
|
case SCSI_CMD_REQUESTSENSE:
|
|
|
|
|
ret = SCSI_requestSense(&buf2send, &len2send);
|
|
|
|
|
break;
|
|
|
|
|
case SCSI_CMD_INQUIRY:
|
|
|
|
|
ret = SCSI_inquiry(&buf2send, &len2send);
|
|
|
|
|
break;
|
|
|
|
|
case SCSI_CMD_STARTSTOPUNIT:
|
|
|
|
|
ret = SCSI_startStopUnit(&buf2send, &len2send);
|
|
|
|
|
break;
|
|
|
|
|
case SCSI_CMD_PREVENTMEDIAREMOVAL:
|
|
|
|
|
ret = SCSI_preventAllowMediaRemoval(&buf2send, &len2send);
|
|
|
|
|
break;
|
|
|
|
|
case SCSI_CMD_MODESENSE6:
|
|
|
|
|
ret = SCSI_modeSense6(&buf2send, &len2send);
|
|
|
|
|
break;
|
|
|
|
|
case SCSI_CMD_MODESENSE10:
|
|
|
|
|
ret = SCSI_modeSense10(&buf2send, &len2send);
|
|
|
|
|
break;
|
|
|
|
|
case SCSI_CMD_READFORMATCAPACITIES:
|
|
|
|
|
ret = SCSI_readFormatCapacity(&buf2send, &len2send);
|
|
|
|
|
break;
|
|
|
|
|
case SCSI_CMD_READCAPACITY10:
|
|
|
|
|
ret = SCSI_readCapacity10(&buf2send, &len2send);
|
|
|
|
|
break;
|
|
|
|
|
case SCSI_CMD_READ10:
|
|
|
|
|
ret = SCSI_read10(NULL, 0);
|
|
|
|
|
break;
|
|
|
|
|
case SCSI_CMD_READ12:
|
|
|
|
|
ret = SCSI_read12(NULL, 0);
|
|
|
|
|
break;
|
|
|
|
|
case SCSI_CMD_WRITE10:
|
|
|
|
|
ret = SCSI_write10(NULL, 0);
|
|
|
|
|
break;
|
|
|
|
|
case SCSI_CMD_WRITE12:
|
|
|
|
|
ret = SCSI_write12(NULL, 0);
|
|
|
|
|
break;
|
|
|
|
|
case SCSI_CMD_VERIFY10:
|
|
|
|
|
ret = SCSI_verify10(NULL, 0);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
SCSI_SetSenseData(SCSI_KCQIR_INVALIDCOMMAND);
|
|
|
|
|
USB_LOG_WRN("unsupported cmd:0x%02x\r\n", usbd_msc_cfg.cbw.CB[0]);
|
|
|
|
|
ret = false;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (ret) {
|
|
|
|
|
if (usbd_msc_cfg.stage == MSC_READ_CBW) {
|
|
|
|
|
if (len2send) {
|
|
|
|
|
USB_LOG_DBG("Send info len:%d\r\n",len2send);
|
|
|
|
|
usbd_msc_send_info(buf2send, len2send);
|
|
|
|
|
} else {
|
|
|
|
|
usbd_msc_send_csw(CSW_STATUS_CMD_PASSED);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void mass_storage_bulk_out(uint8_t ep, uint32_t nbytes)
|
|
|
|
|
{
|
|
|
|
|
switch (usbd_msc_cfg.stage) {
|
|
|
|
|
case MSC_READ_CBW:
|
|
|
|
|
if (SCSI_CBWDecode() == false) {
|
|
|
|
|
if (SCSI_CBWDecode(nbytes) == false) {
|
|
|
|
|
USB_LOG_ERR("Command:0x%02x decode err\r\n", usbd_msc_cfg.cbw.CB[0]);
|
|
|
|
|
usbd_msc_bot_abort();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
/* last command is write10 or write12,and has caculated blk_addr and blk_len,so the device start reading data from host*/
|
|
|
|
|
case MSC_DATA_OUT:
|
|
|
|
|
switch (usbd_msc_cfg.cbw.CB[0]) {
|
|
|
|
|
case SCSI_CMD_WRITE10:
|
|
|
|
|
case SCSI_CMD_WRITE12:
|
|
|
|
|
if (SCSI_processWrite() == false) {
|
|
|
|
|
sendCSW(CSW_STATUS_CMD_FAILED); /* send fail status to host,and the host will retry*/
|
|
|
|
|
//return;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case SCSI_CMD_VERIFY10:
|
|
|
|
|
if (SCSI_processVerify() == false) {
|
|
|
|
|
sendCSW(CSW_STATUS_CMD_FAILED); /* send fail status to host,and the host will retry*/
|
|
|
|
|
//return;
|
|
|
|
|
if (SCSI_processWrite(nbytes) == false) {
|
|
|
|
|
usbd_msc_send_csw(CSW_STATUS_CMD_FAILED); /* send fail status to host,and the host will retry*/
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
@@ -985,65 +908,34 @@ static void mass_storage_bulk_out(uint8_t ep)
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifdef CONFIG_USBDEV_MSC_THREAD
|
|
|
|
|
if (thread_op != MSC_THREAD_OP_WRITE_MEM) {
|
|
|
|
|
/*set ep ack to recv next data*/
|
|
|
|
|
usbd_ep_read(ep, NULL, 0, NULL);
|
|
|
|
|
}
|
|
|
|
|
#else
|
|
|
|
|
/*set ep ack to recv next data*/
|
|
|
|
|
usbd_ep_read(ep, NULL, 0, NULL);
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief EP Bulk IN handler, used to send data to the Host
|
|
|
|
|
*
|
|
|
|
|
* @param ep Endpoint address.
|
|
|
|
|
* @param ep_status Endpoint status code.
|
|
|
|
|
*
|
|
|
|
|
* @return N/A.
|
|
|
|
|
*/
|
|
|
|
|
static void mass_storage_bulk_in(uint8_t ep)
|
|
|
|
|
static void mass_storage_bulk_in(uint8_t ep, uint32_t nbytes)
|
|
|
|
|
{
|
|
|
|
|
switch (usbd_msc_cfg.stage) {
|
|
|
|
|
/* last command is read10 or read12,and has caculated blk_addr and blk_len,so the device has to send remain data to host*/
|
|
|
|
|
case MSC_DATA_IN:
|
|
|
|
|
switch (usbd_msc_cfg.cbw.CB[0]) {
|
|
|
|
|
case SCSI_CMD_READ10:
|
|
|
|
|
case SCSI_CMD_READ12:
|
|
|
|
|
if (SCSI_processRead() == false) {
|
|
|
|
|
sendCSW(CSW_STATUS_CMD_FAILED); /* send fail status to host,and the host will retry*/
|
|
|
|
|
usbd_msc_send_csw(CSW_STATUS_CMD_FAILED); /* send fail status to host,and the host will retry*/
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
/*the device has to send a CSW*/
|
|
|
|
|
/*the device has to send a CSW*/
|
|
|
|
|
case MSC_SEND_CSW:
|
|
|
|
|
sendCSW(CSW_STATUS_CMD_PASSED);
|
|
|
|
|
usbd_msc_send_csw(CSW_STATUS_CMD_PASSED);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
/*the host has received the CSW*/
|
|
|
|
|
case MSC_WAIT_CSW:
|
|
|
|
|
usbd_msc_cfg.stage = MSC_READ_CBW;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void msc_storage_notify_handler(uint8_t event, void *arg)
|
|
|
|
|
{
|
|
|
|
|
switch (event) {
|
|
|
|
|
case USBD_EVENT_RESET:
|
|
|
|
|
usbd_msc_reset();
|
|
|
|
|
USB_LOG_DBG("Start reading cbw\r\n");
|
|
|
|
|
usbd_ep_start_read(mass_ep_data[MSD_OUT_EP_IDX].ep_addr, (uint8_t *)&usbd_msc_cfg.cbw, USB_SIZEOF_MSC_CBW);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
|