2 LPCUSB, an USB device driver for LPC microcontrollers
3 Copyright (C) 2006 Bertrik Sikken (bertrik@sikken.nl)
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are met:
8 1. Redistributions of source code must retain the above copyright
9 notice, this list of conditions and the following disclaimer.
10 2. Redistributions in binary form must reproduce the above copyright
11 notice, this list of conditions and the following disclaimer in the
12 documentation and/or other materials provided with the distribution.
13 3. The name of the author may not be used to endorse or promote products
14 derived from this software without specific prior written permission.
16 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 This is the SCSI layer of the USB mass storage application example.
32 This layer depends directly on the blockdev layer.
34 Windows peculiarities:
35 * Size of REQUEST SENSE CDB is 12 bytes instead of expected 6
36 * Windows requires VERIFY(10) command to do a format.
37 This command is not mandatory in the SBC/SBC-2 specification.
42 #include <string.h> // memcpy
54 // SBC2 mandatory SCSI commands
56 #define SCSI_CMD_TEST_UNIT_READY 0x00
57 #define SCSI_CMD_REQUEST_SENSE 0x03
58 #define SCSI_CMD_FORMAT_UNIT 0x04
59 #define SCSI_CMD_READ_6 0x08 /* not implemented yet */
60 #define SCSI_CMD_INQUIRY 0x12
61 #define SCSI_CMD_SEND_DIAGNOSTIC 0x1D /* not implemented yet */
62 #define SCSI_CMD_READ_CAPACITY_10 0x25
63 #define SCSI_CMD_READ_10 0x28
64 #define SCSI_CMD_REPORT_LUNS 0xa0 /* not implemented yet */
67 // SBC2 optional SCSI commands
69 #define SCSI_CMD_WRITE_6 0x0a /* not implemented yet */
70 #define SCSI_CMD_WRITE_10 0x2a
71 #define SCSI_CMD_VERIFY_10 0x2f /* required for windows format */
76 #define WRITE_ERROR 0x030C00
77 #define READ_ERROR 0x031100
78 #define INVALID_CMD_OPCODE 0x052000
79 #define INVALID_FIELD_IN_CDB 0x052400
82 // Sense code, which is set on error conditions
83 // Hex: 00aabbcc, where aa=KEY, bb=ASC, cc=ASCQ
87 static const U8 abInquiry[] =
89 0x00, // PDT = direct-access device
90 0x80, // removeable medium bit = set
91 0x05, // version = complies to SPC3
92 0x02, // response data format = SPC3
93 0x1F, // additional length
97 'L','P','C','U','S','B',' ',' ', // vendor
98 'M','a','s','s',' ','s','t','o', // product
99 'r','a','g','e',' ',' ',' ',' ',
100 '0','.','1',' ' // revision
104 // Data for "request sense" command. The 0xFF are filled in later
106 static const U8 abSense[] = { 0x70, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x0A,
107 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
111 // Buffer for holding one block of disk data
113 static U8 abBlockBuf [512];
127 void mscscsiReset (void)
134 // Verifies a SCSI CDB and indicates the direction and amount of data
135 // that the device wants to transfer.
137 // If this call fails, a sense code is set in dwSense.
139 // IN pbCDB - Command data block
140 // iCDBLen - Command data block len
141 // OUT *piRspLen - Length of intended response data:
142 // *pfDevIn - TRUE if data is transferred from device-to-host
144 // Returns a pointer to the data exchange buffer if successful,
145 // return NULL otherwise.
147 U8 *mscscsiHandleCmd (U8 *pbCDB, U8 iCDBLen, unsigned int *piRspLen, BOOL *pfDevIn)
149 static const U8 aiCDBLen [] = {6, 10, 10, 0, 16, 12, 0, 0};
155 pCDB = (TCDB6 *) pbCDB;
157 // default direction is from device to host
161 bGroupCode = (pCDB->bOperationCode >> 5) & 0x7;
163 if (iCDBLen < aiCDBLen[bGroupCode])
165 DBG("Invalid CBD len (expected %d)!\n", aiCDBLen[bGroupCode]);
169 switch (pCDB->bOperationCode)
171 case SCSI_CMD_TEST_UNIT_READY :
172 DBG ("TEST UNIT READY\n");
176 case SCSI_CMD_REQUEST_SENSE :
177 DBG ("REQUEST SENSE (%06X)\n", dwSense);
178 *piRspLen = MIN (18, pCDB->bLength);
181 case SCSI_CMD_FORMAT_UNIT :
182 DBG ("FORMAT UNIT %02X\n", pbCDB[1]);
186 case SCSI_CMD_INQUIRY :
188 *piRspLen = MIN (36, pCDB->bLength);
191 case SCSI_CMD_READ_CAPACITY_10 :
192 DBG ("READ CAPACITY\n");
196 case SCSI_CMD_READ_10 :
197 dwLBA = (pbCDB [2] << 24) | (pbCDB [3] << 16) | (pbCDB [4] << 8) | (pbCDB [5]);
198 dwLen = (pbCDB [7] << 8) | pbCDB [8];
199 DBG ("READ10, LBA=%d, len=%d\n", dwLBA, dwLen);
200 *piRspLen = dwLen * BLOCKSIZE;
203 case SCSI_CMD_WRITE_10 :
204 dwLBA = (pbCDB [2] << 24) | (pbCDB [3] << 16) | (pbCDB [4] << 8) | (pbCDB [5]);
205 dwLen = (pbCDB [7] << 8) | pbCDB [8];
206 DBG ("WRITE10, LBA=%d, len=%d\n", dwLBA, dwLen);
207 *piRspLen = dwLen * BLOCKSIZE;
211 case SCSI_CMD_VERIFY_10 :
213 if ((pbCDB [1] & (1 << 1)) != 0)
215 DBG ("BYTCHK not supported\n");
222 DBG ("Unhandled SCSI: ");
223 for (i = 0; i < iCDBLen; i++)
224 DBG (" %02X", pbCDB[i]);
227 dwSense = INVALID_CMD_OPCODE;
237 // Handles a block of SCSI data.
239 // IN pbCDB . Command data block
240 // iCDBLen - Command data block len
241 // IN/OUT pbData - Data buffer
242 // IN dwOffset - Offset in data
244 // Returns a pointer to the next data to be exchanged if successful,
245 // returns NULL otherwise.
247 U8 *mscscsiHandleData (U8 *pbCDB, U8 iCDBLen __attribute__ ((unused)), U8 *pbData, U32 dwOffset)
251 U32 dwBufPos, dwBlockNr;
252 U32 dwDevSize, dwMaxBlock;
254 pCDB = (TCDB6 *)pbCDB;
256 switch (pCDB->bOperationCode)
258 case SCSI_CMD_TEST_UNIT_READY :
263 case SCSI_CMD_REQUEST_SENSE :
264 memcpy (pbData, abSense, 18);
265 pbData [2] = (dwSense >> 16) & 0xff;
266 pbData [12] = (dwSense >> 8) & 0xff;
267 pbData [13] = (dwSense >> 0) & 0xff;
271 case SCSI_CMD_FORMAT_UNIT :
274 case SCSI_CMD_INQUIRY :
275 memcpy (pbData, abInquiry, sizeof(abInquiry));
278 case SCSI_CMD_READ_CAPACITY_10:
279 mscblockGetSize (&dwDevSize);
280 dwMaxBlock = (dwDevSize - 1) / 512;
281 pbData [0] = (dwMaxBlock >> 24) & 0xff;
282 pbData [1] = (dwMaxBlock >> 16) & 0xff;
283 pbData [2] = (dwMaxBlock >> 8) & 0xff;
284 pbData [3] = (dwMaxBlock >> 0) & 0xff;
285 pbData [4] = (BLOCKSIZE >> 24) & 0xff;
286 pbData [5] = (BLOCKSIZE >> 16) & 0xff;
287 pbData [6] = (BLOCKSIZE >> 8) & 0xff;
288 pbData [7] = (BLOCKSIZE >> 0) & 0xff;
291 case SCSI_CMD_READ_10 :
292 dwLBA = (pbCDB [2] << 24) | (pbCDB [3] << 16) | (pbCDB [4] << 8) | (pbCDB [5]);
293 dwBufPos = (dwOffset & (BLOCKSIZE - 1));
296 dwBlockNr = dwLBA + (dwOffset / BLOCKSIZE);
298 if (mscblockRead(dwBlockNr, abBlockBuf) < 0)
300 dwSense = READ_ERROR;
301 DBG ("mscblockRead failed\n");
306 return abBlockBuf + dwBufPos ;
308 case SCSI_CMD_WRITE_10:
309 dwLBA = (pbCDB[2] << 24) | (pbCDB[3] << 16) | (pbCDB[4] << 8) | (pbCDB[5]);
311 dwBufPos = ((dwOffset + 64) & (BLOCKSIZE - 1));
314 dwBlockNr = dwLBA + (dwOffset / BLOCKSIZE);
316 if (mscblockWrite (dwBlockNr, abBlockBuf) < 0)
318 dwSense = WRITE_ERROR;
319 DBG ("mscblockWrite failed\n");
323 return abBlockBuf + dwBufPos;
325 case SCSI_CMD_VERIFY_10 :
329 dwSense = INVALID_CMD_OPCODE;