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
31 BlockDevice blockDev;
\r
34 static int doSdInit()
\r
37 if (blockDev.state & DISK_PRESENT)
\r
43 blockDev.state = blockDev.state | DISK_INITIALISED;
\r
49 // Callback once all data has been read in the data out phase.
\r
50 static void doFormatUnitComplete(void)
\r
52 // TODO start writing the initialisation pattern to the SD
\r
54 scsiDev.phase = STATUS;
\r
57 static void doFormatUnitSkipData(int bytes)
\r
59 // We may not have enough memory to store the initialisation pattern and
\r
60 // defect list data. Since we're not making use of it yet anyway, just
\r
61 // discard the bytes.
\r
62 scsiEnterPhase(DATA_OUT);
\r
64 for (i = 0; i < bytes; ++i)
\r
70 // Callback from the data out phase.
\r
71 static void doFormatUnitPatternHeader(void)
\r
74 ((((uint16_t)scsiDev.data[2])) << 8) +
\r
78 ((((uint16_t)scsiDev.data[4 + 2])) << 8) +
\r
79 scsiDev.data[4 + 3];
\r
81 doFormatUnitSkipData(defectLength + patternLength);
\r
82 doFormatUnitComplete();
\r
85 // Callback from the data out phase.
\r
86 static void doFormatUnitHeader(void)
\r
88 int IP = (scsiDev.data[1] & 0x08) ? 1 : 0;
\r
89 int DSP = (scsiDev.data[1] & 0x04) ? 1 : 0;
\r
91 if (! DSP) // disable save parameters
\r
93 // Save the "MODE SELECT savable parameters"
\r
95 scsiDev.target->targetId,
\r
96 scsiDev.target->liveCfg.bytesPerSector);
\r
101 // We need to read the initialisation pattern header first.
\r
102 scsiDev.dataLen += 4;
\r
103 scsiDev.phase = DATA_OUT;
\r
104 scsiDev.postDataOutHook = doFormatUnitPatternHeader;
\r
108 // Read the defect list data
\r
110 ((((uint16_t)scsiDev.data[2])) << 8) +
\r
112 doFormatUnitSkipData(defectLength);
\r
113 doFormatUnitComplete();
\r
117 static void doReadCapacity()
\r
119 uint32_t lba = (((uint32) scsiDev.cdb[2]) << 24) +
\r
120 (((uint32) scsiDev.cdb[3]) << 16) +
\r
121 (((uint32) scsiDev.cdb[4]) << 8) +
\r
123 int pmi = scsiDev.cdb[8] & 1;
\r
125 uint32_t capacity = getScsiCapacity(
\r
126 scsiDev.target->cfg->sdSectorStart,
\r
127 scsiDev.target->liveCfg.bytesPerSector,
\r
128 scsiDev.target->cfg->scsiSectors);
\r
133 // We don't do anything with the "partial medium indicator", and
\r
134 // assume that delays are constant across each block. But the spec
\r
135 // says we must return this error if pmi is specified incorrectly.
\r
136 scsiDev.status = CHECK_CONDITION;
\r
137 scsiDev.target->sense.code = ILLEGAL_REQUEST;
\r
138 scsiDev.target->sense.asc = INVALID_FIELD_IN_CDB;
\r
139 scsiDev.phase = STATUS;
\r
141 else if (capacity > 0)
\r
143 uint32_t highestBlock = capacity - 1;
\r
145 scsiDev.data[0] = highestBlock >> 24;
\r
146 scsiDev.data[1] = highestBlock >> 16;
\r
147 scsiDev.data[2] = highestBlock >> 8;
\r
148 scsiDev.data[3] = highestBlock;
\r
150 uint32_t bytesPerSector = scsiDev.target->liveCfg.bytesPerSector;
\r
151 scsiDev.data[4] = bytesPerSector >> 24;
\r
152 scsiDev.data[5] = bytesPerSector >> 16;
\r
153 scsiDev.data[6] = bytesPerSector >> 8;
\r
154 scsiDev.data[7] = bytesPerSector;
\r
155 scsiDev.dataLen = 8;
\r
156 scsiDev.phase = DATA_IN;
\r
160 scsiDev.status = CHECK_CONDITION;
\r
161 scsiDev.target->sense.code = NOT_READY;
\r
162 scsiDev.target->sense.asc = MEDIUM_NOT_PRESENT;
\r
163 scsiDev.phase = STATUS;
\r
167 static void doWrite(uint32 lba, uint32 blocks)
\r
169 if (unlikely(scsiDev.target->cfg->deviceType == CONFIG_FLOPPY_14MB)) {
\r
170 // Floppies are supposed to be slow. Some systems can't handle a floppy
\r
171 // without an access time
\r
175 uint32_t bytesPerSector = scsiDev.target->liveCfg.bytesPerSector;
\r
177 if (unlikely(blockDev.state & DISK_WP) ||
\r
178 unlikely(scsiDev.target->cfg->deviceType == CONFIG_OPTICAL))
\r
181 scsiDev.status = CHECK_CONDITION;
\r
182 scsiDev.target->sense.code = ILLEGAL_REQUEST;
\r
183 scsiDev.target->sense.asc = WRITE_PROTECTED;
\r
184 scsiDev.phase = STATUS;
\r
186 else if (unlikely(((uint64) lba) + blocks >
\r
188 scsiDev.target->cfg->sdSectorStart,
\r
190 scsiDev.target->cfg->scsiSectors
\r
194 scsiDev.status = CHECK_CONDITION;
\r
195 scsiDev.target->sense.code = ILLEGAL_REQUEST;
\r
196 scsiDev.target->sense.asc = LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
\r
197 scsiDev.phase = STATUS;
\r
201 transfer.lba = lba;
\r
202 transfer.blocks = blocks;
\r
203 transfer.currentBlock = 0;
\r
204 scsiDev.phase = DATA_OUT;
\r
205 scsiDev.dataLen = bytesPerSector;
\r
206 scsiDev.dataPtr = bytesPerSector;
\r
208 // No need for single-block writes atm. Overhead of the
\r
209 // multi-block write is minimal.
\r
210 transfer.multiBlock = 1;
\r
215 scsiDev.target->cfg->sdSectorStart,
\r
218 uint32_t sdBlocks = blocks * SDSectorsPerSCSISector(bytesPerSector);
\r
219 sdWriteMultiSectorPrep(sdLBA, sdBlocks);
\r
224 static void doRead(uint32 lba, uint32 blocks)
\r
226 if (unlikely(scsiDev.target->cfg->deviceType == CONFIG_FLOPPY_14MB)) {
\r
227 // Floppies are supposed to be slow. Some systems can't handle a floppy
\r
228 // without an access time
\r
232 uint32_t capacity = getScsiCapacity(
\r
233 scsiDev.target->cfg->sdSectorStart,
\r
234 scsiDev.target->liveCfg.bytesPerSector,
\r
235 scsiDev.target->cfg->scsiSectors);
\r
236 if (unlikely(((uint64) lba) + blocks > capacity))
\r
238 scsiDev.status = CHECK_CONDITION;
\r
239 scsiDev.target->sense.code = ILLEGAL_REQUEST;
\r
240 scsiDev.target->sense.asc = LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
\r
241 scsiDev.phase = STATUS;
\r
245 transfer.lba = lba;
\r
246 transfer.blocks = blocks;
\r
247 transfer.currentBlock = 0;
\r
248 scsiDev.phase = DATA_IN;
\r
249 scsiDev.dataLen = 0; // No data yet
\r
251 uint32_t bytesPerSector = scsiDev.target->liveCfg.bytesPerSector;
\r
252 uint32_t sdSectorPerSCSISector = SDSectorsPerSCSISector(bytesPerSector);
\r
253 uint32_t sdSectors =
\r
254 blocks * sdSectorPerSCSISector;
\r
257 (sdSectors == 1) &&
\r
258 !(scsiDev.boardCfg.flags & CONFIG_ENABLE_CACHE)
\r
260 unlikely(((uint64) lba) + blocks == capacity)
\r
263 // We get errors on reading the last sector using a multi-sector
\r
265 transfer.multiBlock = 0;
\r
269 transfer.multiBlock = 1;
\r
273 scsiDev.target->cfg->sdSectorStart,
\r
277 sdReadMultiSectorPrep(sdLBA, sdSectors);
\r
282 static void doSeek(uint32 lba)
\r
286 scsiDev.target->cfg->sdSectorStart,
\r
287 scsiDev.target->liveCfg.bytesPerSector,
\r
288 scsiDev.target->cfg->scsiSectors)
\r
291 scsiDev.status = CHECK_CONDITION;
\r
292 scsiDev.target->sense.code = ILLEGAL_REQUEST;
\r
293 scsiDev.target->sense.asc = LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
\r
294 scsiDev.phase = STATUS;
\r
302 static int doTestUnitReady()
\r
305 if (likely(blockDev.state == (DISK_STARTED | DISK_PRESENT | DISK_INITIALISED)))
\r
309 else if (unlikely(!(blockDev.state & DISK_STARTED)))
\r
312 scsiDev.status = CHECK_CONDITION;
\r
313 scsiDev.target->sense.code = NOT_READY;
\r
314 scsiDev.target->sense.asc = LOGICAL_UNIT_NOT_READY_INITIALIZING_COMMAND_REQUIRED;
\r
315 scsiDev.phase = STATUS;
\r
317 else if (unlikely(!(blockDev.state & DISK_PRESENT)))
\r
320 scsiDev.status = CHECK_CONDITION;
\r
321 scsiDev.target->sense.code = NOT_READY;
\r
322 scsiDev.target->sense.asc = MEDIUM_NOT_PRESENT;
\r
323 scsiDev.phase = STATUS;
\r
325 else if (unlikely(!(blockDev.state & DISK_INITIALISED)))
\r
328 scsiDev.status = CHECK_CONDITION;
\r
329 scsiDev.target->sense.code = NOT_READY;
\r
330 scsiDev.target->sense.asc = LOGICAL_UNIT_NOT_READY_CAUSE_NOT_REPORTABLE;
\r
331 scsiDev.phase = STATUS;
\r
336 // Handle direct-access scsi device commands
\r
337 int scsiDiskCommand()
\r
339 int commandHandled = 1;
\r
341 uint8 command = scsiDev.cdb[0];
\r
342 if (unlikely(command == 0x1B))
\r
345 // Enable or disable media access operations.
\r
346 // Ignore load/eject requests. We can't do that.
\r
347 //int immed = scsiDev.cdb[1] & 1;
\r
348 int start = scsiDev.cdb[4] & 1;
\r
352 blockDev.state = blockDev.state | DISK_STARTED;
\r
353 if (!(blockDev.state & DISK_INITIALISED))
\r
360 blockDev.state &= ~DISK_STARTED;
\r
363 else if (unlikely(command == 0x00))
\r
368 else if (unlikely(!doTestUnitReady()))
\r
370 // Status and sense codes already set by doTestUnitReady
\r
372 else if (likely(command == 0x08))
\r
376 (((uint32) scsiDev.cdb[1] & 0x1F) << 16) +
\r
377 (((uint32) scsiDev.cdb[2]) << 8) +
\r
379 uint32 blocks = scsiDev.cdb[4];
\r
380 if (unlikely(blocks == 0)) blocks = 256;
\r
381 doRead(lba, blocks);
\r
383 else if (likely(command == 0x28))
\r
386 // Ignore all cache control bits - we don't support a memory cache.
\r
389 (((uint32) scsiDev.cdb[2]) << 24) +
\r
390 (((uint32) scsiDev.cdb[3]) << 16) +
\r
391 (((uint32) scsiDev.cdb[4]) << 8) +
\r
394 (((uint32) scsiDev.cdb[7]) << 8) +
\r
397 doRead(lba, blocks);
\r
399 else if (likely(command == 0x0A))
\r
403 (((uint32) scsiDev.cdb[1] & 0x1F) << 16) +
\r
404 (((uint32) scsiDev.cdb[2]) << 8) +
\r
406 uint32 blocks = scsiDev.cdb[4];
\r
407 if (unlikely(blocks == 0)) blocks = 256;
\r
408 doWrite(lba, blocks);
\r
410 else if (likely(command == 0x2A) || // WRITE(10)
\r
411 unlikely(command == 0x2E)) // WRITE AND VERIFY
\r
413 // Ignore all cache control bits - we don't support a memory cache.
\r
414 // Don't bother verifying either. The SD card likely stores ECC
\r
415 // along with each flash row.
\r
418 (((uint32) scsiDev.cdb[2]) << 24) +
\r
419 (((uint32) scsiDev.cdb[3]) << 16) +
\r
420 (((uint32) scsiDev.cdb[4]) << 8) +
\r
423 (((uint32) scsiDev.cdb[7]) << 8) +
\r
426 doWrite(lba, blocks);
\r
429 else if (unlikely(command == 0x04))
\r
432 // We don't really do any formatting, but we need to read the correct
\r
433 // number of bytes in the DATA_OUT phase to make the SCSI host happy.
\r
435 int fmtData = (scsiDev.cdb[1] & 0x10) ? 1 : 0;
\r
438 // We need to read the parameter list, but we don't know how
\r
439 // big it is yet. Start with the header.
\r
440 scsiDev.dataLen = 4;
\r
441 scsiDev.phase = DATA_OUT;
\r
442 scsiDev.postDataOutHook = doFormatUnitHeader;
\r
446 // No data to read, we're already finished!
\r
449 else if (unlikely(command == 0x25))
\r
454 else if (unlikely(command == 0x0B))
\r
458 (((uint32) scsiDev.cdb[1] & 0x1F) << 16) +
\r
459 (((uint32) scsiDev.cdb[2]) << 8) +
\r
465 else if (unlikely(command == 0x2B))
\r
469 (((uint32) scsiDev.cdb[2]) << 24) +
\r
470 (((uint32) scsiDev.cdb[3]) << 16) +
\r
471 (((uint32) scsiDev.cdb[4]) << 8) +
\r
476 else if (unlikely(command == 0x36))
\r
478 // LOCK UNLOCK CACHE
\r
479 // We don't have a cache to lock data into. do nothing.
\r
481 else if (unlikely(command == 0x34))
\r
484 // We don't have a cache to pre-fetch into. do nothing.
\r
486 else if (unlikely(command == 0x1E))
\r
488 // PREVENT ALLOW MEDIUM REMOVAL
\r
489 // Not much we can do to prevent the user removing the SD card.
\r
492 else if (unlikely(command == 0x01))
\r
495 // Set the lun to a vendor-specific state. Ignore.
\r
497 else if (unlikely(command == 0x35))
\r
499 // SYNCHRONIZE CACHE
\r
500 // We don't have a cache. do nothing.
\r
502 else if (unlikely(command == 0x2F))
\r
505 // TODO: When they supply data to verify, we should read the data and
\r
506 // verify it. If they don't supply any data, just say success.
\r
507 if ((scsiDev.cdb[1] & 0x02) == 0)
\r
509 // They are asking us to do a medium verification with no data
\r
510 // comparison. Assume success, do nothing.
\r
514 // TODO. This means they are supplying data to verify against.
\r
515 // Technically we should probably grab the data and compare it.
\r
516 scsiDev.status = CHECK_CONDITION;
\r
517 scsiDev.target->sense.code = ILLEGAL_REQUEST;
\r
518 scsiDev.target->sense.asc = INVALID_FIELD_IN_CDB;
\r
519 scsiDev.phase = STATUS;
\r
522 else if (unlikely(command == 0x37))
\r
524 // READ DEFECT DATA
\r
525 uint32_t allocLength = (((uint16_t)scsiDev.cdb[7]) << 8) |
\r
528 scsiDev.data[0] = 0;
\r
529 scsiDev.data[1] = scsiDev.cdb[1];
\r
530 scsiDev.data[2] = 0;
\r
531 scsiDev.data[3] = 0;
\r
532 scsiDev.dataLen = 4;
\r
534 if (scsiDev.dataLen > allocLength)
\r
536 scsiDev.dataLen = allocLength;
\r
539 scsiDev.phase = DATA_IN;
\r
543 commandHandled = 0;
\r
546 return commandHandled;
\r
549 void scsiDiskPoll()
\r
551 uint32_t bytesPerSector = scsiDev.target->liveCfg.bytesPerSector;
\r
553 if (scsiDev.phase == DATA_IN &&
\r
554 transfer.currentBlock != transfer.blocks)
\r
556 scsiEnterPhase(DATA_IN);
\r
558 int totalSDSectors =
\r
559 transfer.blocks * SDSectorsPerSCSISector(bytesPerSector);
\r
562 scsiDev.target->cfg->sdSectorStart,
\r
566 const int sdPerScsi = SDSectorsPerSCSISector(bytesPerSector);
\r
567 int buffers = sizeof(scsiDev.data) / SD_SECTOR_SIZE;
\r
570 int scsiActive = 0;
\r
572 while ((i < totalSDSectors) &&
\r
573 likely(scsiDev.phase == DATA_IN) &&
\r
574 likely(!scsiDev.resetFlag))
\r
576 // Wait for the next DMA interrupt. It's beneficial to halt the
\r
577 // processor to give the DMA controller more memory bandwidth to
\r
581 while (scsiBusy && sdBusy)
\r
583 uint8_t intr = CyEnterCriticalSection();
\r
584 scsiBusy = scsiDMABusy();
\r
585 sdBusy = sdDMABusy();
\r
586 if (scsiBusy && sdBusy)
\r
590 CyExitCriticalSection(intr);
\r
593 if (sdActive && !sdBusy && sdReadSectorDMAPoll())
\r
599 // Usually SD is slower than the SCSI interface.
\r
600 // Prioritise starting the read of the next sector over starting a
\r
601 // SCSI transfer for the last sector
\r
602 // ie. NO "else" HERE.
\r
604 (prep - i < buffers) &&
\r
605 (prep < totalSDSectors))
\r
607 // Start an SD transfer if we have space.
\r
608 if (transfer.multiBlock)
\r
610 sdReadMultiSectorDMA(&scsiDev.data[SD_SECTOR_SIZE * (prep % buffers)]);
\r
614 sdReadSingleSectorDMA(sdLBA + prep, &scsiDev.data[SD_SECTOR_SIZE * (prep % buffers)]);
\r
619 if (scsiActive && !scsiBusy && scsiWriteDMAPoll())
\r
624 if (!scsiActive && ((prep - i) > 0))
\r
626 int dmaBytes = SD_SECTOR_SIZE;
\r
627 if ((i % sdPerScsi) == (sdPerScsi - 1))
\r
629 dmaBytes = bytesPerSector % SD_SECTOR_SIZE;
\r
630 if (dmaBytes == 0) dmaBytes = SD_SECTOR_SIZE;
\r
632 scsiWriteDMA(&scsiDev.data[SD_SECTOR_SIZE * (i % buffers)], dmaBytes);
\r
636 if (scsiDev.phase == DATA_IN)
\r
638 scsiDev.phase = STATUS;
\r
642 else if (scsiDev.phase == DATA_OUT &&
\r
643 transfer.currentBlock != transfer.blocks)
\r
645 scsiEnterPhase(DATA_OUT);
\r
647 const int sdPerScsi = SDSectorsPerSCSISector(bytesPerSector);
\r
648 int totalSDSectors = transfer.blocks * sdPerScsi;
\r
649 int buffers = sizeof(scsiDev.data) / SD_SECTOR_SIZE;
\r
652 int scsiDisconnected = 0;
\r
653 int scsiComplete = 0;
\r
655 uint32_t lastActivityTime = getTime_ms();
\r
656 int scsiActive = 0;
\r
659 while ((i < totalSDSectors) &&
\r
660 (likely(scsiDev.phase == DATA_OUT) || // scsiDisconnect keeps our phase.
\r
662 likely(!scsiDev.resetFlag))
\r
664 // Wait for the next DMA interrupt. It's beneficial to halt the
\r
665 // processor to give the DMA controller more memory bandwidth to
\r
669 while (scsiBusy && sdBusy)
\r
671 uint8_t intr = CyEnterCriticalSection();
\r
672 scsiBusy = scsiDMABusy();
\r
673 sdBusy = sdDMABusy();
\r
674 if (scsiBusy && sdBusy)
\r
678 CyExitCriticalSection(intr);
\r
681 if (sdActive && !sdBusy && sdWriteSectorDMAPoll())
\r
686 if (!sdActive && ((prep - i) > 0))
\r
688 // Start an SD transfer if we have space.
\r
689 sdWriteMultiSectorDMA(&scsiDev.data[SD_SECTOR_SIZE * (i % buffers)]);
\r
693 uint32_t now = getTime_ms();
\r
695 if (scsiActive && !scsiBusy && scsiReadDMAPoll())
\r
699 lastActivityTime = now;
\r
702 ((prep - i) < buffers) &&
\r
703 (prep < totalSDSectors) &&
\r
704 likely(!scsiDisconnected))
\r
706 int dmaBytes = SD_SECTOR_SIZE;
\r
707 if ((prep % sdPerScsi) == (sdPerScsi - 1))
\r
709 dmaBytes = bytesPerSector % SD_SECTOR_SIZE;
\r
710 if (dmaBytes == 0) dmaBytes = SD_SECTOR_SIZE;
\r
712 scsiReadDMA(&scsiDev.data[SD_SECTOR_SIZE * (prep % buffers)], dmaBytes);
\r
716 (scsiDev.boardCfg.flags & CONFIG_ENABLE_DISCONNECT) &&
\r
717 (scsiActive == 0) &&
\r
718 likely(!scsiDisconnected) &&
\r
719 unlikely(scsiDev.discPriv) &&
\r
720 unlikely(diffTime_ms(lastActivityTime, now) >= 20) &&
\r
721 likely(scsiDev.phase == DATA_OUT))
\r
723 // We're transferring over the SCSI bus faster than the SD card
\r
724 // can write. There is no more buffer space once we've finished
\r
725 // this SCSI transfer.
\r
726 // The NCR 53C700 interface chips have a 250ms "byte-to-byte"
\r
727 // timeout buffer. SD card writes are supposed to complete
\r
728 // within 200ms, but sometimes they don't.
\r
729 // The NCR 53C700 series is used on HP 9000 workstations.
\r
731 scsiDisconnected = 1;
\r
732 lastActivityTime = getTime_ms();
\r
734 else if (unlikely(scsiDisconnected) &&
\r
736 (prep == i) || // Buffers empty.
\r
737 // Send some messages every 100ms so we don't timeout.
\r
738 // At a minimum, a reselection involves an IDENTIFY message.
\r
739 unlikely(diffTime_ms(lastActivityTime, now) >= 100)
\r
742 int reconnected = scsiReconnect();
\r
745 scsiDisconnected = 0;
\r
746 lastActivityTime = getTime_ms(); // Don't disconnect immediately.
\r
748 else if (diffTime_ms(lastActivityTime, getTime_ms()) >= 10000)
\r
750 // Give up after 10 seconds of trying to reconnect.
\r
751 scsiDev.resetFlag = 1;
\r
755 likely(!scsiComplete) &&
\r
757 (prep == totalSDSectors) && // All scsi data read and buffered
\r
758 likely(!scsiDev.discPriv) && // Prefer disconnect where possible.
\r
759 unlikely(diffTime_ms(lastActivityTime, now) >= 150) &&
\r
761 likely(scsiDev.phase == DATA_OUT) &&
\r
762 !(scsiDev.cdb[scsiDev.cdbLen - 1] & 0x01) // Not linked command
\r
765 // We're transferring over the SCSI bus faster than the SD card
\r
766 // can write. All data is buffered, and we're just waiting for
\r
767 // the SD card to complete. The host won't let us disconnect.
\r
768 // Some drivers set a 250ms timeout on transfers to complete.
\r
769 // SD card writes are supposed to complete
\r
770 // within 200ms, but sometimes they don'to.
\r
771 // Just pretend we're finished.
\r
775 clearBSY = process_MessageIn(0); // Will go to BUS_FREE state but keeps BSY asserted
\r
784 !scsiDev.resetFlag &&
\r
785 unlikely(scsiDisconnected) &&
\r
786 (elapsedTime_ms(lastActivityTime) <= 10000))
\r
788 scsiDisconnected = !scsiReconnect();
\r
790 if (scsiDisconnected)
\r
792 // Failed to reconnect
\r
793 scsiDev.resetFlag = 1;
\r
796 if (scsiDev.phase == DATA_OUT)
\r
798 if (scsiDev.parityError &&
\r
799 (scsiDev.boardCfg.flags & CONFIG_ENABLE_PARITY) &&
\r
800 (scsiDev.compatMode >= COMPAT_SCSI2))
\r
802 scsiDev.target->sense.code = ABORTED_COMMAND;
\r
803 scsiDev.target->sense.asc = SCSI_PARITY_ERROR;
\r
804 scsiDev.status = CHECK_CONDITION;;
\r
806 scsiDev.phase = STATUS;
\r
812 void scsiDiskReset()
\r
814 scsiDev.dataPtr = 0;
\r
815 scsiDev.savedDataPtr = 0;
\r
816 scsiDev.dataLen = 0;
\r
817 // transfer.lba = 0; // Needed in Request Sense to determine failure
\r
818 transfer.blocks = 0;
\r
819 transfer.currentBlock = 0;
\r
821 // Cancel long running commands!
\r
823 ((scsiDev.boardCfg.flags & CONFIG_ENABLE_CACHE) == 0) ||
\r
824 (transfer.multiBlock == 0)
\r
827 sdCompleteTransfer();
\r
830 transfer.multiBlock = 0;
\r
833 void scsiDiskInit()
\r
837 // Don't require the host to send us a START STOP UNIT command
\r
838 blockDev.state = DISK_STARTED;
\r
839 // WP pin not available for micro-sd
\r
840 // TODO read card WP register
\r
844 blockDev.state = blockDev.state | DISK_WP;
\r