--- nono/vm/scsi.cpp 2026/04/29 17:04:28 1.1 +++ nono/vm/scsi.cpp 2026/04/29 17:05:28 1.1.1.6 @@ -1,59 +1,73 @@ // // nono -// Copyright (C) 2018 isaki@NetBSD.org +// Copyright (C) 2020 nono project +// Licensed under nono-license.txt // -// SCSI + +// +// SCSI (定数等) // #include "scsi.h" -#include "scheduler.h" -#include "scsitarget.h" -#include "mystring.h" -#include "configfile.h" - -// フェーズ名を返す。 -const char * -SCSI::GetPhaseName(uint phase) -{ - if (phase < countof(phasename)) { - return phasename[phase]; - } else { - return NULL; + +// フェーズ文字列を返す +/*static*/ const char * +SCSI::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"; + default: return "Phase?"; + } +} + +// 情報転送フェーズ文字列を返す +/*static*/ const char * +SCSI::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"; + default: return "XferPhase?"; + } +} + +// デバイス種別文字列を返す +/*static*/ const char * +SCSI::GetDevTypeName(DevType type) +{ + switch (type) { + case DevType::None: return "None"; + case DevType::Initiator: return "Initiator"; + case DevType::HD: return "HD"; + case DevType::CD: return "CD"; + case DevType::MO: return "MO"; + default: return "DevType?"; } } // cmd に対応するコマンド名を返す。 -const char * +/*static*/ const char * SCSI::GetCommandName(uint8 cmd) { - if (cmd < countof(commandname)) { + if (cmd < commandname.size()) { return commandname[cmd]; } else { return NULL; } } -// フェーズ名 -/*static*/ const char * const -SCSI::phasename[Phase::MAX] = -{ - "DataOut", // 0 - "DataIn", // 1 - "Command", // 2 - "Status", // 3 - "4?", // 4 - "5?", // 5 - "MsgOut", // 6 - "MsgIn", // 7 - "BusFree", // 8 - "Arbitration", // 9 - "Selection", // 10 - "Reselection", // 11 -}; - // コマンド名 -/*static*/ const char * const -SCSI::commandname[Command::MAX] = +/*static*/ const std::vector +SCSI::commandname = { "TestUnitReady", // 00 "RezeroUnit", // 01 @@ -92,7 +106,7 @@ SCSI::commandname[Command::MAX] = NULL, // 20 NULL, // 21 NULL, // 22 - NULL, // 23 + "ReadFormatCapacities", // 23 NULL, // 24 "ReadCapacity", // 25 NULL, // 26 @@ -126,8 +140,8 @@ SCSI::commandname[Command::MAX] = "ChangeDefinition", // 40 "WriteSame", // 41 NULL, // 42 - NULL, // 43 - NULL, // 44 + "ReadTOC", // 43 + "ReadHeader", // 44 NULL, // 45 NULL, // 46 NULL, // 47 @@ -140,7 +154,7 @@ SCSI::commandname[Command::MAX] = NULL, // 4e NULL, // 4f NULL, // 50 - NULL, // 51 + "ReadDiscInformation", // 51 NULL, // 52 NULL, // 53 NULL, // 54 @@ -152,320 +166,71 @@ SCSI::commandname[Command::MAX] = "ModeSense(10)", // 5a }; -// -// SCSI ホストデバイス (基本クラス) -// - -// コンストラクタ -SCSIHostDevice::SCSIHostDevice() -{ -} - -// デストラクタ -SCSIHostDevice::~SCSIHostDevice() -{ -} - -// SCSI デバイスオブジェクトの生成 -bool -SCSIHostDevice::Create() -{ - for (int id = 0; id < 8; id++) { - const std::string key = string_format("%s_id%d_devtype", - GetConfigName(), id); - int devtype = gConfig->ReadInt(key); - switch (devtype) { - default: - case SCSI::None: - target[id] = NULL; - break; - case SCSI::HD: - target[id] = new SCSIHD(this, id); - break; - } - } - return true; -} - -// SCSIHostDevice クラスに書いてあるけど -// このへんは SCSI バスの挙動。 - -// 各バスフェーズへ遷移する - -// バスフリーフェーズへ遷移する。 -// 基本的にターゲットが使用する。 -void -SCSIHostDevice::B_BusFree(int id) -{ - if (!IsBusFree()) { - // バスフリーに変化した時刻を記録 - BusPhaseTime = gScheduler->GetVirtTime(); - } - NegateSEL(id); - NegateBSY(id); - SetMSG(false); - SetCD(false); - SetIO(false); - SetATN(false); - SetREQ(false); - SetACK(false); - SetDATA(0); - putlog(3, "BusFree"); -} - -// アービトレーションフェーズを起動する。 -// id はアービトレーションを行おうとしているデバイスの ID。 -// バスフリー状態で呼び出すこと。 -bool -SCSIHostDevice::Arbitration(int id) -{ - assert(IsBusFree()); - - AssertBSY(id); - SetDATA(1 << id); - - putlog(3, "Arbitration invoked by ID=%d", id); - return true; -} - -// アービトレーションフェーズの完了確認。 -// id はアービトレーションを行おうとしているデバイスの ID。 -bool -SCSIHostDevice::ArbitrationAck(int id) -{ - // 自分より上位の ID がいればアービトレーション失敗なのだが、 - // ここでは複数のデバイスが同時にアービトレーションフェーズに入ることは - // ないので、アービトレーションは必ず成功するとする。 - if (0 && GetDATA() > (1 << id)) { - NegateBSY(id); - putlog(3, "Arbitration loose ID=%d", id); - return false; - } - AssertSEL(id); - return true; -} - -// イニシエータによるセレクションフェーズの起動。 -void -SCSIHostDevice::InitiatorSelection(int targetid) -{ - NegateBSY(myid); - SetDATA((1 << myid) | (1 << targetid)); - AssertSEL(myid); -} - -// (イニシエータによる)セレクションへのターゲットの応答。 -void -SCSIHostDevice::TargetSelectionAck(int targetid) -{ - assert(GetDATA() & (1 << targetid)); - - // targetid がセレクトされた - AssertBSY(targetid); - tgtid = targetid; - putlog(3, "Target selected ID=%d", targetid); -} - -void -SCSIHostDevice::InitiatorSelectionAck() -{ - NegateSEL(myid); -} - -// リセレクションフェーズ - -void -SCSIHostDevice::TargetReselection(int targetid, int initiatorID) -{ - SetIO(true); - SetDATA((1 << initiatorID) | (1 << targetid)); - NegateBSY(targetid); -} - -int -BitToID(int x) -{ - return 31 - __builtin_clz(x); -} - -void -SCSIHostDevice::InitiatorReselectionAck() +// センスキーとその名前を表示用に整形したものを返す +/*static*/ std::string +SCSI::GetSenseKeyDisp(uint8 key) { - tgtid = BitToID(GetDATA() & ~(1 << myid)); - AssertBSY(myid); -} - -void -SCSIHostDevice::TargetReselectionAck(int targetid) -{ - AssertBSY(targetid); - NegateSEL(targetid); - target[targetid]->Selected(); -} - -void -SCSIHostDevice::InitiatorReselectionAck2() -{ - NegateBSY(myid); -} - -//////// - -// データバスに data をセット -void -SCSIHostDevice::SetDATA(uint8 data) -{ - DATA = data; - putlog(3, "BUS DATA = $%02x", DATA); -} - -// REQ 信号線をセット -void -SCSIHostDevice::SetREQ(bool val) -{ - // 同じなら何もしない - if (REQ == val) { - return; - } - - REQ = val; - putlog(4, "BUS REQ = %d", REQ); -} - -// ACK 信号線をセット -void -SCSIHostDevice::SetACK(bool val) -{ - // 同じなら何もしない - if (ACK == val) { - return; - } - - ACK = val; - putlog(4, "BUS ACK = %d", ACK); -} - -// RST 信号線をセット -void -SCSIHostDevice::SetRST(bool val) -{ - // 同じなら何もしない - if (RST == val) { - return; - } - - RST = val; - putlog(3, "BUS RST = %d", RST); -} - -// SEL 信号線をアサート -void -SCSIHostDevice::AssertSEL(int id) -{ - // 同じなら何もしない - if (SEL & (1 << id)) { - return; - } - - SEL |= 1 << id; - putlog(3, "BUS SEL = %02x", SEL); -} - -// SEL 信号線をネゲート -void -SCSIHostDevice::NegateSEL(int id) -{ - // 同じなら何もしない - if ((SEL & (1 << id)) == 0) { - return; - } - - SEL &= ~(1 << id); - putlog(3, "BUS SEL = %02x", SEL); -} - -// BSY 信号線をアサート -void -SCSIHostDevice::AssertBSY(int id) -{ - // 同じなら何もしない - if (BSY & (1 << id)) { - return; - } - - BSY |= 1 << id; - putlog(3, "BUS BSY = %02x", BSY); -} - -// BSY 信号線をネゲート -void -SCSIHostDevice::NegateBSY(int id) -{ - // 同じなら何もしない - if ((BSY & (1 << id)) == 0) { - return; - } - - BSY &= ~(1 << id); - putlog(3, "BUS BSY = %02x", BSY); -} - -// MSG 信号線をセット -void -SCSIHostDevice::SetMSG(bool val) -{ - // 同じなら何もしない - if (MSG == val) { - return; + if (__predict_true(key < sensekeyname.size())) { + return string_format("%s($%x)",sensekeyname[key], key); + } else { + return string_format("$%x", key); } - - MSG = val; - putlog(3, "BUS MSG = %d", MSG); } -// C/D 信号線をセット -void -SCSIHostDevice::SetCD(bool val) +/*static*/ const std::vector +SCSI::sensekeyname = { - // 同じなら何もしない - if (CD == val) { - return; - } - - CD = val; - static const char *cdstr[] = { - "Data", - "Ctrl", - }; - putlog(3, "BUS CD = %d(%s)", CD, cdstr[CD]); -} + "NoSense", // 0x0 + "RecoveredError", // 0x1 + "NotReady", // 0x2 + "MediumError", // 0x3 + "HardwareError", // 0x4 + "IllegalRequest", // 0x5 + "UnitAttention", // 0x6 + "DataProtect", // 0x7 + "BlankCheck", // 0x8 + "VendorSpecific", // 0x9 + "CopyAborted", // 0xa + "AbortedCommand", // 0xb + "Equal", // 0xc + "VolumeOverflow", // 0xd + "Miscompare", // 0xe + "Reserved", // 0xf +}; -// I/O 信号線をセット -void -SCSIHostDevice::SetIO(bool val) -{ - // 同じなら何もしない - if (IO == val) { - return; +// Mode Select/Sense のページ番号とページ名を表示用に整形したものを返す +/*static*/ std::string +SCSI::GetModePageDisp(uint8 page) +{ + const char *name; + + if (__predict_true(page < modepagename.size())) { + name = modepagename[page]; + } else if (page == 0x3f) { + name = "AllPages"; + } else { + return string_format("$%02x", page); } - IO = val; - static const char *iostr[] = { - "Out", - "In", - }; - putlog(3, "BUS IO = %d(%s)", IO, iostr[IO]); + return string_format("$%02x(%s)", page, name); } -// ATN 信号線をセット -void -SCSIHostDevice::SetATN(bool val) +/*static*/ const std::vector +SCSI::modepagename = { - // 同じなら何もしない - if (ATN == val) { - return; - } - - ATN = val; - putlog(3, "BUS ATN = %d", ATN); -} + "VendorSpecific", // 00 + "ReadWriteErrorRecovery", // 01 + "DisconnectReconnect", // 02 + "FormatDevice", // 03 + "RigidDiskGeometry", // 04 + "FlexibleDisk", // 05 + "OpticalMemory", // 06 + "VerifyErrorRecovery", // 07 + "CachingPage", // 08 + "PeripheralDevice", // 09 + "ControlMode", // 0a + "MediumTypeSupported", // 0b + "NotchAndPartition", // 0c + "CDROM", // 0d + "CDROMAudioControl", // 0e +};