--- nono/vm/scsi.h 2026/04/29 17:04:28 1.1 +++ nono/vm/scsi.h 2026/04/29 17:05:41 1.1.1.10 @@ -1,40 +1,77 @@ // // nono -// Copyright (C) 2018 isaki@NetBSD.org +// Copyright (C) 2020 nono project +// Licensed under nono-license.txt +// + +// +// SCSI (定数等) // #pragma once #include "device.h" +// このクラスは SCSI プロトコル上の定数などだけを持つ。 class SCSI { public: - // デバイス種別 - enum DevType { - None = 0, - HD = 1, + enum { + IO = 0x01, + CD = 0x02, + MSG = 0x04, + BSY = 0x08, + SEL = 0x10, + }; + + // SCSI のフェーズを表す。 + // フェーズは概ね BSY と SEL の状態遷移によって決まる。 + // 情報転送フェーズの内訳は XferPhase 側で区別する。 + enum Phase { + BusFree = 0, + Arbitration = 1, + Selection = 2, + Reselection = 3, + Transfer = 4, + }; + + // 情報転送フェーズを表す。 + // この値は MSG,CD,IO で表現できる値をそのまま流用して表現する。 + enum XferPhase { // MSG CD IO + DataOut = 0, // 0 0 0 + DataIn = 1, // 0 0 1 + Command = 2, // 0 1 0 + Status = 3, // 0 1 1 + MsgOut = 6, // 1 1 0 + MsgIn = 7, // 1 1 1 + + End = -1, // SCSICmd 内でフェーズ遷移を表現するために使う }; - // フェーズは、バスフェーズと転送フェーズを一緒くたで扱う。 - // 0から7までは転送フェーズを表しているのでこの順序を守ること。 - // 8以上はバスフェーズを表している。 - struct Phase { // MSG CD IO - static const uint DataOut = 0x00; // 0 0 0 - static const uint DataIn = 0x01; // 0 0 1 - static const uint Command = 0x02; // 0 1 0 - static const uint Status = 0x03; // 0 1 1 - static const uint MsgOut = 0x06; // 1 1 0 - static const uint MsgIn = 0x07; // 1 1 1 - - static const uint BusFree = 8; - static const uint Arbitration = 9; - static const uint Selection = 10; - static const uint Reselection = 11; + // フェーズ文字列を返す + static const char *GetPhaseName(Phase phase); + static const char *GetPhaseName(int phase) { + return GetPhaseName((Phase)phase); + } + + // 情報転送フェーズ文字列を返す + static const char *GetXferPhaseName(XferPhase xfer); + static const char *GetXferPhaseName(int xfer) { + return GetXferPhaseName((XferPhase)xfer); + } - static const uint MAX = 12; // 最大値 +1 にすること + // デバイス種別 + enum class DevType { + None = 0, + Initiator, + HD, + CD, + MO, }; + // デバイス種別文字列を返す + static const char *GetDevTypeName(DevType type); + // コマンド。 // ダイレクトアクセスデバイスのコマンドを元にしている。 // シーケンシャルアクセスデバイスでは 0x01 が Rewind だったり @@ -60,7 +97,9 @@ class SCSI static const uint SendDiagnostic = 0x1d; // 共通 static const uint PreventAllowMediumRemoval = 0x1e; // Group1 - static const uint ReadCapacity = 0x25; + static const uint ReadFormatCapacities = 0x23; + static const uint ReadCapacity = 0x25; // Direct Access + static const uint ReadCDROMCapacity = 0x25; // CD-ROM static const uint Read10 = 0x28; static const uint Write10 = 0x2a; static const uint Seek10 = 0x2b; @@ -84,12 +123,19 @@ class SCSI // Group2 static const uint ChangeDefinition = 0x40; static const uint WriteSame = 0x41; + static const uint ReadTOC = 0x43; // CD-ROM + static const uint ReadHeader = 0x44; // CD-ROM static const uint LogSelect = 0x4c; // 共通 static const uint LogSense = 0x4d; // 共通 + static const uint ReadDiscInformation = 0x51; // ? static const uint ModeSelect10 = 0x55; // 共通 static const uint ModeSense10 = 0x5a; // 共通 - static const uint MAX = 0x5b; // 最大値+1にすること + + // SCSI-3(?) + static const uint ReportLUNs = 0xa0; }; + // SCSI コマンド名を返す + static const char *GetCommandName(uint8 cmd); // ステータスバイト struct StatusByte { @@ -131,151 +177,96 @@ class SCSI static const uint8 Identify = 0x80; // 0x80..0xff }; - // Mode Select(6) ヘッダ - struct ModeParamHdr { - uint8 mode_param_len; // ヘッダ以降のバイト数 - uint8 media_type; - uint8 device_specific_param; - uint8 block_desc_len; // 0 か 8の倍数 - } __packed; - - // Mode Select(6) ブロックディスクリプタ - struct BlockDesc { - uint8 density_code; - uint8 block_cnt[3]; // ブロック数 - uint8 reserved; - uint8 block_size[3]; // 論理ブロック長 (バイト) - } __packed; - - // フェーズ名を返す。 - static const char *GetPhaseName(uint); - - // SCSI コマンド名を返す。 - static const char *GetCommandName(uint8); - - private: - static const char * const phasename[Phase::MAX]; - static const char * const commandname[Command::MAX]; -}; - -class SCSIHostDevice : public IODevice -{ - typedef IODevice inherited; - public: - SCSIHostDevice(); - virtual ~SCSIHostDevice(); + // Inquiry コマンドの Peripheral Qualifier フィールド + struct InquiryQualifier { + static const uint8 LU_Present = 0x00; + static const uint8 LU_NotPreseted = 0x20; + static const uint8 Reserved = 0x40; + static const uint8 LU_NotSupported = 0x60; + static const uint8 Mask = 0xe0; + }; + // Inquiry コマンドの Peripheral Device Type フィールド + struct InquiryDeviceType { + static const uint8 DirectAccess = 0x00; + static const uint8 SequentialAccess = 0x01; + static const uint8 Printer = 0x02; + static const uint8 Processor = 0x03; + static const uint8 WriteOnce = 0x04; + static const uint8 CDROM = 0x05; + static const uint8 Scanner = 0x06; + static const uint8 MO = 0x07; + static const uint8 MediaChanger = 0x08; + static const uint8 Communication = 0x09; + static const uint8 Unknown = 0x1f; + }; - virtual bool Create(); + // センスキー + struct SenseKey { + static const uint8 NoSense = 0x0; + static const uint8 RecoveredError = 0x1; + static const uint8 NotReady = 0x2; + static const uint8 MediumError = 0x3; + static const uint8 HardwareError = 0x4; + static const uint8 IllegalRequest = 0x5; + static const uint8 UnitAttention = 0x6; + static const uint8 DataProtect = 0x7; + static const uint8 BlankCheck = 0x8; + static const uint8 VendorSpecific = 0x9; + static const uint8 CopyAborted = 0xa; + static const uint8 AbortedCommand = 0xb; + static const uint8 Equal = 0xc; + static const uint8 VolumeOverflow = 0xd; + static const uint8 Miscompare = 0xe; + static const uint8 Reserved = 0xf; + }; + // センスキーコードとキー名を表示用に整形したものを返す + static std::string GetSenseKeyDisp(uint8 key); - // このホストデバイスを示す接頭語を取得する - const char *GetConfigName() const { return config_name; } + // ASC/ASCQ + // 上位バイトが ASC、下位バイトが ASCQ を示す。 + struct ASC { + static const uint16 NoAdditionalSenseInformation = 0x0000; + static const uint16 PeripheralDeviceWriteFault = 0x0300; + static const uint16 InvalidCommandOperationCode = 0x2000; + static const uint16 InvalidFieldInCDB = 0x2400; + static const uint16 LogicalUnitNotSupported = 0x2500; + static const uint16 MediumNotPresent = 0x3a00; + }; - // ログ識別子を取得する - const std::string& GetLogName() const { return logname; } - - // 自身の SCSI ID (0..7) - int myid = 0; - - // SCSI ターゲット。[0] が ID0, … - // 未接続とイニシエータは NULL。 - SCSITarget *target[8] {}; - - // Select されているターゲット ID - // 選択されていない状態では -1 - int tgtid = 0; - - // Bus Phase - - // バスフェーズが変化した時刻 - uint64 BusPhaseTime = 0; - - // 各バスフェーズへ遷移する - void B_BusFree(int id); - - bool Arbitration(int id); - bool ArbitrationAck(int id); - - void InitiatorSelection(int targetid); - void TargetSelectionAck(int targetid); - void InitiatorSelectionAck(); - - void TargetReselection(int targetid, int initiatorID); - void InitiatorReselectionAck(); - void TargetReselectionAck(int targetid); - void InitiatorReselectionAck2(); - -#if 0 - // Xfer Phase - SCSI::XferPhase GetXferPhase() const { return xfer_phase; } - - // 各転送フェーズへ遷移する - void X_DataOut(); - void X_DataIn(); - void X_Command(); - void X_Status(); - void X_MsgOut(); - void X_MsgIn(); -#endif - - uint8 DATA = 0; - uint8 GetDATA() const { return DATA; } - void SetDATA(uint8 data); - - // 信号線はいずれも true でアサート - bool REQ = false; // REQ 信号 - bool GetREQ() const { return REQ; } - void SetREQ(bool val); - - bool ACK = false; // ACK 信号 - bool GetACK() const { return ACK; } - void SetACK(bool val); - - // RST も本来は OR-tied だが、ここではあまり意味がないので bool にする。 - bool RST = false; // RST 信号 - bool GetRST() const { return RST; } - void SetRST(bool val); - - uint8 SEL = false; // SEL 信号 - bool GetSEL() const { return SEL != 0; } - void AssertSEL(int id); - void NegateSEL(int id); - - uint8 BSY = false; // BSY 信号 - bool GetBSY() const { return BSY != 0; } - void AssertBSY(int id); - void NegateBSY(int id); - - bool MSG = false; // MSG 信号 - bool GetMSG() const { return MSG; } - void SetMSG(bool val); - - bool CD = false; // CD 信号 - bool GetCD() const { return CD; } - void SetCD(bool val); - - bool IO = false; // IO 信号 - bool GetIO() const { return IO; } - void SetIO(bool val); - - bool ATN = false; // ATN 信号 - bool GetATN() const { return ATN; } - void SetATN(bool val); - - // バスフリーフェーズなら true を返す - bool IsBusFree() const { - return (GetSEL() == false && GetBSY() == false); - } + // Mode Select/Sense のページ + // - 詳細解説本の日本語訳が微妙に遠い…。 + // Rigid Disk Geometry Page は「ドライブ・パラメータ」、 + // Flexible Disk Page は「フロッピ・ディスク・パラメータ」、 + // Caching Page は「キャッシュ・コントロール・パラメータ」としてある。 + // ページコード(番号)を軸に読み替えること。 + // - ReadWriteErrorRecovery は CD-ROM クラスではページ番号同じで + // ReadErrorRecovery だがそれはもう区別しない。 + // - 名前の後ろの Page は基本省略しているが、Caching Page は省略すると + // 訳分からんことになるので。 + enum ModePage : uint8 { + VendorSpecific = 0x00, + ReadWriteErrorRecovery = 0x01, + DisconnectReconnect = 0x02, + FormatDevice = 0x03, + RigidDiskGeometry = 0x04, + FlexibleDisk = 0x05, + OpticalMemory = 0x06, + VerifyErrorRecovery = 0x07, + CachingPage = 0x08, + PeripheralDevice = 0x09, + ControlMode = 0x0a, + MediumTypeSupported = 0x0b, + NotchAndPartition = 0x0c, + CDROM = 0x0d, + CDROMAudioControl = 0x0e, - // ターゲットがバスフリーフェーズに移行した - virtual void BusRelease() { } + AllPages = 0x3f, + }; + // ページ番号とページ名を表示用に整形したものを返す + static std::string GetModePageDisp(uint8 page); - protected: - // 設定ファイルに使われるこのホストデバイスを示す接頭語。 - // ("spc0" とか) - const char *config_name = NULL; - -#if 0 - SCSI::BusPhase bus_phase; - SCSI::XferPhase xfer_phase; -#endif + private: + static const std::vector commandname; + static const std::vector sensekeyname; + static const std::vector modepagename; };