int i = 0;\r
// int scsiDisconnected = 0;\r
int scsiComplete = 0;\r
- // uint32_t lastActivityTime = s2s_getTime_ms();\r
+ //uint32_t lastActivityTime = s2s_getTime_ms();\r
// int scsiActive = 0;\r
// int sdActive = 0;\r
+ int clearBSY = 0;\r
\r
int parityError = 0;\r
while ((i < totalSDSectors) &&\r
rem < maxSectors ? rem : maxSectors;\r
scsiRead(&scsiDev.data[0], sectors * SD_SECTOR_SIZE, &parityError);\r
\r
+ if (i + sectors >= totalSDSectors)\r
+ {\r
+ // We're transferring over the SCSI bus faster than the SD card\r
+ // can write. All data is buffered, and we're just waiting for\r
+ // the SD card to complete. The host won't let us disconnect.\r
+ // Some drivers set a 250ms timeout on transfers to complete.\r
+ // SD card writes are supposed to complete\r
+ // within 200ms, but sometimes they don'to.\r
+ // Just pretend we're finished.\r
+ process_Status();\r
+ process_MessageIn(); // Will go to BUS_FREE state\r
+\r
+ // Try and prevent anyone else using the SCSI bus while we're not ready.\r
+ *SCSI_CTRL_BSY = 1;\r
+ clearBSY = 1;\r
+ }\r
+\r
+\r
if (!parityError)\r
{\r
sdTmpWrite(&scsiDev.data[0], i + sdLBA, sectors);\r
#endif\r
}\r
\r
+ if (clearBSY)\r
+ {\r
+ *SCSI_CTRL_BSY = 0;\r
+ }\r
+\r
#if 0\r
if (scsiComplete)\r
{\r
}\r
}\r
\r
+static uint32_t resetUntil = 0;\r
+\r
static void scsiReset()\r
{\r
scsiDev.rstCount++;\r
\r
scsiDev.postDataOutHook = NULL;\r
\r
+\r
// Sleep to allow the bus to settle down a bit.\r
// We must be ready again within the "Reset to selection time" of\r
// 250ms.\r
// in which case TERMPWR cannot be supplied, and reset will ALWAYS\r
// be true. Therefore, the sleep here must be slow to avoid slowing\r
// USB comms\r
- s2s_delay_ms(1); // 1ms.\r
+ resetUntil = s2s_getTime_ms() + 2; // At least 1ms.\r
}\r
\r
static void enter_SelectionPhase()\r
\r
static void process_MessageOut()\r
{\r
+ int wasNeedSyncNegotiationAck = scsiDev.needSyncNegotiationAck;\r
+ scsiDev.needSyncNegotiationAck = 0; // Successful on -most- messages.\r
+\r
scsiEnterPhase(MESSAGE_OUT);\r
\r
scsiDev.atnFlag = 0;\r
// Message Reject\r
// Oh well.\r
\r
- if (scsiDev.needSyncNegotiationAck)\r
+ if (wasNeedSyncNegotiationAck)\r
{\r
scsiDev.target->syncOffset = 0;\r
scsiDev.target->syncPeriod = 0;\r
- scsiDev.needSyncNegotiationAck = 0;\r
}\r
}\r
else if (scsiDev.msgOut == 0x08)\r
// Message Parity Error\r
// Go back and re-send the last message.\r
scsiDev.phase = MESSAGE_IN;\r
+\r
+ if (wasNeedSyncNegotiationAck)\r
+ {\r
+ scsiDev.target->syncOffset = 0;\r
+ scsiDev.target->syncPeriod = 0;\r
+ }\r
}\r
else if (scsiDev.msgOut & 0x80) // 0x80 -> 0xFF\r
{\r
scsiEnterPhase(MESSAGE_IN);\r
static const uint8_t WDTR[] = {0x01, 0x02, 0x03, 0x00};\r
scsiWrite(WDTR, sizeof(WDTR));\r
+\r
+ // SDTR becomes invalidated.\r
+ scsiDev.target->syncOffset = 0;\r
+ scsiDev.target->syncPeriod = 0;\r
}\r
else if (extmsg[0] == 1 && msgLen == 3) // Synchronous data request\r
{\r
+ int oldPeriod = scsiDev.target->syncPeriod;\r
+ int oldOffset = scsiDev.target->syncOffset;\r
+\r
int transferPeriod = extmsg[1];\r
int offset = extmsg[2];\r
\r
}\r
}\r
\r
- scsiEnterPhase(MESSAGE_IN);\r
- uint8_t SDTR[] = {0x01, 0x03, 0x01, scsiDev.target->syncPeriod, scsiDev.target->syncOffset};\r
- scsiWrite(SDTR, sizeof(SDTR));\r
- scsiDev.needSyncNegotiationAck = 1; // Check if this message is rejected.\r
+ if (transferPeriod != oldPeriod ||\r
+ scsiDev.target->syncPeriod != oldPeriod ||\r
+ offset != oldOffset ||\r
+ scsiDev.target->syncOffset != oldOffset ||\r
+ !wasNeedSyncNegotiationAck) // Don't get into infinite loops negotiating.\r
+ {\r
+ scsiEnterPhase(MESSAGE_IN);\r
+ uint8_t SDTR[] = {0x01, 0x03, 0x01, scsiDev.target->syncPeriod, scsiDev.target->syncOffset};\r
+ scsiWrite(SDTR, sizeof(SDTR));\r
+ scsiDev.needSyncNegotiationAck = 1; // Check if this message is rejected.\r
+ }\r
}\r
else\r
{\r
\r
void scsiPoll(void)\r
{\r
+ if (resetUntil != 0 && resetUntil > s2s_getTime_ms())\r
+ {\r
+ return;\r
+ }\r
+ resetUntil = 0;\r
+\r
if (unlikely(scsiDev.resetFlag))\r
{\r
scsiReset();\r
#define SCSI_FAST20_ASSERT 2\r
\r
\r
-#define syncDeskew(period) ((period) < 45 ? \\r
+#define syncDeskew(period) ((period) < 35 ? \\r
SCSI_FAST10_DESKEW : SCSI_FAST5_DESKEW)\r
\r
-#define syncHold(period) ((period) < 45 ? \\r
+#define syncHold(period) ((period) < 35 ? \\r
((period) == 25 ? SCSI_FAST10_HOLD : 4) /* 25ns/33ns */\\r
: SCSI_FAST5_HOLD)\r
\r
}\r
else\r
{\r
+ // Amiga A3000 OS3.9 sets period to 35 and fails with\r
+ // glitch == 1.\r
+ int glitch =\r
+ scsiDev.target->syncPeriod < 35 ? 1 :\r
+ (scsiDev.target->syncPeriod < 45 ? 2 : 5);\r
scsiSetTiming(\r
syncAssertion(scsiDev.target->syncPeriod),\r
syncDeskew(scsiDev.target->syncPeriod),\r
syncHold(scsiDev.target->syncPeriod),\r
- scsiDev.target->syncPeriod < 45 ? 1 : 5);\r
+ glitch);\r
}\r
\r
// See note 26 in SCSI 2 standard: SCSI 1 implementations may assume\r