|
|
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()) {
99: case SCSI::None:
100: break;
101: case SCSI::HD:
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: // コマンドフェーズを処理する。
169: // コマンドが確定したところで呼ばれる。遷移先フェーズを返すこと。
170: virtual SCSI::XferPhase Command(std::vector<uint8>& cmdseq) {
171: return SCSI::XferPhase::Status;
172: }
173:
174: // データインフェーズを完了する。
175: virtual SCSI::XferPhase DoneDataIn() { return SCSI::XferPhase::Status; }
176:
177: // データアウトフェーズを完了する。
178: virtual SCSI::XferPhase DoneDataOut() { return SCSI::XferPhase::Status; }
179:
180: // ステータスフェーズを開始する。
181: // デフォルトでは Good を返す実装を用意しておく。
182: virtual void BeginStatus() {
183: buf.clear();
184: buf.push_back((uint8)SCSI::StatusByte::Good);
185: }
186:
187: // ステータスフェーズを完了する。
188: virtual SCSI::XferPhase DoneStatus() { return SCSI::XferPhase::MsgIn; }
189:
190: // メッセージインフェーズを開始する。
191: // デフォルトでは Command Complete を返す実装を用意しておく。
192: virtual void BeginMsgIn() {
193: buf.clear();
194: buf.push_back((uint8)SCSI::MsgByte::CommandComplete);
195: }
196:
197: // メッセージインフェーズを完了する。
198: virtual SCSI::XferPhase DoneMsgIn() { return SCSI::XferPhase::End; }
199:
200: // メッセージアウトフェーズを開始する。
201: virtual void BeginMsgOut() { }
202:
203: // メッセージアウトフェーズを完了する。
204: virtual SCSI::XferPhase DoneMsgOut() { return SCSI::XferPhase::End; }
205:
206: protected:
207: // このコマンドを実行しているターゲットデバイス。
208: SCSITarget *parent;
209: };
210:
211: //
212: // SCSI コマンド 0x00: TestUnitReady (共通)
213: //
214: class SCSICmdTestUnitReady : public SCSICmd
215: {
1.1.1.3 ! root 216: using inherited = SCSICmd;
1.1 root 217: public:
218: SCSICmdTestUnitReady(SCSITarget *p) : inherited(p) { }
219: virtual ~SCSICmdTestUnitReady() { }
220: };
221:
222: //
1.1.1.2 root 223: // SCSI コマンド 0x01: RezeroUnit (共通)
224: //
225: class SCSICmdRezeroUnit : public SCSICmd
226: {
1.1.1.3 ! root 227: using inherited = SCSICmd;
1.1.1.2 root 228: public:
229: SCSICmdRezeroUnit(SCSITarget *p) : inherited(p) { }
230: virtual ~SCSICmdRezeroUnit() { }
231:
232: // とりあえず黙って成功するだけでいいか
233: };
234:
235: //
1.1 root 236: // SCSI コマンド 0x03: RequestSense (共通)
237: //
238: class SCSICmdRequestSense : public SCSICmd
239: {
1.1.1.3 ! root 240: using inherited = SCSICmd;
1.1 root 241: public:
242: SCSICmdRequestSense(SCSITarget *p) : inherited(p) { }
243: virtual ~SCSICmdRequestSense() { }
244:
245: virtual SCSI::XferPhase Command(std::vector<uint8>& cmdseq) {
246: // この内容は全く不正。でっちあげである。
247: // まず 8バイトのバッファに応答を作成
248: buf.clear();
249: buf.resize(8);
250: buf[0] = 0xf0; // Valid, エラークラス7, エラーコード0
251: buf[1] = 0;
252: buf[2] = 0; // No Sense
253: buf[3] = 0;
254: buf[4] = 0;
255: buf[5] = 0;
256: buf[6] = 0;
257: buf[7] = 0; // 追加センスデータ長 0
258:
259: // それからバッファを指定の長さに変更
260: buf.resize((uint)cmdseq[4]);
261:
262: return SCSI::XferPhase::DataIn;
263: }
264: };
265:
266: //
267: // SCSI コマンド 0x08: Read(6) (共通)
268: //
269: class SCSICmdRead6 : public SCSICmd
270: {
1.1.1.3 ! root 271: using inherited = SCSICmd;
1.1 root 272: public:
273: SCSICmdRead6(SCSITarget *p) : inherited(p) { }
274: virtual ~SCSICmdRead6() { }
275:
276: virtual SCSI::XferPhase Command(std::vector<uint8>& cmdseq) {
277: SCSIHD *hdparent = dynamic_cast<SCSIHD*>(parent);
278: uint32 lba;
279: uint32 blks;
280:
281: lba = (cmdseq[1] & 0x1f) << 16;
282: lba |= cmdseq[2] << 8;
283: lba |= cmdseq[3];
284: blks = cmdseq[4];
285:
286: // blks == 0 は 256 ブロック転送を意味する。
287: if (blks == 0) {
288: blks = 256;
289: }
1.1.1.2 root 290: uint8 *start = hdparent->mem + lba * parent->GetBlocksize();
291: uint8 *end = start + blks * parent->GetBlocksize();
1.1 root 292: buf.assign(start, end);
293:
294: parent->putlog(1, "READ6 LBA=0x%x blks=0x%x", lba, blks);
295: return SCSI::XferPhase::DataIn;
296: }
297: };
298:
299: //
300: // SCSI コマンド 0x0a: Write(6) (共通)
301: //
302: class SCSICmdWrite6 : public SCSICmd
303: {
1.1.1.3 ! root 304: using inherited = SCSICmd;
1.1 root 305: public:
306: SCSICmdWrite6(SCSITarget *p) : inherited(p) {
307: hdparent = dynamic_cast<SCSIHD*>(parent);
308: }
309: virtual ~SCSICmdWrite6() { }
310:
311: virtual SCSI::XferPhase Command(std::vector<uint8>& cmdseq) {
312: lba = (cmdseq[1] & 0x1f) << 16;
313: lba |= cmdseq[2] << 8;
314: lba |= cmdseq[3];
315: blks = cmdseq[4];
316:
317: // blks == 0 は 256 ブロック転送を意味する。
318: if (blks == 0) {
319: blks = 256;
320: }
1.1.1.2 root 321: recvbytes = blks * parent->GetBlocksize();
1.1 root 322:
323: return SCSI::XferPhase::DataOut;
324: }
325:
326: virtual SCSI::XferPhase DoneDataOut() {
327: parent->putlog(1, "WRITE6 LBA=0x%x blks=0x%x", lba, blks);
328: if (hdparent->writeprotect == false) {
1.1.1.2 root 329: memcpy(hdparent->mem + (lba * parent->GetBlocksize()),
1.1 root 330: buf.data(), buf.size());
331: }
332: return SCSI::XferPhase::Status;
333: }
334:
335: private:
336: SCSIHD *hdparent;
337: uint32 lba;
338: uint32 blks;
339: };
340:
341: //
342: // SCSI コマンド 0x12: Inquiry (共通)
343: //
344: class SCSICmdInquiry : public SCSICmd
345: {
1.1.1.3 ! root 346: using inherited = SCSICmd;
1.1 root 347: public:
348: SCSICmdInquiry(SCSITarget *p) : inherited(p) { }
349: virtual ~SCSICmdInquiry() { }
350:
351: virtual SCSI::XferPhase Command(std::vector<uint8>& cmdseq) {
352: // 応答データはターゲットデバイスが持っている
353: buf = parent->inquiry_data;
354:
355: // 本来の応答データ長か reqlen の短いほうまで。
356: uint reqlen = (uint)cmdseq[4];
357: if (reqlen < buf.size()) {
358: buf.resize(reqlen);
359: }
360: return SCSI::XferPhase::DataIn;
361: }
362: };
363:
364: //
365: // SCSI コマンド 0x15 ModeSelect(6) (共通)
366: //
367: class SCSICmdModeSelect6 : public SCSICmd
368: {
1.1.1.3 ! root 369: using inherited = SCSICmd;
1.1 root 370: public:
371: SCSICmdModeSelect6(SCSITarget *p) : inherited(p) { }
372: virtual ~SCSICmdModeSelect6() { }
373:
374: virtual SCSI::XferPhase Command(std::vector<uint8>& cmdseq) {
375: recvbytes = cmdseq[4];
376: return SCSI::XferPhase::DataOut;
377: }
378:
379: virtual SCSI::XferPhase DoneDataOut() {
380: // Mode Select(6) のデータは以下の構造で並んでいる。
381: // ヘッダ
382: // ブロックディスクリプタ#1
383: // :
384: // ブロックディスクリプタ#n
385: // パラメータページ #1
386: // :
387: // パラメータページ #m
388:
389: const SCSI::ModeParamHdr *hdr = (const SCSI::ModeParamHdr *)buf.data();
390:
391: if (hdr->block_desc_len > 0) {
392: const SCSI::BlockDesc *desc =
393: (const SCSI::BlockDesc *)(buf.data() + sizeof(*hdr));
394: uint blocksize;
395: blocksize = (desc->block_size[0]) << 16;
396: blocksize |= (desc->block_size[1]) << 8;
397: blocksize |= (desc->block_size[2]);
398:
399: // ブロック長を書き戻す
1.1.1.2 root 400: parent->SetBlocksize(blocksize);
1.1 root 401: }
402: return SCSI::XferPhase::Status;
403: }
404: };
405:
406: //
1.1.1.2 root 407: // SCSI コマンド 0x1a ModeSense(6) (共通)
408: //
409: class SCSICmdModeSense6 : public SCSICmd
410: {
1.1.1.3 ! root 411: using inherited = SCSICmd;
1.1.1.2 root 412: public:
413: SCSICmdModeSense6(SCSITarget *p) : inherited(p) { }
414: virtual ~SCSICmdModeSense6() { }
415:
416: virtual SCSI::XferPhase Command(std::vector<uint8>& cmdseq) {
417: uint8 pagecode = (cmdseq[2] & 0x3f);
418: // 未実装
419: parent->putlog(1, "ModeSense(6) PageCode $%02x 未実装", pagecode);
420: return SCSI::XferPhase::Status;
421: }
422:
423: virtual void BeginStatus() {
424: buf.clear();
425: buf.push_back((uint8)SCSI::StatusByte::CheckCondition);
426: }
427: };
428:
429: //
1.1 root 430: // SCSI コマンド 0x25 ReadCapacity (ダイレクトアクセスデバイス)
431: //
432: class SCSICmdReadCapacity : public SCSICmd
433: {
1.1.1.3 ! root 434: using inherited = SCSICmd;
1.1 root 435: public:
436: SCSICmdReadCapacity(SCSITarget *p) : inherited(p) { }
437: virtual ~SCSICmdReadCapacity() { }
438:
439: virtual SCSI::XferPhase Command(std::vector<uint8>& cmdseq) {
440: SCSIHD *hdparent = dynamic_cast<SCSIHD*>(parent);
441:
442: // PMI=1 は未サポート
443: if ((cmdseq[8] & 0x01) != 0) {
444: parent->putmsg("SCSI ReadCapacity PMI=1 not supported");
445: }
446:
447: // 応答データは
448: // +00.L 最終論理ブロックアドレス
449: // +04.L ブロック長
1.1.1.2 root 450: uint32 blksize = parent->GetBlocksize();
1.1.1.3 ! root 451: uint32 lastblk = (hdparent->GetSize() / blksize) - 1;
1.1 root 452: buf.resize(8);
453: buf[0] = lastblk >> 24;
454: buf[1] = lastblk >> 16;
455: buf[2] = lastblk >> 8;
456: buf[3] = lastblk;
457: buf[4] = blksize >> 24;
458: buf[5] = blksize >> 16;
459: buf[6] = blksize >> 8;
460: buf[7] = blksize;
461:
462: return SCSI::XferPhase::DataIn;
463: }
464: };
465:
466: //
467: // SCSI コマンド 0x28 Read(10) (ダイレクトアクセスデバイス)
468: //
469: class SCSICmdRead10 : public SCSICmd
470: {
1.1.1.3 ! root 471: using inherited = SCSICmd;
1.1 root 472: public:
473: SCSICmdRead10(SCSITarget *p) : inherited(p) { }
474: virtual ~SCSICmdRead10() { }
475:
476: virtual SCSI::XferPhase Command(std::vector<uint8>& cmdseq) {
477: SCSIHD *hdparent = dynamic_cast<SCSIHD*>(parent);
478: uint32 lba;
479: uint32 blks;
480:
481: if ((cmdseq[1] & 0x01)) {
482: parent->putmsg("SCSI Read(10) RelAdr not supported");
483: }
484:
485: lba = cmdseq[2] << 24;
486: lba |= cmdseq[3] << 16;
487: lba |= cmdseq[4] << 8;
488: lba |= cmdseq[5];
489: blks = cmdseq[7] << 8;
490: blks |= cmdseq[8];
491:
492: // XXX 範囲チェック
1.1.1.2 root 493: uint8 *start = hdparent->mem + lba * parent->GetBlocksize();
494: uint8 *end = start + blks * parent->GetBlocksize();
1.1 root 495: buf.assign(start, end);
496:
497: parent->putlog(1, "READ10 LBA=0x%x blks=0x%x", lba, blks);
498: return SCSI::XferPhase::DataIn;
499: }
500: };
501:
502: //
503: // SCSI コマンド サポートしていないコマンド
504: //
505: class SCSICmdNotSupportedCommand : public SCSICmd
506: {
1.1.1.3 ! root 507: using inherited = SCSICmd;
1.1 root 508: public:
509: SCSICmdNotSupportedCommand(SCSITarget *p) : inherited(p) { }
510: virtual ~SCSICmdNotSupportedCommand() { }
511:
512: // Command は何もせずステータスに移るだけなので基底のやつでいい
513:
514: virtual void BeginStatus() {
515: buf.clear();
516: buf.push_back((uint8)SCSI::StatusByte::CheckCondition);
517: }
518: };
519:
520:
521: //
522: // SCSI ターゲットデバイスの共通部分
523: //
524:
525: // コンストラクタ
526: SCSITarget::SCSITarget(SCSIHostDevice *h, int id, std::vector<uint8>& inq)
527: {
528: logname = "scsitarget";
529: devname = "SCSITarget";
530:
531: inquiry_data = inq;
532: // ホストへのリンク (所有関係のないポインタ)
533: host = h;
534: myid = id;
535: }
536:
537: // デストラクタ
538: SCSITarget::~SCSITarget()
539: {
540: }
541:
542: // セレクションで選択された (SCSIBus から呼ばれる)
543: void
544: SCSITarget::SelectionCB()
545: {
546: // ターゲットが、自身が選択されていることを認識してから BSY を
547: // 立てるまでの時間はもうバス側でカウントしてあるので、ここでは
548: // ただちに BSY を上げてよい。
549: putlog(4, "Selection Callback");
550: AssertBSY();
551: }
552:
553: // 情報転送フェーズを開始する (SCSIBus から呼ばれる)
554: void
555: SCSITarget::StartTransferCB()
556: {
557: // 最初はコマンドフェーズ。(ATN はとりあえず放置)
558: putlog(4, "Start Command Phase");
559: cmdseq.clear();
560: cmdlen = 0;
561: SetXfer(SCSI::XferPhase::Command);
562: AssertREQ();
563: }
564:
565: // 情報転送フェーズ間の遷移について
566: //
567: // 情報転送フェーズは TransferCB() で1バイトずつ転送を行い、所定のバイト数
568: // の転送が完了すればフェーズを遷移する。遷移方法は入出力方向別で6通り。
569: // o IN -> IN
570: // o IN -> OUT
571: // o IN -> END
572: // o OUT -> OUT
573: // o OUT -> IN
574: // o OUT -> END
575: //
576: // IN -> IN の遷移。TransferCB() で前フェーズの最終バイト受信後、フェーズを
577: // 変更して REQ を立てるところまで。
578: //
579: // IN -> OUT の遷移。TransferCB() で前フェーズの最終バイト受信後、フェーズを
580: // 変更して (おそらく {Phase}Begin() を発行してから)、データをセットし REQ
581: // を立てる?
582: //
583: // IN -> END の遷移。TransferCB() で前フェーズの最終バイト受信後、BSY を
584: // 下げて終了。
585: //
586: // OUT -> OUT の遷移。前フェーズの最終バイトをイニシエータが受信後に
587: // TransferCB() が呼ばれるので、フェーズを変更して (おそらく {Phase}Begin()
588: // を発行してから)、データをセットし REQ を立てる?
589: //
590: // OUT -> IN の遷移。前フェーズの最終バイトをイニシエータが受信後に
591: // TransferCB() が呼ばれるので、フェーズを変更して (おそらく {Phase}Begin()
592: // を発行してから)、REQ を立てる?
593: //
594: // OUT -> END の遷移。前フェーズの最終バイトをイニシエータが受信後に
595: // TransferCB() が呼ばれるので、BSY を下げる?
596:
597: // 情報転送フェーズでイニシエータが ACK を上げた。(SCSIBus から呼ばれる)
598: // OUT (イニシエータ → ターゲット方向) なら、ターゲットが上げた REQ に応答
599: // してイニシエータがデータをデータバスに乗せてからこれをコールしてくる。
600: // IN (ターゲット → イニシエータ方向) なら、ターゲットがデータをデータバスに
601: // 乗せて REQ を上げたのをイニシエータが受信した後でこれをコールしてくる。
602: void
603: SCSITarget::TransferCB()
604: {
605: uint8 data;
606: SCSI::XferPhase xfer;
607:
608: // このフェーズの最終バイトか
609: lastbyte = false;
610:
611: // このフェーズの1バイト処理
612: xfer = GetXfer();
613: if (xfer == SCSI::XferPhase::Command) {
614: // コマンドフェーズだけいろいろ特殊なので別処理。
615: // 受信バッファが異なる、1バイト目で受信長が決まるなど。
616: data = GetData();
617: putlog(4, "TransferCB: cmdseq[%02d] = $%02x",
618: (int)cmdseq.size(), data);
619: cmdseq.push_back(data);
620: if (cmdseq.size() == 1) {
621: // 1バイト目ならこのコマンドが何バイトか調べる
622: switch (cmdseq[0] >> 5) {
623: case 0: cmdlen = 6; break;
624: case 1: cmdlen = 10; break;
625: case 2: cmdlen = 10; break;
626: case 5: cmdlen = 12; break;
627: default:
628: // 3,4 はリサーブ、6,7 はベンダー定義。XXX 来たらどうする?
629: cmdlen = 6;
630: break;
631: }
632: } else if (cmdseq.size() >= cmdlen) {
633: if (loglevel >= 1) {
634: std::string cmdbuf;
635: const char *name = SCSI::GetCommandName(cmdseq[0]);
636: cmdbuf += string_format("Command \"%s\"", name ?: "?");
637: for (const auto& v : cmdseq) {
638: cmdbuf += string_format(" $%02x", v);
639: }
640: putlog("%s", cmdbuf.c_str());
641: }
642: // 最終バイトを受信したらコマンドを選択
643: DispatchCmd();
644: lastbyte = true;
645: }
646: } else if (GetIO() == false) {
647: // OUT 方向 (ターゲットが受信側)
648: // bytecount は減算方向。
649: cmd->buf.push_back(GetData());
650: bytecount--;
651: if (bytecount == 0) {
652: lastbyte = true;
653: }
654: } else {
655: // IN 方向 (ターゲットが送信側)
656: // bytecount は加算方向。
657: // データは前のループの終わり (TransferAckCB()の下のほう) で
658: // セットしているのでここでは引き取られた分をカウントする。
659: bytecount++;
660: if (bytecount >= cmd->buf.size()) {
661: lastbyte = true;
662: }
663: }
664:
665: NegateREQ();
666: }
667:
668: // 情報転送フェーズでイニシエータが ACK を下げた。(SCSIBus から呼ばれる)
669: void
670: SCSITarget::TransferAckCB()
671: {
672: SCSI::XferPhase xfer = GetXfer();
673:
674: // これが最終バイトだったら、フェーズ完了 → フェーズ切り替え。
675: if (lastbyte) {
676: SCSI::XferPhase next;
677: // フェーズ完了
678: switch (xfer) {
679: case SCSI::XferPhase::Command:
680: next = cmd->Command(cmdseq);
681: break;
682: case SCSI::XferPhase::DataOut:
683: next = cmd->DoneDataOut();
684: break;
685: case SCSI::XferPhase::DataIn:
686: next = cmd->DoneDataIn();
687: break;
688: case SCSI::XferPhase::MsgOut:
689: next = cmd->DoneMsgOut();
690: break;
691: case SCSI::XferPhase::MsgIn:
692: next = cmd->DoneMsgIn();
693: break;
694: case SCSI::XferPhase::Status:
695: next = cmd->DoneStatus();
696: break;
697: default:
698: PANIC("TransferCB unknown xfer done %d", (int)xfer);
699: }
700: putlog(2, "%s done", SCSI::GetXferPhaseName(xfer));
701:
702: if (next != xfer) {
703: // End ならバスフリーにして終了。
704: if (next == SCSI::XferPhase::End) {
705: NegateBSY();
706: return;
707: }
708:
709: // (必要なら)フェーズを更新
710: SetXfer(next);
711: xfer = next;
712:
713: // 新しいフェーズの開始処理
714: // XXX ここで bytecount とかをリセットできればいいのだが
715: // Command フェーズで Data フェーズの準備をすることが多いので
716: // 悩ましい。
717: switch (xfer) {
718: case SCSI::XferPhase::DataOut:
719: cmd->buf.clear();
720: bytecount = cmd->recvbytes;
721: putlog(3, "DataOut begin (%d bytes)", bytecount);
722: break;
723: case SCSI::XferPhase::DataIn:
724: bytecount = 0;
725: putlog(3, "DataIn begin (%d bytes)", (int)cmd->buf.size());
726: break;
727: case SCSI::XferPhase::MsgOut:
728: cmd->BeginMsgOut();
729: cmd->buf.clear();
730: bytecount = cmd->recvbytes;
731: putlog(3, "MsgOut begin (%d bytes)", bytecount);
732: break;
733: case SCSI::XferPhase::MsgIn:
734: cmd->BeginMsgIn();
735: bytecount = 0;
736: putlog(3, "MsgIn begin (%d bytes)", (int)cmd->buf.size());
737: break;
738: case SCSI::XferPhase::Status:
739: cmd->BeginStatus();
740: bytecount = 0;
741: putlog(3, "Status begin (%d bytes)", (int)cmd->buf.size());
742: break;
743: default:
744: PANIC("TransferCB unknown xfer begin %d", (int)xfer);
745: }
746: }
747: }
748:
749: // IN 方向 (ターゲットが送信側) ならここでデータをバスにセット。
750: if (GetIO()) {
751: SetData(cmd->buf[bytecount]);
752: putlog(4, "SetData $%02x", GetData());
753: }
754:
755: // 次のバイト転送を行うために REQ を上げる。
756: AssertREQ();
757: }
758:
759: // SCSI コマンドのディスパッチャ
760: void
761: SCSITarget::DispatchCmd()
762: {
763: switch (cmdseq[0]) {
764: case SCSI::Command::TestUnitReady: // 0x00
765: cmd.reset(new SCSICmdTestUnitReady(this));
766: break;
767:
1.1.1.2 root 768: case SCSI::Command::RezeroUnit: // 0x01
769: cmd.reset(new SCSICmdRezeroUnit(this));
770: break;
771:
1.1 root 772: case SCSI::Command::RequestSense: // 0x03
773: cmd.reset(new SCSICmdRequestSense(this));
774: break;
775:
776: case SCSI::Command::Inquiry: // 0x12
777: cmd.reset(new SCSICmdInquiry(this));
778: break;
779:
780: case SCSI::Command::ModeSelect6: // 0x15
781: cmd.reset(new SCSICmdModeSelect6(this));
782: break;
783:
1.1.1.2 root 784: case SCSI::Command::ModeSense6: // 0x1a
785: cmd.reset(new SCSICmdModeSense6(this));
786: break;
787:
1.1 root 788: case SCSI::Command::ReadCapacity: // 0x25
789: cmd.reset(new SCSICmdTestUnitReady(this));
790: break;
791:
792: default:
793: // サポートしていないコマンド
794: const char *cname = SCSI::GetCommandName(cmdseq[0]);
795: std::string name;
796: if (cname) {
797: name = string_format(" %s", cname);
798: }
799: putlog(0, "未実装 SCSI コマンド $%02x%s len=%d",
800: cmdseq[0], name.c_str(), (int)cmdseq.size());
801:
802: cmd.reset(new SCSICmdNotSupportedCommand(this));
803: break;
804: }
805: }
806:
807: //
808: // SCSI HD
809: //
810:
811: // コンストラクタ
812: SCSIHD::SCSIHD(SCSIHostDevice *h, int id)
813: : inherited(h, id, inquiry_data)
814: {
815: devname = "SCSIHD";
816: devtype = SCSI::HD;
817: }
818:
819: // デストラクタ
820: SCSIHD::~SCSIHD()
821: {
822: }
823:
824: // 初期化
825: bool
826: SCSIHD::Init()
827: {
828: const std::string myname = string_format("%s:ID%d",
829: host->GetConfigName(), myid);
1.1.1.2 root 830: const std::string keybody = string_format("%s-id%d-",
1.1 root 831: host->GetConfigName(), myid);
832: const std::string imgkey = keybody + "image";
833: const std::string wpkey = keybody + "writeprotect";
834:
1.1.1.3 ! root 835: const ConfigItem& itemimg = gConfig->Find(imgkey);
1.1.1.2 root 836: const std::string& image = itemimg.AsString();
837: // ここに来る時にチェックしているので ',' はあるはず
838: auto pos = image.find(',') + 1;
839: std::string filename = string_ltrim(image.substr(pos, image.size() - pos));
840: if (filename.length() == 0) {
841: itemimg.Err("imagefile not specified");
1.1 root 842: return false;
843: }
844:
1.1.1.3 ! root 845: // ファイルをオープン
1.1.1.2 root 846: const std::string path = gMainApp.GetVMDir() + filename;
1.1.1.3 ! root 847: file.SetFilename(path);
! 848: file.SetDispname(string_format("%s \"%s\"", myname.c_str(), path.c_str()));
! 849: mem = file.OpenFile();
! 850: if (mem == NULL) {
1.1 root 851: return false;
852: }
853:
1.1.1.3 ! root 854: writeprotect = gConfig->Find(wpkey).AsInt();
1.1 root 855: if (writeprotect) {
856: putmsg(0, "%s: write protected", myname.c_str());
857: }
858:
859: return true;
860: }
861:
862: // SCSI コマンドのディスパッチャ
863: void
864: SCSIHD::DispatchCmd()
865: {
866: switch (cmdseq[0]) {
867: case SCSI::Command::Read6: // 0x08
868: cmd.reset(new SCSICmdRead6(this));
869: break;
870:
871: case SCSI::Command::Write6: // 0x0a
872: cmd.reset(new SCSICmdWrite6(this));
873: break;
874:
875: case SCSI::Command::ReadCapacity: // 0x25
876: cmd.reset(new SCSICmdReadCapacity(this));
877: break;
878:
879: case SCSI::Command::Read10: // 0x28
880: cmd.reset(new SCSICmdRead10(this));
881: break;
882:
883: default:
884: // 見付からなければ基本クラス側に任せる
885: inherited::DispatchCmd();
886: break;
887: }
888: }
889:
1.1.1.2 root 890: // 指定の場所を自由に読み出す
891: // (エミュレータ特権アクセス)
892: bool
893: SCSIHD::PeekImage(void *buf, uint32 start, uint32 len) const
894: {
895: if (mem == NULL) {
896: return false;
897: }
1.1.1.3 ! root 898: if ((uint64)start + (uint64)len > GetSize()) {
1.1.1.2 root 899: return false;
900: }
901: memcpy(buf, mem + start, len);
902: return true;
903: }
904:
1.1 root 905: // HD の inquiry データ
906: /*static*/ std::vector<uint8>
907: SCSIHD::inquiry_data = {
908: 0x00, // 00 Qualifier + DeviceType
909: 0x00, // 01 RMB
910: 0x40, // 02 ISO version
911: 0x00, // 03 Response Data Format?
912: 36 - 4, // 04 追加データ長
913: 0, // 05 Reserved
914: 0, // 06 Reserved
915: 0x00, // 07
916: 'N', 'O', 'N', 'O', ' ', ' ', ' ', ' ',
917: 'S', 'C', 'S', 'I', 'H', 'D', ' ', ' ',
918: ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
1.1.1.2 root 919: '0', ' ', ' ', ' ',
1.1 root 920: };
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.