--- nono/vm/scsidev.h 2026/04/29 17:04:45 1.1.1.6 +++ nono/vm/scsidev.h 2026/04/29 17:04:59 1.1.1.10 @@ -8,8 +8,9 @@ #pragma once -#include "mappedfile.h" +#include "diskimage.h" #include "scsibus.h" +#include "scsicmd.h" // IODevice (SPCDevice の親になるため) // | @@ -21,9 +22,7 @@ // SCSIHostDevice SCSITarget (SCSI ホスト/ターゲットとしての共通部分) // | | // v v -// SPCDevice SCSIHD (各デバイス、各ターゲット固有部分) - -class SCSICmd; +// SPCDevice SCSIDisk (各デバイス、各ターゲット固有部分) // // SCSI デバイスとしての共通部分。 @@ -31,8 +30,9 @@ class SCSICmd; // class SCSIDevice : public IODevice { + using inherited = IODevice; public: - SCSIDevice(); + SCSIDevice(const std::string& objname_); virtual ~SCSIDevice() override; // バスに接続 (SCSIBus::Attach から呼ばれる) @@ -123,8 +123,9 @@ class SCSIDevice : public IODevice // class SCSIHostDevice : public SCSIDevice { + using inherited = SCSIDevice; public: - SCSIHostDevice(); + SCSIHostDevice(const std::string& objname_); virtual ~SCSIHostDevice() override; bool Create() override; @@ -136,10 +137,20 @@ class SCSIHostDevice : public SCSIDevice // バスフリーになった (全員に通知される) void BusFreeCB(int id) override; - // ターゲットデバイス取得 (ROM エミュレーション用) + // ターゲットデバイス取得 (ROM エミュレーション/UI用) SCSITarget *GetTarget(int id) const { return target[id].get(); } + // 接続中のデバイスを ID 順に並べたリストを返す (UI ステータスパネル用) + const std::vector& GetConnectedDevices() const { + return connected_devices; + } + + // SCSIBus を取得 (UI からインジケータ表示用) + std::shared_ptr GetSCSIBus() const { return scsibus; } + protected: + DECLARE_MONITOR_CALLBACK(MonitorUpdateDevs); + // 設定ファイルに使われるこのホストデバイスを示す接頭語を設定する // (ここで設定項目を Add するので、継承クラスのコンストラクタから呼ぶこと) void SetConfigName(const char *name); @@ -168,13 +179,19 @@ class SCSIHostDevice : public SCSIDevice // ID7 ||<----> bus | | // || +----------+ | // || | - // || SCSIHD(SCSIDevice) | + // || SCSIDisk(SCSIDevice) | // || +----------+ | // ID0 ||<----> bus |<----------+ // || +----------+ own // - std::unique_ptr scsibus {}; + std::shared_ptr scsibus {}; std::unique_ptr target[8] {}; + + // 接続中のデバイス(イニシエータ含む)を ID 順に並べたリスト (モニタ用) + // (継承クラスの Init() で初期化している) + std::vector connected_devices {}; + + Monitor monitor_devs { this }; }; // @@ -183,13 +200,14 @@ class SCSIHostDevice : public SCSIDevice class SCSITarget : public SCSIDevice { using inherited = SCSIDevice; - friend class SCSICmdModeSelect6; public: - SCSITarget(SCSIHostDevice *h, int id, std::vector& inq); + SCSITarget(const std::string& objname_, SCSIHostDevice *h, int id); virtual ~SCSITarget() override; - // Inquiry 応答データ - std::vector inquiry_data {}; + bool PowerOn() override; + + // Inquiry データを返す (Cmd から呼ばれる) + virtual bool Inquiry(std::vector& buf, int lun) = 0; // 現在のコマンド列を返す (モニタ用) std::vector GetCmdSeq() const { return cmdseq; } @@ -198,6 +216,9 @@ class SCSITarget : public SCSIDevice uint32 GetBlocksize() const { return blocksize; } void SetBlocksize(uint32 val) { blocksize = val; } + // ModeSense コマンドのデバイス固有パラメータを返す + virtual uint8 GetDeviceSpecificParam() const { return 0; } + // センスキーと ASC/ASCQ uint8 sensekey {}; uint16 senseasc {}; @@ -240,9 +261,7 @@ class SCSITarget : public SCSIDevice virtual void DispatchCmd(); // 現在実行中の SCSI コマンド - // SCSICmd は *.cpp のみで完結していて宣言がヘッダにないので - // 一様初期化構文 {} が使えない。 - std::unique_ptr cmd; + std::unique_ptr cmd {}; // 現在のフェーズでの転送カウント。 // IN と OUT でカウント方向が違うことに注意。 @@ -251,42 +270,134 @@ class SCSITarget : public SCSIDevice // 現在処理中のバイトが(各)フェーズの最終バイトなら true bool lastbyte {}; - // 論理ブロック長 (ModeSelect コマンドでホストから指定される) - // XXX: LUNA88K で ROM がたぶんやる。。。 - uint32 blocksize = 512; + // 論理ブロック長 + uint32 blocksize {}; }; // -// SCSI HD +// SCSI Disk (HD,CD,...) // -class SCSIHD : public SCSITarget +class SCSIDisk : public SCSITarget { using inherited = SCSITarget; - friend class SCSICmdRead6; - friend class SCSICmdWrite6; - friend class SCSICmdReadCapacity; - friend class SCSICmdRead10; public: - SCSIHD(SCSIHostDevice *h, int id); - virtual ~SCSIHD() override; + // メディアへの書き込みモード + // + // Device Media Ignore + // RO (RO) * ReadOnly + // RW RO * WriteProtect + // RW RW no Writeable + // RW RW yes WriteIgnore + enum class RW { + ReadOnly = 2, // 読み込み専用デバイス + WriteProtect = 1, // 書き込み禁止メディア + Writeable = 0, // 書き込み可能 + WriteIgnore = -1, // 書き込み可能メディアで書き込みを無視 + }; + + public: + SCSIDisk(SCSIHostDevice *h, int id, SCSI::DevType type); + virtual ~SCSIDisk() override; bool Init() override; + bool PowerOn() override; + void DispatchCmd() override; + bool Inquiry(std::vector& buf, int lun) override; + + // ModeSense コマンドのデバイス固有パラメータを返す + uint8 GetDeviceSpecificParam() const override; + + // buf にデータを読み込む。 + // 単位はセクタではなくバイトなことに注意。 + bool Read(std::vector& buf, uint64 start); + + // buf のデータを書き込む。 + // 単位はセクタではなくバイトなことに注意。 + bool Write(const std::vector& buf, uint64 start); + + // このデバイスのバイトサイズ + off_t GetSize() const; - // このディスクをディスクイメージだと思うとして (いや実際そうだけど) + // このデバイスをディスクイメージだと思うとして (いや実際そうだけど) // 先頭から start バイト目から len バイト読み出して返す。 // 単位はセクタではなくバイトなことに注意。 // (エミュレータ特権アクセス) - bool PeekImage(void *buf, uint32 start, uint32 len) const; + bool Peek(void *buf, uint64 start, uint32 len) const; + + // シーク時間[nsec] + uint64 GetSeekTime() const { return seektime; } + + // リムーバブルデバイスなら true + bool IsRemovableDevice() const { return removable_device; } + + // 書き込み可能デバイスなら true + bool IsWriteableDevice() const { return writeable_device; } + + // メディアが入っていれば true + bool IsMediumLoaded() const { return medium_loaded; } + + // メディアの書き込みモードを返す + RW GetWriteMode() const { return write_mode; } + + // メディア(ディスク)イメージを開く/閉じる。(同一スレッドから呼ぶこと) + bool LoadDisk(const std::string& path_); + void UnloadDisk(bool force = false); + + // メディア(ディスク)イメージを開く/閉じる。(UI スレッドから呼ぶ) + void LoadDiskUI(const std::string& path_); + void UnloadDiskUI(bool force); + + // メディアの取り出し可否 + bool IsMediumRemovalPrevented() const { return medium_removal_prevented; } + bool IsMediumRemovalAllowed() const { return !medium_removal_prevented; } + void PreventMediumRemoval(bool val); - // ディスクイメージ長を取得 - off_t GetSize() const { return file.GetMemSize(); } + // イメージファイルのフルパスを返す + const std::string& GetPathName() const { return pathname; } + + // SCSIBus コールバック + + // バスリセットされた (全員に通知される) + void BusResetCB() override; private: - MappedFile file {}; - uint8 *mem {}; - bool writeprotect {}; + // ディスクイメージを閉じる (内部用) + bool UnloadDisk_internal(); + + // ディスク状態をクリアする + void Clear(); + + // メディア状態変更を UI に通知する + void MediaChanged() const; + + // メディア挿入/排出コールバック + void LoadCallback(Event&); + void UnloadCallback(Event&); + + // イメージファイルのフルパス + std::string pathname {}; + // 新しいイメージファイルのフルパス (UIから) + std::string new_pathname {}; + + // イメージファイル + std::unique_ptr image {}; + + bool removable_device {}; // リムーバブルデバイスなら true + bool writeable_device {}; // 書き込み可能なデバイスなら true + bool write_ignore {}; // 書き込み無視オプション + bool medium_loaded {}; // メディアが挿入されていれば true + + // メディアの書き込みモード + RW write_mode {}; + + // メディアの取り出しを禁止するなら true。 + // XXX Bus Device Reset メッセージでも解除できるがメッセージは未実装 + bool medium_removal_prevented {}; + uint64 seektime {}; - static std::vector inquiry_data; + // UI からの指示を受け取るイベント + // (リムーバブルデバイスでのみ作成するので、ポインタ) + Event *event {}; };