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