Usermode/libc - Fix strchr and strrchr behavior
[tpg/acess2.git] / KernelLand / Modules / USB / MSC / scsi.c
1 /*
2  * Acess2 USB Stack Mass Storage Driver
3  * - By John Hodge (thePowersGang)
4  *
5  * scsi.c
6  * - "SCSI Transparent Command Set" handling code
7  */
8 #define DEBUG   0
9 #include "common.h"
10 #include "scsi.h"
11
12 // === PROTOTYPES ===
13 Uint64  MSC_SCSI_GetSize(tUSBInterface *Dev, size_t *BlockSize);
14 void    MSC_SCSI_DumpSenseData(tUSBInterface *Dev);
15 int     MSC_SCSI_ReadData(void *Ptr, Uint64 Block, size_t Count, void *Dest);
16 int     MSC_SCSI_WriteData(void *Ptr, Uint64 Block, size_t Count, const void *Dest);
17
18 // === GLOBALS ===
19 tLVM_VolType    gMSC_SCSI_VolType = {
20         .Name = "USB-MSC-SCSI",
21         .Read = MSC_SCSI_ReadData,
22         .Write = MSC_SCSI_WriteData
23         };
24
25 // === CODE ===
26 Uint64 MSC_SCSI_GetSize(tUSBInterface *Dev, size_t *BlockSize)
27 {
28         // 1. Attempt a 10 op
29         {
30                 struct sSCSI_Cmd_ReadCapacity10 cmd = {READ_CAPACITY_10,0,0,0,0,0};
31                 struct sSCSI_Ret_ReadCapacity10 ret = {0,0};
32                 
33                 if( MSC_RecvData(Dev, sizeof(cmd), &cmd, sizeof(ret), &ret) != 0 ) {
34                         // Oops?
35                         Log_Warning("MSC SCSI", "Command \"Read Capacity (10)\" failed");
36                         MSC_SCSI_DumpSenseData(Dev);
37                         return 0;
38                 }
39                 
40                 if( ret.LastBlock != 0xFFFFFFFF )
41                 {
42                         *BlockSize = BigEndian32(ret.BlockSize);
43                         return BigEndian32(ret.LastBlock)+1;
44                 }
45                 
46                 // Size was too large for 32-bits, attempt a 16-byte op
47         }
48
49         // 2. Attempt a 16 byte op
50         {
51                 struct sSCSI_Cmd_ReadCapacity16 cmd;
52                 struct sSCSI_Ret_ReadCapacity16 ret;
53                 
54                 cmd.Op   = SERVICE_ACTION_IN_16;
55                 cmd.Svc  = 0x10;
56                 cmd.LBA  = BigEndian64( 0 );
57                 cmd.AllocationLength = BigEndian32(sizeof(ret));
58                 cmd.Flags   = 0;
59                 cmd.Control = 0;
60
61                 ret.BlockSize = 0;
62                 ret.LastBlock = 0;
63                 if( MSC_RecvData(Dev, sizeof(cmd), &cmd, sizeof(ret), &ret) != 0 ) {
64                         // Oops?
65                         Log_Warning("MSC SCSI", "Command \"Read Capacity (16)\" failed");
66                         return 0;
67                 }
68                 
69                 *BlockSize = BigEndian32(ret.BlockSize);
70                 return BigEndian64(ret.LastBlock)+1;
71         }
72 }
73
74 void MSC_SCSI_DumpSenseData(tUSBInterface *Dev)
75 {
76         struct sSCSI_SenseData  ret;
77         struct sSCSI_Cmd_RequestSense cmd = {0x03, 0, 0, sizeof(ret), 0};
78         
79         int rv = MSC_RecvData(Dev, sizeof(cmd), &cmd, sizeof(ret), &ret);
80         if( rv != 0 ) {
81                 // ... oh
82                 Log_Warning("MSC SCSI", "Command \"Request Sense\" failed, giving up");
83                 return ;
84         }
85         
86         const char *const sense_keys[16] = {
87                 "No Sense", "Recovered Error", "Not Ready", "Medium Error",
88                 "Hardware Error", "Illegal Request", "Unit Attention", "Data Protect",
89                 "Blank Check", "Vendor Specific", "Copy Aborted", "Aborted Command",
90                 "-obs-", "Volume Overflow", "Miscompare", "-rsvd-"
91         };
92         Log_Debug("MSC SCSI", "Dumping Sense Data:");
93         Log_Debug("MSC SCSI", ".ResponseCode = %02x", ret.ResponseCode);
94         Log_Debug("MSC SCSI", ".Flags = %02x (%s%s%s%s)", ret.Flags,
95                         (ret.Flags & (1<<7) ? "FILEMARK,":""),
96                         (ret.Flags & (1<<6) ? "EOM,":""),
97                         (ret.Flags & (1<<6) ? "ILI,":""),
98                         sense_keys[ret.Flags & 15]
99                         );
100         Log_Debug("MSC SCSI", ".Information = %08x", BigEndian32(ret.Information));
101         Log_Debug("MSC SCSI", ".AdditionalLen = %02x", ret.AdditionalSenseLength);
102         Log_Debug("MSC SCSI", ".CommandSpecInfomation = %08x", BigEndian32(ret.CommandSpecInfomation));
103         Log_Debug("MSC SCSI", ".ASC  = %02x", ret.AdditionalSenseCode);
104         Log_Debug("MSC SCSI", ".ASCQ = %02x", ret.AdditionalSenseCodeQual);
105 }
106
107 int MSC_SCSI_ReadData(void *Ptr, Uint64 Block, size_t Count, void *Dest)
108 {
109         tUSBInterface   *Dev = Ptr;
110         tMSCInfo        *info = USB_GetDeviceDataPtr(Dev);
111         
112         // Error if more than 64 thousand blocks are read at once
113         if( Count > (1UL<<16) ) {
114                 // What the fsck are you smoking?
115                 Log_Error("MSC SCSI", "Attempt to read >16-bits worth of blocks");
116                 return 0;
117         }
118         
119         // TODO: Bounds checking?
120
121          int    ret;
122         if( Block < (1UL << 20) && Count <= (1UL << 8) )
123         {
124                 // Read (6)
125                 struct sSCSI_Cmd_Read6 cmd;
126                 cmd.Op       = 0x08;
127                 cmd.LBATop   = Block >> 16;
128                 cmd.LBALower = BigEndian16( Block & 0xFFFF );
129                 cmd.Length   = Count & 0xFF;    // 0 == 256
130                 cmd.Control  = 0;
131                 
132                 ret = MSC_RecvData(Dev, sizeof(cmd), &cmd, Count*info->BlockSize, Dest);
133         }
134         else if( Block <= 0xFFFFFFFF )
135         {
136                 // Read (10)
137                 struct sSCSI_Cmd_Read10 cmd;
138                 cmd.Op      = 0x28;
139                 cmd.Flags   = 0;
140                 cmd.LBA     = BigEndian32( Block );
141                 cmd.GroupNumber = 0;
142                 cmd.Length  = BigEndian16( Count );     // 0 == no blocks
143                 cmd.Control = 0;
144                 
145                 ret = MSC_RecvData(Dev, sizeof(cmd), &cmd, Count*info->BlockSize, Dest);
146         }
147         else
148         {
149                 // Read (16)
150                 struct sSCSI_Cmd_Read16 cmd;
151                 cmd.Op     = 0x88;
152                 cmd.Flags  = 0;
153                 cmd.LBA    = BigEndian64(Block);
154                 cmd.Length = BigEndian32(Count);
155                 cmd.GroupNumber = 0;
156                 cmd.Control = 0;
157                 
158                 ret = MSC_RecvData(Dev, sizeof(cmd), &cmd, Count*info->BlockSize, Dest);
159                 // TODO: Error check
160         }
161         
162         if( ret != 0 )
163         {
164                 // TODO: Get read size and find out how much was read
165                 return 0;
166         }
167         
168         return Count;
169 }
170
171 int MSC_SCSI_WriteData(void *Ptr, Uint64 Block, size_t Count, const void *Data)
172 {
173         Log_Warning("MSC_SCSI", "TODO: Implement MSC_SCSI_WriteData");
174         return 0;
175 }
176

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