--- nono/vm/scsi.h 2026/04/29 17:04:28 1.1.1.1 +++ nono/vm/scsi.h 2026/04/29 17:04:42 1.1.1.6 @@ -1,38 +1,84 @@ // // nono -// Copyright (C) 2018 isaki@NetBSD.org +// Copyright (C) 2020 nono project +// Licensed under nono-license.txt // #pragma once #include "device.h" +// このクラスは SCSI プロトコル上の定数などだけを持つ。 class SCSI { public: - // デバイス種別 - enum DevType { - None = 0, - HD = 1, + static const uint IO = 0x01; + static const uint CD = 0x02; + static const uint MSG = 0x04; + static const uint BSY = 0x08; + static const uint SEL = 0x10; + + // SCSI のフェーズを表す。 + // フェーズは概ね BSY と SEL の状態遷移によって決まる。 + // 情報転送フェーズの内訳は XferPhase 側で区別する。 + enum Phase { + BusFree = 0, + Arbitration = 1, + Selection = 2, + Reselection = 3, + Transfer = 4, }; - // フェーズは、バスフェーズと転送フェーズを一緒くたで扱う。 - // 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; + // 情報転送フェーズを表す。 + // この値は 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 内でフェーズ遷移を表現するために使う + }; + + // フェーズ文字列を返す + static const char * GetPhaseName(int phase) { + return GetPhaseName((Phase)phase); + } + static const char * GetPhaseName(Phase phase) { + switch (phase) { + case BusFree: return "BusFree"; + case Arbitration: return "Arbitration"; + case Selection: return "Selection"; + case Reselection: return "Reselection"; + case Transfer: return "Transfer"; + } + return "Phase?"; + } + + // 情報転送フェーズ文字列を返す + static const char * GetXferPhaseName(int xfer) { + return GetXferPhaseName((XferPhase)xfer); + } + static const char * GetXferPhaseName(XferPhase xfer) { + switch (xfer) { + case DataOut: return "DataOut"; + case DataIn: return "DataIn"; + case Command: return "Command"; + case Status: return "Status"; + case MsgOut: return "MsgOut"; + case MsgIn: return "MsgIn"; + case End: return "End"; + } + return "XferPhase?"; + } - static const uint MAX = 12; // 最大値 +1 にすること + // デバイス種別 + enum class DevType { + None = 0, + Initiator, + HD, }; // コマンド。 @@ -131,12 +177,40 @@ class SCSI static const uint8 Identify = 0x80; // 0x80..0xff }; + // センスキー + 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; + }; + + // ASC/ASCQ + // 上位バイトが ASC、下位バイトが ASCQ を示す。 + struct ASC { + static const uint16 NoAdditionalSenseInformation = 0x0000; + static const uint16 InvalidCommandOperationCode = 0x2000; + static const uint16 InvalidFieldInCDB = 0x2400; + }; + // Mode Select(6) ヘッダ struct ModeParamHdr { - uint8 mode_param_len; // ヘッダ以降のバイト数 + uint8 mode_param_len; // バイト長 (このバイトを含まずこれ以降) uint8 media_type; uint8 device_specific_param; - uint8 block_desc_len; // 0 か 8の倍数 + uint8 block_desc_len; // ブロックディスクリプタ長 } __packed; // Mode Select(6) ブロックディスクリプタ @@ -147,135 +221,9 @@ class SCSI uint8 block_size[3]; // 論理ブロック長 (バイト) } __packed; - // フェーズ名を返す。 - static const char *GetPhaseName(uint); - - // SCSI コマンド名を返す。 - static const char *GetCommandName(uint8); + // SCSI コマンド名を返す + static const char *GetCommandName(uint8 cmd); 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(); - - virtual bool Create(); - - // このホストデバイスを示す接頭語を取得する - const char *GetConfigName() const { return config_name; } - - // ログ識別子を取得する - 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); - } - - // ターゲットがバスフリーフェーズに移行した - virtual void BusRelease() { } - - protected: - // 設定ファイルに使われるこのホストデバイスを示す接頭語。 - // ("spc0" とか) - const char *config_name = NULL; - -#if 0 - SCSI::BusPhase bus_phase; - SCSI::XferPhase xfer_phase; -#endif -};