Port XEBEC controller support from v5 firmware
authorMichael McMaster <michael@codesrc.com>
Sat, 2 Mar 2019 05:32:33 +0000 (15:32 +1000)
committerMichael McMaster <michael@codesrc.com>
Sat, 2 Mar 2019 05:32:33 +0000 (15:32 +1000)
CHANGELOG
include/scsi2sd.h
src/firmware/diagnostic.c
src/firmware/diagnostic.h
src/firmware/scsi.c

index 1b9a904..c744518 100644 (file)
--- 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
 
index 44eec49..7a7217e 100755 (executable)
@@ -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
index faddace..17d170b 100755 (executable)
@@ -234,4 +234,14 @@ void scsiWriteBuffer()
        }\r
 }\r
 \r
+// XEBEC specific command. See\r
+// http://www.bitsavers.org/pdf/westernDigital/WD100x/79-000004_WD1002-SHD_OEM_Manual_Aug1984.pdf\r
+// Section 4.3.14\r
+void scsiWriteSectorBuffer()\r
+{\r
+       scsiDev.dataLen = scsiDev.target->liveCfg.bytesPerSector;\r
+       scsiDev.phase = DATA_OUT;\r
+       scsiDev.postDataOutHook = doWriteBuffer;\r
+}\r
+\r
 \r
index 98e90d2..977058f 100755 (executable)
@@ -20,6 +20,7 @@
 void scsiSendDiagnostic(void);
 void scsiReceiveDiagnostic(void);
 void scsiWriteBuffer(void);
+void scsiWriteSectorBuffer(void);
 void scsiReadBuffer(void);
 
 #endif
index ce886e7..4864426 100755 (executable)
@@ -153,7 +153,8 @@ void process_Status()
                }\r
        }\r
 \r
-       if ((scsiDev.status == GOOD) && (control & 0x01))\r
+       if ((scsiDev.status == GOOD) && (control & 0x01) &&\r
+               scsiDev.target->cfg->quirks != S2S_CFG_QUIRKS_XEBEC)\r
        {\r
                // Linked command.\r
                scsiDev.status = INTERMEDIATE;\r
@@ -171,12 +172,31 @@ void process_Status()
                message = MSG_COMMAND_COMPLETE;\r
        }\r
 \r
-       if (scsiDev.target->cfg->quirks == S2S_CFG_QUIRKS_OMTI)\r
+       if (scsiDev.target->cfg->quirks == S2S_CFG_QUIRKS_XEBEC)\r
+       {\r
+               // More non-standardness. Expects 2 status bytes (really status + msg)\r
+               // 00 d 000 err 0\r
+               // d == disk number\r
+               // ERR = 1 if error.\r
+               if (scsiDev.status == GOOD)\r
+               {\r
+                       scsiWriteByte(scsiDev.cdb[1] & 0x20);\r
+               }\r
+               else\r
+               {\r
+                       scsiWriteByte((scsiDev.cdb[1] & 0x20) | 0x2);\r
+               }\r
+               s2s_delay_us(10); // Seems to need a delay before changing phase bits.\r
+       }\r
+       else if (scsiDev.target->cfg->quirks == S2S_CFG_QUIRKS_OMTI)\r
        {\r
                scsiDev.status |= (scsiDev.target->targetId & 0x03) << 5;\r
+               scsiWriteByte(scsiDev.status);\r
+       }\r
+       else\r
+       {\r
+               scsiWriteByte(scsiDev.status);\r
        }\r
-\r
-       scsiWriteByte(scsiDev.status);\r
 \r
        scsiDev.lastStatus = scsiDev.status;\r
        scsiDev.lastSense = scsiDev.target->sense.code;\r
