Annotation of nono/vm/scsidev.cpp, revision 1.1.1.10

1.1       root        1: //
                      2: // nono
1.1.1.3   root        3: // Copyright (C) 2020 nono project
                      4: // Licensed under nono-license.txt
1.1       root        5: //
                      6: 
                      7: // SCSI デバイス共通部分
                      8: 
                      9: #include "scsidev.h"
1.1.1.2   root       10: #include "config.h"
                     11: #include "mainapp.h"
1.1       root       12: 
                     13: //
                     14: // SCSI デバイス
                     15: //
                     16: 
                     17: // コンストラクタ
1.1.1.10! root       18: SCSIDevice::SCSIDevice(const std::string& objname_)
        !            19:        : inherited(objname_)
1.1       root       20: {
                     21: }
                     22: 
                     23: // デストラクタ
                     24: SCSIDevice::~SCSIDevice()
                     25: {
                     26: }
                     27: 
                     28: //
                     29: // SCSI ホストデバイス
                     30: //
                     31: 
                     32: // コンストラクタ
1.1.1.10! root       33: SCSIHostDevice::SCSIHostDevice(const std::string& objname_)
        !            34:        : inherited(objname_)
1.1       root       35: {
1.1.1.5   root       36:        devtype = SCSI::DevType::Initiator;
                     37: 
1.1       root       38:        // バスデバイスを作成する。
                     39:        // ただし自身がバスに参加するのは継承側で行う
                     40:        // (例えば SPC なら BDID 書き込みで ID が決まった後、など)。
                     41:        scsibus.reset(new SCSIBus());
                     42: }
                     43: 
                     44: // デストラクタ
                     45: SCSIHostDevice::~SCSIHostDevice()
                     46: {
                     47: }
                     48: 
1.1.1.2   root       49: // 設定ファイルに使われるこのホストデバイスを示す接頭語を設定する
                     50: // (継承クラス側のコンストラクタで config_name を設定後に呼ぶこと)
                     51: void
                     52: SCSIHostDevice::SetConfigName(const char *name_)
                     53: {
                     54:        config_name = name_;
                     55: }
                     56: 
1.1       root       57: bool
                     58: SCSIHostDevice::Create()
                     59: {
                     60:        // 設定を読み込む。
                     61:        for (int id = 0; id < 8; id++) {
1.1.1.2   root       62:                const std::string key = string_format("%s-id%d-image",
1.1       root       63:                        GetConfigName(), id);
1.1.1.3   root       64:                const ConfigItem& item = gConfig->Find(key);
1.1.1.2   root       65:                const std::string& image = item.AsString();
                     66: 
                     67:                // 空ならデバイスなし
                     68:                if (image.length() == 0) {
1.1.1.5   root       69:                        // 未接続部分のパラメータは減らしておくか。
                     70:                        // --show-config するとさすがに無駄に多くて邪魔なので。
                     71:                        const std::string wpkey = string_format("%s-id%d-writeprotect",
                     72:                                GetConfigName(), id);
                     73:                        const std::string stkey = string_format("%s-id%d-seektime",
                     74:                                GetConfigName(), id);
                     75:                        gConfig->Delete(wpkey);
                     76:                        gConfig->Delete(stkey);
1.1.1.2   root       77:                        continue;
                     78:                }
                     79: 
                     80:                // ',' より前がデバイス種別 (ここではパスは不要)
                     81:                auto pos = image.find(',');
                     82:                if (pos == std::string::npos) {
                     83:                        item.Err("no device type specified");
                     84:                        return false;
                     85:                }
                     86:                std::string type = string_tolower(image.substr(0, pos));
                     87: 
                     88:                if (type == "hd") {
1.1       root       89:                        target[id].reset(new SCSIHD(this, id));
                     90:                        scsibus->Attach(target[id].get(), id);
1.1.1.2   root       91:                } else {
                     92:                        item.Err("invaild device type '%s'", type.c_str());
1.1       root       93:                }
                     94:        }
                     95: 
                     96:        return true;
                     97: }
                     98: 
                     99: bool
                    100: SCSIHostDevice::Init()
                    101: {
                    102:        // 初期化ではないけどログレベルがセットできたここでデバッグ表示。
                    103:        // -L オプションの処理は Create() の後なので。
                    104: 
                    105:        if (loglevel >= 1) {
                    106:                for (int id = 0; id < 8; id++) {
                    107:                        std::string typestr;
                    108:                        if (target[id]) {
                    109:                                switch (target[id]->GetDevType()) {
1.1.1.5   root      110:                                 default:
1.1       root      111:                                        break;
1.1.1.4   root      112:                                 case SCSI::DevType::HD:
1.1       root      113:                                        typestr = "HD";
                    114:                                        break;
                    115:                                }
                    116:                        }
                    117:                        if (!typestr.empty()) {
1.1.1.8   root      118:                                putmsgn("%s target #%d %s", GetConfigName(), id,
1.1       root      119:                                        typestr.c_str());
                    120:                        }
                    121:                }
                    122:        }
                    123: 
                    124:        return true;
                    125: }
                    126: 
                    127: // バスフリーコールバック (SCSIBus から呼ばれる)
                    128: void
                    129: SCSIHostDevice::BusFreeCB(int id)
                    130: {
                    131:        // 実際にはバスフリーを検出したデバイスは各自自身が送出している信号を
                    132:        // 下げるのだが、色々面倒なので、ここではホストのバスフリーコールバックが
                    133:        // 一括して全部の線を下げる。
                    134:        // ただしさすがにログがうるさいので、上がってる線だけ下げる。
                    135: 
                    136:        uint32 data;
                    137:        while ((data = GetBSY()) != 0) {
                    138:                bus->NegateBSY(DecodeID(data));
                    139:        }
                    140:        while ((data = GetSEL()) != 0) {
                    141:                bus->NegateSEL(DecodeID(data));
                    142:        }
                    143:        if (GetREQ()) {
                    144:                NegateREQ();
                    145:        }
                    146:        if (GetACK()) {
                    147:                NegateACK();
                    148:        }
                    149:        if (GetATN()) {
                    150:                NegateATN();
                    151:        }
                    152:        SetXfer(0);
                    153:        SetData(0);
                    154: }
                    155: 
1.1.1.6   root      156: #if defined(__clang__)
                    157: // デストラクタがインラインで書けないのは面倒なのでとりあえず
                    158: #pragma clang diagnostic push
                    159: #pragma clang diagnostic ignored "-Wweak-vtables"
                    160: #endif
                    161: 
