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