Convert CDB10 routines.

This commit is contained in:
Andrew J. Kroll 2013-09-21 15:38:40 -04:00
parent fee903bbac
commit 0c79e8e10f
2 changed files with 206 additions and 140 deletions

View file

@ -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<uint16_t > (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<uint16_t > (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<uint8_t > (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<sizeof (Capacity); i++) capacity.data[i] = 0;
for (uint8_t i = 0; i < 8; i++) capacity.data[i] = 0;
rcode = ReadCapacity(lun, sizeof (Capacity), (uint8_t*) & capacity);
rcode = ReadCapacity10(lun, (uint8_t*)capacity.data);
if (rcode) {
//printf(">>>>>>>>>>>>>>>>ReadCapacity returned %i\r\n", rcode);
return false;
}
ErrorMessage<uint8_t > (PSTR(">>>>>>>>>>>>>>>>CAPACITY OK ON LUN"), lun);
for (uint8_t i = 0; i<sizeof (Capacity); i++)
for (uint8_t i = 0; i < 8 /*sizeof (Capacity)*/; i++)
D_PrintHex<uint8_t > (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);
@ -759,7 +782,56 @@ uint8_t BulkOnly::ModeSense(uint8_t lun, uint8_t pc, uint8_t page, uint8_t subpa
//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);
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<uint8_t > (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<uint8_t > (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<uint32_t > (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;

View file

@ -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) {}
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);