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