1.1       root      162: //
                    163: // SCSI コマンドの共通部分
                    164: //
                    165: class SCSICmd
                    166: {
                    167:  public:
                    168:        SCSICmd(SCSITarget *p) {
                    169:                parent = p;
                    170:        }
                    171:        virtual ~SCSICmd() { }
                    172: 
                    173:        // 転送バッファと転送バイト数。
                    174:        // IN (ターゲットが送出側)なら、各フェーズ開始までに送出バイト数分の
                    175:        // バッファを buf に用意すること。recvbytes は操作不要。
                    176:        //
                    177:        // OUT(ターゲットが受信側)なら、各フェーズ開始前までに受信バイト数を
                    178:        // recvbytes にセットすること。buf は操作不要。
                    179:        // なお parent は OUT(受信)フェーズ中にこの recvbytes を変更しない。
                    180:        std::vector<uint8> buf;
                    181:        uint32 recvbytes;
                    182: 
1.1.1.5   root      183:        // このコマンドの動作時間 [nsec]
                    184:        // シークタイムとかを簡易的に再現するため、次フェーズ遷移時の最初の
                    185:        // REQ アサートを引き延ばすために使う。
                    186:        // 主にコマンドフェーズで使うことになると思う。
                    187:        uint64 optime {};
                    188: 
1.1       root      189:        // 以下いずれも戻り値は遷移先のフェーズ。
                    190: 
                    191:        // コマンドフェーズを処理する。
1.1.1.4   root      192:        // コマンドが確定したところで呼ばれる。戻り値に遷移先フェーズを返すこと。
                    193:        // また、コマンド開始時に各自で ClearSense() を呼ぶこと。センスというか
                    194:        // CA 状態は次のコマンド実行でクリアされるが (ネクサスはとりあえず無視)、
                    195:        // RequestSense の場合は現在保持しているセンス情報をホストに返すので、
                    196:        // つまり RequestSense 以外のコマンドが全員各自でクリアする必要がある。
1.1       root      197:        virtual SCSI::XferPhase Command(std::vector<uint8>& cmdseq) {
1.1.1.4   root      198:                parent->ClearSense();
1.1       root      199:                return SCSI::XferPhase::Status;
                    200:        }
                    201: 
                    202:        // データインフェーズを完了する。
                    203:        virtual SCSI::XferPhase DoneDataIn() { return SCSI::XferPhase::Status; }
                    204: 
                    205:        // データアウトフェーズを完了する。
                    206:        virtual SCSI::XferPhase DoneDataOut() { return SCSI::XferPhase::Status; }
                    207: 
                    208:        // ステータスフェーズを開始する。
1.1.1.4   root      209:        void BeginStatus() {
1.1       root      210:                buf.clear();
1.1.1.4   root      211:                buf.push_back(status_byte);
1.1       root      212:        }
                    213: 
                    214:        // ステータスフェーズを完了する。
                    215:        virtual SCSI::XferPhase DoneStatus() { return SCSI::XferPhase::MsgIn; }
                    216: 
                    217:        // メッセージインフェーズを開始する。
                    218:        // デフォルトでは Command Complete を返す実装を用意しておく。
                    219:        virtual void BeginMsgIn() {
                    220:                buf.clear();
                    221:                buf.push_back((uint8)SCSI::MsgByte::CommandComplete);
                    222:        }
                    223: 
                    224:        // メッセージインフェーズを完了する。
                    225:        virtual SCSI::XferPhase DoneMsgIn() { return SCSI::XferPhase::End; }
                    226: 
                    227:        // メッセージアウトフェーズを開始する。
                    228:        virtual void BeginMsgOut() { }
                    229: 
                    230:        // メッセージアウトフェーズを完了する。
                    231:        virtual SCSI::XferPhase DoneMsgOut() { return SCSI::XferPhase::End; }
                    232: 
                    233:  protected:
                    234:        // このコマンドを実行しているターゲットデバイス。
                    235:        SCSITarget *parent;
1.1.1.4   root      236: 
                    237:        // ステータスバイト (デフォルトは 0 = Good)
                    238:        uint8 status_byte {};
1.1       root      239: };
                    240: 
                    241: //
                    242: // SCSI コマンド 0x00: TestUnitReady (共通)
                    243: //
                    244: class SCSICmdTestUnitReady : public SCSICmd
                    245: {
1.1.1.3   root      246:        using inherited = SCSICmd;
1.1       root      247:  public:
                    248:        SCSICmdTestUnitReady(SCSITarget *p) : inherited(p) { }
1.1.1.6   root      249:        virtual ~SCSICmdTestUnitReady() override { }
1.1       root      250: };
                    251: 
                    252: //
1.1.1.2   root      253: // SCSI コマンド 0x01: RezeroUnit (共通)
                    254: //
                    255: class SCSICmdRezeroUnit : public SCSICmd
                    256: {
1.1.1.3   root      257:        using inherited = SCSICmd;
1.1.1.2   root      258:  public:
                    259:        SCSICmdRezeroUnit(SCSITarget *p) : inherited(p) { }
1.1.1.6   root      260:        virtual ~SCSICmdRezeroUnit() override { }
1.1.1.2   root      261: 
                    262:        // とりあえず黙って成功するだけでいいか
                    263: };
                    264: 
                    265: //
