--- nono/vm/scsidev.cpp 2026/04/29 17:04:29 1.1 +++ nono/vm/scsidev.cpp 2026/04/29 17:04:36 1.1.1.3 @@ -1,16 +1,15 @@ // // nono -// Copyright (C) 2020 isaki@NetBSD.org +// Copyright (C) 2020 nono project +// Licensed under nono-license.txt // // SCSI デバイス共通部分 #include "scsidev.h" -#include "configfile.h" +#include "config.h" +#include "mainapp.h" #include "mystring.h" -#include -#include -#include // // SCSI デバイス @@ -44,19 +43,42 @@ SCSIHostDevice::~SCSIHostDevice() { } +// 設定ファイルに使われるこのホストデバイスを示す接頭語を設定する +// (継承クラス側のコンストラクタで config_name を設定後に呼ぶこと) +void +SCSIHostDevice::SetConfigName(const char *name_) +{ + config_name = name_; +} + bool SCSIHostDevice::Create() { // 設定を読み込む。 for (int id = 0; id < 8; id++) { - const std::string key = string_format("%s_id%d_devtype", + const std::string key = string_format("%s-id%d-image", GetConfigName(), id); - int devtype = gConfig->ReadInt(key); - switch (devtype) { - case SCSI::HD: + const ConfigItem& item = gConfig->Find(key); + const std::string& image = item.AsString(); + + // 空ならデバイスなし + if (image.length() == 0) { + continue; + } + + // ',' より前がデバイス種別 (ここではパスは不要) + auto pos = image.find(','); + if (pos == std::string::npos) { + item.Err("no device type specified"); + return false; + } + std::string type = string_tolower(image.substr(0, pos)); + + if (type == "hd") { target[id].reset(new SCSIHD(this, id)); scsibus->Attach(target[id].get(), id); - break; + } else { + item.Err("invaild device type '%s'", type.c_str()); } } @@ -149,15 +171,9 @@ class SCSICmd return SCSI::XferPhase::Status; } - // データインフェーズを開始する。 - virtual void BeginDataIn() { } - // データインフェーズを完了する。 virtual SCSI::XferPhase DoneDataIn() { return SCSI::XferPhase::Status; } - // データアウトフェーズを開始する。 - virtual void BeginDataOut() { } - // データアウトフェーズを完了する。 virtual SCSI::XferPhase DoneDataOut() { return SCSI::XferPhase::Status; } @@ -197,18 +213,31 @@ class SCSICmd // class SCSICmdTestUnitReady : public SCSICmd { - typedef SCSICmd inherited; + using inherited = SCSICmd; public: SCSICmdTestUnitReady(SCSITarget *p) : inherited(p) { } virtual ~SCSICmdTestUnitReady() { } }; // +// SCSI コマンド 0x01: RezeroUnit (共通) +// +class SCSICmdRezeroUnit : public SCSICmd +{ + using inherited = SCSICmd; + public: + SCSICmdRezeroUnit(SCSITarget *p) : inherited(p) { } + virtual ~SCSICmdRezeroUnit() { } + + // とりあえず黙って成功するだけでいいか +}; + +// // SCSI コマンド 0x03: RequestSense (共通) // class SCSICmdRequestSense : public SCSICmd { - typedef SCSICmd inherited; + using inherited = SCSICmd; public: SCSICmdRequestSense(SCSITarget *p) : inherited(p) { } virtual ~SCSICmdRequestSense() { } @@ -239,7 +268,7 @@ class SCSICmdRequestSense : public SCSIC // class SCSICmdRead6 : public SCSICmd { - typedef SCSICmd inherited; + using inherited = SCSICmd; public: SCSICmdRead6(SCSITarget *p) : inherited(p) { } virtual ~SCSICmdRead6() { } @@ -258,8 +287,8 @@ class SCSICmdRead6 : public SCSICmd if (blks == 0) { blks = 256; } - uint8 *start = hdparent->mem + lba * hdparent->blocksize; - uint8 *end = start + blks * hdparent->blocksize; + uint8 *start = hdparent->mem + lba * parent->GetBlocksize(); + uint8 *end = start + blks * parent->GetBlocksize(); buf.assign(start, end); parent->putlog(1, "READ6 LBA=0x%x blks=0x%x", lba, blks); @@ -272,7 +301,7 @@ class SCSICmdRead6 : public SCSICmd // class SCSICmdWrite6 : public SCSICmd { - typedef SCSICmd inherited; + using inherited = SCSICmd; public: SCSICmdWrite6(SCSITarget *p) : inherited(p) { hdparent = dynamic_cast(parent); @@ -289,7 +318,7 @@ class SCSICmdWrite6 : public SCSICmd if (blks == 0) { blks = 256; } - recvbytes = blks * hdparent->blocksize; + recvbytes = blks * parent->GetBlocksize(); return SCSI::XferPhase::DataOut; } @@ -297,7 +326,7 @@ class SCSICmdWrite6 : public SCSICmd virtual SCSI::XferPhase DoneDataOut() { parent->putlog(1, "WRITE6 LBA=0x%x blks=0x%x", lba, blks); if (hdparent->writeprotect == false) { - memcpy(hdparent->mem + (lba * hdparent->blocksize), + memcpy(hdparent->mem + (lba * parent->GetBlocksize()), buf.data(), buf.size()); } return SCSI::XferPhase::Status; @@ -314,7 +343,7 @@ class SCSICmdWrite6 : public SCSICmd // class SCSICmdInquiry : public SCSICmd { - typedef SCSICmd inherited; + using inherited = SCSICmd; public: SCSICmdInquiry(SCSITarget *p) : inherited(p) { } virtual ~SCSICmdInquiry() { } @@ -337,7 +366,7 @@ class SCSICmdInquiry : public SCSICmd // class SCSICmdModeSelect6 : public SCSICmd { - typedef SCSICmd inherited; + using inherited = SCSICmd; public: SCSICmdModeSelect6(SCSITarget *p) : inherited(p) { } virtual ~SCSICmdModeSelect6() { } @@ -368,18 +397,41 @@ class SCSICmdModeSelect6 : public SCSICm blocksize |= (desc->block_size[2]); // ブロック長を書き戻す - parent->blocksize = blocksize; + parent->SetBlocksize(blocksize); } return SCSI::XferPhase::Status; } }; // +// SCSI コマンド 0x1a ModeSense(6) (共通) +// +class SCSICmdModeSense6 : public SCSICmd +{ + using inherited = SCSICmd; + public: + SCSICmdModeSense6(SCSITarget *p) : inherited(p) { } + virtual ~SCSICmdModeSense6() { } + + virtual SCSI::XferPhase Command(std::vector& cmdseq) { + uint8 pagecode = (cmdseq[2] & 0x3f); + // 未実装 + parent->putlog(1, "ModeSense(6) PageCode $%02x 未実装", pagecode); + return SCSI::XferPhase::Status; + } + + virtual void BeginStatus() { + buf.clear(); + buf.push_back((uint8)SCSI::StatusByte::CheckCondition); + } +}; + +// // SCSI コマンド 0x25 ReadCapacity (ダイレクトアクセスデバイス) // class SCSICmdReadCapacity : public SCSICmd { - typedef SCSICmd inherited; + using inherited = SCSICmd; public: SCSICmdReadCapacity(SCSITarget *p) : inherited(p) { } virtual ~SCSICmdReadCapacity() { } @@ -395,8 +447,8 @@ class SCSICmdReadCapacity : public SCSIC // 応答データは // +00.L 最終論理ブロックアドレス // +04.L ブロック長 - uint32 blksize = hdparent->blocksize; - uint32 lastblk = (hdparent->memlen / blksize) - 1; + uint32 blksize = parent->GetBlocksize(); + uint32 lastblk = (hdparent->GetSize() / blksize) - 1; buf.resize(8); buf[0] = lastblk >> 24; buf[1] = lastblk >> 16; @@ -416,7 +468,7 @@ class SCSICmdReadCapacity : public SCSIC // class SCSICmdRead10 : public SCSICmd { - typedef SCSICmd inherited; + using inherited = SCSICmd; public: SCSICmdRead10(SCSITarget *p) : inherited(p) { } virtual ~SCSICmdRead10() { } @@ -438,8 +490,8 @@ class SCSICmdRead10 : public SCSICmd blks |= cmdseq[8]; // XXX 範囲チェック - uint8 *start = hdparent->mem + lba * hdparent->blocksize; - uint8 *end = start + blks * hdparent->blocksize; + uint8 *start = hdparent->mem + lba * parent->GetBlocksize(); + uint8 *end = start + blks * parent->GetBlocksize(); buf.assign(start, end); parent->putlog(1, "READ10 LBA=0x%x blks=0x%x", lba, blks); @@ -452,7 +504,7 @@ class SCSICmdRead10 : public SCSICmd // class SCSICmdNotSupportedCommand : public SCSICmd { - typedef SCSICmd inherited; + using inherited = SCSICmd; public: SCSICmdNotSupportedCommand(SCSITarget *p) : inherited(p) { } virtual ~SCSICmdNotSupportedCommand() { } @@ -664,13 +716,11 @@ SCSITarget::TransferAckCB() // 悩ましい。 switch (xfer) { case SCSI::XferPhase::DataOut: - cmd->BeginDataOut(); cmd->buf.clear(); bytecount = cmd->recvbytes; putlog(3, "DataOut begin (%d bytes)", bytecount); break; case SCSI::XferPhase::DataIn: - cmd->BeginDataIn(); bytecount = 0; putlog(3, "DataIn begin (%d bytes)", (int)cmd->buf.size()); break; @@ -715,6 +765,10 @@ SCSITarget::DispatchCmd() cmd.reset(new SCSICmdTestUnitReady(this)); break; + case SCSI::Command::RezeroUnit: // 0x01 + cmd.reset(new SCSICmdRezeroUnit(this)); + break; + case SCSI::Command::RequestSense: // 0x03 cmd.reset(new SCSICmdRequestSense(this)); break; @@ -727,6 +781,10 @@ SCSITarget::DispatchCmd() cmd.reset(new SCSICmdModeSelect6(this)); break; + case SCSI::Command::ModeSense6: // 0x1a + cmd.reset(new SCSICmdModeSense6(this)); + break; + case SCSI::Command::ReadCapacity: // 0x25 cmd.reset(new SCSICmdTestUnitReady(this)); break; @@ -756,66 +814,44 @@ SCSIHD::SCSIHD(SCSIHostDevice *h, int id { devname = "SCSIHD"; devtype = SCSI::HD; - fd = -1; - mem = NULL; } // デストラクタ SCSIHD::~SCSIHD() { - if (mem) { - munmap(mem, memlen); - mem = NULL; - } - if (fd >= 0) { - close(fd); - fd = -1; - } } // 初期化 bool SCSIHD::Init() { - struct stat st; - const std::string myname = string_format("%s:ID%d", host->GetConfigName(), myid); - const std::string keybody = string_format("%s_id%d_", + const std::string keybody = string_format("%s-id%d-", host->GetConfigName(), myid); const std::string imgkey = keybody + "image"; const std::string wpkey = keybody + "writeprotect"; - // devtype があって image がないのは異常状態なのでエラー - const std::string& filename = gConfig->ReadStr(imgkey); - if (filename == "") { - gConfig->Err(imgkey, "not specified"); + const ConfigItem& itemimg = gConfig->Find(imgkey); + const std::string& image = itemimg.AsString(); + // ここに来る時にチェックしているので ',' はあるはず + auto pos = image.find(',') + 1; + std::string filename = string_ltrim(image.substr(pos, image.size() - pos)); + if (filename.length() == 0) { + itemimg.Err("imagefile not specified"); return false; } - const std::string path = gConfig->GetConfigDir() + filename; - fd = open(path.c_str(), O_RDWR); - if (fd == -1) { - warn("%s \"%s\" open failed", myname.c_str(), path.c_str()); + // ファイルをオープン + const std::string path = gMainApp.GetVMDir() + filename; + file.SetFilename(path); + file.SetDispname(string_format("%s \"%s\"", myname.c_str(), path.c_str())); + mem = file.OpenFile(); + if (mem == NULL) { return false; } - if (fstat(fd, &st) == -1) { - warn("%s \"%s\" fstat failed", myname.c_str(), path.c_str()); - close(fd); - return false; - } - - memlen = st.st_size; - mem = (uint8 *)mmap(NULL, memlen, PROT_READ | PROT_WRITE, - MAP_SHARED, fd, 0); - if (mem == MAP_FAILED) { - warn("%s \"%s\" mmap failed", myname.c_str(), path.c_str()); - close(fd); - return false; - } - - writeprotect = (bool)gConfig->ReadInt(wpkey); + writeprotect = gConfig->Find(wpkey).AsInt(); if (writeprotect) { putmsg(0, "%s: write protected", myname.c_str()); } @@ -851,6 +887,21 @@ SCSIHD::DispatchCmd() } } +// 指定の場所を自由に読み出す +// (エミュレータ特権アクセス) +bool +SCSIHD::PeekImage(void *buf, uint32 start, uint32 len) const +{ + if (mem == NULL) { + return false; + } + if ((uint64)start + (uint64)len > GetSize()) { + return false; + } + memcpy(buf, mem + start, len); + return true; +} + // HD の inquiry データ /*static*/ std::vector SCSIHD::inquiry_data = { @@ -865,5 +916,5 @@ SCSIHD::inquiry_data = { 'N', 'O', 'N', 'O', ' ', ' ', ' ', ' ', 'S', 'C', 'S', 'I', 'H', 'D', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', - 'r', 'e', 'v', '0', + '0', ' ', ' ', ' ', };