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