|
|
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:
1.1.1.19 root 256: // コマンド前のメッセージアウトフェーズ。
257: std::vector<uint8> msgseq {};
258:
1.1 root 259: // 現在のフェーズでの転送カウント。
260: // IN と OUT でカウント方向が違うことに注意。
1.1.1.5 root 261: uint32 bytecount {};
1.1 root 262:
263: // 現在処理中のバイトが(各)フェーズの最終バイトなら true
1.1.1.5 root 264: bool lastbyte {};
1.1 root 265:
1.1.1.10 root 266: // 論理ブロック長
267: uint32 blocksize {};
1.1 root 268: };
269:
270: //
1.1.1.10 root 271: // SCSI Disk (HD,CD,...)
1.1 root 272: //
1.1.1.10 root 273: class SCSIDisk : public SCSITarget
1.1 root 274: {
1.1.1.3 root 275: using inherited = SCSITarget;
1.1 root 276: public:
1.1.1.10 root 277: // メディアへの書き込みモード
278: //
279: // Device Media Ignore
280: // RO (RO) * ReadOnly
281: // RW RO * WriteProtect
282: // RW RW no Writeable
283: // RW RW yes WriteIgnore
284: enum class RW {
285: ReadOnly = 2, // 読み込み専用デバイス
286: WriteProtect = 1, // 書き込み禁止メディア
287: Writeable = 0, // 書き込み可能
288: WriteIgnore = -1, // 書き込み可能メディアで書き込みを無視
289: };
290:
291: public:
1.1.1.18 root 292: SCSIDisk(SCSIDomain *, uint id, SCSI::DevType type);
1.1.1.16 root 293: ~SCSIDisk() override;
1.1 root 294:
1.1.1.3 root 295: bool Init() override;
1.1.1.12 root 296: void ResetHard(bool poweron) override;
1.1.1.10 root 297:
1.1.1.3 root 298: void DispatchCmd() override;
1.1.1.17 root 299: bool Inquiry(std::vector<uint8>& buf, uint lun) override;
1.1.1.10 root 300:
301: // ModeSense コマンドのデバイス固有パラメータを返す
302: uint8 GetDeviceSpecificParam() const override;
303:
304: // buf にデータを読み込む。
305: // 単位はセクタではなくバイトなことに注意。
306: bool Read(std::vector<uint8>& buf, uint64 start);
307:
308: // buf のデータを書き込む。
309: // 単位はセクタではなくバイトなことに注意。
310: bool Write(const std::vector<uint8>& buf, uint64 start);
1.1 root 311:
1.1.1.10 root 312: // このデバイスのバイトサイズ
313: off_t GetSize() const;
314:
315: // このデバイスをディスクイメージだと思うとして (いや実際そうだけど)
1.1.1.2 root 316: // 先頭から start バイト目から len バイト読み出して返す。
317: // 単位はセクタではなくバイトなことに注意。
318: // (エミュレータ特権アクセス)
1.1.1.10 root 319: bool Peek(void *buf, uint64 start, uint32 len) const;
320:
1.1.1.20! root 321: // シーク時間[tsec]
1.1.1.10 root 322: uint64 GetSeekTime() const { return seektime; }
323:
324: // リムーバブルデバイスなら true
325: bool IsRemovableDevice() const { return removable_device; }
326:
327: // 書き込み可能デバイスなら true
328: bool IsWriteableDevice() const { return writeable_device; }
329:
330: // メディアが入っていれば true
331: bool IsMediumLoaded() const { return medium_loaded; }
1.1.1.2 root 332:
1.1.1.10 root 333: // メディアの書き込みモードを返す
334: RW GetWriteMode() const { return write_mode; }
1.1.1.12 root 335: // メディアの書き込みモードを文字列で返す (モニタ用)
336: const char *GetWriteModeStr() const;
1.1.1.5 root 337:
1.1.1.10 root 338: // メディア(ディスク)イメージを開く/閉じる。(同一スレッドから呼ぶこと)
339: bool LoadDisk(const std::string& path_);
340: void UnloadDisk(bool force = false);
341:
342: // メディア(ディスク)イメージを開く/閉じる。(UI スレッドから呼ぶ)
343: void LoadDiskUI(const std::string& path_);
344: void UnloadDiskUI(bool force);
345:
346: // メディアの取り出し可否
347: bool IsMediumRemovalPrevented() const { return medium_removal_prevented; }
348: bool IsMediumRemovalAllowed() const { return !medium_removal_prevented; }
349: void PreventMediumRemoval(bool val);
350:
1.1.1.19 root 351: // 現在ロードされているイメージファイルのフルパスを返す
1.1.1.10 root 352: const std::string& GetPathName() const { return pathname; }
353:
1.1.1.17 root 354: // SCSIBus から呼ばれる
1.1.1.10 root 355:
356: // バスリセットされた (全員に通知される)
1.1.1.17 root 357: void OnBusReset() override;
1.1.1.9 root 358:
1.1 root 359: private:
1.1.1.10 root 360: // ディスクイメージを閉じる (内部用)
361: bool UnloadDisk_internal();
362:
363: // ディスク状態をクリアする
364: void Clear();
365:
366: // メディア状態変更を UI に通知する
367: void MediaChanged() const;
368:
369: // メディア挿入/排出コールバック
1.1.1.16 root 370: void LoadMessage(MessageID, uint32);
371: void UnloadMessage(MessageID, uint32);
1.1.1.10 root 372:
373: // イメージファイルのフルパス
374: std::string pathname {};
375: // 新しいイメージファイルのフルパス (UIから)
376: std::string new_pathname {};
377:
378: // イメージファイル
1.1.1.11 root 379: DiskImage image {};
1.1.1.10 root 380:
381: bool removable_device {}; // リムーバブルデバイスなら true
382: bool writeable_device {}; // 書き込み可能なデバイスなら true
383: bool write_ignore {}; // 書き込み無視オプション
384: bool medium_loaded {}; // メディアが挿入されていれば true
385:
386: // メディアの書き込みモード
387: RW write_mode {};
388:
389: // メディアの取り出しを禁止するなら true。
390: // XXX Bus Device Reset メッセージでも解除できるがメッセージは未実装
391: bool medium_removal_prevented {};
392:
1.1.1.5 root 393: uint64 seektime {};
1.1 root 394: };
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.