|
|
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.9 root 39: SCSIDevice(const std::string& objname_);
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.9 root 132: SCSIHostDevice(const std::string& objname_);
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.10 root 208: SCSITarget(const std::string& objname_, 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.2 root 219: // 論理ブロック長
220: uint32 GetBlocksize() const { return blocksize; }
221: void SetBlocksize(uint32 val) { blocksize = val; }
222:
1.1.1.10 root 223: // ModeSense コマンドのデバイス固有パラメータを返す
224: virtual uint8 GetDeviceSpecificParam() const { return 0; }
225:
1.1.1.4 root 226: // センスキーと ASC/ASCQ
227: uint8 sensekey {};
228: uint16 senseasc {};
229:
230: // センスキーをクリア
231: void ClearSense() {
232: sensekey = 0;
233: senseasc = 0;
234: }
235:
1.1 root 236: // SCSIBus コールバック
237:
1.1.1.4 root 238: // バスリセットされた (全員に通知される)
239: void BusResetCB() override;
240:
1.1 root 241: // セレクションで選択された (ターゲットのみ通知される)
1.1.1.3 root 242: void SelectionCB() override;
1.1 root 243:
244: // 情報転送フェーズを開始する (ターゲットのみ通知される)
1.1.1.3 root 245: void StartTransferCB() override;
1.1 root 246:
247: // 情報転送フェーズで1バイト送受信が進んだ (ターゲットのみ通知される)
1.1.1.3 root 248: void TransferCB() override;
1.1 root 249:
250: // 情報転送フェーズ(マニュアル転送)で ACK を下げた (ターゲットのみ通知)
1.1.1.3 root 251: void TransferAckCB() override;
1.1 root 252:
253: protected:
1.1.1.12! root 254: // SCSI コマンドのディスパッチャ
! 255: virtual void DispatchCmd();
! 256:
1.1 root 257: // ホスト
1.1.1.5 root 258: SCSIHostDevice *host {};
1.1 root 259:
260: // コマンド
261: std::vector<uint8> cmdseq {};
1.1.1.12! root 262:
1.1 root 263: // このコマンドの長さ。
264: // cmdseq の1バイト目で決まるやつのことで、受信目標バイト数。
265: // 今何バイト受信しているかは cmdseq.size()。
1.1.1.5 root 266: int cmdlen {};
1.1 root 267:
268: // 現在実行中の SCSI コマンド
1.1.1.10 root 269: std::unique_ptr<SCSICmd> cmd {};
1.1 root 270:
271: // 現在のフェーズでの転送カウント。
272: // IN と OUT でカウント方向が違うことに注意。
1.1.1.5 root 273: uint32 bytecount {};
1.1 root 274:
275: // 現在処理中のバイトが(各)フェーズの最終バイトなら true
1.1.1.5 root 276: bool lastbyte {};
1.1 root 277:
1.1.1.10 root 278: // 論理ブロック長
279: uint32 blocksize {};
1.1 root 280: };
281:
282: //
1.1.1.10 root 283: // SCSI Disk (HD,CD,...)
1.1 root 284: //
1.1.1.10 root 285: class SCSIDisk : public SCSITarget
1.1 root 286: {
1.1.1.3 root 287: using inherited = SCSITarget;
1.1 root 288: public:
1.1.1.10 root 289: // メディアへの書き込みモード
290: //
291: // Device Media Ignore
292: // RO (RO) * ReadOnly
293: // RW RO * WriteProtect
294: // RW RW no Writeable
295: // RW RW yes WriteIgnore
296: enum class RW {
297: ReadOnly = 2, // 読み込み専用デバイス
298: WriteProtect = 1, // 書き込み禁止メディア
299: Writeable = 0, // 書き込み可能
300: WriteIgnore = -1, // 書き込み可能メディアで書き込みを無視
301: };
302:
303: public:
304: SCSIDisk(SCSIHostDevice *h, int id, SCSI::DevType type);
305: virtual ~SCSIDisk() override;
1.1 root 306:
1.1.1.3 root 307: bool Init() override;
1.1.1.12! root 308: void ResetHard(bool poweron) override;
1.1.1.10 root 309:
1.1.1.3 root 310: void DispatchCmd() override;
1.1.1.10 root 311: bool Inquiry(std::vector<uint8>& buf, int lun) override;
312:
313: // ModeSense コマンドのデバイス固有パラメータを返す
314: uint8 GetDeviceSpecificParam() const override;
315:
316: // buf にデータを読み込む。
317: // 単位はセクタではなくバイトなことに注意。
318: bool Read(std::vector<uint8>& buf, uint64 start);
319:
320: // buf のデータを書き込む。
321: // 単位はセクタではなくバイトなことに注意。
322: bool Write(const std::vector<uint8>& buf, uint64 start);
1.1 root 323:
1.1.1.10 root 324: // このデバイスのバイトサイズ
325: off_t GetSize() const;
326:
327: // このデバイスをディスクイメージだと思うとして (いや実際そうだけど)
1.1.1.2 root 328: // 先頭から start バイト目から len バイト読み出して返す。
329: // 単位はセクタではなくバイトなことに注意。
330: // (エミュレータ特権アクセス)
1.1.1.10 root 331: bool Peek(void *buf, uint64 start, uint32 len) const;
332:
333: // シーク時間[nsec]
334: uint64 GetSeekTime() const { return seektime; }
335:
336: // リムーバブルデバイスなら true
337: bool IsRemovableDevice() const { return removable_device; }
338:
339: // 書き込み可能デバイスなら true
340: bool IsWriteableDevice() const { return writeable_device; }
341:
342: // メディアが入っていれば true
343: bool IsMediumLoaded() const { return medium_loaded; }
1.1.1.2 root 344:
1.1.1.10 root 345: // メディアの書き込みモードを返す
346: RW GetWriteMode() const { return write_mode; }
1.1.1.12! root 347: // メディアの書き込みモードを文字列で返す (モニタ用)
! 348: const char *GetWriteModeStr() const;
1.1.1.5 root 349:
1.1.1.10 root 350: // メディア(ディスク)イメージを開く/閉じる。(同一スレッドから呼ぶこと)
351: bool LoadDisk(const std::string& path_);
352: void UnloadDisk(bool force = false);
353:
354: // メディア(ディスク)イメージを開く/閉じる。(UI スレッドから呼ぶ)
355: void LoadDiskUI(const std::string& path_);
356: void UnloadDiskUI(bool force);
357:
358: // メディアの取り出し可否
359: bool IsMediumRemovalPrevented() const { return medium_removal_prevented; }
360: bool IsMediumRemovalAllowed() const { return !medium_removal_prevented; }
361: void PreventMediumRemoval(bool val);
362:
363: // イメージファイルのフルパスを返す
364: const std::string& GetPathName() const { return pathname; }
365:
366: // SCSIBus コールバック
367:
368: // バスリセットされた (全員に通知される)
369: void BusResetCB() override;
1.1.1.9 root 370:
1.1 root 371: private:
1.1.1.10 root 372: // ディスクイメージを閉じる (内部用)
373: bool UnloadDisk_internal();
374:
375: // ディスク状態をクリアする
376: void Clear();
377:
378: // メディア状態変更を UI に通知する
379: void MediaChanged() const;
380:
381: // メディア挿入/排出コールバック
1.1.1.12! root 382: void LoadCallback(MessageID, uint32);
! 383: void UnloadCallback(MessageID, uint32);
1.1.1.10 root 384:
385: // イメージファイルのフルパス
386: std::string pathname {};
387: // 新しいイメージファイルのフルパス (UIから)
388: std::string new_pathname {};
389:
390: // イメージファイル
1.1.1.11 root 391: DiskImage image {};
1.1.1.10 root 392:
393: bool removable_device {}; // リムーバブルデバイスなら true
394: bool writeable_device {}; // 書き込み可能なデバイスなら true
395: bool write_ignore {}; // 書き込み無視オプション
396: bool medium_loaded {}; // メディアが挿入されていれば true
397:
398: // メディアの書き込みモード
399: RW write_mode {};
400:
401: // メディアの取り出しを禁止するなら true。
402: // XXX Bus Device Reset メッセージでも解除できるがメッセージは未実装
403: bool medium_removal_prevented {};
404:
1.1.1.5 root 405: uint64 seektime {};
1.1 root 406: };
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.