Implement WRITE BUFFER and WRITE WITH VERIFY commands
[SCSI2SD-V6.git] / software / SCSI2SD / src / sd.c
1 //      Copyright (C) 2013 Michael McMaster <michael@codesrc.com>\r
2 //\r
3 //      This file is part of SCSI2SD.\r
4 //\r
5 //      SCSI2SD is free software: you can redistribute it and/or modify\r
6 //      it under the terms of the GNU General Public License as published by\r
7 //      the Free Software Foundation, either version 3 of the License, or\r
8 //      (at your option) any later version.\r
9 //\r
10 //      SCSI2SD is distributed in the hope that it will be useful,\r
11 //      but WITHOUT ANY WARRANTY; without even the implied warranty of\r
12 //      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
13 //      GNU General Public License for more details.\r
14 //\r
15 //      You should have received a copy of the GNU General Public License\r
16 //      along with SCSI2SD.  If not, see <http://www.gnu.org/licenses/>.\r
17 #pragma GCC push_options\r
18 #pragma GCC optimize("-flto")\r
19 \r
20 #include "device.h"\r
21 #include "scsi.h"\r
22 #include "config.h"\r
23 #include "disk.h"\r
24 #include "sd.h"\r
25 #include "led.h"\r
26 #include "time.h"\r
27 \r
28 #include "scsiPhy.h"\r
29 \r
30 #include <string.h>\r
31 \r
32 // Global\r
33 SdDevice sdDev;\r
34 \r
35 enum SD_IO_STATE { SD_DMA, SD_ACCEPTED, SD_BUSY, SD_IDLE };\r
36 static int sdIOState = SD_IDLE;\r
37 \r
38 // Private DMA variables.\r
39 static uint8 sdDMARxChan = CY_DMA_INVALID_CHANNEL;\r
40 static uint8 sdDMATxChan = CY_DMA_INVALID_CHANNEL;\r
41 \r
42 // Dummy location for DMA to send unchecked CRC bytes to\r
43 static uint8 discardBuffer;\r
44 \r
45 // 2 bytes CRC, response, 8bits to close the clock..\r
46 // "NCR" time is up to 8 bytes.\r
47 static uint8_t writeResponseBuffer[8];\r
48 \r
49 static uint8_t writeStartToken = 0xFC;\r
50 \r
51 // Source of dummy SPI bytes for DMA\r
52 static uint8 dummyBuffer = 0xFF;\r
53 \r
54 volatile uint8_t sdRxDMAComplete;\r
55 volatile uint8_t sdTxDMAComplete;\r
56 \r
57 CY_ISR_PROTO(sdRxISR);\r
58 CY_ISR(sdRxISR)\r
59 {\r
60         sdRxDMAComplete = 1;\r
61 }\r
62 CY_ISR_PROTO(sdTxISR);\r
63 CY_ISR(sdTxISR)\r
64 {\r
65         sdTxDMAComplete = 1;\r
66 }\r
67 \r
68 static uint8 sdCrc7(uint8* chr, uint8 cnt, uint8 crc)\r
69 {\r
70         uint8 a;\r
71         for(a = 0; a < cnt; a++)\r
72         {\r
73                 uint8 Data = chr[a];\r
74                 uint8 i;\r
75                 for(i = 0; i < 8; i++)\r
76                 {\r
77                         crc <<= 1;\r
78                         if( (Data & 0x80) ^ (crc & 0x80) ) {crc ^= 0x09;}\r
79                         Data <<= 1;\r
80                 }\r
81         }\r
82         return crc & 0x7F;\r
83 }\r
84 \r
85 // Read and write 1 byte.\r
86 static uint8_t sdSpiByte(uint8_t value)\r
87 {\r
88         SDCard_WriteTxData(value);\r
89         while (!(SDCard_ReadRxStatus() & SDCard_STS_RX_FIFO_NOT_EMPTY)) {}\r
90         return SDCard_ReadRxData();\r
91 }\r
92 \r
93 static uint16_t sdDoCommand(\r
94         uint8_t cmd,\r
95         uint32_t param,\r
96         int useCRC,\r
97         int use2byteResponse)\r
98 {\r
99         int waitWhileBusy = (cmd != SD_GO_IDLE_STATE) && (cmd != SD_STOP_TRANSMISSION);\r
100 \r
101         // "busy" probe. We'll examine the results later.\r
102         if (waitWhileBusy)\r
103         {\r
104                 SDCard_WriteTxData(0xFF);\r
105         }\r
106 \r
107         // send is static as the address must remain consistent for the static\r
108         // DMA descriptors to work.\r
109         static uint8_t send[7];\r
110         send[0] = cmd | 0x40;\r
111         send[1] = param >> 24;\r
112         send[2] = param >> 16;\r
113         send[3] = param >> 8;\r
114         send[4] = param;\r
115         if (unlikely(useCRC))\r
116         {\r
117                 send[5] = (sdCrc7(send, 5, 0) << 1) | 1;\r
118         }\r
119         else\r
120         {\r
121                 send[5] = 1; // stop bit\r
122         }\r
123         send[6] = 0xFF; // Result code or stuff byte.\r
124 \r
125         static uint8_t dmaRxTd = CY_DMA_INVALID_TD;\r
126         static uint8_t dmaTxTd = CY_DMA_INVALID_TD;\r
127         if (unlikely(dmaRxTd == CY_DMA_INVALID_TD))\r
128         {\r
129                 dmaRxTd = CyDmaTdAllocate();\r
130                 dmaTxTd = CyDmaTdAllocate();\r
131                 CyDmaTdSetConfiguration(dmaTxTd, sizeof(send), CY_DMA_DISABLE_TD, TD_INC_SRC_ADR|SD_TX_DMA__TD_TERMOUT_EN);\r
132                 CyDmaTdSetAddress(dmaTxTd, LO16((uint32)&send), LO16((uint32)SDCard_TXDATA_PTR));\r
133                 CyDmaTdSetConfiguration(dmaRxTd, sizeof(send), CY_DMA_DISABLE_TD, SD_RX_DMA__TD_TERMOUT_EN);\r
134                 CyDmaTdSetAddress(dmaRxTd, LO16((uint32)SDCard_RXDATA_PTR), LO16((uint32)&discardBuffer));\r
135         }\r
136 \r
137         sdTxDMAComplete = 0;\r
138         sdRxDMAComplete = 0;\r
139 \r
140         CyDmaChSetInitialTd(sdDMARxChan, dmaRxTd);\r
141         CyDmaChSetInitialTd(sdDMATxChan, dmaTxTd);\r
142 \r
143         // Some Samsung cards enter a busy-state after single-sector reads.\r
144         // But we also need to wait for R1B to complete from the multi-sector\r
145         // reads.\r
146         if (waitWhileBusy)\r
147         {\r
148                 while (!(SDCard_ReadRxStatus() & SDCard_STS_RX_FIFO_NOT_EMPTY)) {}\r
149                 int busy = SDCard_ReadRxData() != 0xFF;\r
150                 if (unlikely(busy))\r
151                 {\r
152                         while (sdSpiByte(0xFF) != 0xFF) {}\r
153                 }\r
154         }\r
155 \r
156         // The DMA controller is a bit trigger-happy. It will retain\r
157         // a drq request that was triggered while the channel was\r
158         // disabled.\r
159         CyDmaClearPendingDrq(sdDMATxChan);\r
160         CyDmaClearPendingDrq(sdDMARxChan);\r
161 \r
162         // There is no flow control, so we must ensure we can read the bytes\r
163         // before we start transmitting\r
164         CyDmaChEnable(sdDMARxChan, 1);\r
165         CyDmaChEnable(sdDMATxChan, 1);\r
166 \r
167         while (!(sdTxDMAComplete && sdRxDMAComplete)) { __WFI(); }\r
168 \r
169         uint16_t response = discardBuffer;\r
170         if (unlikely(cmd == SD_STOP_TRANSMISSION))\r
171         {\r
172                 // Stuff byte is required for this command only.\r
173                 // Part 1 Simplified standard 3.01\r
174                 // "The stop command has an execution delay due to the serial command\r
175                 // transmission."\r
176                 response = sdSpiByte(0xFF);\r
177         }\r
178 \r
179         uint32_t start = getTime_ms();\r
180         while ((response & 0x80) && likely(elapsedTime_ms(start) <= 200))\r
181         {\r
182                 response = sdSpiByte(0xFF);\r
183         }\r
184         if (unlikely(use2byteResponse))\r
185         {\r
186                 response = (response << 8) | sdSpiByte(0xFF);\r
187         }\r
188         return response;\r
189 }\r
190 \r
191 \r
192 static inline uint16_t sdCommandAndResponse(uint8_t cmd, uint32_t param)\r
193 {\r
194         return sdDoCommand(cmd, param, 0, 0);\r
195 }\r
196 \r
197 static inline uint16_t sdCRCCommandAndResponse(uint8_t cmd, uint32_t param)\r
198 {\r
199         return sdDoCommand(cmd, param, 1, 0);\r
200 }\r
201 \r
202 // Clear the sticky status bits on error.\r
203 static void sdClearStatus()\r
204 {\r
205         sdSpiByte(0xFF);\r
206         uint16_t r2 = sdDoCommand(SD_SEND_STATUS, 0, 1, 1);\r
207         (void) r2;\r
208 }\r
209 \r
210 void\r
211 sdReadMultiSectorPrep()\r
212 {\r
213         uint8 v;\r
214         uint32 scsiLBA = (transfer.lba + transfer.currentBlock);\r
215         uint32 sdLBA =\r
216                 SCSISector2SD(\r
217                         scsiDev.target->cfg->sdSectorStart,\r
218                         scsiDev.target->liveCfg.bytesPerSector,\r
219                         scsiLBA);\r
220 \r
221         if (!sdDev.ccs)\r
222         {\r
223                 sdLBA = sdLBA * SD_SECTOR_SIZE;\r
224         }\r
225         v = sdCommandAndResponse(SD_READ_MULTIPLE_BLOCK, sdLBA);\r
226         if (unlikely(v))\r
227         {\r
228                 scsiDiskReset();\r
229                 sdClearStatus();\r
230 \r
231                 scsiDev.status = CHECK_CONDITION;\r
232                 scsiDev.target->sense.code = HARDWARE_ERROR;\r
233                 scsiDev.target->sense.asc = LOGICAL_UNIT_COMMUNICATION_FAILURE;\r
234                 scsiDev.phase = STATUS;\r
235         }\r
236         else\r
237         {\r
238                 transfer.inProgress = 1;\r
239         }\r
240 }\r
241 \r
242 static void\r
243 dmaReadSector(uint8_t* outputBuffer)\r
244 {\r
245         // Wait for a start-block token.\r
246         // Don't wait more than 200ms.  The standard recommends 100ms.\r
247         uint32_t start = getTime_ms();\r
248         uint8_t token = sdSpiByte(0xFF);\r
249         while (token != 0xFE && likely(elapsedTime_ms(start) <= 200))\r
250         {\r
251                 if (unlikely(token && ((token & 0xE0) == 0)))\r
252                 {\r
253                         // Error token!\r
254                         break;\r
255                 }\r
256                 token = sdSpiByte(0xFF);\r
257         }\r
258         if (unlikely(token != 0xFE))\r
259         {\r
260                 if (transfer.multiBlock)\r
261                 {\r
262                         sdCompleteRead();\r
263                 }\r
264                 if (scsiDev.status != CHECK_CONDITION)\r
265                 {\r
266                         scsiDev.status = CHECK_CONDITION;\r
267                         scsiDev.target->sense.code = HARDWARE_ERROR;\r
268                         scsiDev.target->sense.asc = UNRECOVERED_READ_ERROR;\r
269                         scsiDev.phase = STATUS;\r
270                 }\r
271                 sdClearStatus();\r
272                 return;\r
273         }\r
274 \r
275         static uint8_t dmaRxTd[2] = { CY_DMA_INVALID_TD, CY_DMA_INVALID_TD};\r
276         static uint8_t dmaTxTd = CY_DMA_INVALID_TD;\r
277         if (unlikely(dmaRxTd[0] == CY_DMA_INVALID_TD))\r
278         {\r
279                 dmaRxTd[0] = CyDmaTdAllocate();\r
280                 dmaRxTd[1] = CyDmaTdAllocate();\r
281                 dmaTxTd = CyDmaTdAllocate();\r
282                 \r
283                 // Receive 512 bytes of data and then 2 bytes CRC.\r
284                 CyDmaTdSetConfiguration(dmaRxTd[0], SD_SECTOR_SIZE, dmaRxTd[1], TD_INC_DST_ADR);\r
285                 CyDmaTdSetConfiguration(dmaRxTd[1], 2, CY_DMA_DISABLE_TD, SD_RX_DMA__TD_TERMOUT_EN);\r
286                 CyDmaTdSetAddress(dmaRxTd[1], LO16((uint32)SDCard_RXDATA_PTR), LO16((uint32)&discardBuffer));\r
287         \r
288                 CyDmaTdSetConfiguration(dmaTxTd, SD_SECTOR_SIZE + 2, CY_DMA_DISABLE_TD, SD_TX_DMA__TD_TERMOUT_EN);\r
289                 CyDmaTdSetAddress(dmaTxTd, LO16((uint32)&dummyBuffer), LO16((uint32)SDCard_TXDATA_PTR));\r
290 \r
291         }\r
292         CyDmaTdSetAddress(dmaRxTd[0], LO16((uint32)SDCard_RXDATA_PTR), LO16((uint32)outputBuffer));\r
293 \r
294         sdIOState = SD_DMA;\r
295         sdTxDMAComplete = 0;\r
296         sdRxDMAComplete = 0;\r
297 \r
298         // Re-loading the initial TD's here is very important, or else\r
299         // we'll be re-using the last-used TD, which would be the last\r
300         // in the chain (ie. CRC TD)\r
301         CyDmaChSetInitialTd(sdDMARxChan, dmaRxTd[0]);\r
302         CyDmaChSetInitialTd(sdDMATxChan, dmaTxTd);\r
303 \r
304         // The DMA controller is a bit trigger-happy. It will retain\r
305         // a drq request that was triggered while the channel was\r
306         // disabled.\r
307         CyDmaClearPendingDrq(sdDMATxChan);\r
308         CyDmaClearPendingDrq(sdDMARxChan);\r
309 \r
310         // There is no flow control, so we must ensure we can read the bytes\r
311         // before we start transmitting\r
312         CyDmaChEnable(sdDMARxChan, 1);\r
313         CyDmaChEnable(sdDMATxChan, 1);\r
314 }\r
315 \r
316 int\r
317 sdReadSectorDMAPoll()\r
318 {\r
319         if (sdRxDMAComplete && sdTxDMAComplete)\r
320         {\r
321                 // DMA transfer is complete\r
322                 sdIOState = SD_IDLE;\r
323                 return 1;\r
324         }\r
325         else\r
326         {\r
327                 return 0;\r
328         }\r
329 }\r
330 \r
331 void sdReadSingleSectorDMA(uint32_t lba, uint8_t* outputBuffer)\r
332 {\r
333         uint8 v;\r
334         if (!sdDev.ccs)\r
335         {\r
336                 lba = lba * SD_SECTOR_SIZE;\r
337         }\r
338         v = sdCommandAndResponse(SD_READ_SINGLE_BLOCK, lba);\r
339         if (unlikely(v))\r
340         {\r
341                 scsiDiskReset();\r
342                 sdClearStatus();\r
343 \r
344                 scsiDev.status = CHECK_CONDITION;\r
345                 scsiDev.target->sense.code = HARDWARE_ERROR;\r
346                 scsiDev.target->sense.asc = LOGICAL_UNIT_COMMUNICATION_FAILURE;\r
347                 scsiDev.phase = STATUS;\r
348         }\r
349         else\r
350         {\r
351                 dmaReadSector(outputBuffer);\r
352         }\r
353 }\r
354 \r
355 void\r
356 sdReadMultiSectorDMA(uint8_t* outputBuffer)\r
357 {\r
358         // Pre: sdReadMultiSectorPrep called.\r
359         dmaReadSector(outputBuffer);\r
360 }\r
361 \r
362 \r
363 void sdCompleteRead()\r
364 {\r
365         if (unlikely(sdIOState != SD_IDLE))\r
366         {\r
367                 // Not much choice but to wait until we've completed the transfer.\r
368                 // Cancelling the transfer can't be done as we have no way to reset\r
369                 // the SD card.\r
370                 while (!sdReadSectorDMAPoll()) { /* spin */ }\r
371         }\r
372         \r
373         if (transfer.inProgress)\r
374         {\r
375                 transfer.inProgress = 0;\r
376                 uint8 r1b = sdCommandAndResponse(SD_STOP_TRANSMISSION, 0);\r
377 \r
378                 if (unlikely(r1b))\r
379                 {\r
380                         scsiDev.status = CHECK_CONDITION;\r
381                         scsiDev.target->sense.code = HARDWARE_ERROR;\r
382                         scsiDev.target->sense.asc = UNRECOVERED_READ_ERROR;\r
383                         scsiDev.phase = STATUS;\r
384                 }\r
385         }\r
386 \r
387         // R1b has an optional trailing "busy" signal, but we defer waiting on this.\r
388         // The next call so sdCommandAndResponse will wait for the busy state to\r
389         // clear.\r
390 }\r
391 \r
392 static void sdWaitWriteBusy()\r
393 {\r
394         uint8 val;\r
395         do\r
396         {\r
397                 val = sdSpiByte(0xFF);\r
398         } while (val != 0xFF);\r
399 }\r
400 \r
401 void\r
402 sdWriteMultiSectorDMA(uint8_t* outputBuffer)\r
403 {\r
404         static uint8_t dmaRxTd[2] = { CY_DMA_INVALID_TD, CY_DMA_INVALID_TD};\r
405         static uint8_t dmaTxTd[3] = { CY_DMA_INVALID_TD, CY_DMA_INVALID_TD, CY_DMA_INVALID_TD};\r
406         if (unlikely(dmaRxTd[0] == CY_DMA_INVALID_TD))\r
407         {\r
408                 dmaRxTd[0] = CyDmaTdAllocate();\r
409                 dmaRxTd[1] = CyDmaTdAllocate();\r
410                 dmaTxTd[0] = CyDmaTdAllocate();\r
411                 dmaTxTd[1] = CyDmaTdAllocate();\r
412                 dmaTxTd[2] = CyDmaTdAllocate();\r
413                 \r
414                 // Transmit 512 bytes of data and then 2 bytes CRC, and then get the response byte\r
415                 // We need to do this without stopping the clock\r
416                 CyDmaTdSetConfiguration(dmaTxTd[0], 1, dmaTxTd[1], TD_INC_SRC_ADR);\r
417                 CyDmaTdSetAddress(dmaTxTd[0], LO16((uint32)&writeStartToken), LO16((uint32)SDCard_TXDATA_PTR));\r
418 \r
419                 CyDmaTdSetConfiguration(dmaTxTd[1], SD_SECTOR_SIZE, dmaTxTd[2], TD_INC_SRC_ADR);\r
420 \r
421                 CyDmaTdSetConfiguration(dmaTxTd[2], 2 + sizeof(writeResponseBuffer), CY_DMA_DISABLE_TD, SD_TX_DMA__TD_TERMOUT_EN);\r
422                 CyDmaTdSetAddress(dmaTxTd[2], LO16((uint32)&dummyBuffer), LO16((uint32)SDCard_TXDATA_PTR));\r
423 \r
424                 CyDmaTdSetConfiguration(dmaRxTd[0], SD_SECTOR_SIZE + 3, dmaRxTd[1], 0);\r
425                 CyDmaTdSetAddress(dmaRxTd[0], LO16((uint32)SDCard_RXDATA_PTR), LO16((uint32)&discardBuffer));\r
426                 CyDmaTdSetConfiguration(dmaRxTd[1], sizeof(writeResponseBuffer), CY_DMA_DISABLE_TD, SD_RX_DMA__TD_TERMOUT_EN|TD_INC_DST_ADR);\r
427                 CyDmaTdSetAddress(dmaRxTd[1], LO16((uint32)SDCard_RXDATA_PTR), LO16((uint32)&writeResponseBuffer));\r
428         }\r
429         CyDmaTdSetAddress(dmaTxTd[1], LO16((uint32)outputBuffer), LO16((uint32)SDCard_TXDATA_PTR));\r
430 \r
431 \r
432         sdIOState = SD_DMA;\r
433         // The DMA controller is a bit trigger-happy. It will retain\r
434         // a drq request that was triggered while the channel was\r
435         // disabled.\r
436         CyDmaClearPendingDrq(sdDMATxChan);\r
437         CyDmaClearPendingDrq(sdDMARxChan);\r
438 \r
439         sdTxDMAComplete = 0;\r
440         sdRxDMAComplete = 0;\r
441 \r
442         // Re-loading the initial TD's here is very important, or else\r
443         // we'll be re-using the last-used TD, which would be the last\r
444         // in the chain (ie. CRC TD)\r
445         CyDmaChSetInitialTd(sdDMARxChan, dmaRxTd[0]);\r
446         CyDmaChSetInitialTd(sdDMATxChan, dmaTxTd[0]);\r
447 \r
448         // There is no flow control, so we must ensure we can read the bytes\r
449         // before we start transmitting\r
450         CyDmaChEnable(sdDMARxChan, 1);\r
451         CyDmaChEnable(sdDMATxChan, 1);\r
452 }\r
453 \r
454 int\r
455 sdWriteSectorDMAPoll(int sendStopToken)\r
456 {\r
457         if (sdRxDMAComplete && sdTxDMAComplete)\r
458         {\r
459                 if (sdIOState == SD_DMA)\r
460                 {\r
461                         // Retry a few times. The data token format is:\r
462                         // XXX0AAA1\r
463                         int i = 0;\r
464                         uint8_t dataToken;\r
465                         do\r
466                         {\r
467                                 dataToken = writeResponseBuffer[i]; // Response\r
468                                 ++i;\r
469                         } while (((dataToken & 0x0101) != 1) && (i < sizeof(writeResponseBuffer)));\r
470 \r
471                         // At this point we should either have an accepted token, or we'll\r
472                         // timeout and proceed into the error case below.\r
473                         if (unlikely(((dataToken & 0x1F) >> 1) != 0x2)) // Accepted.\r
474                         {\r
475                                 sdIOState = SD_IDLE;\r
476 \r
477                                 sdWaitWriteBusy();\r
478                                 sdSpiByte(0xFD); // STOP TOKEN\r
479                                 sdWaitWriteBusy();\r
480 \r
481                                 transfer.inProgress = 0;\r
482                                 scsiDiskReset();\r
483                                 sdClearStatus();\r
484 \r
485                                 scsiDev.status = CHECK_CONDITION;\r
486                                 scsiDev.target->sense.code = HARDWARE_ERROR;\r
487                                 scsiDev.target->sense.asc = LOGICAL_UNIT_COMMUNICATION_FAILURE;\r
488                                 scsiDev.phase = STATUS;\r
489                         }\r
490                         else\r
491                         {\r
492                                 sdIOState = SD_ACCEPTED;\r
493                         }\r
494                 }\r
495 \r
496                 if (sdIOState == SD_ACCEPTED)\r
497                 {\r
498                         // Wait while the SD card is busy\r
499                         if (sdSpiByte(0xFF) == 0xFF)\r
500                         {\r
501                                 if (sendStopToken)\r
502                                 {\r
503                                         sdIOState = SD_BUSY;\r
504                                         transfer.inProgress = 0;\r
505 \r
506                                         sdSpiByte(0xFD); // STOP TOKEN\r
507                                 }\r
508                                 else\r
509                                 {\r
510                                         sdIOState = SD_IDLE;\r
511                                 }\r
512                         }\r
513                 }\r
514 \r
515                 if (sdIOState == SD_BUSY)\r
516                 {\r
517                         // Wait while the SD card is busy\r
518                         if (sdSpiByte(0xFF) == 0xFF)\r
519                         {\r
520                                 sdIOState = SD_IDLE;\r
521                         }\r
522                 }\r
523 \r
524                 return sdIOState == SD_IDLE;\r
525         }\r
526         else\r
527         {\r
528                 return 0;\r
529         }\r
530 }\r
531 \r
532 void sdCompleteWrite()\r
533 {\r
534         if (unlikely(sdIOState != SD_IDLE))\r
535         {\r
536                 // Not much choice but to wait until we've completed the transfer.\r
537                 // Cancelling the transfer can't be done as we have no way to reset\r
538                 // the SD card.\r
539                 while (!sdWriteSectorDMAPoll(1)) { /* spin */ }\r
540         }\r
541 \r
542         if (transfer.inProgress && likely(scsiDev.phase == DATA_OUT))\r
543         {\r
544                 uint16_t r2 = sdDoCommand(SD_SEND_STATUS, 0, 0, 1);\r
545                 if (unlikely(r2))\r
546                 {\r
547                         sdClearStatus();\r
548                         scsiDev.status = CHECK_CONDITION;\r
549                         scsiDev.target->sense.code = HARDWARE_ERROR;\r
550                         scsiDev.target->sense.asc = WRITE_ERROR_AUTO_REALLOCATION_FAILED;\r
551                         scsiDev.phase = STATUS;\r
552                 }\r
553         }\r
554         transfer.inProgress = 0;\r
555 }\r
556 \r
557 \r
558 // SD Version 2 (SDHC) support\r
559 static int sendIfCond()\r
560 {\r
561         int retries = 50;\r
562 \r
563         do\r
564         {\r
565                 // 11:8 Host voltage. 1 = 2.7-3.6V\r
566                 // 7:0 Echo bits. Ignore.\r
567                 uint8 status = sdCRCCommandAndResponse(SD_SEND_IF_COND, 0x000001AA);\r
568 \r
569                 if (status == SD_R1_IDLE)\r
570                 {\r
571                         // Version 2 card.\r
572                         sdDev.version = 2;\r
573                         // Read 32bit response. Should contain the same bytes that\r
574                         // we sent in the command parameter.\r
575                         sdSpiByte(0xFF);\r
576                         sdSpiByte(0xFF);\r
577                         sdSpiByte(0xFF);\r
578                         sdSpiByte(0xFF);\r
579                         break;\r
580                 }\r
581                 else if (status & SD_R1_ILLEGAL)\r
582                 {\r
583                         // Version 1 card.\r
584                         sdDev.version = 1;\r
585                         sdClearStatus();\r
586                         break;\r
587                 }\r
588 \r
589                 sdClearStatus();\r
590         } while (--retries > 0);\r
591 \r
592         return retries > 0;\r
593 }\r
594 \r
595 static int sdOpCond()\r
596 {\r
597         uint32_t start = getTime_ms();\r
598 \r
599         uint8 status;\r
600         do\r
601         {\r
602                 sdCRCCommandAndResponse(SD_APP_CMD, 0);\r
603                 // Host Capacity Support = 1 (SDHC/SDXC supported)\r
604                 status = sdCRCCommandAndResponse(SD_APP_SEND_OP_COND, 0x40000000);\r
605 \r
606                 sdClearStatus();\r
607 \r
608         // Spec says to poll for 1 second.\r
609         } while ((status != 0) && (elapsedTime_ms(start) < 1000));\r
610 \r
611         return status == 0;\r
612 }\r
613 \r
614 static int sdReadOCR()\r
615 {\r
616         uint32_t start = getTime_ms();\r
617         int complete;\r
618         uint8 status;\r
619 \r
620         do\r
621         {\r
622                 uint8 buf[4];\r
623                 int i;\r
624 \r
625                 status = sdCRCCommandAndResponse(SD_READ_OCR, 0);\r
626                 if(status) { break; }\r
627 \r
628                 for (i = 0; i < 4; ++i)\r
629                 {\r
630                         buf[i] = sdSpiByte(0xFF);\r
631                 }\r
632 \r
633                 sdDev.ccs = (buf[0] & 0x40) ? 1 : 0;\r
634                 complete = (buf[0] & 0x80);\r
635 \r
636         } while (!status &&\r
637                 !complete &&\r
638                 (elapsedTime_ms(start) < 1000));\r
639 \r
640         return (status == 0) && complete;\r
641 }\r
642 \r
643 static void sdReadCID()\r
644 {\r
645         uint8 startToken;\r
646         int maxWait, i;\r
647 \r
648         uint8 status = sdCRCCommandAndResponse(SD_SEND_CID, 0);\r
649         if(status){return;}\r
650 \r
651         maxWait = 1023;\r
652         do\r
653         {\r
654                 startToken = sdSpiByte(0xFF);\r
655         } while(maxWait-- && (startToken != 0xFE));\r
656         if (startToken != 0xFE) { return; }\r
657 \r
658         for (i = 0; i < 16; ++i)\r
659         {\r
660                 sdDev.cid[i] = sdSpiByte(0xFF);\r
661         }\r
662         sdSpiByte(0xFF); // CRC\r
663         sdSpiByte(0xFF); // CRC\r
664 }\r
665 \r
666 static int sdReadCSD()\r
667 {\r
668         uint8 startToken;\r
669         int maxWait, i;\r
670 \r
671         uint8 status = sdCRCCommandAndResponse(SD_SEND_CSD, 0);\r
672         if(status){goto bad;}\r
673 \r
674         maxWait = 1023;\r
675         do\r
676         {\r
677                 startToken = sdSpiByte(0xFF);\r
678         } while(maxWait-- && (startToken != 0xFE));\r
679         if (startToken != 0xFE) { goto bad; }\r
680 \r
681         for (i = 0; i < 16; ++i)\r
682         {\r
683                 sdDev.csd[i] = sdSpiByte(0xFF);\r
684         }\r
685         sdSpiByte(0xFF); // CRC\r
686         sdSpiByte(0xFF); // CRC\r
687 \r
688         if ((sdDev.csd[0] >> 6) == 0x00)\r
689         {\r
690                 // CSD version 1\r
691                 // C_SIZE in bits [73:62]\r
692                 uint32 c_size = (((((uint32)sdDev.csd[6]) & 0x3) << 16) | (((uint32)sdDev.csd[7]) << 8) | sdDev.csd[8]) >> 6;\r
693                 uint32 c_mult = (((((uint32)sdDev.csd[9]) & 0x3) << 8) | ((uint32)sdDev.csd[0xa])) >> 7;\r
694                 uint32 sectorSize = sdDev.csd[5] & 0x0F;\r
695                 sdDev.capacity = ((c_size+1) * ((uint64)1 << (c_mult+2)) * ((uint64)1 << sectorSize)) / SD_SECTOR_SIZE;\r
696         }\r
697         else if ((sdDev.csd[0] >> 6) == 0x01)\r
698         {\r
699                 // CSD version 2\r
700                 // C_SIZE in bits [69:48]\r
701 \r
702                 uint32 c_size =\r
703                         ((((uint32)sdDev.csd[7]) & 0x3F) << 16) |\r
704                         (((uint32)sdDev.csd[8]) << 8) |\r
705                         ((uint32)sdDev.csd[7]);\r
706                 sdDev.capacity = (c_size + 1) * 1024;\r
707         }\r
708         else\r
709         {\r
710                 goto bad;\r
711         }\r
712 \r
713         return 1;\r
714 bad:\r
715         return 0;\r
716 }\r
717 \r
718 static void sdInitDMA()\r
719 {\r
720         // One-time init only.\r
721         if (sdDMATxChan == CY_DMA_INVALID_CHANNEL)\r
722         {\r
723                 sdDMATxChan =\r
724                         SD_TX_DMA_DmaInitialize(\r
725                                 1, // Bytes per burst\r
726                                 1, // request per burst\r
727                                 HI16(CYDEV_SRAM_BASE),\r
728                                 HI16(CYDEV_PERIPH_BASE)\r
729                                 );\r
730 \r
731                 sdDMARxChan =\r
732                         SD_RX_DMA_DmaInitialize(\r
733                                 1, // Bytes per burst\r
734                                 1, // request per burst\r
735                                 HI16(CYDEV_PERIPH_BASE),\r
736                                 HI16(CYDEV_SRAM_BASE)\r
737                                 );\r
738 \r
739                 CyDmaChDisable(sdDMATxChan);\r
740                 CyDmaChDisable(sdDMARxChan);\r
741 \r
742                 SD_RX_DMA_COMPLETE_StartEx(sdRxISR);\r
743                 SD_TX_DMA_COMPLETE_StartEx(sdTxISR);\r
744         }\r
745 }\r
746 \r
747 int sdInit()\r
748 {\r
749         int result = 0;\r
750         int i;\r
751         uint8 v;\r
752 \r
753         sdDev.version = 0;\r
754         sdDev.ccs = 0;\r
755         sdDev.capacity = 0;\r
756         memset(sdDev.csd, 0, sizeof(sdDev.csd));\r
757         memset(sdDev.cid, 0, sizeof(sdDev.cid));\r
758 \r
759         sdInitDMA();\r
760 \r
761         SD_CS_SetDriveMode(SD_CS_DM_STRONG);\r
762         SD_CS_Write(1); // Set CS inactive (active low)\r
763 \r
764         // Set the SPI clock for 400kHz transfers\r
765         // 25MHz / 400kHz approx factor of 63.\r
766         // The register contains (divider - 1)\r
767         uint16_t clkDiv25MHz =  SD_Data_Clk_GetDividerRegister();\r
768         SD_Data_Clk_SetDivider(((clkDiv25MHz + 1) * 63) - 1);\r
769         // Wait for the clock to settle.\r
770         CyDelayUs(1);\r
771 \r
772         SDCard_Start(); // Enable SPI hardware\r
773 \r
774         // Power on sequence. 74 clock cycles of a "1" while CS unasserted.\r
775         for (i = 0; i < 10; ++i)\r
776         {\r
777                 sdSpiByte(0xFF);\r
778         }\r
779 \r
780         SD_CS_Write(0); // Set CS active (active low)\r
781         CyDelayUs(1);\r
782 \r
783         sdSpiByte(0xFF);\r
784         v = sdDoCommand(SD_GO_IDLE_STATE, 0, 1, 0);\r
785         if(v != 1){goto bad;}\r
786 \r
787         ledOn();\r
788         if (!sendIfCond()) goto bad; // Sets V1 or V2 flag  CMD8\r
789         if (!sdOpCond()) goto bad; // ACMD41. Wait for init completes.\r
790         if (!sdReadOCR()) goto bad; // CMD58. Get CCS flag. Only valid after init.\r
791 \r
792         // This command will be ignored if sdDev.ccs is set.\r
793         // SDHC and SDXC are always 512bytes.\r
794         v = sdCRCCommandAndResponse(SD_SET_BLOCKLEN, SD_SECTOR_SIZE); //Force sector size\r
795         if(v){goto bad;}\r
796         v = sdCRCCommandAndResponse(SD_CRC_ON_OFF, 0); //crc off\r
797         if(v){goto bad;}\r
798 \r
799         // now set the sd card back to full speed.\r
800         // The SD Card spec says we can run SPI @ 25MHz\r
801         SDCard_Stop();\r
802 \r
803         // We can't run at full-speed with the pullup resistors enabled.\r
804         SD_MISO_SetDriveMode(SD_MISO_DM_DIG_HIZ);\r
805         SD_MOSI_SetDriveMode(SD_MOSI_DM_STRONG);\r
806         SD_SCK_SetDriveMode(SD_SCK_DM_STRONG);\r
807 \r
808         SD_Data_Clk_SetDivider(clkDiv25MHz);\r
809         CyDelayUs(1);\r
810         SDCard_Start();\r
811 \r
812         // Clear out rubbish data through clock change\r
813         CyDelayUs(1);\r
814         SDCard_ReadRxStatus();\r
815         SDCard_ReadTxStatus();\r
816         SDCard_ClearFIFO();\r
817 \r
818         if (!sdReadCSD()) goto bad;\r
819         sdReadCID();\r
820 \r
821         result = 1;\r
822         goto out;\r
823 \r
824 bad:\r
825         SD_Data_Clk_SetDivider(clkDiv25MHz); // Restore the clock for our next retry\r
826         sdDev.capacity = 0;\r
827 \r
828 out:\r
829         sdClearStatus();\r
830         ledOff();\r
831         return result;\r
832 \r
833 }\r
834 \r
835 void sdWriteMultiSectorPrep()\r
836 {\r
837         uint8 v;\r
838 \r
839         // Set the number of blocks to pre-erase by the multiple block write command\r
840         // We don't care about the response - if the command is not accepted, writes\r
841         // will just be a bit slower.\r
842         // Max 22bit parameter.\r
843         uint32_t sdBlocks =\r
844                 transfer.blocks *\r
845                         SDSectorsPerSCSISector(scsiDev.target->liveCfg.bytesPerSector);\r
846         uint32 blocks = sdBlocks > 0x7FFFFF ? 0x7FFFFF : sdBlocks;\r
847         sdCommandAndResponse(SD_APP_CMD, 0);\r
848         sdCommandAndResponse(SD_APP_SET_WR_BLK_ERASE_COUNT, blocks);\r
849 \r
850         uint32 scsiLBA = (transfer.lba + transfer.currentBlock);\r
851         uint32 sdLBA =\r
852                 SCSISector2SD(\r
853                         scsiDev.target->cfg->sdSectorStart,\r
854                         scsiDev.target->liveCfg.bytesPerSector,\r
855                         scsiLBA);\r
856         if (!sdDev.ccs)\r
857         {\r
858                 sdLBA = sdLBA * SD_SECTOR_SIZE;\r
859         }\r
860         v = sdCommandAndResponse(SD_WRITE_MULTIPLE_BLOCK, sdLBA);\r
861         if (unlikely(v))\r
862         {\r
863                 scsiDiskReset();\r
864                 sdClearStatus();\r
865                 scsiDev.status = CHECK_CONDITION;\r
866                 scsiDev.target->sense.code = HARDWARE_ERROR;\r
867                 scsiDev.target->sense.asc = LOGICAL_UNIT_COMMUNICATION_FAILURE;\r
868                 scsiDev.phase = STATUS;\r
869         }\r
870         else\r
871         {\r
872                 transfer.inProgress = 1;\r
873         }\r
874 }\r
875 \r
876 void sdPoll()\r
877 {\r
878         // Check if there's an SD card present.\r
879         if ((scsiDev.phase == BUS_FREE) &&\r
880                 (sdIOState == SD_IDLE))\r
881         {\r
882                 // The CS line is pulled high by the SD card.\r
883                 // De-assert the line, and check if it's high.\r
884                 // This isn't foolproof as it'll be left floating without\r
885                 // an SD card. We can't use the built-in pull-down resistor as it will\r
886                 // overpower the SD pullup resistor.\r
887                 SD_CS_Write(0);\r
888                 SD_CS_SetDriveMode(SD_CS_DM_DIG_HIZ);\r
889 \r
890                 CyDelayCycles(64);\r
891                 uint8_t cs = SD_CS_Read();\r
892                 SD_CS_SetDriveMode(SD_CS_DM_STRONG)     ;\r
893 \r
894                 if (cs && !(blockDev.state & DISK_PRESENT))\r
895                 {\r
896                         static int firstInit = 1;\r
897 \r
898                         // Debounce\r
899                         CyDelay(250);\r
900 \r
901                         if (sdInit())\r
902                         {\r
903                                 blockDev.state |= DISK_PRESENT | DISK_INITIALISED;\r
904 \r
905                                 if (!firstInit)\r
906                                 {\r
907                                         int i;\r
908                                         for (i = 0; i < MAX_SCSI_TARGETS; ++i)\r
909                                         {\r
910                                                 scsiDev.targets[i].unitAttention = PARAMETERS_CHANGED;\r
911                                         }\r
912                                 }\r
913                                 firstInit = 0;\r
914                         }\r
915                 }\r
916                 else if (!cs && (blockDev.state & DISK_PRESENT))\r
917                 {\r
918                         sdDev.capacity = 0;\r
919                         blockDev.state &= ~DISK_PRESENT;\r
920                         blockDev.state &= ~DISK_INITIALISED;\r
921                         int i;\r
922                         for (i = 0; i < MAX_SCSI_TARGETS; ++i)\r
923                         {\r
924                                 scsiDev.targets[i].unitAttention = PARAMETERS_CHANGED;\r
925                         }\r
926                 }\r
927         }\r
928 }\r
929 \r
930 #pragma GCC pop_options\r