|
|
1.1 root 1: //
2: // nono
3: // Copyright (C) 2021 nono project
4: // Licensed under nono-license.txt
5: //
6:
7: // SCSI コマンド
8:
9: #include "scsicmd.h"
10: #include "scsidev.h"
11:
12: #define LUN (cmdseq[1] >> 5)
13:
14: // LUN != 0 のリクエストをエラーにする (Command() 内で使う)。
15: #define CheckLUN do { \
16: if (LUN != 0) { \
17: parent->sensekey = SCSI::SenseKey::NotReady; \
18: parent->senseasc = SCSI::ASC::LogicalUnitNotSupported; \
19: status_byte = SCSI::StatusByte::CheckCondition; \
20: return SCSI::XferPhase::Status; \
21: } \
22: } while (0)
23: // メディアがなければエラーにする (Command() 内で使う)。
24: #define CheckMedium do { \
25: if (disk->IsMediumLoaded() == false) { \
26: parent->sensekey = SCSI::SenseKey::NotReady; \
27: parent->senseasc = SCSI::ASC::MediumNotPresent; \
28: status_byte = SCSI::StatusByte::CheckCondition; \
29: return SCSI::XferPhase::Status; \
30: } \
31: } while (0)
32:
33:
34: //
35: // SCSI コマンドの基本クラス
36: //
37:
38: // コンストラクタ
39: SCSICmd::SCSICmd(SCSITarget *parent_)
40: : parent(parent_)
41: {
42: }
43:
44: // デストラクタ
45: SCSICmd::~SCSICmd()
46: {
47: }
48:
49: // コマンドフェーズ
50: SCSI::XferPhase
51: SCSICmd::Command(std::vector<uint8>& cmdseq)
52: {
53: // コマンド開始前に直前のセンスデータをクリア
54: parent->ClearSense();
55:
56: CheckLUN;
57:
58: return SCSI::XferPhase::Status;
59: }
60:
61:
62: //
63: // SCSI コマンド: サポートしていないコマンド
64: //
65:
66: // コンストラクタ
67: SCSICmdNotSupportedCommand::SCSICmdNotSupportedCommand(SCSITarget *parent_)
68: : inherited(parent_)
69: {
70: }
71:
72: // デストラクタ
73: SCSICmdNotSupportedCommand::~SCSICmdNotSupportedCommand()
74: {
75: }
76:
77: // コマンドフェーズ
78: SCSI::XferPhase
79: SCSICmdNotSupportedCommand::Command(std::vector<uint8>& cmdseq)
80: {
81: // XXX センスキーよく分からんけどとりあえず
82: parent->sensekey = SCSI::SenseKey::IllegalRequest;
83: parent->senseasc = SCSI::ASC::InvalidCommandOperationCode;
84: status_byte = SCSI::StatusByte::CheckCondition;
85:
86: return SCSI::XferPhase::Status;
87: }
88:
89:
90: //
91: // SCSI コマンド 0x03 RequestSense (共通)
92: //
93: // +---+---+---+---+---+---+---+---+
94: // 0 | Operation Code |
95: // +-----------+-------------------+
96: // 1 | LUN | 0 |
97: // +-------+---+-------------------+
98: // 2 | 0 |
99: // 3 | 0 |
100: // +-------------------------------+
101: // 4 | アロケーション長 |
102: // +-------------------------------+
103: // 5 | Control Byte |
104: // +-------------------------------+
105:
106: // コンストラクタ
107: SCSICmdRequestSense::SCSICmdRequestSense(SCSITarget *parent_)
108: : inherited(parent_)
109: {
110: }
111:
112: // デストラクタ
113: SCSICmdRequestSense::~SCSICmdRequestSense()
114: {
115: }
116:
117: // コマンドフェーズ
118: SCSI::XferPhase
119: SCSICmdRequestSense::Command(std::vector<uint8>& cmdseq)
120: {
121: CheckLUN;
122:
123: // 応答のセンスデータは SCSI-2 形式(最小18バイト) を実装。
124: // 今の所、センスキー、ASC、ASCQ だけで返せる内容にだけ対応している。
125: // これ以外のフィールドを返す必要が出来たらまた考えること。
126: uint sensekey = parent->sensekey;
127: uint senseasc = parent->senseasc;
128: parent->putlogf(1, lstr("%s -> %s asc=$%04x",
129: SCSI::GetCommandName(cmdseq[0]),
130: SCSI::GetSenseKeyDisp(sensekey).c_str(),
131: senseasc));
132:
133: // 送信用に取り出した後でセンスデータをクリア
134: // (reqlen によって実際に送信したかどうかは問わない)
135: parent->ClearSense();
136:
137: buf.clear();
138: buf.resize(18);
139: buf[0] = 0x70; // Valid=0、エラーコード 0x70
140: buf[1] = 0; // セグメント番号(?)
141: buf[2] = sensekey; // センスキー (上位4ビットは今の所 0)
142: buf[3] = 0; // Information
143: buf[4] = 0; // Information
144: buf[5] = 0; // Information
145: buf[6] = 0; // Information
146: buf[7] = 0; // 追加センスデータ長 0
147: buf[8] = 0; // Command specific Information
148: buf[9] = 0; // Command specific Information
149: buf[10] = 0; // Command specific Information
150: buf[11] = 0; // Command specific Information
151: buf[12] = senseasc >> 8;
152: buf[13] = senseasc & 0xff;
153: buf[14] = 0; // FRU
154: buf[15] = 0; // センスキー固有情報
155: buf[16] = 0; // センスキー固有情報
156: buf[17] = 0; // センスキー固有情報
157: // 追加センスデータなし
158:
159: // アロケーション長が 0 なら送信せずに終了。
160: // XXX 送信せずにってステータスフェーズに移るってことだろうか?
161: uint reqlen = cmdseq[4];
162: if (reqlen == 0) {
163: return SCSI::XferPhase::Status;
164: }
165: // 本来の応答データ長か reqlen の短いほうまで。
166: if (reqlen < buf.size()) {
167: buf.resize(reqlen);
168: }
169: return SCSI::XferPhase::DataIn;
170: }
171:
172:
173: //
174: // SCSI コマンド 0x08 Read(6) (DA / CD-ROM)
175: // 0x28 Read(10) (DA / CD-ROM)
176: //
177: // Read(6):
178: // +---+---+---+---+---+---+---+---+
179: // 0 | Operation Code = 0x08 |
180: // +-----------+-------------------+
181: // 1 | LUN | |
182: // +-----------+ |
183: // 2 | 論理ブロックアドレス |
184: // 3 | |
185: // +-------------------------------+
186: // 4 | 転送データ長 (0 なら 256) |
187: // +-------------------------------+
188: // 5 | Control Byte |
189: // +-------------------------------+
190: //
191: // Read(10):
192: // +---+---+---+---+---+---+---+---+
193: // 0 | Operation Code = 0x28 |
194: // +-----------+-----------+---+---+
195: // 1 | LUN |DPO|FUA| 0 |Rel|
196: // +-----------+-----------+---+---+
197: // 2 | |
198: // 3 | 論理ブロックアドレス |
199: // 4 | |
200: // 5 | |
201: // +-------------------------------+
202: // 6 | 0 |
203: // +-------------------------------+
204: // 7 | 転送データ長 |
205: // 8 | (0 なら転送しない) |
206: // +-------------------------------+
207: // 9 | Control Byte |
208: // +-------------------------------+
209:
210: // コンストラクタ
211: SCSICmdRead::SCSICmdRead(SCSIDisk *parent_)
212: : inherited(parent_)
213: {
214: disk = parent_;
215: }
216:
217: // デストラクタ
218: SCSICmdRead::~SCSICmdRead()
219: {
220: }
221:
222: // コマンドフェーズ
223: SCSI::XferPhase
224: SCSICmdRead::Command(std::vector<uint8>& cmdseq)
225: {
226: uint32 lba;
227: uint32 blks;
228:
229: // コマンド開始前に直前のセンスデータをクリア
230: parent->ClearSense();
231:
232: CheckLUN;
233: CheckMedium;
234:
235: const uint8& cmd = cmdseq[0];
236: if (cmd == SCSI::Command::Read10) {
237: if ((cmdseq[1] & 0x01)) {
238: parent->putlogf(0, lstr("%s RelAdr not supported",
239: SCSI::GetCommandName(cmd)));
240: }
241: lba = cmdseq[2] << 24;
242: lba |= cmdseq[3] << 16;
243: lba |= cmdseq[4] << 8;
244: lba |= cmdseq[5];
245: blks = cmdseq[7] << 8;
246: blks |= cmdseq[8];
247: } else {
248: lba = (cmdseq[1] & 0x1f) << 16;
249: lba |= cmdseq[2] << 8;
250: lba |= cmdseq[3];
251: blks = cmdseq[4];
252: // Read(6) の blks == 0 は 256 ブロック転送を意味する。
253: if (blks == 0) {
254: blks = 256;
255: }
256: }
257: #if !defined(NO_READWRITE_LOG)
258: parent->putlogf(1, lstr("%s LBA=0x%x blks=0x%x",
259: SCSI::GetCommandName(cmd), lba, blks));
260: #endif
261:
262: uint64 start = (uint64)lba * parent->GetBlocksize();
263: uint64 len = (uint64)blks * parent->GetBlocksize();
264: uint64 end = start + len;
265:
266: if (end > disk->GetSize()) {
267: parent->sensekey = SCSI::SenseKey::IllegalRequest;
268: parent->senseasc = SCSI::ASC::InvalidFieldInCDB;
269: status_byte = SCSI::StatusByte::CheckCondition;
270: return SCSI::XferPhase::Status;
271: }
272: buf.resize(len);
273: disk->Read(buf, start);
274:
275: // 平均シークタイム
276: optime = disk->GetSeekTime();
277:
278: return SCSI::XferPhase::DataIn;
279: }
280:
281:
282: //
283: // SCSI コマンド 0x0a Write(6) (DA / CD-ROM)
284: // 0x2a Write(10) (DA / CD-ROM)
285: //
286: // Write(6):
287: // +---+---+---+---+---+---+---+---+
288: // 0 | Operation Code = 0x0a |
289: // +-----------+-------------------+
290: // 1 | LUN | |
291: // +-----------+ |
292: // 2 | 論理ブロックアドレス |
293: // 3 | |
294: // +-------------------------------+
295: // 4 | 転送データ長 (0 なら 256) |
296: // +-------------------------------+
297: // 5 | Control Byte |
298: // +-------------------------------+
299: //
300: // Write(10):
301: // +---+---+---+---+---+---+---+---+
302: // 0 | Operation Code = 0x2a |
303: // +-----------+-----------+---+---+
304: // 1 | LUN |DPO|FUA| 0 |Rel|
305: // +-----------+-----------+---+---+
306: // 2 | |
307: // 3 | 論理ブロックアドレス |
308: // 4 | |
309: // 5 | |
310: // +-------------------------------+
311: // 6 | 0 |
312: // +-------------------------------+
313: // 7 | 転送データ長 |
314: // 8 | (0 なら転送しない) |
315: // +-------------------------------+
316: // 9 | Control Byte |
317: // +-------------------------------+
318:
319: // コンストラクタ
320: SCSICmdWrite::SCSICmdWrite(SCSIDisk *parent_)
321: : inherited(parent_)
322: {
323: disk = parent_;
324: }
325:
326: // デストラクタ
327: SCSICmdWrite::~SCSICmdWrite()
328: {
329: }
330:
331: // コマンドフェーズ
332: SCSI::XferPhase
333: SCSICmdWrite::Command(std::vector<uint8>& cmdseq)
334: {
335: // コマンド開始前に直前のセンスデータをクリア
336: parent->ClearSense();
337:
338: CheckLUN;
339: CheckMedium;
340:
341: cmd = cmdseq[0];
342: if (cmd == SCSI::Command::Write10) {
343: lba = cmdseq[2] << 24;
344: lba |= cmdseq[3] << 16;
345: lba |= cmdseq[4] << 8;
346: lba |= cmdseq[5];
347: blks = cmdseq[7] << 8;
348: blks |= cmdseq[8];
349: } else {
350: lba = (cmdseq[1] & 0x1f) << 16;
351: lba |= cmdseq[2] << 8;
352: lba |= cmdseq[3];
353: blks = cmdseq[4];
354: // Write(6) の blks == 0 は 256 ブロック転送を意味する。
355: if (blks == 0) {
356: blks = 256;
357: }
358: }
359:
360: if (((uint64)lba + blks) * parent->GetBlocksize() > disk->GetSize()) {
361: parent->sensekey = SCSI::SenseKey::IllegalRequest;
362: parent->senseasc = SCSI::ASC::InvalidFieldInCDB;
363: status_byte = SCSI::StatusByte::CheckCondition;
364: return SCSI::XferPhase::Status;
365: }
366:
367: // 平均シークタイム
368: optime = disk->GetSeekTime();
369:
370: recvbytes = blks * parent->GetBlocksize();
371: return SCSI::XferPhase::DataOut;
372: }
373:
374: // データアウトフェーズ完了
375: SCSI::XferPhase
376: SCSICmdWrite::DoneDataOut()
377: {
378: #if !defined(NO_READWRITE_LOG)
379: parent->putlogf(1, lstr("%s LBA=0x%x blks=0x%x",
380: SCSI::GetCommandName(cmd), lba, blks));
381: #endif
382: uint64 start = (uint64)lba * parent->GetBlocksize();
383: if (disk->Write(buf, start) == false) {
384: parent->sensekey = SCSI::SenseKey::HardwareError;
385: parent->senseasc = SCSI::ASC::PeripheralDeviceWriteFault;
386: status_byte = SCSI::StatusByte::CheckCondition;
387: }
388: return SCSI::XferPhase::Status;
389: }
390:
391:
392: //
393: // SCSI コマンド 0x12 Inquiry (共通)
394: //
395: // +---+---+---+---+---+---+---+---+
396: // 0 | Operation Code |
397: // +-----------+---------------+---+
398: // 1 | LUN | 0 | E | E:Enable Vital Product Data
399: // +-----------+---------------+---+
400: // 2 | ページコード |
401: // +-------------------------------+
402: // 3 | 0 |
403: // +-------------------------------+
404: // 4 | アロケーション長 |
405: // +-------------------------------+
406: // 5 | Control Byte |
407: // +-------------------------------+
408: //
409: // 応答
410: // +---+---+---+---+---+---+---+---+
411: // 0 | Qualifier | Device Type Code |
412: // +---+-------+-------------------+
413: // 1 |RMB| Device Type Modifier |
414: // +---+---+-----------+-----------+
415: // 2 |ISO ver| ECMA ver | ANSI ver |
416: // +---+---+-------+---------------+
417: // 3 | A | T | 0 |ResponseFormat |
418: // +---+---+-------+---------------+
419: // 4 | 追加データ長 (n-4) |
420: // +-------------------------------+
421: // 5 | 0 |
422: // 6 | 0 |
423: // +---+---+---+---+---+---+---+---+
424: // 7 |Rel|W32|W16|Syn|Lnk| 0 |CQ |SR |
425: // +---+---+---+---+---+---+---+---+
426: // 8 | ベンダ文字列 (8Byte) |
427: // : :
428: // 15 | |
429: // +-------------------------------+
430: // 16 | プロダクト文字列 (16Byte) |
431: // : :
432: // 31 | |
433: // +-------------------------------+
434: // 32 | プロダクト版数文字列 (4Byte) |
435: // : :
436: // 35 | |
437: // +-------------------------------+
438: // 36 以下ベンダ固有
439:
440: // コンストラクタ
441: SCSICmdInquiry::SCSICmdInquiry(SCSITarget *parent_)
442: : inherited(parent_)
443: {
444: }
445:
446: // デストラクタ
447: SCSICmdInquiry::~SCSICmdInquiry()
448: {
449: }
450:
451: // コマンドフェーズ
452: SCSI::XferPhase
453: SCSICmdInquiry::Command(std::vector<uint8>& cmdseq)
454: {
455: // コマンド開始前に直前のセンスデータをクリア
456: parent->ClearSense();
457:
458: uint reqlen = (uint)cmdseq[4];
459: parent->putlogf(1, lstr("%s LUN=%d reqlen=$%02x",
460: SCSI::GetCommandName(cmdseq[0]), LUN, reqlen));
461:
462: // 基本の 36バイト分を用意した上でデバイスに問い合わせ。
463: // これ以上必要ならデバイス側で伸ばしてもよい。
464: buf.resize(36);
465: std::fill(buf.begin(), buf.end(), 0);
466: if (parent->Inquiry(buf, LUN) == false) {
467: status_byte = SCSI::StatusByte::CheckCondition;
468: return SCSI::XferPhase::Status;
469: }
470:
471: // 本来の応答データ長か reqlen の短いほうまで。
472: int origlen = buf.size();
473: if (reqlen < origlen) {
474: buf.resize(reqlen);
475: }
476:
477: if (parent->loglevel >= 2) {
478: // 応答をダンプ、ここで表示する長さは本来の応答データ長
479: std::string str = string_format("%s Response len=$%02x:",
480: SCSI::GetCommandName(cmdseq[0]), origlen);
481: // 一方ダンプは実際の送信長
482: for (int i = 0; i < buf.size(); i++) {
483: if (i % 8 == 0 && i != 0) {
484: str += " ";
485: }
486: str += string_format(" %02x", buf[i]);
487: }
488: parent->putlogn("%s", str.c_str());
489: }
490:
491: return SCSI::XferPhase::DataIn;
492: }
493:
494:
495: //
496: // SCSI コマンド 0x15 ModeSelect(6) (共通)
497: // 0x55 ModeSelect(10) (共通)
498: //
499: // ModeSelect(6):
500: // +---+---+---+---+---+---+---+---+
501: // 0 | Operation Code = 0x15 |
502: // +-----------+---+-----------+---+
503: // 1 | LUN |PF | 0 |SP | PF:PageFormat, SP:SavePages
504: // +-----------+---+-----------+---+
505: // 2 | 0 |
506: // 3 | 0 |
507: // +-------------------------------+
508: // 4 | パラメータリスト長 |
509: // +-------------------------------+
510: // 5 | Control Byte |
511: // +-------------------------------+
512: //
513: // ModeSelect(10):
514: // +---+---+---+---+---+---+---+---+
515: // 0 | Operation Code = 0x55 |
516: // +-----------+---+-----------+---+
517: // 1 | LUN |PF | 0 |SP | PF:PageFormat, SP:SavePages
518: // +-----------+---+-----------+---+
519: // 2 | |
520: // 3 | |
521: // 4 | 0 |
522: // 5 | |
523: // 6 | |
524: // +-------------------------------+
525: // 7 | パラメータリスト長 |
526: // 8 | 0 |
527: // +-------------------------------+
528: // 9 | Control Byte |
529: // +-------------------------------+
530: //
531: // 応答: (モードパラメータヘッダ、6の時)
532: // +-------------------------------+
533: // 0 | モードパラメータ長 | (このバイトを含まずこれ以降)
534: // +-------------------------------+
535: // 1 | メディアタイプ |
536: // +-------------------------------+
537: // 2 | デバイス固有パラメータ |
538: // +-------------------------------+
539: // 3 | ブロックディスクリプタ長 m |
540: // +-------------------------------+
541: //
542: // (モードパラメータヘッダ、10の時)
543: // +-------------------------------+
544: // 0 | モードパラメータ長 | (このフィールドを含まずこれ以降?)
545: // 1 | |
546: // +-------------------------------+
547: // 2 | メディアタイプ |
548: // +-------------------------------+
549: // 3 | デバイス固有パラメータ |
550: // +-------------------------------+
551: // 4 | 0 |
552: // 5 | 0 |
553: // +-------------------------------+
554: // 6 | ブロックディスクリプタ長 m |
555: // 7 | |
556: // +-------------------------------+
557: //
558: // (ブロックディスクリプタ) * m 個
559: // +-------------------------------+
560: // 0 | デンシティコード | (デバイスタイプごとに固有)
561: // +-------------------------------+
562: // 1 | |
563: // 2 | ブロック数 |
564: // 3 | |
565: // +-------------------------------+
566: // 4 | 0 |
567: // +-------------------------------+
568: // 5 | |
569: // 6 | ブロック長 |
570: // 7 | |
571: // +-------------------------------+ ブロックディスクリプタここまで
572: //
573: // (パラメータページ) * ? 個
574: // +---+---+-----------------------+
575: // 0 |PS | 0 | ページコード | PS:Parameter Savable
576: // +---+---+-----------------------+
577: // 1 | ページ長 | (このバイトを含まずこれ以降の長さ)
578: // +-------------------------------+
579: // 2 | ページコード固有のパラメータ |
580: // : :
581: // | |
582: // +-------------------------------+
583:
584: // コンストラクタ
585: SCSICmdModeSelect::SCSICmdModeSelect(SCSITarget *parent_)
586: : inherited(parent_)
587: {
588: }
589:
590: // デストラクタ
591: SCSICmdModeSelect::~SCSICmdModeSelect()
592: {
593: }
594:
595: // コマンドフェーズ
596: SCSI::XferPhase
597: SCSICmdModeSelect::Command(std::vector<uint8>& cmdseq)
598: {
599: // コマンド開始前に直前のセンスデータをクリア
600: parent->ClearSense();
601:
602: CheckLUN;
603:
604: cmd = cmdseq[0];
605: if (cmd == SCSI::Command::ModeSelect10) {
606: recvbytes = cmdseq[7] << 8;
607: recvbytes |= cmdseq[8];
608: } else {
609: recvbytes = cmdseq[4];
610: }
611:
612: parent->putlogf(1, lstr("%s len=$%02x",
613: SCSI::GetCommandName(cmd), recvbytes));
614:
615: return SCSI::XferPhase::DataOut;
616: }
617:
618: // データアウトフェーズ完了
619: SCSI::XferPhase
620: SCSICmdModeSelect::DoneDataOut()
621: {
622: uint block_desc_len;
623: const uint8 *desc;
624:
625: // ヘッダの構造と長さが ModeSelect(6)/(10) で違う
626: if (cmd == SCSI::Command::ModeSelect10) {
627: block_desc_len = buf[6] << 8;
628: block_desc_len |= buf[7];
629: desc = &buf[8];
630: } else {
631: block_desc_len = buf[3];
632: desc = &buf[4];
633: }
634:
635: if (block_desc_len > 0) {
636: // ブロックディスクリプタの構造は ModeSelect(6)/(10) で共通
637: uint blocksize;
638: blocksize = desc[5] << 16;
639: blocksize |= desc[6] << 8;
640: blocksize |= desc[7];
641:
642: // ブロック長を書き戻す
643: parent->SetBlocksize(blocksize);
644: }
645:
646: return SCSI::XferPhase::Status;
647: }
648:
649:
650: //
651: // SCSI コマンド 0x1a ModeSense(6) (共通)
652: // 0x5a ModeSense(10) (共通)
653: //
654: // ModeSense(6):
655: // +---+---+---+---+---+---+---+---+
656: // 0 | Operation Code = 0x1a |
657: // +-----------+---+---+-----------+
658: // 1 | LUN | 0 |DBD| 0 | DBD:Disable Block Descriptors
659: // +-------+---+---+---+-----------+
660: // 2 | PC | Page Code | PC:Page Control
661: // +-------+-----------------------+
662: // 3 | 0 |
663: // +-------------------------------+
664: // 4 | アロケーション長 |
665: // +-------------------------------+
666: // 5 | Control Byte |
667: // +-------------------------------+
668: //
669: // ModeSense(10):
670: // +---+---+---+---+---+---+---+---+
671: // 0 | Operation Code = 0x5a |
672: // +-----------+---+---+-----------+
673: // 1 | LUN |LLA|DBD| 0 | DBD:Disable Block Descriptors
674: // +-------+---+---+---+-----------+ LLA:Long LBA Accepted
675: // 2 | PC | Page Code | PC:Page Control
676: // +-------+-----------------------+
677: // 3 | SubPageCode |
678: // +-------------------------------+
679: // 4 | |
680: // 5 | 0 |
681: // 6 | |
682: // +-------------------------------+
683: // 7 | アロケーション長 |
684: // 8 | |
685: // +-------------------------------+
686: // 9 | Control Byte |
687: // +-------------------------------+
688:
689: // コンストラクタ
690: SCSICmdModeSense::SCSICmdModeSense(SCSITarget *parent_)
691: : inherited(parent_)
692: {
693: }
694:
695: // デストラクタ
696: SCSICmdModeSense::~SCSICmdModeSense()
697: {
698: }
699:
700: // コマンドフェーズ
701: SCSI::XferPhase
702: SCSICmdModeSense::Command(std::vector<uint8>& cmdseq)
703: {
704: uint reqlen;
705:
706: // コマンド開始前に直前のセンスデータをクリア
707: parent->ClearSense();
708:
709: CheckLUN;
710:
711: uint cmd = cmdseq[0];
712: pc = (PC)(cmdseq[2] >> 6);
713: pagecode = (cmdseq[2] & 0x3f);
714: if (cmd == SCSI::Command::ModeSense10) {
715: reqlen = cmdseq[7] << 8;
716: reqlen |= cmdseq[8];
717: } else {
718: reqlen = cmdseq[4];
719: }
720: bool dbd = (cmdseq[1] & 0x08);
721:
722: if (parent->loglevel >= 1) {
723: log = string_format("%s %s",
724: SCSI::GetCommandName(cmd),
725: SCSI::GetModePageDisp(pagecode).c_str());
726: if (pc != PC::Current) {
727: log += string_format(" PC=%d", (int)pc);
728: }
729: }
730:
731: // ヘッダを用意。
732:
733: // メディアタイプ。
734: // XXX 実際にはデバイス種別ごとに定義があるが、とりあえず 0 でよさげ
735: const uint8 mediatype = 0;
736: // デバイス固有パラメータを取得
737: uint8 devspec = parent->GetDeviceSpecificParam();
738: // ブロックディスクリプタ長 (バイト数)
739: uint8 bdlen = dbd ? 0 : 8;
740:
741: // ヘッダは (6) と (10) で形式が違う。
742: // モードパラメータ長(全長)は最後に代入する。
743: buf.clear();
744: if (cmd == SCSI::Command::ModeSense10) {
745: buf.resize(8);
746: buf[2] = mediatype;
747: buf[3] = devspec;
748: buf[6] = bdlen >> 8;
749: buf[7] = bdlen;
750: } else {
751: buf.resize(4);
752: buf[1] = mediatype;
753: buf[2] = devspec;
754: buf[3] = bdlen;
755: }
756:
757: // ブロックディスクリプタ
758: if (dbd == false) {
759: // ブロック数とブロックサイズ
760: uint32 blocks = 0;
761: uint32 blocklen = parent->GetBlocksize();
762: const SCSIDisk *disk = dynamic_cast<const SCSIDisk*>(parent);
763: if (disk) {
764: blocks = disk->GetSize() / blocklen;
765: }
766:
767: // 1バイトずつ追加していくほうが楽…。
768: // デンシティコードは実際にはデバイスごとだが、だいたい 0 でよさげ。
769: buf.emplace_back(0); // +0 デンシティコード
770: buf.emplace_back((blocks >> 16) & 0xff); // +1 ブロック数
771: buf.emplace_back((blocks >> 8) & 0xff); // +2 ブロック数
772: buf.emplace_back( blocks & 0xff); // +3 ブロック数
773: buf.emplace_back(0); // +4 reserved
774: buf.emplace_back((blocklen >> 16) & 0xff); // +5 ブロック長
775: buf.emplace_back((blocklen >> 8) & 0xff); // +6 ブロック長
776: buf.emplace_back( blocklen & 0xff); // +7 ブロック長
777: }
778:
779: // ページを送信する順(=昇順)に (手動で) 並べること。
780: // ただし 0x00 (VendorSpecific) は最後。
781: std::vector<std::pair<uint8, PageFunc>> pagelist;
782:
783: #define ADD(code, func) do { \
784: pagelist.emplace_back(SCSI::ModePage::code, \
785: std::bind(&SCSICmdModeSense::func, this)); \
786: } while (0)
787:
788: ADD(/*04*/RigidDiskGeometry, AddNotSupportedPage);
789: ADD(/*05*/FlexibleDisk, AddNotSupportedPage);
790: ADD(/*08*/CachingPage, AddCachingPage);
791: ADD(/*00*/VendorSpecific, AddEmptyPage);
792:
793: if (pagecode == SCSI::ModePage::AllPages) {
794: // サポートしているのを全部送る。
795: if (parent->loglevel >= 1) {
796: log += " " + SCSI::GetModePageDisp(pagecode);
797: log += "->";
798: }
799: for (auto& pair : pagelist) {
800: auto code = pair.first;
801: auto& func = pair.second;
802:
803: if (func() != ModePageResult::Failed) {
804: if (parent->loglevel >= 1) {
805: log += " " + SCSI::GetModePageDisp(code);
806: }
807: }
808: }
809: } else {
810: // 指定されたページコードを送る。
811: ModePageResult r = ModePageResult::NotImplemented;
812: for (auto& pair : pagelist) {
813: auto code = pair.first;
814: auto& func = pair.second;
815:
816: if (pagecode == code) {
817: r = (ModePageResult)func();
818: break;
819: }
820: }
821:
822: // Failed は対応しない/できないと分かっているページ、
823: // NotImplemented は未実装や知らないページ。
824: if (r <= ModePageResult::Failed) {
825: if (parent->loglevel >= 1) {
826: if (r == ModePageResult::NotImplemented) {
827: parent->putlogn("%s 未実装", log.c_str());
828: } else {
829: parent->putlogn("%s", log.c_str());
830: }
831: }
832: parent->sensekey = SCSI::SenseKey::IllegalRequest;
833: parent->senseasc = SCSI::ASC::InvalidFieldInCDB;
834: status_byte = SCSI::StatusByte::CheckCondition;
835: return SCSI::XferPhase::Status;
836: }
837: }
838:
839: parent->putlogf(1, [&] { return log; });
840:
841: // モードパラメータ長は自フィールドを含まない長さ
842: if (cmd == SCSI::Command::ModeSelect10) {
843: uint buflen = buf.size() - 2;
844: buf[0] = buflen >> 8;
845: buf[1] = buflen;
846: } else {
847: uint buflen = buf.size() - 1;
848: buf[0] = buflen;
849: }
850:
851: // 本来の応答データ長か reqlen の短いほうまで
852: if (reqlen < buf.size()) {
853: buf.resize(reqlen);
854: }
855: return SCSI::XferPhase::DataIn;
856: }
857:
858: // サポートしないページ
859: //
860: // ページコード 04 RigidDiskGeometry (DA)
861: // -> 生イメージからジオメトリを求めるのは意味ないので実装しない。
862: // ページコード 05 FlexibleDisk (DA)
863: // -> ジオメトリなどのパラメータがメインっぽいので実装しない。
864: int
865: SCSICmdModeSense::AddNotSupportedPage()
866: {
867: return ModePageResult::Failed;
868: }
869:
870: // 空のページ
871: int
872: SCSICmdModeSense::AddEmptyPage()
873: {
874: std::vector<uint8> page(2);
875: page[0] = pagecode; // +0 ページコード
876: page[1] = page.size() - 2; // +1 このバイト以降のページ長
877:
878: buf.insert(buf.end(), page.begin(), page.end());
879: buf[0] += page.size();
880: return ModePageResult::Success;
881: }
882:
883: // ページコード 08 CachingPage (DA, MO, CD-ROM)
884: int
885: SCSICmdModeSense::AddCachingPage()
886: {
887: const SCSIDisk *disk = dynamic_cast<const SCSIDisk*>(parent);
888: assert(disk);
889:
890: // とりあえずパラメータはなんもなし。
891: // PC::Changeable でも全部 0 なのでこのままでいい。
892: std::vector<uint8> page(12);
893: page[0] = pagecode; // +0 ページコード
894: page[1] = page.size() - 2; // +1 このバイト以降のページ長
895: // +2 WCE, MF, RCD フラグ
896: // +3 データの保持優先度
897: // +4 プリフェッチ抑止ブロック数
898: // +6 最小プリフェッチ
899: // +8 最大プリフェッチ
900: // +10 最大プリフェッチ制限ブロック数
901:
902: buf.insert(buf.end(), page.begin(), page.end());
903: buf[0] += page.size();
904: return ModePageResult::Success;
905: }
906:
907:
908: //
909: // SCSI コマンド 0x1b StartStopUnit (DA / CD-ROM)
910: //
911: // +---+---+---+---+---+---+---+---+
912: // 0 | Operation Code |
913: // +-----------+---------------+---+
914: // 1 | LUN | 0 | I | I:Immediate
915: // +-----------+---------------+---+
916: // 2 | 0 |
917: // 3 | 0 |
918: // +-----------------------+---+---+
919: // 4 | 0 |L/E| S | L/E:Load/Eject, S:Start
920: // +-----------------------+---+---+
921: // 5 | Control Byte |
922: // +-------------------------------+
923:
924: // コンストラクタ
925: SCSICmdStartStopUnit::SCSICmdStartStopUnit(SCSIDisk *parent_)
926: : inherited(parent_)
927: {
928: disk = parent_;
929: }
930:
931: // デストラクタ
932: SCSICmdStartStopUnit::~SCSICmdStartStopUnit()
933: {
934: }
935:
936: // コマンドフェーズ
937: SCSI::XferPhase
938: SCSICmdStartStopUnit::Command(std::vector<uint8>& cmdseq)
939: {
940: bool immed = (cmdseq[1] & 0x01);
941: if (immed) {
942: parent->putlogf(1, lstr("%s Immed=1 not supported",
943: SCSI::GetCommandName(cmdseq[0])));
944: }
945:
946: bool loej = (cmdseq[4] & 0x02);
947: bool start = (cmdseq[4] & 0x01);
948: parent->putlogf(1, lstr("%s LoEj=%d Start=%d",
949: SCSI::GetCommandName(cmdseq[0]), (loej ? 1 : 0), (start ? 1 : 0)));
950:
951: if (disk->IsRemovableDevice()) {
952: // LoEj Start
953: // x 0 媒体へのアクセスを不可にする?
954: // x 1 媒体へのアクセスを可にする?
955: // 1 0 媒体のアンロード
956: // 1 1 媒体のロード
957: //
958: // らしいけど、イジェクトのみ対応
959: if (loej) {
960: if (disk->IsMediumLoaded()) {
961: disk->UnloadDisk();
962: } else {
963: // メディアがロードされてない時にトレイを開ける動作に
964: // 相当するのは「ファイルダイアログを出す」だが伝わるだろうか
965: parent->putlogf(0, lstr("%s Loading not supported",
966: SCSI::GetCommandName(cmdseq[0])));
967: }
968: } else {
969: parent->putlogf(0, lstr("%s LoEj=0 not supported",
970: SCSI::GetCommandName(cmdseq[0])));
971: }
972: } else {
973: // 固定デバイスなら黙って成功しておく?
974: }
975: return inherited::Command(cmdseq);
976: }
977:
978:
979: //
980: // SCSI コマンド 0x1e PreventAllowMediumRemoval (DA / CD-ROM)
981: //
982: // +---+---+---+---+---+---+---+---+
983: // 0 | Operation Code |
984: // +-----------+-------------------+
985: // 1 | LUN | 0 |
986: // +-----------+-------------------+
987: // 2 | 0 |
988: // 3 | 0 |
989: // +---------------------------+---+
990: // 4 | 0 | P | P:Prevent
991: // +---------------------------+---+
992: // 5 | Control Byte |
993: // +-------------------------------+
994:
995: // XXX コマンドとしてはダイレクトアクセスデバイスに対しても発行できるが、
996: // その時どう応答すべきかは要調査
997:
998: // コンストラクタ
999: SCSICmdPreventAllowMediumRemoval::SCSICmdPreventAllowMediumRemoval(
1000: SCSIDisk *parent_)
1001: : inherited(parent_)
1002: {
1003: disk = parent_;
1004: }
1005:
1006: // デストラクタ
1007: SCSICmdPreventAllowMediumRemoval::~SCSICmdPreventAllowMediumRemoval()
1008: {
1009: }
1010:
1011: // コマンドフェーズ
1012: SCSI::XferPhase
1013: SCSICmdPreventAllowMediumRemoval::Command(std::vector<uint8>& cmdseq)
1014: {
1015: // コマンド開始前に直前のセンスデータをクリア
1016: parent->ClearSense();
1017:
1018: CheckLUN;
1019: CheckMedium;
1020:
1021: // PreventMediumRemoval() は状態変化でログレベル 1 で表示してるので、
1022: // ここではログレベル 2 で常に表示にしておく。
1023: uint prevent = cmdseq[4] & 1;
1024: parent->putlogf(2, lstr("%s prevent=%d",
1025: SCSI::GetCommandName(cmdseq[0]), prevent));
1026:
1027: disk->PreventMediumRemoval(prevent);
1028: return SCSI::XferPhase::Status;
1029: }
1030:
1031:
1032: //
1033: // SCSI コマンド 0x25 ReadCapacity (DA)
1034: // 0x25 ReadCDROMCapacity (CD-ROM)
1035: //
1036: // +---+---+---+---+---+---+---+---+
1037: // 0 | Operation Code |
1038: // +-----------+---------------+---+
1039: // 1 | LUN | 0 |Rel|
1040: // +-----------+---------------+---+
1041: // 2 | |
1042: // 3 | 論理ブロックアドレス |
1043: // 4 | (PMI=0 なら 0) |
1044: // 5 | |
1045: // +-------------------------------+
1046: // 6 | 0 |
1047: // 7 | 0 |
1048: // +---------------------------+---+
1049: // 8 | 0 |PMI|
1050: // +---------------------------+---+
1051: // 9 | Control Byte |
1052: // +-------------------------------+
1053: //
1054: // CD-ROM デバイスでは同じ 0x25 で Read CDROM Capacity というコマンド名。
1055: // Read CDROM Capacity のほうはオーディオ CD の場合の意味分けが追加されて
1056: // いるが、たぶんデータ CD だけを扱ううちはダイレクトアクセスデバイスの
1057: // Read Capacity と同じでいいはず。
1058:
1059: // コンストラクタ
1060: SCSICmdReadCapacity::SCSICmdReadCapacity(SCSIDisk *parent_)
1061: : inherited(parent_)
1062: {
1063: disk = parent_;
1064: }
1065:
1066: // デストラクタ
1067: SCSICmdReadCapacity::~SCSICmdReadCapacity()
1068: {
1069: }
1070:
1071: // コマンドフェーズ
1072: SCSI::XferPhase
1073: SCSICmdReadCapacity::Command(std::vector<uint8>& cmdseq)
1074: {
1075: // コマンド開始前に直前のセンスデータをクリア
1076: parent->ClearSense();
1077:
1078: CheckLUN;
1079: CheckMedium;
1080:
1081: // PMI=1 は未サポート
1082: if ((cmdseq[8] & 0x01) != 0) {
1083: parent->putlogf(0, lstr("%s PMI=1 not supported",
1084: SCSI::GetCommandName(cmdseq[0])));
1085: }
1086:
1087: // 応答データは
1088: // +00.L 最終論理ブロックアドレス
1089: // +04.L ブロック長
1090: uint32 blksize = parent->GetBlocksize();
1091: uint32 lastblk = (disk->GetSize() / blksize) - 1;
1092: parent->putlogf(1, lstr("%s -> lastblk=$%x blksize=$%x",
1093: SCSI::GetCommandName(cmdseq[0]), lastblk, blksize));
1094: buf.resize(8);
1095: buf[0] = lastblk >> 24;
1096: buf[1] = lastblk >> 16;
1097: buf[2] = lastblk >> 8;
1098: buf[3] = lastblk;
1099: buf[4] = blksize >> 24;
1100: buf[5] = blksize >> 16;
1101: buf[6] = blksize >> 8;
1102: buf[7] = blksize;
1103:
1104: return SCSI::XferPhase::DataIn;
1105: }
1106:
1107:
1108: //
1109: // SCSI コマンド 0x43 ReadTOC (CD-ROM)
1110: //
1111: // +---+---+---+---+---+---+---+---+
1112: // 0 | Operation Code |
1113: // +-----------+-----------+---+---+
1114: // 1 | LUN | 0 |MSF| 0 |
1115: // +-----------+-----------+---+---+
1116: // 2 | 0 |
1117: // 3 | 0 |
1118: // 4 | 0 |
1119: // 5 | 0 |
1120: // +-------------------------------+
1121: // 6 | 開始トラック |
1122: // +-------------------------------+
1123: // 7 | アロケーション長 |
1124: // 8 | |
1125: // +-------------------------------+
1126: // 9 | Control Byte |
1127: // +-------------------------------+
1128:
1129: // コンストラクタ
1130: SCSICmdReadTOC::SCSICmdReadTOC(SCSIDisk *parent_)
1131: : inherited(parent_)
1132: {
1133: disk = parent_;
1134: }
1135:
1136: // デストラクタ
1137: SCSICmdReadTOC::~SCSICmdReadTOC()
1138: {
1139: }
1140:
1141: // コマンドフェーズ
1142: SCSI::XferPhase
1143: SCSICmdReadTOC::Command(std::vector<uint8>& cmdseq)
1144: {
1145: // コマンド開始前に直前のセンスデータをクリア
1146: parent->ClearSense();
1147:
1148: CheckLUN;
1149: CheckMedium;
1150:
1151: // MSF 形式は未実装
1152: if ((cmdseq[1] & 0x02)) {
1153: parent->putlogf(0, lstr("ReadTOC MSF=1 未実装"));
1154: }
1155:
1156: // 開始トラックが 0 なら、媒体上の先頭トラックからを意味する。
1157: // ここでは1トラック目から始まることにしてみる。
1158: const int TrackStart = 1;
1159: const int TrackMax = 1;
1160:
1161: int start = cmdseq[6];
1162: if (start == 0) {
1163: start = TrackStart;
1164: }
1165:
1166: // イニシエータが用意しているバッファ長
1167: int reqlen = (cmdseq[7] << 8) | cmdseq[8];
1168:
1169: // start は送られてきた情報が知りたいだろう
1170: parent->putlogf(1, lstr("%s start=$%x len=$%x",
1171: SCSI::GetCommandName(cmdseq[0]), cmdseq[6], reqlen));
1172:
1173: // ヘッダ4バイト + トラックディスクリプタ(8バイト) * トラック数で、
1174: // ここではトラックは常に1つ。
1175: buf.clear();
1176: buf.resize(4 + 8 * 1);
1177:
1178: // TOC データ長はこの2バイトのフィールドを含まないバイト数で、
1179: // 開始トラック以降の有効な全トラック数。
1180: int tocdatalen = 2;
1181: if (start <= TrackMax) {
1182: tocdatalen += (TrackMax - start) * 8;
1183: }
1184: // 開始論理アドレス
1185: uint32 address = 0;
1186:
1187: // ヘッダ
1188: buf[0] = tocdatalen >> 8; // TOC データ長
1189: buf[1] = tocdatalen; // TOC データ長
1190: buf[2] = start; // 先頭トラック番号
1191: buf[3] = TrackMax; // 最終トラック番号
1192: // トラック1
1193: buf[4] = 0; // Reserved
1194: buf[5] = 0x06; // ADR=0(?)、データトラック
1195: buf[6] = 1; // トラック番号
1196: buf[7] = 0; // Reserved
1197: buf[8] = address >> 24; // 論理アドレス
1198: buf[9] = address >> 16; // 論理アドレス
1199: buf[10] = address >> 8; // 論理アドレス
1200: buf[11] = address; // 論理アドレス
1201:
1202: // 本来の応答データ長か reqlen の短いほうまで
1203: if (reqlen < buf.size()) {
1204: buf.resize(reqlen);
1205: }
1206:
1207: return SCSI::XferPhase::DataIn;
1208: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.