@@ -289,7 +309,31 @@ static void process_Command()
        // Prefer LUN's set by IDENTIFY messages for newer hosts.\r
        if (scsiDev.lun < 0)\r
        {\r
-               scsiDev.lun = scsiDev.cdb[1] >> 5;\r
+               if (command == 0xE0 || command == 0xE4) // XEBEC s1410\r
+               {\r
+                       scsiDev.lun = 0;\r
+               }\r
+               else\r
+               {\r
+                       scsiDev.lun = scsiDev.cdb[1] >> 5;\r
+               }\r
+       }\r
+\r
+\r
+       // For Philips P2000C with Xebec S1410 SASI/MFM adapter\r
+       // http://bitsavers.trailing-edge.com/pdf/xebec/104524C_S1410Man_Aug83.pdf\r
+       if ((scsiDev.lun > 0) && (scsiDev.boardCfg.flags & S2S_CFG_MAP_LUNS_TO_IDS))\r
+       {\r
+               int tgtIndex;\r
+               for (tgtIndex = 0; tgtIndex < S2S_MAX_TARGETS; ++tgtIndex)\r
+               {\r
+                       if (scsiDev.targets[tgtIndex].targetId == scsiDev.lun)\r
+                       {\r
+                               scsiDev.target = &scsiDev.targets[tgtIndex];\r
+                               scsiDev.lun = 0;\r
+                               break;\r
+                       }\r
+               }\r
        }\r
 \r
        control = scsiDev.cdb[scsiDev.cdbLen - 1];\r
@@ -311,7 +355,9 @@ static void process_Command()
                scsiDev.target->sense.asc = SCSI_PARITY_ERROR;\r
                enter_Status(CHECK_CONDITION);\r
        }\r