1.1       root      266: // SCSI コマンド 0x03: RequestSense (共通)
                    267: //
                    268: class SCSICmdRequestSense : public SCSICmd
                    269: {
1.1.1.3   root      270:        using inherited = SCSICmd;
1.1       root      271:  public:
                    272:        SCSICmdRequestSense(SCSITarget *p) : inherited(p) { }
1.1.1.6   root      273:        virtual ~SCSICmdRequestSense() override { }
1.1       root      274: 
1.1.1.6   root      275:        SCSI::XferPhase Command(std::vector<uint8>& cmdseq) override {
1.1.1.4   root      276:                // 応答のセンスデータは SCSI-2 形式(最小18バイト) を実装。
                    277:                // 今の所、センスキー、ASC、ASCQ だけで返せる内容にだけ対応している。
                    278:                // これ以外のフィールドを返す必要が出来たらまた考えること。
                    279: 
1.1       root      280:                buf.clear();
1.1.1.6   root      281:                buf.resize(18);
1.1.1.4   root      282:                buf[0] = 0xf0;                          // Valid、エラーコード 0x70
                    283:                buf[1]  = 0;                            // セグメント番号(?)
                    284:                buf[2]  = parent->sensekey;     // センスキー (上位4ビットは今の所 0)
                    285:                buf[3]  = 0;                            // Information
                    286:                buf[4]  = 0;                            // Information
                    287:                buf[5]  = 0;                            // Information
                    288:                buf[6]  = 0;                            // Information
                    289:                buf[7]  = 0;                            // 追加センスデータ長 0
                    290:                buf[8]  = 0;                            // Command specific Information
                    291:                buf[9]  = 0;                            // Command specific Information
                    292:                buf[10] = 0;                            // Command specific Information
                    293:                buf[11] = 0;                            // Command specific Information
                    294:                buf[12] = parent->senseasc >> 8;
                    295:                buf[13] = parent->senseasc & 0xff;
                    296:                buf[14] = 0;                            // FRU
                    297:                buf[15] = 0;                            // センスキー固有情報
                    298:                buf[16] = 0;                            // センスキー固有情報
                    299:                buf[17] = 0;                            // センスキー固有情報
                    300:                // 追加センスデータなし
1.1       root      301: 
                    302:                // それからバッファを指定の長さに変更
                    303:                buf.resize((uint)cmdseq[4]);
                    304: 
1.1.1.4   root      305:                // 転送した後にセンスデータをクリア
                    306:                parent->ClearSense();
                    307: 
1.1       root      308:                return SCSI::XferPhase::DataIn;
                    309:        }
                    310: };
                    311: 
                    312: //
                    313: // SCSI コマンド 0x08: Read(6) (共通)
                    314: //
                    315: class SCSICmdRead6 : public SCSICmd
                    316: {
1.1.1.3   root      317:        using inherited = SCSICmd;
1.1       root      318:  public:
                    319:        SCSICmdRead6(SCSITarget *p) : inherited(p) { }
1.1.1.6   root      320:        virtual ~SCSICmdRead6() override { }
1.1       root      321: 
1.1.1.6   root      322:        SCSI::XferPhase Command(std::vector<uint8>& cmdseq) override {
1.1       root      323:                SCSIHD *hdparent = dynamic_cast<SCSIHD*>(parent);
                    324:                uint32 lba;
                    325:                uint32 blks;
                    326: 
1.1.1.4   root      327:                // センスデータをクリア
                    328:                parent->ClearSense();
                    329: 
1.1       root      330:                lba  = (cmdseq[1] & 0x1f) << 16;
                    331:                lba |= cmdseq[2] << 8;
                    332:                lba |= cmdseq[3];
                    333:                blks = cmdseq[4];
                    334:                // blks == 0 は 256 ブロック転送を意味する。
                    335:                if (blks == 0) {
                    336:                        blks = 256;
                    337:                }
1.1.1.8   root      338:                parent->putlogf(1, lstr("READ6 LBA=0x%x blks=0x%x", lba, blks));
1.1.1.4   root      339: 
                    340:                if (((uint64)lba + (uint64)blks) * parent->GetBlocksize() >
                    341:                    hdparent->GetSize())
                    342:                {
                    343:                        parent->sensekey = SCSI::SenseKey::IllegalRequest;
                    344:                        parent->senseasc = SCSI::ASC::InvalidFieldInCDB;
                    345:                        status_byte = SCSI::StatusByte::CheckCondition;
                    346:                        return SCSI::XferPhase::Status;
                    347:                }
                    348: 
1.1.1.2   root      349:                uint8 *start = hdparent->mem + lba * parent->GetBlocksize();
                    350:                uint8 *end = start + blks * parent->GetBlocksize();
1.1       root      351:                buf.assign(start, end);
                    352: 
1.1.1.5   root      353:                // 平均シークタイム
                    354:                optime = hdparent->seektime;
                    355: 
1.1       root      356:                return SCSI::XferPhase::DataIn;
                    357:        }
                    358: };
                    359: 
                    360: //
                    361: // SCSI コマンド 0x0a: Write(6) (共通)
                    362: //
                    363: class SCSICmdWrite6 : public SCSICmd
                    364: {
1.1.1.3   root      365:        using inherited = SCSICmd;
1.1       root      366:  public:
                    367:        SCSICmdWrite6(SCSITarget *p) : inherited(p) {
                    368:                hdparent = dynamic_cast<SCSIHD*>(parent);
                    369:        }
1.1.1.6   root      370:        virtual ~SCSICmdWrite6() override { }
1.1       root      371: 
1.1.1.6   root      372:        SCSI::XferPhase Command(std::vector<uint8>& cmdseq) override {
1.1.1.4   root      373:                // センスデータをクリア
                    374:                parent->ClearSense();
                    375: 
1.1       root      376:                lba  = (cmdseq[1] & 0x1f) << 16;
                    377:                lba |= cmdseq[2] << 8;
                    378:                lba |= cmdseq[3];
                    379:                blks = cmdseq[4];
                    380:                // blks == 0 は 256 ブロック転送を意味する。
                    381:                if (blks == 0) {
                    382:                        blks = 256;
                    383:                }
                    384: 
1.1.1.4   root      385:                if (((uint64)lba + (uint64)blks) * parent->GetBlocksize() >
                    386:                    hdparent->GetSize())
                    387:                {
                    388:                        parent->sensekey = SCSI::SenseKey::IllegalRequest;
                    389:                        parent->senseasc = SCSI::ASC::InvalidFieldInCDB;
                    390:                        status_byte = SCSI::StatusByte::CheckCondition;
                    391:                        return SCSI::XferPhase::Status;
                    392:                }
                    393: 
1.1.1.5   root      394:                // 平均シークタイム
                    395:                optime = hdparent->seektime;
                    396: 
1.1.1.4   root      397:                recvbytes = blks * parent->GetBlocksize();
1.1       root      398:                return SCSI::XferPhase::DataOut;
                    399:        }
                    400: 
1.1.1.6   root      401:        SCSI::XferPhase DoneDataOut() override {
1.1.1.8   root      402:                parent->putlogf(1, lstr("WRITE6 LBA=0x%x blks=0x%x", lba, blks));
1.1       root      403:                if (hdparent->writeprotect == false) {
1.1.1.2   root      404:                        memcpy(hdparent->mem + (lba * parent->GetBlocksize()),
1.1       root      405:                                buf.data(), buf.size());
                    406:                }
                    407:                return SCSI::XferPhase::Status;
                    408:        }
                    409: 
                    410:  private:
                    411:        SCSIHD *hdparent;
                    412:        uint32 lba;
                    413:        uint32 blks;
                    414: };
                    415: 
                    416: //
                    417: // SCSI コマンド 0x12: Inquiry (共通)
                    418: //
                    419: class SCSICmdInquiry : public SCSICmd
                    420: {
1.1.1.3   root      421:        using inherited = SCSICmd;
1.1       root      422:  public:
                    423:        SCSICmdInquiry(SCSITarget *p) : inherited(p) { }
1.1.1.6   root      424:        virtual ~SCSICmdInquiry() override { }
1.1       root      425: 
1.1.1.6   root      426:        SCSI::XferPhase Command(std::vector<uint8>& cmdseq) override {
1.1.1.4   root      427:                // センスデータをクリア
                    428:                parent->ClearSense();
                    429: 
1.1       root      430:                // 応答データはターゲットデバイスが持っている
                    431:                buf = parent->inquiry_data;
                    432: 
                    433:                // 本来の応答データ長か reqlen の短いほうまで。
                    434:                uint reqlen = (uint)cmdseq[4];
                    435:                if (reqlen < buf.size()) {
                    436:                        buf.resize(reqlen);
                    437:                }
                    438:                return SCSI::XferPhase::DataIn;
                    439:        }
                    440: };
                    441: 
                    442: //
                    443: // SCSI コマンド 0x15 ModeSelect(6) (共通)
                    444: //
                    445: class SCSICmdModeSelect6 : public SCSICmd
                    446: {
1.1.1.3   root      447:        using inherited = SCSICmd;
1.1       root      448:  public:
                    449:        SCSICmdModeSelect6(SCSITarget *p) : inherited(p) { }
1.1.1.6   root      450:        virtual ~SCSICmdModeSelect6() override { }
1.1       root      451: 
1.1.1.6   root      452:        SCSI::XferPhase Command(std::vector<uint8>& cmdseq) override {
1.1.1.4   root      453:                // センスデータをクリア
                    454:                parent->ClearSense();
                    455: 
1.1       root      456:                recvbytes = cmdseq[4];
                    457:                return SCSI::XferPhase::DataOut;
                    458:        }
                    459: 
1.1.1.6   root      460:        SCSI::XferPhase DoneDataOut() override {
1.1       root      461:                // Mode Select(6) のデータは以下の構造で並んでいる。
                    462:                //  ヘッダ
                    463:                //  ブロックディスクリプタ#1
                    464:                //   :
                    465:                //  ブロックディスクリプタ#n
                    466:                //  パラメータページ #1
                    467:                //   :
                    468:                //  パラメータページ #m
                    469: 
                    470:                const SCSI::ModeParamHdr *hdr = (const SCSI::ModeParamHdr *)buf.data();
                    471: 
                    472:                if (hdr->block_desc_len > 0) {
                    473:                        const SCSI::BlockDesc *desc =
                    474:                                (const SCSI::BlockDesc *)(buf.data() + sizeof(*hdr));
                    475:                        uint blocksize;
                    476:                        blocksize  = (desc->block_size[0]) << 16;
                    477:                        blocksize |= (desc->block_size[1]) << 8;
                    478:                        blocksize |= (desc->block_size[2]);
                    479: 
                    480:                        // ブロック長を書き戻す
1.1.1.2   root      481:                        parent->SetBlocksize(blocksize);
1.1       root      482:                }
                    483:                return SCSI::XferPhase::Status;
                    484:        }
                    485: };
                    486: 
                    487: //
