Support custom mode pages
authorMichael McMaster <michael@codesrc.com>
Wed, 13 Jan 2016 11:22:16 +0000 (21:22 +1000)
committerMichael McMaster <michael@codesrc.com>
Wed, 13 Jan 2016 11:22:16 +0000 (21:22 +1000)
CHANGELOG
software/SCSI2SD/src/mode.c
software/include/scsi2sd.h
software/scsi2sd-util/ConfigUtil.cc

index efe8538..e773d33 100644 (file)
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,6 @@
+2016xxxx               4.x
+       - Added support for configurable mode pages
+
 20160111               4.6
        - Fixed bug when using sector size that isn't a multiple of 4
        (eg. 522 bytes)
index 5cdf5de..c362878 100755 (executable)
@@ -197,6 +197,33 @@ static void pageIn(int pc, int dataIdx, const uint8* pageData, int pageLen)
        }\r
 }\r
 \r
+static int useCustomPages(TargetConfig* cfg, int pc, int pageCode, int* idx)\r
+{\r
+       int found = 0;\r
+       int cfgIdx = 0;\r
+       while ((cfgIdx < sizeof(cfg->modePages) + 2) &&\r
+               (cfg->modePages[cfgIdx + 1] != 0)\r
+               )\r
+       {\r
+               int pageSize = cfg->modePages[cfgIdx + 1] + 2;\r
+               int dataPageCode = cfg->modePages[cfgIdx] & 0x3f;\r
+               if ((dataPageCode == pageCode) ||\r
+                       (pageCode == 0x3f)\r
+                       )\r
+               {\r
+                       pageIn(pc, *idx, &cfg->modePages[cfgIdx], pageSize);\r
+                       *idx += pageSize;\r
+                       found = 1;\r
+                       if (pageCode != 0x3f)\r
+                       {\r
+                               break;\r
+                       }\r
+               }\r
+               cfgIdx += pageSize;\r
+       }\r
+       return found;\r
+}\r
+\r
 static void doModeSense(\r
        int sixByteCmd, int dbd, int pc, int pageCode, int allocLength)\r
 {\r
@@ -305,6 +332,12 @@ static void doModeSense(
 \r
        int pageFound = 0;\r
 \r
+       if (scsiDev.target->cfg->modePages[1] != 0)\r
+       {\r
+               pageFound = useCustomPages(scsiDev.target->cfg, pc, pageCode, &idx);\r
+               pageCode = 0xFF; // dodgy, skip rest of logic\r
+       }\r
+\r
        if (pageCode == 0x01 || pageCode == 0x3F)\r
        {\r
                pageFound = 1;\r
index 1da8316..54f6bb9 100755 (executable)
@@ -153,7 +153,8 @@ typedef struct __attribute__((packed))
 
        uint8_t reserved[960]; // Pad out to 1024 bytes for main section.
 
-       uint8_t vpd[3072]; // Total size is 4k.
+       uint8_t modePages[1024];
+       uint8_t unused[2048]; // Total size is 4k.
 } TargetConfig;
 
 typedef struct __attribute__((packed))
index 5a8713b..2074ad5 100644 (file)
 
 #include <string.h>
 
+#include <wx/wxprec.h>
+#ifndef WX_PRECOMP
+#include <wx/wx.h>
+#endif
+#include <wx/base64.h>
+#include <wx/buffer.h>
 #include <wx/xml/xml.h>
 
 
@@ -80,6 +86,22 @@ namespace
                return toLE32(in);
        }
 
+       std::vector<uint8_t> getModePages(const TargetConfig& cfg)
+       {
+               std::vector<uint8_t> result;
+               int i = 0;
+               while (i < sizeof(cfg.modePages) + 2)
+               {
+                       int pageLen = cfg.modePages[i+1];
+                       if (pageLen == 0) break;
+                       std::copy(
+                               &cfg.modePages[i],
+                               &cfg.modePages[i+pageLen+2],
+                               std::back_inserter(result));
+                       i += pageLen + 2;
+               }
+               return result;
+       }
 }
 
 BoardConfig
