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

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

unix.superglobalmegacorp.com

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