From 9a4d75b51dae5ef48fc60518e7391ee59c252304 Mon Sep 17 00:00:00 2001 From: Michael McMaster Date: Thu, 21 Sep 2017 20:51:25 +1000 Subject: [PATCH] Fix sync negotiation bug --- CHANGELOG | 3 +++ src/firmware/disk.c | 26 +++++++++++++++++++++++- src/firmware/scsi.c | 45 +++++++++++++++++++++++++++++++++++------- src/firmware/scsiPhy.c | 11 ++++++++--- 4 files changed, 74 insertions(+), 11 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 6af0a610..a308438d 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,6 @@ +2017XXXX 6.1.2 + - Fix synchronous negotiation bugs + 20170520 6.1.1 - Performance improvements to improve throughput at all scsi speeds - Add new "turbo" speed option to boost speeds. diff --git a/src/firmware/disk.c b/src/firmware/disk.c index 4496c289..e7c097fc 100755 --- a/src/firmware/disk.c +++ b/src/firmware/disk.c @@ -684,9 +684,10 @@ void scsiDiskPoll() int i = 0; // int scsiDisconnected = 0; int scsiComplete = 0; - // uint32_t lastActivityTime = s2s_getTime_ms(); + //uint32_t lastActivityTime = s2s_getTime_ms(); // int scsiActive = 0; // int sdActive = 0; + int clearBSY = 0; int parityError = 0; while ((i < totalSDSectors) && @@ -704,6 +705,24 @@ void scsiDiskPoll() rem < maxSectors ? rem : maxSectors; scsiRead(&scsiDev.data[0], sectors * SD_SECTOR_SIZE, &parityError); + if (i + sectors >= totalSDSectors) + { + // We're transferring over the SCSI bus faster than the SD card + // can write. All data is buffered, and we're just waiting for + // the SD card to complete. The host won't let us disconnect. + // Some drivers set a 250ms timeout on transfers to complete. + // SD card writes are supposed to complete + // within 200ms, but sometimes they don'to. + // Just pretend we're finished. + process_Status(); + process_MessageIn(); // Will go to BUS_FREE state + + // Try and prevent anyone else using the SCSI bus while we're not ready. + *SCSI_CTRL_BSY = 1; + clearBSY = 1; + } + + if (!parityError) { sdTmpWrite(&scsiDev.data[0], i + sdLBA, sectors); @@ -830,6 +849,11 @@ void scsiDiskPoll() #endif } + if (clearBSY) + { + *SCSI_CTRL_BSY = 0; + } + #if 0 if (scsiComplete) { diff --git a/src/firmware/scsi.c b/src/firmware/scsi.c index 19fb4764..78dfbf42 100755 --- a/src/firmware/scsi.c +++ b/src/firmware/scsi.c @@ -477,6 +477,8 @@ static void doReserveRelease() } } +static uint32_t resetUntil = 0; + static void scsiReset() { scsiDev.rstCount++; @@ -515,6 +517,7 @@ static void scsiReset() scsiDev.postDataOutHook = NULL; + // Sleep to allow the bus to settle down a bit. // We must be ready again within the "Reset to selection time" of // 250ms. @@ -523,7 +526,7 @@ static void scsiReset() // in which case TERMPWR cannot be supplied, and reset will ALWAYS // be true. Therefore, the sleep here must be slow to avoid slowing // USB comms - s2s_delay_ms(1); // 1ms. + resetUntil = s2s_getTime_ms() + 2; // At least 1ms. } static void enter_SelectionPhase() @@ -646,6 +649,9 @@ static void process_SelectionPhase() static void process_MessageOut() { + int wasNeedSyncNegotiationAck = scsiDev.needSyncNegotiationAck; + scsiDev.needSyncNegotiationAck = 0; // Successful on -most- messages. + scsiEnterPhase(MESSAGE_OUT); scsiDev.atnFlag = 0; @@ -716,11 +722,10 @@ static void process_MessageOut() // Message Reject // Oh well. - if (scsiDev.needSyncNegotiationAck) + if (wasNeedSyncNegotiationAck) { scsiDev.target->syncOffset = 0; scsiDev.target->syncPeriod = 0; - scsiDev.needSyncNegotiationAck = 0; } } else if (scsiDev.msgOut == 0x08) @@ -732,6 +737,12 @@ static void process_MessageOut() // Message Parity Error // Go back and re-send the last message. scsiDev.phase = MESSAGE_IN; + + if (wasNeedSyncNegotiationAck) + { + scsiDev.target->syncOffset = 0; + scsiDev.target->syncPeriod = 0; + } } else if (scsiDev.msgOut & 0x80) // 0x80 -> 0xFF { @@ -778,9 +789,16 @@ static void process_MessageOut() scsiEnterPhase(MESSAGE_IN); static const uint8_t WDTR[] = {0x01, 0x02, 0x03, 0x00}; scsiWrite(WDTR, sizeof(WDTR)); + + // SDTR becomes invalidated. + scsiDev.target->syncOffset = 0; + scsiDev.target->syncPeriod = 0; } else if (extmsg[0] == 1 && msgLen == 3) // Synchronous data request { + int oldPeriod = scsiDev.target->syncPeriod; + int oldOffset = scsiDev.target->syncOffset; + int transferPeriod = extmsg[1]; int offset = extmsg[2]; @@ -836,10 +854,17 @@ static void process_MessageOut() } } - scsiEnterPhase(MESSAGE_IN); - uint8_t SDTR[] = {0x01, 0x03, 0x01, scsiDev.target->syncPeriod, scsiDev.target->syncOffset}; - scsiWrite(SDTR, sizeof(SDTR)); - scsiDev.needSyncNegotiationAck = 1; // Check if this message is rejected. + if (transferPeriod != oldPeriod || + scsiDev.target->syncPeriod != oldPeriod || + offset != oldOffset || + scsiDev.target->syncOffset != oldOffset || + !wasNeedSyncNegotiationAck) // Don't get into infinite loops negotiating. + { + scsiEnterPhase(MESSAGE_IN); + uint8_t SDTR[] = {0x01, 0x03, 0x01, scsiDev.target->syncPeriod, scsiDev.target->syncOffset}; + scsiWrite(SDTR, sizeof(SDTR)); + scsiDev.needSyncNegotiationAck = 1; // Check if this message is rejected. + } } else { @@ -864,6 +889,12 @@ static void process_MessageOut() void scsiPoll(void) { + if (resetUntil != 0 && resetUntil > s2s_getTime_ms()) + { + return; + } + resetUntil = 0; + if (unlikely(scsiDev.resetFlag)) { scsiReset(); diff --git a/src/firmware/scsiPhy.c b/src/firmware/scsiPhy.c index d0e70028..fadddcb3 100755 --- a/src/firmware/scsiPhy.c +++ b/src/firmware/scsiPhy.c @@ -66,10 +66,10 @@ static uint8_t asyncTimings[][4] = #define SCSI_FAST20_ASSERT 2 -#define syncDeskew(period) ((period) < 45 ? \ +#define syncDeskew(period) ((period) < 35 ? \ SCSI_FAST10_DESKEW : SCSI_FAST5_DESKEW) -#define syncHold(period) ((period) < 45 ? \ +#define syncHold(period) ((period) < 35 ? \ ((period) == 25 ? SCSI_FAST10_HOLD : 4) /* 25ns/33ns */\ : SCSI_FAST5_HOLD) @@ -509,11 +509,16 @@ void scsiEnterPhase(int phase) } else { + // Amiga A3000 OS3.9 sets period to 35 and fails with + // glitch == 1. + int glitch = + scsiDev.target->syncPeriod < 35 ? 1 : + (scsiDev.target->syncPeriod < 45 ? 2 : 5); scsiSetTiming( syncAssertion(scsiDev.target->syncPeriod), syncDeskew(scsiDev.target->syncPeriod), syncHold(scsiDev.target->syncPeriod), - scsiDev.target->syncPeriod < 45 ? 1 : 5); + glitch); } // See note 26 in SCSI 2 standard: SCSI 1 implementations may assume -- 2.38.5