/** * For driver use only. * * @param status * @return */ uint8_t BulkOnly::HandleSCSIError(uint8_t status) { uint8_t ret = 0; switch(status) { case 0: return MASS_ERR_SUCCESS; case 2: ErrorMessage<uint8_t > (PSTR("Phase Error"), status); ErrorMessage<uint8_t > (PSTR("LUN"), bTheLUN); ResetRecovery(); return MASS_ERR_GENERAL_SCSI_ERROR; case 1: ErrorMessage<uint8_t > (PSTR("SCSI Error"), status); ErrorMessage<uint8_t > (PSTR("LUN"), bTheLUN); RequestSenseResponce rsp; ret = RequestSense(bTheLUN, sizeof (RequestSenseResponce), (uint8_t*) & rsp); if(ret) { return MASS_ERR_GENERAL_SCSI_ERROR; } ErrorMessage<uint8_t > (PSTR("Response Code"), rsp.bResponseCode); if(rsp.bResponseCode & 0x80) { Notify(PSTR("Information field: "), 0x80); for(int i = 0; i < 4; i++) { D_PrintHex<uint8_t > (rsp.CmdSpecificInformation[i], 0x80); Notify(PSTR(" "), 0x80); } Notify(PSTR("\r\n"), 0x80); } ErrorMessage<uint8_t > (PSTR("Sense Key"), rsp.bmSenseKey); ErrorMessage<uint8_t > (PSTR("Add Sense Code"), rsp.bAdditionalSenseCode); ErrorMessage<uint8_t > (PSTR("Add Sense Qual"), rsp.bAdditionalSenseQualifier); // warning, this is not testing ASQ, only SK and ASC. switch(rsp.bmSenseKey) { case SCSI_S_UNIT_ATTENTION: switch(rsp.bAdditionalSenseCode) { case SCSI_ASC_MEDIA_CHANGED: return MASS_ERR_MEDIA_CHANGED; default: return MASS_ERR_UNIT_NOT_READY; } case SCSI_S_NOT_READY: switch(rsp.bAdditionalSenseCode) { case SCSI_ASC_MEDIUM_NOT_PRESENT: return MASS_ERR_NO_MEDIA; default: return MASS_ERR_UNIT_NOT_READY; } case SCSI_S_ILLEGAL_REQUEST: switch(rsp.bAdditionalSenseCode) { case SCSI_ASC_LBA_OUT_OF_RANGE: return MASS_ERR_BAD_LBA; default: return MASS_ERR_CMD_NOT_SUPPORTED; } default: return MASS_ERR_GENERAL_SCSI_ERROR; } // case 4: return MASS_ERR_UNIT_BUSY; // Busy means retry later. // case 0x05/0x14: we stalled out // case 0x15/0x16: we naked out. default: ErrorMessage<uint8_t > (PSTR("Gen SCSI Err"), status); ErrorMessage<uint8_t > (PSTR("LUN"), bTheLUN); return status; } // switch }
/***************************************************************************//** * @brief * Perform an MSD Bulk Only Transfer (BOT). * * @param[in] cbw * Pointer to a Command Block Wrapper (CBW) data structure. * * @param[in] data * Data buffer for data to be transferred. * * @return * A positive (or zero) value indicating the number of bytes transferred. * @n A negative value indicates a transfer error code enumerated in * @ref MSDBOT_Status_TypeDef. ******************************************************************************/ int MSDBOT_Xfer(void* cbw, void* data) { uint32_t len; int timeout, result, direction, retVal; MSDBOT_CBW_TypeDef *pCbw = (MSDBOT_CBW_TypeDef*) cbw; /* Send CBW. */ result = USBH_WriteB(epOut, cbw, CBW_LEN, DEFAULT_TIMEOUT); if (result != CBW_LEN) { ResetRecovery(); return MSDBOT_XFER_ERROR; } retVal = 0; direction = pCbw->Direction; len = pCbw->dCBWDataTransferLength; /* Send/receive data (optional phase). */ if (len) { timeout = DEFAULT_TIMEOUT + (len / timeoutFactor); if (direction) result = USBH_ReadB(epIn, data, len, timeout); else result = USBH_WriteB(epOut, data, len, timeout); retVal = result; if (result == USB_STATUS_EP_STALLED) { if (direction) USBH_UnStallEpB(epIn); else USBH_UnStallEpB(epOut); } else if (result <= 0) { ResetRecovery(); return MSDBOT_XFER_ERROR; } } /* Retrieve CSW. */ result = USBH_ReadB(epIn, csw, CSW_LEN, DEFAULT_TIMEOUT); if (result != CSW_LEN) { if (result == USB_STATUS_EP_STALLED) { if (direction) USBH_UnStallEpB(epIn); else USBH_UnStallEpB(epOut); result = USBH_ReadB(epIn, csw, CSW_LEN, DEFAULT_TIMEOUT); if (result != CSW_LEN) { ResetRecovery(); return MSDBOT_XFER_ERROR; } } else { ResetRecovery(); return MSDBOT_XFER_ERROR; } } if (CswValid(pCbw) && CswMeaningful(pCbw)) { if (pCsw->bCSWStatus == USB_CLASS_MSD_CSW_CMDPASSED) { return retVal; } return MSDBOT_CMD_FAILED; } ResetRecovery(); return MSDBOT_XFER_ERROR; }
/** * For driver use only. * * @param pcbw * @param buf_size * @param buf * @param flags * @return */ uint8_t BulkOnly::Transaction(CommandBlockWrapper *pcbw, uint16_t buf_size, void *buf #if MS_WANT_PARSER , uint8_t flags #endif ) { #if MS_WANT_PARSER uint16_t bytes = (pcbw->dCBWDataTransferLength > buf_size) ? buf_size : pcbw->dCBWDataTransferLength; printf("Transfersize %i\r\n", bytes); delay(1000); bool callback = (flags & MASS_TRANS_FLG_CALLBACK) == MASS_TRANS_FLG_CALLBACK; #else uint16_t bytes = buf_size; #endif bool write = (pcbw->bmCBWFlags & MASS_CMD_DIR_IN) != MASS_CMD_DIR_IN; uint8_t ret = 0; uint8_t usberr; CommandStatusWrapper csw; // up here, we allocate ahead to save cpu cycles. SetCurLUN(pcbw->bmCBWLUN); ErrorMessage<uint32_t > (PSTR("CBW.dCBWTag"), pcbw->dCBWTag); while((usberr = pUsb->outTransfer(bAddress, epInfo[epDataOutIndex].epAddr, sizeof (CommandBlockWrapper), (uint8_t*)pcbw)) == hrBUSY) delay(1); ret = HandleUsbError(usberr, epDataOutIndex); //ret = HandleUsbError(pUsb->outTransfer(bAddress, epInfo[epDataOutIndex].epAddr, sizeof (CommandBlockWrapper), (uint8_t*)pcbw), epDataOutIndex); if(ret) { ErrorMessage<uint8_t > (PSTR("============================ CBW"), ret); } else { if(bytes) { if(!write) { #if MS_WANT_PARSER if(callback) { uint8_t rbuf[bytes]; while((usberr = pUsb->inTransfer(bAddress, epInfo[epDataInIndex].epAddr, &bytes, rbuf)) == hrBUSY) delay(1); if(usberr == hrSUCCESS) ((USBReadParser*)buf)->Parse(bytes, rbuf, 0); } else { #endif while((usberr = pUsb->inTransfer(bAddress, epInfo[epDataInIndex].epAddr, &bytes, (uint8_t*)buf)) == hrBUSY) delay(1); #if MS_WANT_PARSER } #endif ret = HandleUsbError(usberr, epDataInIndex); } else { while((usberr = pUsb->outTransfer(bAddress, epInfo[epDataOutIndex].epAddr, bytes, (uint8_t*)buf)) == hrBUSY) delay(1); ret = HandleUsbError(usberr, epDataOutIndex); } if(ret) { ErrorMessage<uint8_t > (PSTR("============================ DAT"), ret); } } } { bytes = sizeof (CommandStatusWrapper); int tries = 2; while(tries--) { while((usberr = pUsb->inTransfer(bAddress, epInfo[epDataInIndex].epAddr, &bytes, (uint8_t*) & csw)) == hrBUSY) delay(1); if(!usberr) break; ClearEpHalt(epDataInIndex); if(tries) ResetRecovery(); } if(!ret) { Notify(PSTR("CBW:\t\tOK\r\n"), 0x80); Notify(PSTR("Data Stage:\tOK\r\n"), 0x80); } else { // Throw away csw, IT IS NOT OF ANY USE. ResetRecovery(); return ret; } ret = HandleUsbError(usberr, epDataInIndex); if(ret) { ErrorMessage<uint8_t > (PSTR("============================ CSW"), ret); } if(usberr == hrSUCCESS) { if(IsValidCSW(&csw, pcbw)) { //ErrorMessage<uint32_t > (PSTR("CSW.dCBWTag"), csw.dCSWTag); //ErrorMessage<uint8_t > (PSTR("bCSWStatus"), csw.bCSWStatus); //ErrorMessage<uint32_t > (PSTR("dCSWDataResidue"), csw.dCSWDataResidue); Notify(PSTR("CSW:\t\tOK\r\n\r\n"), 0x80); return csw.bCSWStatus; } else { // NOTE! Sometimes this is caused by the reported residue being wrong. // Get a different device. It isn't compliant, and should have never passed Q&A. // I own one... 05e3:0701 Genesys Logic, Inc. USB 2.0 IDE Adapter. // Other devices that exhibit this behavior exist in the wild too. // Be sure to check quirks in the Linux source code before reporting a bug. --xxxajk Notify(PSTR("Invalid CSW\r\n"), 0x80); ResetRecovery(); //return MASS_ERR_SUCCESS; return MASS_ERR_INVALID_CSW; } } } return ret; }