Annotation of nono/vm/scsidev.h, revision 1.1.1.17

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: 
1.1.1.12  root        7: //
                      8: // SCSI デバイス
                      9: //
1.1       root       10: 
1.1.1.17! root       11: // Device                 Device
        !            12: //    |                     |
        !            13: //    v                     v
        !            14: // IODevice             SCSIDevice         (SCSI デバイスとしての共通部分)
        !            15: //    |                     |
        !            16: //    v               +-----+------+
        !            17: // SPCDevice          v             v
        !            18: //      .scsi -> SCSIHostDevice SCSITarget (SCSI ホスト/ターゲットの共通部分)
        !            19: //                                  |
        !            20: //                                  v
        !            21: //                               SCSIDisk  (各デバイス、各ターゲット固有部分)
1.1       root       22: 
1.1.1.12  root       23: #pragma once
                     24: 
                     25: #include "diskimage.h"
                     26: #include "message.h"
                     27: #include "scsibus.h"
                     28: #include "scsicmd.h"
                     29: 
1.1       root       30: //
                     31: // SCSI デバイスとしての共通部分。
                     32: //
1.1.1.17! root       33: class SCSIDevice : public Device
1.1       root       34: {
1.1.1.17! root       35:        using inherited = Device;
1.1       root       36:  public:
1.1.1.17! root       37:        explicit SCSIDevice(uint objid_);
1.1.1.16  root       38:        ~SCSIDevice() override;
1.1       root       39: 
1.1.1.17! root       40:        // バスに接続された (SCSIBus から呼ばれる)
        !            41:        void OnAttached(SCSIBus *bus_, uint myid_);
1.1       root       42: 
1.1.1.5   root       43:        // SCSI ID を返す
1.1.1.17! root       44:        uint GetMyID() const { return myid; }
1.1.1.5   root       45: 
                     46:        // デバイス種別を返す (主にデバッグ表示用)
                     47:        SCSI::DevType GetDevType() const { return devtype; }
                     48: 
1.1.1.17! root       49:        // 自身が接続しているバスを返す。
        !            50:        // イニシエータがバスに接続するのは VM 実行後なことに注意。
        !            51:        SCSIBus *GetBus() const { return bus; }
        !            52: 
1.1       root       53:        //
                     54:        // 信号線制御
                     55:        // (ソースコード的なショートカットのため)
                     56:        //
                     57:        bool GetRST() const                             { return bus->GetRST(); }
                     58:        void AssertRST()                                { bus->AssertRST(); }
                     59:        void NegateRST()                                { bus->NegateRST(); }
                     60:        bool GetREQ() const                             { return bus->GetREQ(); }
                     61:        void AssertREQ()                                { bus->AssertREQ(); }
                     62:        void NegateREQ()                                { bus->NegateREQ(); }
                     63:        bool GetACK() const                             { return bus->GetACK(); }
                     64:        void AssertACK()                                { bus->AssertACK(); }
                     65:        void NegateACK()                                { bus->NegateACK(); }
                     66:        bool GetATN() const                             { return bus->GetATN(); }
                     67:        void AssertATN()                                { bus->AssertATN(); }
                     68:        void NegateATN()                                { bus->NegateATN(); }
                     69:        uint8 GetSEL() const                    { return bus->GetSEL(); }
                     70:        void AssertSEL()                                { bus->AssertSEL(myid); }
                     71:        void NegateSEL()                                { bus->NegateSEL(myid); }
                     72:        uint8 GetBSY() const                    { return bus->GetBSY(); }
                     73:        void AssertBSY()                                { bus->AssertBSY(myid); }
                     74:        void NegateBSY()                                { bus->NegateBSY(myid); }
                     75:        bool GetMSG() const                             { return bus->GetMSG(); }
                     76:        bool GetCD() const                              { return bus->GetCD(); }
                     77:        bool GetIO() const                              { return bus->GetIO(); }
                     78:        SCSI::XferPhase GetXfer() const { return bus->GetXfer(); }
                     79:        void SetXfer(uint8 val)                 { bus->SetXfer(val); }
                     80:        SCSI::Phase GetPhase() const    { return bus->GetPhase(); }
                     81:        uint8 GetData() const                   { return bus->GetData(); }
                     82:        void SetData(uint8 val) const   { bus->SetData(val); }
                     83: 
                     84:        //
1.1.1.17! root       85:        // SCSIBus から呼ばれる
1.1       root       86:        //
                     87: 
                     88:        // バスリセットされた (全員に通知される)
1.1.1.17! root       89:        virtual void OnBusReset() { }
1.1       root       90: 
                     91:        // バスフリーになった (全員に通知される)
1.1.1.17! root       92:        virtual void OnBusFree(uint id) { }
1.1       root       93: 
                     94:        // セレクションで選択された (ターゲットのみ通知される)
1.1.1.17! root       95:        virtual void OnSelected() { }
1.1       root       96: 
                     97:        // ターゲットがセレクションに応答した (イニシエータのみ通知される)
1.1.1.17! root       98:        virtual void OnSelectionAck() { }
1.1       root       99: 
                    100:        // 情報転送フェーズを開始する (ターゲットのみ通知される)
1.1.1.17! root      101:        virtual void OnStartTransfer() { }
1.1       root      102: 
                    103:        // 情報転送フェーズで REQ を立てた (イニシエータのみ通知される)
1.1.1.17! root      104:        virtual void OnTransferReq() { }
1.1       root      105: 
                    106:        // 情報転送フェーズで1バイト送受信が進んだ (ターゲットのみ通知される)
1.1.1.17! root      107:        virtual void OnTransfer() { }
1.1       root      108: 
                    109:        // 情報転送フェーズ(マニュアル転送)で ACK を下げた (ターゲットのみ通知)
1.1.1.17! root      110:        virtual void OnTransferAck() { }
1.1       root      111: 
                    112:  protected:
                    113:        // 自身の ID
1.1.1.5   root      114:        uint myid {};
                    115: 
                    116:        // デバイス種別
                    117:        SCSI::DevType devtype {};
1.1       root      118: 
                    119:        // 自身が繋がっているバスへのポインタ。
                    120:        // (イニシエータ自身も含めて) 所有していない。
1.1.1.5   root      121:        SCSIBus *bus {};
1.1       root      122: };
                    123: 
                    124: //
                    125: // ホストデバイスの共通部分。
