Rework Mass Storage Driver
- Implemented (hopefully) correct Mass Storage Reset Recovery protocol - Implemented auto-sense protocol for SCSI command failure
This commit is contained in:
parent
835bb887c0
commit
b58a299521
|
@ -25,7 +25,6 @@
|
||||||
/* TODO:
|
/* TODO:
|
||||||
*
|
*
|
||||||
* - Implement of conditional compilation of multiple-luns per instance.
|
* - Implement of conditional compilation of multiple-luns per instance.
|
||||||
* - Implement error checking and recovery when commands fail.
|
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
|
@ -261,32 +261,170 @@ typedef PACKED_STRUCT {
|
||||||
} msd_csw_t;
|
} msd_csw_t;
|
||||||
#define MSD_CSW_SIGNATURE 0x53425355
|
#define MSD_CSW_SIGNATURE 0x53425355
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
typedef union {
|
msd_cbw_t *cbw;
|
||||||
msd_cbw_t cbw;
|
uint8_t csw_status;
|
||||||
msd_csw_t csw;
|
uint32_t data_processed;
|
||||||
} msd_transaction_t;
|
} msd_transaction_t;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
MSD_TRANSACTIONRESULT_OK,
|
MSD_BOTRESULT_OK,
|
||||||
MSD_TRANSACTIONRESULT_DISCONNECTED,
|
MSD_BOTRESULT_DISCONNECTED,
|
||||||
MSD_TRANSACTIONRESULT_STALL,
|
MSD_BOTRESULT_ERROR
|
||||||
MSD_TRANSACTIONRESULT_BUS_ERROR,
|
} msd_bot_result_t;
|
||||||
MSD_TRANSACTIONRESULT_SYNC_ERROR
|
|
||||||
} msd_transaction_result_t;
|
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
MSD_COMMANDRESULT_PASSED = 0,
|
MSD_RESULT_OK = MSD_BOTRESULT_OK,
|
||||||
MSD_COMMANDRESULT_FAILED = 1,
|
MSD_RESULT_DISCONNECTED = MSD_BOTRESULT_DISCONNECTED,
|
||||||
MSD_COMMANDRESULT_PHASE_ERROR = 2
|
MSD_RESULT_TRANSPORT_ERROR = MSD_BOTRESULT_ERROR,
|
||||||
} msd_command_result_t;
|
MSD_RESULT_FAILED
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
msd_transaction_result_t tres;
|
|
||||||
msd_command_result_t cres;
|
|
||||||
} msd_result_t;
|
} msd_result_t;
|
||||||
|
|
||||||
|
|
||||||
|
#define CSW_STATUS_PASSED 0
|
||||||
|
#define CSW_STATUS_FAILED 1
|
||||||
|
#define CSW_STATUS_PHASE_ERROR 2
|
||||||
|
|
||||||
|
static bool _msd_bot_reset(USBHMassStorageDriver *msdp) {
|
||||||
|
|
||||||
|
usbh_urbstatus_t res;
|
||||||
|
res = usbhControlRequest(msdp->dev, USBH_CLASSOUT(USBH_REQTYPE_CLASS, 0xFF, 0, msdp->ifnum), 0, NULL);
|
||||||
|
if (res != USBH_URBSTATUS_OK) {
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
osalThreadSleepMilliseconds(100);
|
||||||
|
|
||||||
|
return usbhEPReset(&msdp->epin) && usbhEPReset(&msdp->epout);
|
||||||
|
}
|
||||||
|
|
||||||
|
static msd_bot_result_t _msd_bot_transaction(msd_transaction_t *tran, USBHMassStorageLUNDriver *lunp, void *data) {
|
||||||
|
|
||||||
|
uint32_t data_actual_len, actual_len;
|
||||||
|
usbh_urbstatus_t status;
|
||||||
|
USBH_DEFINE_BUFFER(msd_csw_t csw);
|
||||||
|
|
||||||
|
tran->cbw->bCBWLUN = (uint8_t)(lunp - &lunp->msdp->luns[0]);
|
||||||
|
tran->cbw->dCBWSignature = MSD_CBW_SIGNATURE;
|
||||||
|
tran->cbw->dCBWTag = ++lunp->msdp->tag;
|
||||||
|
tran->data_processed = 0;
|
||||||
|
|
||||||
|
/* control phase */
|
||||||
|
status = usbhBulkTransfer(&lunp->msdp->epout, &tran->cbw,
|
||||||
|
sizeof(tran->cbw), &actual_len, MS2ST(1000));
|
||||||
|
|
||||||
|
if (status == USBH_URBSTATUS_CANCELLED) {
|
||||||
|
uerr("\tMSD: Control phase: USBH_URBSTATUS_CANCELLED");
|
||||||
|
return MSD_BOTRESULT_DISCONNECTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((status != USBH_URBSTATUS_OK) || (actual_len != sizeof(tran->cbw))) {
|
||||||
|
uerrf("\tMSD: Control phase: status = %d (!= OK), actual_len = %d (expected to send %d)",
|
||||||
|
status, actual_len, sizeof(tran->cbw));
|
||||||
|
_msd_bot_reset(lunp->msdp);
|
||||||
|
return MSD_BOTRESULT_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* data phase */
|
||||||
|
data_actual_len = 0;
|
||||||
|
if (tran->cbw->dCBWDataTransferLength) {
|
||||||
|
usbh_ep_t *const ep = tran->cbw->bmCBWFlags & MSD_CBWFLAGS_D2H ? &lunp->msdp->epin : &lunp->msdp->epout;
|
||||||
|
status = usbhBulkTransfer(
|
||||||
|
ep,
|
||||||
|
data,
|
||||||
|
tran->cbw->dCBWDataTransferLength,
|
||||||
|
&data_actual_len, MS2ST(20000));
|
||||||
|
|
||||||
|
if (status == USBH_URBSTATUS_CANCELLED) {
|
||||||
|
uerr("\tMSD: Data phase: USBH_URBSTATUS_CANCELLED");
|
||||||
|
return MSD_BOTRESULT_DISCONNECTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status == USBH_URBSTATUS_STALL) {
|
||||||
|
uerrf("\tMSD: Data phase: USBH_URBSTATUS_STALL, clear halt");
|
||||||
|
status = usbhEPReset(ep);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status != USBH_URBSTATUS_OK) {
|
||||||
|
uerrf("\tMSD: Data phase: status = %d (!= OK), resetting", status);
|
||||||
|
_msd_bot_reset(lunp->msdp);
|
||||||
|
return MSD_BOTRESULT_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* status phase */
|
||||||
|
status = usbhBulkTransfer(&lunp->msdp->epin, &csw,
|
||||||
|
sizeof(csw), &actual_len, MS2ST(1000));
|
||||||
|
|
||||||
|
if (status == USBH_URBSTATUS_STALL) {
|
||||||
|
uwarn("\tMSD: Status phase: USBH_URBSTATUS_STALL, clear halt and retry");
|
||||||
|
|
||||||
|
status = usbhEPReset(&lunp->msdp->epin);
|
||||||
|
|
||||||
|
if (status == USBH_URBSTATUS_OK) {
|
||||||
|
status = usbhBulkTransfer(&lunp->msdp->epin, &csw,
|
||||||
|
sizeof(csw), &actual_len, MS2ST(1000));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status == USBH_URBSTATUS_CANCELLED) {
|
||||||
|
uerr("\tMSD: Status phase: USBH_URBSTATUS_CANCELLED");
|
||||||
|
return MSD_BOTRESULT_DISCONNECTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status != USBH_URBSTATUS_OK) {
|
||||||
|
uerrf("\tMSD: Status phase: status = %d (!= OK), resetting", status);
|
||||||
|
_msd_bot_reset(lunp->msdp);
|
||||||
|
return MSD_BOTRESULT_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* validate CSW */
|
||||||
|
if ((actual_len != sizeof(csw))
|
||||||
|
|| (csw.dCSWSignature != MSD_CSW_SIGNATURE)
|
||||||
|
|| (csw.dCSWTag != lunp->msdp->tag)
|
||||||
|
|| (csw.bCSWStatus >= CSW_STATUS_PHASE_ERROR)) {
|
||||||
|
/* CSW is not valid */
|
||||||
|
uerrf("\tMSD: Status phase: Invalid CSW: len=%d, dCSWSignature=%x, dCSWTag=%x (expected %x), bCSWStatus=%d, resetting",
|
||||||
|
actual_len,
|
||||||
|
csw.dCSWSignature,
|
||||||
|
csw.dCSWTag,
|
||||||
|
lunp->msdp->tag,
|
||||||
|
csw.bCSWStatus);
|
||||||
|
_msd_bot_reset(lunp->msdp);
|
||||||
|
return MSD_BOTRESULT_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* check if CSW is meaningful */
|
||||||
|
if ((csw.bCSWStatus != CSW_STATUS_PHASE_ERROR)
|
||||||
|
&& (csw.dCSWDataResidue > tran->cbw->dCBWDataTransferLength)) {
|
||||||
|
/* CSW is not meaningful */
|
||||||
|
uerrf("\tMSD: Status phase: CSW not meaningful: bCSWStatus=%d, dCSWDataResidue=%u, dCBWDataTransferLength=%u, resetting",
|
||||||
|
csw.bCSWStatus,
|
||||||
|
csw.dCSWDataResidue,
|
||||||
|
tran->cbw->dCBWDataTransferLength);
|
||||||
|
_msd_bot_reset(lunp->msdp);
|
||||||
|
return MSD_BOTRESULT_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (csw.bCSWStatus == CSW_STATUS_PHASE_ERROR) {
|
||||||
|
uerr("\tMSD: Status phase: Phase error, resetting");
|
||||||
|
_msd_bot_reset(lunp->msdp);
|
||||||
|
return MSD_BOTRESULT_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
tran->data_processed = tran->cbw->dCBWDataTransferLength - csw.dCSWDataResidue;
|
||||||
|
if (data_actual_len < tran->data_processed) {
|
||||||
|
tran->data_processed = data_actual_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
tran->csw_status = csw.bCSWStatus;
|
||||||
|
|
||||||
|
return MSD_BOTRESULT_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* ----------------------------------------------------- */
|
/* ----------------------------------------------------- */
|
||||||
/* SCSI Commands */
|
/* SCSI Commands */
|
||||||
/* ----------------------------------------------------- */
|
/* ----------------------------------------------------- */
|
||||||
|
@ -366,216 +504,175 @@ typedef PACKED_STRUCT {
|
||||||
/* test unit ready */
|
/* test unit ready */
|
||||||
#define SCSI_CMD_TEST_UNIT_READY 0x00
|
#define SCSI_CMD_TEST_UNIT_READY 0x00
|
||||||
|
|
||||||
/* Other commands, TODO: use or remove them
|
static msd_result_t scsi_requestsense(USBHMassStorageLUNDriver *lunp, scsi_sense_response_t *resp);
|
||||||
#define SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL 0x1E
|
|
||||||
#define SCSI_CMD_VERIFY_10 0x2F
|
|
||||||
#define SCSI_CMD_SEND_DIAGNOSTIC 0x1D
|
|
||||||
#define SCSI_CMD_MODE_SENSE_6 0x1A
|
|
||||||
*/
|
|
||||||
|
|
||||||
static inline void _prepare_cbw(msd_transaction_t *tran, USBHMassStorageLUNDriver *lunp) {
|
static msd_result_t _scsi_perform_transaction(USBHMassStorageLUNDriver *lunp,
|
||||||
tran->cbw.bCBWLUN = (uint8_t)(lunp - &lunp->msdp->luns[0]);
|
msd_transaction_t *transaction, void *data) {
|
||||||
memset(&tran->cbw.CBWCB, 0, sizeof(tran->cbw.CBWCB));
|
|
||||||
|
msd_bot_result_t res;
|
||||||
|
res = _msd_bot_transaction(transaction, lunp, data);
|
||||||
|
if (res != MSD_BOTRESULT_OK) {
|
||||||
|
return (msd_result_t)res;
|
||||||
}
|
}
|
||||||
|
|
||||||
static msd_transaction_result_t _msd_transaction(msd_transaction_t *tran, USBHMassStorageLUNDriver *lunp, void *data) {
|
if (transaction->csw_status == CSW_STATUS_FAILED) {
|
||||||
|
if (transaction->cbw->CBWCB[0] != SCSI_CMD_REQUEST_SENSE) {
|
||||||
uint32_t actual_len;
|
/* do auto-sense (except for SCSI_CMD_REQUEST_SENSE!) */
|
||||||
usbh_urbstatus_t status;
|
uwarn("\tMSD: Command failed, auto-sense");
|
||||||
|
USBH_DEFINE_BUFFER(scsi_sense_response_t sense);
|
||||||
tran->cbw.dCBWSignature = MSD_CBW_SIGNATURE;
|
if (scsi_requestsense(lunp, &sense) == MSD_RESULT_OK) {
|
||||||
tran->cbw.dCBWTag = ++lunp->msdp->tag;
|
uwarnf("\tMSD: REQUEST SENSE: Sense key=%x, ASC=%02x, ASCQ=%02x",
|
||||||
|
sense.byte[2] & 0xf, sense.byte[12], sense.byte[13]);
|
||||||
/* control phase */
|
|
||||||
status = usbhBulkTransfer(&lunp->msdp->epout, &tran->cbw,
|
|
||||||
sizeof(tran->cbw), &actual_len, MS2ST(1000));
|
|
||||||
|
|
||||||
if (status == USBH_URBSTATUS_CANCELLED) {
|
|
||||||
uerr("\tMSD: Control phase: USBH_URBSTATUS_CANCELLED");
|
|
||||||
return MSD_TRANSACTIONRESULT_DISCONNECTED;
|
|
||||||
} else if (status == USBH_URBSTATUS_STALL) {
|
|
||||||
uerr("\tMSD: Control phase: USBH_URBSTATUS_STALL");
|
|
||||||
return MSD_TRANSACTIONRESULT_STALL;
|
|
||||||
} else if (status != USBH_URBSTATUS_OK) {
|
|
||||||
uerrf("\tMSD: Control phase: status = %d, != OK", status);
|
|
||||||
return MSD_TRANSACTIONRESULT_BUS_ERROR;
|
|
||||||
} else if (actual_len != sizeof(tran->cbw)) {
|
|
||||||
uerrf("\tMSD: Control phase: wrong actual_len = %d", actual_len);
|
|
||||||
return MSD_TRANSACTIONRESULT_BUS_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* data phase */
|
|
||||||
if (tran->cbw.dCBWDataTransferLength) {
|
|
||||||
status = usbhBulkTransfer(
|
|
||||||
tran->cbw.bmCBWFlags & MSD_CBWFLAGS_D2H ? &lunp->msdp->epin : &lunp->msdp->epout,
|
|
||||||
data,
|
|
||||||
tran->cbw.dCBWDataTransferLength,
|
|
||||||
&actual_len, MS2ST(20000));
|
|
||||||
|
|
||||||
if (status == USBH_URBSTATUS_CANCELLED) {
|
|
||||||
uerr("\tMSD: Data phase: USBH_URBSTATUS_CANCELLED");
|
|
||||||
return MSD_TRANSACTIONRESULT_DISCONNECTED;
|
|
||||||
} else if (status == USBH_URBSTATUS_STALL) {
|
|
||||||
uerr("\tMSD: Data phase: USBH_URBSTATUS_STALL");
|
|
||||||
return MSD_TRANSACTIONRESULT_STALL;
|
|
||||||
} else if (status != USBH_URBSTATUS_OK) {
|
|
||||||
uerrf("\tMSD: Data phase: status = %d, != OK", status);
|
|
||||||
return MSD_TRANSACTIONRESULT_BUS_ERROR;
|
|
||||||
} else if (actual_len != tran->cbw.dCBWDataTransferLength) {
|
|
||||||
uerrf("\tMSD: Data phase: wrong actual_len = %d", actual_len);
|
|
||||||
return MSD_TRANSACTIONRESULT_BUS_ERROR;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return MSD_RESULT_FAILED;
|
||||||
|
|
||||||
/* status phase */
|
|
||||||
status = usbhBulkTransfer(&lunp->msdp->epin, &tran->csw,
|
|
||||||
sizeof(tran->csw), &actual_len, MS2ST(1000));
|
|
||||||
|
|
||||||
if (status == USBH_URBSTATUS_CANCELLED) {
|
|
||||||
uerr("\tMSD: Status phase: USBH_URBSTATUS_CANCELLED");
|
|
||||||
return MSD_TRANSACTIONRESULT_DISCONNECTED;
|
|
||||||
} else if (status == USBH_URBSTATUS_STALL) {
|
|
||||||
uerr("\tMSD: Status phase: USBH_URBSTATUS_STALL");
|
|
||||||
return MSD_TRANSACTIONRESULT_STALL;
|
|
||||||
} else if (status != USBH_URBSTATUS_OK) {
|
|
||||||
uerrf("\tMSD: Status phase: status = %d, != OK", status);
|
|
||||||
return MSD_TRANSACTIONRESULT_BUS_ERROR;
|
|
||||||
} else if (actual_len != sizeof(tran->csw)) {
|
|
||||||
uerrf("\tMSD: Status phase: wrong actual_len = %d", actual_len);
|
|
||||||
return MSD_TRANSACTIONRESULT_BUS_ERROR;
|
|
||||||
} else if (tran->csw.dCSWSignature != MSD_CSW_SIGNATURE) {
|
|
||||||
uerr("\tMSD: Status phase: wrong signature");
|
|
||||||
return MSD_TRANSACTIONRESULT_BUS_ERROR;
|
|
||||||
} else if (tran->csw.dCSWTag != lunp->msdp->tag) {
|
|
||||||
uerrf("\tMSD: Status phase: wrong tag (expected %d, got %d)",
|
|
||||||
lunp->msdp->tag, tran->csw.dCSWTag);
|
|
||||||
return MSD_TRANSACTIONRESULT_SYNC_ERROR;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tran->csw.dCSWDataResidue) {
|
return MSD_RESULT_OK;
|
||||||
uwarnf("\tMSD: Residue=%d", tran->csw.dCSWDataResidue);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return MSD_TRANSACTIONRESULT_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static msd_result_t scsi_inquiry(USBHMassStorageLUNDriver *lunp, scsi_inquiry_response_t *resp) {
|
static msd_result_t scsi_inquiry(USBHMassStorageLUNDriver *lunp, scsi_inquiry_response_t *resp) {
|
||||||
|
USBH_DEFINE_BUFFER(msd_cbw_t cbw);
|
||||||
msd_transaction_t transaction;
|
msd_transaction_t transaction;
|
||||||
msd_result_t res;
|
msd_result_t res;
|
||||||
|
|
||||||
_prepare_cbw(&transaction, lunp);
|
memset(cbw.CBWCB, 0, sizeof(cbw.CBWCB));
|
||||||
transaction.cbw.dCBWDataTransferLength = sizeof(scsi_inquiry_response_t);
|
cbw.dCBWDataTransferLength = sizeof(scsi_inquiry_response_t);
|
||||||
transaction.cbw.bmCBWFlags = MSD_CBWFLAGS_D2H;
|
cbw.bmCBWFlags = MSD_CBWFLAGS_D2H;
|
||||||
transaction.cbw.bCBWCBLength = 6;
|
cbw.bCBWCBLength = 6;
|
||||||
transaction.cbw.CBWCB[0] = SCSI_CMD_INQUIRY;
|
cbw.CBWCB[0] = SCSI_CMD_INQUIRY;
|
||||||
transaction.cbw.CBWCB[4] = sizeof(scsi_inquiry_response_t);
|
cbw.CBWCB[4] = sizeof(scsi_inquiry_response_t);
|
||||||
|
transaction.cbw = &cbw;
|
||||||
|
|
||||||
res.tres = _msd_transaction(&transaction, lunp, resp);
|
res = _scsi_perform_transaction(lunp, &transaction, resp);
|
||||||
if (res.tres == MSD_TRANSACTIONRESULT_OK) {
|
if (res == MSD_RESULT_OK) {
|
||||||
res.cres = (msd_command_result_t) transaction.csw.bCSWStatus;
|
//transaction is OK; check length
|
||||||
|
if (transaction.data_processed < cbw.dCBWDataTransferLength) {
|
||||||
|
res = MSD_RESULT_TRANSPORT_ERROR;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
static msd_result_t scsi_requestsense(USBHMassStorageLUNDriver *lunp, scsi_sense_response_t *resp) {
|
static msd_result_t scsi_requestsense(USBHMassStorageLUNDriver *lunp, scsi_sense_response_t *resp) {
|
||||||
|
USBH_DEFINE_BUFFER(msd_cbw_t cbw);
|
||||||
msd_transaction_t transaction;
|
msd_transaction_t transaction;
|
||||||
msd_result_t res;
|
msd_result_t res;
|
||||||
|
|
||||||
_prepare_cbw(&transaction, lunp);
|
memset(cbw.CBWCB, 0, sizeof(cbw.CBWCB));
|
||||||
transaction.cbw.dCBWDataTransferLength = sizeof(scsi_sense_response_t);
|
cbw.dCBWDataTransferLength = sizeof(scsi_sense_response_t);
|
||||||
transaction.cbw.bmCBWFlags = MSD_CBWFLAGS_D2H;
|
cbw.bmCBWFlags = MSD_CBWFLAGS_D2H;
|
||||||
transaction.cbw.bCBWCBLength = 12;
|
cbw.bCBWCBLength = 12;
|
||||||
transaction.cbw.CBWCB[0] = SCSI_CMD_REQUEST_SENSE;
|
cbw.CBWCB[0] = SCSI_CMD_REQUEST_SENSE;
|
||||||
transaction.cbw.CBWCB[4] = sizeof(scsi_sense_response_t);
|
cbw.CBWCB[4] = sizeof(scsi_sense_response_t);
|
||||||
|
|
||||||
res.tres = _msd_transaction(&transaction, lunp, resp);
|
res = _scsi_perform_transaction(lunp, &transaction, resp);
|
||||||
if (res.tres == MSD_TRANSACTIONRESULT_OK) {
|
if (res == MSD_RESULT_OK) {
|
||||||
res.cres = (msd_command_result_t) transaction.csw.bCSWStatus;
|
//transaction is OK; check length
|
||||||
|
if (transaction.data_processed < cbw.dCBWDataTransferLength) {
|
||||||
|
res = MSD_RESULT_TRANSPORT_ERROR;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
static msd_result_t scsi_testunitready(USBHMassStorageLUNDriver *lunp) {
|
static msd_result_t scsi_testunitready(USBHMassStorageLUNDriver *lunp) {
|
||||||
|
USBH_DEFINE_BUFFER(msd_cbw_t cbw);
|
||||||
msd_transaction_t transaction;
|
msd_transaction_t transaction;
|
||||||
msd_result_t res;
|
|
||||||
|
|
||||||
_prepare_cbw(&transaction, lunp);
|
memset(cbw.CBWCB, 0, sizeof(cbw.CBWCB));
|
||||||
transaction.cbw.dCBWDataTransferLength = 0;
|
cbw.dCBWDataTransferLength = 0;
|
||||||
transaction.cbw.bmCBWFlags = MSD_CBWFLAGS_D2H;
|
cbw.bmCBWFlags = MSD_CBWFLAGS_D2H;
|
||||||
transaction.cbw.bCBWCBLength = 6;
|
cbw.bCBWCBLength = 6;
|
||||||
transaction.cbw.CBWCB[0] = SCSI_CMD_TEST_UNIT_READY;
|
cbw.CBWCB[0] = SCSI_CMD_TEST_UNIT_READY;
|
||||||
|
|
||||||
res.tres = _msd_transaction(&transaction, lunp, NULL);
|
return _scsi_perform_transaction(lunp, &transaction, NULL);
|
||||||
if (res.tres == MSD_TRANSACTIONRESULT_OK) {
|
|
||||||
res.cres = (msd_command_result_t) transaction.csw.bCSWStatus;
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static msd_result_t scsi_readcapacity10(USBHMassStorageLUNDriver *lunp, scsi_readcapacity10_response_t *resp) {
|
static msd_result_t scsi_readcapacity10(USBHMassStorageLUNDriver *lunp, scsi_readcapacity10_response_t *resp) {
|
||||||
|
USBH_DEFINE_BUFFER(msd_cbw_t cbw);
|
||||||
msd_transaction_t transaction;
|
msd_transaction_t transaction;
|
||||||
msd_result_t res;
|
msd_result_t res;
|
||||||
|
|
||||||
_prepare_cbw(&transaction, lunp);
|
memset(cbw.CBWCB, 0, sizeof(cbw.CBWCB));
|
||||||
transaction.cbw.dCBWDataTransferLength = sizeof(scsi_readcapacity10_response_t);
|
cbw.dCBWDataTransferLength = sizeof(scsi_readcapacity10_response_t);
|
||||||
transaction.cbw.bmCBWFlags = MSD_CBWFLAGS_D2H;
|
cbw.bmCBWFlags = MSD_CBWFLAGS_D2H;
|
||||||
transaction.cbw.bCBWCBLength = 12;
|
cbw.bCBWCBLength = 12;
|
||||||
transaction.cbw.CBWCB[0] = SCSI_CMD_READ_CAPACITY_10;
|
cbw.CBWCB[0] = SCSI_CMD_READ_CAPACITY_10;
|
||||||
|
|
||||||
res.tres = _msd_transaction(&transaction, lunp, resp);
|
res = _scsi_perform_transaction(lunp, &transaction, resp);
|
||||||
if (res.tres == MSD_TRANSACTIONRESULT_OK) {
|
if (res == MSD_RESULT_OK) {
|
||||||
res.cres = (msd_command_result_t) transaction.csw.bCSWStatus;
|
//transaction is OK; check length
|
||||||
|
if (transaction.data_processed < cbw.dCBWDataTransferLength) {
|
||||||
|
res = MSD_RESULT_TRANSPORT_ERROR;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static msd_result_t scsi_read10(USBHMassStorageLUNDriver *lunp, uint32_t lba, uint16_t n, uint8_t *data) {
|
static msd_result_t scsi_read10(USBHMassStorageLUNDriver *lunp, uint32_t lba, uint16_t n, uint8_t *data, uint32_t *actual_len) {
|
||||||
|
USBH_DEFINE_BUFFER(msd_cbw_t cbw);
|
||||||
msd_transaction_t transaction;
|
msd_transaction_t transaction;
|
||||||
msd_result_t res;
|
msd_result_t res;
|
||||||
|
|
||||||
_prepare_cbw(&transaction, lunp);
|
memset(cbw.CBWCB, 0, sizeof(cbw.CBWCB));
|
||||||
transaction.cbw.dCBWDataTransferLength = n * lunp->info.blk_size;
|
cbw.dCBWDataTransferLength = n * lunp->info.blk_size;
|
||||||
transaction.cbw.bmCBWFlags = MSD_CBWFLAGS_D2H;
|
cbw.bmCBWFlags = MSD_CBWFLAGS_D2H;
|
||||||
transaction.cbw.bCBWCBLength = 10;
|
cbw.bCBWCBLength = 10;
|
||||||
transaction.cbw.CBWCB[0] = SCSI_CMD_READ_10;
|
cbw.CBWCB[0] = SCSI_CMD_READ_10;
|
||||||
transaction.cbw.CBWCB[2] = (uint8_t)(lba >> 24);
|
cbw.CBWCB[2] = (uint8_t)(lba >> 24);
|
||||||
transaction.cbw.CBWCB[3] = (uint8_t)(lba >> 16);
|
cbw.CBWCB[3] = (uint8_t)(lba >> 16);
|
||||||
transaction.cbw.CBWCB[4] = (uint8_t)(lba >> 8);
|
cbw.CBWCB[4] = (uint8_t)(lba >> 8);
|
||||||
transaction.cbw.CBWCB[5] = (uint8_t)(lba);
|
cbw.CBWCB[5] = (uint8_t)(lba);
|
||||||
transaction.cbw.CBWCB[7] = (uint8_t)(n >> 8);
|
cbw.CBWCB[7] = (uint8_t)(n >> 8);
|
||||||
transaction.cbw.CBWCB[8] = (uint8_t)(n);
|
cbw.CBWCB[8] = (uint8_t)(n);
|
||||||
|
|
||||||
res.tres = _msd_transaction(&transaction, lunp, data);
|
res = _scsi_perform_transaction(lunp, &transaction, data);
|
||||||
if (res.tres == MSD_TRANSACTIONRESULT_OK) {
|
if (actual_len) {
|
||||||
res.cres = (msd_command_result_t) transaction.csw.bCSWStatus;
|
*actual_len = transaction.data_processed;
|
||||||
}
|
}
|
||||||
|
if (res == MSD_RESULT_OK) {
|
||||||
|
//transaction is OK; check length
|
||||||
|
if (transaction.data_processed < cbw.dCBWDataTransferLength) {
|
||||||
|
res = MSD_RESULT_TRANSPORT_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
static msd_result_t scsi_write10(USBHMassStorageLUNDriver *lunp, uint32_t lba, uint16_t n, const uint8_t *data) {
|
static msd_result_t scsi_write10(USBHMassStorageLUNDriver *lunp, uint32_t lba, uint16_t n, const uint8_t *data, uint32_t *actual_len) {
|
||||||
|
USBH_DEFINE_BUFFER(msd_cbw_t cbw);
|
||||||
msd_transaction_t transaction;
|
msd_transaction_t transaction;
|
||||||
msd_result_t res;
|
msd_result_t res;
|
||||||
|
|
||||||
_prepare_cbw(&transaction, lunp);
|
memset(cbw.CBWCB, 0, sizeof(cbw.CBWCB));
|
||||||
transaction.cbw.dCBWDataTransferLength = n * lunp->info.blk_size;
|
cbw.dCBWDataTransferLength = n * lunp->info.blk_size;
|
||||||
transaction.cbw.bmCBWFlags = MSD_CBWFLAGS_H2D;
|
cbw.bmCBWFlags = MSD_CBWFLAGS_H2D;
|
||||||
transaction.cbw.bCBWCBLength = 10;
|
cbw.bCBWCBLength = 10;
|
||||||
transaction.cbw.CBWCB[0] = SCSI_CMD_WRITE_10;
|
cbw.CBWCB[0] = SCSI_CMD_WRITE_10;
|
||||||
transaction.cbw.CBWCB[2] = (uint8_t)(lba >> 24);
|
cbw.CBWCB[2] = (uint8_t)(lba >> 24);
|
||||||
transaction.cbw.CBWCB[3] = (uint8_t)(lba >> 16);
|
cbw.CBWCB[3] = (uint8_t)(lba >> 16);
|
||||||
transaction.cbw.CBWCB[4] = (uint8_t)(lba >> 8);
|
cbw.CBWCB[4] = (uint8_t)(lba >> 8);
|
||||||
transaction.cbw.CBWCB[5] = (uint8_t)(lba);
|
cbw.CBWCB[5] = (uint8_t)(lba);
|
||||||
transaction.cbw.CBWCB[7] = (uint8_t)(n >> 8);
|
cbw.CBWCB[7] = (uint8_t)(n >> 8);
|
||||||
transaction.cbw.CBWCB[8] = (uint8_t)(n);
|
cbw.CBWCB[8] = (uint8_t)(n);
|
||||||
|
|
||||||
res.tres = _msd_transaction(&transaction, lunp, (uint8_t *)data);
|
res = _scsi_perform_transaction(lunp, &transaction, (void *)data);
|
||||||
if (res.tres == MSD_TRANSACTIONRESULT_OK) {
|
if (actual_len) {
|
||||||
res.cres = (msd_command_result_t) transaction.csw.bCSWStatus;
|
*actual_len = transaction.data_processed;
|
||||||
}
|
}
|
||||||
|
if (res == MSD_RESULT_OK) {
|
||||||
|
//transaction is OK; check length
|
||||||
|
if (transaction.data_processed < cbw.dCBWDataTransferLength) {
|
||||||
|
res = MSD_RESULT_TRANSPORT_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -598,34 +695,6 @@ static const struct USBHMassStorageDriverVMT blk_vmt = {
|
||||||
(bool (*)(void *, BlockDeviceInfo *))usbhmsdLUNGetInfo
|
(bool (*)(void *, BlockDeviceInfo *))usbhmsdLUNGetInfo
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static uint32_t _requestsense(USBHMassStorageLUNDriver *lunp) {
|
|
||||||
scsi_sense_response_t sense;
|
|
||||||
msd_result_t res;
|
|
||||||
|
|
||||||
res = scsi_requestsense(lunp, &sense);
|
|
||||||
if (res.tres != MSD_TRANSACTIONRESULT_OK) {
|
|
||||||
uerr("\tREQUEST SENSE: Transaction error");
|
|
||||||
goto failed;
|
|
||||||
} else if (res.cres == MSD_COMMANDRESULT_FAILED) {
|
|
||||||
uerr("\tREQUEST SENSE: Command Failed");
|
|
||||||
goto failed;
|
|
||||||
} else if (res.cres == MSD_COMMANDRESULT_PHASE_ERROR) {
|
|
||||||
//TODO: Do reset, etc.
|
|
||||||
uerr("\tREQUEST SENSE: Command Phase Error");
|
|
||||||
goto failed;
|
|
||||||
}
|
|
||||||
|
|
||||||
uerrf("\tREQUEST SENSE: Sense key=%x, ASC=%02x, ASCQ=%02x",
|
|
||||||
sense.byte[2] & 0xf, sense.byte[12], sense.byte[13]);
|
|
||||||
|
|
||||||
return (sense.byte[2] & 0xf) | (sense.byte[12] << 8) | (sense.byte[13] << 16);
|
|
||||||
|
|
||||||
failed:
|
|
||||||
return 0xffffffff;
|
|
||||||
}
|
|
||||||
|
|
||||||
void usbhmsdLUNObjectInit(USBHMassStorageLUNDriver *lunp) {
|
void usbhmsdLUNObjectInit(USBHMassStorageLUNDriver *lunp) {
|
||||||
osalDbgCheck(lunp != NULL);
|
osalDbgCheck(lunp != NULL);
|
||||||
memset(lunp, 0, sizeof(*lunp));
|
memset(lunp, 0, sizeof(*lunp));
|
||||||
|
@ -678,71 +747,66 @@ bool usbhmsdLUNConnect(USBHMassStorageLUNDriver *lunp) {
|
||||||
|
|
||||||
osalMutexLock(&msdp->mtx);
|
osalMutexLock(&msdp->mtx);
|
||||||
|
|
||||||
USBH_DEFINE_BUFFER(union {
|
{
|
||||||
scsi_inquiry_response_t inq;
|
USBH_DEFINE_BUFFER(scsi_inquiry_response_t inq);
|
||||||
scsi_readcapacity10_response_t cap; } u);
|
|
||||||
|
|
||||||
uinfo("INQUIRY...");
|
uinfo("INQUIRY...");
|
||||||
res = scsi_inquiry(lunp, &u.inq);
|
res = scsi_inquiry(lunp, &inq);
|
||||||
if (res.tres != MSD_TRANSACTIONRESULT_OK) {
|
if (res == MSD_RESULT_DISCONNECTED) {
|
||||||
uerr("\tINQUIRY: Transaction error");
|
|
||||||
goto failed;
|
goto failed;
|
||||||
} else if (res.cres == MSD_COMMANDRESULT_FAILED) {
|
} else if (res == MSD_RESULT_TRANSPORT_ERROR) {
|
||||||
uerr("\tINQUIRY: Command Failed");
|
//retry?
|
||||||
_requestsense(lunp);
|
|
||||||
goto failed;
|
goto failed;
|
||||||
} else if (res.cres == MSD_COMMANDRESULT_PHASE_ERROR) {
|
} else if (res == MSD_RESULT_FAILED) {
|
||||||
//TODO: Do reset, etc.
|
//retry?
|
||||||
uerr("\tINQUIRY: Command Phase Error");
|
|
||||||
goto failed;
|
goto failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
uinfof("\tPDT=%02x", u.inq.peripheral & 0x1f);
|
uinfof("\tPDT=%02x", inq.peripheral & 0x1f);
|
||||||
if (u.inq.peripheral != 0) {
|
if (inq.peripheral != 0) {
|
||||||
uerr("\tUnsupported PDT");
|
uerr("\tUnsupported PDT");
|
||||||
goto failed;
|
goto failed;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Test if unit ready
|
// Test if unit ready
|
||||||
uint8_t i;
|
uint8_t i;
|
||||||
for (i = 0; i < 10; i++) {
|
for (i = 0; i < 10; i++) {
|
||||||
uinfo("TEST UNIT READY...");
|
uinfo("TEST UNIT READY...");
|
||||||
res = scsi_testunitready(lunp);
|
res = scsi_testunitready(lunp);
|
||||||
if (res.tres != MSD_TRANSACTIONRESULT_OK) {
|
if (res == MSD_RESULT_DISCONNECTED) {
|
||||||
uerr("\tTEST UNIT READY: Transaction error");
|
|
||||||
goto failed;
|
goto failed;
|
||||||
} else if (res.cres == MSD_COMMANDRESULT_FAILED) {
|
} else if (res == MSD_RESULT_TRANSPORT_ERROR) {
|
||||||
uerr("\tTEST UNIT READY: Command Failed");
|
//retry?
|
||||||
_requestsense(lunp);
|
goto failed;
|
||||||
|
} else if (res == MSD_RESULT_FAILED) {
|
||||||
|
uinfo("\tTEST UNIT READY: Command Failed, retry");
|
||||||
|
osalThreadSleepMilliseconds(200);
|
||||||
continue;
|
continue;
|
||||||
} else if (res.cres == MSD_COMMANDRESULT_PHASE_ERROR) {
|
|
||||||
//TODO: Do reset, etc.
|
|
||||||
uerr("\tTEST UNIT READY: Command Phase Error");
|
|
||||||
goto failed;
|
|
||||||
}
|
}
|
||||||
uinfo("\tReady.");
|
uinfo("\tReady.");
|
||||||
break;
|
break;
|
||||||
// osalThreadSleepMilliseconds(200); // will raise 'code is unreachable' warning
|
|
||||||
}
|
}
|
||||||
if (i == 10) goto failed;
|
if (i == 10) goto failed;
|
||||||
|
|
||||||
|
{
|
||||||
|
USBH_DEFINE_BUFFER(scsi_readcapacity10_response_t cap);
|
||||||
// Read capacity
|
// Read capacity
|
||||||
uinfo("READ CAPACITY(10)...");
|
uinfo("READ CAPACITY(10)...");
|
||||||
res = scsi_readcapacity10(lunp, &u.cap);
|
res = scsi_readcapacity10(lunp, &cap);
|
||||||
if (res.tres != MSD_TRANSACTIONRESULT_OK) {
|
if (res == MSD_RESULT_DISCONNECTED) {
|
||||||
uerr("\tREAD CAPACITY(10): Transaction error");
|
|
||||||
goto failed;
|
goto failed;
|
||||||
} else if (res.cres == MSD_COMMANDRESULT_FAILED) {
|
} else if (res == MSD_RESULT_TRANSPORT_ERROR) {
|
||||||
uerr("\tREAD CAPACITY(10): Command Failed");
|
//retry?
|
||||||
_requestsense(lunp);
|
|
||||||
goto failed;
|
goto failed;
|
||||||
} else if (res.cres == MSD_COMMANDRESULT_PHASE_ERROR) {
|
} else if (res == MSD_RESULT_FAILED) {
|
||||||
//TODO: Do reset, etc.
|
//retry?
|
||||||
uerr("\tREAD CAPACITY(10): Command Phase Error");
|
|
||||||
goto failed;
|
goto failed;
|
||||||
}
|
}
|
||||||
lunp->info.blk_size = __REV(u.cap.block_size);
|
|
||||||
lunp->info.blk_num = __REV(u.cap.last_block_addr) + 1;
|
lunp->info.blk_size = __REV(cap.block_size);
|
||||||
|
lunp->info.blk_num = __REV(cap.last_block_addr) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
uinfof("\tBlock size=%dbytes, blocks=%u (~%u MB)", lunp->info.blk_size, lunp->info.blk_num,
|
uinfof("\tBlock size=%dbytes, blocks=%u (~%u MB)", lunp->info.blk_size, lunp->info.blk_num,
|
||||||
(uint32_t)(((uint64_t)lunp->info.blk_size * lunp->info.blk_num) / (1024UL * 1024UL)));
|
(uint32_t)(((uint64_t)lunp->info.blk_size * lunp->info.blk_num) / (1024UL * 1024UL)));
|
||||||
|
|
||||||
|
@ -792,6 +856,7 @@ bool usbhmsdLUNRead(USBHMassStorageLUNDriver *lunp, uint32_t startblk,
|
||||||
bool ret = HAL_FAILED;
|
bool ret = HAL_FAILED;
|
||||||
uint16_t blocks;
|
uint16_t blocks;
|
||||||
msd_result_t res;
|
msd_result_t res;
|
||||||
|
uint32_t actual_len;
|
||||||
|
|
||||||
osalSysLock();
|
osalSysLock();
|
||||||
if (lunp->state != BLK_READY) {
|
if (lunp->state != BLK_READY) {
|
||||||
|
@ -808,18 +873,14 @@ bool usbhmsdLUNRead(USBHMassStorageLUNDriver *lunp, uint32_t startblk,
|
||||||
} else {
|
} else {
|
||||||
blocks = (uint16_t)n;
|
blocks = (uint16_t)n;
|
||||||
}
|
}
|
||||||
res = scsi_read10(lunp, startblk, blocks, buffer);
|
res = scsi_read10(lunp, startblk, blocks, buffer, &actual_len);
|
||||||
if (res.tres != MSD_TRANSACTIONRESULT_OK) {
|
if (res == MSD_RESULT_DISCONNECTED) {
|
||||||
uerr("\tREAD (10): Transaction error");
|
|
||||||
goto exit;
|
goto exit;
|
||||||
} else if (res.cres == MSD_COMMANDRESULT_FAILED) {
|
} else if (res == MSD_RESULT_TRANSPORT_ERROR) {
|
||||||
//TODO: request sense, and act appropriately
|
//retry?
|
||||||
uerr("\tREAD (10): Command Failed");
|
|
||||||
_requestsense(lunp);
|
|
||||||
goto exit;
|
goto exit;
|
||||||
} else if (res.cres == MSD_COMMANDRESULT_PHASE_ERROR) {
|
} else if (res == MSD_RESULT_FAILED) {
|
||||||
//TODO: Do reset, etc.
|
//retry?
|
||||||
uerr("\tREAD (10): Command Phase Error");
|
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
n -= blocks;
|
n -= blocks;
|
||||||
|
@ -849,6 +910,7 @@ bool usbhmsdLUNWrite(USBHMassStorageLUNDriver *lunp, uint32_t startblk,
|
||||||
bool ret = HAL_FAILED;
|
bool ret = HAL_FAILED;
|
||||||
uint16_t blocks;
|
uint16_t blocks;
|
||||||
msd_result_t res;
|
msd_result_t res;
|
||||||
|
uint32_t actual_len;
|
||||||
|
|
||||||
osalSysLock();
|
osalSysLock();
|
||||||
if (lunp->state != BLK_READY) {
|
if (lunp->state != BLK_READY) {
|
||||||
|
@ -865,18 +927,14 @@ bool usbhmsdLUNWrite(USBHMassStorageLUNDriver *lunp, uint32_t startblk,
|
||||||
} else {
|
} else {
|
||||||
blocks = (uint16_t)n;
|
blocks = (uint16_t)n;
|
||||||
}
|
}
|
||||||
res = scsi_write10(lunp, startblk, blocks, buffer);
|
res = scsi_write10(lunp, startblk, blocks, buffer, &actual_len);
|
||||||
if (res.tres != MSD_TRANSACTIONRESULT_OK) {
|
if (res == MSD_RESULT_DISCONNECTED) {
|
||||||
uerr("\tWRITE (10): Transaction error");
|
|
||||||
goto exit;
|
goto exit;
|
||||||
} else if (res.cres == MSD_COMMANDRESULT_FAILED) {
|
} else if (res == MSD_RESULT_TRANSPORT_ERROR) {
|
||||||
//TODO: request sense, and act appropriately
|
//retry?
|
||||||
uerr("\tWRITE (10): Command Failed");
|
|
||||||
_requestsense(lunp);
|
|
||||||
goto exit;
|
goto exit;
|
||||||
} else if (res.cres == MSD_COMMANDRESULT_PHASE_ERROR) {
|
} else if (res == MSD_RESULT_FAILED) {
|
||||||
//TODO: Do reset, etc.
|
//retry?
|
||||||
uerr("\tWRITE (10): Command Phase Error");
|
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
n -= blocks;
|
n -= blocks;
|
||||||
|
|
Loading…
Reference in New Issue