1.1.1.2   root      488: // SCSI コマンド 0x1a ModeSense(6) (共通)
                    489: //
                    490: class SCSICmdModeSense6 : public SCSICmd
                    491: {
1.1.1.3   root      492:        using inherited = SCSICmd;
1.1.1.2   root      493:  public:
                    494:        SCSICmdModeSense6(SCSITarget *p) : inherited(p) { }
1.1.1.6   root      495:        virtual ~SCSICmdModeSense6() override { }
1.1.1.2   root      496: 
1.1.1.6   root      497:        SCSI::XferPhase Command(std::vector<uint8>& cmdseq) override {
1.1.1.2   root      498:                uint8 pagecode = (cmdseq[2] & 0x3f);
1.1.1.4   root      499: 
                    500:                // センスデータをクリア
                    501:                parent->ClearSense();
                    502: 
                    503:                // 未実装 (XXX センスデータは適当)
1.1.1.8   root      504:                parent->putlogf(1, lstr("ModeSense(6) PageCode $%02x 未実装",
                    505:                        pagecode));
1.1.1.4   root      506:                parent->sensekey = SCSI::SenseKey::IllegalRequest;
                    507:                parent->senseasc = SCSI::ASC::InvalidFieldInCDB;
                    508:                status_byte = SCSI::StatusByte::CheckCondition;
                    509: 
1.1.1.2   root      510:                return SCSI::XferPhase::Status;
                    511:        }
1.1.1.4   root      512: };
1.1.1.2   root      513: 
1.1.1.4   root      514: //
                    515: // SCSI コマンド 0x1b StartStopUnit (ダイレクトアクセスデバイス)
                    516: //
                    517: class SCSICmdStartStopUnit : public SCSICmd
                    518: {
                    519:        using inherited = SCSICmd;
                    520:  public:
                    521:        SCSICmdStartStopUnit(SCSITarget *p) : inherited(p) { }
1.1.1.6   root      522:        virtual ~SCSICmdStartStopUnit() override { }
1.1.1.4   root      523: 
                    524:        // スピンアップ/ダウンやメディアのロード/アンロードを指示する。
                    525:        // ので今の所エミュレーション上は特にすることはない。
                    526:        // XXX それっぽい時間待つくらいはしてもいいかも知れない
                    527: 
1.1.1.6   root      528:        SCSI::XferPhase Command(std::vector<uint8>& cmdseq) override {
1.1.1.8   root      529:                parent->putlogf(1, lstr("StartStopUnit"));
1.1.1.4   root      530:                return inherited::Command(cmdseq);
1.1.1.2   root      531:        }
                    532: };
                    533: 
                    534: //