1.1.1.17! root      126: // イニシエータもしくは HBA (ホストバスアダプタ) に相当する部分。
1.1       root      127: //
                    128: class SCSIHostDevice : public SCSIDevice
                    129: {
1.1.1.9   root      130:        using inherited = SCSIDevice;
1.1.1.17! root      131: 
1.1       root      132:  public:
1.1.1.17! root      133:        using SCSIHostCallback_t = void (Device::*)();
        !           134:        using BusFreeCallback_t = void (Device::*)(uint);
        !           135: #define ToSCSIHostCallback(f)  \
        !           136:        static_cast<SCSIHostDevice::SCSIHostCallback_t>(f)
        !           137: #define ToBusFreeCallback(f)   \
        !           138:        static_cast<SCSIHostDevice::BusFreeCallback_t>(f)
        !           139: 
        !           140:  public:
        !           141:        SCSIHostDevice(IODevice *parent_, const char *config_name_);
1.1.1.16  root      142:        ~SCSIHostDevice() override;
1.1       root      143: 
1.1.1.3   root      144:        bool Init() override;
1.1       root      145: 
1.1.1.17! root      146:        // コールバック関数を設定する。
        !           147:        void SetCallback(
        !           148:                BusFreeCallback_t busfree_,
        !           149:                SCSIHostCallback_t selack_,
        !           150:                SCSIHostCallback_t xferreq_);
1.1       root      151: 
1.1.1.17! root      152:        // 所有している SCSIBus ポインタを返す。こっちは接続前でも使える。
        !           153:        SCSIBus *GetOwnedBus() const { return scsibus.get(); }
1.1       root      154: 
1.1.1.17! root      155:        // ターゲットデバイスを返す。(ショートカット)
        !           156:        SCSITarget *GetTarget(uint id) const { return scsibus->GetTarget(id); }
1.1.1.2   root      157: 
1.1.1.17! root      158:  private:
        !           159:        // SCSIBus から呼ばれる
1.1.1.10  root      160: 
1.1.1.17! root      161:        // バスフリーになった (SCSIBus から全員に通知される)
        !           162:        void OnBusFree(uint id) override;
        !           163:        // ターゲットがセレクションに応答した (SCSIBus から呼ばれる)
        !           164:        void OnSelectionAck() override;
        !           165:        // 情報転送フェーズで REQ を立てた (イニシエータのみ通知される)
        !           166:        void OnTransferReq() override;
1.1.1.8   root      167: 
1.1.1.17! root      168:        // 親クラス(コントローラ) へのコールバック。
1.1.1.10  root      169: 
1.1.1.17! root      170:        // バスフリーを通知する
        !           171:        BusFreeCallback_t BusFreeCallback {};
        !           172:        // ターゲットがセレクションに応答したことを通知する
        !           173:        SCSIHostCallback_t SelectionAckCallback {};
        !           174:        // 転送フェーズでターゲットが REQ を立てたことを通知する
        !           175:        SCSIHostCallback_t TransferReqCallback {};
1.1       root      176: 
                    177:        // SCSI バス (とターゲットオブジェクト)
                    178:        //
                    179:        // ホストデバイスなのでバスオブジェクト(SCSIBus *scsibus)と、このバスに
                    180:        // 繋がるターゲットデバイスのオブジェクト(SCSITarget *target[]) を所有
                    181:        // (unique_ptr) している。これはオブジェクト同士の所有関係の話。
1.1.1.17! root      182:        // ホストデバイスは SCSIDevice を継承しているので target[] にホスト自身は
        !           183:        // 含めない。
1.1       root      184:        //
                    185:        // それとは別に SCSI バスと SCSI デバイスの仮想的な接続関係があり、
                    186:        // こっちはすべて所有権のないただのポインタで相互にリンクする。
                    187:        // これが scsibus->device[] と SCSIDevice::bus の相互リンク。
                    188:        //
                    189:        // こんな感じ。
                    190:        //             SCSIHostDevice
1.1.1.17! root      191:        // +----------------------+
        !           192:        // |  .scsibus            |
        !           193:        // +--- || ----+          |
        !           194:        //      ||     |SCSIDevice|
        !           195:        //  ID7 ||<----> .bus     |
        !           196:        //      ||     +----------+
        !           197:        //      ||
        !           198:        //      ||      SCSIDisk(SCSIDevice)
        !           199:        //      ||     +----------+
        !           200:        //  ID0 ||<----> .bus     |
        !           201:        //      ||     +----------+
1.1       root      202:        //
1.1.1.15  root      203:        std::unique_ptr<SCSIBus> scsibus {};
1.1.1.10  root      204: 
1.1.1.17! root      205:        // コントローラデバイス。
        !           206:        IODevice *parent {};
1.1       root      207: };
                    208: 
                    209: //
                    210: // ターゲットデバイスの共通部分。
                    211: //
                    212: class SCSITarget : public SCSIDevice
                    213: {
1.1.1.3   root      214:        using inherited = SCSIDevice;
1.1       root      215:  public:
1.1.1.17! root      216:        SCSITarget(SCSIBus *, uint id);
1.1.1.16  root      217:        ~SCSITarget() override;
1.1       root      218: 
1.1.1.12  root      219:        void ResetHard(bool poweron) override;
1.1.1.8   root      220: 
1.1.1.10  root      221:        // Inquiry データを返す (Cmd から呼ばれる)
1.1.1.17! root      222:        virtual bool Inquiry(std::vector<uint8>& buf, uint lun) = 0;
1.1       root      223: 
                    224:        // 現在のコマンド列を返す (モニタ用)
                    225:        std::vector<uint8> GetCmdSeq() const { return cmdseq; }
                    226: 
1.1.1.13  root      227:        // コマンドを選択する (ROM30 エミュレーション用)
                    228:        SCSICmd *SelectCommand(const std::vector<uint8>& cmdseq_);
                    229: 
1.1.1.2   root      230:        // 論理ブロック長
                    231:        uint32 GetBlocksize() const { return blocksize; }
                    232:        void SetBlocksize(uint32 val) { blocksize = val; }
                    233: 
1.1.1.10  root      234:        // ModeSense コマンドのデバイス固有パラメータを返す
                    235:        virtual uint8 GetDeviceSpecificParam() const { return 0; }
                    236: 
1.1.1.4   root      237:        // センスキーと ASC/ASCQ
                    238:        uint8  sensekey {};
                    239:        uint16 senseasc {};
                    240: 
                    241:        // センスキーをクリア
                    242:        void ClearSense() {
                    243:                sensekey = 0;
                    244:                senseasc = 0;
                    245:        }
                    246: 
1.1.1.17! root      247:        // SCSIBus から呼ばれる
1.1       root      248: 
1.1.1.4   root      249:        // バスリセットされた (全員に通知される)
1.1.1.17! root      250:        void OnBusReset() override;
1.1.1.4   root      251: 
1.1       root      252:        // セレクションで選択された (ターゲットのみ通知される)
1.1.1.17! root      253:        void OnSelected() override;
1.1       root      254: 
                    255:        // 情報転送フェーズを開始する (ターゲットのみ通知される)
1.1.1.17! root      256:        void OnStartTransfer() override;
1.1       root      257: 
                    258:        // 情報転送フェーズで1バイト送受信が進んだ (ターゲットのみ通知される)
1.1.1.17! root      259:        void OnTransfer() override;
1.1       root      260: 
                    261:        // 情報転送フェーズ(マニュアル転送)で ACK を下げた (ターゲットのみ通知)
1.1.1.17! root      262:        void OnTransferAck() override;
1.1       root      263: 
                    264:  protected:
1.1.1.12  root      265:        // SCSI コマンドのディスパッチャ
                    266:        virtual void DispatchCmd();
                    267: 
1.1       root      268:        // コマンド
                    269:        std::vector<uint8> cmdseq {};
1.1.1.12  root      270: 
1.1       root      271:        // このコマンドの長さ。
                    272:        // cmdseq の1バイト目で決まるやつのことで、受信目標バイト数。
                    273:        // 今何バイト受信しているかは cmdseq.size()。
1.1.1.17! root      274:        uint cmdlen {};
1.1       root      275: 
                    276:        // 現在実行中の SCSI コマンド
1.1.1.10  root      277:        std::unique_ptr<SCSICmd> cmd {};
1.1       root      278: 
                    279:        // 現在のフェーズでの転送カウント。
                    280:        // IN と OUT でカウント方向が違うことに注意。
1.1.1.5   root      281:        uint32 bytecount {};
1.1       root      282: 
                    283:        // 現在処理中のバイトが(各)フェーズの最終バイトなら true
1.1.1.5   root      284:        bool lastbyte {};
1.1       root      285: 
1.1.1.10  root      286:        // 論理ブロック長
                    287:        uint32 blocksize {};
1.1       root      288: };
                    289: 
                    290: //
