Track start/stop status per virtual scsi device.
[SCSI2SD-V6.git] / src / firmware / disk.c
1 //    Copyright (C) 2013 Michael McMaster <michael@codesrc.com>\r
2 //    Copyright (C) 2014 Doug Brown <doug@downtowndougbrown.com>\r
3 //\r
4 //    This file is part of SCSI2SD.\r
5 //\r
6 //    SCSI2SD is free software: you can redistribute it and/or modify\r
7 //    it under the terms of the GNU General Public License as published by\r
8 //    the Free Software Foundation, either version 3 of the License, or\r
9 //    (at your option) any later version.\r
10 //\r
11 //    SCSI2SD is distributed in the hope that it will be useful,\r
12 //    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
13 //    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
14 //    GNU General Public License for more details.\r
15 //\r
16 //    You should have received a copy of the GNU General Public License\r
17 //    along with SCSI2SD.  If not, see <http://www.gnu.org/licenses/>.\r
18 \r
19 #ifdef STM32F2xx\r
20 #include "stm32f2xx.h"\r
21 #endif\r
22 #ifdef STM32F4xx\r
23 #include "stm32f4xx.h"\r
24 #endif\r
25 \r
26 #include <assert.h>\r
27 \r
28 // For SD write direct routines\r
29 #include "sdio.h"\r
30 #include "bsp_driver_sd.h"\r
31 \r
32 \r
33 #include "scsi.h"\r
34 #include "scsiPhy.h"\r
35 #include "config.h"\r
36 #include "disk.h"\r
37 #include "sd.h"\r
38 #include "time.h"\r
39 #include "bsp.h"\r
40 \r
41 #include <string.h>\r
42 \r
43 // Global\r
44 BlockDevice blockDev;\r
45 Transfer transfer;\r
46 \r
47 static int doSdInit()\r
48 {\r
49     int result = 0;\r
50     if (blockDev.state & DISK_PRESENT)\r
51     {\r
52         blockDev.state = blockDev.state | DISK_INITIALISED;\r
53     }\r
54     return result;\r
55 }\r
56 \r
57 // Callback once all data has been read in the data out phase.\r
58 static void doFormatUnitComplete(void)\r
59 {\r
60     // TODO start writing the initialisation pattern to the SD\r
61     // card\r
62     scsiDev.phase = STATUS;\r
63 }\r
64 \r
65 static void doFormatUnitSkipData(int bytes)\r
66 {\r
67     // We may not have enough memory to store the initialisation pattern and\r
68     // defect list data.  Since we're not making use of it yet anyway, just\r
69     // discard the bytes.\r
70     scsiEnterPhase(DATA_OUT);\r
71     int i;\r
72     for (i = 0; i < bytes; ++i)\r
73     {\r
74         scsiReadByte();\r
75     }\r
76 }\r
77 \r
78 // Callback from the data out phase.\r
79 static void doFormatUnitPatternHeader(void)\r
80 {\r
81     int defectLength =\r
82         ((((uint16_t)scsiDev.data[2])) << 8) +\r
83             scsiDev.data[3];\r
84 \r
85     int patternLength =\r
86         ((((uint16_t)scsiDev.data[4 + 2])) << 8) +\r
87         scsiDev.data[4 + 3];\r
88 \r
89         doFormatUnitSkipData(defectLength + patternLength);\r
90         doFormatUnitComplete();\r
91 }\r
92 \r
93 // Callback from the data out phase.\r
94 static void doFormatUnitHeader(void)\r
95 {\r
96     int IP = (scsiDev.data[1] & 0x08) ? 1 : 0;\r
97     int DSP = (scsiDev.data[1] & 0x04) ? 1 : 0;\r
98 \r
99     if (! DSP) // disable save parameters\r
100     {\r
101         // Save the "MODE SELECT savable parameters"\r
102         s2s_configSave(\r
103             scsiDev.target->targetId,\r
104             scsiDev.target->liveCfg.bytesPerSector);\r
105     }\r
106 \r
107     if (IP)\r
108     {\r
109         // We need to read the initialisation pattern header first.\r
110         scsiDev.dataLen += 4;\r
111         scsiDev.phase = DATA_OUT;\r
112         scsiDev.postDataOutHook = doFormatUnitPatternHeader;\r
113     }\r
114     else\r
115     {\r
116         // Read the defect list data\r
117         int defectLength =\r
118             ((((uint16_t)scsiDev.data[2])) << 8) +\r
119             scsiDev.data[3];\r
120         doFormatUnitSkipData(defectLength);\r
121         doFormatUnitComplete();\r
122     }\r
123 }\r
124 \r
125 static void doReadCapacity()\r
126 {\r
127     uint32_t lba = (((uint32_t) scsiDev.cdb[2]) << 24) +\r
128         (((uint32_t) scsiDev.cdb[3]) << 16) +\r
129         (((uint32_t) scsiDev.cdb[4]) << 8) +\r
130         scsiDev.cdb[5];\r
131     int pmi = scsiDev.cdb[8] & 1;\r
132 \r
133     uint32_t capacity = getScsiCapacity(\r
134         scsiDev.target->cfg->sdSectorStart,\r
135         scsiDev.target->liveCfg.bytesPerSector,\r
136         scsiDev.target->cfg->scsiSectors);\r
137 \r
138     if (!pmi && lba)\r
139     {\r
140         // error.\r
141         // We don't do anything with the "partial medium indicator", and\r
142         // assume that delays are constant across each block. But the spec\r
143         // says we must return this error if pmi is specified incorrectly.\r
144         scsiDev.status = CHECK_CONDITION;\r
145         scsiDev.target->sense.code = ILLEGAL_REQUEST;\r
146         scsiDev.target->sense.asc = INVALID_FIELD_IN_CDB;\r
147         scsiDev.phase = STATUS;\r
148     }\r
149     else if (capacity > 0)\r
150     {\r
151         uint32_t highestBlock = capacity - 1;\r
152 \r
153         scsiDev.data[0] = highestBlock >> 24;\r
154         scsiDev.data[1] = highestBlock >> 16;\r
155         scsiDev.data[2] = highestBlock >> 8;\r
156         scsiDev.data[3] = highestBlock;\r
157 \r
158         uint32_t bytesPerSector = scsiDev.target->liveCfg.bytesPerSector;\r
159         scsiDev.data[4] = bytesPerSector >> 24;\r
160         scsiDev.data[5] = bytesPerSector >> 16;\r
161         scsiDev.data[6] = bytesPerSector >> 8;\r
162         scsiDev.data[7] = bytesPerSector;\r
163         scsiDev.dataLen = 8;\r
164         scsiDev.phase = DATA_IN;\r
165     }\r
166     else\r
167     {\r
168         scsiDev.status = CHECK_CONDITION;\r
169         scsiDev.target->sense.code = NOT_READY;\r
170         scsiDev.target->sense.asc = MEDIUM_NOT_PRESENT;\r
171         scsiDev.phase = STATUS;\r
172     }\r
173 }\r
174 \r
175 static void doWrite(uint32_t lba, uint32_t blocks)\r
176 {\r
177     if (unlikely(scsiDev.target->cfg->deviceType == S2S_CFG_FLOPPY_14MB)) {\r
178         // Floppies are supposed to be slow. Some systems can't handle a floppy\r
179         // without an access time\r
180         s2s_delay_ms(10);\r
181     }\r
182 \r
183     uint32_t bytesPerSector = scsiDev.target->liveCfg.bytesPerSector;\r
184 \r
185     if (unlikely(blockDev.state & DISK_WP) ||\r
186         unlikely(scsiDev.target->cfg->deviceType == S2S_CFG_OPTICAL))\r
187 \r
188     {\r
189         scsiDev.status = CHECK_CONDITION;\r
190         scsiDev.target->sense.code = ILLEGAL_REQUEST;\r
191         scsiDev.target->sense.asc = WRITE_PROTECTED;\r
192         scsiDev.phase = STATUS;\r
193     }\r
194     else if (unlikely(((uint64_t) lba) + blocks >\r
195         getScsiCapacity(\r
196             scsiDev.target->cfg->sdSectorStart,\r
197             bytesPerSector,\r
198             scsiDev.target->cfg->scsiSectors\r
199             )\r
200         ))\r
201     {\r
202         scsiDev.status = CHECK_CONDITION;\r
203         scsiDev.target->sense.code = ILLEGAL_REQUEST;\r
204         scsiDev.target->sense.asc = LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;\r
205         scsiDev.phase = STATUS;\r
206     }\r
207     else\r
208     {\r
209         transfer.lba = lba;\r
210         transfer.blocks = blocks;\r
211         transfer.currentBlock = 0;\r
212         scsiDev.phase = DATA_OUT;\r
213         scsiDev.dataLen = bytesPerSector;\r
214         scsiDev.dataPtr = bytesPerSector;\r
215 \r
216         // No need for single-block writes atm.  Overhead of the\r
217         // multi-block write is minimal.\r
218         transfer.multiBlock = 1;\r
219 \r
220 \r
221         // TODO uint32_t sdLBA =\r
222 // TODO             SCSISector2SD(\r
223     // TODO             scsiDev.target->cfg->sdSectorStart,\r
224         // TODO         bytesPerSector,\r
225             // TODO     lba);\r
226         // TODO uint32_t sdBlocks = blocks * SDSectorsPerSCSISector(bytesPerSector);\r
227         // TODO sdWriteMultiSectorPrep(sdLBA, sdBlocks);\r
228     }\r
229 }\r
230 \r
231 \r
232 static void doRead(uint32_t lba, uint32_t blocks)\r
233 {\r
234     if (unlikely(scsiDev.target->cfg->deviceType == S2S_CFG_FLOPPY_14MB)) {\r
235         // Floppies are supposed to be slow. Some systems can't handle a floppy\r
236         // without an access time\r
237         s2s_delay_ms(10);\r
238     }\r
239 \r
240     uint32_t capacity = getScsiCapacity(\r
241         scsiDev.target->cfg->sdSectorStart,\r
242         scsiDev.target->liveCfg.bytesPerSector,\r
243         scsiDev.target->cfg->scsiSectors);\r
244     if (unlikely(((uint64_t) lba) + blocks > capacity))\r
245     {\r
246         scsiDev.status = CHECK_CONDITION;\r
247         scsiDev.target->sense.code = ILLEGAL_REQUEST;\r
248         scsiDev.target->sense.asc = LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;\r
249         scsiDev.phase = STATUS;\r
250     }\r
251     else\r
252     {\r
253         transfer.lba = lba;\r
254         transfer.blocks = blocks;\r
255         transfer.currentBlock = 0;\r
256         scsiDev.phase = DATA_IN;\r
257         scsiDev.dataLen = 0; // No data yet\r
258 \r
259         uint32_t bytesPerSector = scsiDev.target->liveCfg.bytesPerSector;\r
260         uint32_t sdSectorPerSCSISector = SDSectorsPerSCSISector(bytesPerSector);\r
261         uint32_t sdSectors =\r
262             blocks * sdSectorPerSCSISector;\r
263 \r
264         if ((\r
265                 (sdSectors == 1) &&\r
266                 !(scsiDev.boardCfg.flags & S2S_CFG_ENABLE_CACHE)\r
267             ) ||\r
268             unlikely(((uint64_t) lba) + blocks == capacity)\r
269             )\r
270         {\r
271             // We get errors on reading the last sector using a multi-sector\r
272             // read :-(\r
273             transfer.multiBlock = 0;\r
274         }\r
275         else\r
276         {\r
277             transfer.multiBlock = 1;\r
278 \r
279             // uint32_t sdLBA =\r
280                 // SCSISector2SD(\r
281                     // scsiDev.target->cfg->sdSectorStart,\r
282                     // bytesPerSector,\r
283                     // lba);\r
284 \r
285             // TODO sdReadMultiSectorPrep(sdLBA, sdSectors);\r
286         }\r
287     }\r
288 }\r
289 \r
290 static void doSeek(uint32_t lba)\r
291 {\r
292     if (lba >=\r
293         getScsiCapacity(\r
294             scsiDev.target->cfg->sdSectorStart,\r
295             scsiDev.target->liveCfg.bytesPerSector,\r
296             scsiDev.target->cfg->scsiSectors)\r
297         )\r
298     {\r
299         scsiDev.status = CHECK_CONDITION;\r
300         scsiDev.target->sense.code = ILLEGAL_REQUEST;\r
301         scsiDev.target->sense.asc = LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;\r
302         scsiDev.phase = STATUS;\r
303     }\r
304     else\r
305     {\r
306         s2s_delay_ms(10);\r
307     }\r
308 }\r
309 \r
310 static int doTestUnitReady()\r
311 {\r
312     int ready = 1;\r
313     if (likely(blockDev.state == (DISK_PRESENT | DISK_INITIALISED) &&\r
314                 scsiDev.target->started))\r
315     {\r
316         // nothing to do.\r
317     }\r
318     else if (unlikely(!scsiDev.target->started))\r
319     {\r
320         ready = 0;\r
321         scsiDev.status = CHECK_CONDITION;\r
322         scsiDev.target->sense.code = NOT_READY;\r
323         scsiDev.target->sense.asc = LOGICAL_UNIT_NOT_READY_INITIALIZING_COMMAND_REQUIRED;\r
324         scsiDev.phase = STATUS;\r
325     }\r
326     else if (unlikely(!(blockDev.state & DISK_PRESENT)))\r
327     {\r
328         ready = 0;\r
329         scsiDev.status = CHECK_CONDITION;\r
330         scsiDev.target->sense.code = NOT_READY;\r
331         scsiDev.target->sense.asc = MEDIUM_NOT_PRESENT;\r
332         scsiDev.phase = STATUS;\r
333     }\r
334     else if (unlikely(!(blockDev.state & DISK_INITIALISED)))\r
335     {\r
336         ready = 0;\r
337         scsiDev.status = CHECK_CONDITION;\r
338         scsiDev.target->sense.code = NOT_READY;\r
339         scsiDev.target->sense.asc = LOGICAL_UNIT_NOT_READY_CAUSE_NOT_REPORTABLE;\r
340         scsiDev.phase = STATUS;\r
341     }\r
342     return ready;\r
343 }\r
344 \r
345 // Handle direct-access scsi device commands\r
346 int scsiDiskCommand()\r
347 {\r
348     int commandHandled = 1;\r
349 \r
350     uint8_t command = scsiDev.cdb[0];\r
351     if (unlikely(command == 0x1B))\r
352     {\r
353         // START STOP UNIT\r
354         // Enable or disable media access operations.\r
355         //int immed = scsiDev.cdb[1] & 1;\r
356         int start = scsiDev.cdb[4] & 1;\r
357         int loadEject = scsiDev.cdb[4] & 2;\r
358         \r
359         if (loadEject)\r
360         {\r
361             // Ignore load/eject requests. We can't do that.\r
362         }\r
363         else if (start)\r
364         {\r
365             scsiDev.target->started = 1;\r
366             if (!(blockDev.state & DISK_INITIALISED))\r
367             {\r
368                 doSdInit();\r
369             }\r
370         }\r
371         else\r
372         {\r
373             scsiDev.target->started = 0;\r
374         }\r
375     }\r
376     else if (unlikely(command == 0x00))\r
377     {\r
378         // TEST UNIT READY\r
379         doTestUnitReady();\r
380     }\r
381     else if (unlikely(!doTestUnitReady()))\r
382     {\r
383         // Status and sense codes already set by doTestUnitReady\r
384     }\r
385     else if (likely(command == 0x08))\r
386     {\r
387         // READ(6)\r
388         uint32_t lba =\r
389             (((uint32_t) scsiDev.cdb[1] & 0x1F) << 16) +\r
390             (((uint32_t) scsiDev.cdb[2]) << 8) +\r
391             scsiDev.cdb[3];\r
392         uint32_t blocks = scsiDev.cdb[4];\r
393         if (unlikely(blocks == 0)) blocks = 256;\r
394         doRead(lba, blocks);\r
395     }\r
396     else if (likely(command == 0x28))\r
397     {\r
398         // READ(10)\r
399         // Ignore all cache control bits - we don't support a memory cache.\r
400 \r
401         uint32_t lba =\r
402             (((uint32_t) scsiDev.cdb[2]) << 24) +\r
403             (((uint32_t) scsiDev.cdb[3]) << 16) +\r
404             (((uint32_t) scsiDev.cdb[4]) << 8) +\r
405             scsiDev.cdb[5];\r
406         uint32_t blocks =\r
407             (((uint32_t) scsiDev.cdb[7]) << 8) +\r
408             scsiDev.cdb[8];\r
409 \r
410         doRead(lba, blocks);\r
411     }\r
412     else if (likely(command == 0x0A))\r
413     {\r
414         // WRITE(6)\r
415         uint32_t lba =\r
416             (((uint32_t) scsiDev.cdb[1] & 0x1F) << 16) +\r
417             (((uint32_t) scsiDev.cdb[2]) << 8) +\r
418             scsiDev.cdb[3];\r
419         uint32_t blocks = scsiDev.cdb[4];\r
420         if (unlikely(blocks == 0)) blocks = 256;\r
421         doWrite(lba, blocks);\r
422     }\r
423     else if (likely(command == 0x2A) || // WRITE(10)\r
424         unlikely(command == 0x2E)) // WRITE AND VERIFY\r
425     {\r
426         // Ignore all cache control bits - we don't support a memory cache.\r
427         // Don't bother verifying either. The SD card likely stores ECC\r
428         // along with each flash row.\r
429 \r
430         uint32_t lba =\r
431             (((uint32_t) scsiDev.cdb[2]) << 24) +\r
432             (((uint32_t) scsiDev.cdb[3]) << 16) +\r
433             (((uint32_t) scsiDev.cdb[4]) << 8) +\r
434             scsiDev.cdb[5];\r
435         uint32_t blocks =\r
436             (((uint32_t) scsiDev.cdb[7]) << 8) +\r
437             scsiDev.cdb[8];\r
438 \r
439         doWrite(lba, blocks);\r
440     }\r
441     else if (unlikely(command == 0x04))\r
442     {\r
443         // FORMAT UNIT\r
444         // We don't really do any formatting, but we need to read the correct\r
445         // number of bytes in the DATA_OUT phase to make the SCSI host happy.\r
446 \r
447         int fmtData = (scsiDev.cdb[1] & 0x10) ? 1 : 0;\r
448         if (fmtData)\r
449         {\r
450             // We need to read the parameter list, but we don't know how\r
451             // big it is yet. Start with the header.\r
452             scsiDev.dataLen = 4;\r
453             scsiDev.phase = DATA_OUT;\r
454             scsiDev.postDataOutHook = doFormatUnitHeader;\r
455         }\r
456         else\r
457         {\r
458             // No data to read, we're already finished!\r
459         }\r
460     }\r
461     else if (unlikely(command == 0x25))\r
462     {\r
463         // READ CAPACITY\r
464         doReadCapacity();\r
465     }\r
466     else if (unlikely(command == 0x0B))\r
467     {\r
468         // SEEK(6)\r
469         uint32_t lba =\r
470             (((uint32_t) scsiDev.cdb[1] & 0x1F) << 16) +\r
471             (((uint32_t) scsiDev.cdb[2]) << 8) +\r
472             scsiDev.cdb[3];\r
473 \r
474         doSeek(lba);\r
475     }\r
476 \r
477     else if (unlikely(command == 0x2B))\r
478     {\r
479         // SEEK(10)\r
480         uint32_t lba =\r
481             (((uint32_t) scsiDev.cdb[2]) << 24) +\r
482             (((uint32_t) scsiDev.cdb[3]) << 16) +\r
483             (((uint32_t) scsiDev.cdb[4]) << 8) +\r
484             scsiDev.cdb[5];\r
485 \r
486         doSeek(lba);\r
487     }\r
488     else if (unlikely(command == 0x36))\r
489     {\r
490         // LOCK UNLOCK CACHE\r
491         // We don't have a cache to lock data into. do nothing.\r
492     }\r
493     else if (unlikely(command == 0x34))\r
494     {\r
495         // PRE-FETCH.\r
496         // We don't have a cache to pre-fetch into. do nothing.\r
497     }\r
498     else if (unlikely(command == 0x1E))\r
499     {\r
500         // PREVENT ALLOW MEDIUM REMOVAL\r
501         // Not much we can do to prevent the user removing the SD card.\r
502         // do nothing.\r
503     }\r
504     else if (unlikely(command == 0x01))\r
505     {\r
506         // REZERO UNIT\r
507         // Set the lun to a vendor-specific state. Ignore.\r
508     }\r
509     else if (unlikely(command == 0x35))\r
510     {\r
511         // SYNCHRONIZE CACHE\r
512         // We don't have a cache. do nothing.\r
513     }\r
514     else if (unlikely(command == 0x2F))\r
515     {\r
516         // VERIFY\r
517         // TODO: When they supply data to verify, we should read the data and\r
518         // verify it. If they don't supply any data, just say success.\r
519         if ((scsiDev.cdb[1] & 0x02) == 0)\r
520         {\r
521             // They are asking us to do a medium verification with no data\r
522             // comparison. Assume success, do nothing.\r
523         }\r
524         else\r
525         {\r
526             // TODO. This means they are supplying data to verify against.\r
527             // Technically we should probably grab the data and compare it.\r
528             scsiDev.status = CHECK_CONDITION;\r
529             scsiDev.target->sense.code = ILLEGAL_REQUEST;\r
530             scsiDev.target->sense.asc = INVALID_FIELD_IN_CDB;\r
531             scsiDev.phase = STATUS;\r
532         }\r
533     }\r
534     else if (unlikely(command == 0x37))\r
535     {\r
536         // READ DEFECT DATA\r
537         uint32_t allocLength = (((uint16_t)scsiDev.cdb[7]) << 8) |\r
538             scsiDev.cdb[8];\r
539 \r
540         scsiDev.data[0] = 0;\r
541         scsiDev.data[1] = scsiDev.cdb[1];\r
542         scsiDev.data[2] = 0;\r
543         scsiDev.data[3] = 0;\r
544         scsiDev.dataLen = 4;\r
545 \r
546         if (scsiDev.dataLen > allocLength)\r
547         {\r
548             scsiDev.dataLen = allocLength;\r
549         }\r
550 \r
551         scsiDev.phase = DATA_IN;\r
552     }\r
553     else\r
554     {\r
555         commandHandled = 0;\r
556     }\r
557 \r
558     return commandHandled;\r
559 }\r
560 \r
561 void scsiDiskPoll()\r
562 {\r
563     uint32_t bytesPerSector = scsiDev.target->liveCfg.bytesPerSector;\r
564 \r
565     if (scsiDev.phase == DATA_IN &&\r
566         transfer.currentBlock != transfer.blocks)\r
567     {\r
568         // Take responsibility for waiting for the phase delays\r
569         uint32_t phaseChangeDelayUs = scsiEnterPhaseImmediate(DATA_IN);\r
570 \r
571         int totalSDSectors =\r
572             transfer.blocks * SDSectorsPerSCSISector(bytesPerSector);\r
573         uint32_t sdLBA =\r
574             SCSISector2SD(\r
575                 scsiDev.target->cfg->sdSectorStart,\r
576                 bytesPerSector,\r
577                 transfer.lba);\r
578 \r
579         const int sdPerScsi = SDSectorsPerSCSISector(bytesPerSector);\r
580         const int buffers = sizeof(scsiDev.data) / SD_SECTOR_SIZE;\r
581         int prep = 0;\r
582         int i = 0;\r
583         int scsiActive __attribute__((unused)) = 0; // unused if DMA disabled\r
584         int sdActive = 0;\r
585 \r
586         // It's highly unlikely that someone is going to use huge transfers\r
587         // per scsi command, but if they do it'll be slower than usual.\r
588         uint32_t totalScsiBytes = transfer.blocks * bytesPerSector;\r
589         int useSlowDataCount = totalScsiBytes >= SCSI_XFER_MAX;\r
590         if (!useSlowDataCount)\r
591         {\r
592             scsiSetDataCount(totalScsiBytes);\r
593         }\r
594 \r
595         while ((i < totalSDSectors) &&\r
596             likely(scsiDev.phase == DATA_IN) &&\r
597             likely(!scsiDev.resetFlag))\r
598         {\r
599             int completedDmaSectors;\r
600             if (sdActive && (completedDmaSectors = sdReadDMAPoll(sdActive)))\r
601             {\r
602                 prep += completedDmaSectors;\r
603                 sdActive -= completedDmaSectors;\r
604             } else if (sdActive > 1)\r
605             {\r
606                 if ((scsiDev.data[SD_SECTOR_SIZE * (prep % buffers) + 510] != 0xAA) ||\r
607                     (scsiDev.data[SD_SECTOR_SIZE * (prep % buffers) + 511] != 0x33))\r
608                 {\r
609                     prep += 1;\r
610                     sdActive -= 1;\r
611                 }\r
612             }\r
613 \r
614             if (!sdActive &&\r
615                 (prep - i < buffers) &&\r
616                 (prep < totalSDSectors) &&\r
617                 ((totalSDSectors - prep) >= sdPerScsi) &&\r
618                 (likely(!useSlowDataCount) || scsiPhyComplete()) &&\r
619                 (HAL_SD_GetState(&hsd) != HAL_SD_STATE_BUSY)) // rx complete but IRQ not fired yet.\r
620             {\r
621                 // Start an SD transfer if we have space.\r
622                 uint32_t startBuffer = prep % buffers;\r
623                 uint32_t sectors = totalSDSectors - prep;\r
624                 uint32_t freeBuffers = buffers - (prep - i);\r
625 \r
626                 uint32_t contiguousBuffers = buffers - startBuffer;\r
627                 freeBuffers = freeBuffers < contiguousBuffers\r
628                     ? freeBuffers : contiguousBuffers;\r
629                 sectors = sectors < freeBuffers ? sectors : freeBuffers;\r
630 \r
631                 if (sectors > 128) sectors = 128; // 65536 DMA limit !!\r
632 \r
633                 // Round-down when we have odd sector sizes.\r
634                 if (sdPerScsi != 1)\r
635                 {\r
636                     sectors = (sectors / sdPerScsi) * sdPerScsi;\r
637                 }\r
638 \r
639                 for (int dodgy = 0; dodgy < sectors; dodgy++)\r
640                 {\r
641                     scsiDev.data[SD_SECTOR_SIZE * (startBuffer + dodgy) + 510] = 0xAA;\r
642                     scsiDev.data[SD_SECTOR_SIZE * (startBuffer + dodgy) + 511] = 0x33;\r
643                 }\r
644 \r
645                 sdReadDMA(sdLBA + prep, sectors, &scsiDev.data[SD_SECTOR_SIZE * startBuffer]);\r
646 \r
647                 sdActive = sectors;\r
648 \r
649                 if (useSlowDataCount)\r
650                 {\r
651                     scsiSetDataCount((sectors / sdPerScsi) * bytesPerSector);\r
652                 }\r
653 \r
654                 // Wait now that the SD card is busy\r
655                 // Chances are we've probably already waited sufficient time,\r
656                 // but it's hard to measure microseconds cheaply. So just wait\r
657                 // extra just-in-case. Hopefully it's in parallel with dma.\r
658                 if (phaseChangeDelayUs > 0)\r
659                 {\r
660                     s2s_delay_us(phaseChangeDelayUs);\r
661                     phaseChangeDelayUs = 0;\r
662                 }\r
663             }\r
664 \r
665             if (((prep - i) > 0) &&\r
666                 scsiFifoReady())\r
667             {\r
668                 int dmaBytes = SD_SECTOR_SIZE;\r
669                 if ((i % sdPerScsi) == (sdPerScsi - 1))\r
670                 {\r
671                     dmaBytes = bytesPerSector % SD_SECTOR_SIZE;\r
672                     if (dmaBytes == 0) dmaBytes = SD_SECTOR_SIZE;\r
673                 }\r
674 \r
675                 uint8_t* scsiDmaData = &(scsiDev.data[SD_SECTOR_SIZE * (i % buffers)]);\r
676                 scsiWritePIO(scsiDmaData, dmaBytes);\r
677 \r
678                 ++i;\r
679             }\r
680         }\r
681 \r
682         if (phaseChangeDelayUs > 0 && !scsiDev.resetFlag) // zero bytes ?\r
683         {\r
684             s2s_delay_us(phaseChangeDelayUs);\r
685             phaseChangeDelayUs = 0;\r
686         }\r
687 \r
688         if (scsiDev.resetFlag)\r
689         {\r
690             HAL_SD_Abort(&hsd);\r
691         }\r
692         else\r
693         {\r
694             // Wait for the SD transfer to complete before we disable IRQs.\r
695             // (Otherwise some cards will cause an error if we don't sent the\r
696             // stop transfer command via the DMA complete handler in time)\r
697             while (HAL_SD_GetState(&hsd) == HAL_SD_STATE_BUSY)\r
698             {\r
699                 // Wait while keeping BSY.\r
700             }\r
701         }\r
702 \r
703         HAL_SD_CardStateTypeDef cardState = HAL_SD_GetCardState(&hsd);\r
704         while (cardState == HAL_SD_CARD_PROGRAMMING || cardState == HAL_SD_CARD_SENDING) \r
705         {\r
706             cardState = HAL_SD_GetCardState(&hsd);\r
707          }\r
708 \r
709         // We've finished transferring the data to the FPGA, now wait until it's\r
710         // written to he SCSI bus.\r
711         while (!scsiPhyComplete() &&\r
712             likely(scsiDev.phase == DATA_IN) &&\r
713             likely(!scsiDev.resetFlag))\r
714         {\r
715             __disable_irq();\r
716             if (!scsiPhyComplete() && likely(!scsiDev.resetFlag))\r
717             {\r
718                 __WFI();\r
719             }\r
720             __enable_irq();\r
721         }\r
722 \r
723         if (scsiDev.phase == DATA_IN)\r
724         {\r
725             scsiDev.phase = STATUS;\r
726         }\r
727         scsiDiskReset();\r
728     }\r
729     else if (scsiDev.phase == DATA_OUT &&\r
730         transfer.currentBlock != transfer.blocks)\r
731     {\r
732         scsiEnterPhase(DATA_OUT);\r
733 \r
734         const int sdPerScsi = SDSectorsPerSCSISector(bytesPerSector);\r
735         int totalSDSectors = transfer.blocks * sdPerScsi;\r
736         uint32_t sdLBA =\r
737             SCSISector2SD(\r
738                 scsiDev.target->cfg->sdSectorStart,\r
739                 bytesPerSector,\r
740                 transfer.lba);\r
741         int i = 0;\r
742         int clearBSY = 0;\r
743         int disconnected = 0;\r
744 \r
745         int parityError = 0;\r
746         int enableParity = scsiDev.boardCfg.flags & S2S_CFG_ENABLE_PARITY;\r
747 \r
748         uint32_t maxSectors = sizeof(scsiDev.data) / SD_SECTOR_SIZE;\r
749 \r
750         static_assert(SCSI_XFER_MAX >= sizeof(scsiDev.data), "Assumes SCSI_XFER_MAX >= sizeof(scsiDev.data)");\r
751 \r
752         // Start reading and filling fifos as soon as possible.\r
753         // It's highly unlikely that someone is going to use huge transfers\r
754         // per scsi command, but if they do it'll be slower than usual.\r
755         // Note: Happens in Macintosh FWB HDD Toolkit benchmarks which default\r
756         // to 768kb\r
757         uint32_t totalTransferBytes = transfer.blocks * bytesPerSector;\r
758         int useSlowDataCount = totalTransferBytes >= SCSI_XFER_MAX;\r
759         if (!useSlowDataCount)\r
760         {\r
761             DWT->CYCCNT = 0; // Start counting cycles\r
762             scsiSetDataCount(totalTransferBytes);\r
763         }\r
764 \r
765         int lastWriteSize = 0;\r
766 \r
767         while ((i < totalSDSectors) &&\r
768             likely(scsiDev.phase == DATA_OUT) &&\r
769             likely(!scsiDev.resetFlag))\r
770             // KEEP GOING to ensure FIFOs are in a good state.\r
771             // likely(!parityError || !enableParity))\r
772         {\r
773             if (bytesPerSector == SD_SECTOR_SIZE)\r
774             {\r
775                 uint32_t maxXferSectors = SCSI_XFER_MAX / SD_SECTOR_SIZE;\r
776                 uint32_t rem = totalSDSectors - i;\r
777                 uint32_t sectors = rem < maxXferSectors ? rem : maxXferSectors;\r
778 \r
779                 uint32_t totalBytes = sectors * SD_SECTOR_SIZE;\r
780 \r
781                 if (useSlowDataCount)\r
782                 {\r
783                     scsiSetDataCount(totalBytes);\r
784                 }\r
785 \r
786                 lastWriteSize = sectors;\r
787                 HAL_SD_WriteBlocks_DMA(&hsd, i + sdLBA, sectors);\r
788                 int j = 0;\r
789                 int prep = 0;\r
790                 int sdActive = 0;\r
791                 uint32_t dmaFinishTime = 0;\r
792                 while (j < sectors && !scsiDev.resetFlag)\r
793                 {\r
794                     if (sdActive &&\r
795                         HAL_SD_GetState(&hsd) != HAL_SD_STATE_BUSY &&\r
796                         !sdIsBusy())\r
797                     {\r
798                         j += sdActive;\r
799                         sdActive = 0;\r
800                     }\r
801                     if (!sdActive && ((prep - j) > 0))\r
802                     {\r
803                         // Start an SD transfer if we have space.\r
804                         HAL_SD_WriteBlocks_Data(&hsd, &scsiDev.data[SD_SECTOR_SIZE * (j % maxSectors)]);\r
805 \r
806                         sdActive = 1;\r
807                     }\r
808 \r
809                     if (((prep - j) < maxSectors) &&\r
810                         (prep < sectors) &&\r
811                         scsiFifoReady())\r
812                     {\r
813                         scsiReadPIO(\r
814                             &scsiDev.data[(prep % maxSectors) * SD_SECTOR_SIZE],\r
815                             SD_SECTOR_SIZE,\r
816                             &parityError);\r
817                         prep++;\r
818                         if (prep == sectors)\r
819                         {\r
820                             dmaFinishTime = s2s_getTime_ms();\r
821                         }\r
822                     }\r
823                 \r
824                     if (i + prep >= totalSDSectors &&\r
825                         !disconnected &&\r
826                         (!parityError || !enableParity) &&\r
827                         s2s_elapsedTime_ms(dmaFinishTime) >= 180)\r
828                     {\r
829                         // We're transferring over the SCSI bus faster than the SD card\r
830                         // can write.  All data is buffered, and we're just waiting for\r
831                         // the SD card to complete. The host won't let us disconnect.\r
832                         // Some drivers set a 250ms timeout on transfers to complete.\r
833                         // SD card writes are supposed to complete\r
834                         // within 200ms, but sometimes they don't.\r
835                         // Just pretend we're finished.\r
836                         process_Status();\r
837                         clearBSY = process_MessageIn(0); // Will go to BUS_FREE state but keep BSY asserted.\r
838                         disconnected = 1;\r
839                     }\r
840                 }\r
841 \r
842                 if (scsiDev.resetFlag)\r
843                 {\r
844                     HAL_SD_Abort(&hsd);\r
845                 }\r
846                 else\r
847                 {\r
848                     while (HAL_SD_GetState(&hsd) == HAL_SD_STATE_BUSY) {} // Waits for DMA to complete\r
849                     if (lastWriteSize > 1)\r
850                     {\r
851                         SDMMC_CmdStopTransfer(hsd.Instance);\r
852                     }\r
853                 }\r
854 \r
855                 while (sdIsBusy() &&\r
856                     s2s_elapsedTime_ms(dmaFinishTime) < 180)\r
857                 {\r
858                     // Wait while the SD card is writing buffer to flash\r
859                     // The card may remain in the RECEIVING state (even though it's programming) if\r
860                     // it has buffer space to receive more data available.\r
861                 }\r
862 \r
863                 if (!disconnected && \r
864                     i + sectors >= totalSDSectors &&\r
865                     (!parityError || !enableParity))\r
866                 {\r
867                     // We're transferring over the SCSI bus faster than the SD card\r
868                     // can write.  All data is buffered, and we're just waiting for\r
869                     // the SD card to complete. The host won't let us disconnect.\r
870                     // Some drivers set a 250ms timeout on transfers to complete.\r
871                     // SD card writes are supposed to complete\r
872                     // within 200ms, but sometimes they don't.\r
873                     // Just pretend we're finished.\r
874                     process_Status();\r
875                     clearBSY = process_MessageIn(0); // Will go to BUS_FREE state but keep BSY asserted.\r
876                 }\r
877 \r
878                 // Wait while the SD card is writing buffer to flash\r
879                 // The card may remain in the RECEIVING state (even though it's programming) if\r
880                 // it has buffer space to receive more data available.\r
881                 while (sdIsBusy()) {}\r
882                 HAL_SD_CardStateTypeDef cardState = HAL_SD_GetCardState(&hsd);\r
883                 while (cardState == HAL_SD_CARD_PROGRAMMING || cardState == HAL_SD_CARD_RECEIVING) \r
884                 {\r
885                     // Wait while the SD card is writing buffer to flash\r
886                     // The card may remain in the RECEIVING state (even though it's programming) if\r
887                     // it has buffer space to receive more data available.\r
888                     cardState = HAL_SD_GetCardState(&hsd);\r
889                 }\r
890 \r
891                 i += sectors;\r
892             }\r
893             else\r
894             {\r
895                 // Well, until we have some proper non-blocking SD code, we must\r
896                 // do this in a half-duplex fashion. We need to write as much as\r
897                 // possible in each SD card transaction.\r
898                 // use sg_dd from sg_utils3 tools to test.\r
899 \r
900                 uint32_t rem = totalSDSectors - i;\r
901                 uint32_t sectors;\r
902                 if (rem <= maxSectors)\r
903                 {\r
904                     sectors = rem;\r
905                 }\r
906                 else\r
907                 {\r
908                     sectors = maxSectors;\r
909                     while (sectors % sdPerScsi) sectors--;\r
910                 }\r
911                 \r
912 \r
913                 if (useSlowDataCount)\r
914                 {\r
915                     scsiSetDataCount((sectors / sdPerScsi) * bytesPerSector);\r
916                 }\r
917 \r
918                 for (int scsiSector = i; scsiSector < i + sectors; ++scsiSector)\r
919                 {\r
920                     int dmaBytes = SD_SECTOR_SIZE;\r
921                     if ((scsiSector % sdPerScsi) == (sdPerScsi - 1))\r
922                     {\r
923                         dmaBytes = bytesPerSector % SD_SECTOR_SIZE;\r
924                         if (dmaBytes == 0) dmaBytes = SD_SECTOR_SIZE;\r
925                     }\r
926 \r
927                     scsiReadPIO(&scsiDev.data[SD_SECTOR_SIZE * (scsiSector - i)], dmaBytes, &parityError);\r
928                 }\r
929                 if (!parityError || !enableParity)\r
930                 {\r
931                     BSP_SD_WriteBlocks_DMA(&scsiDev.data[0], i + sdLBA, sectors);\r
932                 }\r
933                 i += sectors;\r
934             }\r
935         }\r
936 \r
937         // Should already be complete here as we've ready the FIFOs\r
938         // by now. Check anyway.\r
939         __disable_irq();\r
940         while (!scsiPhyComplete() && likely(!scsiDev.resetFlag))\r
941         {\r
942             __WFI();\r
943         }\r
944         __enable_irq();\r
945 \r
946         if (clearBSY)\r
947         {\r
948             enter_BusFree();\r
949         }\r
950 \r
951         if (scsiDev.phase == DATA_OUT)\r
952         {\r
953             if (parityError &&\r
954                 (scsiDev.boardCfg.flags & S2S_CFG_ENABLE_PARITY))\r
955             {\r
956                 scsiDev.target->sense.code = ABORTED_COMMAND;\r
957                 scsiDev.target->sense.asc = SCSI_PARITY_ERROR;\r
958                 scsiDev.status = CHECK_CONDITION;;\r
959             }\r
960             scsiDev.phase = STATUS;\r
961         }\r
962         scsiDiskReset();\r
963     }\r
964 }\r
965 \r
966 void scsiDiskReset()\r
967 {\r
968     scsiDev.dataPtr = 0;\r
969     scsiDev.savedDataPtr = 0;\r
970     scsiDev.dataLen = 0;\r
971     // transfer.lba = 0; // Needed in Request Sense to determine failure\r
972     transfer.blocks = 0;\r
973     transfer.currentBlock = 0;\r
974 \r
975     // Cancel long running commands!\r
976 #if 0\r
977     if (\r
978         ((scsiDev.boardCfg.flags & S2S_CFG_ENABLE_CACHE) == 0) ||\r
979             (transfer.multiBlock == 0)\r
980         )\r
981 #endif\r
982     {\r
983         sdCompleteTransfer();\r
984     }\r
985 \r
986     transfer.multiBlock = 0;\r
987 }\r
988 \r
989 void scsiDiskInit()\r
990 {\r
991     scsiDiskReset();\r
992 }\r
993 \r