1.1       root      535: // SCSI コマンド 0x25 ReadCapacity (ダイレクトアクセスデバイス)
                    536: //
                    537: class SCSICmdReadCapacity : public SCSICmd
                    538: {
1.1.1.3   root      539:        using inherited = SCSICmd;
1.1       root      540:  public:
                    541:        SCSICmdReadCapacity(SCSITarget *p) : inherited(p) { }
1.1.1.6   root      542:        virtual ~SCSICmdReadCapacity() override { }
1.1       root      543: 
1.1.1.6   root      544:        SCSI::XferPhase Command(std::vector<uint8>& cmdseq) override {
1.1       root      545:                SCSIHD *hdparent = dynamic_cast<SCSIHD*>(parent);
                    546: 
1.1.1.4   root      547:                // センスデータをクリア
                    548:                parent->ClearSense();
                    549: 
1.1       root      550:                // PMI=1 は未サポート
                    551:                if ((cmdseq[8] & 0x01) != 0) {
1.1.1.8   root      552:                        parent->putlogf(0, lstr("SCSI ReadCapacity PMI=1 not supported"));
1.1       root      553:                }
                    554: 
                    555:                // 応答データは
                    556:                // +00.L 最終論理ブロックアドレス
                    557:                // +04.L ブロック長
1.1.1.2   root      558:                uint32 blksize = parent->GetBlocksize();
1.1.1.3   root      559:                uint32 lastblk = (hdparent->GetSize() / blksize) - 1;
1.1       root      560:                buf.resize(8);
                    561:                buf[0] = lastblk >> 24;
                    562:                buf[1] = lastblk >> 16;
                    563:                buf[2] = lastblk >> 8;
                    564:                buf[3] = lastblk;
                    565:                buf[4] = blksize >> 24;
                    566:                buf[5] = blksize >> 16;
                    567:                buf[6] = blksize >> 8;
                    568:                buf[7] = blksize;
                    569: 
                    570:                return SCSI::XferPhase::DataIn;
                    571:        }
                    572: };
                    573: 
                    574: //
                    575: // SCSI コマンド 0x28 Read(10) (ダイレクトアクセスデバイス)
                    576: //
                    577: class SCSICmdRead10 : public SCSICmd
                    578: {
1.1.1.3   root      579:        using inherited = SCSICmd;
1.1       root      580:  public:
                    581:        SCSICmdRead10(SCSITarget *p) : inherited(p) { }
1.1.1.6   root      582:        virtual ~SCSICmdRead10() override { }
1.1       root      583: 
1.1.1.6   root      584:        SCSI::XferPhase Command(std::vector<uint8>& cmdseq) override {
1.1       root      585:                SCSIHD *hdparent = dynamic_cast<SCSIHD*>(parent);
                    586:                uint32 lba;
                    587:                uint32 blks;
                    588: 
1.1.1.4   root      589:                // センスデータをクリア
                    590:                parent->ClearSense();
                    591: 
1.1       root      592:                if ((cmdseq[1] & 0x01)) {
1.1.1.8   root      593:                        parent->putlogf(0, lstr("SCSI Read(10) RelAdr not supported"));
1.1       root      594:                }
                    595: 
                    596:                lba  = cmdseq[2] << 24;
                    597:                lba |= cmdseq[3] << 16;
                    598:                lba |= cmdseq[4] << 8;
                    599:                lba |= cmdseq[5];
                    600:                blks  = cmdseq[7] << 8;
                    601:                blks |= cmdseq[8];
1.1.1.8   root      602:                parent->putlogf(1, lstr("READ10 LBA=0x%x blks=0x%x", lba, blks));
1.1.1.4   root      603: 
                    604:                if (((uint64)lba + (uint64)blks) * parent->GetBlocksize() >
                    605:                    hdparent->GetSize())
                    606:                {
                    607:                        parent->sensekey = SCSI::SenseKey::IllegalRequest;
                    608:                        parent->senseasc = SCSI::ASC::InvalidFieldInCDB;
                    609:                        status_byte = SCSI::StatusByte::CheckCondition;
                    610:                        return SCSI::XferPhase::Status;
                    611:                }
1.1       root      612: 
1.1.1.2   root      613:                uint8 *start = hdparent->mem + lba * parent->GetBlocksize();
                    614:                uint8 *end = start + blks * parent->GetBlocksize();
1.1       root      615:                buf.assign(start, end);
                    616: 
1.1.1.5   root      617:                // 平均シークタイム
                    618:                optime = hdparent->seektime;
                    619: 
1.1       root      620:                return SCSI::XferPhase::DataIn;
                    621:        }
                    622: };
                    623: 
                    624: //
1.1.1.7   root      625: // SCSI コマンド 0x2a Write(10) (ダイレクトアクセスデバイス)
                    626: //
                    627: class SCSICmdWrite10 : public SCSICmd
                    628: {
                    629:        using inherited = SCSICmd;
                    630:  public:
                    631:        SCSICmdWrite10(SCSITarget *p) : inherited(p) {
                    632:                hdparent = dynamic_cast<SCSIHD*>(parent);
                    633:        }
                    634:        virtual ~SCSICmdWrite10() override { }
                    635: 
                    636:        SCSI::XferPhase Command(std::vector<uint8>& cmdseq) override {
                    637:                // センスデータをクリア
                    638:                parent->ClearSense();
                    639: 
                    640:                lba  = cmdseq[2] << 24;
                    641:                lba |= cmdseq[3] << 16;
                    642:                lba |= cmdseq[4] << 8;
                    643:                lba |= cmdseq[5];
                    644:                blks  = cmdseq[7] << 8;
                    645:                blks |= cmdseq[8];
                    646: 
                    647:                if (((uint64)lba + (uint64)blks) * parent->GetBlocksize() >
                    648:                        hdparent->GetSize())
                    649:                {
                    650:                        parent->sensekey = SCSI::SenseKey::IllegalRequest;
                    651:                        parent->senseasc = SCSI::ASC::InvalidFieldInCDB;
                    652:                        status_byte = SCSI::StatusByte::CheckCondition;
                    653:                        return SCSI::XferPhase::Status;
                    654:                }
                    655: 
                    656:                // 平均シークタイム
                    657:                optime = hdparent->seektime;
                    658: 
                    659:                recvbytes = blks * parent->GetBlocksize();
                    660:                return SCSI::XferPhase::DataOut;
                    661:        }
                    662: 
                    663:        SCSI::XferPhase DoneDataOut() override {
1.1.1.8   root      664:                parent->putlogf(1, lstr("WRITE10 LBA=0x%x blks=0x%x", lba, blks));
1.1.1.7   root      665:                if (hdparent->writeprotect == false) {
                    666:                        memcpy(hdparent->mem + (lba * parent->GetBlocksize()),
                    667:                                buf.data(), buf.size());
                    668:                }
                    669:                return SCSI::XferPhase::Status;
                    670:        }
                    671: 
                    672:  private:
                    673:        SCSIHD *hdparent;
                    674:        uint32 lba;
                    675:        uint32 blks;
                    676: };
                    677: 
                    678: //
1.1       root      679: // SCSI コマンド サポートしていないコマンド
                    680: //
                    681: class SCSICmdNotSupportedCommand : public SCSICmd
                    682: {
1.1.1.3   root      683:        using inherited = SCSICmd;
1.1       root      684:  public:
                    685:        SCSICmdNotSupportedCommand(SCSITarget *p) : inherited(p) { }
1.1.1.6   root      686:        virtual ~SCSICmdNotSupportedCommand() override { }
1.1       root      687: 
1.1.1.6   root      688:        SCSI::XferPhase Command(std::vector<uint8>& cmdseq) override {
1.1.1.4   root      689:                // XXX センスキーよく分からんけどとりあえず
                    690:                parent->sensekey = SCSI::SenseKey::IllegalRequest;
                    691:                parent->senseasc = SCSI::ASC::InvalidCommandOperationCode;
                    692:                status_byte = SCSI::StatusByte::CheckCondition;
                    693:                return SCSI::XferPhase::Status;
1.1       root      694:        }
                    695: };
                    696: 
1.1.1.6   root      697: #if defined(__clang__)
                    698: #pragma clang diagnostic pop
                    699: #endif
1.1       root      700: 
                    701: //
                    702: // SCSI ターゲットデバイスの共通部分
                    703: //
                    704: 
                    705: // コンストラクタ
1.1.1.10! root      706: SCSITarget::SCSITarget(const std::string& objname_,
        !           707:        SCSIHostDevice *h, int id, std::vector<uint8>& inq)
        !           708:        : inherited(objname_)