-       else if ((control & 0x02) && ((control & 0x01) == 0))\r
+       else if ((control & 0x02) && ((control & 0x01) == 0) &&\r
+               // used for head step options on xebec.\r
+               likely(scsiDev.target->cfg->quirks != S2S_CFG_QUIRKS_XEBEC))\r
        {\r
                // FLAG set without LINK flag.\r
                scsiDev.target->sense.code = ILLEGAL_REQUEST;\r
@@ -327,23 +373,43 @@ static void process_Command()
                // REQUEST SENSE\r
                uint32_t allocLength = scsiDev.cdb[4];\r
 \r
-               // As specified by the SASI and SCSI1 standard.\r
-               // Newer initiators won't be specifying 0 anyway.\r
-               if (allocLength == 0) allocLength = 4;\r
-\r
-               memset(scsiDev.data, 0, 256); // Max possible alloc length\r
-               scsiDev.data[0] = 0xF0;\r
-               scsiDev.data[2] = scsiDev.target->sense.code & 0x0F;\r
-\r
-               scsiDev.data[3] = transfer.lba >> 24;\r
-               scsiDev.data[4] = transfer.lba >> 16;\r
-               scsiDev.data[5] = transfer.lba >> 8;\r
-               scsiDev.data[6] = transfer.lba;\r
+               if (scsiDev.target->cfg->quirks == S2S_CFG_QUIRKS_XEBEC)\r
+               {\r
+                       // Completely non-standard\r
+                       allocLength = 4;\r
+                       if (scsiDev.target->sense.code == NO_SENSE)\r
+                               scsiDev.data[0] = 0;\r
+                       else if (scsiDev.target->sense.code == ILLEGAL_REQUEST)\r
+                               scsiDev.data[0] = 0x20; // Illegal command\r
+                       else if (scsiDev.target->sense.code == NOT_READY)\r
+                               scsiDev.data[0] = 0x04; // Drive not ready\r
+                       else\r
+                               scsiDev.data[0] = 0x11;  // Uncorrectable data error\r
 \r
-               // Additional bytes if there are errors to report\r
-               scsiDev.data[7] = 10; // additional length\r
-               scsiDev.data[12] = scsiDev.target->sense.asc >> 8;\r
-               scsiDev.data[13] = scsiDev.target->sense.asc;\r
+                       scsiDev.data[1] = (scsiDev.cdb[1] & 0x20) | ((transfer.lba >> 16) & 0x1F);\r
+                       scsiDev.data[2] = transfer.lba >> 8;\r
+                       scsiDev.data[3] = transfer.lba;\r
+               }\r
+               else\r
+               {\r
+                       // As specified by the SASI and SCSI1 standard.\r
+                       // Newer initiators won't be specifying 0 anyway.\r
+                       if (allocLength == 0) allocLength = 4;\r
+\r
+                       memset(scsiDev.data, 0, 256); // Max possible alloc length\r
+                       scsiDev.data[0] = 0xF0;\r
+                       scsiDev.data[2] = scsiDev.target->sense.code & 0x0F;\r
+\r
+                       scsiDev.data[3] = transfer.lba >> 24;\r
+                       scsiDev.data[4] = transfer.lba >> 16;\r
+                       scsiDev.data[5] = transfer.lba >> 8;\r
+                       scsiDev.data[6] = transfer.lba;\r
+\r
+                       // Additional bytes if there are errors to report\r
+                       scsiDev.data[7] = 10; // additional length\r
+                       scsiDev.data[12] = scsiDev.target->sense.asc >> 8;\r
+                       scsiDev.data[13] = scsiDev.target->sense.asc;\r
+               }\r
 \r
                // Silently truncate results. SCSI-2 spec 8.2.14.\r
                enter_DataIn(allocLength);\r
@@ -409,6 +475,11 @@ static void process_Command()
        {\r
                scsiWriteBuffer();\r
        }\r
+       else if (command == 0x0f &&\r
+               scsiDev.target->cfg->quirks == S2S_CFG_QUIRKS_XEBEC)\r
+       {\r
+               scsiWriteSectorBuffer();\r
+       }\r
        else if (command == 0x3C)\r
        {\r
                scsiReadBuffer();\r
@@ -567,7 +638,11 @@ static void process_SelectionPhase()
        // The Mac Plus boot-time (ie. rom code) selection abort time\r
        // is < 1ms and must have no delay (standard suggests 250ms abort time)\r
        // Most newer SCSI2 hosts don't care either way.\r
-       if (scsiDev.boardCfg.selectionDelay == 255) // auto\r
+       if (scsiDev.target->cfg->quirks == S2S_CFG_QUIRKS_XEBEC)\r
+       {\r
+               s2s_delay_ms(1); // Simply won't work if set to 0.\r
+       }\r
+       else if (scsiDev.boardCfg.selectionDelay == 255) // auto\r
        {\r
                if (scsiDev.compatMode < COMPAT_SCSI2)\r
                {\r
@@ -640,9 +715,27 @@ static void process_SelectionPhase()
                // SCSI1/SASI initiators may not set their own ID.\r
                scsiDev.initiatorId = (selStatus >> 3) & 0x7;\r
 \r
-               while (likely(!scsiDev.resetFlag) && scsiStatusSEL())\r
+               // Wait until the end of the selection phase.\r
+               uint32_t selTimerBegin = s2s_getTime_ms();\r
+               while (likely(!scsiDev.resetFlag))\r
                {\r
-                       // Wait until the end of the selection phase.\r
+                       if (!scsiStatusSEL())\r
+                       {\r
+                               break;\r
+                       }\r
+                       else if (s2s_elapsedTime_ms(selTimerBegin) >= 10 &&\r
+                               scsiDev.target->cfg->quirks == S2S_CFG_QUIRKS_XEBEC)\r
+                       {\r
+                               // XEBEC hosts may not bother releasing SEL at all until\r
+                               // just before the command ends.\r
+                               break;\r
+                       }\r
+                       else if (s2s_elapsedTime_ms(selTimerBegin) >= 250)\r
+                       {\r
+                               *SCSI_CTRL_BSY = 0;\r
+                               scsiDev.resetFlag = 1;\r
+                               break;\r
+                       }\r
                }\r
 \r
                scsiDev.phase = COMMAND;\r