Dependencies:   ChaNFSSD mbed ChaNFS

Committer:
okini3939
Date:
Thu Nov 10 03:20:42 2011 +0000
Revision:
1:efbcfbae4747
Parent:
0:02c293160df3

        

Who changed what in which revision?

UserRevisionLine numberNew contents of line
okini3939 0:02c293160df3 1 /*
okini3939 0:02c293160df3 2 LPCUSB, an USB device driver for LPC microcontrollers
okini3939 0:02c293160df3 3 Copyright (C) 2006 Bertrik Sikken (bertrik@sikken.nl)
okini3939 0:02c293160df3 4
okini3939 0:02c293160df3 5 Redistribution and use in source and binary forms, with or without
okini3939 0:02c293160df3 6 modification, are permitted provided that the following conditions are met:
okini3939 0:02c293160df3 7
okini3939 0:02c293160df3 8 1. Redistributions of source code must retain the above copyright
okini3939 0:02c293160df3 9 notice, this list of conditions and the following disclaimer.
okini3939 0:02c293160df3 10 2. Redistributions in binary form must reproduce the above copyright
okini3939 0:02c293160df3 11 notice, this list of conditions and the following disclaimer in the
okini3939 0:02c293160df3 12 documentation and/or other materials provided with the distribution.
okini3939 0:02c293160df3 13 3. The name of the author may not be used to endorse or promote products
okini3939 0:02c293160df3 14 derived from this software without specific prior written permission.
okini3939 0:02c293160df3 15
okini3939 0:02c293160df3 16 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
okini3939 0:02c293160df3 17 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
okini3939 0:02c293160df3 18 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
okini3939 0:02c293160df3 19 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
okini3939 0:02c293160df3 20 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
okini3939 0:02c293160df3 21 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
okini3939 0:02c293160df3 22 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
okini3939 0:02c293160df3 23 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
okini3939 0:02c293160df3 24 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
okini3939 0:02c293160df3 25 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
okini3939 0:02c293160df3 26 */
okini3939 0:02c293160df3 27
okini3939 0:02c293160df3 28 /**
okini3939 0:02c293160df3 29 @file
okini3939 0:02c293160df3 30
okini3939 0:02c293160df3 31 This is the SCSI layer of the USB mass storage application example.
okini3939 0:02c293160df3 32 This layer depends directly on the blockdev layer.
okini3939 0:02c293160df3 33
okini3939 0:02c293160df3 34 Windows peculiarities:
okini3939 0:02c293160df3 35 * Size of REQUEST SENSE CDB is 12 bytes instead of expected 6
okini3939 0:02c293160df3 36 * Windows requires VERIFY(10) command to do a format.
okini3939 0:02c293160df3 37 This command is not mandatory in the SBC/SBC-2 specification.
okini3939 0:02c293160df3 38 */
okini3939 0:02c293160df3 39 /*
okini3939 0:02c293160df3 40 * Modified for mbed NXP LPC1768 & LPCXpresso board
okini3939 0:02c293160df3 41 * original LPC214x USB stack beta by bertrik
okini3939 0:02c293160df3 42 * target-20070727.tar.gr (119.5KB)
okini3939 0:02c293160df3 43 * http://sourceforge.net/projects/lpcusb/
okini3939 0:02c293160df3 44 * By Kenji Arai / JH1PJL on September 25th, 2010
okini3939 0:02c293160df3 45 * October 3rd, 2010
okini3939 0:02c293160df3 46 */
okini3939 0:02c293160df3 47 #define FATFS
okini3939 0:02c293160df3 48
okini3939 0:02c293160df3 49 //#define DEBUG
okini3939 0:02c293160df3 50 #include "dbg.h"
okini3939 0:02c293160df3 51 #include "mbed.h"
okini3939 0:02c293160df3 52 #include <string.h> // memcpy
okini3939 0:02c293160df3 53
okini3939 0:02c293160df3 54 #include "blockdev.h"
okini3939 0:02c293160df3 55 #include "msc_scsi.h"
okini3939 0:02c293160df3 56
okini3939 0:02c293160df3 57 //#include "SDFileSystem.h"
okini3939 0:02c293160df3 58 //extern SDFileSystem sd;
okini3939 0:02c293160df3 59
okini3939 0:02c293160df3 60 #define BLOCKSIZE 512
okini3939 0:02c293160df3 61
okini3939 0:02c293160df3 62 // SBC2 mandatory SCSI commands
okini3939 0:02c293160df3 63 #define SCSI_CMD_TEST_UNIT_READY 0x00
okini3939 0:02c293160df3 64 #define SCSI_CMD_REQUEST_SENSE 0x03
okini3939 0:02c293160df3 65 #define SCSI_CMD_FORMAT_UNIT 0x04
okini3939 0:02c293160df3 66 #define SCSI_CMD_READ_6 0x08 /* not implemented yet */
okini3939 0:02c293160df3 67 #define SCSI_CMD_INQUIRY 0x12
okini3939 0:02c293160df3 68 #define SCSI_CMD_SEND_DIAGNOSTIC 0x1D /* not implemented yet */
okini3939 0:02c293160df3 69 #define SCSI_CMD_READ_CAPACITY_10 0x25
okini3939 0:02c293160df3 70 #define SCSI_CMD_READ_10 0x28
okini3939 0:02c293160df3 71 #define SCSI_CMD_REPORT_LUNS 0xA0 /* not implemented yet */
okini3939 0:02c293160df3 72
okini3939 0:02c293160df3 73 // SBC2 optional SCSI commands
okini3939 0:02c293160df3 74 #define SCSI_CMD_WRITE_6 0x0A /* not implemented yet */
okini3939 0:02c293160df3 75 #define SCSI_CMD_WRITE_10 0x2A
okini3939 0:02c293160df3 76 #define SCSI_CMD_VERIFY_10 0x2F /* required for windows format */
okini3939 0:02c293160df3 77
okini3939 0:02c293160df3 78 // sense codes
okini3939 0:02c293160df3 79 #define WRITE_ERROR 0x030C00
okini3939 0:02c293160df3 80 #define READ_ERROR 0x031100
okini3939 0:02c293160df3 81 #define INVALID_CMD_OPCODE 0x052000
okini3939 0:02c293160df3 82 #define INVALID_FIELD_IN_CDB 0x052400
okini3939 0:02c293160df3 83
okini3939 0:02c293160df3 84 // Sense code, which is set on error conditions
okini3939 0:02c293160df3 85 static uint32_t dwSense; // hex: 00aabbcc, where aa=KEY, bb=ASC, cc=ASCQ
okini3939 0:02c293160df3 86
okini3939 0:02c293160df3 87 static const uint8_t abInquiry[] = {
okini3939 0:02c293160df3 88 0x00, // PDT = direct-access device
okini3939 0:02c293160df3 89 0x80, // removeable medium bit = set
okini3939 0:02c293160df3 90 0x05, // version = complies to SPC3
okini3939 0:02c293160df3 91 0x02, // response data format = SPC3
okini3939 0:02c293160df3 92 0x1F, // additional length
okini3939 0:02c293160df3 93 0x00,
okini3939 0:02c293160df3 94 0x00,
okini3939 0:02c293160df3 95 0x00,
okini3939 0:02c293160df3 96 'L','P','C','U','S','B',' ',' ', // vendor
okini3939 0:02c293160df3 97 'M','a','s','s',' ','s','t','o', // product
okini3939 0:02c293160df3 98 'r','a','g','e',' ',' ',' ',' ',
okini3939 0:02c293160df3 99 '0','.','1',' ' // revision
okini3939 0:02c293160df3 100 };
okini3939 0:02c293160df3 101
okini3939 0:02c293160df3 102 // Data for "request sense" command. The 0xFF are filled in later
okini3939 0:02c293160df3 103 static const uint8_t abSense[] = { 0x70, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x0A,
okini3939 0:02c293160df3 104 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
okini3939 0:02c293160df3 105 0x00, 0x00 };
okini3939 0:02c293160df3 106
okini3939 0:02c293160df3 107 // Buffer for holding one block of disk data
okini3939 0:02c293160df3 108 static uint8_t abBlockBuf[512];
okini3939 0:02c293160df3 109
okini3939 0:02c293160df3 110
okini3939 0:02c293160df3 111 struct TCDB6 {
okini3939 0:02c293160df3 112 uint8_t bOperationCode;
okini3939 0:02c293160df3 113 uint8_t abLBA[3];
okini3939 0:02c293160df3 114 uint8_t bLength;
okini3939 0:02c293160df3 115 uint8_t bControl;
okini3939 0:02c293160df3 116 } __attribute__((packed));
okini3939 0:02c293160df3 117
okini3939 0:02c293160df3 118
okini3939 0:02c293160df3 119 /*************************************************************************
okini3939 0:02c293160df3 120 SCSIReset
okini3939 0:02c293160df3 121 =========
okini3939 0:02c293160df3 122 Resets any SCSI state
okini3939 0:02c293160df3 123
okini3939 0:02c293160df3 124 **************************************************************************/
okini3939 0:02c293160df3 125 void SCSIReset(void)
okini3939 0:02c293160df3 126 {
okini3939 0:02c293160df3 127 dwSense = 0;
okini3939 0:02c293160df3 128 }
okini3939 0:02c293160df3 129
okini3939 0:02c293160df3 130
okini3939 0:02c293160df3 131 /*************************************************************************
okini3939 0:02c293160df3 132 SCSIHandleCmd
okini3939 0:02c293160df3 133 =============
okini3939 0:02c293160df3 134 Verifies a SCSI CDB and indicates the direction and amount of data
okini3939 0:02c293160df3 135 that the device wants to transfer.
okini3939 0:02c293160df3 136
okini3939 0:02c293160df3 137 If this call fails, a sense code is set in dwSense.
okini3939 0:02c293160df3 138
okini3939 0:02c293160df3 139 IN pbCDB Command data block
okini3939 0:02c293160df3 140 iCDBLen Command data block len
okini3939 0:02c293160df3 141 OUT *piRspLen Length of intended response data:
okini3939 0:02c293160df3 142 *pfDevIn true if data is transferred from device-to-host
okini3939 0:02c293160df3 143
okini3939 0:02c293160df3 144 Returns a pointer to the data exchange buffer if successful,
okini3939 0:02c293160df3 145 return NULL otherwise.
okini3939 0:02c293160df3 146 **************************************************************************/
okini3939 0:02c293160df3 147 uint8_t * SCSIHandleCmd(uint8_t *pbCDB, uint8_t iCDBLen, int *piRspLen, bool *pfDevIn)
okini3939 0:02c293160df3 148 {
okini3939 0:02c293160df3 149 static const uint8_t aiCDBLen[] = {6, 10, 10, 0, 16, 12, 0, 0};
okini3939 0:02c293160df3 150 int i;
okini3939 0:02c293160df3 151 TCDB6 *pCDB;
okini3939 0:02c293160df3 152 uint32_t dwLen, dwLBA;
okini3939 0:02c293160df3 153 uint8_t bGroupCode;
okini3939 0:02c293160df3 154
okini3939 0:02c293160df3 155 pCDB = (TCDB6 *)pbCDB;
okini3939 0:02c293160df3 156
okini3939 0:02c293160df3 157 // default direction is from device to host
okini3939 0:02c293160df3 158 *pfDevIn = true;
okini3939 0:02c293160df3 159
okini3939 0:02c293160df3 160 // check CDB length
okini3939 0:02c293160df3 161 bGroupCode = (pCDB->bOperationCode >> 5) & 0x7;
okini3939 0:02c293160df3 162 if (iCDBLen < aiCDBLen[bGroupCode]) {
okini3939 0:02c293160df3 163 DBG("Invalid CBD len (expected %d)!\n", aiCDBLen[bGroupCode]);
okini3939 0:02c293160df3 164 return NULL;
okini3939 0:02c293160df3 165 }
okini3939 0:02c293160df3 166
okini3939 0:02c293160df3 167 switch (pCDB->bOperationCode) {
okini3939 0:02c293160df3 168
okini3939 0:02c293160df3 169 // test unit ready (6)
okini3939 0:02c293160df3 170 case SCSI_CMD_TEST_UNIT_READY:
okini3939 0:02c293160df3 171 DBG("TEST UNIT READY\n");
okini3939 0:02c293160df3 172 *piRspLen = 0;
okini3939 0:02c293160df3 173 break;
okini3939 0:02c293160df3 174
okini3939 0:02c293160df3 175 // request sense (6)
okini3939 0:02c293160df3 176 case SCSI_CMD_REQUEST_SENSE:
okini3939 0:02c293160df3 177 DBG("REQUEST SENSE (%06X)\n", dwSense);
okini3939 0:02c293160df3 178 // check params
okini3939 0:02c293160df3 179 *piRspLen = MIN(18, pCDB->bLength);
okini3939 0:02c293160df3 180 break;
okini3939 0:02c293160df3 181
okini3939 0:02c293160df3 182 case SCSI_CMD_FORMAT_UNIT:
okini3939 0:02c293160df3 183 DBG("FORMAT UNIT %02X\n", pbCDB[1]);
okini3939 0:02c293160df3 184 *piRspLen = 0;
okini3939 0:02c293160df3 185 break;
okini3939 0:02c293160df3 186
okini3939 0:02c293160df3 187 // inquiry (6)
okini3939 0:02c293160df3 188 case SCSI_CMD_INQUIRY:
okini3939 0:02c293160df3 189 DBG("INQUIRY\n");
okini3939 0:02c293160df3 190 // see SPC3r23, 4.3.4.6
okini3939 0:02c293160df3 191 *piRspLen = MIN(36, pCDB->bLength);
okini3939 0:02c293160df3 192 break;
okini3939 0:02c293160df3 193
okini3939 0:02c293160df3 194 // read capacity (10)
okini3939 0:02c293160df3 195 case SCSI_CMD_READ_CAPACITY_10:
okini3939 0:02c293160df3 196 DBG("READ CAPACITY\n");
okini3939 0:02c293160df3 197 *piRspLen = 8;
okini3939 0:02c293160df3 198 break;
okini3939 0:02c293160df3 199
okini3939 0:02c293160df3 200 // read (10)
okini3939 0:02c293160df3 201 case SCSI_CMD_READ_10:
okini3939 0:02c293160df3 202 dwLBA = (pbCDB[2] << 24) | (pbCDB[3] << 16) | (pbCDB[4] << 8) | (pbCDB[5]);
okini3939 0:02c293160df3 203 dwLen = (pbCDB[7] << 8) | pbCDB[8];
okini3939 0:02c293160df3 204 DBG("READ10, LBA=%d, len=%d\n", dwLBA, dwLen);
okini3939 0:02c293160df3 205 *piRspLen = dwLen * BLOCKSIZE;
okini3939 0:02c293160df3 206 break;
okini3939 0:02c293160df3 207
okini3939 0:02c293160df3 208 // write (10)
okini3939 0:02c293160df3 209 case SCSI_CMD_WRITE_10:
okini3939 0:02c293160df3 210 dwLBA = (pbCDB[2] << 24) | (pbCDB[3] << 16) | (pbCDB[4] << 8) | (pbCDB[5]);
okini3939 0:02c293160df3 211 dwLen = (pbCDB[7] << 8) | pbCDB[8];
okini3939 0:02c293160df3 212 DBG("WRITE10, LBA=%d, len=%d\n", dwLBA, dwLen);
okini3939 0:02c293160df3 213 *piRspLen = dwLen * BLOCKSIZE;
okini3939 0:02c293160df3 214 *pfDevIn = false;
okini3939 0:02c293160df3 215 break;
okini3939 0:02c293160df3 216
okini3939 0:02c293160df3 217 case SCSI_CMD_VERIFY_10:
okini3939 0:02c293160df3 218 DBG("VERIFY10\n");
okini3939 0:02c293160df3 219 if ((pbCDB[1] & (1 << 1)) != 0) {
okini3939 0:02c293160df3 220 // we don't support BYTCHK
okini3939 0:02c293160df3 221 DBG("BYTCHK not supported\n");
okini3939 0:02c293160df3 222 return NULL;
okini3939 0:02c293160df3 223 }
okini3939 0:02c293160df3 224 *piRspLen = 0;
okini3939 0:02c293160df3 225 break;
okini3939 0:02c293160df3 226
okini3939 0:02c293160df3 227 default:
okini3939 0:02c293160df3 228 DBG("Unhandled SCSI: ");
okini3939 0:02c293160df3 229 for (i = 0; i < iCDBLen; i++) {
okini3939 0:02c293160df3 230 DBG(" %02X", pbCDB[i]);
okini3939 0:02c293160df3 231 }
okini3939 0:02c293160df3 232 DBG("\n");
okini3939 0:02c293160df3 233 // unsupported command
okini3939 0:02c293160df3 234 dwSense = INVALID_CMD_OPCODE;
okini3939 0:02c293160df3 235 *piRspLen = 0;
okini3939 0:02c293160df3 236 return NULL;
okini3939 0:02c293160df3 237 }
okini3939 0:02c293160df3 238
okini3939 0:02c293160df3 239
okini3939 0:02c293160df3 240 return abBlockBuf;
okini3939 0:02c293160df3 241 }
okini3939 0:02c293160df3 242
okini3939 0:02c293160df3 243
okini3939 0:02c293160df3 244 /*************************************************************************
okini3939 0:02c293160df3 245 SCSIHandleData
okini3939 0:02c293160df3 246 ==============
okini3939 0:02c293160df3 247 Handles a block of SCSI data.
okini3939 0:02c293160df3 248
okini3939 0:02c293160df3 249 IN pbCDB Command data block
okini3939 0:02c293160df3 250 iCDBLen Command data block len
okini3939 0:02c293160df3 251 IN/OUT pbData Data buffer
okini3939 0:02c293160df3 252 IN dwOffset Offset in data
okini3939 0:02c293160df3 253
okini3939 0:02c293160df3 254 Returns a pointer to the next data to be exchanged if successful,
okini3939 0:02c293160df3 255 returns NULL otherwise.
okini3939 0:02c293160df3 256 **************************************************************************/
okini3939 0:02c293160df3 257 uint8_t * SCSIHandleData(uint8_t *pbCDB, uint8_t iCDBLen, uint8_t *pbData, uint32_t dwOffset)
okini3939 0:02c293160df3 258 {
okini3939 0:02c293160df3 259 TCDB6 *pCDB;
okini3939 0:02c293160df3 260 uint32_t dwLBA;
okini3939 0:02c293160df3 261 uint32_t dwBufPos, dwBlockNr;
okini3939 0:02c293160df3 262 uint32_t dwDevSize, dwMaxBlock;
okini3939 0:02c293160df3 263
okini3939 0:02c293160df3 264 pCDB = (TCDB6 *)pbCDB;
okini3939 0:02c293160df3 265
okini3939 0:02c293160df3 266 switch (pCDB->bOperationCode) {
okini3939 0:02c293160df3 267
okini3939 0:02c293160df3 268 // test unit ready
okini3939 0:02c293160df3 269 case SCSI_CMD_TEST_UNIT_READY:
okini3939 0:02c293160df3 270 if (dwSense != 0) {
okini3939 0:02c293160df3 271 return NULL;
okini3939 0:02c293160df3 272 }
okini3939 0:02c293160df3 273 break;
okini3939 0:02c293160df3 274
okini3939 0:02c293160df3 275 // request sense
okini3939 0:02c293160df3 276 case SCSI_CMD_REQUEST_SENSE:
okini3939 0:02c293160df3 277 memcpy(pbData, abSense, 18);
okini3939 0:02c293160df3 278 // fill in KEY/ASC/ASCQ
okini3939 0:02c293160df3 279 pbData[2] = (dwSense >> 16) & 0xFF;
okini3939 0:02c293160df3 280 pbData[12] = (dwSense >> 8) & 0xFF;
okini3939 0:02c293160df3 281 pbData[13] = (dwSense >> 0) & 0xFF;
okini3939 0:02c293160df3 282 // reset sense data
okini3939 0:02c293160df3 283 dwSense = 0;
okini3939 0:02c293160df3 284 break;
okini3939 0:02c293160df3 285
okini3939 0:02c293160df3 286 case SCSI_CMD_FORMAT_UNIT:
okini3939 0:02c293160df3 287 // nothing to do, ignore this command
okini3939 0:02c293160df3 288 break;
okini3939 0:02c293160df3 289
okini3939 0:02c293160df3 290 // inquiry
okini3939 0:02c293160df3 291 case SCSI_CMD_INQUIRY:
okini3939 0:02c293160df3 292 memcpy(pbData, abInquiry, sizeof(abInquiry));
okini3939 0:02c293160df3 293 break;
okini3939 0:02c293160df3 294
okini3939 0:02c293160df3 295 // read capacity
okini3939 0:02c293160df3 296 case SCSI_CMD_READ_CAPACITY_10:
okini3939 0:02c293160df3 297 #ifdef FATFS
okini3939 0:02c293160df3 298 // get size of drive (bytes)
okini3939 0:02c293160df3 299 dwDevSize = BlockDevGetSize();
okini3939 0:02c293160df3 300 // dwDevSize = sd.disk_sectors() * 512;
okini3939 0:02c293160df3 301 #else
okini3939 0:02c293160df3 302 // get size of drive (bytes)
okini3939 0:02c293160df3 303 BlockDevGetSize(&dwDevSize);
okini3939 0:02c293160df3 304 #endif
okini3939 0:02c293160df3 305 // calculate highest LBA
okini3939 0:02c293160df3 306 dwMaxBlock = (dwDevSize - 1) / 512;
okini3939 0:02c293160df3 307
okini3939 0:02c293160df3 308 pbData[0] = (dwMaxBlock >> 24) & 0xFF;
okini3939 0:02c293160df3 309 pbData[1] = (dwMaxBlock >> 16) & 0xFF;
okini3939 0:02c293160df3 310 pbData[2] = (dwMaxBlock >> 8) & 0xFF;
okini3939 0:02c293160df3 311 pbData[3] = (dwMaxBlock >> 0) & 0xFF;
okini3939 0:02c293160df3 312 pbData[4] = (BLOCKSIZE >> 24) & 0xFF;
okini3939 0:02c293160df3 313 pbData[5] = (BLOCKSIZE >> 16) & 0xFF;
okini3939 0:02c293160df3 314 pbData[6] = (BLOCKSIZE >> 8) & 0xFF;
okini3939 0:02c293160df3 315 pbData[7] = (BLOCKSIZE >> 0) & 0xFF;
okini3939 0:02c293160df3 316 break;
okini3939 0:02c293160df3 317
okini3939 0:02c293160df3 318 // read10
okini3939 0:02c293160df3 319 case SCSI_CMD_READ_10:
okini3939 0:02c293160df3 320 dwLBA = (pbCDB[2] << 24) | (pbCDB[3] << 16) | (pbCDB[4] << 8) | (pbCDB[5]);
okini3939 0:02c293160df3 321
okini3939 0:02c293160df3 322 // copy data from block buffer
okini3939 0:02c293160df3 323 dwBufPos = (dwOffset & (BLOCKSIZE - 1));
okini3939 0:02c293160df3 324 if (dwBufPos == 0) {
okini3939 0:02c293160df3 325 // read new block
okini3939 0:02c293160df3 326 dwBlockNr = dwLBA + (dwOffset / BLOCKSIZE);
okini3939 0:02c293160df3 327 DBG("R");
okini3939 0:02c293160df3 328 if (BlockDevRead(dwBlockNr, abBlockBuf)) {
okini3939 0:02c293160df3 329 // if (sd.disk_read((char*)abBlockBuf, dwBlockNr)) {
okini3939 0:02c293160df3 330 dwSense = READ_ERROR;
okini3939 0:02c293160df3 331 DBG("BlockDevRead failed\n");
okini3939 0:02c293160df3 332 return NULL;
okini3939 0:02c293160df3 333 }
okini3939 0:02c293160df3 334 }
okini3939 0:02c293160df3 335 // return pointer to data
okini3939 0:02c293160df3 336 return abBlockBuf + dwBufPos;
okini3939 0:02c293160df3 337
okini3939 0:02c293160df3 338 // write10
okini3939 0:02c293160df3 339 case SCSI_CMD_WRITE_10:
okini3939 0:02c293160df3 340 dwLBA = (pbCDB[2] << 24) | (pbCDB[3] << 16) | (pbCDB[4] << 8) | (pbCDB[5]);
okini3939 0:02c293160df3 341
okini3939 0:02c293160df3 342 // copy data to block buffer
okini3939 0:02c293160df3 343 dwBufPos = ((dwOffset + 64) & (BLOCKSIZE - 1));
okini3939 0:02c293160df3 344 if (dwBufPos == 0) {
okini3939 0:02c293160df3 345 // write new block
okini3939 0:02c293160df3 346 dwBlockNr = dwLBA + (dwOffset / BLOCKSIZE);
okini3939 0:02c293160df3 347 DBG("W");
okini3939 0:02c293160df3 348 if (BlockDevWrite(dwBlockNr, abBlockBuf)) {
okini3939 0:02c293160df3 349 // if (sd.disk_write((char*)abBlockBuf, dwBlockNr)) {
okini3939 0:02c293160df3 350 dwSense = WRITE_ERROR;
okini3939 0:02c293160df3 351 DBG("BlockDevWrite failed\n");
okini3939 0:02c293160df3 352 return NULL;
okini3939 0:02c293160df3 353 }
okini3939 0:02c293160df3 354 }
okini3939 0:02c293160df3 355 // return pointer to next data
okini3939 0:02c293160df3 356 return abBlockBuf + dwBufPos;
okini3939 0:02c293160df3 357
okini3939 0:02c293160df3 358 case SCSI_CMD_VERIFY_10:
okini3939 0:02c293160df3 359 // dummy implementation
okini3939 0:02c293160df3 360 break;
okini3939 0:02c293160df3 361
okini3939 0:02c293160df3 362 default:
okini3939 0:02c293160df3 363 // unsupported command
okini3939 0:02c293160df3 364 dwSense = INVALID_CMD_OPCODE;
okini3939 0:02c293160df3 365 return NULL;
okini3939 0:02c293160df3 366 }
okini3939 0:02c293160df3 367
okini3939 0:02c293160df3 368 // default: return pointer to start of block buffer
okini3939 0:02c293160df3 369 return abBlockBuf;
okini3939 0:02c293160df3 370 }