|
|
1.1 root 1: //
2: // nono
1.1.1.3 root 3: // Copyright (C) 2020 nono project
4: // Licensed under nono-license.txt
1.1 root 5: //
6:
1.1.1.12 root 7: //
8: // SCSI デバイス
9: //
1.1 root 10:
1.1.1.17 root 11: // Device Device
12: // | |
13: // v v
14: // IODevice SCSIDevice (SCSI デバイスとしての共通部分)
15: // | |
16: // v +-----+------+
17: // SPCDevice v v
18: // .scsi -> SCSIHostDevice SCSITarget (SCSI ホスト/ターゲットの共通部分)
19: // |
20: // v
21: // SCSIDisk (各デバイス、各ターゲット固有部分)
1.1 root 22:
1.1.1.12 root 23: #pragma once
24:
25: #include "diskimage.h"
26: #include "message.h"
27: #include "scsibus.h"
28: #include "scsicmd.h"
29:
1.1.1.18! root 30: class SCSIDomain;
! 31:
1.1 root 32: //
33: // SCSI デバイスとしての共通部分。
34: //
1.1.1.17 root 35: class SCSIDevice : public Device
1.1 root 36: {
1.1.1.17 root 37: using inherited = Device;
1.1 root 38: public:
1.1.1.17 root 39: explicit SCSIDevice(uint objid_);
1.1.1.16 root 40: ~SCSIDevice() override;
1.1 root 41:
1.1.1.5 root 42: // SCSI ID を返す
1.1.1.17 root 43: uint GetMyID() const { return myid; }
1.1.1.5 root 44:
45: // デバイス種別を返す (主にデバッグ表示用)
46: SCSI::DevType GetDevType() const { return devtype; }
47:
1.1.1.18! root 48: // バスに接続する。
! 49: void Attach(SCSIBus *bus_);
! 50:
1.1.1.17 root 51: // 自身が接続しているバスを返す。
52: // イニシエータがバスに接続するのは VM 実行後なことに注意。
53: SCSIBus *GetBus() const { return bus; }
54:
1.1 root 55: //
56: // 信号線制御
57: // (ソースコード的なショートカットのため)
58: //
59: bool GetRST() const { return bus->GetRST(); }
60: void AssertRST() { bus->AssertRST(); }
61: void NegateRST() { bus->NegateRST(); }
62: bool GetREQ() const { return bus->GetREQ(); }
63: void AssertREQ() { bus->AssertREQ(); }
64: void NegateREQ() { bus->NegateREQ(); }
65: bool GetACK() const { return bus->GetACK(); }
66: void AssertACK() { bus->AssertACK(); }
67: void NegateACK() { bus->NegateACK(); }
68: bool GetATN() const { return bus->GetATN(); }
69: void AssertATN() { bus->AssertATN(); }
70: void NegateATN() { bus->NegateATN(); }
71: uint8 GetSEL() const { return bus->GetSEL(); }
72: void AssertSEL() { bus->AssertSEL(myid); }
73: void NegateSEL() { bus->NegateSEL(myid); }
74: uint8 GetBSY() const { return bus->GetBSY(); }
75: void AssertBSY() { bus->AssertBSY(myid); }
76: void NegateBSY() { bus->NegateBSY(myid); }
77: bool GetMSG() const { return bus->GetMSG(); }
78: bool GetCD() const { return bus->GetCD(); }
79: bool GetIO() const { return bus->GetIO(); }
80: SCSI::XferPhase GetXfer() const { return bus->GetXfer(); }
81: void SetXfer(uint8 val) { bus->SetXfer(val); }
82: SCSI::Phase GetPhase() const { return bus->GetPhase(); }
83: uint8 GetData() const { return bus->GetData(); }
84: void SetData(uint8 val) const { bus->SetData(val); }
85:
86: //
1.1.1.17 root 87: // SCSIBus から呼ばれる
1.1 root 88: //
89:
90: // バスリセットされた (全員に通知される)
1.1.1.17 root 91: virtual void OnBusReset() { }
1.1 root 92:
93: // バスフリーになった (全員に通知される)
1.1.1.17 root 94: virtual void OnBusFree(uint id) { }
1.1 root 95:
96: // セレクションで選択された (ターゲットのみ通知される)
1.1.1.17 root 97: virtual void OnSelected() { }
1.1 root 98:
99: // ターゲットがセレクションに応答した (イニシエータのみ通知される)
1.1.1.17 root 100: virtual void OnSelectionAck() { }
1.1 root 101:
102: // 情報転送フェーズを開始する (ターゲットのみ通知される)
1.1.1.17 root 103: virtual void OnStartTransfer() { }
1.1 root 104:
105: // 情報転送フェーズで REQ を立てた (イニシエータのみ通知される)
1.1.1.17 root 106: virtual void OnTransferReq() { }
1.1 root 107:
108: // 情報転送フェーズで1バイト送受信が進んだ (ターゲットのみ通知される)
1.1.1.17 root 109: virtual void OnTransfer() { }
1.1 root 110:
111: // 情報転送フェーズ(マニュアル転送)で ACK を下げた (ターゲットのみ通知)
1.1.1.17 root 112: virtual void OnTransferAck() { }
1.1 root 113:
114: protected:
115: // 自身の ID
1.1.1.5 root 116: uint myid {};
117:
118: // デバイス種別
119: SCSI::DevType devtype {};
1.1 root 120:
1.1.1.18! root 121: // あれば自身が繋がっているバスへのポインタ。
! 122: // (イニシエータ自身も含めて) 所有ではない。
1.1.1.5 root 123: SCSIBus *bus {};
1.1.1.18! root 124:
! 125: // 自身を管理しているドメイン(親) へのポインタ。
! 126: SCSIDomain *domain {};
1.1 root 127: };
128:
129: //
130: // ホストデバイスの共通部分。
1.1.1.17 root 131: // イニシエータもしくは HBA (ホストバスアダプタ) に相当する部分。
1.1 root 132: //
133: class SCSIHostDevice : public SCSIDevice
134: {
1.1.1.9 root 135: using inherited = SCSIDevice;
1.1.1.17 root 136:
1.1 root 137: public:
1.1.1.17 root 138: using SCSIHostCallback_t = void (Device::*)();
139: using BusFreeCallback_t = void (Device::*)(uint);
140: #define ToSCSIHostCallback(f) \
141: static_cast<SCSIHostDevice::SCSIHostCallback_t>(f)
142: #define ToBusFreeCallback(f) \
143: static_cast<SCSIHostDevice::BusFreeCallback_t>(f)
144:
145: public:
1.1.1.18! root 146: SCSIHostDevice(SCSIDomain *domain_, IODevice *parent_);
1.1.1.16 root 147: ~SCSIHostDevice() override;
1.1 root 148:
1.1.1.18! root 149: // SCSI ID を設定する。(SCSIDomain からのみ呼ぶこと)
! 150: void SetID(uint myid_);
1.1 root 151:
1.1.1.18! root 152: // SCSIBus からのコールバック関数を設定する。
! 153: void SetBusCallback(
1.1.1.17 root 154: BusFreeCallback_t busfree_,
155: SCSIHostCallback_t selack_,
156: SCSIHostCallback_t xferreq_);
1.1 root 157:
1.1.1.17 root 158: private:
159: // SCSIBus から呼ばれる
1.1.1.10 root 160:
1.1.1.17 root 161: // バスフリーになった (SCSIBus から全員に通知される)
162: void OnBusFree(uint id) override;
163: // ターゲットがセレクションに応答した (SCSIBus から呼ばれる)
164: void OnSelectionAck() override;
165: // 情報転送フェーズで REQ を立てた (イニシエータのみ通知される)
166: void OnTransferReq() override;
1.1.1.8 root 167:
1.1.1.17 root 168: // 親クラス(コントローラ) へのコールバック。
1.1.1.10 root 169:
1.1.1.17 root 170: // バスフリーを通知する
171: BusFreeCallback_t BusFreeCallback {};
172: // ターゲットがセレクションに応答したことを通知する
173: SCSIHostCallback_t SelectionAckCallback {};
174: // 転送フェーズでターゲットが REQ を立てたことを通知する
175: SCSIHostCallback_t TransferReqCallback {};
1.1 root 176:
1.1.1.17 root 177: // コントローラデバイス。
178: IODevice *parent {};
1.1 root 179: };
180:
181: //
182: // ターゲットデバイスの共通部分。
183: //
184: class SCSITarget : public SCSIDevice
185: {
1.1.1.3 root 186: using inherited = SCSIDevice;
1.1 root 187: public:
1.1.1.18! root 188: SCSITarget(SCSIDomain *, uint id);
1.1.1.16 root 189: ~SCSITarget() override;
1.1 root 190:
1.1.1.12 root 191: void ResetHard(bool poweron) override;
1.1.1.8 root 192:
1.1.1.10 root 193: // Inquiry データを返す (Cmd から呼ばれる)
1.1.1.17 root 194: virtual bool Inquiry(std::vector<uint8>& buf, uint lun) = 0;
1.1 root 195:
196: // 現在のコマンド列を返す (モニタ用)
197: std::vector<uint8> GetCmdSeq() const { return cmdseq; }
198:
1.1.1.18! root 199: // コマンド列から SCSICmd を選択する。
! 200: // (VirtIOSCSI と ROM30 エミュレーションから使う)
1.1.1.13 root 201: SCSICmd *SelectCommand(const std::vector<uint8>& cmdseq_);
202:
1.1.1.2 root 203: // 論理ブロック長
204: uint32 GetBlocksize() const { return blocksize; }
205: void SetBlocksize(uint32 val) { blocksize = val; }
206:
1.1.1.10 root 207: // ModeSense コマンドのデバイス固有パラメータを返す
208: virtual uint8 GetDeviceSpecificParam() const { return 0; }
209:
1.1.1.18! root 210: // センスキー
1.1.1.4 root 211: uint8 sensekey {};
1.1.1.18! root 212: // 上位バイトが ASC、下位バイトが ASCQ
1.1.1.4 root 213: uint16 senseasc {};
214:
215: // センスキーをクリア
216: void ClearSense() {
217: sensekey = 0;
218: senseasc = 0;
219: }
220:
1.1.1.17 root 221: // SCSIBus から呼ばれる
1.1 root 222:
1.1.1.4 root 223: // バスリセットされた (全員に通知される)
1.1.1.17 root 224: void OnBusReset() override;
1.1.1.4 root 225:
1.1 root 226: // セレクションで選択された (ターゲットのみ通知される)
1.1.1.17 root 227: void OnSelected() override;
1.1 root 228:
229: // 情報転送フェーズを開始する (ターゲットのみ通知される)
1.1.1.17 root 230: void OnStartTransfer() override;
1.1 root 231:
232: // 情報転送フェーズで1バイト送受信が進んだ (ターゲットのみ通知される)
1.1.1.17 root 233: void OnTransfer() override;
1.1 root 234:
235: // 情報転送フェーズ(マニュアル転送)で ACK を下げた (ターゲットのみ通知)
1.1.1.17 root 236: void OnTransferAck() override;
1.1 root 237:
238: protected:
1.1.1.18! root 239: // SCSI コマンドを選択する。内部用。
! 240: void SelectCommand();
! 241:
1.1.1.12 root 242: // SCSI コマンドのディスパッチャ
243: virtual void DispatchCmd();
244:
1.1 root 245: // コマンド
246: std::vector<uint8> cmdseq {};
1.1.1.12 root 247:
1.1 root 248: // このコマンドの長さ。
249: // cmdseq の1バイト目で決まるやつのことで、受信目標バイト数。
250: // 今何バイト受信しているかは cmdseq.size()。
1.1.1.17 root 251: uint cmdlen {};
1.1 root 252:
253: // 現在実行中の SCSI コマンド
1.1.1.10 root 254: std::unique_ptr<SCSICmd> cmd {};
1.1 root 255:
256: // 現在のフェーズでの転送カウント。
257: // IN と OUT でカウント方向が違うことに注意。
1.1.1.5 root 258: uint32 bytecount {};
1.1 root 259:
260: // 現在処理中のバイトが(各)フェーズの最終バイトなら true
1.1.1.5 root 261: bool lastbyte {};
1.1 root 262:
1.1.1.10 root 263: // 論理ブロック長
264: uint32 blocksize {};
1.1 root 265: };
266:
267: //
1.1.1.10 root 268: // SCSI Disk (HD,CD,...)
1.1 root 269: //
1.1.1.10 root 270: class SCSIDisk : public SCSITarget
1.1 root 271: {
1.1.1.3 root 272: using inherited = SCSITarget;
1.1 root 273: public:
1.1.1.10 root 274: // メディアへの書き込みモード
275: //
276: // Device Media Ignore
277: // RO (RO) * ReadOnly
278: // RW RO * WriteProtect
279: // RW RW no Writeable
280: // RW RW yes WriteIgnore
281: enum class RW {
282: ReadOnly = 2, // 読み込み専用デバイス
283: WriteProtect = 1, // 書き込み禁止メディア
284: Writeable = 0, // 書き込み可能
285: WriteIgnore = -1, // 書き込み可能メディアで書き込みを無視
286: };
287:
288: public:
1.1.1.18! root 289: SCSIDisk(SCSIDomain *, uint id, SCSI::DevType type);
1.1.1.16 root 290: ~SCSIDisk() override;
1.1 root 291:
1.1.1.3 root 292: bool Init() override;
1.1.1.12 root 293: void ResetHard(bool poweron) override;
1.1.1.10 root 294:
1.1.1.3 root 295: void DispatchCmd() override;
1.1.1.17 root 296: bool Inquiry(std::vector<uint8>& buf, uint lun) override;
1.1.1.10 root 297:
298: // ModeSense コマンドのデバイス固有パラメータを返す
299: uint8 GetDeviceSpecificParam() const override;
300:
301: // buf にデータを読み込む。
302: // 単位はセクタではなくバイトなことに注意。
303: bool Read(std::vector<uint8>& buf, uint64 start);
304:
305: // buf のデータを書き込む。
306: // 単位はセクタではなくバイトなことに注意。
307: bool Write(const std::vector<uint8>& buf, uint64 start);
1.1 root 308:
1.1.1.10 root 309: // このデバイスのバイトサイズ
310: off_t GetSize() const;
311:
312: // このデバイスをディスクイメージだと思うとして (いや実際そうだけど)
1.1.1.2 root 313: // 先頭から start バイト目から len バイト読み出して返す。
314: // 単位はセクタではなくバイトなことに注意。
315: // (エミュレータ特権アクセス)
1.1.1.10 root 316: bool Peek(void *buf, uint64 start, uint32 len) const;
317:
318: // シーク時間[nsec]
319: uint64 GetSeekTime() const { return seektime; }
320:
321: // リムーバブルデバイスなら true
322: bool IsRemovableDevice() const { return removable_device; }
323:
324: // 書き込み可能デバイスなら true
325: bool IsWriteableDevice() const { return writeable_device; }
326:
327: // メディアが入っていれば true
328: bool IsMediumLoaded() const { return medium_loaded; }
1.1.1.2 root 329:
1.1.1.10 root 330: // メディアの書き込みモードを返す
331: RW GetWriteMode() const { return write_mode; }
1.1.1.12 root 332: // メディアの書き込みモードを文字列で返す (モニタ用)
333: const char *GetWriteModeStr() const;
1.1.1.5 root 334:
1.1.1.10 root 335: // メディア(ディスク)イメージを開く/閉じる。(同一スレッドから呼ぶこと)
336: bool LoadDisk(const std::string& path_);
337: void UnloadDisk(bool force = false);
338:
339: // メディア(ディスク)イメージを開く/閉じる。(UI スレッドから呼ぶ)
340: void LoadDiskUI(const std::string& path_);
341: void UnloadDiskUI(bool force);
342:
343: // メディアの取り出し可否
344: bool IsMediumRemovalPrevented() const { return medium_removal_prevented; }
345: bool IsMediumRemovalAllowed() const { return !medium_removal_prevented; }
346: void PreventMediumRemoval(bool val);
347:
348: // イメージファイルのフルパスを返す
349: const std::string& GetPathName() const { return pathname; }
350:
1.1.1.17 root 351: // SCSIBus から呼ばれる
1.1.1.10 root 352:
353: // バスリセットされた (全員に通知される)
1.1.1.17 root 354: void OnBusReset() override;
1.1.1.9 root 355:
1.1 root 356: private:
1.1.1.10 root 357: // ディスクイメージを閉じる (内部用)
358: bool UnloadDisk_internal();
359:
360: // ディスク状態をクリアする
361: void Clear();
362:
363: // メディア状態変更を UI に通知する
364: void MediaChanged() const;
365:
366: // メディア挿入/排出コールバック
1.1.1.16 root 367: void LoadMessage(MessageID, uint32);
368: void UnloadMessage(MessageID, uint32);
1.1.1.10 root 369:
370: // イメージファイルのフルパス
371: std::string pathname {};
372: // 新しいイメージファイルのフルパス (UIから)
373: std::string new_pathname {};
374:
375: // イメージファイル
1.1.1.11 root 376: DiskImage image {};
1.1.1.10 root 377:
378: bool removable_device {}; // リムーバブルデバイスなら true
379: bool writeable_device {}; // 書き込み可能なデバイスなら true
380: bool write_ignore {}; // 書き込み無視オプション
381: bool medium_loaded {}; // メディアが挿入されていれば true
382:
383: // メディアの書き込みモード
384: RW write_mode {};
385:
386: // メディアの取り出しを禁止するなら true。
387: // XXX Bus Device Reset メッセージでも解除できるがメッセージは未実装
388: bool medium_removal_prevented {};
389:
1.1.1.5 root 390: uint64 seektime {};
1.1 root 391: };
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.