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