Modules/USB MSC - Error handling and fix for Tegra2 Qemu
authorJohn Hodge <[email protected]>
Wed, 18 Dec 2013 14:15:22 +0000 (22:15 +0800)
committerJohn Hodge <[email protected]>
Wed, 18 Dec 2013 14:15:22 +0000 (22:15 +0800)
KernelLand/Modules/USB/MSC/common.h [changed mode: 0644->0755]
KernelLand/Modules/USB/MSC/main.c [changed mode: 0644->0755]
KernelLand/Modules/USB/MSC/msc_proto.h
KernelLand/Modules/USB/MSC/scsi.c [changed mode: 0644->0755]
KernelLand/Modules/USB/MSC/scsi.h [changed mode: 0644->0755]

old mode 100644 (file)
new mode 100755 (executable)
index f459080..48fa398
@@ -19,8 +19,8 @@ struct sMSCInfo
        size_t  BlockSize;
 };
 
-extern void    MSC_SendData(tUSBInterface *Dev, size_t CmdLen, const void *CmdData, size_t DataLen, const void *Data);
-extern void    MSC_RecvData(tUSBInterface *Dev, size_t CmdLen, const void *CmdData, size_t DataLen, void *Data);
+extern int     MSC_SendData(tUSBInterface *Dev, size_t CmdLen, const void *CmdData, size_t DataLen, const void *Data);
+extern int     MSC_RecvData(tUSBInterface *Dev, size_t CmdLen, const void *CmdData, size_t DataLen, void *Data);
 
 extern tLVM_VolType    gMSC_SCSI_VolType;
 extern Uint64 MSC_SCSI_GetSize(tUSBInterface *Dev, size_t *BlockSize);
