|
|
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.