00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00041 #include <string.h>
00042
00043 #include "lpcusb\target\type.h"
00044 #include "lpcusb\target\debug.h"
00045 #include "blockdev.h"
00046 #include "msc_scsi.h"
00047
00048
00049 #define BLOCKSIZE 512
00050
00051
00052 #define SCSI_CMD_TEST_UNIT_READY 0x00
00053 #define SCSI_CMD_REQUEST_SENSE 0x03
00054 #define SCSI_CMD_FORMAT_UNIT 0x04
00055 #define SCSI_CMD_READ_6 0x08
00056 #define SCSI_CMD_INQUIRY 0x12
00057 #define SCSI_CMD_SEND_DIAGNOSTIC 0x1D
00058 #define SCSI_CMD_READ_CAPACITY_10 0x25
00059 #define SCSI_CMD_READ_10 0x28
00060 #define SCSI_CMD_REPORT_LUNS 0xA0
00061
00062
00063 #define SCSI_CMD_WRITE_6 0x0A
00064 #define SCSI_CMD_WRITE_10 0x2A
00065 #define SCSI_CMD_VERIFY_10 0x2F
00066
00067
00068 #define WRITE_ERROR 0x030C00
00069 #define READ_ERROR 0x031100
00070 #define INVALID_CMD_OPCODE 0x052000
00071 #define INVALID_FIELD_IN_CDB 0x052400
00072
00073
00074 static U32 dwSense;
00075
00076 static const U8 abInquiry[] = {
00077 0x00,
00078 0x80,
00079 0x05,
00080 0x02,
00081 0x1F,
00082 0x00,
00083 0x00,
00084 0x00,
00085 'L','P','C','U','S','B',' ',' ',
00086 'M','a','s','s',' ','s','t','o',
00087 'r','a','g','e',' ',' ',' ',' ',
00088 '0','.','1',' '
00089 };
00090
00091
00092 static const U8 abSense[] = { 0x70, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x0A,
00093 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
00094 0x00, 0x00 };
00095
00096
00097 static U8 abBlockBuf[BLOCKSIZE];
00098
00099
00100 typedef struct {
00101 U8 bOperationCode;
00102 U8 abLBA[3];
00103 U8 bLength;
00104 U8 bControl;
00105 } TCDB6;
00106
00107
00108
00109
00110
00111
00112
00113
00114 void SCSIReset(void)
00115 {
00116 dwSense = 0;
00117 }
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136 U8 * SCSIHandleCmd(U8 *pbCDB, U8 iCDBLen, int *piRspLen, BOOL *pfDevIn)
00137 {
00138 static const U8 aiCDBLen[] = {6, 10, 10, 0, 16, 12, 0, 0};
00139 int i;
00140 TCDB6 *pCDB;
00141 U32 dwLen, dwLBA;
00142 U8 bGroupCode;
00143
00144 pCDB = (TCDB6 *)pbCDB;
00145
00146
00147 *pfDevIn = TRUE;
00148
00149
00150 bGroupCode = (pCDB->bOperationCode >> 5) & 0x7;
00151 if (iCDBLen < aiCDBLen[bGroupCode]) {
00152 DBG("Invalid CDB len (expected %d)!\n", aiCDBLen[bGroupCode]);
00153 return NULL;
00154 }
00155
00156 switch (pCDB->bOperationCode) {
00157
00158
00159 case SCSI_CMD_TEST_UNIT_READY:
00160 DBG("TEST UNIT READY\n");
00161 *piRspLen = 0;
00162 break;
00163
00164
00165 case SCSI_CMD_REQUEST_SENSE:
00166 DBG("REQUEST SENSE (%06X)\n", dwSense);
00167
00168 *piRspLen = MIN(18, pCDB->bLength);
00169 break;
00170
00171 case SCSI_CMD_FORMAT_UNIT:
00172 DBG("FORMAT UNIT %02X\n", pbCDB[1]);
00173 *piRspLen = 0;
00174 break;
00175
00176
00177 case SCSI_CMD_INQUIRY:
00178 DBG("INQUIRY\n");
00179
00180 *piRspLen = MIN(36, pCDB->bLength);
00181 break;
00182
00183
00184 case SCSI_CMD_READ_CAPACITY_10:
00185 DBG("READ CAPACITY\n");
00186 *piRspLen = 8;
00187 break;
00188
00189
00190 case SCSI_CMD_READ_10:
00191 dwLBA = (pbCDB[2] << 24) | (pbCDB[3] << 16) | (pbCDB[4] << 8) | (pbCDB[5]);
00192 dwLen = (pbCDB[7] << 8) | pbCDB[8];
00193 DBG("READ10, LBA=%d, len=%d\n", dwLBA, dwLen);
00194 *piRspLen = dwLen * BLOCKSIZE;
00195 break;
00196
00197
00198 case SCSI_CMD_WRITE_10:
00199 dwLBA = (pbCDB[2] << 24) | (pbCDB[3] << 16) | (pbCDB[4] << 8) | (pbCDB[5]);
00200 dwLen = (pbCDB[7] << 8) | pbCDB[8];
00201 DBG("WRITE10, LBA=%d, len=%d\n", dwLBA, dwLen);
00202 *piRspLen = dwLen * BLOCKSIZE;
00203 *pfDevIn = FALSE;
00204 break;
00205
00206 case SCSI_CMD_VERIFY_10:
00207 dwLBA = (pbCDB[2] << 24) | (pbCDB[3] << 16) | (pbCDB[4] << 8) | (pbCDB[5]);
00208 dwLen = (pbCDB[7] << 8) | pbCDB[8];
00209 DBG("VERIFY10, LBA=%d, len=%d\n", dwLBA, dwLen);
00210 *piRspLen = 0;
00211 if ((pbCDB[1] & (1 << 1)) != 0) {
00212
00213 DBG("BYTCHK not supported\n");
00214 dwSense = INVALID_FIELD_IN_CDB;
00215 return NULL;
00216 }
00217 break;
00218
00219 default:
00220 DBG("Unhandled SCSI: ");
00221 for (i = 0; i < iCDBLen; i++) {
00222 DBG(" %02X", pbCDB[i]);
00223 }
00224 DBG("\n");
00225
00226 dwSense = INVALID_CMD_OPCODE;
00227 *piRspLen = 0;
00228 return NULL;
00229 }
00230
00231 return abBlockBuf;
00232 }
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248 U8 * SCSIHandleData(U8 *pbCDB, U8 iCDBLen, U8 *pbData, U32 dwOffset)
00249 {
00250 TCDB6 *pCDB;
00251 U32 dwLBA;
00252 U32 dwBufPos, dwBlockNr;
00253 U32 dwDevSize, dwMaxBlock;
00254
00255 pCDB = (TCDB6 *)pbCDB;
00256
00257 switch (pCDB->bOperationCode) {
00258
00259
00260 case SCSI_CMD_TEST_UNIT_READY:
00261 if (dwSense != 0) {
00262 DBG("UNIT NOT READY!\n");
00263 return NULL;
00264 }
00265 break;
00266
00267
00268 case SCSI_CMD_REQUEST_SENSE:
00269 memcpy(pbData, abSense, 18);
00270
00271 pbData[2] = (dwSense >> 16) & 0xFF;
00272 pbData[12] = (dwSense >> 8) & 0xFF;
00273 pbData[13] = (dwSense >> 0) & 0xFF;
00274
00275 dwSense = 0;
00276 break;
00277
00278 case SCSI_CMD_FORMAT_UNIT:
00279
00280 break;
00281
00282
00283 case SCSI_CMD_INQUIRY:
00284 memcpy(pbData, abInquiry, sizeof(abInquiry));
00285 break;
00286
00287
00288 case SCSI_CMD_READ_CAPACITY_10:
00289
00290 BlockDevGetSize(&dwDevSize);
00291
00292 dwMaxBlock = (dwDevSize - 1) / BLOCKSIZE;
00293
00294 pbData[0] = (dwMaxBlock >> 24) & 0xFF;
00295 pbData[1] = (dwMaxBlock >> 16) & 0xFF;
00296 pbData[2] = (dwMaxBlock >> 8) & 0xFF;
00297 pbData[3] = (dwMaxBlock >> 0) & 0xFF;
00298 pbData[4] = (BLOCKSIZE >> 24) & 0xFF;
00299 pbData[5] = (BLOCKSIZE >> 16) & 0xFF;
00300 pbData[6] = (BLOCKSIZE >> 8) & 0xFF;
00301 pbData[7] = (BLOCKSIZE >> 0) & 0xFF;
00302 break;
00303
00304
00305 case SCSI_CMD_READ_10:
00306 dwLBA = (pbCDB[2] << 24) | (pbCDB[3] << 16) | (pbCDB[4] << 8) | (pbCDB[5]);
00307
00308
00309 dwBufPos = (dwOffset & (BLOCKSIZE - 1));
00310 if (dwBufPos == 0) {
00311
00312 dwBlockNr = dwLBA + (dwOffset / BLOCKSIZE);
00313 DBG("R");
00314 if (BlockDevRead(dwBlockNr, abBlockBuf) < 0) {
00315 dwSense = READ_ERROR;
00316 DBG("BlockDevRead failed\n");
00317 return NULL;
00318 }
00319 }
00320
00321 return abBlockBuf + dwBufPos;
00322
00323
00324 case SCSI_CMD_WRITE_10:
00325 dwLBA = (pbCDB[2] << 24) | (pbCDB[3] << 16) | (pbCDB[4] << 8) | (pbCDB[5]);
00326
00327
00328 dwBufPos = ((dwOffset + 64) & (BLOCKSIZE - 1));
00329 if (dwBufPos == 0) {
00330
00331 dwBlockNr = dwLBA + (dwOffset / BLOCKSIZE);
00332 DBG("W");
00333 if (BlockDevWrite(dwBlockNr, abBlockBuf) < 0) {
00334 dwSense = WRITE_ERROR;
00335 DBG("BlockDevWrite failed\n");
00336 return NULL;
00337 }
00338 }
00339
00340 return abBlockBuf + dwBufPos;
00341
00342 case SCSI_CMD_VERIFY_10:
00343
00344 break;
00345
00346 default:
00347
00348 dwSense = INVALID_CMD_OPCODE;
00349 return NULL;
00350 }
00351
00352
00353 return abBlockBuf;
00354 }
00355
00356