1.1       root      709: {
                    710:        inquiry_data = inq;
                    711:        // ホストへのリンク (所有関係のないポインタ)
                    712:        host = h;
                    713:        myid = id;
                    714: }
                    715: 
                    716: // デストラクタ
                    717: SCSITarget::~SCSITarget()
                    718: {
                    719: }
                    720: 
1.1.1.9   root      721: // 電源オン
                    722: bool
                    723: SCSITarget::PowerOn()
                    724: {
                    725:        ClearSense();
                    726:        cmdseq.clear();
                    727:        cmdlen = 0;
                    728:        cmd.reset();
                    729:        bytecount = 0;
                    730:        lastbyte = false;
                    731: 
                    732:        return true;
                    733: }
                    734: 
1.1.1.4   root      735: // バスリセットされた (SCSIBus から呼ばれる)
                    736: void
                    737: SCSITarget::BusResetCB()
                    738: {
1.1.1.5   root      739:        // リセットされたので持ってる信号を全部解放。
                    740:        // 一応自分が変えていい信号線だけを落とす。
                    741:        switch (GetPhase()) {
                    742:         case SCSI::Phase::BusFree:
                    743:                break;
                    744:         case SCSI::Phase::Arbitration:
                    745:         case SCSI::Phase::Selection:
                    746:         case SCSI::Phase::Reselection:
                    747:                NegateSEL();
                    748:                NegateBSY();
                    749:                break;
                    750:         case SCSI::Phase::Transfer:
                    751:                NegateBSY();
                    752:                break;
                    753:        }
                    754: 
1.1.1.4   root      755:        // センスキーをクリア
                    756:        ClearSense();
                    757: }
                    758: 
