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
20 #include "scsiPhy.h"
\r
29 BlockDevice blockDev;
\r
32 static int doSdInit()
\r
35 if (blockDev.state & DISK_PRESENT)
\r
37 blockDev.state = blockDev.state | DISK_INITIALISED;
\r
42 // Callback once all data has been read in the data out phase.
\r
43 static void doFormatUnitComplete(void)
\r
45 // TODO start writing the initialisation pattern to the SD
\r
47 scsiDev.phase = STATUS;
\r
50 static void doFormatUnitSkipData(int bytes)
\r
52 // We may not have enough memory to store the initialisation pattern and
\r
53 // defect list data. Since we're not making use of it yet anyway, just
\r
54 // discard the bytes.
\r
55 scsiEnterPhase(DATA_OUT);
\r
57 for (i = 0; i < bytes; ++i)
\r
63 // Callback from the data out phase.
\r
64 static void doFormatUnitPatternHeader(void)
\r
67 ((((uint16_t)scsiDev.data[2])) << 8) +
\r
71 ((((uint16_t)scsiDev.data[4 + 2])) << 8) +
\r
72 scsiDev.data[4 + 3];
\r
74 doFormatUnitSkipData(defectLength + patternLength);
\r
75 doFormatUnitComplete();
\r
78 // Callback from the data out phase.
\r
79 static void doFormatUnitHeader(void)
\r
81 int IP = (scsiDev.data[1] & 0x08) ? 1 : 0;
\r
82 int DSP = (scsiDev.data[1] & 0x04) ? 1 : 0;
\r
84 if (! DSP) // disable save parameters
\r
86 // Save the "MODE SELECT savable parameters"
\r
88 scsiDev.target->targetId,
\r
89 scsiDev.target->liveCfg.bytesPerSector);
\r
94 // We need to read the initialisation pattern header first.
\r
95 scsiDev.dataLen += 4;
\r
96 scsiDev.phase = DATA_OUT;
\r
97 scsiDev.postDataOutHook = doFormatUnitPatternHeader;
\r
101 // Read the defect list data
\r
103 ((((uint16_t)scsiDev.data[2])) << 8) +
\r
105 doFormatUnitSkipData(defectLength);
\r
106 doFormatUnitComplete();
\r
110 static void doReadCapacity()
\r
112 uint32_t lba = (((uint32_t) scsiDev.cdb[2]) << 24) +
\r
113 (((uint32_t) scsiDev.cdb[3]) << 16) +
\r
114 (((uint32_t) scsiDev.cdb[4]) << 8) +
\r
116 int pmi = scsiDev.cdb[8] & 1;
\r
118 uint32_t capacity = getScsiCapacity(
\r
119 scsiDev.target->cfg->sdSectorStart,
\r
120 scsiDev.target->liveCfg.bytesPerSector,
\r
121 scsiDev.target->cfg->scsiSectors);
\r
126 // We don't do anything with the "partial medium indicator", and
\r
127 // assume that delays are constant across each block. But the spec
\r
128 // says we must return this error if pmi is specified incorrectly.
\r
129 scsiDev.status = CHECK_CONDITION;
\r
130 scsiDev.target->sense.code = ILLEGAL_REQUEST;
\r
131 scsiDev.target->sense.asc = INVALID_FIELD_IN_CDB;
\r
132 scsiDev.phase = STATUS;
\r
134 else if (capacity > 0)
\r
136 uint32_t highestBlock = capacity - 1;
\r
138 scsiDev.data[0] = highestBlock >> 24;
\r
139 scsiDev.data[1] = highestBlock >> 16;
\r
140 scsiDev.data[2] = highestBlock >> 8;
\r
141 scsiDev.data[3] = highestBlock;
\r
143 uint32_t bytesPerSector = scsiDev.target->liveCfg.bytesPerSector;
\r
144 scsiDev.data[4] = bytesPerSector >> 24;
\r
145 scsiDev.data[5] = bytesPerSector >> 16;
\r
146 scsiDev.data[6] = bytesPerSector >> 8;
\r
147 scsiDev.data[7] = bytesPerSector;
\r
148 scsiDev.dataLen = 8;
\r
149 scsiDev.phase = DATA_IN;
\r
153 scsiDev.status = CHECK_CONDITION;
\r
154 scsiDev.target->sense.code = NOT_READY;
\r
155 scsiDev.target->sense.asc = MEDIUM_NOT_PRESENT;
\r
156 scsiDev.phase = STATUS;
\r
160 static void doWrite(uint32_t lba, uint32_t blocks)
\r
162 if (unlikely(scsiDev.target->cfg->deviceType == S2S_CFG_FLOPPY_14MB)) {
\r
163 // Floppies are supposed to be slow. Some systems can't handle a floppy
\r
164 // without an access time
\r
168 uint32_t bytesPerSector = scsiDev.target->liveCfg.bytesPerSector;
\r
170 if (unlikely(blockDev.state & DISK_WP) ||
\r
171 unlikely(scsiDev.target->cfg->deviceType == S2S_CFG_OPTICAL))
\r
174 scsiDev.status = CHECK_CONDITION;
\r
175 scsiDev.target->sense.code = ILLEGAL_REQUEST;
\r
176 scsiDev.target->sense.asc = WRITE_PROTECTED;
\r
177 scsiDev.phase = STATUS;
\r
179 else if (unlikely(((uint64_t) lba) + blocks >
\r
181 scsiDev.target->cfg->sdSectorStart,
\r
183 scsiDev.target->cfg->scsiSectors
\r
187 scsiDev.status = CHECK_CONDITION;
\r
188 scsiDev.target->sense.code = ILLEGAL_REQUEST;
\r
189 scsiDev.target->sense.asc = LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
\r
190 scsiDev.phase = STATUS;
\r
194 transfer.lba = lba;
\r
195 transfer.blocks = blocks;
\r
196 transfer.currentBlock = 0;
\r
197 scsiDev.phase = DATA_OUT;
\r
198 scsiDev.dataLen = bytesPerSector;
\r
199 scsiDev.dataPtr = bytesPerSector;
\r
201 // No need for single-block writes atm. Overhead of the
\r
202 // multi-block write is minimal.
\r
203 transfer.multiBlock = 1;
\r
206 // TODO uint32_t sdLBA =
\r
207 // TODO SCSISector2SD(
\r
208 // TODO scsiDev.target->cfg->sdSectorStart,
\r
209 // TODO bytesPerSector,
\r
211 // TODO uint32_t sdBlocks = blocks * SDSectorsPerSCSISector(bytesPerSector);
\r
212 // TODO sdWriteMultiSectorPrep(sdLBA, sdBlocks);
\r
217 static void doRead(uint32_t lba, uint32_t blocks)
\r
219 if (unlikely(scsiDev.target->cfg->deviceType == S2S_CFG_FLOPPY_14MB)) {
\r
220 // Floppies are supposed to be slow. Some systems can't handle a floppy
\r
221 // without an access time
\r
225 uint32_t capacity = getScsiCapacity(
\r
226 scsiDev.target->cfg->sdSectorStart,
\r
227 scsiDev.target->liveCfg.bytesPerSector,
\r
228 scsiDev.target->cfg->scsiSectors);
\r
229 if (unlikely(((uint64_t) lba) + blocks > capacity))
\r
231 scsiDev.status = CHECK_CONDITION;
\r
232 scsiDev.target->sense.code = ILLEGAL_REQUEST;
\r
233 scsiDev.target->sense.asc = LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
\r
234 scsiDev.phase = STATUS;
\r
238 transfer.lba = lba;
\r
239 transfer.blocks = blocks;
\r
240 transfer.currentBlock = 0;
\r
241 scsiDev.phase = DATA_IN;
\r
242 scsiDev.dataLen = 0; // No data yet
\r
244 uint32_t bytesPerSector = scsiDev.target->liveCfg.bytesPerSector;
\r
245 uint32_t sdSectorPerSCSISector = SDSectorsPerSCSISector(bytesPerSector);
\r
246 uint32_t sdSectors =
\r
247 blocks * sdSectorPerSCSISector;
\r
250 (sdSectors == 1) &&
\r
251 !(scsiDev.boardCfg.flags & S2S_CFG_ENABLE_CACHE)
\r
253 unlikely(((uint64_t) lba) + blocks == capacity)
\r
256 // We get errors on reading the last sector using a multi-sector
\r
258 transfer.multiBlock = 0;
\r
262 transfer.multiBlock = 1;
\r
264 // uint32_t sdLBA =
\r
266 // scsiDev.target->cfg->sdSectorStart,
\r
270 // TODO sdReadMultiSectorPrep(sdLBA, sdSectors);
\r
275 static void doSeek(uint32_t lba)
\r
279 scsiDev.target->cfg->sdSectorStart,
\r
280 scsiDev.target->liveCfg.bytesPerSector,
\r
281 scsiDev.target->cfg->scsiSectors)
\r
284 scsiDev.status = CHECK_CONDITION;
\r
285 scsiDev.target->sense.code = ILLEGAL_REQUEST;
\r
286 scsiDev.target->sense.asc = LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
\r
287 scsiDev.phase = STATUS;
\r
291 static int doTestUnitReady()
\r
294 if (likely(blockDev.state == (DISK_STARTED | DISK_PRESENT | DISK_INITIALISED)))
\r
298 else if (unlikely(!(blockDev.state & DISK_STARTED)))
\r
301 scsiDev.status = CHECK_CONDITION;
\r
302 scsiDev.target->sense.code = NOT_READY;
\r
303 scsiDev.target->sense.asc = LOGICAL_UNIT_NOT_READY_INITIALIZING_COMMAND_REQUIRED;
\r
304 scsiDev.phase = STATUS;
\r
306 else if (unlikely(!(blockDev.state & DISK_PRESENT)))
\r
309 scsiDev.status = CHECK_CONDITION;
\r
310 scsiDev.target->sense.code = NOT_READY;
\r
311 scsiDev.target->sense.asc = MEDIUM_NOT_PRESENT;
\r
312 scsiDev.phase = STATUS;
\r
314 else if (unlikely(!(blockDev.state & DISK_INITIALISED)))
\r
317 scsiDev.status = CHECK_CONDITION;
\r
318 scsiDev.target->sense.code = NOT_READY;
\r
319 scsiDev.target->sense.asc = LOGICAL_UNIT_NOT_READY_CAUSE_NOT_REPORTABLE;
\r
320 scsiDev.phase = STATUS;
\r
325 // Handle direct-access scsi device commands
\r
326 int scsiDiskCommand()
\r
328 int commandHandled = 1;
\r
330 uint8_t command = scsiDev.cdb[0];
\r
331 if (unlikely(command == 0x1B))
\r
334 // Enable or disable media access operations.
\r
335 // Ignore load/eject requests. We can't do that.
\r
336 //int immed = scsiDev.cdb[1] & 1;
\r
337 int start = scsiDev.cdb[4] & 1;
\r
341 blockDev.state = blockDev.state | DISK_STARTED;
\r
342 if (!(blockDev.state & DISK_INITIALISED))
\r
349 blockDev.state &= ~DISK_STARTED;
\r
352 else if (unlikely(command == 0x00))
\r
357 else if (unlikely(!doTestUnitReady()))
\r
359 // Status and sense codes already set by doTestUnitReady
\r
361 else if (likely(command == 0x08))
\r
365 (((uint32_t) scsiDev.cdb[1] & 0x1F) << 16) +
\r
366 (((uint32_t) scsiDev.cdb[2]) << 8) +
\r
368 uint32_t blocks = scsiDev.cdb[4];
\r
369 if (unlikely(blocks == 0)) blocks = 256;
\r
370 doRead(lba, blocks);
\r
372 else if (likely(command == 0x28))
\r
375 // Ignore all cache control bits - we don't support a memory cache.
\r
378 (((uint32_t) scsiDev.cdb[2]) << 24) +
\r
379 (((uint32_t) scsiDev.cdb[3]) << 16) +
\r
380 (((uint32_t) scsiDev.cdb[4]) << 8) +
\r
383 (((uint32_t) scsiDev.cdb[7]) << 8) +
\r
386 doRead(lba, blocks);
\r
388 else if (likely(command == 0x0A))
\r
392 (((uint32_t) scsiDev.cdb[1] & 0x1F) << 16) +
\r
393 (((uint32_t) scsiDev.cdb[2]) << 8) +
\r
395 uint32_t blocks = scsiDev.cdb[4];
\r
396 if (unlikely(blocks == 0)) blocks = 256;
\r
397 doWrite(lba, blocks);
\r
399 else if (likely(command == 0x2A) || // WRITE(10)
\r
400 unlikely(command == 0x2E)) // WRITE AND VERIFY
\r
402 // Ignore all cache control bits - we don't support a memory cache.
\r
403 // Don't bother verifying either. The SD card likely stores ECC
\r
404 // along with each flash row.
\r
407 (((uint32_t) scsiDev.cdb[2]) << 24) +
\r
408 (((uint32_t) scsiDev.cdb[3]) << 16) +
\r
409 (((uint32_t) scsiDev.cdb[4]) << 8) +
\r
412 (((uint32_t) scsiDev.cdb[7]) << 8) +
\r
415 doWrite(lba, blocks);
\r
417 else if (unlikely(command == 0x04))
\r
420 // We don't really do any formatting, but we need to read the correct
\r
421 // number of bytes in the DATA_OUT phase to make the SCSI host happy.
\r
423 int fmtData = (scsiDev.cdb[1] & 0x10) ? 1 : 0;
\r
426 // We need to read the parameter list, but we don't know how
\r
427 // big it is yet. Start with the header.
\r
428 scsiDev.dataLen = 4;
\r
429 scsiDev.phase = DATA_OUT;
\r
430 scsiDev.postDataOutHook = doFormatUnitHeader;
\r
434 // No data to read, we're already finished!
\r
437 else if (unlikely(command == 0x25))
\r
442 else if (unlikely(command == 0x0B))
\r
446 (((uint32_t) scsiDev.cdb[1] & 0x1F) << 16) +
\r
447 (((uint32_t) scsiDev.cdb[2]) << 8) +
\r
453 else if (unlikely(command == 0x2B))
\r
457 (((uint32_t) scsiDev.cdb[2]) << 24) +
\r
458 (((uint32_t) scsiDev.cdb[3]) << 16) +
\r
459 (((uint32_t) scsiDev.cdb[4]) << 8) +
\r
464 else if (unlikely(command == 0x36))
\r
466 // LOCK UNLOCK CACHE
\r
467 // We don't have a cache to lock data into. do nothing.
\r
469 else if (unlikely(command == 0x34))
\r
472 // We don't have a cache to pre-fetch into. do nothing.
\r
474 else if (unlikely(command == 0x1E))
\r
476 // PREVENT ALLOW MEDIUM REMOVAL
\r
477 // Not much we can do to prevent the user removing the SD card.
\r
480 else if (unlikely(command == 0x01))
\r
483 // Set the lun to a vendor-specific state. Ignore.
\r
485 else if (unlikely(command == 0x35))
\r
487 // SYNCHRONIZE CACHE
\r
488 // We don't have a cache. do nothing.
\r
490 else if (unlikely(command == 0x2F))
\r
493 // TODO: When they supply data to verify, we should read the data and
\r
494 // verify it. If they don't supply any data, just say success.
\r
495 if ((scsiDev.cdb[1] & 0x02) == 0)
\r
497 // They are asking us to do a medium verification with no data
\r
498 // comparison. Assume success, do nothing.
\r
502 // TODO. This means they are supplying data to verify against.
\r
503 // Technically we should probably grab the data and compare it.
\r
504 scsiDev.status = CHECK_CONDITION;
\r
505 scsiDev.target->sense.code = ILLEGAL_REQUEST;
\r
506 scsiDev.target->sense.asc = INVALID_FIELD_IN_CDB;
\r
507 scsiDev.phase = STATUS;
\r
510 else if (unlikely(command == 0x37))
\r
512 // READ DEFECT DATA
\r
513 scsiDev.status = CHECK_CONDITION;
\r
514 scsiDev.target->sense.code = NO_SENSE;
\r
515 scsiDev.target->sense.asc = DEFECT_LIST_NOT_FOUND;
\r
516 scsiDev.phase = STATUS;
\r
521 commandHandled = 0;
\r
524 return commandHandled;
\r
527 void scsiDiskPoll()
\r
529 uint32_t bytesPerSector = scsiDev.target->liveCfg.bytesPerSector;
\r
531 if (scsiDev.phase == DATA_IN &&
\r
532 transfer.currentBlock != transfer.blocks)
\r
534 scsiEnterPhase(DATA_IN);
\r
536 int totalSDSectors =
\r
537 transfer.blocks * SDSectorsPerSCSISector(bytesPerSector);
\r
540 scsiDev.target->cfg->sdSectorStart,
\r
544 const int sdPerScsi = SDSectorsPerSCSISector(bytesPerSector);
\r
545 int buffers = sizeof(scsiDev.data) / SD_SECTOR_SIZE;
\r
548 int scsiActive = 0;
\r
549 // int sdActive = 0;
\r
550 while ((i < totalSDSectors) &&
\r
551 likely(scsiDev.phase == DATA_IN) &&
\r
552 likely(!scsiDev.resetFlag))
\r
554 // Wait for the next DMA interrupt. It's beneficial to halt the
\r
555 // processor to give the DMA controller more memory bandwidth to
\r
560 while (scsiBusy && sdBusy)
\r
562 uint8_t intr = CyEnterCriticalSection();
\r
563 scsiBusy = scsiDMABusy();
\r
564 sdBusy = sdDMABusy();
\r
565 if (scsiBusy && sdBusy)
\r
569 CyExitCriticalSection(intr);
\r
574 if (sdActive && !sdBusy && sdReadSectorDMAPoll())
\r
580 // Usually SD is slower than the SCSI interface.
\r
581 // Prioritise starting the read of the next sector over starting a
\r
582 // SCSI transfer for the last sector
\r
583 // ie. NO "else" HERE.
\r
585 (prep - i < buffers) &&
\r
586 (prep < totalSDSectors))
\r
588 // Start an SD transfer if we have space.
\r
589 if (transfer.multiBlock)
\r
591 sdReadMultiSectorDMA(&scsiDev.data[SD_SECTOR_SIZE * (prep % buffers)]);
\r
595 sdReadSingleSectorDMA(sdLBA + prep, &scsiDev.data[SD_SECTOR_SIZE * (prep % buffers)]);
\r
601 uint32_t maxSectors = sizeof(scsiDev.data) / SD_SECTOR_SIZE;
\r
602 uint32_t rem = totalSDSectors - i;
\r
604 rem < maxSectors ? rem : maxSectors;
\r
605 sdTmpRead(&scsiDev.data[0], i + sdLBA, sectors);
\r
606 scsiWrite(&scsiDev.data[0], sectors * SD_SECTOR_SIZE);
\r
609 if ((prep - i < buffers) &&
\r
610 (prep < totalSDSectors))
\r
612 // TODO MM Blocking reads are bad mmkay
\r
613 sdTmpRead(&scsiDev.data[SD_SECTOR_SIZE * (prep % buffers)], sdLBA + prep, 1);
\r
617 if (scsiActive && scsiPhyComplete() && scsiWriteDMAPoll())
\r
623 if (!scsiActive && ((prep - i) > 0))
\r
625 int dmaBytes = SD_SECTOR_SIZE;
\r
626 if ((i % sdPerScsi) == (sdPerScsi - 1))
\r
628 dmaBytes = bytesPerSector % SD_SECTOR_SIZE;
\r
629 if (dmaBytes == 0) dmaBytes = SD_SECTOR_SIZE;
\r
631 scsiWriteDMA(&scsiDev.data[SD_SECTOR_SIZE * (i % buffers)], dmaBytes);
\r
636 // We've finished transferring the data to the FPGA, now wait until it's
\r
637 // written to he SCSI bus.
\r
638 while (!scsiPhyComplete() &&
\r
639 likely(scsiDev.phase == DATA_IN) &&
\r
640 likely(!scsiDev.resetFlag))
\r
648 if (scsiDev.phase == DATA_IN)
\r
650 scsiDev.phase = STATUS;
\r
654 else if (scsiDev.phase == DATA_OUT &&
\r
655 transfer.currentBlock != transfer.blocks)
\r
657 scsiEnterPhase(DATA_OUT);
\r
659 const int sdPerScsi = SDSectorsPerSCSISector(bytesPerSector);
\r
660 int totalSDSectors = transfer.blocks * sdPerScsi;
\r
663 scsiDev.target->cfg->sdSectorStart,
\r
666 // int buffers = sizeof(scsiDev.data) / SD_SECTOR_SIZE;
\r
669 // int scsiDisconnected = 0;
\r
670 int scsiComplete = 0;
\r
671 // uint32_t lastActivityTime = s2s_getTime_ms();
\r
672 // int scsiActive = 0;
\r
673 // int sdActive = 0;
\r
675 while ((i < totalSDSectors) &&
\r
676 (likely(scsiDev.phase == DATA_OUT) || // scsiDisconnect keeps our phase.
\r
678 likely(!scsiDev.resetFlag))
\r
680 // Well, until we have some proper non-blocking SD code, we must
\r
681 // do this in a half-duplex fashion. We need to write as much as
\r
682 // possible in each SD card transaction.
\r
683 uint32_t maxSectors = sizeof(scsiDev.data) / SD_SECTOR_SIZE;
\r
684 uint32_t rem = totalSDSectors - i;
\r
686 rem < maxSectors ? rem : maxSectors;
\r
687 scsiRead(&scsiDev.data[0], sectors * SD_SECTOR_SIZE);
\r
688 sdTmpWrite(&scsiDev.data[0], i + sdLBA, sectors);
\r
691 // Wait for the next DMA interrupt. It's beneficial to halt the
\r
692 // processor to give the DMA controller more memory bandwidth to
\r
696 while (scsiBusy && sdBusy)
\r
698 uint8_t intr = CyEnterCriticalSection();
\r
699 scsiBusy = scsiDMABusy();
\r
700 sdBusy = sdDMABusy();
\r
701 if (scsiBusy && sdBusy)
\r
705 CyExitCriticalSection(intr);
\r
708 if (sdActive && !sdBusy && sdWriteSectorDMAPoll())
\r
713 if (!sdActive && ((prep - i) > 0))
\r
715 // Start an SD transfer if we have space.
\r
716 sdWriteMultiSectorDMA(&scsiDev.data[SD_SECTOR_SIZE * (i % buffers)]);
\r
720 uint32_t now = getTime_ms();
\r
722 if (scsiActive && !scsiBusy && scsiReadDMAPoll())
\r
726 lastActivityTime = now;
\r
729 ((prep - i) < buffers) &&
\r
730 (prep < totalSDSectors) &&
\r
731 likely(!scsiDisconnected))
\r
733 int dmaBytes = SD_SECTOR_SIZE;
\r
734 if ((prep % sdPerScsi) == (sdPerScsi - 1))
\r
736 dmaBytes = bytesPerSector % SD_SECTOR_SIZE;
\r
737 if (dmaBytes == 0) dmaBytes = SD_SECTOR_SIZE;
\r
739 scsiReadDMA(&scsiDev.data[SD_SECTOR_SIZE * (prep % buffers)], dmaBytes);
\r
743 (scsiDev.boardCfg.flags & CONFIG_ENABLE_DISCONNECT) &&
\r
744 (scsiActive == 0) &&
\r
745 likely(!scsiDisconnected) &&
\r
746 unlikely(scsiDev.discPriv) &&
\r
747 unlikely(diffTime_ms(lastActivityTime, now) >= 20) &&
\r
748 likely(scsiDev.phase == DATA_OUT))
\r
750 // We're transferring over the SCSI bus faster than the SD card
\r
751 // can write. There is no more buffer space once we've finished
\r
752 // this SCSI transfer.
\r
753 // The NCR 53C700 interface chips have a 250ms "byte-to-byte"
\r
754 // timeout buffer. SD card writes are supposed to complete
\r
755 // within 200ms, but sometimes they don't.
\r
756 // The NCR 53C700 series is used on HP 9000 workstations.
\r
758 scsiDisconnected = 1;
\r
759 lastActivityTime = getTime_ms();
\r
761 else if (unlikely(scsiDisconnected) &&
\r
763 (prep == i) || // Buffers empty.
\r
764 // Send some messages every 100ms so we don't timeout.
\r
765 // At a minimum, a reselection involves an IDENTIFY message.
\r
766 unlikely(diffTime_ms(lastActivityTime, now) >= 100)
\r
769 int reconnected = scsiReconnect();
\r
772 scsiDisconnected = 0;
\r
773 lastActivityTime = getTime_ms(); // Don't disconnect immediately.
\r
775 else if (diffTime_ms(lastActivityTime, getTime_ms()) >= 10000)
\r
777 // Give up after 10 seconds of trying to reconnect.
\r
778 scsiDev.resetFlag = 1;
\r
782 likely(!scsiComplete) &&
\r
784 (prep == totalSDSectors) && // All scsi data read and buffered
\r
785 likely(!scsiDev.discPriv) && // Prefer disconnect where possible.
\r
786 unlikely(diffTime_ms(lastActivityTime, now) >= 150) &&
\r
788 likely(scsiDev.phase == DATA_OUT) &&
\r
789 !(scsiDev.cdb[scsiDev.cdbLen - 1] & 0x01) // Not linked command
\r
792 // We're transferring over the SCSI bus faster than the SD card
\r
793 // can write. All data is buffered, and we're just waiting for
\r
794 // the SD card to complete. The host won't let us disconnect.
\r
795 // Some drivers set a 250ms timeout on transfers to complete.
\r
796 // SD card writes are supposed to complete
\r
797 // within 200ms, but sometimes they don'to.
\r
798 // Just pretend we're finished.
\r
802 process_MessageIn(); // Will go to BUS_FREE state
\r
804 // Try and prevent anyone else using the SCSI bus while we're not ready.
\r
805 SCSI_SetPin(SCSI_Out_BSY);
\r
813 SCSI_ClearPin(SCSI_Out_BSY);
\r
816 !scsiDev.resetFlag &&
\r
817 unlikely(scsiDisconnected) &&
\r
818 (s2s_elapsedTime_ms(lastActivityTime) <= 10000))
\r
820 scsiDisconnected = !scsiReconnect();
\r
822 if (scsiDisconnected)
\r
824 // Failed to reconnect
\r
825 scsiDev.resetFlag = 1;
\r
829 if (scsiDev.phase == DATA_OUT)
\r
831 if (scsiDev.parityError &&
\r
832 (scsiDev.boardCfg.flags & S2S_CFG_ENABLE_PARITY) &&
\r
833 (scsiDev.compatMode >= COMPAT_SCSI2))
\r
835 scsiDev.target->sense.code = ABORTED_COMMAND;
\r
836 scsiDev.target->sense.asc = SCSI_PARITY_ERROR;
\r
837 scsiDev.status = CHECK_CONDITION;;
\r
839 scsiDev.phase = STATUS;
\r
845 void scsiDiskReset()
\r
847 scsiDev.dataPtr = 0;
\r
848 scsiDev.savedDataPtr = 0;
\r
849 scsiDev.dataLen = 0;
\r
850 // transfer.lba = 0; // Needed in Request Sense to determine failure
\r
851 transfer.blocks = 0;
\r
852 transfer.currentBlock = 0;
\r
854 // Cancel long running commands!
\r
856 ((scsiDev.boardCfg.flags & S2S_CFG_ENABLE_CACHE) == 0) ||
\r
857 (transfer.multiBlock == 0)
\r
861 sdCompleteTransfer();
\r
865 transfer.multiBlock = 0;
\r
868 void scsiDiskInit()
\r
872 // Don't require the host to send us a START STOP UNIT command
\r
873 blockDev.state = DISK_STARTED;
\r