--- nono/vm/scsidev.cpp 2026/04/29 17:04:39 1.1.1.4 +++ nono/vm/scsidev.cpp 2026/04/29 17:04:42 1.1.1.5 @@ -32,6 +32,8 @@ SCSIDevice::~SCSIDevice() // コンストラクタ SCSIHostDevice::SCSIHostDevice() { + devtype = SCSI::DevType::Initiator; + // バスデバイスを作成する。 // ただし自身がバスに参加するのは継承側で行う // (例えば SPC なら BDID 書き込みで ID が決まった後、など)。 @@ -63,6 +65,14 @@ SCSIHostDevice::Create() // 空ならデバイスなし if (image.length() == 0) { + // 未接続部分のパラメータは減らしておくか。 + // --show-config するとさすがに無駄に多くて邪魔なので。 + const std::string wpkey = string_format("%s-id%d-writeprotect", + GetConfigName(), id); + const std::string stkey = string_format("%s-id%d-seektime", + GetConfigName(), id); + gConfig->Delete(wpkey); + gConfig->Delete(stkey); continue; } @@ -96,7 +106,7 @@ SCSIHostDevice::Init() std::string typestr; if (target[id]) { switch (target[id]->GetDevType()) { - case SCSI::DevType::None: + default: break; case SCSI::DevType::HD: typestr = "HD"; @@ -163,6 +173,12 @@ class SCSICmd std::vector buf; uint32 recvbytes; + // このコマンドの動作時間 [nsec] + // シークタイムとかを簡易的に再現するため、次フェーズ遷移時の最初の + // REQ アサートを引き延ばすために使う。 + // 主にコマンドフェーズで使うことになると思う。 + uint64 optime {}; + // 以下いずれも戻り値は遷移先のフェーズ。 // コマンドフェーズを処理する。 @@ -327,6 +343,9 @@ class SCSICmdRead6 : public SCSICmd uint8 *end = start + blks * parent->GetBlocksize(); buf.assign(start, end); + // 平均シークタイム + optime = hdparent->seektime; + return SCSI::XferPhase::DataIn; } }; @@ -365,6 +384,9 @@ class SCSICmdWrite6 : public SCSICmd return SCSI::XferPhase::Status; } + // 平均シークタイム + optime = hdparent->seektime; + recvbytes = blks * parent->GetBlocksize(); return SCSI::XferPhase::DataOut; } @@ -584,6 +606,9 @@ class SCSICmdRead10 : public SCSICmd uint8 *end = start + blks * parent->GetBlocksize(); buf.assign(start, end); + // 平均シークタイム + optime = hdparent->seektime; + return SCSI::XferPhase::DataIn; } }; @@ -633,6 +658,22 @@ SCSITarget::~SCSITarget() void SCSITarget::BusResetCB() { + // リセットされたので持ってる信号を全部解放。 + // 一応自分が変えていい信号線だけを落とす。 + switch (GetPhase()) { + case SCSI::Phase::BusFree: + break; + case SCSI::Phase::Arbitration: + case SCSI::Phase::Selection: + case SCSI::Phase::Reselection: + NegateSEL(); + NegateBSY(); + break; + case SCSI::Phase::Transfer: + NegateBSY(); + break; + } + // センスキーをクリア ClearSense(); } @@ -797,6 +838,12 @@ SCSITarget::TransferAckCB() } putlog(2, "%s done", SCSI::GetXferPhaseName(xfer)); + // 簡略化のため、フェーズ完了時だけ REQ を引き伸ばすことができる + if (cmd->optime != 0) { + bus->SetOneshotReqWait(cmd->optime); + cmd->optime = 0; + } + if (next != xfer) { // End ならバスフリーにして終了。 if (next == SCSI::XferPhase::End) { @@ -929,6 +976,7 @@ SCSIHD::Init() host->GetConfigName(), myid); const std::string imgkey = keybody + "image"; const std::string wpkey = keybody + "writeprotect"; + const std::string stkey = keybody + "seektime"; const ConfigItem& itemimg = gConfig->Find(imgkey); const std::string& image = itemimg.AsString(); @@ -954,6 +1002,10 @@ SCSIHD::Init() putmsg(0, "%s: write protected", myname.c_str()); } + // 設定は [msec]、変数は [nsec]。 + seektime = gConfig->Find(stkey).AsInt(); + seektime *= 1_msec; + return true; }