1.1       root      759: // セレクションで選択された (SCSIBus から呼ばれる)
                    760: void
                    761: SCSITarget::SelectionCB()
                    762: {
                    763:        // ターゲットが、自身が選択されていることを認識してから BSY を
                    764:        // 立てるまでの時間はもうバス側でカウントしてあるので、ここでは
                    765:        // ただちに BSY を上げてよい。
                    766:        putlog(4, "Selection Callback");
                    767:        AssertBSY();
                    768: }
                    769: 
                    770: // 情報転送フェーズを開始する (SCSIBus から呼ばれる)
                    771: void
                    772: SCSITarget::StartTransferCB()
                    773: {
                    774:        // 最初はコマンドフェーズ。(ATN はとりあえず放置)
                    775:        putlog(4, "Start Command Phase");
                    776:        cmdseq.clear();
                    777:        cmdlen = 0;
                    778:        SetXfer(SCSI::XferPhase::Command);
                    779:        AssertREQ();
                    780: }
                    781: 
                    782: // 情報転送フェーズ間の遷移について
                    783: //
                    784: // 情報転送フェーズは TransferCB() で1バイトずつ転送を行い、所定のバイト数
                    785: // の転送が完了すればフェーズを遷移する。遷移方法は入出力方向別で6通り。
                    786: //  o IN  -> IN
                    787: //  o IN  -> OUT
                    788: //  o IN  -> END
                    789: //  o OUT -> OUT
                    790: //  o OUT -> IN
                    791: //  o OUT -> END
                    792: //
                    793: // IN -> IN の遷移。TransferCB() で前フェーズの最終バイト受信後、フェーズを
                    794: // 変更して REQ を立てるところまで。
                    795: //
                    796: // IN -> OUT の遷移。TransferCB() で前フェーズの最終バイト受信後、フェーズを
                    797: // 変更して (おそらく {Phase}Begin() を発行してから)、データをセットし REQ
                    798: // を立てる?
                    799: //
                    800: // IN -> END の遷移。TransferCB() で前フェーズの最終バイト受信後、BSY を
                    801: // 下げて終了。
                    802: //
                    803: // OUT -> OUT の遷移。前フェーズの最終バイトをイニシエータが受信後に
                    804: // TransferCB() が呼ばれるので、フェーズを変更して (おそらく {Phase}Begin()
                    805: // を発行してから)、データをセットし REQ を立てる?
                    806: //
                    807: // OUT -> IN の遷移。前フェーズの最終バイトをイニシエータが受信後に
                    808: // TransferCB() が呼ばれるので、フェーズを変更して (おそらく {Phase}Begin()
                    809: // を発行してから)、REQ を立てる?
                    810: //
                    811: // OUT -> END の遷移。前フェーズの最終バイトをイニシエータが受信後に
                    812: // TransferCB() が呼ばれるので、BSY を下げる?
                    813: 
                    814: // 情報転送フェーズでイニシエータが ACK を上げた。(SCSIBus から呼ばれる)
                    815: // OUT (イニシエータ → ターゲット方向) なら、ターゲットが上げた REQ に応答
                    816: // してイニシエータがデータをデータバスに乗せてからこれをコールしてくる。
                    817: // IN (ターゲット → イニシエータ方向) なら、ターゲットがデータをデータバスに
                    818: // 乗せて REQ を上げたのをイニシエータが受信した後でこれをコールしてくる。
                    819: void
                    820: SCSITarget::TransferCB()
                    821: {
                    822:        uint8 data;
                    823:        SCSI::XferPhase xfer;
                    824: 
                    825:        // このフェーズの最終バイトか
                    826:        lastbyte = false;
                    827: 
                    828:        // このフェーズの1バイト処理
                    829:        xfer = GetXfer();
                    830:        if (xfer == SCSI::XferPhase::Command) {
                    831:                // コマンドフェーズだけいろいろ特殊なので別処理。
                    832:                // 受信バッファが異なる、1バイト目で受信長が決まるなど。
                    833:                data = GetData();
                    834:                putlog(4, "TransferCB: cmdseq[%02d] = $%02x",
                    835:                        (int)cmdseq.size(), data);
                    836:                cmdseq.push_back(data);
                    837:                if (cmdseq.size() == 1) {
                    838:                        // 1バイト目ならこのコマンドが何バイトか調べる
                    839:                        switch (cmdseq[0] >> 5) {
                    840:                         case 0:        cmdlen =  6;    break;
                    841:                         case 1:        cmdlen = 10;    break;
                    842:                         case 2:        cmdlen = 10;    break;
                    843:                         case 5:        cmdlen = 12;    break;
                    844:                         default:
                    845:                                // 3,4 はリサーブ、6,7 はベンダー定義。XXX 来たらどうする?
                    846:                                cmdlen = 6;
                    847:                                break;
                    848:                        }
                    849:                } else if (cmdseq.size() >= cmdlen) {
                    850:                        if (loglevel >= 1) {
                    851:                                std::string cmdbuf;
                    852:                                const char *name = SCSI::GetCommandName(cmdseq[0]);
                    853:                                cmdbuf += string_format("Command \"%s\"", name ?: "?");
                    854:                                for (const auto& v : cmdseq) {
                    855:                                        cmdbuf += string_format(" $%02x", v);
                    856:                                }
1.1.1.8   root      857:                                putlogn("%s", cmdbuf.c_str());
1.1       root      858:                        }
                    859:                        // 最終バイトを受信したらコマンドを選択
                    860:                        DispatchCmd();
                    861:                        lastbyte = true;
                    862:                }
                    863:        } else if (GetIO() == false) {
                    864:                // OUT 方向 (ターゲットが受信側)
                    865:                // bytecount は減算方向。
                    866:                cmd->buf.push_back(GetData());
                    867:                bytecount--;
                    868:                if (bytecount == 0) {
                    869:                        lastbyte = true;
                    870:                }
                    871:        } else {
                    872:                // IN 方向 (ターゲットが送信側)
                    873:                // bytecount は加算方向。
                    874:                // データは前のループの終わり (TransferAckCB()の下のほう) で
                    875:                // セットしているのでここでは引き取られた分をカウントする。
                    876:                bytecount++;
                    877:                if (bytecount >= cmd->buf.size()) {
                    878:                        lastbyte = true;
                    879:                }
                    880:        }
                    881: 
                    882:        NegateREQ();
                    883: }
                    884: 
                    885: // 情報転送フェーズでイニシエータが ACK を下げた。(SCSIBus から呼ばれる)
                    886: void
                    887: SCSITarget::TransferAckCB()
                    888: {
                    889:        SCSI::XferPhase xfer = GetXfer();
                    890: 
                    891:        // これが最終バイトだったら、フェーズ完了 → フェーズ切り替え。
                    892:        if (lastbyte) {
                    893:                SCSI::XferPhase next;
                    894:                // フェーズ完了
                    895:                switch (xfer) {
                    896:                 case SCSI::XferPhase::Command:
                    897:                        next = cmd->Command(cmdseq);
                    898:                        break;
                    899:                 case SCSI::XferPhase::DataOut:
                    900:                        next = cmd->DoneDataOut();
                    901:                        break;
                    902:                 case SCSI::XferPhase::DataIn:
                    903:                        next = cmd->DoneDataIn();
                    904:                        break;
                    905:                 case SCSI::XferPhase::MsgOut:
                    906:                        next = cmd->DoneMsgOut();
                    907:                        break;
                    908:                 case SCSI::XferPhase::MsgIn:
                    909:                        next = cmd->DoneMsgIn();
                    910:                        break;
                    911:                 case SCSI::XferPhase::Status:
                    912:                        next = cmd->DoneStatus();
                    913:                        break;
                    914:                 default:
                    915:                        PANIC("TransferCB unknown xfer done %d", (int)xfer);
                    916:                }
                    917:                putlog(2, "%s done", SCSI::GetXferPhaseName(xfer));
                    918: 
1.1.1.5   root      919:                // 簡略化のため、フェーズ完了時だけ REQ を引き伸ばすことができる
                    920:                if (cmd->optime != 0) {
                    921:                        bus->SetOneshotReqWait(cmd->optime);
                    922:                        cmd->optime = 0;
                    923:                }
                    924: 
1.1       root      925:                if (next != xfer) {
                    926:                        // End ならバスフリーにして終了。
                    927:                        if (next == SCSI::XferPhase::End) {
                    928:                                NegateBSY();
                    929:                                return;
                    930:                        }
                    931: 
                    932:                        // (必要なら)フェーズを更新
                    933:                        SetXfer(next);
                    934:                        xfer = next;
                    935: 
                    936:                        // 新しいフェーズの開始処理
                    937:                        // XXX ここで bytecount とかをリセットできればいいのだが
                    938:                        // Command フェーズで Data フェーズの準備をすることが多いので
                    939:                        // 悩ましい。
                    940:                        switch (xfer) {
                    941:                         case SCSI::XferPhase::DataOut:
                    942:                                cmd->buf.clear();
                    943:                                bytecount = cmd->recvbytes;
                    944:                                putlog(3, "DataOut begin (%d bytes)", bytecount);
                    945:                                break;
                    946:                         case SCSI::XferPhase::DataIn:
                    947:                                bytecount = 0;
                    948:                                putlog(3, "DataIn begin (%d bytes)", (int)cmd->buf.size());
                    949:                                break;
                    950:                         case SCSI::XferPhase::MsgOut:
                    951:                                cmd->BeginMsgOut();
                    952:                                cmd->buf.clear();
                    953:                                bytecount = cmd->recvbytes;
                    954:                                putlog(3, "MsgOut begin (%d bytes)", bytecount);
                    955:                                break;
                    956:                         case SCSI::XferPhase::MsgIn:
                    957:                                cmd->BeginMsgIn();
                    958:                                bytecount = 0;
                    959:                                putlog(3, "MsgIn begin (%d bytes)", (int)cmd->buf.size());
                    960:                                break;
                    961:                         case SCSI::XferPhase::Status:
                    962:                                cmd->BeginStatus();
                    963:                                bytecount = 0;
                    964:                                putlog(3, "Status begin (%d bytes)", (int)cmd->buf.size());
                    965:                                break;
                    966:                         default:
                    967:                                PANIC("TransferCB unknown xfer begin %d", (int)xfer);
                    968:                        }
                    969:                }
                    970:        }
                    971: 
                    972:        // IN 方向 (ターゲットが送信側) ならここでデータをバスにセット。
                    973:        if (GetIO()) {
                    974:                SetData(cmd->buf[bytecount]);
                    975:                putlog(4, "SetData $%02x", GetData());
                    976:        }
                    977: 
                    978:        // 次のバイト転送を行うために REQ を上げる。
                    979:        AssertREQ();
                    980: }
                    981: 
                    982: // SCSI コマンドのディスパッチャ
                    983: void
                    984: SCSITarget::DispatchCmd()
                    985: {
                    986:        switch (cmdseq[0]) {
                    987:         case SCSI::Command::TestUnitReady:     // 0x00
                    988:                cmd.reset(new SCSICmdTestUnitReady(this));
                    989:                break;
                    990: 
1.1.1.2   root      991:         case SCSI::Command::RezeroUnit:        // 0x01
                    992:                cmd.reset(new SCSICmdRezeroUnit(this));
                    993:                break;
                    994: 
1.1       root      995:         case SCSI::Command::RequestSense:      // 0x03
                    996:                cmd.reset(new SCSICmdRequestSense(this));
                    997:                break;
                    998: 
                    999:         case SCSI::Command::Inquiry:           // 0x12
                   1000:                cmd.reset(new SCSICmdInquiry(this));
                   1001:                break;
                   1002: 
                   1003:         case SCSI::Command::ModeSelect6:       // 0x15
                   1004:                cmd.reset(new SCSICmdModeSelect6(this));
                   1005:                break;
                   1006: 
1.1.1.2   root     1007:         case SCSI::Command::ModeSense6:        // 0x1a
                   1008:                cmd.reset(new SCSICmdModeSense6(this));
                   1009:                break;
                   1010: 
1.1       root     1011:         case SCSI::Command::ReadCapacity:      // 0x25
                   1012:                cmd.reset(new SCSICmdTestUnitReady(this));
                   1013:                break;
                   1014: 
                   1015:         default:
                   1016:                // サポートしていないコマンド
                   1017:                const char *cname = SCSI::GetCommandName(cmdseq[0]);
                   1018:                std::string name;
                   1019:                if (cname) {
                   1020:                        name = string_format(" %s", cname);
                   1021:                }
                   1022:                putlog(0, "未実装 SCSI コマンド $%02x%s len=%d",
                   1023:                        cmdseq[0], name.c_str(), (int)cmdseq.size());
                   1024: 
                   1025:                cmd.reset(new SCSICmdNotSupportedCommand(this));
                   1026:                break;
                   1027:        }
                   1028: }
                   1029: 
                   1030: //
                   1031: // SCSI HD
                   1032: //
                   1033: 
                   1034: // コンストラクタ
                   1035: SCSIHD::SCSIHD(SCSIHostDevice *h, int id)
