From c8b36446cd7ce4546f4f39193240c7d339cccf4d Mon Sep 17 00:00:00 2001 From: Michael McMaster Date: Sat, 2 Mar 2019 15:32:33 +1000 Subject: [PATCH] Port XEBEC controller support from v5 firmware --- CHANGELOG | 3 + include/scsi2sd.h | 7 +- src/firmware/diagnostic.c | 10 +++ src/firmware/diagnostic.h | 1 + src/firmware/scsi.c | 143 +++++++++++++++++++++++++++++++------- 5 files changed, 136 insertions(+), 28 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 1b9a904a..c744518c 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,6 @@ +2019XXXX + - Port XEBEC support from v5 firmware + 20181011 6.2.1 - Fix bug in USB disk interface with disks over 4GB diff --git a/include/scsi2sd.h b/include/scsi2sd.h index 44eec495..7a7217e5 100755 --- a/include/scsi2sd.h +++ b/include/scsi2sd.h @@ -78,9 +78,10 @@ typedef enum typedef enum { - S2S_CFG_QUIRKS_NONE, - S2S_CFG_QUIRKS_APPLE, - S2S_CFG_QUIRKS_OMTI + S2S_CFG_QUIRKS_NONE = 0, + S2S_CFG_QUIRKS_APPLE = 1, + S2S_CFG_QUIRKS_OMTI = 2, + S2S_CFG_QUIRKS_XEBEC = 4 } S2S_CFG_QUIRKS; typedef enum diff --git a/src/firmware/diagnostic.c b/src/firmware/diagnostic.c index faddace1..17d170b3 100755 --- a/src/firmware/diagnostic.c +++ b/src/firmware/diagnostic.c @@ -234,4 +234,14 @@ void scsiWriteBuffer() } } +// XEBEC specific command. See +// http://www.bitsavers.org/pdf/westernDigital/WD100x/79-000004_WD1002-SHD_OEM_Manual_Aug1984.pdf +// Section 4.3.14 +void scsiWriteSectorBuffer() +{ + scsiDev.dataLen = scsiDev.target->liveCfg.bytesPerSector; + scsiDev.phase = DATA_OUT; + scsiDev.postDataOutHook = doWriteBuffer; +} + diff --git a/src/firmware/diagnostic.h b/src/firmware/diagnostic.h index 98e90d2e..977058fd 100755 --- a/src/firmware/diagnostic.h +++ b/src/firmware/diagnostic.h @@ -20,6 +20,7 @@ void scsiSendDiagnostic(void); void scsiReceiveDiagnostic(void); void scsiWriteBuffer(void); +void scsiWriteSectorBuffer(void); void scsiReadBuffer(void); #endif diff --git a/src/firmware/scsi.c b/src/firmware/scsi.c index ce886e7e..4864426f 100755 --- a/src/firmware/scsi.c +++ b/src/firmware/scsi.c @@ -153,7 +153,8 @@ void process_Status() } } - if ((scsiDev.status == GOOD) && (control & 0x01)) + if ((scsiDev.status == GOOD) && (control & 0x01) && + scsiDev.target->cfg->quirks != S2S_CFG_QUIRKS_XEBEC) { // Linked command. scsiDev.status = INTERMEDIATE; @@ -171,12 +172,31 @@ void process_Status() message = MSG_COMMAND_COMPLETE; } - if (scsiDev.target->cfg->quirks == S2S_CFG_QUIRKS_OMTI) + if (scsiDev.target->cfg->quirks == S2S_CFG_QUIRKS_XEBEC) + { + // More non-standardness. Expects 2 status bytes (really status + msg) + // 00 d 000 err 0 + // d == disk number + // ERR = 1 if error. + if (scsiDev.status == GOOD) + { + scsiWriteByte(scsiDev.cdb[1] & 0x20); + } + else + { + scsiWriteByte((scsiDev.cdb[1] & 0x20) | 0x2); + } + s2s_delay_us(10); // Seems to need a delay before changing phase bits. + } + else if (scsiDev.target->cfg->quirks == S2S_CFG_QUIRKS_OMTI) { scsiDev.status |= (scsiDev.target->targetId & 0x03) << 5; + scsiWriteByte(scsiDev.status); + } + else + { + scsiWriteByte(scsiDev.status); } - - scsiWriteByte(scsiDev.status); scsiDev.lastStatus = scsiDev.status; scsiDev.lastSense = scsiDev.target->sense.code; @@ -289,7 +309,31 @@ static void process_Command() // Prefer LUN's set by IDENTIFY messages for newer hosts. if (scsiDev.lun < 0) { - scsiDev.lun = scsiDev.cdb[1] >> 5; + if (command == 0xE0 || command == 0xE4) // XEBEC s1410 + { + scsiDev.lun = 0; + } + else + { + scsiDev.lun = scsiDev.cdb[1] >> 5; + } + } + + + // For Philips P2000C with Xebec S1410 SASI/MFM adapter + // http://bitsavers.trailing-edge.com/pdf/xebec/104524C_S1410Man_Aug83.pdf + if ((scsiDev.lun > 0) && (scsiDev.boardCfg.flags & S2S_CFG_MAP_LUNS_TO_IDS)) + { + int tgtIndex; + for (tgtIndex = 0; tgtIndex < S2S_MAX_TARGETS; ++tgtIndex) + { + if (scsiDev.targets[tgtIndex].targetId == scsiDev.lun) + { + scsiDev.target = &scsiDev.targets[tgtIndex]; + scsiDev.lun = 0; + break; + } + } } control = scsiDev.cdb[scsiDev.cdbLen - 1]; @@ -311,7 +355,9 @@ static void process_Command() scsiDev.target->sense.asc = SCSI_PARITY_ERROR; enter_Status(CHECK_CONDITION); } - else if ((control & 0x02) && ((control & 0x01) == 0)) + else if ((control & 0x02) && ((control & 0x01) == 0) && + // used for head step options on xebec. + likely(scsiDev.target->cfg->quirks != S2S_CFG_QUIRKS_XEBEC)) { // FLAG set without LINK flag. scsiDev.target->sense.code = ILLEGAL_REQUEST; @@ -327,23 +373,43 @@ static void process_Command() // REQUEST SENSE uint32_t allocLength = scsiDev.cdb[4]; - // As specified by the SASI and SCSI1 standard. - // Newer initiators won't be specifying 0 anyway. - if (allocLength == 0) allocLength = 4; - - memset(scsiDev.data, 0, 256); // Max possible alloc length - scsiDev.data[0] = 0xF0; - scsiDev.data[2] = scsiDev.target->sense.code & 0x0F; - - scsiDev.data[3] = transfer.lba >> 24; - scsiDev.data[4] = transfer.lba >> 16; - scsiDev.data[5] = transfer.lba >> 8; - scsiDev.data[6] = transfer.lba; + if (scsiDev.target->cfg->quirks == S2S_CFG_QUIRKS_XEBEC) + { + // Completely non-standard + allocLength = 4; + if (scsiDev.target->sense.code == NO_SENSE) + scsiDev.data[0] = 0; + else if (scsiDev.target->sense.code == ILLEGAL_REQUEST) + scsiDev.data[0] = 0x20; // Illegal command + else if (scsiDev.target->sense.code == NOT_READY) + scsiDev.data[0] = 0x04; // Drive not ready + else + scsiDev.data[0] = 0x11; // Uncorrectable data error - // 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[1] = (scsiDev.cdb[1] & 0x20) | ((transfer.lba >> 16) & 0x1F); + scsiDev.data[2] = transfer.lba >> 8; + scsiDev.data[3] = transfer.lba; + } + else + { + // As specified by the SASI and SCSI1 standard. + // Newer initiators won't be specifying 0 anyway. + if (allocLength == 0) allocLength = 4; + + memset(scsiDev.data, 0, 256); // Max possible alloc length + scsiDev.data[0] = 0xF0; + scsiDev.data[2] = scsiDev.target->sense.code & 0x0F; + + scsiDev.data[3] = transfer.lba >> 24; + scsiDev.data[4] = transfer.lba >> 16; + scsiDev.data[5] = transfer.lba >> 8; + scsiDev.data[6] = transfer.lba; + + // 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; + } // Silently truncate results. SCSI-2 spec 8.2.14. enter_DataIn(allocLength); @@ -409,6 +475,11 @@ static void process_Command() { scsiWriteBuffer(); } + else if (command == 0x0f && + scsiDev.target->cfg->quirks == S2S_CFG_QUIRKS_XEBEC) + { + scsiWriteSectorBuffer(); + } else if (command == 0x3C) { scsiReadBuffer(); @@ -567,7 +638,11 @@ static void process_SelectionPhase() // The Mac Plus boot-time (ie. rom code) selection abort time // is < 1ms and must have no delay (standard suggests 250ms abort time) // Most newer SCSI2 hosts don't care either way. - if (scsiDev.boardCfg.selectionDelay == 255) // auto + if (scsiDev.target->cfg->quirks == S2S_CFG_QUIRKS_XEBEC) + { + s2s_delay_ms(1); // Simply won't work if set to 0. + } + else if (scsiDev.boardCfg.selectionDelay == 255) // auto { if (scsiDev.compatMode < COMPAT_SCSI2) { @@ -640,9 +715,27 @@ static void process_SelectionPhase() // SCSI1/SASI initiators may not set their own ID. scsiDev.initiatorId = (selStatus >> 3) & 0x7; - while (likely(!scsiDev.resetFlag) && scsiStatusSEL()) + // Wait until the end of the selection phase. + uint32_t selTimerBegin = s2s_getTime_ms(); + while (likely(!scsiDev.resetFlag)) { - // Wait until the end of the selection phase. + if (!scsiStatusSEL()) + { + break; + } + else if (s2s_elapsedTime_ms(selTimerBegin) >= 10 && + scsiDev.target->cfg->quirks == S2S_CFG_QUIRKS_XEBEC) + { + // XEBEC hosts may not bother releasing SEL at all until + // just before the command ends. + break; + } + else if (s2s_elapsedTime_ms(selTimerBegin) >= 250) + { + *SCSI_CTRL_BSY = 0; + scsiDev.resetFlag = 1; + break; + } } scsiDev.phase = COMMAND; -- 2.38.5