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