static bool_t msc_decode(USBDriver *usbp) { uint32_t nblocks, secsize; switch (CBW.CBWCB[0]) { case SCSI_REQUEST_SENSE: break; case SCSI_INQUIRY: msc_transmit(usbp, (uint8_t *)&scsi_inquiry_data, sizeof scsi_inquiry_data); CSW.bCSWStatus = MSC_CSW_STATUS_PASSED; break; case SCSI_READ_FORMAT_CAPACITIES: buf[8] = scsi_read_format_capacities(&nblocks, &secsize); buf[0] = buf[1] = buf[2] = 0; buf[3] = 8; buf[4] = (uint8_t)(nblocks >> 24); buf[5] = (uint8_t)(nblocks >> 16); buf[6] = (uint8_t)(nblocks >> 8); buf[7] = (uint8_t)(nblocks >> 0); buf[9] = (uint8_t)(secsize >> 16); buf[10] = (uint8_t)(secsize >> 8); buf[11] = (uint8_t)(secsize >> 0); msc_transmit(usbp, buf, 12); CSW.bCSWStatus = MSC_CSW_STATUS_PASSED; break; default: return TRUE; } return FALSE; }
void msc_handle_command (void) { size_t n; uint32_t nblocks, secsize; uint32_t lba; int r; chopstx_mutex_lock (msc_mutex); msc_state = MSC_IDLE; usb_start_receive ((uint8_t *)&CBW, sizeof CBW); chopstx_cond_wait (msc_cond, msc_mutex); if (msg != RDY_OK) { /* Error occured, ignore the request and go into error state */ msc_state = MSC_ERROR; usb_lld_stall_rx (ENDP6); goto done; } n = ep6_out.rxcnt; if ((n != sizeof (struct CBW)) || (CBW.dCBWSignature != MSC_CBW_SIGNATURE)) { msc_state = MSC_ERROR; usb_lld_stall_rx (ENDP6); goto done; } CSW.dCSWTag = CBW.dCBWTag; switch (CBW.CBWCB[0]) { case SCSI_REPORT_LUN: buf[0] = buf[1] = buf[2] = buf[3] = 0; buf[4] = buf[5] = buf[6] = buf[7] = 0; msc_send_result (buf, 8); goto done; case SCSI_REQUEST_SENSE: if (CBW.CBWCB[1] & 0x01) /* DESC */ msc_send_result ((uint8_t *)&scsi_sense_data_desc, sizeof scsi_sense_data_desc); else msc_send_result ((uint8_t *)&scsi_sense_data_fixed, sizeof scsi_sense_data_fixed); /* After the error is reported, clear it, if it's . */ if (!keep_contingent_allegiance) { contingent_allegiance = 0; set_scsi_sense_data (0x00, 0x00); } goto done; case SCSI_INQUIRY: if (CBW.CBWCB[1] & 0x01) /* EVPD */ { if (CBW.CBWCB[2] == 0x83) /* Handle the case Page Code 0x83 */ msc_send_result ((uint8_t *)&scsi_inquiry_data_83, sizeof scsi_inquiry_data_83); else /* Otherwise, assume page 00 */ msc_send_result ((uint8_t *)&scsi_inquiry_data_00, sizeof scsi_inquiry_data_00); } else msc_send_result ((uint8_t *)&scsi_inquiry_data, sizeof scsi_inquiry_data); goto done; case SCSI_READ_FORMAT_CAPACITIES: buf[8] = scsi_read_format_capacities (&nblocks, &secsize); buf[0] = buf[1] = buf[2] = 0; buf[3] = 8; buf[4] = (uint8_t)(nblocks >> 24); buf[5] = (uint8_t)(nblocks >> 16); buf[6] = (uint8_t)(nblocks >> 8); buf[7] = (uint8_t)(nblocks >> 0); buf[9] = (uint8_t)(secsize >> 16); buf[10] = (uint8_t)(secsize >> 8); buf[11] = (uint8_t)(secsize >> 0); msc_send_result (buf, 12); goto done; case SCSI_START_STOP_UNIT: if (CBW.CBWCB[4] == 0x00 /* stop */ || CBW.CBWCB[4] == 0x02 /* eject */ || CBW.CBWCB[4] == 0x03 /* close */) { msc_scsi_stop (CBW.CBWCB[4]); set_scsi_sense_data (0x05, 0x24); /* ILLEGAL_REQUEST */ contingent_allegiance = 1; keep_contingent_allegiance = 1; } /* CBW.CBWCB[4] == 0x01 *//* start */ goto success; case SCSI_TEST_UNIT_READY: if (contingent_allegiance) { CSW.bCSWStatus = MSC_CSW_STATUS_FAILED; CSW.dCSWDataResidue = 0; msc_send_result (NULL, 0); goto done; } /* fall through */ success: case SCSI_SYNCHRONIZE_CACHE: case SCSI_VERIFY10: case SCSI_ALLOW_MEDIUM_REMOVAL: CSW.bCSWStatus = MSC_CSW_STATUS_PASSED; CSW.dCSWDataResidue = CBW.dCBWDataTransferLength; msc_send_result (NULL, 0); goto done; case SCSI_MODE_SENSE6: buf[0] = 0x03; buf[1] = buf[2] = buf[3] = 0; msc_send_result (buf, 4); goto done; case SCSI_READ_CAPACITY10: scsi_read_format_capacities (&nblocks, &secsize); buf[0] = (uint8_t)((nblocks - 1) >> 24); buf[1] = (uint8_t)((nblocks - 1) >> 16); buf[2] = (uint8_t)((nblocks - 1) >> 8); buf[3] = (uint8_t)((nblocks - 1) >> 0); buf[4] = (uint8_t)(secsize >> 24); buf[5] = (uint8_t)(secsize >> 16); buf[6] = (uint8_t)(secsize >> 8); buf[7] = (uint8_t)(secsize >> 0); msc_send_result (buf, 8); goto done; case SCSI_READ10: case SCSI_WRITE10: break; default: if (CBW.dCBWDataTransferLength == 0) { CSW.bCSWStatus = MSC_CSW_STATUS_FAILED; CSW.dCSWDataResidue = 0; msc_send_result (NULL, 0); goto done; } else { msc_state = MSC_ERROR; usb_lld_stall_tx (ENDP6); usb_lld_stall_rx (ENDP6); goto done; } } lba = (CBW.CBWCB[2] << 24) | (CBW.CBWCB[3] << 16) | (CBW.CBWCB[4] << 8) | CBW.CBWCB[5]; /* Transfer direction.*/ if (CBW.bmCBWFlags & 0x80) { /* IN, Device to Host.*/ msc_state = MSC_DATA_IN; if (CBW.CBWCB[0] == SCSI_READ10) { const uint8_t *p; CSW.dCSWDataResidue = 0; while (1) { if (CBW.CBWCB[7] == 0 && CBW.CBWCB[8] == 0) { CSW.bCSWStatus = MSC_CSW_STATUS_PASSED; break; } if ((r = msc_scsi_read (lba, &p)) == 0) { msc_send_data (p, 512); if (++CBW.CBWCB[5] == 0) if (++CBW.CBWCB[4] == 0) if (++CBW.CBWCB[3] == 0) ++CBW.CBWCB[2]; if (CBW.CBWCB[8]-- == 0) CBW.CBWCB[7]--; CSW.dCSWDataResidue += 512; lba++; } else { CSW.bCSWStatus = MSC_CSW_STATUS_FAILED; contingent_allegiance = 1; if (r == SCSI_ERROR_NOT_READY) set_scsi_sense_data (SCSI_ERROR_NOT_READY, 0x3a); else set_scsi_sense_data (r, 0x00); break; } } msc_send_result (NULL, 0); } } else { /* OUT, Host to Device.*/ if (CBW.CBWCB[0] == SCSI_WRITE10) { CSW.dCSWDataResidue = CBW.dCBWDataTransferLength; while (1) { if (CBW.CBWCB[8] == 0 && CBW.CBWCB[7] == 0) { CSW.bCSWStatus = MSC_CSW_STATUS_PASSED; break; } msc_recv_data (); if (msg != RDY_OK) /* ignore erroneous packet, ang go next. */ continue; if ((r = msc_scsi_write (lba, buf, 512)) == 0) { if (++CBW.CBWCB[5] == 0) if (++CBW.CBWCB[4] == 0) if (++CBW.CBWCB[3] == 0) ++CBW.CBWCB[2]; if (CBW.CBWCB[8]-- == 0) CBW.CBWCB[7]--; CSW.dCSWDataResidue -= 512; lba++; } else { CSW.bCSWStatus = MSC_CSW_STATUS_FAILED; contingent_allegiance = 1; if (r == SCSI_ERROR_NOT_READY) set_scsi_sense_data (SCSI_ERROR_NOT_READY, 0x3a); else set_scsi_sense_data (r, 0x00); break; } } msc_send_result (NULL, 0); } } done: chopstx_mutex_unlock (msc_mutex); }
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; }