--- nono/vm/scsidev.h 2026/04/29 17:04:29 1.1.1.1 +++ nono/vm/scsidev.h 2026/04/29 17:04:56 1.1.1.9 @@ -1,12 +1,14 @@ // // nono -// Copyright (C) 2020 isaki@NetBSD.org +// Copyright (C) 2020 nono project +// Licensed under nono-license.txt // // SCSI デバイス共通部分 #pragma once +#include "mappedfile.h" #include "scsibus.h" // IODevice (SPCDevice の親になるため) @@ -29,9 +31,10 @@ class SCSICmd; // class SCSIDevice : public IODevice { + using inherited = IODevice; public: - SCSIDevice(); - virtual ~SCSIDevice(); + SCSIDevice(const std::string& objname_); + virtual ~SCSIDevice() override; // バスに接続 (SCSIBus::Attach から呼ばれる) void Attach(SCSIBus *bus_, int id) { @@ -39,6 +42,12 @@ class SCSIDevice : public IODevice myid = id; } + // SCSI ID を返す + int GetMyID() const { return myid; } + + // デバイス種別を返す (主にデバッグ表示用) + SCSI::DevType GetDevType() const { return devtype; } + // // 信号線制御 // (ソースコード的なショートカットのため) @@ -100,11 +109,14 @@ class SCSIDevice : public IODevice protected: // 自身の ID - uint myid; + uint myid {}; + + // デバイス種別 + SCSI::DevType devtype {}; // 自身が繋がっているバスへのポインタ。 // (イニシエータ自身も含めて) 所有していない。 - SCSIBus *bus; + SCSIBus *bus {}; }; // @@ -112,23 +124,34 @@ class SCSIDevice : public IODevice // class SCSIHostDevice : public SCSIDevice { + using inherited = SCSIDevice; public: - SCSIHostDevice(); - virtual ~SCSIHostDevice(); + SCSIHostDevice(const std::string& objname_); + virtual ~SCSIHostDevice() override; - virtual bool Create(); - virtual bool Init(); + bool Create() override; + bool Init() override; // 設定ファイル上のこのホストデバイスを示す接頭語を返す const char *GetConfigName() const { return config_name; } // バスフリーになった (全員に通知される) - virtual void BusFreeCB(int id); + void BusFreeCB(int id) override; + + // ターゲットデバイス取得 (ROM エミュレーション用) + SCSITarget *GetTarget(int id) const { return target[id].get(); } + + // SCSIBus を取得 (UI からインジケータ表示用) + std::shared_ptr GetSCSIBus() const { return scsibus; } protected: + // 設定ファイルに使われるこのホストデバイスを示す接頭語を設定する + // (ここで設定項目を Add するので、継承クラスのコンストラクタから呼ぶこと) + void SetConfigName(const char *name); + // 設定ファイルに使われるこのホストデバイスを示す接頭語。 // ("spc0" とか) - const char *config_name = NULL; + const char *config_name {}; // SCSI バス (とターゲットオブジェクト) // @@ -155,8 +178,8 @@ class SCSIHostDevice : public SCSIDevice // ID0 ||<----> bus |<----------+ // || +----------+ own // - std::unique_ptr scsibus; - std::unique_ptr target[8]; + std::shared_ptr scsibus {}; + std::unique_ptr target[8] {}; }; // @@ -164,60 +187,77 @@ class SCSIHostDevice : public SCSIDevice // class SCSITarget : public SCSIDevice { - typedef SCSIDevice inherited; + using inherited = SCSIDevice; friend class SCSICmdModeSelect6; public: - SCSITarget(SCSIHostDevice *h, int id, std::vector& inq); - virtual ~SCSITarget(); + SCSITarget(const std::string& objname_, + SCSIHostDevice *h, int id, std::vector& inq); + virtual ~SCSITarget() override; - // デバイス種別を返す (主にデバッグ表示用) - SCSI::DevType GetDevType() const { return devtype; } + bool PowerOn() override; // Inquiry 応答データ - std::vector inquiry_data; + std::vector inquiry_data {}; // 現在のコマンド列を返す (モニタ用) std::vector GetCmdSeq() const { return cmdseq; } + // 論理ブロック長 + uint32 GetBlocksize() const { return blocksize; } + void SetBlocksize(uint32 val) { blocksize = val; } + + // センスキーと ASC/ASCQ + uint8 sensekey {}; + uint16 senseasc {}; + + // センスキーをクリア + void ClearSense() { + sensekey = 0; + senseasc = 0; + } + // SCSIBus コールバック + // バスリセットされた (全員に通知される) + void BusResetCB() override; + // セレクションで選択された (ターゲットのみ通知される) - virtual void SelectionCB(); + void SelectionCB() override; // 情報転送フェーズを開始する (ターゲットのみ通知される) - virtual void StartTransferCB(); + void StartTransferCB() override; // 情報転送フェーズで1バイト送受信が進んだ (ターゲットのみ通知される) - virtual void TransferCB(); + void TransferCB() override; // 情報転送フェーズ(マニュアル転送)で ACK を下げた (ターゲットのみ通知) - virtual void TransferAckCB(); + void TransferAckCB() override; protected: - // デバイス種別 - SCSI::DevType devtype; // ホスト - SCSIHostDevice *host; + SCSIHostDevice *host {}; // コマンド std::vector cmdseq {}; // このコマンドの長さ。 // cmdseq の1バイト目で決まるやつのことで、受信目標バイト数。 // 今何バイト受信しているかは cmdseq.size()。 - int cmdlen; + int cmdlen {}; // SCSI コマンドのディスパッチャ virtual void DispatchCmd(); // 現在実行中の SCSI コマンド + // SCSICmd は *.cpp のみで完結していて宣言がヘッダにないので + // 一様初期化構文 {} が使えない。 std::unique_ptr cmd; // 現在のフェーズでの転送カウント。 // IN と OUT でカウント方向が違うことに注意。 - uint32 bytecount = 0; + uint32 bytecount {}; // 現在処理中のバイトが(各)フェーズの最終バイトなら true - bool lastbyte = false; + bool lastbyte {}; // 論理ブロック長 (ModeSelect コマンドでホストから指定される) // XXX: LUNA88K で ROM がたぶんやる。。。 @@ -229,23 +269,36 @@ class SCSITarget : public SCSIDevice // class SCSIHD : public SCSITarget { - typedef SCSITarget inherited; + using inherited = SCSITarget; friend class SCSICmdRead6; friend class SCSICmdWrite6; friend class SCSICmdReadCapacity; friend class SCSICmdRead10; + friend class SCSICmdWrite10; public: SCSIHD(SCSIHostDevice *h, int id); - virtual ~SCSIHD(); + virtual ~SCSIHD() override; - virtual bool Init(); - virtual void DispatchCmd(); + bool Init() override; + void DispatchCmd() override; + + // このディスクをディスクイメージだと思うとして (いや実際そうだけど) + // 先頭から start バイト目から len バイト読み出して返す。 + // 単位はセクタではなくバイトなことに注意。 + // (エミュレータ特権アクセス) + bool PeekImage(void *buf, uint32 start, uint32 len) const; + + // ディスクイメージ長を取得 + off_t GetSize() const { return file.GetMemSize(); } + + // デバイスがライトプロテクトかどうかを返す + bool GetWriteProtect() const { return writeprotect; } private: - int fd = 0; - uint8 *mem = NULL; - size_t memlen = 0; - bool writeprotect = false; + MappedFile file {}; + uint8 *mem {}; + bool writeprotect {}; + uint64 seektime {}; static std::vector inquiry_data; };