1.1.1.10  root      291: // SCSI Disk (HD,CD,...)
1.1       root      292: //
1.1.1.10  root      293: class SCSIDisk : public SCSITarget
1.1       root      294: {
1.1.1.3   root      295:        using inherited = SCSITarget;
1.1       root      296:  public:
1.1.1.10  root      297:        // メディアへの書き込みモード
                    298:        //
                    299:        // Device       Media   Ignore
                    300:        // RO           (RO)    *               ReadOnly
                    301:        // RW           RO              *               WriteProtect
                    302:        // RW           RW              no              Writeable
                    303:        // RW           RW              yes             WriteIgnore
                    304:        enum class RW {
                    305:                ReadOnly                = 2,    // 読み込み専用デバイス
                    306:                WriteProtect    = 1,    // 書き込み禁止メディア
                    307:                Writeable               = 0,    // 書き込み可能
                    308:                WriteIgnore             = -1,   // 書き込み可能メディアで書き込みを無視
                    309:        };
                    310: 
                    311:  public:
1.1.1.17! root      312:        SCSIDisk(SCSIBus *, uint id, SCSI::DevType type);
1.1.1.16  root      313:        ~SCSIDisk() override;
1.1       root      314: 
1.1.1.3   root      315:        bool Init() override;
1.1.1.12  root      316:        void ResetHard(bool poweron) override;
1.1.1.10  root      317: 
1.1.1.3   root      318:        void DispatchCmd() override;
1.1.1.17! root      319:        bool Inquiry(std::vector<uint8>& buf, uint lun) override;
1.1.1.10  root      320: 
                    321:        // ModeSense コマンドのデバイス固有パラメータを返す
                    322:        uint8 GetDeviceSpecificParam() const override;
                    323: 
                    324:        // buf にデータを読み込む。
                    325:        // 単位はセクタではなくバイトなことに注意。
                    326:        bool Read(std::vector<uint8>& buf, uint64 start);
                    327: 
                    328:        // buf のデータを書き込む。
                    329:        // 単位はセクタではなくバイトなことに注意。
                    330:        bool Write(const std::vector<uint8>& buf, uint64 start);
1.1       root      331: 
1.1.1.10  root      332:        // このデバイスのバイトサイズ
                    333:        off_t GetSize() const;
                    334: 
                    335:        // このデバイスをディスクイメージだと思うとして (いや実際そうだけど)
1.1.1.2   root      336:        // 先頭から start バイト目から len バイト読み出して返す。
                    337:        // 単位はセクタではなくバイトなことに注意。
                    338:        // (エミュレータ特権アクセス)
1.1.1.10  root      339:        bool Peek(void *buf, uint64 start, uint32 len) const;
                    340: 
                    341:        // シーク時間[nsec]
                    342:        uint64 GetSeekTime() const { return seektime; }
                    343: 
                    344:        // リムーバブルデバイスなら true
                    345:        bool IsRemovableDevice() const { return removable_device; }
                    346: 
                    347:        // 書き込み可能デバイスなら true
                    348:        bool IsWriteableDevice() const { return writeable_device; }
                    349: 
                    350:        // メディアが入っていれば true
                    351:        bool IsMediumLoaded() const { return medium_loaded; }
1.1.1.2   root      352: 
1.1.1.10  root      353:        // メディアの書き込みモードを返す
                    354:        RW GetWriteMode() const { return write_mode; }
1.1.1.12  root      355:        // メディアの書き込みモードを文字列で返す (モニタ用)
                    356:        const char *GetWriteModeStr() const;
1.1.1.5   root      357: 
1.1.1.10  root      358:        // メディア(ディスク)イメージを開く/閉じる。(同一スレッドから呼ぶこと)
                    359:        bool LoadDisk(const std::string& path_);
                    360:        void UnloadDisk(bool force = false);
                    361: 
                    362:        // メディア(ディスク)イメージを開く/閉じる。(UI スレッドから呼ぶ)
                    363:        void LoadDiskUI(const std::string& path_);
                    364:        void UnloadDiskUI(bool force);
                    365: 
                    366:        // メディアの取り出し可否
                    367:        bool IsMediumRemovalPrevented() const { return medium_removal_prevented; }
                    368:        bool IsMediumRemovalAllowed() const  { return !medium_removal_prevented; }
                    369:        void PreventMediumRemoval(bool val);
                    370: 
                    371:        // イメージファイルのフルパスを返す
                    372:        const std::string& GetPathName() const { return pathname; }
                    373: 
1.1.1.17! root      374:        // SCSIBus から呼ばれる
1.1.1.10  root      375: 
                    376:        // バスリセットされた (全員に通知される)
1.1.1.17! root      377:        void OnBusReset() override;
1.1.1.9   root      378: 
1.1       root      379:  private:
1.1.1.10  root      380:        // ディスクイメージを閉じる (内部用)
                    381:        bool UnloadDisk_internal();
                    382: 
                    383:        // ディスク状態をクリアする
                    384:        void Clear();
                    385: 
                    386:        // メディア状態変更を UI に通知する
                    387:        void MediaChanged() const;
                    388: 
                    389:        // メディア挿入/排出コールバック
1.1.1.16  root      390:        void LoadMessage(MessageID, uint32);
                    391:        void UnloadMessage(MessageID, uint32);
1.1.1.10  root      392: 
                    393:        // イメージファイルのフルパス
                    394:        std::string pathname {};
                    395:        // 新しいイメージファイルのフルパス (UIから)
                    396:        std::string new_pathname {};
                    397: 
                    398:        // イメージファイル
1.1.1.11  root      399:        DiskImage image {};
1.1.1.10  root      400: 
                    401:        bool removable_device {};       // リムーバブルデバイスなら true
                    402:        bool writeable_device {};       // 書き込み可能なデバイスなら true
                    403:        bool write_ignore {};           // 書き込み無視オプション
                    404:        bool medium_loaded {};          // メディアが挿入されていれば true
                    405: 
                    406:        // メディアの書き込みモード
                    407:        RW write_mode {};
                    408: 
                    409:        // メディアの取り出しを禁止するなら true。
                    410:        // XXX Bus Device Reset メッセージでも解除できるがメッセージは未実装
                    411:        bool medium_removal_prevented {};
                    412: 
1.1.1.5   root      413:        uint64 seektime {};
1.1       root      414: };

unix.superglobalmegacorp.com

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