diff --git a/masstorage.cpp b/masstorage.cpp index 627364c6..ab1d21d4 100644 --- a/masstorage.cpp +++ b/masstorage.cpp @@ -70,6 +70,22 @@ uint8_t BulkOnly::SCSITransaction6(CDB6_t *cdb, uint16_t buf_size, void *buf, ui return (HandleSCSIError(Transaction(&cbw, buf_size, buf))); } +/** + * Wrap and execute a SCSI CDB with length of 10 + * + * @param cdb CDB to execute + * @param buf_size Size of expected transaction + * @param buf Buffer + * @param dir MASS_CMD_DIR_IN | MASS_CMD_DIR_OUT + * @return + */ +uint8_t BulkOnly::SCSITransaction10(CDB10_t *cdb, uint16_t buf_size, void *buf, uint8_t dir) { + // promote to 32bits. + CommandBlockWrapper cbw = CommandBlockWrapper(++dCBWTag, (uint32_t)buf_size, cdb, dir); + SetCurLUN(cdb->LUN); + return (HandleSCSIError(Transaction(&cbw, buf_size, buf))); +} + /** * Lock or Unlock the tray or door on device. * Caution: Some devices with buggy firmware will lock up. @@ -133,18 +149,24 @@ uint8_t BulkOnly::Read(uint8_t lun, uint32_t addr, uint16_t bsize, uint8_t block Notify(PSTR("\r\nblock size:\t"), 0x90); D_PrintHex (bsize, 0x90); Notify(PSTR("\r\n---------\r\n"), 0x80); - CommandBlockWrapper cbw = CommandBlockWrapper(0, ((uint32_t)bsize * blocks), MASS_CMD_DIR_IN, lun, 10, SCSI_CMD_READ_10); - cbw.CBWCB[1] = lun << 5; - cbw.CBWCB[2] = ((addr >> 24) & 0xff); - cbw.CBWCB[3] = ((addr >> 16) & 0xff); - cbw.CBWCB[4] = ((addr >> 8) & 0xff); - cbw.CBWCB[5] = (addr & 0xff); - cbw.CBWCB[8] = blocks; + + //CommandBlockWrapper cbw = CommandBlockWrapper(0, ((uint32_t)bsize * blocks), MASS_CMD_DIR_IN, lun, 10, SCSI_CMD_READ_10); + //cbw.CBWCB[1] = lun << 5; + //cbw.CBWCB[2] = ((addr >> 24) & 0xff); + //cbw.CBWCB[3] = ((addr >> 16) & 0xff); + //cbw.CBWCB[4] = ((addr >> 8) & 0xff); + //cbw.CBWCB[5] = (addr & 0xff); + //cbw.CBWCB[8] = blocks; + + CDB10_t cdb = CDB10_t(SCSI_CMD_READ_10, lun, blocks, addr); again: - cbw.dCBWTag = ++dCBWTag; - SetCurLUN(lun); - uint8_t er = HandleSCSIError(Transaction(&cbw, bsize, buf)); + //cbw.dCBWTag = ++dCBWTag; + //SetCurLUN(lun); + //uint8_t er = HandleSCSIError(Transaction(&cbw, bsize, buf)); + + uint8_t er = SCSITransaction10(&cdb, ((uint16_t)bsize * blocks), buf, (uint8_t)MASS_CMD_DIR_IN); + if (er == MASS_ERR_STALL) { MediaCTL(lun, 1); delay(150); @@ -177,18 +199,23 @@ uint8_t BulkOnly::Write(uint8_t lun, uint32_t addr, uint16_t bsize, uint8_t bloc D_PrintHex (bsize, 0x90); Notify(PSTR("\r\n---------\r\n"), 0x80); //MediaCTL(lun, 0x01); - CommandBlockWrapper cbw = CommandBlockWrapper(0, ((uint32_t)bsize * blocks), MASS_CMD_DIR_OUT, lun, 10, SCSI_CMD_WRITE_10); - cbw.CBWCB[1] = lun << 5; - cbw.CBWCB[2] = ((addr >> 24) & 0xff); - cbw.CBWCB[3] = ((addr >> 16) & 0xff); - cbw.CBWCB[4] = ((addr >> 8) & 0xff); - cbw.CBWCB[5] = (addr & 0xff); - cbw.CBWCB[8] = 1; + + //CommandBlockWrapper cbw = CommandBlockWrapper(0, ((uint32_t)bsize * blocks), MASS_CMD_DIR_OUT, lun, 10, SCSI_CMD_WRITE_10); + //cbw.CBWCB[1] = lun << 5; + //cbw.CBWCB[2] = ((addr >> 24) & 0xff); + //cbw.CBWCB[3] = ((addr >> 16) & 0xff); + //cbw.CBWCB[4] = ((addr >> 8) & 0xff); + //cbw.CBWCB[5] = (addr & 0xff); + //cbw.CBWCB[8] = blocks; + + CDB10_t cdb = CDB10_t(SCSI_CMD_WRITE_10, lun, blocks, addr); again: - cbw.dCBWTag = ++dCBWTag; - SetCurLUN(lun); - uint8_t er = HandleSCSIError(Transaction(&cbw, bsize, (void*)buf)); + //cbw.dCBWTag = ++dCBWTag; + //SetCurLUN(lun); + //uint8_t er = HandleSCSIError(Transaction(&cbw, bsize, (void*)buf)); + uint8_t er = SCSITransaction10(&cdb, ((uint16_t)bsize * blocks), (void*)buf, (uint8_t)MASS_CMD_DIR_OUT); + if (er == MASS_ERR_WRITE_STALL) { MediaCTL(lun, 1); delay(150); @@ -397,14 +424,51 @@ uint8_t BulkOnly::Init(uint8_t parent, uint8_t port, bool lowspeed) { delay(1000); // Delay a bit for slow firmware. - //bTheLUN = bMaxLUN; - for (uint8_t lun = 0; lun <= bMaxLUN; lun++) { InquiryResponse response; rcode = Inquiry(lun, sizeof (InquiryResponse), (uint8_t*) & response); if (rcode) { ErrorMessage (PSTR("Inquiry"), rcode); } else { +#if 0 + printf("LUN %i `", lun); + uint8_t *buf = response.VendorID; + for (int i = 0; i < 28; i++) printf("%c", buf[i]); + printf("'\r\nQualifier %1.1X ", response.PeripheralQualifier); + printf("Device type %2.2X ", response.DeviceType); + printf("RMB %1.1X ", response.Removable); + printf("SSCS %1.1X ", response.SCCS); + uint8_t sv = response.Version; + printf("SCSI version %2.2X\r\nDevice conforms to ", sv); + switch (sv) { + case 0: + printf("No specific"); + break; + /* + case 1: + printf(""); + break; + */ + case 2: + printf("ANSI 2"); + break; + case 3: + printf("ANSI INCITS 301-1997 (SPC)"); + break; + case 4: + printf("ANSI INCITS 351-2001 (SPC-2)"); + break; + case 5: + printf("ANSI INCITS 408-2005 (SPC-4)"); + break; + case 6: + printf("T10/1731-D (SPC-4)"); + break; + default: + printf("unknown"); + } + printf(" standards.\r\n"); +#endif uint8_t tries = 0xf0; while (rcode = TestUnitReady(lun)) { if (rcode == 0x08) break; // break on no media, this is OK to do. @@ -444,7 +508,6 @@ uint8_t BulkOnly::Init(uint8_t parent, uint8_t port, bool lowspeed) { if (rcode) goto FailOnInit; - USBTRACE("MS configured\r\n\r\n"); bPollEnable = true; @@ -551,15 +614,15 @@ uint8_t BulkOnly::Release() { boolean BulkOnly::CheckLUN(uint8_t lun) { uint8_t rcode; Capacity capacity; - for (uint8_t i = 0; i>>>>>>>>>>>>>>>ReadCapacity returned %i\r\n", rcode); return false; } ErrorMessage (PSTR(">>>>>>>>>>>>>>>>CAPACITY OK ON LUN"), lun); - for (uint8_t i = 0; i (capacity.data[i], 0x80); Notify(PSTR("\r\n\r\n"), 0x80); // Only 512/1024/2048/4096 are valid values! @@ -671,46 +734,6 @@ uint8_t BulkOnly::Inquiry(uint8_t lun, uint16_t bsize, uint8_t *buf) { CDB6_t cdb = CDB6_t(SCSI_CMD_INQUIRY, lun, 0LU, (uint8_t)bsize, 0); uint8_t rc = SCSITransaction6(&cdb, bsize, buf, (uint8_t)MASS_CMD_DIR_IN); -#if 0 - if (!rc) { - printf("LUN %i `", lun); - for (int i = 8; i < 36; i++) printf("%c", buf[i]); - printf("'\r\nQualifier %1.1X ", (buf[0]&0xE0) >> 5); - printf("Device type %2.2X ", buf[0]&0x1f); - printf("RMB %1.1X ", buf[1]&0x80 >> 7); - printf("SSCS% 1.1X ", buf[5]&0x80 >> 7); - uint8_t sv = buf[2]; - printf("SCSI version %2.2X\r\nDevice conforms to ", sv); - switch (sv) { - case 0: - printf("No specific"); - break; - /* - case 1: - printf(""); - break; - */ - case 2: - printf("ANSI 2"); - break; - case 3: - printf("ANSI INCITS 301-1997 (SPC)"); - break; - case 4: - printf("ANSI INCITS 351-2001 (SPC-2)"); - break; - case 5: - printf("ANSI INCITS 408-2005 (SPC-4)"); - break; - case 6: - printf("T10/1731-D (SPC-4)"); - break; - default: - printf("unknown"); - } - printf(" standards.\r\n"); - } -#endif return rc; } @@ -748,7 +771,7 @@ uint8_t BulkOnly::TestUnitReady(uint8_t lun) { * @param pbuf * @return */ -uint8_t BulkOnly::ModeSense(uint8_t lun, uint8_t pc, uint8_t page, uint8_t subpage, uint8_t len, uint8_t * pbuf) { +uint8_t BulkOnly::ModeSense6(uint8_t lun, uint8_t pc, uint8_t page, uint8_t subpage, uint8_t len, uint8_t * pbuf) { Notify(PSTR("\r\rModeSense\r\n"), 0x80); Notify(PSTR("------------\r\n"), 0x80); @@ -758,8 +781,57 @@ uint8_t BulkOnly::ModeSense(uint8_t lun, uint8_t pc, uint8_t page, uint8_t subpa //cbw.CBWCB[3] = subpage; //cbw.CBWCB[4] = len; //return HandleSCSIError(Transaction(&cbw, 512, pbuf)); - CDB6_t cdb = CDB6_t(SCSI_CMD_TEST_UNIT_READY, lun, (uint32_t)((((pc << 6) | page) << 8) | subpage) , len, 0); - return SCSITransaction6(&cdb, 512, pbuf, (uint8_t)MASS_CMD_DIR_IN); + CDB6_t cdb = CDB6_t(SCSI_CMD_TEST_UNIT_READY, lun, (uint32_t)((((pc << 6) | page) << 8) | subpage), len, 0); + return SCSITransaction6(&cdb, len, pbuf, (uint8_t)MASS_CMD_DIR_IN); +} + +/** + * For driver use only. + * + * @param lun Logical Unit Number + * @param bsize + * @param buf + * @return + */ +uint8_t BulkOnly::ReadCapacity10(uint8_t lun, uint8_t *buf) { + Notify(PSTR("\r\nReadCapacity\r\n"), 0x80); + Notify(PSTR("---------------\r\n"), 0x80); +#if 0 + CommandBlockWrapper cbw = CommandBlockWrapper(++dCBWTag, 8, MASS_CMD_DIR_IN, lun, 10, SCSI_CMD_READ_CAPACITY_10); + SetCurLUN(lun); + cbw.CBWCB[1] = lun << 5; + return HandleSCSIError(Transaction(&cbw, 8, buf)); +#else + CDB10_t cdb = CDB10_t(SCSI_CMD_READ_CAPACITY_10, lun); + return SCSITransaction10(&cdb, 8, buf, (uint8_t)MASS_CMD_DIR_IN); +#endif +} + +/** + * For driver use only. + * + * Page 3F contains write protect status. + * + * @param lun Logical Unit Number to test. + * @return Write protect switch status. + */ +uint8_t BulkOnly::Page3F(uint8_t lun) { + uint8_t buf[192]; + for (int i = 0; i < 192; i++) { + buf[i] = 0x00; + } + WriteOk[lun] = true; + uint8_t rc = ModeSense6(lun, 0, 0x3f, 0, 192, buf); + if (!rc) { + WriteOk[lun] = ((buf[2] & 0x80) == 0); + Notify(PSTR("Mode Sense: "), 0x80); + for (int i = 0; i < 4; i++) { + D_PrintHex (buf[i], 0x80); + Notify(PSTR(" "), 0x80); + } + Notify(PSTR("\r\n"), 0x80); + } + return rc; } /** @@ -786,53 +858,6 @@ uint8_t BulkOnly::RequestSense(uint8_t lun, uint16_t size, uint8_t *buf) { return Transaction(&cbw, size, buf); } -/** - * For driver use only. - * - * Page 3F contains write protect status. - * - * @param lun Logical Unit Number to test. - * @return Write protect switch status. - */ -uint8_t BulkOnly::Page3F(uint8_t lun) { - uint8_t buf[192]; - for (int i = 0; i < 192; i++) { - buf[i] = 0x00; - } - WriteOk[lun] = true; - uint8_t rc = ModeSense(lun, 0, 0x3f, 0, 192, buf); - if (!rc) { - WriteOk[lun] = ((buf[2] & 0x80) == 0); - Notify(PSTR("Mode Sense: "), 0x80); - for (int i = 0; i < 4; i++) { - D_PrintHex (buf[i], 0x80); - Notify(PSTR(" "), 0x80); - } - Notify(PSTR("\r\n"), 0x80); - } - return rc; -} - -/** - * For driver use only. - * - * @param lun Logical Unit Number - * @param bsize - * @param buf - * @return - */ -uint8_t BulkOnly::ReadCapacity(uint8_t lun, uint16_t bsize, uint8_t *buf) { - Notify(PSTR("\r\nReadCapacity\r\n"), 0x80); - Notify(PSTR("---------------\r\n"), 0x80); - CommandBlockWrapper cbw = CommandBlockWrapper(++dCBWTag, bsize, MASS_CMD_DIR_IN, lun, 10, SCSI_CMD_READ_CAPACITY_10); - - SetCurLUN(lun); - cbw.CBWCB[1] = lun << 5; - - return HandleSCSIError(Transaction(&cbw, bsize, buf)); -} - - //////////////////////////////////////////////////////////////////////////////// @@ -1035,19 +1060,19 @@ uint8_t BulkOnly::Transaction(CommandBlockWrapper *pcbw, uint16_t buf_size, void , uint8_t flags #endif ) { - uint16_t bytes = (pcbw->dCBWDataTransferLength > buf_size) ? buf_size : pcbw->dCBWDataTransferLength; - boolean write = (pcbw->bmCBWFlags & MASS_CMD_DIR_IN) != MASS_CMD_DIR_IN; + #if WANT_PARSER + uint16_t bytes = (pcbw->dCBWDataTransferLength > buf_size) ? buf_size : pcbw->dCBWDataTransferLength; + printf("Transfersize %i\r\n", bytes); delay(1000); boolean callback = (flags & MASS_TRANS_FLG_CALLBACK) == MASS_TRANS_FLG_CALLBACK; +#else + uint16_t bytes = buf_size; #endif + boolean 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. - // Not needed any longer, the constructor ensures this now - // Fix reserved bits. - //pcbw->bmReserved1 = 0; - //pcbw->bmReserved2 = 0; ErrorMessage (PSTR("CBW.dCBWTag"), pcbw->dCBWTag); while ((usberr = pUsb->outTransfer(bAddress, epInfo[epDataOutIndex].epAddr, sizeof (CommandBlockWrapper), (uint8_t*)pcbw)) == hrBUSY) delay(1); @@ -1115,7 +1140,7 @@ uint8_t BulkOnly::Transaction(CommandBlockWrapper *pcbw, uint16_t buf_size, void // 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 for quirks on Linux before reporting a bug. --xxxajk + // 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; diff --git a/masstorage.h b/masstorage.h index d0938f62..ad5169cb 100644 --- a/masstorage.h +++ b/masstorage.h @@ -196,6 +196,17 @@ struct Capacity { //uint32_t dwBlockLength; } __attribute__((packed)); +struct BASICCDB { + uint8_t Opcode; + + unsigned unused :5; + unsigned LUN : 3; + + uint8_t info[12]; +} __attribute__((packed)); + +typedef BASICCDB BASICCDB_t; + struct CDB6 { uint8_t Opcode; @@ -208,12 +219,16 @@ struct CDB6 { uint8_t Control; public: + CDB6(uint8_t _Opcode, uint8_t _LUN, uint32_t LBA, uint8_t _AllocationLength, uint8_t _Control) : - Opcode(_Opcode), LUN(_LUN), LBAMSB((LBA >>16) & 0x1f), LBAHB((LBA >> 8) & 0xff), LBALB(LBA & 0xff), - AllocationLength(_AllocationLength), Control(_Control) {} + Opcode(_Opcode), LUN(_LUN), LBAMSB((LBA >> 16) & 0x1f), LBAHB((LBA >> 8) & 0xff), LBALB(LBA & 0xff), + AllocationLength(_AllocationLength), Control(_Control) { + } + CDB6(uint8_t _Opcode, uint8_t _LUN, uint8_t _AllocationLength, uint8_t _Control) : Opcode(_Opcode), LUN(_LUN), LBAMSB(0), LBAHB(0), LBALB(0), - AllocationLength(_AllocationLength), Control(_Control) {} + AllocationLength(_AllocationLength), Control(_Control) { + } } __attribute__((packed)); typedef CDB6 CDB6_t; @@ -222,7 +237,7 @@ struct CDB10 { uint8_t Opcode; unsigned Service_Action : 5; - unsigned Misc : 3; + unsigned LUN : 3; uint8_t LBA_L_M_MB; uint8_t LBA_L_M_LB; @@ -235,8 +250,24 @@ struct CDB10 { uint8_t ALC_LB; uint8_t Control; +public: -}; + CDB10(uint8_t _Opcode, uint8_t _LUN) : + Opcode(_Opcode), Service_Action(0), LUN(_LUN), + LBA_L_M_MB(0), LBA_L_M_LB(0), LBA_L_L_MB(0), LBA_L_L_LB(0), + Misc2(0), ALC_MB(0), ALC_LB(0), Control(0) { + } +// CDB10(uint8_t _Opcode, uint8_t _LUN, uint16_t xflen) : +// Opcode(_Opcode), Service_Action(0), LUN(_LUN), +// LBA_L_M_MB(0), LBA_L_M_LB(0), LBA_L_L_MB(0), LBA_L_L_LB(0), +// Misc2(0), ALC_MB((xflen >> 8) & 0xff), ALC_LB(xflen & 0xff), Control(0) { +// } + CDB10(uint8_t _Opcode, uint8_t _LUN, uint16_t xflen, uint32_t _LBA) : + Opcode(_Opcode), Service_Action(0), LUN(_LUN), + LBA_L_M_MB((_LBA >> 24) & 0xff), LBA_L_M_LB((_LBA >> 16) & 0xff), LBA_L_L_MB((_LBA >> 8) & 0xff), LBA_L_L_LB(_LBA & 0xff), + Misc2(0), ALC_MB((xflen >> 8) & 0xff), ALC_LB(xflen & 0xff), Control(0) { + } +} __attribute__((packed)); typedef CDB10 CDB10_t; @@ -254,7 +285,7 @@ struct CDB12 { uint8_t ALC_L_MB; uint8_t ALC_L_LB; uint8_t Control; -}; +} __attribute__((packed)); typedef CDB12 CDB12_t; @@ -281,7 +312,7 @@ struct CDB_LBA32_16 { uint8_t Misc2; uint8_t Control; -}; +} __attribute__((packed)); struct CDB_LBA64_16 { uint8_t Opcode; @@ -304,7 +335,7 @@ struct CDB_LBA64_16 { uint8_t Misc2; uint8_t Control; -}; +} __attribute__((packed)); struct InquiryResponse { uint8_t DeviceType : 5; @@ -383,24 +414,33 @@ struct CommandBlockWrapper : public CommandBlockWrapperBase { uint8_t CBWCB[16]; - CommandBlockWrapper() : bmReserved1(0), bmReserved2(0) { - for(uint8_t i = 0; i < 16; i++) CBWCB[i] = 0; - } public: + // All zeroed. + CommandBlockWrapper() : + CommandBlockWrapperBase(0,0,0), bmReserved1(0), bmReserved2(0) + { + for (int i=0; i<16; i++) CBWCB[i]=0; + } - // Generic Wrap + // Generic Wrap, CDB zeroed. CommandBlockWrapper(uint32_t tag, uint32_t xflen, uint8_t flgs, uint8_t lu, uint8_t cmdlen, uint8_t cmd) : CommandBlockWrapperBase(tag, xflen, flgs), bmReserved1(0), bmReserved2(0), bmCBWLUN(lu), bmCBWCBLength(cmdlen) { - for(uint8_t i = 1; i < cmdlen; i++) CBWCB[i] = 0; - CBWCB[0] = cmd; + for (int i=0; i<16; i++) CBWCB[i]=0; + ((BASICCDB_t *)CBWCB)->LUN = cmd; } // Wrap for CDB of 6 CommandBlockWrapper(uint32_t tag, uint32_t xflen, CDB6_t *cdb, uint8_t dir) : CommandBlockWrapperBase(tag, xflen, dir), bmReserved1(0), bmReserved2(0), bmCBWLUN(cdb->LUN), bmCBWCBLength(6) { - memcpy(CBWCB, cdb, 6); + memcpy(&CBWCB, cdb, 6); + } + // Wrap for CDB of 10 + CommandBlockWrapper(uint32_t tag, uint32_t xflen, CDB10_t *cdb, uint8_t dir) : + CommandBlockWrapperBase(tag, xflen, dir), + bmReserved1(0), bmReserved2(0), bmCBWLUN(cdb->LUN), bmCBWCBLength(10) { + memcpy(&CBWCB, cdb, 10); } } __attribute__((packed)); @@ -508,17 +548,18 @@ public: } uint8_t SCSITransaction6(CDB6_t *cdb, uint16_t buf_size, void *buf, uint8_t dir); + uint8_t SCSITransaction10(CDB10_t *cdb, uint16_t buf_size, void *buf, uint8_t dir); private: uint8_t Inquiry(uint8_t lun, uint16_t size, uint8_t *buf); uint8_t TestUnitReady(uint8_t lun); uint8_t RequestSense(uint8_t lun, uint16_t size, uint8_t *buf); - uint8_t ModeSense(uint8_t lun, uint8_t pc, uint8_t page, uint8_t subpage, uint8_t len, uint8_t *buf); + uint8_t ModeSense6(uint8_t lun, uint8_t pc, uint8_t page, uint8_t subpage, uint8_t len, uint8_t *buf); uint8_t GetMaxLUN(uint8_t *max_lun); uint8_t SetCurLUN(uint8_t lun); void Reset(); uint8_t ResetRecovery(); - uint8_t ReadCapacity(uint8_t lun, uint16_t size, uint8_t *buf); + uint8_t ReadCapacity10(uint8_t lun, uint8_t *buf); void ClearAllEP(); void CheckMedia(); boolean CheckLUN(uint8_t lun);