old mode 100644 (file)
new mode 100755 (executable)
index 94d258a..1cc4d02
@@ -19,8 +19,8 @@ void  MSC_DeviceConnected(tUSBInterface *Dev, void *Descriptors, size_t Descripto
 void   MSC_DataIn(tUSBInterface *Dev, int EndPt, int Length, void *Data);
 // --- Internal Helpers
  int   MSC_int_CreateCBW(tMSC_CBW *Cbw, int bInput, size_t CmdLen, const void *CmdData, size_t DataLen);
-void   MSC_SendData(tUSBInterface *Dev, size_t CmdLen, const void *CmdData, size_t DataLen, const void *Data);
-void   MSC_RecvData(tUSBInterface *Dev, size_t CmdLen, const void *CmdData, size_t DataLen, void *Data);
+ int   MSC_SendData(tUSBInterface *Dev, size_t CmdLen, const void *CmdData, size_t DataLen, const void *Data);
+ int   MSC_RecvData(tUSBInterface *Dev, size_t CmdLen, const void *CmdData, size_t DataLen, void *Data);
 
 // === GLOBALS ===
 MODULE_DEFINE(0, VERSION, USB_MSC, MSC_Initialise, MSC_Cleanup, "USB_Core", NULL);
@@ -63,6 +63,10 @@ void MSC_DeviceConnected(tUSBInterface *Dev, void *Descriptors, size_t Descripto
        // SCSI Transparent Command Set
        case 0x06:
                info->BlockCount = MSC_SCSI_GetSize(Dev, &info->BlockSize);
+               // HACK! Try twice if needed
+               // Qemu Tegra2 appears to error with Sense=RESET on the first attempt
+               if( !info->BlockCount )
+                       info->BlockCount = MSC_SCSI_GetSize(Dev, &info->BlockSize);
                vt = &gMSC_SCSI_VolType;
                break;
        // Unknown, prepare to chuck sad
@@ -72,6 +76,14 @@ void MSC_DeviceConnected(tUSBInterface *Dev, void *Descriptors, size_t Descripto
                free(info);
                return ;
        }
+       
+       // Zero size indicates some form of critical error
+       if( !info->BlockCount ) {
+               Log_Error("USB MSC", "Device did not report a valid size");
+               USB_SetDeviceDataPtr(Dev, NULL);
+               free(info);
+               return ;
+       }
 
        // Create device name from Vendor ID, Device ID and Serial Number
        Uint16  vendor, devid;
@@ -124,7 +136,7 @@ int MSC_int_CreateCBW(tMSC_CBW *Cbw, int bInput, size_t CmdLen, const void *CmdD
        return 0;
 }
 
-void MSC_SendData(tUSBInterface *Dev, size_t CmdLen, const void *CmdData, size_t DataLen, const void *Data)
+int MSC_SendData(tUSBInterface *Dev, size_t CmdLen, const void *CmdData, size_t DataLen, const void *Data)
 {
        tMSC_CBW        cbw;
        tMSC_CSW        csw;
@@ -132,7 +144,7 @@ void MSC_SendData(tUSBInterface *Dev, size_t CmdLen, const void *CmdData, size_t
        const int       endpoint_in = 1;
        
        if( MSC_int_CreateCBW(&cbw, 0, CmdLen, CmdData, DataLen) )
-               return ;
+               return 2;
        
        // Send CBW
        USB_SendData(Dev, endpoint_out, sizeof(cbw), &cbw);
@@ -143,9 +155,11 @@ void MSC_SendData(tUSBInterface *Dev, size_t CmdLen, const void *CmdData, size_t
        // Read CSW
        USB_RecvData(Dev, endpoint_in, sizeof(csw), &csw);
        // TODO: Validate CSW
+
+       return (csw.bCSWStatus != 0x00);
 }
 
-void MSC_RecvData(tUSBInterface *Dev, size_t CmdLen, const void *CmdData, size_t DataLen, void *Data)
+int MSC_RecvData(tUSBInterface *Dev, size_t CmdLen, const void *CmdData, size_t DataLen, void *Data)
 {
        tMSC_CBW        cbw;
        tMSC_CSW        csw;
@@ -153,7 +167,7 @@ void MSC_RecvData(tUSBInterface *Dev, size_t CmdLen, const void *CmdData, size_t
        const int       endpoint_in = 1;
                
        if( MSC_int_CreateCBW(&cbw, 1, CmdLen, CmdData, DataLen) )
-               return ;
+               return 2;
        
        // Send CBW
        USB_SendData(Dev, endpoint_out, sizeof(cbw), &cbw);
@@ -164,6 +178,29 @@ void MSC_RecvData(tUSBInterface *Dev, size_t CmdLen, const void *CmdData, size_t
        
        // Read CSW
        USB_RecvData(Dev, endpoint_in, sizeof(csw), &csw);
+       
+       Debug_HexDump("MSC RecvData, cbw=", &cbw, sizeof(cbw));
+       Debug_HexDump("MSC RecvData, csw=", &csw, sizeof(csw));
+       Debug_HexDump("MSC RecvData, Data=", Data, DataLen);
+       
        // TODO: Validate CSW
+       if( LittleEndian32(csw.dCSWSignature) != MSC_CSW_SIGNATURE ) {
+               Log_Warning("MSC", "CSW Signature invalid %x!=exp %x",
+                       LittleEndian32(csw.dCSWSignature), MSC_CSW_SIGNATURE);
+       }
+       if( csw.dCSWTag != cbw.dCBWTag ) {
+               Log_Warning("MSC", "Recv - CSW tag (%x) doesn't match CBW tag (%x)",
+                       LittleEndian32(csw.dCSWTag), LittleEndian32(cbw.dCBWTag));
+       }
+       if( LittleEndian32(csw.dCSWDataResidue) > DataLen ) {
+               Log_Warning("MSC", "Recv - CSW residue (0x%x) is larger than DatLen (0x%x)",
+                       LittleEndian32(csw.dCSWDataResidue), DataLen);
+       }
+       if( csw.bCSWStatus != 0x00 ) {
+               Log_Warning("MWC", "Recv - CSW indicated error (Status=%02x, Residue=0x%x/0x%x)",
+                       csw.bCSWStatus, LittleEndian32(csw.dCSWDataResidue), DataLen);
+       }
+       
+       return (csw.bCSWStatus != 0x00);
 }
 
index 8cbd852..b35a587 100644 (file)
@@ -22,12 +22,14 @@ struct sMSC_CBW
        Uint8   CBWCB[16];
 } PACKED;
 
+#define MSC_CSW_SIGNATURE      0x53425355
+
 struct sMSC_CSW
 {
        Uint32  dCSWSignature;  // = 0x53425355
        Uint32  dCSWTag;
        Uint32  dCSWDataResidue;
-       Uint8   dCSWStatus;
+       Uint8   bCSWStatus;
 } PACKED;
 
 #endif
old mode 100644 (file)
new mode 100755 (executable)
index c4220d8..0fd8c12
@@ -11,6 +11,7 @@
 
 // === PROTOTYPES ===
 Uint64 MSC_SCSI_GetSize(tUSBInterface *Dev, size_t *BlockSize);
+void   MSC_SCSI_DumpSenseData(tUSBInterface *Dev);
 int    MSC_SCSI_ReadData(void *Ptr, Uint64 Block, size_t Count, void *Dest);
 int    MSC_SCSI_WriteData(void *Ptr, Uint64 Block, size_t Count, const void *Dest);
 
@@ -24,48 +25,152 @@ tLVM_VolType       gMSC_SCSI_VolType = {
 // === CODE ===
 Uint64 MSC_SCSI_GetSize(tUSBInterface *Dev, size_t *BlockSize)
 {
-       struct sSCSI_Cmd_ReadCapacity16 cmd;
-       struct sSCSI_Ret_ReadCapacity16 ret;
-       
-       cmd.Op   = 0x9E;
-       cmd.Svc  = 0x10;
-       cmd.LBA  = BigEndian64( 0 );
-       cmd.AllocationLength = BigEndian32(sizeof(ret));
-       cmd.Flags   = 0;
-       cmd.Control = 0;
+       // 1. Attempt a 10 op
+       {
+               struct sSCSI_Cmd_ReadCapacity10 cmd = {READ_CAPACITY_10,0,0,0,0,0};
+               struct sSCSI_Ret_ReadCapacity10 ret = {0,0};
+               
+               if( MSC_RecvData(Dev, sizeof(cmd), &cmd, sizeof(ret), &ret) != 0 ) {
+                       // Oops?
+                       Log_Warning("MSC SCSI", "Command \"Read Capacity (10)\" failed");
+                       MSC_SCSI_DumpSenseData(Dev);
+                       return 0;
+               }
+               
+               if( ret.LastBlock != 0xFFFFFFFF )
+               {
+                       *BlockSize = BigEndian32(ret.BlockSize);
+                       return BigEndian32(ret.LastBlock)+1;
+               }
+               
+               // Size was too large for 32-bits, attempt a 16-byte op
+       }
+
+       // 2. Attempt a 16 byte op
+       {
+               struct sSCSI_Cmd_ReadCapacity16 cmd;
+               struct sSCSI_Ret_ReadCapacity16 ret;
+               
+               cmd.Op   = SERVICE_ACTION_IN_16;
+               cmd.Svc  = 0x10;
+               cmd.LBA  = BigEndian64( 0 );
+               cmd.AllocationLength = BigEndian32(sizeof(ret));
+               cmd.Flags   = 0;
+               cmd.Control = 0;
+
+               ret.BlockSize = 0;
+               ret.LastBlock = 0;
+               if( MSC_RecvData(Dev, sizeof(cmd), &cmd, sizeof(ret), &ret) != 0 ) {
+                       // Oops?
+                       Log_Warning("MSC SCSI", "Command \"Read Capacity (16)\" failed");
+                       return 0;
+               }
+               
+               *BlockSize = BigEndian32(ret.BlockSize);
+               return BigEndian64(ret.LastBlock)+1;
+       }
+}
 
-       ret.BlockSize = 0;
-       ret.BlockCount = 0;     
-       MSC_RecvData(Dev, sizeof(cmd), &cmd, sizeof(ret), &ret);
+void MSC_SCSI_DumpSenseData(tUSBInterface *Dev)
+{
+       struct sSCSI_SenseData  ret;
+       struct sSCSI_Cmd_RequestSense cmd = {0x03, 0, 0, sizeof(ret), 0};
+       
+       int rv = MSC_RecvData(Dev, sizeof(cmd), &cmd, sizeof(ret), &ret);
+       if( rv != 0 ) {
+               // ... oh
+               Log_Warning("MSC SCSI", "Command \"Request Sense\" failed, giving up");
+               return ;
+       }
        
-       *BlockSize = BigEndian32(ret.BlockSize);
-       return BigEndian64(ret.BlockCount);
+       const char *const sense_keys[16] = {
+               "No Sense", "Recovered Error", "Not Ready", "Medium Error",
+               "Hardware Error", "Illegal Request", "Unit Attention", "Data Protect",
+               "Blank Check", "Vendor Specific", "Copy Aborted", "Aborted Command",
+               "-obs-", "Volume Overflow", "Miscompare", "-rsvd-"
+       };
+       Log_Debug("MSC SCSI", "Dumping Sense Data:");
+       Log_Debug("MSC SCSI", ".ResponseCode = %02x", ret.ResponseCode);
+       Log_Debug("MSC SCSI", ".Flags = %02x (%s%s%s%s)", ret.Flags,
+                       (ret.Flags & (1<<7) ? "FILEMARK,":""),
+                       (ret.Flags & (1<<6) ? "EOM,":""),
+                       (ret.Flags & (1<<6) ? "ILI,":""),
+                       sense_keys[ret.Flags & 15]
+                       );
+       Log_Debug("MSC SCSI", ".Information = %08x", BigEndian32(ret.Information));
+       Log_Debug("MSC SCSI", ".AdditionalLen = %02x", ret.AdditionalSenseLength);
+       Log_Debug("MSC SCSI", ".CommandSpecInfomation = %08x", BigEndian32(ret.CommandSpecInfomation));
+       Log_Debug("MSC SCSI", ".ASC  = %02x", ret.AdditionalSenseCode);
+       Log_Debug("MSC SCSI", ".ASCQ = %02x", ret.AdditionalSenseCodeQual);
 }
 
 int MSC_SCSI_ReadData(void *Ptr, Uint64 Block, size_t Count, void *Dest)
 {
        tUSBInterface   *Dev = Ptr;
        tMSCInfo        *info = USB_GetDeviceDataPtr(Dev);
-       struct sSCSI_Cmd_Read16 cmd;
-
-       // TODO: Bounds checking?
        
-       cmd.Op     = 0x88;
-       cmd.Flags  = 0;
-       cmd.LBA    = BigEndian64(Block);
-       cmd.Length = BigEndian32(Count);
-       cmd.GroupNumber = 0;
-       cmd.Control = 0;
+       // Error if more than 64 thousand blocks are read at once
+       if( Count > (1UL<<16) ) {
+               // What the fsck are you smoking?
+               Log_Error("MSC SCSI", "Attempt to read >16-bits worth of blocks");
+               return 0;
+       }
        
-       MSC_RecvData(Dev, sizeof(cmd), &cmd, Count*info->BlockSize, Dest);
-       // TODO: Error check    
+       // TODO: Bounds checking?
 
+        int    ret;
+       if( Block < (1UL << 20) && Count <= (1UL << 8) )
+       {
+               // Read (6)
+               struct sSCSI_Cmd_Read6 cmd;
+               cmd.Op       = 0x08;
+               cmd.LBATop   = Block >> 16;
+               cmd.LBALower = BigEndian16( Block & 0xFFFF );
+               cmd.Length   = Count & 0xFF;    // 0 == 256
+               cmd.Control  = 0;
+               
+               ret = MSC_RecvData(Dev, sizeof(cmd), &cmd, Count*info->BlockSize, Dest);
+       }
+       else if( Block <= 0xFFFFFFFF )
+       {
+               // Read (10)
+               struct sSCSI_Cmd_Read10 cmd;
+               cmd.Op      = 0x28;
+               cmd.Flags   = 0;
+               cmd.LBA     = BigEndian32( Block );
+               cmd.GroupNumber = 0;
+               cmd.Length  = BigEndian16( Count );     // 0 == no blocks
+               cmd.Control = 0;
+               
+               ret = MSC_RecvData(Dev, sizeof(cmd), &cmd, Count*info->BlockSize, Dest);
+       }
+       else
+       {
+               // Read (16)
+               struct sSCSI_Cmd_Read16 cmd;
+               cmd.Op     = 0x88;
+               cmd.Flags  = 0;
+               cmd.LBA    = BigEndian64(Block);
+               cmd.Length = BigEndian32(Count);
+               cmd.GroupNumber = 0;
+               cmd.Control = 0;
+               
+               ret = MSC_RecvData(Dev, sizeof(cmd), &cmd, Count*info->BlockSize, Dest);
+               // TODO: Error check
+       }
+       
+       if( ret != 0 )
+       {
+               // TODO: Get read size and find out how much was read
+               return 0;
+       }
+       
        return Count;
 }
 
 int MSC_SCSI_WriteData(void *Ptr, Uint64 Block, size_t Count, const void *Data)
 {
-       Log_Warning("MSC_SCSI", "TODO: Impliment MSC_SCSI_WriteData");
+       Log_Warning("MSC_SCSI", "TODO: Implement MSC_SCSI_WriteData");
        return 0;
 }
 
old mode 100644 (file)
new mode 100755 (executable)
index 4795989..7bd50a5
@@ -9,6 +9,44 @@
 #define _MSC__SCSI_H_
 
 // NOTE: All commands are big-endian
+enum eSCSI_Ops
+{
+       READ_CAPACITY_10 = 0x25,
+       SERVICE_ACTION_IN_16 = 0x9E
+};
+
+struct sSCSI_Cmd_RequestSense
+{
+       Uint8   Op;     // 0x03
+       Uint8   Desc;
+       Uint16  _resvd;
+       Uint8   AllocationLength;
+       Uint8   Control;
+} PACKED;
+
+struct sSCSI_SenseData
+{
+       Uint8   ResponseCode;
+       Uint8   _obselete;
+       Uint8   Flags;
+       Uint32  Information;
+       Uint8   AdditionalSenseLength;
+       Uint32  CommandSpecInfomation;
+       Uint8   AdditionalSenseCode;
+       Uint8   AdditionalSenseCodeQual;
+       Uint8   FRUC;
+       //Uint
+} PACKED;
+
+struct sSCSI_Cmd_ReadCapacity10
+{
+       Uint8   Op;     // 0x25
+       Uint8   _resvd1;
+       Uint32  LBA;
+       Uint16  _resvd2;
+       Uint8   Flags;
+       Uint8   Control;
+} PACKED;
 
 struct sSCSI_Cmd_ReadCapacity16
 {
@@ -20,14 +58,39 @@ struct sSCSI_Cmd_ReadCapacity16
        Uint8   Control;
 } PACKED;
 
+struct sSCSI_Ret_ReadCapacity10
+{
+       Uint32  LastBlock;
+       Uint32  BlockSize;
+} PACKED;
+
 struct sSCSI_Ret_ReadCapacity16
 {
-       Uint64  BlockCount;
+       Uint64  LastBlock;
        Uint32  BlockSize;
        Uint8   Flags;
        Uint8   _resvd[32-13];
 } PACKED;
 
+struct sSCSI_Cmd_Read6
+{
+       Uint8   Op;     // 0x08
+       Uint8   LBATop;
+       Uint16  LBALower;
+       Uint8   Length;
+       Uint8   Control;
+} PACKED;
+
+struct sSCSI_Cmd_Read10
+{
+       Uint8   Op;     // 0x28
+       Uint8   Flags;
+       Uint32  LBA;
+       Uint8   GroupNumber;
+       Uint16  Length;
+       Uint8   Control;
+} PACKED;
+
 struct sSCSI_Cmd_Read16
 {
        Uint8   Op;     // 0x88

UCC git Repository :: git.ucc.asn.au