--- nono/vm/scsidev.h 2026/04/29 17:05:11 1.1.1.12 +++ nono/vm/scsidev.h 2026/04/29 17:05:30 1.1.1.17 @@ -8,49 +8,48 @@ // SCSI デバイス // -// IODevice (SPCDevice の親になるため) -// | -// v -// SCSIDevice (SCSI デバイスとしての共通部分) -// | -// +------+---------+ -// v v -// SCSIHostDevice SCSITarget (SCSI ホスト/ターゲットとしての共通部分) -// | | -// v v -// SPCDevice SCSIDisk (各デバイス、各ターゲット固有部分) +// Device Device +// | | +// v v +// IODevice SCSIDevice (SCSI デバイスとしての共通部分) +// | | +// v +-----+------+ +// SPCDevice v v +// .scsi -> SCSIHostDevice SCSITarget (SCSI ホスト/ターゲットの共通部分) +// | +// v +// SCSIDisk (各デバイス、各ターゲット固有部分) #pragma once #include "diskimage.h" #include "message.h" -#include "monitor.h" #include "scsibus.h" #include "scsicmd.h" // // SCSI デバイスとしての共通部分。 -// これ自体は IODevice ではないが SCSI ホストアダプタがこれを継承するため。 // -class SCSIDevice : public IODevice +class SCSIDevice : public Device { - using inherited = IODevice; + using inherited = Device; public: - SCSIDevice(const std::string& objname_); - virtual ~SCSIDevice() override; + explicit SCSIDevice(uint objid_); + ~SCSIDevice() override; - // バスに接続 (SCSIBus::Attach から呼ばれる) - void Attach(SCSIBus *bus_, int id) { - bus = bus_; - myid = id; - } + // バスに接続された (SCSIBus から呼ばれる) + void OnAttached(SCSIBus *bus_, uint myid_); // SCSI ID を返す - int GetMyID() const { return myid; } + uint GetMyID() const { return myid; } // デバイス種別を返す (主にデバッグ表示用) SCSI::DevType GetDevType() const { return devtype; } + // 自身が接続しているバスを返す。 + // イニシエータがバスに接続するのは VM 実行後なことに注意。 + SCSIBus *GetBus() const { return bus; } + // // 信号線制御 // (ソースコード的なショートカットのため) @@ -83,32 +82,32 @@ class SCSIDevice : public IODevice void SetData(uint8 val) const { bus->SetData(val); } // - // SCSIBus コールバック + // SCSIBus から呼ばれる // // バスリセットされた (全員に通知される) - virtual void BusResetCB() { } + virtual void OnBusReset() { } // バスフリーになった (全員に通知される) - virtual void BusFreeCB(int id) { } + virtual void OnBusFree(uint id) { } // セレクションで選択された (ターゲットのみ通知される) - virtual void SelectionCB() { } + virtual void OnSelected() { } // ターゲットがセレクションに応答した (イニシエータのみ通知される) - virtual void SelectionAckCB() { } + virtual void OnSelectionAck() { } // 情報転送フェーズを開始する (ターゲットのみ通知される) - virtual void StartTransferCB() { } + virtual void OnStartTransfer() { } // 情報転送フェーズで REQ を立てた (イニシエータのみ通知される) - virtual void TransferReqCB() { } + virtual void OnTransferReq() { } // 情報転送フェーズで1バイト送受信が進んだ (ターゲットのみ通知される) - virtual void TransferCB() { } + virtual void OnTransfer() { } // 情報転送フェーズ(マニュアル転送)で ACK を下げた (ターゲットのみ通知) - virtual void TransferAckCB() { } + virtual void OnTransferAck() { } protected: // 自身の ID @@ -124,51 +123,64 @@ class SCSIDevice : public IODevice // // ホストデバイスの共通部分。 +// イニシエータもしくは HBA (ホストバスアダプタ) に相当する部分。 // class SCSIHostDevice : public SCSIDevice { using inherited = SCSIDevice; + public: - SCSIHostDevice(const std::string& objname_); - virtual ~SCSIHostDevice() override; + using SCSIHostCallback_t = void (Device::*)(); + using BusFreeCallback_t = void (Device::*)(uint); +#define ToSCSIHostCallback(f) \ + static_cast(f) +#define ToBusFreeCallback(f) \ + static_cast(f) + + public: + SCSIHostDevice(IODevice *parent_, const char *config_name_); + ~SCSIHostDevice() override; - bool Create() override; bool Init() override; - // 設定ファイル上のこのホストデバイスを示す接頭語を返す - const char *GetConfigName() const { return config_name; } + // コールバック関数を設定する。 + void SetCallback( + BusFreeCallback_t busfree_, + SCSIHostCallback_t selack_, + SCSIHostCallback_t xferreq_); - // バスフリーになった (全員に通知される) - void BusFreeCB(int id) override; + // 所有している SCSIBus ポインタを返す。こっちは接続前でも使える。 + SCSIBus *GetOwnedBus() const { return scsibus.get(); } - // ターゲットデバイス取得 (ROM エミュレーション/UI用) - SCSITarget *GetTarget(int id) const { return target[id].get(); } + // ターゲットデバイスを返す。(ショートカット) + SCSITarget *GetTarget(uint id) const { return scsibus->GetTarget(id); } - // 接続中のデバイスを ID 順に並べたリストを返す (UI ステータスパネル用) - const std::vector& GetConnectedDevices() const { - return connected_devices; - } + private: + // SCSIBus から呼ばれる - // SCSIBus を取得 (UI からインジケータ表示用) - std::shared_ptr GetSCSIBus() const { return scsibus; } + // バスフリーになった (SCSIBus から全員に通知される) + void OnBusFree(uint id) override; + // ターゲットがセレクションに応答した (SCSIBus から呼ばれる) + void OnSelectionAck() override; + // 情報転送フェーズで REQ を立てた (イニシエータのみ通知される) + void OnTransferReq() override; - protected: - DECLARE_MONITOR_CALLBACK(MonitorUpdateDevs); + // 親クラス(コントローラ) へのコールバック。 - // 設定ファイルに使われるこのホストデバイスを示す接頭語を設定する - // (ここで設定項目を Add するので、継承クラスのコンストラクタから呼ぶこと) - void SetConfigName(const char *name); - - // 設定ファイルに使われるこのホストデバイスを示す接頭語。 - // ("spc0" とか) - const char *config_name {}; + // バスフリーを通知する + BusFreeCallback_t BusFreeCallback {}; + // ターゲットがセレクションに応答したことを通知する + SCSIHostCallback_t SelectionAckCallback {}; + // 転送フェーズでターゲットが REQ を立てたことを通知する + SCSIHostCallback_t TransferReqCallback {}; // SCSI バス (とターゲットオブジェクト) // // ホストデバイスなのでバスオブジェクト(SCSIBus *scsibus)と、このバスに // 繋がるターゲットデバイスのオブジェクト(SCSITarget *target[]) を所有 // (unique_ptr) している。これはオブジェクト同士の所有関係の話。 - // ホストは SCSIDevice を継承しているので target[] にホスト自身は含めない。 + // ホストデバイスは SCSIDevice を継承しているので target[] にホスト自身は + // 含めない。 // // それとは別に SCSI バスと SCSI デバイスの仮想的な接続関係があり、 // こっちはすべて所有権のないただのポインタで相互にリンクする。 @@ -176,26 +188,22 @@ class SCSIHostDevice : public SCSIDevice // // こんな感じ。 // SCSIHostDevice - // +-------------------------------------+ - // | scsibus target[0] | - // +--- || ----+ +---------- | -+ - // || |SCSIDevice| | - // ID7 ||<----> bus | | - // || +----------+ | - // || | - // || SCSIDisk(SCSIDevice) | - // || +----------+ | - // ID0 ||<----> bus |<----------+ - // || +----------+ own + // +----------------------+ + // | .scsibus | + // +--- || ----+ | + // || |SCSIDevice| + // ID7 ||<----> .bus | + // || +----------+ + // || + // || SCSIDisk(SCSIDevice) + // || +----------+ + // ID0 ||<----> .bus | + // || +----------+ // - std::shared_ptr scsibus {}; - std::unique_ptr target[8] {}; + std::unique_ptr scsibus {}; - // 接続中のデバイス(イニシエータ含む)を ID 順に並べたリスト (モニタ用) - // (継承クラスの Init() で初期化している) - std::vector connected_devices {}; - - Monitor monitor_devs { this }; + // コントローラデバイス。 + IODevice *parent {}; }; // @@ -205,17 +213,20 @@ class SCSITarget : public SCSIDevice { using inherited = SCSIDevice; public: - SCSITarget(const std::string& objname_, SCSIHostDevice *h, int id); - virtual ~SCSITarget() override; + SCSITarget(SCSIBus *, uint id); + ~SCSITarget() override; void ResetHard(bool poweron) override; // Inquiry データを返す (Cmd から呼ばれる) - virtual bool Inquiry(std::vector& buf, int lun) = 0; + virtual bool Inquiry(std::vector& buf, uint lun) = 0; // 現在のコマンド列を返す (モニタ用) std::vector GetCmdSeq() const { return cmdseq; } + // コマンドを選択する (ROM30 エミュレーション用) + SCSICmd *SelectCommand(const std::vector& cmdseq_); + // 論理ブロック長 uint32 GetBlocksize() const { return blocksize; } void SetBlocksize(uint32 val) { blocksize = val; } @@ -233,37 +244,34 @@ class SCSITarget : public SCSIDevice senseasc = 0; } - // SCSIBus コールバック + // SCSIBus から呼ばれる // バスリセットされた (全員に通知される) - void BusResetCB() override; + void OnBusReset() override; // セレクションで選択された (ターゲットのみ通知される) - void SelectionCB() override; + void OnSelected() override; // 情報転送フェーズを開始する (ターゲットのみ通知される) - void StartTransferCB() override; + void OnStartTransfer() override; // 情報転送フェーズで1バイト送受信が進んだ (ターゲットのみ通知される) - void TransferCB() override; + void OnTransfer() override; // 情報転送フェーズ(マニュアル転送)で ACK を下げた (ターゲットのみ通知) - void TransferAckCB() override; + void OnTransferAck() override; protected: // SCSI コマンドのディスパッチャ virtual void DispatchCmd(); - // ホスト - SCSIHostDevice *host {}; - // コマンド std::vector cmdseq {}; // このコマンドの長さ。 // cmdseq の1バイト目で決まるやつのことで、受信目標バイト数。 // 今何バイト受信しているかは cmdseq.size()。 - int cmdlen {}; + uint cmdlen {}; // 現在実行中の SCSI コマンド std::unique_ptr cmd {}; @@ -301,14 +309,14 @@ class SCSIDisk : public SCSITarget }; public: - SCSIDisk(SCSIHostDevice *h, int id, SCSI::DevType type); - virtual ~SCSIDisk() override; + SCSIDisk(SCSIBus *, uint id, SCSI::DevType type); + ~SCSIDisk() override; bool Init() override; void ResetHard(bool poweron) override; void DispatchCmd() override; - bool Inquiry(std::vector& buf, int lun) override; + bool Inquiry(std::vector& buf, uint lun) override; // ModeSense コマンドのデバイス固有パラメータを返す uint8 GetDeviceSpecificParam() const override; @@ -363,10 +371,10 @@ class SCSIDisk : public SCSITarget // イメージファイルのフルパスを返す const std::string& GetPathName() const { return pathname; } - // SCSIBus コールバック + // SCSIBus から呼ばれる // バスリセットされた (全員に通知される) - void BusResetCB() override; + void OnBusReset() override; private: // ディスクイメージを閉じる (内部用) @@ -379,8 +387,8 @@ class SCSIDisk : public SCSITarget void MediaChanged() const; // メディア挿入/排出コールバック - void LoadCallback(MessageID, uint32); - void UnloadCallback(MessageID, uint32); + void LoadMessage(MessageID, uint32); + void UnloadMessage(MessageID, uint32); // イメージファイルのフルパス std::string pathname {};