|
|
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: #include "scsidev.h"
1.1.1.2 root 10: #include "config.h"
11: #include "mainapp.h"
1.1 root 12:
13: //
14: // SCSI デバイス
15: //
16:
17: // コンストラクタ
1.1.1.10! root 18: SCSIDevice::SCSIDevice(const std::string& objname_)
! 19: : inherited(objname_)
1.1 root 20: {
21: }
22:
23: // デストラクタ
24: SCSIDevice::~SCSIDevice()
25: {
26: }
27:
28: //
29: // SCSI ホストデバイス
30: //
31:
32: // コンストラクタ
1.1.1.10! root 33: SCSIHostDevice::SCSIHostDevice(const std::string& objname_)
! 34: : inherited(objname_)
1.1 root 35: {
1.1.1.5 root 36: devtype = SCSI::DevType::Initiator;
37:
1.1 root 38: // バスデバイスを作成する。
39: // ただし自身がバスに参加するのは継承側で行う
40: // (例えば SPC なら BDID 書き込みで ID が決まった後、など)。
41: scsibus.reset(new SCSIBus());
42: }
43:
44: // デストラクタ
45: SCSIHostDevice::~SCSIHostDevice()
46: {
47: }
48:
1.1.1.2 root 49: // 設定ファイルに使われるこのホストデバイスを示す接頭語を設定する
50: // (継承クラス側のコンストラクタで config_name を設定後に呼ぶこと)
51: void
52: SCSIHostDevice::SetConfigName(const char *name_)
53: {
54: config_name = name_;
55: }
56:
1.1 root 57: bool
58: SCSIHostDevice::Create()
59: {
60: // 設定を読み込む。
61: for (int id = 0; id < 8; id++) {
1.1.1.2 root 62: const std::string key = string_format("%s-id%d-image",
1.1 root 63: GetConfigName(), id);
1.1.1.3 root 64: const ConfigItem& item = gConfig->Find(key);
1.1.1.2 root 65: const std::string& image = item.AsString();
66:
67: // 空ならデバイスなし
68: if (image.length() == 0) {
1.1.1.5 root 69: // 未接続部分のパラメータは減らしておくか。
70: // --show-config するとさすがに無駄に多くて邪魔なので。
71: const std::string wpkey = string_format("%s-id%d-writeprotect",
72: GetConfigName(), id);
73: const std::string stkey = string_format("%s-id%d-seektime",
74: GetConfigName(), id);
75: gConfig->Delete(wpkey);
76: gConfig->Delete(stkey);
1.1.1.2 root 77: continue;
78: }
79:
80: // ',' より前がデバイス種別 (ここではパスは不要)
81: auto pos = image.find(',');
82: if (pos == std::string::npos) {
83: item.Err("no device type specified");
84: return false;
85: }
86: std::string type = string_tolower(image.substr(0, pos));
87:
88: if (type == "hd") {
1.1 root 89: target[id].reset(new SCSIHD(this, id));
90: scsibus->Attach(target[id].get(), id);
1.1.1.2 root 91: } else {
92: item.Err("invaild device type '%s'", type.c_str());
1.1 root 93: }
94: }
95:
96: return true;
97: }
98:
99: bool
100: SCSIHostDevice::Init()
101: {
102: // 初期化ではないけどログレベルがセットできたここでデバッグ表示。
103: // -L オプションの処理は Create() の後なので。
104:
105: if (loglevel >= 1) {
106: for (int id = 0; id < 8; id++) {
107: std::string typestr;
108: if (target[id]) {
109: switch (target[id]->GetDevType()) {
1.1.1.5 root 110: default:
1.1 root 111: break;
1.1.1.4 root 112: case SCSI::DevType::HD:
1.1 root 113: typestr = "HD";
114: break;
115: }
116: }
117: if (!typestr.empty()) {
1.1.1.8 root 118: putmsgn("%s target #%d %s", GetConfigName(), id,
1.1 root 119: typestr.c_str());
120: }
121: }
122: }
123:
124: return true;
125: }
126:
127: // バスフリーコールバック (SCSIBus から呼ばれる)
128: void
129: SCSIHostDevice::BusFreeCB(int id)
130: {
131: // 実際にはバスフリーを検出したデバイスは各自自身が送出している信号を
132: // 下げるのだが、色々面倒なので、ここではホストのバスフリーコールバックが
133: // 一括して全部の線を下げる。
134: // ただしさすがにログがうるさいので、上がってる線だけ下げる。
135:
136: uint32 data;
137: while ((data = GetBSY()) != 0) {
138: bus->NegateBSY(DecodeID(data));
139: }
140: while ((data = GetSEL()) != 0) {
141: bus->NegateSEL(DecodeID(data));
142: }
143: if (GetREQ()) {
144: NegateREQ();
145: }
146: if (GetACK()) {
147: NegateACK();
148: }
149: if (GetATN()) {
150: NegateATN();
151: }
152: SetXfer(0);
153: SetData(0);
154: }
155:
1.1.1.6 root 156: #if defined(__clang__)
157: // デストラクタがインラインで書けないのは面倒なのでとりあえず
158: #pragma clang diagnostic push
159: #pragma clang diagnostic ignored "-Wweak-vtables"
160: #endif
161:
1.1 root 162: //
163: // SCSI コマンドの共通部分
164: //
165: class SCSICmd
166: {
167: public:
168: SCSICmd(SCSITarget *p) {
169: parent = p;
170: }
171: virtual ~SCSICmd() { }
172:
173: // 転送バッファと転送バイト数。
174: // IN (ターゲットが送出側)なら、各フェーズ開始までに送出バイト数分の
175: // バッファを buf に用意すること。recvbytes は操作不要。
176: //
177: // OUT(ターゲットが受信側)なら、各フェーズ開始前までに受信バイト数を
178: // recvbytes にセットすること。buf は操作不要。
179: // なお parent は OUT(受信)フェーズ中にこの recvbytes を変更しない。
180: std::vector<uint8> buf;
181: uint32 recvbytes;
182:
1.1.1.5 root 183: // このコマンドの動作時間 [nsec]
184: // シークタイムとかを簡易的に再現するため、次フェーズ遷移時の最初の
185: // REQ アサートを引き延ばすために使う。
186: // 主にコマンドフェーズで使うことになると思う。
187: uint64 optime {};
188:
1.1 root 189: // 以下いずれも戻り値は遷移先のフェーズ。
190:
191: // コマンドフェーズを処理する。
1.1.1.4 root 192: // コマンドが確定したところで呼ばれる。戻り値に遷移先フェーズを返すこと。
193: // また、コマンド開始時に各自で ClearSense() を呼ぶこと。センスというか
194: // CA 状態は次のコマンド実行でクリアされるが (ネクサスはとりあえず無視)、
195: // RequestSense の場合は現在保持しているセンス情報をホストに返すので、
196: // つまり RequestSense 以外のコマンドが全員各自でクリアする必要がある。
1.1 root 197: virtual SCSI::XferPhase Command(std::vector<uint8>& cmdseq) {
1.1.1.4 root 198: parent->ClearSense();
1.1 root 199: return SCSI::XferPhase::Status;
200: }
201:
202: // データインフェーズを完了する。
203: virtual SCSI::XferPhase DoneDataIn() { return SCSI::XferPhase::Status; }
204:
205: // データアウトフェーズを完了する。
206: virtual SCSI::XferPhase DoneDataOut() { return SCSI::XferPhase::Status; }
207:
208: // ステータスフェーズを開始する。
1.1.1.4 root 209: void BeginStatus() {
1.1 root 210: buf.clear();
1.1.1.4 root 211: buf.push_back(status_byte);
1.1 root 212: }
213:
214: // ステータスフェーズを完了する。
215: virtual SCSI::XferPhase DoneStatus() { return SCSI::XferPhase::MsgIn; }
216:
217: // メッセージインフェーズを開始する。
218: // デフォルトでは Command Complete を返す実装を用意しておく。
219: virtual void BeginMsgIn() {
220: buf.clear();
221: buf.push_back((uint8)SCSI::MsgByte::CommandComplete);
222: }
223:
224: // メッセージインフェーズを完了する。
225: virtual SCSI::XferPhase DoneMsgIn() { return SCSI::XferPhase::End; }
226:
227: // メッセージアウトフェーズを開始する。
228: virtual void BeginMsgOut() { }
229:
230: // メッセージアウトフェーズを完了する。
231: virtual SCSI::XferPhase DoneMsgOut() { return SCSI::XferPhase::End; }
232:
233: protected:
234: // このコマンドを実行しているターゲットデバイス。
235: SCSITarget *parent;
1.1.1.4 root 236:
237: // ステータスバイト (デフォルトは 0 = Good)
238: uint8 status_byte {};
1.1 root 239: };
240:
241: //
242: // SCSI コマンド 0x00: TestUnitReady (共通)
243: //
244: class SCSICmdTestUnitReady : public SCSICmd
245: {
1.1.1.3 root 246: using inherited = SCSICmd;
1.1 root 247: public:
248: SCSICmdTestUnitReady(SCSITarget *p) : inherited(p) { }
1.1.1.6 root 249: virtual ~SCSICmdTestUnitReady() override { }
1.1 root 250: };
251:
252: //
1.1.1.2 root 253: // SCSI コマンド 0x01: RezeroUnit (共通)
254: //
255: class SCSICmdRezeroUnit : public SCSICmd
256: {
1.1.1.3 root 257: using inherited = SCSICmd;
1.1.1.2 root 258: public:
259: SCSICmdRezeroUnit(SCSITarget *p) : inherited(p) { }
1.1.1.6 root 260: virtual ~SCSICmdRezeroUnit() override { }
1.1.1.2 root 261:
262: // とりあえず黙って成功するだけでいいか
263: };
264:
265: //
1.1 root 266: // SCSI コマンド 0x03: RequestSense (共通)
267: //
268: class SCSICmdRequestSense : public SCSICmd
269: {
1.1.1.3 root 270: using inherited = SCSICmd;
1.1 root 271: public:
272: SCSICmdRequestSense(SCSITarget *p) : inherited(p) { }
1.1.1.6 root 273: virtual ~SCSICmdRequestSense() override { }
1.1 root 274:
1.1.1.6 root 275: SCSI::XferPhase Command(std::vector<uint8>& cmdseq) override {
1.1.1.4 root 276: // 応答のセンスデータは SCSI-2 形式(最小18バイト) を実装。
277: // 今の所、センスキー、ASC、ASCQ だけで返せる内容にだけ対応している。
278: // これ以外のフィールドを返す必要が出来たらまた考えること。
279:
1.1 root 280: buf.clear();
1.1.1.6 root 281: buf.resize(18);
1.1.1.4 root 282: buf[0] = 0xf0; // Valid、エラーコード 0x70
283: buf[1] = 0; // セグメント番号(?)
284: buf[2] = parent->sensekey; // センスキー (上位4ビットは今の所 0)
285: buf[3] = 0; // Information
286: buf[4] = 0; // Information
287: buf[5] = 0; // Information
288: buf[6] = 0; // Information
289: buf[7] = 0; // 追加センスデータ長 0
290: buf[8] = 0; // Command specific Information
291: buf[9] = 0; // Command specific Information
292: buf[10] = 0; // Command specific Information
293: buf[11] = 0; // Command specific Information
294: buf[12] = parent->senseasc >> 8;
295: buf[13] = parent->senseasc & 0xff;
296: buf[14] = 0; // FRU
297: buf[15] = 0; // センスキー固有情報
298: buf[16] = 0; // センスキー固有情報
299: buf[17] = 0; // センスキー固有情報
300: // 追加センスデータなし
1.1 root 301:
302: // それからバッファを指定の長さに変更
303: buf.resize((uint)cmdseq[4]);
304:
1.1.1.4 root 305: // 転送した後にセンスデータをクリア
306: parent->ClearSense();
307:
1.1 root 308: return SCSI::XferPhase::DataIn;
309: }
310: };
311:
312: //
313: // SCSI コマンド 0x08: Read(6) (共通)
314: //
315: class SCSICmdRead6 : public SCSICmd
316: {
1.1.1.3 root 317: using inherited = SCSICmd;
1.1 root 318: public:
319: SCSICmdRead6(SCSITarget *p) : inherited(p) { }
1.1.1.6 root 320: virtual ~SCSICmdRead6() override { }
1.1 root 321:
1.1.1.6 root 322: SCSI::XferPhase Command(std::vector<uint8>& cmdseq) override {
1.1 root 323: SCSIHD *hdparent = dynamic_cast<SCSIHD*>(parent);
324: uint32 lba;
325: uint32 blks;
326:
1.1.1.4 root 327: // センスデータをクリア
328: parent->ClearSense();
329:
1.1 root 330: lba = (cmdseq[1] & 0x1f) << 16;
331: lba |= cmdseq[2] << 8;
332: lba |= cmdseq[3];
333: blks = cmdseq[4];
334: // blks == 0 は 256 ブロック転送を意味する。
335: if (blks == 0) {
336: blks = 256;
337: }
1.1.1.8 root 338: parent->putlogf(1, lstr("READ6 LBA=0x%x blks=0x%x", lba, blks));
1.1.1.4 root 339:
340: if (((uint64)lba + (uint64)blks) * parent->GetBlocksize() >
341: hdparent->GetSize())
342: {
343: parent->sensekey = SCSI::SenseKey::IllegalRequest;
344: parent->senseasc = SCSI::ASC::InvalidFieldInCDB;
345: status_byte = SCSI::StatusByte::CheckCondition;
346: return SCSI::XferPhase::Status;
347: }
348:
1.1.1.2 root 349: uint8 *start = hdparent->mem + lba * parent->GetBlocksize();
350: uint8 *end = start + blks * parent->GetBlocksize();
1.1 root 351: buf.assign(start, end);
352:
1.1.1.5 root 353: // 平均シークタイム
354: optime = hdparent->seektime;
355:
1.1 root 356: return SCSI::XferPhase::DataIn;
357: }
358: };
359:
360: //
361: // SCSI コマンド 0x0a: Write(6) (共通)
362: //
363: class SCSICmdWrite6 : public SCSICmd
364: {
1.1.1.3 root 365: using inherited = SCSICmd;
1.1 root 366: public:
367: SCSICmdWrite6(SCSITarget *p) : inherited(p) {
368: hdparent = dynamic_cast<SCSIHD*>(parent);
369: }
1.1.1.6 root 370: virtual ~SCSICmdWrite6() override { }
1.1 root 371:
1.1.1.6 root 372: SCSI::XferPhase Command(std::vector<uint8>& cmdseq) override {
1.1.1.4 root 373: // センスデータをクリア
374: parent->ClearSense();
375:
1.1 root 376: lba = (cmdseq[1] & 0x1f) << 16;
377: lba |= cmdseq[2] << 8;
378: lba |= cmdseq[3];
379: blks = cmdseq[4];
380: // blks == 0 は 256 ブロック転送を意味する。
381: if (blks == 0) {
382: blks = 256;
383: }
384:
1.1.1.4 root 385: if (((uint64)lba + (uint64)blks) * parent->GetBlocksize() >
386: hdparent->GetSize())
387: {
388: parent->sensekey = SCSI::SenseKey::IllegalRequest;
389: parent->senseasc = SCSI::ASC::InvalidFieldInCDB;
390: status_byte = SCSI::StatusByte::CheckCondition;
391: return SCSI::XferPhase::Status;
392: }
393:
1.1.1.5 root 394: // 平均シークタイム
395: optime = hdparent->seektime;
396:
1.1.1.4 root 397: recvbytes = blks * parent->GetBlocksize();
1.1 root 398: return SCSI::XferPhase::DataOut;
399: }
400:
1.1.1.6 root 401: SCSI::XferPhase DoneDataOut() override {
1.1.1.8 root 402: parent->putlogf(1, lstr("WRITE6 LBA=0x%x blks=0x%x", lba, blks));
1.1 root 403: if (hdparent->writeprotect == false) {
1.1.1.2 root 404: memcpy(hdparent->mem + (lba * parent->GetBlocksize()),
1.1 root 405: buf.data(), buf.size());
406: }
407: return SCSI::XferPhase::Status;
408: }
409:
410: private:
411: SCSIHD *hdparent;
412: uint32 lba;
413: uint32 blks;
414: };
415:
416: //
417: // SCSI コマンド 0x12: Inquiry (共通)
418: //
419: class SCSICmdInquiry : public SCSICmd
420: {
1.1.1.3 root 421: using inherited = SCSICmd;
1.1 root 422: public:
423: SCSICmdInquiry(SCSITarget *p) : inherited(p) { }
1.1.1.6 root 424: virtual ~SCSICmdInquiry() override { }
1.1 root 425:
1.1.1.6 root 426: SCSI::XferPhase Command(std::vector<uint8>& cmdseq) override {
1.1.1.4 root 427: // センスデータをクリア
428: parent->ClearSense();
429:
1.1 root 430: // 応答データはターゲットデバイスが持っている
431: buf = parent->inquiry_data;
432:
433: // 本来の応答データ長か reqlen の短いほうまで。
434: uint reqlen = (uint)cmdseq[4];
435: if (reqlen < buf.size()) {
436: buf.resize(reqlen);
437: }
438: return SCSI::XferPhase::DataIn;
439: }
440: };
441:
442: //
443: // SCSI コマンド 0x15 ModeSelect(6) (共通)
444: //
445: class SCSICmdModeSelect6 : public SCSICmd
446: {
1.1.1.3 root 447: using inherited = SCSICmd;
1.1 root 448: public:
449: SCSICmdModeSelect6(SCSITarget *p) : inherited(p) { }
1.1.1.6 root 450: virtual ~SCSICmdModeSelect6() override { }
1.1 root 451:
1.1.1.6 root 452: SCSI::XferPhase Command(std::vector<uint8>& cmdseq) override {
1.1.1.4 root 453: // センスデータをクリア
454: parent->ClearSense();
455:
1.1 root 456: recvbytes = cmdseq[4];
457: return SCSI::XferPhase::DataOut;
458: }
459:
1.1.1.6 root 460: SCSI::XferPhase DoneDataOut() override {
1.1 root 461: // Mode Select(6) のデータは以下の構造で並んでいる。
462: // ヘッダ
463: // ブロックディスクリプタ#1
464: // :
465: // ブロックディスクリプタ#n
466: // パラメータページ #1
467: // :
468: // パラメータページ #m
469:
470: const SCSI::ModeParamHdr *hdr = (const SCSI::ModeParamHdr *)buf.data();
471:
472: if (hdr->block_desc_len > 0) {
473: const SCSI::BlockDesc *desc =
474: (const SCSI::BlockDesc *)(buf.data() + sizeof(*hdr));
475: uint blocksize;
476: blocksize = (desc->block_size[0]) << 16;
477: blocksize |= (desc->block_size[1]) << 8;
478: blocksize |= (desc->block_size[2]);
479:
480: // ブロック長を書き戻す
1.1.1.2 root 481: parent->SetBlocksize(blocksize);
1.1 root 482: }
483: return SCSI::XferPhase::Status;
484: }
485: };
486:
487: //
1.1.1.2 root 488: // SCSI コマンド 0x1a ModeSense(6) (共通)
489: //
490: class SCSICmdModeSense6 : public SCSICmd
491: {
1.1.1.3 root 492: using inherited = SCSICmd;
1.1.1.2 root 493: public:
494: SCSICmdModeSense6(SCSITarget *p) : inherited(p) { }
1.1.1.6 root 495: virtual ~SCSICmdModeSense6() override { }
1.1.1.2 root 496:
1.1.1.6 root 497: SCSI::XferPhase Command(std::vector<uint8>& cmdseq) override {
1.1.1.2 root 498: uint8 pagecode = (cmdseq[2] & 0x3f);
1.1.1.4 root 499:
500: // センスデータをクリア
501: parent->ClearSense();
502:
503: // 未実装 (XXX センスデータは適当)
1.1.1.8 root 504: parent->putlogf(1, lstr("ModeSense(6) PageCode $%02x 未実装",
505: pagecode));
1.1.1.4 root 506: parent->sensekey = SCSI::SenseKey::IllegalRequest;
507: parent->senseasc = SCSI::ASC::InvalidFieldInCDB;
508: status_byte = SCSI::StatusByte::CheckCondition;
509:
1.1.1.2 root 510: return SCSI::XferPhase::Status;
511: }
1.1.1.4 root 512: };
1.1.1.2 root 513:
1.1.1.4 root 514: //
515: // SCSI コマンド 0x1b StartStopUnit (ダイレクトアクセスデバイス)
516: //
517: class SCSICmdStartStopUnit : public SCSICmd
518: {
519: using inherited = SCSICmd;
520: public:
521: SCSICmdStartStopUnit(SCSITarget *p) : inherited(p) { }
1.1.1.6 root 522: virtual ~SCSICmdStartStopUnit() override { }
1.1.1.4 root 523:
524: // スピンアップ/ダウンやメディアのロード/アンロードを指示する。
525: // ので今の所エミュレーション上は特にすることはない。
526: // XXX それっぽい時間待つくらいはしてもいいかも知れない
527:
1.1.1.6 root 528: SCSI::XferPhase Command(std::vector<uint8>& cmdseq) override {
1.1.1.8 root 529: parent->putlogf(1, lstr("StartStopUnit"));
1.1.1.4 root 530: return inherited::Command(cmdseq);
1.1.1.2 root 531: }
532: };
533:
534: //
1.1 root 535: // SCSI コマンド 0x25 ReadCapacity (ダイレクトアクセスデバイス)
536: //
537: class SCSICmdReadCapacity : public SCSICmd
538: {
1.1.1.3 root 539: using inherited = SCSICmd;
1.1 root 540: public:
541: SCSICmdReadCapacity(SCSITarget *p) : inherited(p) { }
1.1.1.6 root 542: virtual ~SCSICmdReadCapacity() override { }
1.1 root 543:
1.1.1.6 root 544: SCSI::XferPhase Command(std::vector<uint8>& cmdseq) override {
1.1 root 545: SCSIHD *hdparent = dynamic_cast<SCSIHD*>(parent);
546:
1.1.1.4 root 547: // センスデータをクリア
548: parent->ClearSense();
549:
1.1 root 550: // PMI=1 は未サポート
551: if ((cmdseq[8] & 0x01) != 0) {
1.1.1.8 root 552: parent->putlogf(0, lstr("SCSI ReadCapacity PMI=1 not supported"));
1.1 root 553: }
554:
555: // 応答データは
556: // +00.L 最終論理ブロックアドレス
557: // +04.L ブロック長
1.1.1.2 root 558: uint32 blksize = parent->GetBlocksize();
1.1.1.3 root 559: uint32 lastblk = (hdparent->GetSize() / blksize) - 1;
1.1 root 560: buf.resize(8);
561: buf[0] = lastblk >> 24;
562: buf[1] = lastblk >> 16;
563: buf[2] = lastblk >> 8;
564: buf[3] = lastblk;
565: buf[4] = blksize >> 24;
566: buf[5] = blksize >> 16;
567: buf[6] = blksize >> 8;
568: buf[7] = blksize;
569:
570: return SCSI::XferPhase::DataIn;
571: }
572: };
573:
574: //
575: // SCSI コマンド 0x28 Read(10) (ダイレクトアクセスデバイス)
576: //
577: class SCSICmdRead10 : public SCSICmd
578: {
1.1.1.3 root 579: using inherited = SCSICmd;
1.1 root 580: public:
581: SCSICmdRead10(SCSITarget *p) : inherited(p) { }
1.1.1.6 root 582: virtual ~SCSICmdRead10() override { }
1.1 root 583:
1.1.1.6 root 584: SCSI::XferPhase Command(std::vector<uint8>& cmdseq) override {
1.1 root 585: SCSIHD *hdparent = dynamic_cast<SCSIHD*>(parent);
586: uint32 lba;
587: uint32 blks;
588:
1.1.1.4 root 589: // センスデータをクリア
590: parent->ClearSense();
591:
1.1 root 592: if ((cmdseq[1] & 0x01)) {
1.1.1.8 root 593: parent->putlogf(0, lstr("SCSI Read(10) RelAdr not supported"));
1.1 root 594: }
595:
596: lba = cmdseq[2] << 24;
597: lba |= cmdseq[3] << 16;
598: lba |= cmdseq[4] << 8;
599: lba |= cmdseq[5];
600: blks = cmdseq[7] << 8;
601: blks |= cmdseq[8];
1.1.1.8 root 602: parent->putlogf(1, lstr("READ10 LBA=0x%x blks=0x%x", lba, blks));
1.1.1.4 root 603:
604: if (((uint64)lba + (uint64)blks) * parent->GetBlocksize() >
605: hdparent->GetSize())
606: {
607: parent->sensekey = SCSI::SenseKey::IllegalRequest;
608: parent->senseasc = SCSI::ASC::InvalidFieldInCDB;
609: status_byte = SCSI::StatusByte::CheckCondition;
610: return SCSI::XferPhase::Status;
611: }
1.1 root 612:
1.1.1.2 root 613: uint8 *start = hdparent->mem + lba * parent->GetBlocksize();
614: uint8 *end = start + blks * parent->GetBlocksize();
1.1 root 615: buf.assign(start, end);
616:
1.1.1.5 root 617: // 平均シークタイム
618: optime = hdparent->seektime;
619:
1.1 root 620: return SCSI::XferPhase::DataIn;
621: }
622: };
623:
624: //
1.1.1.7 root 625: // SCSI コマンド 0x2a Write(10) (ダイレクトアクセスデバイス)
626: //
627: class SCSICmdWrite10 : public SCSICmd
628: {
629: using inherited = SCSICmd;
630: public:
631: SCSICmdWrite10(SCSITarget *p) : inherited(p) {
632: hdparent = dynamic_cast<SCSIHD*>(parent);
633: }
634: virtual ~SCSICmdWrite10() override { }
635:
636: SCSI::XferPhase Command(std::vector<uint8>& cmdseq) override {
637: // センスデータをクリア
638: parent->ClearSense();
639:
640: lba = cmdseq[2] << 24;
641: lba |= cmdseq[3] << 16;
642: lba |= cmdseq[4] << 8;
643: lba |= cmdseq[5];
644: blks = cmdseq[7] << 8;
645: blks |= cmdseq[8];
646:
647: if (((uint64)lba + (uint64)blks) * parent->GetBlocksize() >
648: hdparent->GetSize())
649: {
650: parent->sensekey = SCSI::SenseKey::IllegalRequest;
651: parent->senseasc = SCSI::ASC::InvalidFieldInCDB;
652: status_byte = SCSI::StatusByte::CheckCondition;
653: return SCSI::XferPhase::Status;
654: }
655:
656: // 平均シークタイム
657: optime = hdparent->seektime;
658:
659: recvbytes = blks * parent->GetBlocksize();
660: return SCSI::XferPhase::DataOut;
661: }
662:
663: SCSI::XferPhase DoneDataOut() override {
1.1.1.8 root 664: parent->putlogf(1, lstr("WRITE10 LBA=0x%x blks=0x%x", lba, blks));
1.1.1.7 root 665: if (hdparent->writeprotect == false) {
666: memcpy(hdparent->mem + (lba * parent->GetBlocksize()),
667: buf.data(), buf.size());
668: }
669: return SCSI::XferPhase::Status;
670: }
671:
672: private:
673: SCSIHD *hdparent;
674: uint32 lba;
675: uint32 blks;
676: };
677:
678: //
1.1 root 679: // SCSI コマンド サポートしていないコマンド
680: //
681: class SCSICmdNotSupportedCommand : public SCSICmd
682: {
1.1.1.3 root 683: using inherited = SCSICmd;
1.1 root 684: public:
685: SCSICmdNotSupportedCommand(SCSITarget *p) : inherited(p) { }
1.1.1.6 root 686: virtual ~SCSICmdNotSupportedCommand() override { }
1.1 root 687:
1.1.1.6 root 688: SCSI::XferPhase Command(std::vector<uint8>& cmdseq) override {
1.1.1.4 root 689: // XXX センスキーよく分からんけどとりあえず
690: parent->sensekey = SCSI::SenseKey::IllegalRequest;
691: parent->senseasc = SCSI::ASC::InvalidCommandOperationCode;
692: status_byte = SCSI::StatusByte::CheckCondition;
693: return SCSI::XferPhase::Status;
1.1 root 694: }
695: };
696:
1.1.1.6 root 697: #if defined(__clang__)
698: #pragma clang diagnostic pop
699: #endif
1.1 root 700:
701: //
702: // SCSI ターゲットデバイスの共通部分
703: //
704:
705: // コンストラクタ
1.1.1.10! root 706: SCSITarget::SCSITarget(const std::string& objname_,
! 707: SCSIHostDevice *h, int id, std::vector<uint8>& inq)
! 708: : inherited(objname_)
1.1 root 709: {
710: inquiry_data = inq;
711: // ホストへのリンク (所有関係のないポインタ)
712: host = h;
713: myid = id;
714: }
715:
716: // デストラクタ
717: SCSITarget::~SCSITarget()
718: {
719: }
720:
1.1.1.9 root 721: // 電源オン
722: bool
723: SCSITarget::PowerOn()
724: {
725: ClearSense();
726: cmdseq.clear();
727: cmdlen = 0;
728: cmd.reset();
729: bytecount = 0;
730: lastbyte = false;
731:
732: return true;
733: }
734:
1.1.1.4 root 735: // バスリセットされた (SCSIBus から呼ばれる)
736: void
737: SCSITarget::BusResetCB()
738: {
1.1.1.5 root 739: // リセットされたので持ってる信号を全部解放。
740: // 一応自分が変えていい信号線だけを落とす。
741: switch (GetPhase()) {
742: case SCSI::Phase::BusFree:
743: break;
744: case SCSI::Phase::Arbitration:
745: case SCSI::Phase::Selection:
746: case SCSI::Phase::Reselection:
747: NegateSEL();
748: NegateBSY();
749: break;
750: case SCSI::Phase::Transfer:
751: NegateBSY();
752: break;
753: }
754:
1.1.1.4 root 755: // センスキーをクリア
756: ClearSense();
757: }
758:
1.1 root 759: // セレクションで選択された (SCSIBus から呼ばれる)
760: void
761: SCSITarget::SelectionCB()
762: {
763: // ターゲットが、自身が選択されていることを認識してから BSY を
764: // 立てるまでの時間はもうバス側でカウントしてあるので、ここでは
765: // ただちに BSY を上げてよい。
766: putlog(4, "Selection Callback");
767: AssertBSY();
768: }
769:
770: // 情報転送フェーズを開始する (SCSIBus から呼ばれる)
771: void
772: SCSITarget::StartTransferCB()
773: {
774: // 最初はコマンドフェーズ。(ATN はとりあえず放置)
775: putlog(4, "Start Command Phase");
776: cmdseq.clear();
777: cmdlen = 0;
778: SetXfer(SCSI::XferPhase::Command);
779: AssertREQ();
780: }
781:
782: // 情報転送フェーズ間の遷移について
783: //
784: // 情報転送フェーズは TransferCB() で1バイトずつ転送を行い、所定のバイト数
785: // の転送が完了すればフェーズを遷移する。遷移方法は入出力方向別で6通り。
786: // o IN -> IN
787: // o IN -> OUT
788: // o IN -> END
789: // o OUT -> OUT
790: // o OUT -> IN
791: // o OUT -> END
792: //
793: // IN -> IN の遷移。TransferCB() で前フェーズの最終バイト受信後、フェーズを
794: // 変更して REQ を立てるところまで。
795: //
796: // IN -> OUT の遷移。TransferCB() で前フェーズの最終バイト受信後、フェーズを
797: // 変更して (おそらく {Phase}Begin() を発行してから)、データをセットし REQ
798: // を立てる?
799: //
800: // IN -> END の遷移。TransferCB() で前フェーズの最終バイト受信後、BSY を
801: // 下げて終了。
802: //
803: // OUT -> OUT の遷移。前フェーズの最終バイトをイニシエータが受信後に
804: // TransferCB() が呼ばれるので、フェーズを変更して (おそらく {Phase}Begin()
805: // を発行してから)、データをセットし REQ を立てる?
806: //
807: // OUT -> IN の遷移。前フェーズの最終バイトをイニシエータが受信後に
808: // TransferCB() が呼ばれるので、フェーズを変更して (おそらく {Phase}Begin()
809: // を発行してから)、REQ を立てる?
810: //
811: // OUT -> END の遷移。前フェーズの最終バイトをイニシエータが受信後に
812: // TransferCB() が呼ばれるので、BSY を下げる?
813:
814: // 情報転送フェーズでイニシエータが ACK を上げた。(SCSIBus から呼ばれる)
815: // OUT (イニシエータ → ターゲット方向) なら、ターゲットが上げた REQ に応答
816: // してイニシエータがデータをデータバスに乗せてからこれをコールしてくる。
817: // IN (ターゲット → イニシエータ方向) なら、ターゲットがデータをデータバスに
818: // 乗せて REQ を上げたのをイニシエータが受信した後でこれをコールしてくる。
819: void
820: SCSITarget::TransferCB()
821: {
822: uint8 data;
823: SCSI::XferPhase xfer;
824:
825: // このフェーズの最終バイトか
826: lastbyte = false;
827:
828: // このフェーズの1バイト処理
829: xfer = GetXfer();
830: if (xfer == SCSI::XferPhase::Command) {
831: // コマンドフェーズだけいろいろ特殊なので別処理。
832: // 受信バッファが異なる、1バイト目で受信長が決まるなど。
833: data = GetData();
834: putlog(4, "TransferCB: cmdseq[%02d] = $%02x",
835: (int)cmdseq.size(), data);
836: cmdseq.push_back(data);
837: if (cmdseq.size() == 1) {
838: // 1バイト目ならこのコマンドが何バイトか調べる
839: switch (cmdseq[0] >> 5) {
840: case 0: cmdlen = 6; break;
841: case 1: cmdlen = 10; break;
842: case 2: cmdlen = 10; break;
843: case 5: cmdlen = 12; break;
844: default:
845: // 3,4 はリサーブ、6,7 はベンダー定義。XXX 来たらどうする?
846: cmdlen = 6;
847: break;
848: }
849: } else if (cmdseq.size() >= cmdlen) {
850: if (loglevel >= 1) {
851: std::string cmdbuf;
852: const char *name = SCSI::GetCommandName(cmdseq[0]);
853: cmdbuf += string_format("Command \"%s\"", name ?: "?");
854: for (const auto& v : cmdseq) {
855: cmdbuf += string_format(" $%02x", v);
856: }
1.1.1.8 root 857: putlogn("%s", cmdbuf.c_str());
1.1 root 858: }
859: // 最終バイトを受信したらコマンドを選択
860: DispatchCmd();
861: lastbyte = true;
862: }
863: } else if (GetIO() == false) {
864: // OUT 方向 (ターゲットが受信側)
865: // bytecount は減算方向。
866: cmd->buf.push_back(GetData());
867: bytecount--;
868: if (bytecount == 0) {
869: lastbyte = true;
870: }
871: } else {
872: // IN 方向 (ターゲットが送信側)
873: // bytecount は加算方向。
874: // データは前のループの終わり (TransferAckCB()の下のほう) で
875: // セットしているのでここでは引き取られた分をカウントする。
876: bytecount++;
877: if (bytecount >= cmd->buf.size()) {
878: lastbyte = true;
879: }
880: }
881:
882: NegateREQ();
883: }
884:
885: // 情報転送フェーズでイニシエータが ACK を下げた。(SCSIBus から呼ばれる)
886: void
887: SCSITarget::TransferAckCB()
888: {
889: SCSI::XferPhase xfer = GetXfer();
890:
891: // これが最終バイトだったら、フェーズ完了 → フェーズ切り替え。
892: if (lastbyte) {
893: SCSI::XferPhase next;
894: // フェーズ完了
895: switch (xfer) {
896: case SCSI::XferPhase::Command:
897: next = cmd->Command(cmdseq);
898: break;
899: case SCSI::XferPhase::DataOut:
900: next = cmd->DoneDataOut();
901: break;
902: case SCSI::XferPhase::DataIn:
903: next = cmd->DoneDataIn();
904: break;
905: case SCSI::XferPhase::MsgOut:
906: next = cmd->DoneMsgOut();
907: break;
908: case SCSI::XferPhase::MsgIn:
909: next = cmd->DoneMsgIn();
910: break;
911: case SCSI::XferPhase::Status:
912: next = cmd->DoneStatus();
913: break;
914: default:
915: PANIC("TransferCB unknown xfer done %d", (int)xfer);
916: }
917: putlog(2, "%s done", SCSI::GetXferPhaseName(xfer));
918:
1.1.1.5 root 919: // 簡略化のため、フェーズ完了時だけ REQ を引き伸ばすことができる
920: if (cmd->optime != 0) {
921: bus->SetOneshotReqWait(cmd->optime);
922: cmd->optime = 0;
923: }
924:
1.1 root 925: if (next != xfer) {
926: // End ならバスフリーにして終了。
927: if (next == SCSI::XferPhase::End) {
928: NegateBSY();
929: return;
930: }
931:
932: // (必要なら)フェーズを更新
933: SetXfer(next);
934: xfer = next;
935:
936: // 新しいフェーズの開始処理
937: // XXX ここで bytecount とかをリセットできればいいのだが
938: // Command フェーズで Data フェーズの準備をすることが多いので
939: // 悩ましい。
940: switch (xfer) {
941: case SCSI::XferPhase::DataOut:
942: cmd->buf.clear();
943: bytecount = cmd->recvbytes;
944: putlog(3, "DataOut begin (%d bytes)", bytecount);
945: break;
946: case SCSI::XferPhase::DataIn:
947: bytecount = 0;
948: putlog(3, "DataIn begin (%d bytes)", (int)cmd->buf.size());
949: break;
950: case SCSI::XferPhase::MsgOut:
951: cmd->BeginMsgOut();
952: cmd->buf.clear();
953: bytecount = cmd->recvbytes;
954: putlog(3, "MsgOut begin (%d bytes)", bytecount);
955: break;
956: case SCSI::XferPhase::MsgIn:
957: cmd->BeginMsgIn();
958: bytecount = 0;
959: putlog(3, "MsgIn begin (%d bytes)", (int)cmd->buf.size());
960: break;
961: case SCSI::XferPhase::Status:
962: cmd->BeginStatus();
963: bytecount = 0;
964: putlog(3, "Status begin (%d bytes)", (int)cmd->buf.size());
965: break;
966: default:
967: PANIC("TransferCB unknown xfer begin %d", (int)xfer);
968: }
969: }
970: }
971:
972: // IN 方向 (ターゲットが送信側) ならここでデータをバスにセット。
973: if (GetIO()) {
974: SetData(cmd->buf[bytecount]);
975: putlog(4, "SetData $%02x", GetData());
976: }
977:
978: // 次のバイト転送を行うために REQ を上げる。
979: AssertREQ();
980: }
981:
982: // SCSI コマンドのディスパッチャ
983: void
984: SCSITarget::DispatchCmd()
985: {
986: switch (cmdseq[0]) {
987: case SCSI::Command::TestUnitReady: // 0x00
988: cmd.reset(new SCSICmdTestUnitReady(this));
989: break;
990:
1.1.1.2 root 991: case SCSI::Command::RezeroUnit: // 0x01
992: cmd.reset(new SCSICmdRezeroUnit(this));
993: break;
994:
1.1 root 995: case SCSI::Command::RequestSense: // 0x03
996: cmd.reset(new SCSICmdRequestSense(this));
997: break;
998:
999: case SCSI::Command::Inquiry: // 0x12
1000: cmd.reset(new SCSICmdInquiry(this));
1001: break;
1002:
1003: case SCSI::Command::ModeSelect6: // 0x15
1004: cmd.reset(new SCSICmdModeSelect6(this));
1005: break;
1006:
1.1.1.2 root 1007: case SCSI::Command::ModeSense6: // 0x1a
1008: cmd.reset(new SCSICmdModeSense6(this));
1009: break;
1010:
1.1 root 1011: case SCSI::Command::ReadCapacity: // 0x25
1012: cmd.reset(new SCSICmdTestUnitReady(this));
1013: break;
1014:
1015: default:
1016: // サポートしていないコマンド
1017: const char *cname = SCSI::GetCommandName(cmdseq[0]);
1018: std::string name;
1019: if (cname) {
1020: name = string_format(" %s", cname);
1021: }
1022: putlog(0, "未実装 SCSI コマンド $%02x%s len=%d",
1023: cmdseq[0], name.c_str(), (int)cmdseq.size());
1024:
1025: cmd.reset(new SCSICmdNotSupportedCommand(this));
1026: break;
1027: }
1028: }
1029:
1030: //
1031: // SCSI HD
1032: //
1033:
1034: // コンストラクタ
1035: SCSIHD::SCSIHD(SCSIHostDevice *h, int id)
1.1.1.10! root 1036: : inherited(string_format("SCSIHD%d", id), h, id, inquiry_data)
1.1 root 1037: {
1.1.1.10! root 1038: AddAlias(string_format("HD%d", id));
! 1039:
1.1.1.4 root 1040: devtype = SCSI::DevType::HD;
1.1 root 1041: }
1042:
1043: // デストラクタ
1044: SCSIHD::~SCSIHD()
1045: {
1046: }
1047:
1048: // 初期化
1049: bool
1050: SCSIHD::Init()
1051: {
1052: const std::string myname = string_format("%s:ID%d",
1053: host->GetConfigName(), myid);
1.1.1.2 root 1054: const std::string keybody = string_format("%s-id%d-",
1.1 root 1055: host->GetConfigName(), myid);
1056: const std::string imgkey = keybody + "image";
1057: const std::string wpkey = keybody + "writeprotect";
1.1.1.5 root 1058: const std::string stkey = keybody + "seektime";
1.1 root 1059:
1.1.1.3 root 1060: const ConfigItem& itemimg = gConfig->Find(imgkey);
1.1.1.2 root 1061: const std::string& image = itemimg.AsString();
1062: // ここに来る時にチェックしているので ',' はあるはず
1063: auto pos = image.find(',') + 1;
1064: std::string filename = string_ltrim(image.substr(pos, image.size() - pos));
1065: if (filename.length() == 0) {
1066: itemimg.Err("imagefile not specified");
1.1 root 1067: return false;
1068: }
1069:
1.1.1.3 root 1070: // ファイルをオープン
1.1.1.2 root 1071: const std::string path = gMainApp.GetVMDir() + filename;
1.1.1.3 root 1072: file.SetFilename(path);
1073: file.SetDispname(string_format("%s \"%s\"", myname.c_str(), path.c_str()));
1074: mem = file.OpenFile();
1075: if (mem == NULL) {
1.1 root 1076: return false;
1077: }
1078:
1.1.1.3 root 1079: writeprotect = gConfig->Find(wpkey).AsInt();
1.1 root 1080: if (writeprotect) {
1081: putmsg(0, "%s: write protected", myname.c_str());
1082: }
1083:
1.1.1.5 root 1084: // 設定は [msec]、変数は [nsec]。
1085: seektime = gConfig->Find(stkey).AsInt();
1086: seektime *= 1_msec;
1087:
1.1 root 1088: return true;
1089: }
1090:
1091: // SCSI コマンドのディスパッチャ
1092: void
1093: SCSIHD::DispatchCmd()
1094: {
1095: switch (cmdseq[0]) {
1096: case SCSI::Command::Read6: // 0x08
1097: cmd.reset(new SCSICmdRead6(this));
1098: break;
1099:
1100: case SCSI::Command::Write6: // 0x0a
1101: cmd.reset(new SCSICmdWrite6(this));
1102: break;
1103:
1.1.1.4 root 1104: case SCSI::Command::StartStopUnit: // 0x1b
1105: cmd.reset(new SCSICmdStartStopUnit(this));
1106: break;
1107:
1.1 root 1108: case SCSI::Command::ReadCapacity: // 0x25
1109: cmd.reset(new SCSICmdReadCapacity(this));
1110: break;
1111:
1112: case SCSI::Command::Read10: // 0x28
1113: cmd.reset(new SCSICmdRead10(this));
1114: break;
1115:
1.1.1.7 root 1116: case SCSI::Command::Write10: // 0x2a
1117: cmd.reset(new SCSICmdWrite10(this));
1118: break;
1119:
1.1 root 1120: default:
1121: // 見付からなければ基本クラス側に任せる
1122: inherited::DispatchCmd();
1123: break;
1124: }
1125: }
1126:
1.1.1.2 root 1127: // 指定の場所を自由に読み出す
1128: // (エミュレータ特権アクセス)
1129: bool
1130: SCSIHD::PeekImage(void *buf, uint32 start, uint32 len) const
1131: {
1132: if (mem == NULL) {
1133: return false;
1134: }
1.1.1.3 root 1135: if ((uint64)start + (uint64)len > GetSize()) {
1.1.1.2 root 1136: return false;
1137: }
1138: memcpy(buf, mem + start, len);
1139: return true;
1140: }
1141:
1.1 root 1142: // HD の inquiry データ
1143: /*static*/ std::vector<uint8>
1144: SCSIHD::inquiry_data = {
1145: 0x00, // 00 Qualifier + DeviceType
1146: 0x00, // 01 RMB
1147: 0x40, // 02 ISO version
1148: 0x00, // 03 Response Data Format?
1149: 36 - 4, // 04 追加データ長
1150: 0, // 05 Reserved
1151: 0, // 06 Reserved
1152: 0x00, // 07
1153: 'N', 'O', 'N', 'O', ' ', ' ', ' ', ' ',
1154: 'S', 'C', 'S', 'I', 'H', 'D', ' ', ' ',
1155: ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
1.1.1.2 root 1156: '0', ' ', ' ', ' ',
1.1 root 1157: };
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.