1.1.1.10! root     1036:        : inherited(string_format("SCSIHD%d", id), h, id, inquiry_data)
1.1       root     1037: {
1.1.1.10! root     1038:        AddAlias(string_format("HD%d", id));
        !          1039: 
1.1.1.4   root     1040:        devtype = SCSI::DevType::HD;
1.1       root     1041: }
                   1042: 
                   1043: // デストラクタ
                   1044: SCSIHD::~SCSIHD()
                   1045: {
                   1046: }
                   1047: 
                   1048: // 初期化
                   1049: bool
                   1050: SCSIHD::Init()
                   1051: {
                   1052:        const std::string myname = string_format("%s:ID%d",
                   1053:                host->GetConfigName(), myid);
1.1.1.2   root     1054:        const std::string keybody = string_format("%s-id%d-",
1.1       root     1055:                host->GetConfigName(), myid);
                   1056:        const std::string imgkey = keybody + "image";
                   1057:        const std::string wpkey  = keybody + "writeprotect";
1.1.1.5   root     1058:        const std::string stkey  = keybody + "seektime";
1.1       root     1059: 
1.1.1.3   root     1060:        const ConfigItem& itemimg = gConfig->Find(imgkey);
1.1.1.2   root     1061:        const std::string& image = itemimg.AsString();
                   1062:        // ここに来る時にチェックしているので ',' はあるはず
                   1063:        auto pos = image.find(',') + 1;
                   1064:        std::string filename = string_ltrim(image.substr(pos, image.size() - pos));
                   1065:        if (filename.length() == 0) {
                   1066:                itemimg.Err("imagefile not specified");
1.1       root     1067:                return false;
                   1068:        }
                   1069: 
1.1.1.3   root     1070:        // ファイルをオープン
1.1.1.2   root     1071:        const std::string path = gMainApp.GetVMDir() + filename;
1.1.1.3   root     1072:        file.SetFilename(path);
                   1073:        file.SetDispname(string_format("%s \"%s\"", myname.c_str(), path.c_str()));
                   1074:        mem = file.OpenFile();
                   1075:        if (mem == NULL) {
1.1       root     1076:                return false;
                   1077:        }
                   1078: 
1.1.1.3   root     1079:        writeprotect = gConfig->Find(wpkey).AsInt();
1.1       root     1080:        if (writeprotect) {
                   1081:                putmsg(0, "%s: write protected", myname.c_str());
                   1082:        }
                   1083: 
1.1.1.5   root     1084:        // 設定は [msec]、変数は [nsec]。
                   1085:        seektime = gConfig->Find(stkey).AsInt();
                   1086:        seektime *= 1_msec;
                   1087: 
1.1       root     1088:        return true;
                   1089: }
                   1090: 
                   1091: // SCSI コマンドのディスパッチャ
                   1092: void
                   1093: SCSIHD::DispatchCmd()
                   1094: {
                   1095:        switch (cmdseq[0]) {
                   1096:         case SCSI::Command::Read6:                     // 0x08
                   1097:                cmd.reset(new SCSICmdRead6(this));
                   1098:                break;
                   1099: 
                   1100:         case SCSI::Command::Write6:            // 0x0a
                   1101:                cmd.reset(new SCSICmdWrite6(this));
                   1102:                break;
                   1103: 
1.1.1.4   root     1104:         case SCSI::Command::StartStopUnit:     // 0x1b
                   1105:                cmd.reset(new SCSICmdStartStopUnit(this));
                   1106:                break;
                   1107: 
1.1       root     1108:         case SCSI::Command::ReadCapacity:      // 0x25
                   1109:                cmd.reset(new SCSICmdReadCapacity(this));
                   1110:                break;
                   1111: 
                   1112:         case SCSI::Command::Read10:            // 0x28
                   1113:                cmd.reset(new SCSICmdRead10(this));
                   1114:                break;
                   1115: 
1.1.1.7   root     1116:         case SCSI::Command::Write10:           // 0x2a
                   1117:                cmd.reset(new SCSICmdWrite10(this));
                   1118:                break;
                   1119: 
1.1       root     1120:         default:
                   1121:                // 見付からなければ基本クラス側に任せる
                   1122:                inherited::DispatchCmd();
                   1123:                break;
                   1124:        }
                   1125: }
                   1126: 
1.1.1.2   root     1127: // 指定の場所を自由に読み出す
                   1128: // (エミュレータ特権アクセス)
                   1129: bool
                   1130: SCSIHD::PeekImage(void *buf, uint32 start, uint32 len) const
                   1131: {
                   1132:        if (mem == NULL) {
                   1133:                return false;
                   1134:        }
1.1.1.3   root     1135:        if ((uint64)start + (uint64)len > GetSize()) {
1.1.1.2   root     1136:                return false;
                   1137:        }
                   1138:        memcpy(buf, mem + start, len);
                   1139:        return true;
                   1140: }
                   1141: 
1.1       root     1142: // HD の inquiry データ
                   1143: /*static*/ std::vector<uint8>
                   1144: SCSIHD::inquiry_data = {
                   1145:        0x00,   // 00 Qualifier + DeviceType
                   1146:        0x00,   // 01 RMB
                   1147:        0x40,   // 02 ISO version
                   1148:        0x00,   // 03 Response Data Format?
                   1149:        36 - 4, // 04 追加データ長
                   1150:        0,              // 05 Reserved
                   1151:        0,              // 06 Reserved
                   1152:        0x00,   // 07
                   1153:        'N', 'O', 'N', 'O', ' ', ' ', ' ', ' ',
                   1154:        'S', 'C', 'S', 'I', 'H', 'D', ' ', ' ',
                   1155:        ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
1.1.1.2   root     1156:        '0', ' ', ' ', ' ',
1.1       root     1157: };

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.