1 // Copyright (C) 2013 Michael McMaster <michael@codesrc.com>
\r
2 // Copyright (C) 2014 Doug Brown <doug@downtowndougbrown.com>
\r
4 // This file is part of SCSI2SD.
\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
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
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
19 #include "stm32f2xx.h"
\r
21 // For SD write direct routines
\r
23 #include "bsp_driver_sd.h"
\r
27 #include "scsiPhy.h"
\r
37 BlockDevice blockDev;
\r
40 static int doSdInit()
\r
43 if (blockDev.state & DISK_PRESENT)
\r
45 blockDev.state = blockDev.state | DISK_INITIALISED;
\r
50 // Callback once all data has been read in the data out phase.
\r
51 static void doFormatUnitComplete(void)
\r
53 // TODO start writing the initialisation pattern to the SD
\r
55 scsiDev.phase = STATUS;
\r
58 static void doFormatUnitSkipData(int bytes)
\r
60 // We may not have enough memory to store the initialisation pattern and
\r
61 // defect list data. Since we're not making use of it yet anyway, just
\r
62 // discard the bytes.
\r
63 scsiEnterPhase(DATA_OUT);
\r
65 for (i = 0; i < bytes; ++i)
\r
71 // Callback from the data out phase.
\r
72 static void doFormatUnitPatternHeader(void)
\r
75 ((((uint16_t)scsiDev.data[2])) << 8) +
\r
79 ((((uint16_t)scsiDev.data[4 + 2])) << 8) +
\r
80 scsiDev.data[4 + 3];
\r
82 doFormatUnitSkipData(defectLength + patternLength);
\r
83 doFormatUnitComplete();
\r
86 // Callback from the data out phase.
\r
87 static void doFormatUnitHeader(void)
\r
89 int IP = (scsiDev.data[1] & 0x08) ? 1 : 0;
\r
90 int DSP = (scsiDev.data[1] & 0x04) ? 1 : 0;
\r
92 if (! DSP) // disable save parameters
\r
94 // Save the "MODE SELECT savable parameters"
\r
96 scsiDev.target->targetId,
\r
97 scsiDev.target->liveCfg.bytesPerSector);
\r
102 // We need to read the initialisation pattern header first.
\r
103 scsiDev.dataLen += 4;
\r
104 scsiDev.phase = DATA_OUT;
\r
105 scsiDev.postDataOutHook = doFormatUnitPatternHeader;
\r
109 // Read the defect list data
\r
111 ((((uint16_t)scsiDev.data[2])) << 8) +
\r
113 doFormatUnitSkipData(defectLength);
\r
114 doFormatUnitComplete();
\r
118 static void doReadCapacity()
\r
120 uint32_t lba = (((uint32_t) scsiDev.cdb[2]) << 24) +
\r
121 (((uint32_t) scsiDev.cdb[3]) << 16) +
\r
122 (((uint32_t) scsiDev.cdb[4]) << 8) +
\r
124 int pmi = scsiDev.cdb[8] & 1;
\r
126 uint32_t capacity = getScsiCapacity(
\r
127 scsiDev.target->cfg->sdSectorStart,
\r
128 scsiDev.target->liveCfg.bytesPerSector,
\r
129 scsiDev.target->cfg->scsiSectors);
\r
134 // We don't do anything with the "partial medium indicator", and
\r
135 // assume that delays are constant across each block. But the spec
\r
136 // says we must return this error if pmi is specified incorrectly.
\r
137 scsiDev.status = CHECK_CONDITION;
\r
138 scsiDev.target->sense.code = ILLEGAL_REQUEST;
\r
139 scsiDev.target->sense.asc = INVALID_FIELD_IN_CDB;
\r
140 scsiDev.phase = STATUS;
\r
142 else if (capacity > 0)
\r
144 uint32_t highestBlock = capacity - 1;
\r
146 scsiDev.data[0] = highestBlock >> 24;
\r
147 scsiDev.data[1] = highestBlock >> 16;
\r
148 scsiDev.data[2] = highestBlock >> 8;
\r
149 scsiDev.data[3] = highestBlock;
\r
151 uint32_t bytesPerSector = scsiDev.target->liveCfg.bytesPerSector;
\r
152 scsiDev.data[4] = bytesPerSector >> 24;
\r
153 scsiDev.data[5] = bytesPerSector >> 16;
\r
154 scsiDev.data[6] = bytesPerSector >> 8;
\r
155 scsiDev.data[7] = bytesPerSector;
\r
156 scsiDev.dataLen = 8;
\r
157 scsiDev.phase = DATA_IN;
\r
161 scsiDev.status = CHECK_CONDITION;
\r
162 scsiDev.target->sense.code = NOT_READY;
\r
163 scsiDev.target->sense.asc = MEDIUM_NOT_PRESENT;
\r
164 scsiDev.phase = STATUS;
\r
168 static void doWrite(uint32_t lba, uint32_t blocks)
\r
170 if (unlikely(scsiDev.target->cfg->deviceType == S2S_CFG_FLOPPY_14MB)) {
\r
171 // Floppies are supposed to be slow. Some systems can't handle a floppy
\r
172 // without an access time
\r
176 uint32_t bytesPerSector = scsiDev.target->liveCfg.bytesPerSector;
\r
178 if (unlikely(blockDev.state & DISK_WP) ||
\r
179 unlikely(scsiDev.target->cfg->deviceType == S2S_CFG_OPTICAL))
\r
182 scsiDev.status = CHECK_CONDITION;
\r
183 scsiDev.target->sense.code = ILLEGAL_REQUEST;
\r
184 scsiDev.target->sense.asc = WRITE_PROTECTED;
\r
185 scsiDev.phase = STATUS;
\r
187 else if (unlikely(((uint64_t) lba) + blocks >
\r
189 scsiDev.target->cfg->sdSectorStart,
\r
191 scsiDev.target->cfg->scsiSectors
\r
195 scsiDev.status = CHECK_CONDITION;
\r
196 scsiDev.target->sense.code = ILLEGAL_REQUEST;
\r
197 scsiDev.target->sense.asc = LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
\r
198 scsiDev.phase = STATUS;
\r
202 transfer.lba = lba;
\r
203 transfer.blocks = blocks;
\r
204 transfer.currentBlock = 0;
\r
205 scsiDev.phase = DATA_OUT;
\r
206 scsiDev.dataLen = bytesPerSector;
\r
207 scsiDev.dataPtr = bytesPerSector;
\r
209 // No need for single-block writes atm. Overhead of the
\r
210 // multi-block write is minimal.
\r
211 transfer.multiBlock = 1;
\r
214 // TODO uint32_t sdLBA =
\r
215 // TODO SCSISector2SD(
\r
216 // TODO scsiDev.target->cfg->sdSectorStart,
\r
217 // TODO bytesPerSector,
\r
219 // TODO uint32_t sdBlocks = blocks * SDSectorsPerSCSISector(bytesPerSector);
\r
220 // TODO sdWriteMultiSectorPrep(sdLBA, sdBlocks);
\r
225 static void doRead(uint32_t lba, uint32_t blocks)
\r
227 if (unlikely(scsiDev.target->cfg->deviceType == S2S_CFG_FLOPPY_14MB)) {
\r
228 // Floppies are supposed to be slow. Some systems can't handle a floppy
\r
229 // without an access time
\r
233 uint32_t capacity = getScsiCapacity(
\r
234 scsiDev.target->cfg->sdSectorStart,
\r
235 scsiDev.target->liveCfg.bytesPerSector,
\r
236 scsiDev.target->cfg->scsiSectors);
\r
237 if (unlikely(((uint64_t) lba) + blocks > capacity))
\r
239 scsiDev.status = CHECK_CONDITION;
\r
240 scsiDev.target->sense.code = ILLEGAL_REQUEST;
\r
241 scsiDev.target->sense.asc = LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
\r
242 scsiDev.phase = STATUS;
\r
246 transfer.lba = lba;
\r
247 transfer.blocks = blocks;
\r
248 transfer.currentBlock = 0;
\r
249 scsiDev.phase = DATA_IN;
\r
250 scsiDev.dataLen = 0; // No data yet
\r
252 uint32_t bytesPerSector = scsiDev.target->liveCfg.bytesPerSector;
\r
253 uint32_t sdSectorPerSCSISector = SDSectorsPerSCSISector(bytesPerSector);
\r
254 uint32_t sdSectors =
\r
255 blocks * sdSectorPerSCSISector;
\r
258 (sdSectors == 1) &&
\r
259 !(scsiDev.boardCfg.flags & S2S_CFG_ENABLE_CACHE)
\r
261 unlikely(((uint64_t) lba) + blocks == capacity)
\r
264 // We get errors on reading the last sector using a multi-sector
\r
266 transfer.multiBlock = 0;
\r
270 transfer.multiBlock = 1;
\r
272 // uint32_t sdLBA =
\r
274 // scsiDev.target->cfg->sdSectorStart,
\r
278 // TODO sdReadMultiSectorPrep(sdLBA, sdSectors);
\r
283 static void doSeek(uint32_t lba)
\r
287 scsiDev.target->cfg->sdSectorStart,
\r
288 scsiDev.target->liveCfg.bytesPerSector,
\r
289 scsiDev.target->cfg->scsiSectors)
\r
292 scsiDev.status = CHECK_CONDITION;
\r
293 scsiDev.target->sense.code = ILLEGAL_REQUEST;
\r
294 scsiDev.target->sense.asc = LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
\r
295 scsiDev.phase = STATUS;
\r
299 static int doTestUnitReady()
\r
302 if (likely(blockDev.state == (DISK_STARTED | DISK_PRESENT | DISK_INITIALISED)))
\r
306 else if (unlikely(!(blockDev.state & DISK_STARTED)))
\r
309 scsiDev.status = CHECK_CONDITION;
\r
310 scsiDev.target->sense.code = NOT_READY;
\r
311 scsiDev.target->sense.asc = LOGICAL_UNIT_NOT_READY_INITIALIZING_COMMAND_REQUIRED;
\r
312 scsiDev.phase = STATUS;
\r
314 else if (unlikely(!(blockDev.state & DISK_PRESENT)))
\r
317 scsiDev.status = CHECK_CONDITION;
\r
318 scsiDev.target->sense.code = NOT_READY;
\r
319 scsiDev.target->sense.asc = MEDIUM_NOT_PRESENT;
\r
320 scsiDev.phase = STATUS;
\r
322 else if (unlikely(!(blockDev.state & DISK_INITIALISED)))
\r
325 scsiDev.status = CHECK_CONDITION;
\r
326 scsiDev.target->sense.code = NOT_READY;
\r
327 scsiDev.target->sense.asc = LOGICAL_UNIT_NOT_READY_CAUSE_NOT_REPORTABLE;
\r
328 scsiDev.phase = STATUS;
\r
333 // Handle direct-access scsi device commands
\r
334 int scsiDiskCommand()
\r
336 int commandHandled = 1;
\r
338 uint8_t command = scsiDev.cdb[0];
\r
339 if (unlikely(command == 0x1B))
\r
342 // Enable or disable media access operations.
\r
343 // Ignore load/eject requests. We can't do that.
\r
344 //int immed = scsiDev.cdb[1] & 1;
\r
345 int start = scsiDev.cdb[4] & 1;
\r
349 blockDev.state = blockDev.state | DISK_STARTED;
\r
350 if (!(blockDev.state & DISK_INITIALISED))
\r
357 blockDev.state &= ~DISK_STARTED;
\r
360 else if (unlikely(command == 0x00))
\r
365 else if (unlikely(!doTestUnitReady()))
\r
367 // Status and sense codes already set by doTestUnitReady
\r
369 else if (likely(command == 0x08))
\r
373 (((uint32_t) scsiDev.cdb[1] & 0x1F) << 16) +
\r
374 (((uint32_t) scsiDev.cdb[2]) << 8) +
\r
376 uint32_t blocks = scsiDev.cdb[4];
\r
377 if (unlikely(blocks == 0)) blocks = 256;
\r
378 doRead(lba, blocks);
\r
380 else if (likely(command == 0x28))
\r
383 // Ignore all cache control bits - we don't support a memory cache.
\r
386 (((uint32_t) scsiDev.cdb[2]) << 24) +
\r
387 (((uint32_t) scsiDev.cdb[3]) << 16) +
\r
388 (((uint32_t) scsiDev.cdb[4]) << 8) +
\r
391 (((uint32_t) scsiDev.cdb[7]) << 8) +
\r
394 doRead(lba, blocks);
\r
396 else if (likely(command == 0x0A))
\r
400 (((uint32_t) scsiDev.cdb[1] & 0x1F) << 16) +
\r
401 (((uint32_t) scsiDev.cdb[2]) << 8) +
\r
403 uint32_t blocks = scsiDev.cdb[4];
\r
404 if (unlikely(blocks == 0)) blocks = 256;
\r
405 doWrite(lba, blocks);
\r
407 else if (likely(command == 0x2A) || // WRITE(10)
\r
408 unlikely(command == 0x2E)) // WRITE AND VERIFY
\r
410 // Ignore all cache control bits - we don't support a memory cache.
\r
411 // Don't bother verifying either. The SD card likely stores ECC
\r
412 // along with each flash row.
\r
415 (((uint32_t) scsiDev.cdb[2]) << 24) +
\r
416 (((uint32_t) scsiDev.cdb[3]) << 16) +
\r
417 (((uint32_t) scsiDev.cdb[4]) << 8) +
\r
420 (((uint32_t) scsiDev.cdb[7]) << 8) +
\r
423 doWrite(lba, blocks);
\r
425 else if (unlikely(command == 0x04))
\r
428 // We don't really do any formatting, but we need to read the correct
\r
429 // number of bytes in the DATA_OUT phase to make the SCSI host happy.
\r
431 int fmtData = (scsiDev.cdb[1] & 0x10) ? 1 : 0;
\r
434 // We need to read the parameter list, but we don't know how
\r
435 // big it is yet. Start with the header.
\r
436 scsiDev.dataLen = 4;
\r
437 scsiDev.phase = DATA_OUT;
\r
438 scsiDev.postDataOutHook = doFormatUnitHeader;
\r
442 // No data to read, we're already finished!
\r
445 else if (unlikely(command == 0x25))
\r
450 else if (unlikely(command == 0x0B))
\r
454 (((uint32_t) scsiDev.cdb[1] & 0x1F) << 16) +
\r
455 (((uint32_t) scsiDev.cdb[2]) << 8) +
\r
461 else if (unlikely(command == 0x2B))
\r
465 (((uint32_t) scsiDev.cdb[2]) << 24) +
\r
466 (((uint32_t) scsiDev.cdb[3]) << 16) +
\r
467 (((uint32_t) scsiDev.cdb[4]) << 8) +
\r
472 else if (unlikely(command == 0x36))
\r
474 // LOCK UNLOCK CACHE
\r
475 // We don't have a cache to lock data into. do nothing.
\r
477 else if (unlikely(command == 0x34))
\r
480 // We don't have a cache to pre-fetch into. do nothing.
\r
482 else if (unlikely(command == 0x1E))
\r
484 // PREVENT ALLOW MEDIUM REMOVAL
\r
485 // Not much we can do to prevent the user removing the SD card.
\r
488 else if (unlikely(command == 0x01))
\r
491 // Set the lun to a vendor-specific state. Ignore.
\r
493 else if (unlikely(command == 0x35))
\r
495 // SYNCHRONIZE CACHE
\r
496 // We don't have a cache. do nothing.
\r
498 else if (unlikely(command == 0x2F))
\r
501 // TODO: When they supply data to verify, we should read the data and
\r
502 // verify it. If they don't supply any data, just say success.
\r
503 if ((scsiDev.cdb[1] & 0x02) == 0)
\r
505 // They are asking us to do a medium verification with no data
\r
506 // comparison. Assume success, do nothing.
\r
510 // TODO. This means they are supplying data to verify against.
\r
511 // Technically we should probably grab the data and compare it.
\r
512 scsiDev.status = CHECK_CONDITION;
\r
513 scsiDev.target->sense.code = ILLEGAL_REQUEST;
\r
514 scsiDev.target->sense.asc = INVALID_FIELD_IN_CDB;
\r
515 scsiDev.phase = STATUS;
\r
518 else if (unlikely(command == 0x37))
\r
520 // READ DEFECT DATA
\r
521 scsiDev.status = CHECK_CONDITION;
\r
522 scsiDev.target->sense.code = NO_SENSE;
\r
523 scsiDev.target->sense.asc = DEFECT_LIST_NOT_FOUND;
\r
524 scsiDev.phase = STATUS;
\r
529 commandHandled = 0;
\r
532 return commandHandled;
\r
535 void scsiDiskPoll()
\r
537 uint32_t bytesPerSector = scsiDev.target->liveCfg.bytesPerSector;
\r
539 if (scsiDev.phase == DATA_IN &&
\r
540 transfer.currentBlock != transfer.blocks)
\r
543 int totalSDSectors =
\r
544 transfer.blocks * SDSectorsPerSCSISector(bytesPerSector);
\r
547 scsiDev.target->cfg->sdSectorStart,
\r
551 const int sdPerScsi = SDSectorsPerSCSISector(bytesPerSector);
\r
552 const int buffers = sizeof(scsiDev.data) / SD_SECTOR_SIZE;
\r
555 int scsiActive __attribute__((unused)) = 0; // unused if DMA disabled
\r
558 uint32_t partialScsiChunk = 0;
\r
560 // Start reading from the SD card FIRST, because we change state and
\r
561 // wai for SCSI signals
\r
562 int dataInStarted = 0;
\r
564 while ((i < totalSDSectors) &&
\r
565 (!dataInStarted || likely(scsiDev.phase == DATA_IN)) &&
\r
566 likely(!scsiDev.resetFlag))
\r
568 int completedDmaSectors;
\r
569 if (sdActive && (completedDmaSectors = sdReadDMAPoll(sdActive)))
\r
571 prep += completedDmaSectors;
\r
572 sdActive -= completedDmaSectors;
\r
573 } else if (sdActive > 1)
\r
575 if ((scsiDev.data[SD_SECTOR_SIZE * (prep % buffers) + 510] != 0xAA) ||
\r
576 (scsiDev.data[SD_SECTOR_SIZE * (prep % buffers) + 511] != 0x33))
\r
584 (prep - i < buffers) &&
\r
585 (prep < totalSDSectors))
\r
587 // Start an SD transfer if we have space.
\r
588 uint32_t startBuffer = prep % buffers;
\r
589 uint32_t sectors = totalSDSectors - prep;
\r
591 uint32_t freeBuffers = buffers - (prep - i);
\r
593 uint32_t contiguousBuffers = buffers - startBuffer;
\r
594 freeBuffers = freeBuffers < contiguousBuffers
\r
595 ? freeBuffers : contiguousBuffers;
\r
596 sectors = sectors < freeBuffers ? sectors : freeBuffers;
\r
598 if (sectors > 128) sectors = 128; // 65536 DMA limit !!
\r
600 for (int dodgy = 0; dodgy < sectors; dodgy++)
\r
602 scsiDev.data[SD_SECTOR_SIZE * (startBuffer + dodgy) + 510] = 0xAA;
\r
603 scsiDev.data[SD_SECTOR_SIZE * (startBuffer + dodgy) + 511] = 0x33;
\r
606 sdReadDMA(sdLBA + prep, sectors, &scsiDev.data[SD_SECTOR_SIZE * startBuffer]);
\r
608 sdActive = sectors;
\r
610 if (!dataInStarted)
\r
613 scsiEnterPhase(DATA_IN); // Will wait a few microseconds.
\r
617 #ifdef SCSI_FSMC_DMA
\r
618 #error this code not updated for 256 max bytes in scsi fifo
\r
619 if (scsiActive && scsiPhyComplete() && scsiWriteDMAPoll())
\r
625 if (!scsiActive && ((prep - i) > 0))
\r
627 int dmaBytes = SD_SECTOR_SIZE;
\r
628 if ((i % sdPerScsi) == (sdPerScsi - 1))
\r
630 dmaBytes = bytesPerSector % SD_SECTOR_SIZE;
\r
631 if (dmaBytes == 0) dmaBytes = SD_SECTOR_SIZE;
\r
633 scsiWriteDMA(&scsiDev.data[SD_SECTOR_SIZE * (i % buffers)], dmaBytes);
\r
637 if ((prep - i) > 0)
\r
639 int dmaBytes = SD_SECTOR_SIZE;
\r
640 if ((i % sdPerScsi) == (sdPerScsi - 1))
\r
642 dmaBytes = bytesPerSector % SD_SECTOR_SIZE;
\r
643 if (dmaBytes == 0) dmaBytes = SD_SECTOR_SIZE;
\r
646 // Manually unrolled loop for performance.
\r
647 // -Os won't unroll this for us automatically,
\r
648 // especially since scsiPhyTx does volatile stuff.
\r
649 // Reduces bus utilisation by making the fsmc split
\r
650 // 32bits into 2 16 bit writes.
\r
652 uint16_t* scsiDmaData = (uint16_t*) &(scsiDev.data[SD_SECTOR_SIZE * (i % buffers) + partialScsiChunk]);
\r
654 uint32_t chunk = ((dmaBytes - partialScsiChunk) > SCSI_FIFO_DEPTH)
\r
655 ? SCSI_FIFO_DEPTH : (dmaBytes - partialScsiChunk);
\r
658 for (; k + 4 < (chunk + 1) / 2; k += 4)
\r
660 scsiPhyTx32(scsiDmaData[k], scsiDmaData[k+1]);
\r
661 scsiPhyTx32(scsiDmaData[k+2], scsiDmaData[k+3]);
\r
663 for (; k < (chunk + 1) / 2; ++k)
\r
665 scsiPhyTx(scsiDmaData[k]);
\r
667 while (!scsiPhyComplete() && !scsiDev.resetFlag)
\r
669 __WFE(); // Wait for event
\r
672 scsiSetDataCount(chunk);
\r
674 partialScsiChunk += chunk;
\r
675 if (partialScsiChunk == dmaBytes)
\r
677 partialScsiChunk = 0;
\r
684 if (!dataInStarted && !scsiDev.resetFlag) // zero bytes ?
\r
686 scsiEnterPhase(DATA_IN); // Will wait a few microseconds.
\r
689 // We've finished transferring the data to the FPGA, now wait until it's
\r
690 // written to he SCSI bus.
\r
691 while (!scsiPhyComplete() &&
\r
692 likely(scsiDev.phase == DATA_IN) &&
\r
693 likely(!scsiDev.resetFlag))
\r
695 __WFE(); // Wait for event
\r
699 if (scsiDev.phase == DATA_IN)
\r
701 scsiDev.phase = STATUS;
\r
705 else if (scsiDev.phase == DATA_OUT &&
\r
706 transfer.currentBlock != transfer.blocks)
\r
708 scsiEnterPhase(DATA_OUT);
\r
710 const int sdPerScsi = SDSectorsPerSCSISector(bytesPerSector);
\r
711 int totalSDSectors = transfer.blocks * sdPerScsi;
\r
714 scsiDev.target->cfg->sdSectorStart,
\r
720 int parityError = 0;
\r
721 int enableParity = scsiDev.boardCfg.flags & S2S_CFG_ENABLE_PARITY;
\r
723 while ((i < totalSDSectors) &&
\r
724 likely(scsiDev.phase == DATA_OUT) &&
\r
725 likely(!scsiDev.resetFlag) &&
\r
726 likely(!parityError || !enableParity))
\r
728 // Well, until we have some proper non-blocking SD code, we must
\r
729 // do this in a half-duplex fashion. We need to write as much as
\r
730 // possible in each SD card transaction.
\r
731 uint32_t maxSectors = sizeof(scsiDev.data) / SD_SECTOR_SIZE;
\r
732 uint32_t rem = totalSDSectors - i;
\r
734 rem < maxSectors ? rem : maxSectors;
\r
736 if (bytesPerSector == SD_SECTOR_SIZE)
\r
738 // We assume the SD card is faster than the SCSI interface, but has
\r
739 // no flow control. This can be handled if a) the scsi interface
\r
740 // doesn't block and b) we read enough SCSI sectors first so that
\r
741 // the SD interface cannot catch up.
\r
742 uint32_t totalBytes = sectors * SD_SECTOR_SIZE;
\r
743 uint32_t readAheadBytes = sectors * SD_SECTOR_SIZE;
\r
744 uint32_t sdSpeed = s2s_getSdRateMBs() + (scsiDev.sdUnderrunCount / 2);
\r
745 uint32_t scsiSpeed = s2s_getScsiRateMBs();
\r
746 // if (have blind writes)
\r
747 if (scsiSpeed > 0 && scsiDev.sdUnderrunCount < 16)
\r
749 // readAhead = sectors * (sd / scsi - 1 + 0.1);
\r
750 readAheadBytes = totalBytes * sdSpeed / scsiSpeed - totalBytes + SCSI_FIFO_DEPTH;
\r
751 if (readAheadBytes < SCSI_FIFO_DEPTH)
\r
753 readAheadBytes = SCSI_FIFO_DEPTH;
\r
756 if (readAheadBytes > totalBytes)
\r
758 readAheadBytes = totalBytes;
\r
762 uint32_t chunk = (readAheadBytes > SCSI_FIFO_DEPTH) ? SCSI_FIFO_DEPTH : readAheadBytes;
\r
763 scsiSetDataCount(chunk);
\r
765 uint32_t scsiBytesRead = 0;
\r
766 while (scsiBytesRead < readAheadBytes)
\r
768 while (!scsiPhyComplete() && likely(!scsiDev.resetFlag))
\r
770 __WFE(); // Wait for event
\r
772 parityError |= scsiParityError();
\r
774 uint32_t nextChunk = ((totalBytes - scsiBytesRead - chunk) > SCSI_FIFO_DEPTH)
\r
775 ? SCSI_FIFO_DEPTH : (totalBytes - scsiBytesRead - chunk);
\r
777 if (nextChunk > 0) scsiSetDataCount(nextChunk);
\r
778 scsiReadPIO(&scsiDev.data[scsiBytesRead], chunk);
\r
779 scsiBytesRead += chunk;
\r
783 HAL_SD_WriteBlocks_DMA(&hsd, (uint32_t*) (&scsiDev.data[0]), (i + sdLBA) * 512ll, SD_SECTOR_SIZE, sectors);
\r
785 while (scsiBytesRead < totalBytes)
\r
787 while (!scsiPhyComplete() && likely(!scsiDev.resetFlag))
\r
789 __WFE(); // Wait for event
\r
791 parityError |= scsiParityError();
\r
793 uint32_t nextChunk = ((totalBytes - scsiBytesRead - chunk) > SCSI_FIFO_DEPTH)
\r
794 ? SCSI_FIFO_DEPTH : (totalBytes - scsiBytesRead - chunk);
\r
796 if (nextChunk > 0) scsiSetDataCount(nextChunk);
\r
797 scsiReadPIO(&scsiDev.data[scsiBytesRead], chunk);
\r
798 scsiBytesRead += chunk;
\r
802 // Oh dear, SD finished first.
\r
803 int underrun = totalBytes > readAheadBytes && hsd.DmaTransferCplt;
\r
805 uint32_t dmaFinishTime = s2s_getTime_ms();
\r
806 while (!hsd.SdTransferCplt &&
\r
807 s2s_elapsedTime_ms(dmaFinishTime) < 180)
\r
809 // Wait while keeping BSY.
\r
811 while((__HAL_SD_SDIO_GET_FLAG(&hsd, SDIO_FLAG_TXACT)) &&
\r
812 s2s_elapsedTime_ms(dmaFinishTime) < 180)
\r
814 // Wait for SD card while keeping BSY.
\r
817 if (i + sectors >= totalSDSectors &&
\r
819 (!parityError || !enableParity))
\r
821 // We're transferring over the SCSI bus faster than the SD card
\r
822 // can write. All data is buffered, and we're just waiting for
\r
823 // the SD card to complete. The host won't let us disconnect.
\r
824 // Some drivers set a 250ms timeout on transfers to complete.
\r
825 // SD card writes are supposed to complete
\r
826 // within 200ms, but sometimes they don't.
\r
827 // Just pretend we're finished.
\r
829 clearBSY = process_MessageIn(0); // Will go to BUS_FREE state but keep BSY asserted.
\r
832 HAL_SD_CheckWriteOperation(&hsd, (uint32_t)SD_DATATIMEOUT);
\r
836 // Try again. Data is still in memory.
\r
837 sdTmpWrite(&scsiDev.data[0], i + sdLBA, sectors);
\r
838 scsiDev.sdUnderrunCount++;
\r
845 // Well, until we have some proper non-blocking SD code, we must
\r
846 // do this in a half-duplex fashion. We need to write as much as
\r
847 // possible in each SD card transaction.
\r
848 // use sg_dd from sg_utils3 tools to test.
\r
849 uint32_t maxSectors = sizeof(scsiDev.data) / SD_SECTOR_SIZE;
\r
850 uint32_t rem = totalSDSectors - i;
\r
851 uint32_t sectors = rem < maxSectors ? rem : maxSectors;
\r
853 for (scsiSector = i; scsiSector < i + sectors; ++scsiSector)
\r
855 int dmaBytes = SD_SECTOR_SIZE;
\r
856 if ((scsiSector % sdPerScsi) == (sdPerScsi - 1))
\r
858 dmaBytes = bytesPerSector % SD_SECTOR_SIZE;
\r
859 if (dmaBytes == 0) dmaBytes = SD_SECTOR_SIZE;
\r
861 scsiRead(&scsiDev.data[SD_SECTOR_SIZE * (scsiSector - i)], dmaBytes, &parityError);
\r
865 sdTmpWrite(&scsiDev.data[0], i + sdLBA, sectors);
\r
876 if (scsiDev.phase == DATA_OUT)
\r
879 (scsiDev.boardCfg.flags & S2S_CFG_ENABLE_PARITY))
\r
881 scsiDev.target->sense.code = ABORTED_COMMAND;
\r
882 scsiDev.target->sense.asc = SCSI_PARITY_ERROR;
\r
883 scsiDev.status = CHECK_CONDITION;;
\r
885 scsiDev.phase = STATUS;
\r
891 void scsiDiskReset()
\r
893 scsiDev.dataPtr = 0;
\r
894 scsiDev.savedDataPtr = 0;
\r
895 scsiDev.dataLen = 0;
\r
896 // transfer.lba = 0; // Needed in Request Sense to determine failure
\r
897 transfer.blocks = 0;
\r
898 transfer.currentBlock = 0;
\r
900 // Cancel long running commands!
\r
903 ((scsiDev.boardCfg.flags & S2S_CFG_ENABLE_CACHE) == 0) ||
\r
904 (transfer.multiBlock == 0)
\r
908 sdCompleteTransfer();
\r
911 transfer.multiBlock = 0;
\r
914 void scsiDiskInit()
\r
918 // Don't require the host to send us a START STOP UNIT command
\r
919 blockDev.state = DISK_STARTED;
\r