--- nono/vm/scsidev.cpp 2026/04/29 17:05:06 1.1.1.13 +++ nono/vm/scsidev.cpp 2026/04/29 17:05:25 1.1.1.17 @@ -4,6 +4,10 @@ // Licensed under nono-license.txt // +// +// SCSI デバイス +// + // ログレベルは // 1: SCSI コマンドの概要。 // デバイスの動作のうち大きな変更のもの @@ -16,6 +20,7 @@ #include "scsidev.h" #include "config.h" #include "mainapp.h" +#include "scheduler.h" #include "uimessage.h" // @@ -23,8 +28,8 @@ // // コンストラクタ -SCSIDevice::SCSIDevice(const std::string& objname_) - : inherited(objname_) +SCSIDevice::SCSIDevice(int objid_) + : inherited(objid_) { } @@ -33,17 +38,18 @@ SCSIDevice::~SCSIDevice() { } + // // SCSI ホストデバイス // // コンストラクタ -SCSIHostDevice::SCSIHostDevice(const std::string& objname_) - : inherited(objname_) +SCSIHostDevice::SCSIHostDevice(int objid_) + : inherited(objid_) { devtype = SCSI::DevType::Initiator; - monitor_devs.func = (MonitorCallback_t)&SCSIHostDevice::MonitorUpdateDevs; + monitor_devs.func = ToMonitorCallback(&SCSIHostDevice::MonitorUpdateDevs); // サイズは Create で決まる monitor_devs.Regist(ID_MONITOR_SCSIDEVS); @@ -77,7 +83,7 @@ SCSIHostDevice::Create() const std::string& image = item.AsString(); // 空ならデバイスなし - if (image.length() == 0) { + if (image.empty()) { // 未接続部分のパラメータは減らしておくか。 // --show-config するとさすがに無駄に多くて邪魔なので。 const std::string wikey = string_format("%s-id%d-writeignore", @@ -106,7 +112,7 @@ SCSIHostDevice::Create() } else if (type == "mo") { target_devtype = SCSI::DevType::MO; } else { - item.Err("invaild device type '%s'", type.c_str()); + item.Err("Invaild device type '%s'", type.c_str()); return false; } target[id].reset(new SCSIDisk(this, id, target_devtype)); @@ -121,6 +127,10 @@ SCSIHostDevice::Create() bool SCSIHostDevice::Init() { + if (inherited::Init() == false) { + return false; + } + // 初期化ではないけどログレベルがセットできたここでデバッグ表示。 // -L オプションの処理は Create() の後なので。 if (loglevel >= 1) { @@ -135,7 +145,7 @@ SCSIHostDevice::Init() } // connected_devices によってモニタの大きさを決定。 - monitor_devs.SetSize(80, (connected_devices.size() - 1) * 4 + 1); + monitor_devs.SetSize(75, (connected_devices.size() - 1) * 4 + 1); return true; } @@ -175,9 +185,14 @@ SCSIHostDevice::BusFreeCB(int id) void SCSIHostDevice::MonitorUpdateDevs(Monitor *, TextScreen& screen) { - int x; int y; +// 012345678901234567890123456789012345678901234567890123456789012345678901234 +// ID6: HD(2048MB) +// MediumLoaded Off LogicalBlock 2048 ImageSize 2,147,483,648 +// RemovalPrevent Off WriteProtected + + screen.Clear(); y = 0; @@ -212,58 +227,32 @@ SCSIHostDevice::MonitorUpdateDevs(Monito continue; } - // 1列目 - x = 5; - screen.Print(x, y, + const int x1 = 5; + const int x2 = 29; + const int x3 = 50; + + // 1行目 + screen.Print(x1, y, (disk->IsRemovableDevice() ? TA::Normal : TA::Disable), "MediumLoaded %s", disk->IsMediumLoaded() ? "On" : "Off"); - screen.Print(x, y + 1, + screen.Print(x2, y, "LogicalBlock %d", disk->GetBlocksize()); + std::string imagesize = format_number(disk->GetSize()); + screen.Print(x3, y, "ImageSize %13s", imagesize.c_str()); + y++; + + // 2行目 + screen.Print(x1, y, (disk->IsRemovableDevice() ? TA::Normal : TA::Disable), "RemovalPrevent %s", disk->IsMediumRemovalPrevented() ? "On" : "Off"); - // 2列目 - x = 29; - const char *wstr; - switch (disk->GetWriteMode()) { - case SCSIDisk::RW::ReadOnly: wstr = "ReadOnly"; break; - case SCSIDisk::RW::WriteProtect: wstr = "WriteProtected"; break; - case SCSIDisk::RW::Writeable: wstr = "Writeable"; break; - case SCSIDisk::RW::WriteIgnore: wstr = "WriteIgnored"; break; - default: __unreachable(); - } - screen.Puts(x, y, - (disk->IsMediumLoaded() ? TA::Normal : TA::Disable), wstr); - - // 3列目 - x = 50; - uint64 v = disk->GetSize(); - std::string bytes; - if (v < 1000) { - bytes = string_format("%u", (uint32)v); - } else if (v < 1000 * 1000) { - bytes = string_format("%u,%03u", - (uint)(v / 1000), - (uint)(v % 1000)); - } else if (v < 1000 * 1000 * 1000) { - bytes = string_format("%u,%03u,%03u", - (uint)(v / 1000 / 1000), - (uint)((v / 1000) % 1000), - (uint)(v % 1000)); - } else if (v < 1000ULL * 1000 * 1000 * 1000) { - bytes = string_format("%u,%03u,%03u,%03u", - (uint)(v / 1000 / 1000 / 1000), - (uint)((v / 1000 / 1000) % 1000), - (uint)((v / 1000) % 1000), - (uint)(v % 1000)); - } else { - bytes = string_format("%ju", (uintmax_t)v); - } - screen.Print(x, y, "TotalBytes %s", bytes.c_str()); - screen.Print(x, y + 1, "LogicalBlock %d", disk->GetBlocksize()); + screen.Puts(x2, y, + (disk->IsMediumLoaded() ? TA::Normal : TA::Disable), + disk->GetWriteModeStr()); + y++; - y += 3; + y++; } } @@ -272,9 +261,9 @@ SCSIHostDevice::MonitorUpdateDevs(Monito // SCSI ターゲットデバイスの共通部分 // -// コンストラクタ -SCSITarget::SCSITarget(const std::string& objname_, SCSIHostDevice *h, int id) - : inherited(objname_) +// コンストラクタ。 +SCSITarget::SCSITarget(SCSIHostDevice *h, int id) + : inherited(OBJ_NONE) // オブジェクト ID で検索することはない { // ホストへのリンク (所有関係のないポインタ) host = h; @@ -287,17 +276,17 @@ SCSITarget::~SCSITarget() } // 電源オン -bool -SCSITarget::PowerOn() +void +SCSITarget::ResetHard(bool poweron) { - ClearSense(); - cmdseq.clear(); - cmdlen = 0; - cmd.reset(); - bytecount = 0; - lastbyte = false; - - return true; + if (poweron) { + ClearSense(); + cmdseq.clear(); + cmdlen = 0; + cmd.reset(); + bytecount = 0; + lastbyte = false; + } } // バスリセットされた (SCSIBus から呼ばれる) @@ -592,7 +581,7 @@ SCSITarget::DispatchCmd() if (cname) { name = string_format(" %s", cname); } - putlog(0, "未実装 SCSI コマンド $%02x%s len=%d", + putlog(0, "SCSI Command $%02x%s len=%d not supported", cmdseq[0], name.c_str(), (int)cmdseq.size()); cmd.reset(new SCSICmdNotSupportedCommand(this)); @@ -600,6 +589,16 @@ SCSITarget::DispatchCmd() } } +// コマンド列を指定して対応するコマンドを選択する。なければ NULL を返す。 +// ROM30 エミュレーション用。 +SCSICmd * +SCSITarget::SelectCommand(const std::vector& cmdseq_) +{ + cmdseq = cmdseq_; + DispatchCmd(); + return cmd.get(); +} + // // SCSI Disk @@ -607,7 +606,7 @@ SCSITarget::DispatchCmd() // コンストラクタ SCSIDisk::SCSIDisk(SCSIHostDevice *h, int id, SCSI::DevType devtype_) - : inherited("", h, id) + : inherited(h, id) { devtype = devtype_; @@ -619,6 +618,7 @@ SCSIDisk::SCSIDisk(SCSIHostDevice *h, in // lib/object.h 参照。 SetName(string_format("SCSI%s%d", devtypename, id)); ClearAlias(); + AddAlias(string_format("SCSI%s%d", devtypename, id)); AddAlias(string_format("SCSI%d", id)); AddAlias(string_format("%s%d", devtypename, id)); @@ -639,28 +639,24 @@ SCSIDisk::SCSIDisk(SCSIHostDevice *h, in blocksize = 512; break; default: - __unreachable(); + PANIC("corrupted devtype=%d", (int)devtype); } - // リムーバブルデバイスのみ UI からの通知を受け取るイベントを用意 - if (IsRemovableDevice()) { - event = new Event(this); - event->SetName(GetName() + " MediaChange"); - } } // デストラクタ SCSIDisk::~SCSIDisk() { - if (event) { - delete event; - } } // 初期化 bool SCSIDisk::Init() { + if (inherited::Init() == false) { + return false; + } + const std::string keybody = string_format("%s-id%d-", host->GetConfigName(), myid); const std::string imgkey = keybody + "image"; @@ -684,6 +680,14 @@ SCSIDisk::Init() return false; } + // リムーバブルデバイスのみ UI からの通知を受け取るイベントを用意 + if (IsRemovableDevice()) { + scheduler->ConnectMessage(MessageID::SCSIDEV_LOAD(myid), this, + ToMessageCallback(&SCSIDisk::LoadMessage)); + scheduler->ConnectMessage(MessageID::SCSIDEV_UNLOAD(myid), this, + ToMessageCallback(&SCSIDisk::UnloadMessage)); + } + // オープン前に writeignore をチェック。 // この後パス名を処理するとすぐに UI に通知を出すため、それより前で // 行わないといけない。うーん。 @@ -716,7 +720,7 @@ SCSIDisk::Init() // 設定時点でファイルが指定されていればオープン if (filename.empty() == false) { - const std::string path = gMainApp.GetVMDir() + filename; + std::string path = gMainApp.NormalizePath(filename); if (LoadDisk(path) == false) { return false; } @@ -734,17 +738,15 @@ SCSIDisk::Init() } // 電源オン -bool -SCSIDisk::PowerOn() +void +SCSIDisk::ResetHard(bool poweron) { - if (inherited::PowerOn() == false) { - return false; - } - - // メディアの取り出し禁止を解除 - PreventMediumRemoval(false); + inherited::ResetHard(poweron); - return true; + if (poweron) { + // メディアの取り出し禁止を解除 + PreventMediumRemoval(false); + } } // バスリセット @@ -763,13 +765,13 @@ SCSIDisk::BusResetCB() bool SCSIDisk::LoadDisk(const std::string& pathname_) { - bool changed = false; + bool unloaded; off_t size; bool w_ok; bool read_only; // すでにあればクローズ (ここでは通知は行わない) - changed = UnloadDisk_internal(); + unloaded = UnloadDisk_internal(); // 新しいイメージをオープン(する準備) pathname = pathname_; @@ -826,7 +828,7 @@ SCSIDisk::LoadDisk(const std::string& pa } break; default: - __unreachable(); + PANIC("corrupted devtype=%d", (int)devtype); } // 書き込みモードをここで確定 @@ -858,21 +860,21 @@ SCSIDisk::LoadDisk(const std::string& pa } medium_loaded = true; - changed = true; -done: - if (changed) { - // HD 初期化時はログに出さない - if (IsRemovableDevice()) { - putlog(1, "Medium loaded"); - } - - // 変化があれば通知 - MediaChanged(); + // リムーバブルデバイスでだけログを出す + if (IsRemovableDevice()) { + putlog(1, "Medium loaded"); } + + done: if (medium_loaded == false) { // ここで状態をクリアする Clear(); } + + // 変化があれば通知 + if (unloaded || medium_loaded) { + MediaChanged(); + } return medium_loaded; } @@ -929,15 +931,13 @@ SCSIDisk::MediaChanged() const UIMessage::Post(UIMessage::SCSI_MEDIA_CHANGE, GetMyID()); } - // メディアを挿入する。 // UI スレッドで実行されるので、VM スレッドに通知するだけ。 void SCSIDisk::LoadDiskUI(const std::string& pathname_) { new_pathname = pathname_; - event->func = (DeviceCallback_t)&SCSIDisk::LoadCallback; - event->Start(); + scheduler->SendMessage(MessageID::SCSIDEV_LOAD(GetMyID())); } // メディアを排出する。 @@ -945,14 +945,12 @@ SCSIDisk::LoadDiskUI(const std::string& void SCSIDisk::UnloadDiskUI(bool force) { - event->func = (DeviceCallback_t)&SCSIDisk::UnloadCallback; - event->code = force; - event->Start(); + scheduler->SendMessage(MessageID::SCSIDEV_UNLOAD(GetMyID()), force); } -// メディア挿入コールバック +// メディア挿入メッセージコールバック void -SCSIDisk::LoadCallback(Event& ev) +SCSIDisk::LoadMessage(MessageID msgid, uint32 arg) { if (LoadDisk(new_pathname) == false) { // 失敗したら UI に通知 @@ -960,11 +958,11 @@ SCSIDisk::LoadCallback(Event& ev) } } -// メディア排出コールバック +// メディア排出メッセージコールバック void -SCSIDisk::UnloadCallback(Event& ev) +SCSIDisk::UnloadMessage(MessageID msgid, uint32 arg) { - bool force = ev.code; + bool force = arg; UnloadDisk(force); } @@ -1064,7 +1062,7 @@ SCSIDisk::Inquiry(std::vector& bu prodname = "SCSIMO"; break; default: - assert(false); + PANIC("Unexpected devtype=%d", (int)devtype); } buf[0] = inqtype; @@ -1177,3 +1175,17 @@ SCSIDisk::PreventMediumRemoval(bool val) } medium_removal_prevented = val; } + +// メディアの書き込みモードを文字列で返す +const char * +SCSIDisk::GetWriteModeStr() const +{ + switch (write_mode) { + case RW::ReadOnly: return "ReadOnly"; + case RW::WriteProtect: return "WriteProtected"; + case RW::Writeable: return "Writeable"; + case RW::WriteIgnore: return "WriteIgnore"; + default: + PANIC("corrupted write_mode=%d", (int)write_mode); + } +}