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