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