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

unix.superglobalmegacorp.com

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