@@ -194,6 +216,7 @@ std::string
 ConfigUtil::toXML(const TargetConfig& config)
 {
        std::stringstream s;
+       std::vector<uint8_t> modePages(getModePages(config));
 
        s <<
                "<SCSITarget id=\"" <<
@@ -269,6 +292,13 @@ ConfigUtil::toXML(const TargetConfig& config)
                "\n" <<
                "       <!-- 16 character serial number -->\n" <<
                "       <serial>" << std::string(config.serial, 16) << "</serial>\n" <<
+               "\n" <<
+               "       <!-- Custom mode pages, base64 encoded, up to 1024 bytes.-->\n" <<
+               "       <modePages>\n" <<
+                       (modePages.size() == 0 ? "" :
+                               wxBase64Encode(&modePages[0], modePages.size())) <<
+                               "\n" <<
+               "       </modePages>\n" <<
                "</SCSITarget>\n";
 
        return s.str();
@@ -292,7 +322,7 @@ ConfigUtil::toXML(const BoardConfig& config)
                "       <!-- ********************************************************\n" <<
                "       Only set to true when using with a fast SCSI2 host\n " <<
                "       controller. This can cause problems with older/slower\n" <<
-               "        hardware.\n" <<
+               "       hardware.\n" <<
                "       ********************************************************* -->\n" <<
                "       <enableScsi2>" <<
                        (config.flags & CONFIG_ENABLE_SCSI2 ? "true" : "false") <<
@@ -318,9 +348,9 @@ ConfigUtil::toXML(const BoardConfig& config)
                        "</enableDisconnect>\n" <<
 
                "       <!-- ********************************************************\n" <<
-               "   Respond to very short duration selection attempts. This supports\n" <<
-               "   non-standard hardware, but is generally safe to enable.\n" <<
-               "   Required for Philips P2000C.\n" <<
+               "       Respond to very short duration selection attempts. This supports\n" <<
+               "       non-standard hardware, but is generally safe to enable.\n" <<
+               "       Required for Philips P2000C.\n" <<
                "       ********************************************************* -->\n" <<
                "       <selLatch>" <<
                        (config.flags & CONFIG_ENABLE_SEL_LATCH? "true" : "false") <<
@@ -328,12 +358,12 @@ ConfigUtil::toXML(const BoardConfig& config)
 
 
                "       <!-- ********************************************************\n" <<
-               "   Convert luns to IDs. The unit must already be configured to respond\n" <<
-               "   on the ID. Allows dual drives to be accessed from a \n" <<
-               "   XEBEC S1410 SASI bridge.\n" <<
-               "   eg. Configured for dual drives as IDs 0 and 1, but the XEBEC will\n" <<
-               "   access the second disk as ID0, lun 1.\n" <<
-               "   See ttp://bitsavers.trailing-edge.com/pdf/xebec/104524C_S1410Man_Aug83.pdf\n" <<
+               "       Convert luns to IDs. The unit must already be configured to respond\n" <<
+               "       on the ID. Allows dual drives to be accessed from a \n" <<
+               "       XEBEC S1410 SASI bridge.\n" <<
+               "       eg. Configured for dual drives as IDs 0 and 1, but the XEBEC will\n" <<
+               "       access the second disk as ID0, lun 1.\n" <<
+               "       See ttp://bitsavers.trailing-edge.com/pdf/xebec/104524C_S1410Man_Aug83.pdf\n" <<
                "       ********************************************************* -->\n" <<
                "       <mapLunsToIds>" <<
                        (config.flags & CONFIG_MAP_LUNS_TO_IDS ? "true" : "false") <<
@@ -474,6 +504,13 @@ parseTarget(wxXmlNode* node)
                        memset(result.serial, ' ', sizeof(result.serial));
                        memcpy(result.serial, s.c_str(), s.size());
                }
+               else if (child->GetName() == "modePages")
+               {
+                       wxMemoryBuffer buf =
+                               wxBase64Decode(child->GetNodeContent(), wxBase64DecodeMode_SkipWS);
+                       size_t len = std::min(buf.GetDataLen(), sizeof(result.modePages));
+                       memcpy(result.modePages, buf.GetData(), len);
+               }
 
                child = child->GetNext();
        }