diff --git a/software/SCSI2SD/src/cdrom.c b/software/SCSI2SD/src/cdrom.c index 9b40859..7f93948 100755 --- a/software/SCSI2SD/src/cdrom.c +++ b/software/SCSI2SD/src/cdrom.c @@ -152,8 +152,8 @@ static void doReadTOC(int MSF, uint8_t track, uint16_t allocationLength) if (track > 1) { scsiDev.status = CHECK_CONDITION; - scsiDev.target->sense.code = ILLEGAL_REQUEST; - scsiDev.target->sense.asc = INVALID_FIELD_IN_CDB; + scsiDev.target->state.sense.code = ILLEGAL_REQUEST; + scsiDev.target->state.sense.asc = INVALID_FIELD_IN_CDB; scsiDev.phase = STATUS; } else @@ -162,8 +162,9 @@ static void doReadTOC(int MSF, uint8_t track, uint16_t allocationLength) memcpy(scsiDev.data, SimpleTOC, len); uint32_t capacity = getScsiCapacity( + scsoDev.target->device, scsiDev.target->cfg->sdSectorStart, - scsiDev.target->liveCfg.bytesPerSector, + scsiDev.target->state.bytesPerSector, scsiDev.target->cfg->scsiSectors); // Replace start of leadout track @@ -213,8 +214,8 @@ static void doReadFullTOC(int convertBCD, uint8_t session, uint16_t allocationLe if (session > 1) { scsiDev.status = CHECK_CONDITION; - scsiDev.target->sense.code = ILLEGAL_REQUEST; - scsiDev.target->sense.asc = INVALID_FIELD_IN_CDB; + scsiDev.target->state.sense.code = ILLEGAL_REQUEST; + scsiDev.target->state.sense.asc = INVALID_FIELD_IN_CDB; scsiDev.phase = STATUS; } else @@ -297,8 +298,8 @@ int scsiCDRomCommand() default: { scsiDev.status = CHECK_CONDITION; - scsiDev.target->sense.code = ILLEGAL_REQUEST; - scsiDev.target->sense.asc = INVALID_FIELD_IN_CDB; + scsiDev.target->state.sense.code = ILLEGAL_REQUEST; + scsiDev.target->state.sense.asc = INVALID_FIELD_IN_CDB; scsiDev.phase = STATUS; } } diff --git a/software/SCSI2SD/src/config.c b/software/SCSI2SD/src/config.c index cc3233e..ada1a47 100755 --- a/software/SCSI2SD/src/config.c +++ b/software/SCSI2SD/src/config.c @@ -31,7 +31,7 @@ #include -static const uint16_t FIRMWARE_VERSION = 0x0484; +static const uint16_t FIRMWARE_VERSION = 0x0485; // 1 flash row static const uint8_t DEFAULT_CONFIG[256] = @@ -175,9 +175,9 @@ pingCommand() static void sdInfoCommand() { - uint8_t response[sizeof(sdDev.csd) + sizeof(sdDev.cid)]; - memcpy(response, sdDev.csd, sizeof(sdDev.csd)); - memcpy(response + sizeof(sdDev.csd), sdDev.cid, sizeof(sdDev.cid)); + uint8_t response[sizeof(sdCard.csd) + sizeof(sdCard.cid)]; + memcpy(response, sdCard.csd, sizeof(sdCard.csd)); + memcpy(response + sizeof(sdCard.csd), sdCard.cid, sizeof(sdCard.cid)); hidPacket_send(response, sizeof(response)); } @@ -340,16 +340,16 @@ void debugPoll() hidBuffer[23] = scsiDev.msgCount; hidBuffer[24] = scsiDev.cmdCount; hidBuffer[25] = scsiDev.watchdogTick; - hidBuffer[26] = blockDev.state; + hidBuffer[26] = 0; // OBSOLETE. Previously media state hidBuffer[27] = scsiDev.lastSenseASC >> 8; hidBuffer[28] = scsiDev.lastSenseASC; hidBuffer[29] = scsiReadDBxPins(); hidBuffer[30] = LastTrace; - hidBuffer[58] = sdDev.capacity >> 24; - hidBuffer[59] = sdDev.capacity >> 16; - hidBuffer[60] = sdDev.capacity >> 8; - hidBuffer[61] = sdDev.capacity; + hidBuffer[58] = sdCard.capacity >> 24; + hidBuffer[59] = sdCard.capacity >> 16; + hidBuffer[60] = sdCard.capacity >> 8; + hidBuffer[61] = sdCard.capacity; hidBuffer[62] = FIRMWARE_VERSION >> 8; hidBuffer[63] = FIRMWARE_VERSION; diff --git a/software/SCSI2SD/src/diagnostic.c b/software/SCSI2SD/src/diagnostic.c index d8f6477..a359df3 100755 --- a/software/SCSI2SD/src/diagnostic.c +++ b/software/SCSI2SD/src/diagnostic.c @@ -50,8 +50,8 @@ void scsiSendDiagnostic() // Nowhere to store this data! // Shouldn't happen - our buffer should be many magnitudes larger // than the required size for diagnostic parameters. - scsiDev.target->sense.code = ILLEGAL_REQUEST; - scsiDev.target->sense.asc = INVALID_FIELD_IN_CDB; + scsiDev.target->state.sense.code = ILLEGAL_REQUEST; + scsiDev.target->state.sense.asc = INVALID_FIELD_IN_CDB; scsiDev.status = CHECK_CONDITION; scsiDev.phase = STATUS; } @@ -95,14 +95,14 @@ void scsiReceiveDiagnostic() // 64bit linear address, then convert back again. uint64 fromByteAddr = scsiByteAddress( - scsiDev.target->liveCfg.bytesPerSector, + scsiDev.target->state.bytesPerSector, scsiDev.target->cfg->headsPerCylinder, scsiDev.target->cfg->sectorsPerTrack, suppliedFmt, &scsiDev.data[6]); scsiSaveByteAddress( - scsiDev.target->liveCfg.bytesPerSector, + scsiDev.target->state.bytesPerSector, scsiDev.target->cfg->headsPerCylinder, scsiDev.target->cfg->sectorsPerTrack, translateFmt, @@ -121,8 +121,8 @@ void scsiReceiveDiagnostic() { // error. scsiDev.status = CHECK_CONDITION; - scsiDev.target->sense.code = ILLEGAL_REQUEST; - scsiDev.target->sense.asc = INVALID_FIELD_IN_CDB; + scsiDev.target->state.sense.code = ILLEGAL_REQUEST; + scsiDev.target->state.sense.asc = INVALID_FIELD_IN_CDB; scsiDev.phase = STATUS; } @@ -169,8 +169,8 @@ void scsiReadBuffer() { // error. scsiDev.status = CHECK_CONDITION; - scsiDev.target->sense.code = ILLEGAL_REQUEST; - scsiDev.target->sense.asc = INVALID_FIELD_IN_CDB; + scsiDev.target->state.sense.code = ILLEGAL_REQUEST; + scsiDev.target->state.sense.asc = INVALID_FIELD_IN_CDB; scsiDev.phase = STATUS; } } @@ -208,8 +208,8 @@ void scsiWriteBuffer() { // error. scsiDev.status = CHECK_CONDITION; - scsiDev.target->sense.code = ILLEGAL_REQUEST; - scsiDev.target->sense.asc = INVALID_FIELD_IN_CDB; + scsiDev.target->state.sense.code = ILLEGAL_REQUEST; + scsiDev.target->state.sense.asc = INVALID_FIELD_IN_CDB; scsiDev.phase = STATUS; } } @@ -219,7 +219,7 @@ void scsiWriteBuffer() // Section 4.3.14 void scsiWriteSectorBuffer() { - scsiDev.dataLen = scsiDev.target->liveCfg.bytesPerSector; + scsiDev.dataLen = scsiDev.target->state.bytesPerSector; scsiDev.phase = DATA_OUT; scsiDev.postDataOutHook = doWriteBuffer; } diff --git a/software/SCSI2SD/src/disk.c b/software/SCSI2SD/src/disk.c index 5c5a1de..b49923a 100755 --- a/software/SCSI2SD/src/disk.c +++ b/software/SCSI2SD/src/disk.c @@ -28,24 +28,8 @@ #include // Global -BlockDevice blockDev; Transfer transfer; -static int doSdInit() -{ - int result = 0; - if (blockDev.state & DISK_PRESENT) - { - result = sdInit(); - - if (result) - { - blockDev.state = blockDev.state | DISK_INITIALISED; - } - } - return result; -} - // Callback once all data has been read in the data out phase. static void doFormatUnitComplete(void) { @@ -93,7 +77,7 @@ static void doFormatUnitHeader(void) // Save the "MODE SELECT savable parameters" configSave( scsiDev.target->targetId, - scsiDev.target->liveCfg.bytesPerSector); + scsiDev.target->state.bytesPerSector); } if (IP) @@ -123,8 +107,10 @@ static void doReadCapacity() int pmi = scsiDev.cdb[8] & 1; uint32_t capacity = getScsiCapacity( + scsiDev.target->device, + scsiDev.device, scsiDev.target->cfg->sdSectorStart, - scsiDev.target->liveCfg.bytesPerSector, + scsiDev.target->state.bytesPerSector, scsiDev.target->cfg->scsiSectors); if (!pmi && lba) @@ -134,8 +120,8 @@ static void doReadCapacity() // assume that delays are constant across each block. But the spec // says we must return this error if pmi is specified incorrectly. scsiDev.status = CHECK_CONDITION; - scsiDev.target->sense.code = ILLEGAL_REQUEST; - scsiDev.target->sense.asc = INVALID_FIELD_IN_CDB; + scsiDev.target->state.sense.code = ILLEGAL_REQUEST; + scsiDev.target->state.sense.asc = INVALID_FIELD_IN_CDB; scsiDev.phase = STATUS; } else if (capacity > 0) @@ -147,7 +133,7 @@ static void doReadCapacity() scsiDev.data[2] = highestBlock >> 8; scsiDev.data[3] = highestBlock; - uint32_t bytesPerSector = scsiDev.target->liveCfg.bytesPerSector; + uint32_t bytesPerSector = scsiDev.target->state.bytesPerSector; scsiDev.data[4] = bytesPerSector >> 24; scsiDev.data[5] = bytesPerSector >> 16; scsiDev.data[6] = bytesPerSector >> 8; @@ -158,8 +144,8 @@ static void doReadCapacity() else { scsiDev.status = CHECK_CONDITION; - scsiDev.target->sense.code = NOT_READY; - scsiDev.target->sense.asc = MEDIUM_NOT_PRESENT; + scsiDev.target->state.sense.code = NOT_READY; + scsiDev.target->state.sense.asc = MEDIUM_NOT_PRESENT; scsiDev.phase = STATUS; } } @@ -172,19 +158,21 @@ static void doWrite(uint32 lba, uint32 blocks) CyDelay(10); } - uint32_t bytesPerSector = scsiDev.target->liveCfg.bytesPerSector; + uint32_t bytesPerSector = scsiDev.target->state.bytesPerSector; + MEDIA_STATE* mediaState = &(scsiDev.target->device->mediaState); - if (unlikely(blockDev.state & DISK_WP) || + if (unlikely(*mediaState & MEDIA_WP) || unlikely(scsiDev.target->cfg->deviceType == CONFIG_OPTICAL)) { scsiDev.status = CHECK_CONDITION; - scsiDev.target->sense.code = ILLEGAL_REQUEST; - scsiDev.target->sense.asc = WRITE_PROTECTED; + scsiDev.target->state.sense.code = ILLEGAL_REQUEST; + scsiDev.target->state.sense.asc = WRITE_PROTECTED; scsiDev.phase = STATUS; } else if (unlikely(((uint64) lba) + blocks > getScsiCapacity( + scsiDev->device, scsiDev.target->cfg->sdSectorStart, bytesPerSector, scsiDev.target->cfg->scsiSectors @@ -192,8 +180,8 @@ static void doWrite(uint32 lba, uint32 blocks) )) { scsiDev.status = CHECK_CONDITION; - scsiDev.target->sense.code = ILLEGAL_REQUEST; - scsiDev.target->sense.asc = LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; + scsiDev.target->state.sense.code = ILLEGAL_REQUEST; + scsiDev.target->state.sense.asc = LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; scsiDev.phase = STATUS; } else @@ -231,13 +219,13 @@ static void doRead(uint32 lba, uint32 blocks) uint32_t capacity = getScsiCapacity( scsiDev.target->cfg->sdSectorStart, - scsiDev.target->liveCfg.bytesPerSector, + scsiDev.target->state.bytesPerSector, scsiDev.target->cfg->scsiSectors); if (unlikely(((uint64) lba) + blocks > capacity)) { scsiDev.status = CHECK_CONDITION; - scsiDev.target->sense.code = ILLEGAL_REQUEST; - scsiDev.target->sense.asc = LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; + scsiDev.target->state.sense.code = ILLEGAL_REQUEST; + scsiDev.target->state.sense.asc = LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; scsiDev.phase = STATUS; } else @@ -248,7 +236,7 @@ static void doRead(uint32 lba, uint32 blocks) scsiDev.phase = DATA_IN; scsiDev.dataLen = 0; // No data yet - uint32_t bytesPerSector = scsiDev.target->liveCfg.bytesPerSector; + uint32_t bytesPerSector = scsiDev.target->state.bytesPerSector; uint32_t sdSectorPerSCSISector = SDSectorsPerSCSISector(bytesPerSector); uint32_t sdSectors = blocks * sdSectorPerSCSISector; @@ -284,13 +272,13 @@ static void doSeek(uint32 lba) if (lba >= getScsiCapacity( scsiDev.target->cfg->sdSectorStart, - scsiDev.target->liveCfg.bytesPerSector, + scsiDev.target->state.bytesPerSector, scsiDev.target->cfg->scsiSectors) ) { scsiDev.status = CHECK_CONDITION; - scsiDev.target->sense.code = ILLEGAL_REQUEST; - scsiDev.target->sense.asc = LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; + scsiDev.target->state.sense.code = ILLEGAL_REQUEST; + scsiDev.target->state.sense.asc = LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; scsiDev.phase = STATUS; } else @@ -301,33 +289,35 @@ static void doSeek(uint32 lba) static int doTestUnitReady() { + MEDIA_STATE* mediaState = &(scsiDev.target->device->mediaState); + int ready = 1; - if (likely(blockDev.state == (DISK_STARTED | DISK_PRESENT | DISK_INITIALISED))) + if (likely(*mediaState == (MEDIA_STARTED | MEDIA_PRESENT | MEDIA_INITIALISED))) { // nothing to do. } - else if (unlikely(!(blockDev.state & DISK_STARTED))) + else if (unlikely(!(*mediaState & MEDIA_STARTED))) { ready = 0; scsiDev.status = CHECK_CONDITION; - scsiDev.target->sense.code = NOT_READY; - scsiDev.target->sense.asc = LOGICAL_UNIT_NOT_READY_INITIALIZING_COMMAND_REQUIRED; + scsiDev.target->state.sense.code = NOT_READY; + scsiDev.target->state.sense.asc = LOGICAL_UNIT_NOT_READY_INITIALIZING_COMMAND_REQUIRED; scsiDev.phase = STATUS; } - else if (unlikely(!(blockDev.state & DISK_PRESENT))) + else if (unlikely(!(*mediaState & MEDIA_PRESENT))) { ready = 0; scsiDev.status = CHECK_CONDITION; - scsiDev.target->sense.code = NOT_READY; - scsiDev.target->sense.asc = MEDIUM_NOT_PRESENT; + scsiDev.target->state.sense.code = NOT_READY; + scsiDev.target->state.sense.asc = MEDIUM_NOT_PRESENT; scsiDev.phase = STATUS; } - else if (unlikely(!(blockDev.state & DISK_INITIALISED))) + else if (unlikely(!(*mediaState & MEDIA_INITIALISED))) { ready = 0; scsiDev.status = CHECK_CONDITION; - scsiDev.target->sense.code = NOT_READY; - scsiDev.target->sense.asc = LOGICAL_UNIT_NOT_READY_CAUSE_NOT_REPORTABLE; + scsiDev.target->state.sense.code = NOT_READY; + scsiDev.target->state.sense.asc = LOGICAL_UNIT_NOT_READY_CAUSE_NOT_REPORTABLE; scsiDev.phase = STATUS; } return ready; @@ -347,17 +337,21 @@ int scsiDiskCommand() //int immed = scsiDev.cdb[1] & 1; int start = scsiDev.cdb[4] & 1; + MEDIA_STATE* mediaState = &(scsiDev.target->device->mediaState); if (start) { - blockDev.state = blockDev.state | DISK_STARTED; - if (!(blockDev.state & DISK_INITIALISED)) + *mediaState = *mediaState | MEDIA_STARTED; + if (!(*mediaState & MEDIA_INITIALISED)) { - doSdInit(); + if (*mediaState & MEDIA_PRESENT) + { + *mediaState = *mediaState | MEDIA_INITIALISED; + } } } else { - blockDev.state &= ~DISK_STARTED; + *mediaState &= ~MEDIA_STARTED; } } else if (unlikely(command == 0x00)) @@ -514,8 +508,8 @@ int scsiDiskCommand() // TODO. This means they are supplying data to verify against. // Technically we should probably grab the data and compare it. scsiDev.status = CHECK_CONDITION; - scsiDev.target->sense.code = ILLEGAL_REQUEST; - scsiDev.target->sense.asc = INVALID_FIELD_IN_CDB; + scsiDev.target->state.sense.code = ILLEGAL_REQUEST; + scsiDev.target->state.sense.asc = INVALID_FIELD_IN_CDB; scsiDev.phase = STATUS; } } @@ -548,7 +542,7 @@ int scsiDiskCommand() void scsiDiskPoll() { - uint32_t bytesPerSector = scsiDev.target->liveCfg.bytesPerSector; + uint32_t bytesPerSector = scsiDev.target->state.bytesPerSector; if (scsiDev.phase == DATA_IN && transfer.currentBlock != transfer.blocks) @@ -799,8 +793,8 @@ void scsiDiskPoll() (scsiDev.boardCfg.flags & CONFIG_ENABLE_PARITY) && (scsiDev.compatMode >= COMPAT_SCSI2)) { - scsiDev.target->sense.code = ABORTED_COMMAND; - scsiDev.target->sense.asc = SCSI_PARITY_ERROR; + scsiDev.target->state.sense.code = ABORTED_COMMAND; + scsiDev.target->state.sense.asc = SCSI_PARITY_ERROR; scsiDev.status = CHECK_CONDITION;; } scsiDev.phase = STATUS; @@ -834,8 +828,6 @@ void scsiDiskInit() { scsiDiskReset(); - // Don't require the host to send us a START STOP UNIT command - blockDev.state = DISK_STARTED; // WP pin not available for micro-sd // TODO read card WP register #if 0 diff --git a/software/SCSI2SD/src/disk.h b/software/SCSI2SD/src/disk.h index df197d7..f78b032 100755 --- a/software/SCSI2SD/src/disk.h +++ b/software/SCSI2SD/src/disk.h @@ -17,25 +17,12 @@ #ifndef DISK_H #define DISK_H -typedef enum -{ - DISK_STARTED = 1, // Controlled via START STOP UNIT - DISK_PRESENT = 2, // SD card is physically present - DISK_INITIALISED = 4, // SD card responded to init sequence - DISK_WP = 8 // Write-protect. -} DISK_STATE; - typedef enum { TRANSFER_READ, TRANSFER_WRITE } TRANSFER_DIR; -typedef struct -{ - int state; -} BlockDevice; - typedef struct { int multiBlock; // True if we're using a multi-block SPI transfer. @@ -45,7 +32,6 @@ typedef struct uint32 currentBlock; } Transfer; -extern BlockDevice blockDev; extern Transfer transfer; void scsiDiskInit(void); diff --git a/software/SCSI2SD/src/geometry.h b/software/SCSI2SD/src/geometry.h index 8df3d4c..76da6e1 100755 --- a/software/SCSI2SD/src/geometry.h +++ b/software/SCSI2SD/src/geometry.h @@ -20,7 +20,7 @@ #include "device.h" #include "config.h" -#include "sd.h" +#include "storedevice.h" typedef enum { @@ -35,6 +35,7 @@ static inline int SDSectorsPerSCSISector(uint16_t bytesPerSector) } uint32_t getScsiCapacity( + S2S_Device* device, uint32_t sdSectorStart, uint16_t bytesPerSector, uint32_t scsiSectors); diff --git a/software/SCSI2SD/src/inquiry.c b/software/SCSI2SD/src/inquiry.c index 3b84c52..b51069d 100755 --- a/software/SCSI2SD/src/inquiry.c +++ b/software/SCSI2SD/src/inquiry.c @@ -116,8 +116,8 @@ static void useCustomVPD(const TargetConfig* cfg, int pageCode) { // error. scsiDev.status = CHECK_CONDITION; - scsiDev.target->sense.code = ILLEGAL_REQUEST; - scsiDev.target->sense.asc = INVALID_FIELD_IN_CDB; + scsiDev.target->state.sense.code = ILLEGAL_REQUEST; + scsiDev.target->state.sense.asc = INVALID_FIELD_IN_CDB; scsiDev.phase = STATUS; } } @@ -141,8 +141,8 @@ void scsiInquiry() { // error. scsiDev.status = CHECK_CONDITION; - scsiDev.target->sense.code = ILLEGAL_REQUEST; - scsiDev.target->sense.asc = INVALID_FIELD_IN_CDB; + scsiDev.target->state.sense.code = ILLEGAL_REQUEST; + scsiDev.target->state.sense.asc = INVALID_FIELD_IN_CDB; scsiDev.phase = STATUS; } else @@ -206,8 +206,8 @@ void scsiInquiry() { // error. scsiDev.status = CHECK_CONDITION; - scsiDev.target->sense.code = ILLEGAL_REQUEST; - scsiDev.target->sense.asc = INVALID_FIELD_IN_CDB; + scsiDev.target->state.sense.code = ILLEGAL_REQUEST; + scsiDev.target->state.sense.asc = INVALID_FIELD_IN_CDB; scsiDev.phase = STATUS; } diff --git a/software/SCSI2SD/src/main.c b/software/SCSI2SD/src/main.c index aa144bd..f552923 100755 --- a/software/SCSI2SD/src/main.c +++ b/software/SCSI2SD/src/main.c @@ -29,6 +29,7 @@ int main() { timeInit(); ledInit(); + s2s_deviceEarlyInit(); traceInit(); // Enable global interrupts. @@ -41,6 +42,7 @@ int main() configInit(&scsiDev.boardCfg); debugInit(); + scsiPhyConfig(); scsiInit(); @@ -60,7 +62,6 @@ int main() ++delaySeconds; } - uint32_t lastSDPoll = getTime_ms(); sdCheckPresent(); while (1) @@ -74,10 +75,10 @@ int main() if (unlikely(scsiDev.phase == BUS_FREE)) { - if (unlikely(elapsedTime_ms(lastSDPoll) > 200)) + if (s2s_pollMediaChange()) { - lastSDPoll = getTime_ms(); - sdCheckPresent(); + scsiPhyConfig(); + scsiInit(); } else { @@ -94,10 +95,11 @@ int main() CyExitCriticalSection(interruptState); } } - else if ((scsiDev.phase >= 0) && (blockDev.state & DISK_PRESENT)) + else if ((scsiDev.phase >= 0) && + scsiDev.target && + (scsiDev.target->device->mediaState & MEDIA_PRESENT)) { - // don't waste time scanning SD cards while we're doing disk IO - lastSDPoll = getTime_ms(); + scsiDev.target->device->pollMediaBusy(); } } return 0; diff --git a/software/SCSI2SD/src/mode.c b/software/SCSI2SD/src/mode.c index bb16cf7..5c2e4dc 100755 --- a/software/SCSI2SD/src/mode.c +++ b/software/SCSI2SD/src/mode.c @@ -269,7 +269,12 @@ static int useCustomPages(const TargetConfig* cfg, int pc, int pageCode, int* id } static void doModeSense( - int sixByteCmd, int dbd, int pc, int pageCode, int allocLength) + S2S_Device* dev, + int sixByteCmd, + int dbd, + int pc, + int pageCode, + int allocLength) { ////////////// Mode Parameter Header //////////////////////////////////// @@ -288,14 +293,14 @@ static void doModeSense( mediumType = 0; // We should support various floppy types here! // Contains cache bits (0) and a Write-Protect bit. deviceSpecificParam = - (blockDev.state & DISK_WP) ? 0x80 : 0; + (dev->mediaState & MEDIA_WP) ? 0x80 : 0; density = 0; // reserved for direct access break; case CONFIG_FLOPPY_14MB: mediumType = 0x1E; // 90mm/3.5" deviceSpecificParam = - (blockDev.state & DISK_WP) ? 0x80 : 0; + (dev->mediaState & MEDIA_WP) ? 0x80 : 0; density = 0; // reserved for direct access break; @@ -308,14 +313,14 @@ static void doModeSense( case CONFIG_SEQUENTIAL: mediumType = 0; // reserved deviceSpecificParam = - (blockDev.state & DISK_WP) ? 0x80 : 0; - density = 0x13; // DAT Data Storage, X3B5/88-185A + (dev->mediaState & MEDIA_WP) ? 0x80 : 0; + density = 0x13; // DAT Data Storage, X3B5/88-185A break; case CONFIG_MO: - mediumType = 0x03; // Optical reversible or erasable medium + mediumType = 0x03; // Optical reversible or erasable medium deviceSpecificParam = - (blockDev.state & DISK_WP) ? 0x80 : 0; + (dev->mediaState & MEDIA_WP) ? 0x80 : 0; density = 0x00; // Default break; @@ -368,7 +373,7 @@ static void doModeSense( scsiDev.data[idx++] = 0; // reserved // Block length - uint32_t bytesPerSector = scsiDev.target->liveCfg.bytesPerSector; + uint32_t bytesPerSector = scsiDev.target->state.bytesPerSector; scsiDev.data[idx++] = bytesPerSector >> 16; scsiDev.data[idx++] = bytesPerSector >> 8; scsiDev.data[idx++] = bytesPerSector & 0xFF; @@ -423,7 +428,7 @@ static void doModeSense( scsiDev.data[idx+11] = sectorsPerTrack & 0xFF; // Fill out the configured bytes-per-sector - uint32_t bytesPerSector = scsiDev.target->liveCfg.bytesPerSector; + uint32_t bytesPerSector = scsiDev.target->state.bytesPerSector; scsiDev.data[idx+12] = bytesPerSector >> 8; scsiDev.data[idx+13] = bytesPerSector & 0xFF; } @@ -457,8 +462,9 @@ static void doModeSense( uint32 sector; LBA2CHS( getScsiCapacity( + scsiDev.target->device, scsiDev.target->cfg->sdSectorStart, - scsiDev.target->liveCfg.bytesPerSector, + scsiDev.target->state.bytesPerSector, scsiDev.target->cfg->scsiSectors), &cyl, &head, @@ -557,8 +563,8 @@ static void doModeSense( // Unknown Page Code pageFound = 0; scsiDev.status = CHECK_CONDITION; - scsiDev.target->sense.code = ILLEGAL_REQUEST; - scsiDev.target->sense.asc = INVALID_FIELD_IN_CDB; + scsiDev.target->state.sense.code = ILLEGAL_REQUEST; + scsiDev.target->state.sense.asc = INVALID_FIELD_IN_CDB; scsiDev.phase = STATUS; } else @@ -617,7 +623,7 @@ static void doModeSelect(void) } else { - scsiDev.target->liveCfg.bytesPerSector = bytesPerSector; + scsiDev.target->state.bytesPerSector = bytesPerSector; if (bytesPerSector != scsiDev.target->cfg->bytesPerSector) { configSave(scsiDev.target->targetId, bytesPerSector); @@ -650,7 +656,7 @@ static void doModeSelect(void) goto bad; } - scsiDev.target->liveCfg.bytesPerSector = bytesPerSector; + scsiDev.target->state.bytesPerSector = bytesPerSector; if (scsiDev.cdb[1] & 1) // SP Save Pages flag { configSave(scsiDev.target->targetId, bytesPerSector); @@ -669,14 +675,14 @@ static void doModeSelect(void) goto out; bad: scsiDev.status = CHECK_CONDITION; - scsiDev.target->sense.code = ILLEGAL_REQUEST; - scsiDev.target->sense.asc = INVALID_FIELD_IN_PARAMETER_LIST; + scsiDev.target->state.sense.code = ILLEGAL_REQUEST; + scsiDev.target->state.sense.asc = INVALID_FIELD_IN_PARAMETER_LIST; out: scsiDev.phase = STATUS; } -int scsiModeCommand() +int scsiModeCommand(S2S_Device* dev) { int commandHandled = 1; @@ -696,7 +702,7 @@ int scsiModeCommand() // SCSI1 standard: (CCS X3T9.2/86-52) // "An Allocation Length of zero indicates that no MODE SENSE data shall // be transferred. This condition shall not be considered as an error." - doModeSense(1, dbd, pc, pageCode, allocLength); + doModeSense(dev, 1, dbd, pc, pageCode, allocLength); } else if (command == 0x5A) { @@ -707,7 +713,7 @@ int scsiModeCommand() int allocLength = (((uint16) scsiDev.cdb[7]) << 8) + scsiDev.cdb[8]; - doModeSense(0, dbd, pc, pageCode, allocLength); + doModeSense(dev, 0, dbd, pc, pageCode, allocLength); } else if (command == 0x15) { diff --git a/software/SCSI2SD/src/mode.h b/software/SCSI2SD/src/mode.h index 819b1f5..887e91a 100755 --- a/software/SCSI2SD/src/mode.h +++ b/software/SCSI2SD/src/mode.h @@ -17,6 +17,6 @@ #ifndef MODE_H #define MODE_H -int scsiModeCommand(void); +int scsiModeCommand(S2S_Device* dev); #endif diff --git a/software/SCSI2SD/src/scsi.c b/software/SCSI2SD/src/scsi.c index dc39968..a4d59f0 100755 --- a/software/SCSI2SD/src/scsi.c +++ b/software/SCSI2SD/src/scsi.c @@ -132,8 +132,8 @@ static void enter_Status(uint8 status) scsiDev.phase = STATUS; scsiDev.lastStatus = scsiDev.status; - scsiDev.lastSense = scsiDev.target->sense.code; - scsiDev.lastSenseASC = scsiDev.target->sense.asc; + scsiDev.lastSense = scsiDev.target->state.sense.code; + scsiDev.lastSenseASC = scsiDev.target->state.sense.asc; } void process_Status() @@ -192,7 +192,7 @@ void process_Status() } else if (scsiDev.target->cfg->quirks == CONFIG_QUIRKS_OMTI) { - scsiDev.status |= (scsiDev.target->targetId & 0x03) << 5; + scsiDev.status |= (scsiDev.target->cfg->scsiId & 0x03) << 5; scsiWriteByte(scsiDev.status); } else @@ -201,8 +201,8 @@ void process_Status() } scsiDev.lastStatus = scsiDev.status; - scsiDev.lastSense = scsiDev.target->sense.code; - scsiDev.lastSenseASC = scsiDev.target->sense.asc; + scsiDev.lastSense = scsiDev.target->state.sense.code; + scsiDev.lastSenseASC = scsiDev.target->state.sense.asc; // Command Complete occurs AFTER a valid status has been @@ -262,8 +262,8 @@ static void process_DataOut() (scsiDev.boardCfg.flags & CONFIG_ENABLE_PARITY) && (scsiDev.compatMode >= COMPAT_SCSI2)) { - scsiDev.target->sense.code = ABORTED_COMMAND; - scsiDev.target->sense.asc = SCSI_PARITY_ERROR; + scsiDev.target->state.sense.code = ABORTED_COMMAND; + scsiDev.target->state.sense.asc = SCSI_PARITY_ERROR; enter_Status(CHECK_CONDITION); } } @@ -318,15 +318,11 @@ static void process_Command() // http://bitsavers.trailing-edge.com/pdf/xebec/104524C_S1410Man_Aug83.pdf if ((scsiDev.lun > 0) && (scsiDev.boardCfg.flags & CONFIG_MAP_LUNS_TO_IDS)) { - int tgtIndex; - for (tgtIndex = 0; tgtIndex < MAX_SCSI_TARGETS; ++tgtIndex) + S2S_Target* lunTarget = s2s_DeviceFindByScsiId(scsiDev.lun); + if (lunTarget! = NULL) { - if (scsiDev.targets[tgtIndex].targetId == scsiDev.lun) - { - scsiDev.target = &scsiDev.targets[tgtIndex]; - scsiDev.lun = 0; - break; - } + scsiDev.target = lunTarget; + scsiDev.lun = 0; } } @@ -347,8 +343,8 @@ static void process_Command() (scsiDev.boardCfg.flags & CONFIG_ENABLE_PARITY) && (scsiDev.compatMode >= COMPAT_SCSI2)) { - scsiDev.target->sense.code = ABORTED_COMMAND; - scsiDev.target->sense.asc = SCSI_PARITY_ERROR; + scsiDev.target->state.sense.code = ABORTED_COMMAND; + scsiDev.target->state.sense.asc = SCSI_PARITY_ERROR; enter_Status(CHECK_CONDITION); } else if ((control & 0x02) && ((control & 0x01) == 0) && @@ -356,8 +352,8 @@ static void process_Command() likely(scsiDev.target->cfg->quirks != CONFIG_QUIRKS_XEBEC)) { // FLAG set without LINK flag. - scsiDev.target->sense.code = ILLEGAL_REQUEST; - scsiDev.target->sense.asc = INVALID_FIELD_IN_CDB; + scsiDev.target->state.sense.code = ILLEGAL_REQUEST; + scsiDev.target->state.sense.asc = INVALID_FIELD_IN_CDB; enter_Status(CHECK_CONDITION); } else if (command == 0x12) @@ -373,11 +369,11 @@ static void process_Command() { // Completely non-standard allocLength = 4; - if (scsiDev.target->sense.code == NO_SENSE) + if (scsiDev.target->state.sense.code == NO_SENSE) scsiDev.data[0] = 0; - else if (scsiDev.target->sense.code == ILLEGAL_REQUEST) + else if (scsiDev.target->state.sense.code == ILLEGAL_REQUEST) scsiDev.data[0] = 0x20; // Illegal command - else if (scsiDev.target->sense.code == NOT_READY) + else if (scsiDev.target->state.sense.code == NOT_READY) scsiDev.data[0] = 0x04; // Drive not ready else scsiDev.data[0] = 0x11; // Uncorrectable data error @@ -395,7 +391,7 @@ static void process_Command() memset(scsiDev.data, 0, 256); // Max possible alloc length scsiDev.data[0] = 0xF0; - scsiDev.data[2] = scsiDev.target->sense.code & 0x0F; + scsiDev.data[2] = scsiDev.target->state.sense.code & 0x0F; scsiDev.data[3] = transfer.lba >> 24; scsiDev.data[4] = transfer.lba >> 16; @@ -404,45 +400,45 @@ static void process_Command() // Additional bytes if there are errors to report scsiDev.data[7] = 10; // additional length - scsiDev.data[12] = scsiDev.target->sense.asc >> 8; - scsiDev.data[13] = scsiDev.target->sense.asc; + scsiDev.data[12] = scsiDev.target->state.sense.asc >> 8; + scsiDev.data[13] = scsiDev.target->state.sense.asc; } // Silently truncate results. SCSI-2 spec 8.2.14. enter_DataIn(allocLength); // This is a good time to clear out old sense information. - scsiDev.target->sense.code = NO_SENSE; - scsiDev.target->sense.asc = NO_ADDITIONAL_SENSE_INFORMATION; + scsiDev.target->state.sense.code = NO_SENSE; + scsiDev.target->state.sense.asc = NO_ADDITIONAL_SENSE_INFORMATION; } // Some old SCSI drivers do NOT properly support // unitAttention. eg. the Mac Plus would trigger a SCSI reset // on receiving the unit attention response on boot, thus // triggering another unit attention condition. - else if (scsiDev.target->unitAttention && + else if (scsiDev.target->state.unitAttention && (scsiDev.boardCfg.flags & CONFIG_ENABLE_UNIT_ATTENTION)) { - scsiDev.target->sense.code = UNIT_ATTENTION; - scsiDev.target->sense.asc = scsiDev.target->unitAttention; + scsiDev.target->state.sense.code = UNIT_ATTENTION; + scsiDev.target->state.sense.asc = scsiDev.target->state.unitAttention; // If initiator doesn't do REQUEST SENSE for the next command, then // data is lost. - scsiDev.target->unitAttention = 0; + scsiDev.target->state.unitAttention = 0; enter_Status(CHECK_CONDITION); } else if (scsiDev.lun) { - scsiDev.target->sense.code = ILLEGAL_REQUEST; - scsiDev.target->sense.asc = LOGICAL_UNIT_NOT_SUPPORTED; + scsiDev.target->state.sense.code = ILLEGAL_REQUEST; + scsiDev.target->state.sense.asc = LOGICAL_UNIT_NOT_SUPPORTED; enter_Status(CHECK_CONDITION); } else if (command == 0x17 || command == 0x16) { doReserveRelease(); } - else if ((scsiDev.target->reservedId >= 0) && - (scsiDev.target->reservedId != scsiDev.initiatorId)) + else if ((scsiDev.target->state.reservedId >= 0) && + (scsiDev.target->state.reservedId != scsiDev.initiatorId)) { enter_Status(CONFLICT); } @@ -481,10 +477,10 @@ static void process_Command() { scsiReadBuffer(); } - else if (!scsiModeCommand() && !scsiVendorCommand()) + else if (!scsiModeCommand(scsiDev.target->device) && !scsiVendorCommand()) { - scsiDev.target->sense.code = ILLEGAL_REQUEST; - scsiDev.target->sense.asc = INVALID_COMMAND_OPERATION_CODE; + scsiDev.target->state.sense.code = ILLEGAL_REQUEST; + scsiDev.target->state.sense.asc = INVALID_COMMAND_OPERATION_CODE; enter_Status(CHECK_CONDITION); } @@ -504,25 +500,25 @@ static void doReserveRelease() uint8 command = scsiDev.cdb[0]; int canRelease = - (!thirdPty && (scsiDev.initiatorId == scsiDev.target->reservedId)) || + (!thirdPty && (scsiDev.initiatorId == scsiDev.target->state.reservedId)) || (thirdPty && - (scsiDev.target->reserverId == scsiDev.initiatorId) && - (scsiDev.target->reservedId == thirdPtyId) + (scsiDev.target->state.reserverId == scsiDev.initiatorId) && + (scsiDev.target->state.reservedId == thirdPtyId) ); if (extentReservation) { // Not supported. - scsiDev.target->sense.code = ILLEGAL_REQUEST; - scsiDev.target->sense.asc = INVALID_FIELD_IN_CDB; + scsiDev.target->state.sense.code = ILLEGAL_REQUEST; + scsiDev.target->state.sense.asc = INVALID_FIELD_IN_CDB; enter_Status(CHECK_CONDITION); } else if (command == 0x17) // release { - if ((scsiDev.target->reservedId < 0) || canRelease) + if ((scsiDev.target->state.reservedId < 0) || canRelease) { - scsiDev.target->reservedId = -1; - scsiDev.target->reserverId = -1; + scsiDev.target->state.reservedId = -1; + scsiDev.target->state.reserverId = -1; } else { @@ -531,16 +527,16 @@ static void doReserveRelease() } else // assume reserve. { - if ((scsiDev.target->reservedId < 0) || canRelease) + if ((scsiDev.target->state.reservedId < 0) || canRelease) { - scsiDev.target->reserverId = scsiDev.initiatorId; + scsiDev.target->state.reserverId = scsiDev.initiatorId; if (thirdPty) { - scsiDev.target->reservedId = thirdPtyId; + scsiDev.target->state.reservedId = thirdPtyId; } else { - scsiDev.target->reservedId = scsiDev.initiatorId; + scsiDev.target->state.reservedId = scsiDev.initiatorId; } } else @@ -569,14 +565,14 @@ static void scsiReset() if (scsiDev.target) { - if (scsiDev.target->unitAttention != POWER_ON_RESET) + if (scsiDev.target->state.unitAttention != POWER_ON_RESET) { - scsiDev.target->unitAttention = SCSI_BUS_RESET; + scsiDev.target->state.unitAttention = SCSI_BUS_RESET; } - scsiDev.target->reservedId = -1; - scsiDev.target->reserverId = -1; - scsiDev.target->sense.code = NO_SENSE; - scsiDev.target->sense.asc = NO_ADDITIONAL_SENSE_INFORMATION; + scsiDev.target->state.reservedId = -1; + scsiDev.target->state.reserverId = -1; + scsiDev.target->state.sense.code = NO_SENSE; + scsiDev.target->state.sense.asc = NO_ADDITIONAL_SENSE_INFORMATION; } scsiDev.target = NULL; scsiDiskReset(); @@ -666,16 +662,16 @@ static void process_SelectionPhase() int goodParity = (Lookup_OddParity[mask] == SCSI_ReadPin(SCSI_In_DBP)); int atnFlag = SCSI_ReadFilt(SCSI_Filt_ATN); - int tgtIndex; - TargetState* target = NULL; - for (tgtIndex = 0; tgtIndex < MAX_SCSI_TARGETS; ++tgtIndex) + S2S_Target* target = NULL; + for (int testIdx = 0; testtIndex < 8; ++testtIndex) { - if (mask & (1 << scsiDev.targets[tgtIndex].targetId)) + target = s2s_DeviceFindByScsiId(1 << testIdx); + if (target) { - target = &scsiDev.targets[tgtIndex]; break; } } + sel &= (selLatchCfg && scsiDev.selFlag) || SCSI_ReadFilt(SCSI_Filt_SEL); bsy |= SCSI_ReadFilt(SCSI_Filt_BSY); #ifdef SCSI_In_IO @@ -709,7 +705,7 @@ static void process_SelectionPhase() // controllers don't generate parity bits. if (!scsiDev.atnFlag) { - target->unitAttention = 0; + target->state.unitAttention = 0; scsiDev.compatMode = COMPAT_SCSI1; } else if (!(scsiDev.boardCfg.flags & CONFIG_ENABLE_SCSI2)) @@ -816,11 +812,11 @@ static void process_MessageOut() scsiDiskReset(); - scsiDev.target->unitAttention = SCSI_BUS_RESET; + scsiDev.target->state.unitAttention = SCSI_BUS_RESET; // ANY initiator can reset the reservation state via this message. - scsiDev.target->reservedId = -1; - scsiDev.target->reserverId = -1; + scsiDev.target->state.reservedId = -1; + scsiDev.target->state.reserverId = -1; enter_BusFree(); } else if (scsiDev.msgOut == 0x05) @@ -1055,27 +1051,25 @@ void scsiInit() scsiDev.target = NULL; scsiDev.compatMode = COMPAT_UNKNOWN; - int i; - for (i = 0; i < MAX_SCSI_TARGETS; ++i) + int deviceCount; + S2S_Device* allDevices = s2s_GetDevices(&deviceCount); + for (int devIdx = 0; devIdx < deviceCount; ++devIdx) { - const TargetConfig* cfg = getConfigByIndex(i); - if (cfg && (cfg->scsiId & CONFIG_TARGET_ENABLED)) - { - scsiDev.targets[i].targetId = cfg->scsiId & CONFIG_TARGET_ID_BITS; - scsiDev.targets[i].cfg = cfg; + int targetCount; + S2S_Target* targets = devices[deviceIdx].getTargets(devices + deviceIdx, &targetCount); - scsiDev.targets[i].liveCfg.bytesPerSector = cfg->bytesPerSector; - } - else + for (int i = 0; i < targetCount; ++i) { - scsiDev.targets[i].targetId = 0xff; - scsiDev.targets[i].cfg = NULL; + S2S_TargetState* state = &(targets[i].state); + + scsiDev.targets[i].state.reservedId = -1; + scsiDev.targets[i].state.reserverId = -1; + scsiDev.targets[i].state.unitAttention = POWER_ON_RESET; + scsiDev.targets[i].state.sense.code = NO_SENSE; + scsiDev.targets[i].state.sense.asc = NO_ADDITIONAL_SENSE_INFORMATION; + + state->bytesPerSector = targets[i].cfg->bytesPerSector; } - scsiDev.targets[i].reservedId = -1; - scsiDev.targets[i].reserverId = -1; - scsiDev.targets[i].unitAttention = POWER_ON_RESET; - scsiDev.targets[i].sense.code = NO_SENSE; - scsiDev.targets[i].sense.asc = NO_ADDITIONAL_SENSE_INFORMATION; } } diff --git a/software/SCSI2SD/src/scsi.h b/software/SCSI2SD/src/scsi.h index d1a9f54..a259105 100755 --- a/software/SCSI2SD/src/scsi.h +++ b/software/SCSI2SD/src/scsi.h @@ -17,8 +17,8 @@ #ifndef SCSI_H #define SCSI_H +#include "storedevice.h" #include "geometry.h" -#include "sense.h" typedef enum { @@ -73,37 +73,9 @@ typedef enum #define MAX_SECTOR_SIZE 8192 #define MIN_SECTOR_SIZE 64 -// Shadow parameters, possibly not saved to flash yet. -// Set via Mode Select typedef struct { - uint16_t bytesPerSector; -} LiveCfg; - -typedef struct -{ - uint8_t targetId; - - const TargetConfig* cfg; - - LiveCfg liveCfg; - - ScsiSense sense; - - uint16 unitAttention; // Set to the sense qualifier key to be returned. - - // Only let the reserved initiator talk to us. - // A 3rd party may be sending the RESERVE/RELEASE commands - int reservedId; // 0 -> 7 if reserved. -1 if not reserved. - int reserverId; // 0 -> 7 if reserved. -1 if not reserved. -} TargetState; - -typedef struct -{ - TargetState targets[MAX_SCSI_TARGETS]; - TargetState* target; - BoardConfig boardCfg; - + S2S_Target* target; // Set to true (1) if the ATN flag was set, and we need to // enter the MESSAGE_OUT phase. diff --git a/software/SCSI2SD/src/sd.c b/software/SCSI2SD/src/sd.c index 6cd9029..3014e70 100755 --- a/software/SCSI2SD/src/sd.c +++ b/software/SCSI2SD/src/sd.c @@ -28,8 +28,23 @@ #include +static void sd_earlyInit(S2S_Device* dev); +static S2S_Target* sd_getTargets(S2S_Device* dev, int* count); +static uint32_t sd_getCapacity(S2S_Device* dev); +static int sd_pollMediaChange(S2S_Device* dev); +static void sd_pollMediaBusy(S2S_Device* dev); + // Global -SdDevice sdDev; +SdCard sdCard S2S_DMA_ALIGN = { + { + sd_earlyInit, + sd_getTargets, + sd_getCapacity, + sd_pollMediaChange, + sd_pollMediaBusy + } +}; +S2S_Device* sdDevice = &(sdCard.dev); enum SD_CMD_STATE { CMD_STATE_IDLE, CMD_STATE_READ, CMD_STATE_WRITE }; static int sdCmdState = CMD_STATE_IDLE; @@ -268,7 +283,7 @@ sdReadMultiSectorPrep(uint32_t sdLBA, uint32_t sdSectors) { uint32_t tmpNextLBA = sdLBA + sdSectors; - if (!sdDev.ccs) + if (!sdCard.ccs) { sdLBA = sdLBA * SD_SECTOR_SIZE; tmpNextLBA = tmpNextLBA * SD_SECTOR_SIZE; @@ -291,8 +306,8 @@ sdReadMultiSectorPrep(uint32_t sdLBA, uint32_t sdSectors) sdClearStatus(); scsiDev.status = CHECK_CONDITION; - scsiDev.target->sense.code = HARDWARE_ERROR; - scsiDev.target->sense.asc = LOGICAL_UNIT_COMMUNICATION_FAILURE; + scsiDev.target->state.sense.code = HARDWARE_ERROR; + scsiDev.target->state.sense.asc = LOGICAL_UNIT_COMMUNICATION_FAILURE; scsiDev.phase = STATUS; } else @@ -330,8 +345,8 @@ dmaReadSector(uint8_t* outputBuffer) if (scsiDev.status != CHECK_CONDITION) { scsiDev.status = CHECK_CONDITION; - scsiDev.target->sense.code = HARDWARE_ERROR; - scsiDev.target->sense.asc = UNRECOVERED_READ_ERROR; + scsiDev.target->state.sense.code = HARDWARE_ERROR; + scsiDev.target->state.sense.asc = UNRECOVERED_READ_ERROR; scsiDev.phase = STATUS; } sdClearStatus(); @@ -399,7 +414,7 @@ void sdReadSingleSectorDMA(uint32_t lba, uint8_t* outputBuffer) sdPreCmdState(CMD_STATE_READ); uint8 v; - if (!sdDev.ccs) + if (!sdCard.ccs) { lba = lba * SD_SECTOR_SIZE; } @@ -410,8 +425,8 @@ void sdReadSingleSectorDMA(uint32_t lba, uint8_t* outputBuffer) sdClearStatus(); scsiDev.status = CHECK_CONDITION; - scsiDev.target->sense.code = HARDWARE_ERROR; - scsiDev.target->sense.asc = LOGICAL_UNIT_COMMUNICATION_FAILURE; + scsiDev.target->state.sense.code = HARDWARE_ERROR; + scsiDev.target->state.sense.asc = LOGICAL_UNIT_COMMUNICATION_FAILURE; scsiDev.phase = STATUS; } else @@ -446,8 +461,8 @@ static void sdCompleteRead() if (unlikely(r1b) && (scsiDev.phase == DATA_IN)) { scsiDev.status = CHECK_CONDITION; - scsiDev.target->sense.code = HARDWARE_ERROR; - scsiDev.target->sense.asc = UNRECOVERED_READ_ERROR; + scsiDev.target->state.sense.code = HARDWARE_ERROR; + scsiDev.target->state.sense.asc = UNRECOVERED_READ_ERROR; scsiDev.phase = STATUS; } } @@ -544,8 +559,8 @@ sdWriteSectorDMAPoll() sdClearStatus(); scsiDev.status = CHECK_CONDITION; - scsiDev.target->sense.code = HARDWARE_ERROR; - scsiDev.target->sense.asc = LOGICAL_UNIT_COMMUNICATION_FAILURE; + scsiDev.target->state.sense.code = HARDWARE_ERROR; + scsiDev.target->state.sense.asc = LOGICAL_UNIT_COMMUNICATION_FAILURE; scsiDev.phase = STATUS; } else @@ -599,8 +614,8 @@ static void sdCompleteWrite() { sdClearStatus(); scsiDev.status = CHECK_CONDITION; - scsiDev.target->sense.code = HARDWARE_ERROR; - scsiDev.target->sense.asc = WRITE_ERROR_AUTO_REALLOCATION_FAILED; + scsiDev.target->state.sense.code = HARDWARE_ERROR; + scsiDev.target->state.sense.asc = WRITE_ERROR_AUTO_REALLOCATION_FAILED; scsiDev.phase = STATUS; } } @@ -627,7 +642,7 @@ static int sendIfCond() if (status == SD_R1_IDLE) { // Version 2 card. - sdDev.version = 2; + sdCard.version = 2; // Read 32bit response. Should contain the same bytes that // we sent in the command parameter. sdSpiByte(0xFF); @@ -639,7 +654,7 @@ static int sendIfCond() else if (status & SD_R1_ILLEGAL) { // Version 1 card. - sdDev.version = 1; + sdCard.version = 1; sdClearStatus(); break; } @@ -688,7 +703,7 @@ static int sdReadOCR() buf[i] = sdSpiByte(0xFF); } - sdDev.ccs = (buf[0] & 0x40) ? 1 : 0; + sdCard.ccs = (buf[0] & 0x40) ? 1 : 0; complete = (buf[0] & 0x80); } while (!status && @@ -715,7 +730,7 @@ static void sdReadCID() for (i = 0; i < 16; ++i) { - sdDev.cid[i] = sdSpiByte(0xFF); + sdCard.cid[i] = sdSpiByte(0xFF); } sdSpiByte(0xFF); // CRC sdSpiByte(0xFF); // CRC @@ -738,30 +753,30 @@ static int sdReadCSD() for (i = 0; i < 16; ++i) { - sdDev.csd[i] = sdSpiByte(0xFF); + sdCard.csd[i] = sdSpiByte(0xFF); } sdSpiByte(0xFF); // CRC sdSpiByte(0xFF); // CRC - if ((sdDev.csd[0] >> 6) == 0x00) + if ((sdCard.csd[0] >> 6) == 0x00) { // CSD version 1 // C_SIZE in bits [73:62] - uint32 c_size = (((((uint32)sdDev.csd[6]) & 0x3) << 16) | (((uint32)sdDev.csd[7]) << 8) | sdDev.csd[8]) >> 6; - uint32 c_mult = (((((uint32)sdDev.csd[9]) & 0x3) << 8) | ((uint32)sdDev.csd[0xa])) >> 7; - uint32 sectorSize = sdDev.csd[5] & 0x0F; - sdDev.capacity = ((c_size+1) * ((uint64)1 << (c_mult+2)) * ((uint64)1 << sectorSize)) / SD_SECTOR_SIZE; + uint32 c_size = (((((uint32)sdCard.csd[6]) & 0x3) << 16) | (((uint32)sdCard.csd[7]) << 8) | sdCard.csd[8]) >> 6; + uint32 c_mult = (((((uint32)sdCard.csd[9]) & 0x3) << 8) | ((uint32)sdCard.csd[0xa])) >> 7; + uint32 sectorSize = sdCard.csd[5] & 0x0F; + sdCard.capacity = ((c_size+1) * ((uint64)1 << (c_mult+2)) * ((uint64)1 << sectorSize)) / SD_SECTOR_SIZE; } - else if ((sdDev.csd[0] >> 6) == 0x01) + else if ((sdCard.csd[0] >> 6) == 0x01) { // CSD version 2 // C_SIZE in bits [69:48] uint32 c_size = - ((((uint32)sdDev.csd[7]) & 0x3F) << 16) | - (((uint32)sdDev.csd[8]) << 8) | - ((uint32)sdDev.csd[7]); - sdDev.capacity = (c_size + 1) * 1024; + ((((uint32)sdCard.csd[7]) & 0x3F) << 16) | + (((uint32)sdCard.csd[8]) << 8) | + ((uint32)sdCard.csd[7]); + sdCard.capacity = (c_size + 1) * 1024; } else { @@ -809,11 +824,11 @@ int sdInit() uint8 v; sdCmdState = CMD_STATE_IDLE; - sdDev.version = 0; - sdDev.ccs = 0; - sdDev.capacity = 0; - memset(sdDev.csd, 0, sizeof(sdDev.csd)); - memset(sdDev.cid, 0, sizeof(sdDev.cid)); + sdCard.version = 0; + sdCard.ccs = 0; + sdCard.capacity = 0; + memset(sdCard.csd, 0, sizeof(sdCard.csd)); + memset(sdCard.cid, 0, sizeof(sdCard.cid)); sdInitDMA(); @@ -848,7 +863,7 @@ int sdInit() if (!sdOpCond()) goto bad; // ACMD41. Wait for init completes. if (!sdReadOCR()) goto bad; // CMD58. Get CCS flag. Only valid after init. - // This command will be ignored if sdDev.ccs is set. + // This command will be ignored if sdCard.ccs is set. // SDHC and SDXC are always 512bytes. v = sdCRCCommandAndResponse(SD_SET_BLOCKLEN, SD_SECTOR_SIZE); //Force sector size if(v){goto bad;} @@ -882,7 +897,7 @@ int sdInit() bad: SD_Data_Clk_SetDivider(clkDiv25MHz); // Restore the clock for our next retry - sdDev.capacity = 0; + sdCard.capacity = 0; out: sdClearStatus(); @@ -895,7 +910,7 @@ void sdWriteMultiSectorPrep(uint32_t sdLBA, uint32_t sdSectors) { uint32_t tmpNextLBA = sdLBA + sdSectors; - if (!sdDev.ccs) + if (!sdCard.ccs) { sdLBA = sdLBA * SD_SECTOR_SIZE; tmpNextLBA = tmpNextLBA * SD_SECTOR_SIZE; @@ -924,8 +939,8 @@ void sdWriteMultiSectorPrep(uint32_t sdLBA, uint32_t sdSectors) scsiDiskReset(); sdClearStatus(); scsiDev.status = CHECK_CONDITION; - scsiDev.target->sense.code = HARDWARE_ERROR; - scsiDev.target->sense.asc = LOGICAL_UNIT_COMMUNICATION_FAILURE; + scsiDev.target->state.sense.code = HARDWARE_ERROR; + scsiDev.target->state.sense.asc = LOGICAL_UNIT_COMMUNICATION_FAILURE; scsiDev.phase = STATUS; } else @@ -968,7 +983,7 @@ void sdCheckPresent() uint8_t cs = SD_CS_Read(); SD_CS_SetDriveMode(SD_CS_DM_STRONG) ; - if (cs && !(blockDev.state & DISK_PRESENT)) + if (cs && !(sdCard.dev.mediaState & MEDIA_PRESENT)) { static int firstInit = 1; @@ -981,7 +996,7 @@ void sdCheckPresent() if (sdInit()) { - blockDev.state |= DISK_PRESENT | DISK_INITIALISED; + sdCard.dev.mediaState |= MEDIA_PRESENT | MEDIA_INITIALISED; // Always "start" the device. Many systems (eg. Apple System 7) // won't respond properly to @@ -1001,18 +1016,68 @@ void sdCheckPresent() firstInit = 0; } } - else if (!cs && (blockDev.state & DISK_PRESENT)) + else if (!cs && (sdCard.dev.mediaState & MEDIA_PRESENT)) { - sdDev.capacity = 0; - blockDev.state &= ~DISK_PRESENT; - blockDev.state &= ~DISK_INITIALISED; + sdCard.capacity = 0; + sdCard.dev.mediaState &= ~MEDIA_PRESENT; + sdCard.dev.mediaState &= ~MEDIA_INITIALISED; int i; for (i = 0; i < MAX_SCSI_TARGETS; ++i) { - scsiDev.targets[i].unitAttention = PARAMETERS_CHANGED; + sdCard.targets[i].state.unitAttention = PARAMETERS_CHANGED; } } } firstCheck = 0; } +static void sd_earlyInit(S2S_Device* dev) +{ + SdCard* sdCardDevice = (SdCard*)dev; + + for (int i = 0; i < MAX_TARGETS; ++i) + { + sdCardDevice->targets[i].device = dev; + sdCardDevice->targets[i].cfg = getConfigByIndex(i); + } + sdCardDevice->lastPollMediaTime = s2s_getTime_ms(); + + // Don't require the host to send us a START STOP UNIT command + sdCardDevice->dev.mediaState = MEDIA_STARTED; + +} + +static S2S_Target* sd_getTargets(S2S_Device* dev, int* count) +{ + SdCard* sdCardDevice = (SdCard*)dev; + *count = MAX_TARGETS; + return sdCardDevice->targets; +} + +static uint32_t sd_getCapacity(S2S_Device* dev) +{ + SdCard* sdCardDevice = (SdCard*)dev; + return sdCardDevice->capacity; +} + +static int sd_pollMediaChange(S2S_Device* dev) +{ + SdCard* sdCardDevice = (SdCard*)dev; + if (s2s_elapsedTime_ms(sdCardDevice->lastPollMediaTime) > 200) + { + sdCardDevice->lastPollMediaTime = s2s_getTime_ms(); + sdCheckPresent(); + return 0; + } + else + { + return 0; + } +} + +static void sd_pollMediaBusy(S2S_Device* dev) +{ + SdCard* sdCardDevice = (SdCard*)dev; + sdCardDevice->lastPollMediaTime = s2s_getTime_ms(); +} + diff --git a/software/SCSI2SD/src/sd.h b/software/SCSI2SD/src/sd.h index 8ffcee7..d6e2ec8 100755 --- a/software/SCSI2SD/src/sd.h +++ b/software/SCSI2SD/src/sd.h @@ -17,6 +17,8 @@ #ifndef SD_H #define SD_H +#include "storedevice.h" + #define SD_SECTOR_SIZE 512 typedef enum @@ -52,15 +54,23 @@ typedef enum typedef struct { + S2S_Device dev; + + S2S_Target targets[MAX_TARGETS]; + int version; // SDHC = version 2. int ccs; // Card Capacity Status. 1 = SDHC or SDXC uint32 capacity; // in 512 byte blocks uint8_t csd[16]; // Unparsed CSD uint8_t cid[16]; // Unparsed CID -} SdDevice; -extern SdDevice sdDev; + uint32_t lastPollMediaTime; +} SdCard; + +extern SdCard sdCard; +extern S2S_Device* sdDevice; + extern volatile uint8_t sdRxDMAComplete; extern volatile uint8_t sdTxDMAComplete; diff --git a/software/SCSI2SD/src/storedevice.c b/software/SCSI2SD/src/storedevice.c new file mode 100644 index 0000000..261f461 --- /dev/null +++ b/software/SCSI2SD/src/storedevice.c @@ -0,0 +1,74 @@ +// Copyright (C) 2020 Michael McMaster +// +// This file is part of SCSI2SD. +// +// SCSI2SD is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// SCSI2SD is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with SCSI2SD. If not, see . +#include "storedevice.h" + +#include "sd.h" + +#include +#include + +S2S_Target* s2s_DeviceFindByScsiId(int scsiId) +{ + int deviceCount; + S2S_Device* devices = s2s_GetDevices(&deviceCount); + for (int deviceIdx = 0; deviceIdx < deviceCount; ++deviceIdx) + { + int targetCount; + S2S_Target* targets = devices[deviceIdx].getTargets(devices + deviceIdx, &targetCount); + for (int targetIdx = 0; targetIdx < targetCount; ++targetIdx) + { + S2S_Target* target = targets + targetIdx; + if (target && + (target->cfg->scsiId & S2S_CFG_TARGET_ENABLED) && + ((target->cfg->scsiId & S2S_CFG_TARGET_ID_BITS) == scsiId)) + { + return target; + } + } + } + + return NULL; +} + +S2S_Device* s2s_GetDevices(int* count) +{ + *count = 1; + return sdDevice; +} + +void s2s_deviceEarlyInit() +{ + int count; + S2S_Device* devices = s2s_GetDevices(&count); + for (int i = 0; i < count; ++i) + { + devices[i].earlyInit(&(devices[i])); + } +} + +int s2s_pollMediaChange() +{ + int result = 0; + int count; + S2S_Device* devices = s2s_GetDevices(&count); + for (int i = 0; i < count; ++i) + { + int devResult = devices[i].pollMediaChange(&(devices[i])); + result = result || devResult; + } + return result; +} diff --git a/software/SCSI2SD/src/storedevice.h b/software/SCSI2SD/src/storedevice.h new file mode 100644 index 0000000..8d39cbd --- /dev/null +++ b/software/SCSI2SD/src/storedevice.h @@ -0,0 +1,89 @@ +// Copyright (C) 2020 Michael McMaster +// +// This file is part of SCSI2SD. +// +// SCSI2SD is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// SCSI2SD is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with SCSI2SD. If not, see . +#ifndef S2S_DEVICE_H +#define S2S_DEVICE_H + +#include "scsi2sd.h" +#include "sense.h" + +#include + +struct S2S_DeviceStruct; +typedef struct S2S_DeviceStruct S2S_Device; + +struct S2S_TargetStruct; +typedef struct S2S_TargetStruct S2S_Target; + +struct S2S_TargetStateStruct; +typedef struct S2S_TargetStateStruct S2S_TargetState; + +typedef enum +{ + MEDIA_STARTED = 1, // Controlled via START STOP UNIT + MEDIA_PRESENT = 2, // SD card is physically present + MEDIA_INITIALISED = 4, // SD card responded to init sequence + MEDIA_WP = 8 // Write-protect. +} MEDIA_STATE; + +struct S2S_TargetStateStruct +{ + ScsiSense sense; + + uint16_t unitAttention; // Set to the sense qualifier key to be returned. + + // Only let the reserved initiator talk to us. + // A 3rd party may be sending the RESERVE/RELEASE commands + int reservedId; // 0 -> 7 if reserved. -1 if not reserved. + int reserverId; // 0 -> 7 if reserved. -1 if not reserved. + + // Shadow parameters, possibly not saved to flash yet. + // Set via Mode Select + uint16_t bytesPerSector; +}; + +struct S2S_TargetStruct +{ + S2S_Device* device; + S2S_TargetCfg* cfg; + + S2S_TargetState state; +}; + +struct S2S_DeviceStruct +{ + void (*earlyInit)(S2S_Device* dev); + + S2S_Target* (*getTargets)(S2S_Device* dev, int* count); + + // Get the number of 512 byte blocks + uint32_t (*getCapacity)(S2S_Device* dev); + + int (*pollMediaChange)(S2S_Device* dev); + void (*pollMediaBusy)(S2S_Device* dev); + + MEDIA_STATE mediaState; +}; + +S2S_Target* s2s_DeviceFindByScsiId(int scsiId); + +S2S_Device* s2s_GetDevices(int* count); + +void s2s_deviceEarlyInit(); +int s2s_pollMediaChange(); +#endif + +