|
|
1.1 ! root 1: // ! 2: // nono ! 3: // Copyright (C) 2018 [email protected] ! 4: // ! 5: ! 6: #include <algorithm> ! 7: #include <fcntl.h> ! 8: #include <sys/stat.h> ! 9: #include <sys/mman.h> ! 10: #include "scsitarget.h" ! 11: #include "scsi.h" ! 12: #include "configfile.h" ! 13: #include "mystring.h" ! 14: ! 15: // ! 16: // SCSI コマンドクラス ! 17: // ! 18: class SCSICmd ! 19: { ! 20: public: ! 21: SCSICmd(SCSITarget *p) { ! 22: parent = p; ! 23: } ! 24: virtual ~SCSICmd() { } ! 25: ! 26: // コマンドフェーズを開始する。 ! 27: // コマンドバイト列が揃ったところでコールされるので、 ! 28: // 必要な処理を行い、次のフェーズ (SCSI::Phase::*) を返す。 ! 29: virtual uint8 Command(const std::vector<uint8>& cmds) { ! 30: // 何もしない系コマンドなら次はステータスフェーズ ! 31: return SCSI::Phase::Status; ! 32: } ! 33: ! 34: // データインフェーズを開始する。 ! 35: // データインフェーズ開始時にコールされるので、 ! 36: // ホストに転送するデータを用意し、 ! 37: // *ptr にデータの先頭、戻り値にデータ長を返す。 ! 38: virtual uint DataInBegin(const uint8 **ptr) { ! 39: return 0; ! 40: } ! 41: ! 42: // データアウトフェーズを開始する。 ! 43: // データアウトフェーズ開始時にコールされるので、 ! 44: // ホストからのデータ受信用バッファを用意し、 ! 45: // *ptr にバッファ、戻り値にバッファ長を返す。 ! 46: virtual uint DataOutBegin(uint8 **ptr) { ! 47: return 0; ! 48: } ! 49: ! 50: // データイン、データアウトフェーズ完了時にコールされる。 ! 51: virtual void DataDone() { } ! 52: ! 53: // ステータスフェーズを開始する。 ! 54: // ステータス (SCSI::StatusByte::*) を返す。 ! 55: virtual uint Status() { ! 56: return SCSI::StatusByte::Good; ! 57: } ! 58: ! 59: // メッセージインフェーズを開始する。 ! 60: // メッセージ (SCSI::MsgByte::*) を返す。 ! 61: virtual uint MsgIn() { ! 62: return SCSI::MsgByte::CommandComplete; ! 63: } ! 64: ! 65: protected: ! 66: // このコマンドを呼び出したデバイス ! 67: SCSITarget *parent = NULL; ! 68: }; ! 69: ! 70: // $00 TestUnitReady コマンド (共通) ! 71: // とりあえず何もせず正常を返すだけでいい。 ! 72: class SCSICmdTestUnitReady : public SCSICmd ! 73: { ! 74: typedef SCSICmd inherited; ! 75: public: ! 76: SCSICmdTestUnitReady(SCSITarget *p) : inherited(p) { } ! 77: virtual ~SCSICmdTestUnitReady() { } ! 78: }; ! 79: ! 80: // $03 RequestSense コマンド (共通) ! 81: class SCSICmdRequestSense: public SCSICmd ! 82: { ! 83: typedef SCSICmd inherited; ! 84: public: ! 85: SCSICmdRequestSense(SCSITarget *p) : inherited(p) { } ! 86: virtual ~SCSICmdRequestSense() { } ! 87: ! 88: virtual uint8 Command(const std::vector<uint8>& cmds) { ! 89: parent->putlog(1, "RequestSense %d", cmds[4]); ! 90: ! 91: // この内容は全く不正。でっちあげである。 ! 92: ! 93: len = (uint)cmds[4]; ! 94: mem[0] = 0x80 | 0x70; ! 95: mem[1] = 0; ! 96: mem[2] = 0; // No Sense ! 97: mem[3] = 0; ! 98: mem[4] = 0; ! 99: mem[5] = 0; ! 100: mem[6] = 0; ! 101: mem[7] = 0; // 追加センスデータ長 ! 102: ! 103: return SCSI::Phase::DataIn; ! 104: } ! 105: ! 106: virtual uint DataInBegin(const uint8 **ptr) { ! 107: *ptr = mem; ! 108: return len; ! 109: } ! 110: ! 111: private: ! 112: uint len = 0; ! 113: uint8 mem[256] {}; ! 114: }; ! 115: ! 116: // $08 Read(6) コマンド (ダイレクトアクセスデバイス) ! 117: class SCSICmdRead6 : public SCSICmd ! 118: { ! 119: typedef SCSICmd inherited; ! 120: public: ! 121: SCSICmdRead6(SCSITarget *p) ! 122: : inherited(p) ! 123: { ! 124: hdparent = dynamic_cast<SCSIHD*>(p); ! 125: } ! 126: virtual ~SCSICmdRead6() { } ! 127: ! 128: virtual uint8 Command(const std::vector<uint8>& cmds) { ! 129: uint32 lba; ! 130: uint32 blks; ! 131: ! 132: lba = (cmds[1] & 0x1f) << 16; ! 133: lba |= cmds[2] << 8; ! 134: lba |= cmds[3]; ! 135: blks = cmds[4]; ! 136: ! 137: // XXX 範囲チェック ! 138: // READ(6) の blks == 0 は 256 を意味する。 ! 139: // なお READ(10) ではこの変換は無い。 ! 140: if (blks == 0) { ! 141: blks = 256; ! 142: } ! 143: dataptr = hdparent->mem + (lba * hdparent->blocksize); ! 144: datalen = blks * parent->blocksize; ! 145: ! 146: parent->putlog(1, "READ6 $%x %d", lba, blks); ! 147: ! 148: return SCSI::Phase::DataIn; ! 149: } ! 150: ! 151: virtual uint DataInBegin(const uint8 **ptr) { ! 152: *ptr = dataptr; ! 153: return datalen; ! 154: } ! 155: ! 156: private: ! 157: SCSIHD *hdparent = NULL; ! 158: uint8 *dataptr = NULL; // 今回の Read の先頭 ! 159: uint datalen = 0; // 今回の Read のバイト数 ! 160: }; ! 161: ! 162: // $0a Write(6) コマンド (ダイレクトアクセスデバイス) ! 163: class SCSICmdWrite6 : public SCSICmd ! 164: { ! 165: typedef SCSICmd inherited; ! 166: public: ! 167: SCSICmdWrite6(SCSITarget *p) ! 168: : inherited(p) ! 169: { ! 170: hdparent = dynamic_cast<SCSIHD*>(p); ! 171: databuf = NULL; ! 172: datalen = 0; ! 173: } ! 174: virtual ~SCSICmdWrite6() { ! 175: if (databuf) { ! 176: delete[] databuf; ! 177: } ! 178: } ! 179: ! 180: virtual uint8 Command(const std::vector<uint8>& cmds) { ! 181: uint32 blks; ! 182: ! 183: lba = (cmds[1] & 0x1f) << 16; ! 184: lba |= cmds[2] << 8; ! 185: lba |= cmds[3]; ! 186: blks = cmds[4]; ! 187: ! 188: // XXX 範囲チェック ! 189: // WRITE(6) の blks == 0 は 256 を意味する。 ! 190: // なお WRITE(10) ではこの変換は無い。 ! 191: if (blks == 0) { ! 192: blks = 256; ! 193: } ! 194: datalen = blks * parent->blocksize; ! 195: databuf = new uint8[datalen]; ! 196: ! 197: parent->putlog(1, "WRITE6 $%x %d", lba, blks); ! 198: ! 199: return SCSI::Phase::DataOut; ! 200: } ! 201: ! 202: virtual uint DataOutBegin(uint8 **ptr) { ! 203: *ptr = databuf; ! 204: return datalen; ! 205: } ! 206: ! 207: virtual void DataDone() { ! 208: if (hdparent->writeprotect == false) ! 209: memcpy(hdparent->mem + (lba * hdparent->blocksize), ! 210: databuf, datalen); ! 211: } ! 212: ! 213: private: ! 214: SCSIHD *hdparent = NULL; ! 215: uint8 *databuf = NULL; // 今回の Write バッファ ! 216: uint datalen = 0; // 今回の Write のバイト数 ! 217: uint32 lba = 0; // 今回の Write の LBA ! 218: }; ! 219: ! 220: // $12 Inquiry コマンド (共通) ! 221: class SCSICmdInquiry : public SCSICmd ! 222: { ! 223: typedef SCSICmd inherited; ! 224: public: ! 225: // inq, len は INQUIRY 応答データ ! 226: SCSICmdInquiry(SCSITarget *p, const uint8 *inq, uint len) ! 227: : inherited(p) ! 228: { ! 229: inquiry_buf = inq; ! 230: inquiry_len = len; ! 231: } ! 232: virtual ~SCSICmdInquiry() { } ! 233: ! 234: virtual uint8 Command(const std::vector<uint8>& cmds) { ! 235: inquiry_len = std::min(inquiry_len, (uint)cmds[4]); ! 236: ! 237: return SCSI::Phase::DataIn; ! 238: } ! 239: ! 240: virtual uint DataInBegin(const uint8 **ptr) { ! 241: *ptr = inquiry_buf; ! 242: return inquiry_len; ! 243: } ! 244: ! 245: private: ! 246: // Inquiry データは SCSI 種別で異なる ! 247: const uint8 *inquiry_buf = NULL; ! 248: uint inquiry_len = 0; ! 249: }; ! 250: ! 251: // $15 ModeSelect(6) コマンド (共通) ! 252: class SCSICmdModeSelect6 : public SCSICmd ! 253: { ! 254: typedef SCSICmd inherited; ! 255: public: ! 256: // ModeSelect コマンドではホストからブロック長が指定される。 ! 257: // blocksizep はその指定されたブロック長を書き戻す場所。 ! 258: SCSICmdModeSelect6(SCSITarget *p) ! 259: : inherited(p) ! 260: { ! 261: modebuf = NULL; ! 262: len = 0; ! 263: } ! 264: virtual ~SCSICmdModeSelect6() { ! 265: if (modebuf) { ! 266: delete[] modebuf; ! 267: } ! 268: } ! 269: ! 270: virtual uint8 Command(const std::vector<uint8>& cmds) { ! 271: // 指定されたバッファ長のメモリを確保。 ! 272: len = cmds[4]; ! 273: modebuf = new uint8[len]; ! 274: return SCSI::Phase::DataOut; ! 275: } ! 276: ! 277: virtual uint DataOutBegin(uint8 **ptr) { ! 278: *ptr = modebuf; ! 279: return len; ! 280: } ! 281: ! 282: virtual void DataDone() { ! 283: // Mode Select(6) のデータは以下の構造で並んでいる。 ! 284: // ヘッダ ! 285: // ブロックディスクリプタ#1 ! 286: // : ! 287: // ブロックディスクリプタ#n ! 288: // パラメータページ #1 ! 289: // : ! 290: // パラメータページ #m ! 291: ! 292: const SCSI::ModeParamHdr *hdr = (const SCSI::ModeParamHdr *)modebuf; ! 293: ! 294: if (hdr->block_desc_len > 0) { ! 295: const SCSI::BlockDesc *desc = ! 296: (const SCSI::BlockDesc *)(modebuf + sizeof(*hdr)); ! 297: uint blocksize; ! 298: blocksize = (desc->block_size[0]) << 16; ! 299: blocksize |= (desc->block_size[1]) << 8; ! 300: blocksize |= (desc->block_size[2]); ! 301: ! 302: // ブロック長を書き戻す ! 303: parent->blocksize = blocksize; ! 304: } ! 305: }; ! 306: ! 307: private: ! 308: uint8 *modebuf = NULL; ! 309: uint len = 0; ! 310: }; ! 311: ! 312: // $25 ReadCapacity コマンド (ダイレクトアクセスデバイス) ! 313: class SCSICmdReadCapacity : public SCSICmd ! 314: { ! 315: typedef SCSICmd inherited; ! 316: public: ! 317: SCSICmdReadCapacity(SCSITarget *p) ! 318: : inherited(p) ! 319: { ! 320: hdparent = dynamic_cast<SCSIHD*>(p); ! 321: ! 322: // 応答データは ! 323: // +00.L 最終論理ブロックアドレス ! 324: // +04.L ブロック長 ! 325: uint32 blksize = hdparent->blocksize; ! 326: uint32 lastblk = (hdparent->memlen / blksize) - 1; ! 327: databuf[0] = lastblk >> 24; ! 328: databuf[1] = lastblk >> 16; ! 329: databuf[2] = lastblk >> 8; ! 330: databuf[3] = lastblk; ! 331: databuf[4] = blksize >> 24; ! 332: databuf[5] = blksize >> 16; ! 333: databuf[6] = blksize >> 8; ! 334: databuf[7] = blksize; ! 335: } ! 336: virtual ~SCSICmdReadCapacity() { } ! 337: ! 338: virtual uint8 Command(const std::vector<uint8>& cmds) { ! 339: uint8 pmi; ! 340: // PMI=1 は未サポート ! 341: pmi = cmds[8] & 0x01; ! 342: if (pmi != 0) { ! 343: PANIC("SCSI ReadCapacity PMI=1 not supported"); ! 344: } ! 345: ! 346: return SCSI::Phase::DataIn; ! 347: } ! 348: ! 349: virtual uint DataInBegin(const uint8 **ptr) { ! 350: *ptr = databuf; ! 351: return sizeof(databuf); ! 352: } ! 353: ! 354: private: ! 355: SCSIHD *hdparent = NULL; ! 356: uint8 databuf[8] {}; ! 357: }; ! 358: ! 359: // $28 Read(10) コマンド (ダイレクトアクセスデバイス) ! 360: class SCSICmdRead10 : public SCSICmd ! 361: { ! 362: typedef SCSICmd inherited; ! 363: public: ! 364: SCSICmdRead10(SCSITarget *p) ! 365: : inherited(p) ! 366: { ! 367: hdparent = dynamic_cast<SCSIHD*>(p); ! 368: } ! 369: virtual ~SCSICmdRead10() { } ! 370: ! 371: virtual uint8 Command(const std::vector<uint8>& cmds) { ! 372: uint32 lba; ! 373: uint32 blks; ! 374: ! 375: if ((cmds[1] & 0x01)) { ! 376: PANIC("SCSI Read(10) RelAdr not supported"); ! 377: } ! 378: ! 379: lba = cmds[2] << 24; ! 380: lba |= cmds[3] << 16; ! 381: lba |= cmds[4] << 8; ! 382: lba |= cmds[5]; ! 383: ! 384: blks = cmds[7] << 8; ! 385: blks |= cmds[8]; ! 386: ! 387: // XXX 範囲チェック ! 388: dataptr = hdparent->mem + (lba * hdparent->blocksize); ! 389: datalen = blks * parent->blocksize; ! 390: ! 391: parent->putlog(1, "READ10 $%x %d", lba, blks); ! 392: ! 393: return SCSI::Phase::DataIn; ! 394: } ! 395: ! 396: virtual uint DataInBegin(const uint8 **ptr) { ! 397: *ptr = dataptr; ! 398: return datalen; ! 399: } ! 400: ! 401: private: ! 402: SCSIHD *hdparent = NULL; ! 403: uint8 *dataptr = 0; // 今回の Read の先頭 ! 404: uint datalen = 0; // 今回の Read のバイト数 ! 405: }; ! 406: ! 407: // サポートしていないコマンドを受け取った時の処理。 ! 408: class SCSICmdNotSupportedCommand : public SCSICmd ! 409: { ! 410: typedef SCSICmd inherited; ! 411: public: ! 412: SCSICmdNotSupportedCommand(SCSITarget *p) : inherited(p) { } ! 413: virtual ~SCSICmdNotSupportedCommand() { } ! 414: ! 415: // Command は何もせずステータスに移るだけなので基底のやつでいい ! 416: ! 417: virtual uint Status() { ! 418: return SCSI::StatusByte::CheckCondition; ! 419: } ! 420: }; ! 421: ! 422: // ! 423: // SCSI ターゲットデバイス基本クラス ! 424: // ! 425: ! 426: // コンストラクタ ! 427: SCSITarget::SCSITarget(SCSIHostDevice *h, int id, SCSI::DevType type) ! 428: { ! 429: host = h; ! 430: logname = host->GetLogName(); ! 431: devtype = type; ! 432: ID = id; ! 433: phase = SCSI::Phase::BusFree; ! 434: } ! 435: ! 436: // デストラクタ ! 437: SCSITarget::~SCSITarget() ! 438: { ! 439: } ! 440: ! 441: // フェーズを newphase に遷移する ! 442: void ! 443: SCSITarget::SetPhase(uint newphase) ! 444: { ! 445: // フェーズ遷移時に ATN をチェック。 ! 446: // バスフリーフェーズ・アービトレーションフェーズでは ATN はセットできない。 ! 447: // ので、それら以外で ATN が立ってる時だけ処理が必要。 ! 448: if (phase != SCSI::Phase::BusFree && ! 449: phase != SCSI::Phase::Arbitration && ! 450: GetATN()) ! 451: { ! 452: // lastmsg は CommandComplete に初期化してあり、CommandComplete には ! 453: // 解除義務はないので、1回目は必ず default に落ちるという寸法。 ! 454: switch (lastmsg) { ! 455: case SCSI::MsgByte::Disconnect: ! 456: case SCSI::MsgByte::InitiatorDetectedError: ! 457: case SCSI::MsgByte::Abort: ! 458: case SCSI::MsgByte::MessageReject: ! 459: case SCSI::MsgByte::NoOperation: ! 460: case SCSI::MsgByte::MessageParityError: ! 461: case SCSI::MsgByte::BusDeviceReset: ! 462: case SCSI::MsgByte::AbortTag: ! 463: case SCSI::MsgByte::ClearQueue: ! 464: case SCSI::MsgByte::InitiateRecovery: ! 465: case SCSI::MsgByte::ReleaseRecovery: ! 466: case SCSI::MsgByte::TerminateIOProcess: ! 467: // 2バイトコードは未対応 ! 468: // 解除義務があるので、継続してたらバスフリーへ移行。 ! 469: newphase = SCSI::Phase::BusFree; ! 470: break; ! 471: default: ! 472: // 解除義務はないので、継続して受け付ける。 ! 473: // (1回目もここに来る) ! 474: nextphase = newphase; ! 475: newphase = SCSI::Phase::MsgOut; ! 476: break; ! 477: } ! 478: } ! 479: ! 480: // MsgOut フェーズを抜ける際には必ず lastmsg を CommandComplete に戻す。 ! 481: // CommandComplete が1回目フラグも兼ねているので。 ! 482: if (phase == SCSI::Phase::MsgOut && newphase != SCSI::Phase::MsgOut) { ! 483: lastmsg = SCSI::MsgByte::CommandComplete; ! 484: } ! 485: ! 486: // フェーズ遷移 ! 487: phase = newphase; ! 488: switch (newphase) { ! 489: case SCSI::Phase::BusFree: ! 490: // 自身の状態を変更 ! 491: BusFreePhase(); ! 492: // バスの状態を変更 (バスを管理してるのはここではホストの基本クラス) ! 493: host->B_BusFree(ID); ! 494: // ホストに状態変更を通知 ! 495: host->BusRelease(); ! 496: break; ! 497: case SCSI::Phase::Arbitration: ! 498: case SCSI::Phase::Selection: ! 499: case SCSI::Phase::Reselection: ! 500: // ? ! 501: break; ! 502: case SCSI::Phase::DataOut: ! 503: DataOutPhase(); ! 504: break; ! 505: case SCSI::Phase::DataIn: ! 506: DataInPhase(); ! 507: break; ! 508: case SCSI::Phase::Command: ! 509: CommandPhase(); ! 510: break; ! 511: case SCSI::Phase::Status: ! 512: StatusPhase(); ! 513: break; ! 514: case SCSI::Phase::MsgOut: ! 515: MsgOutPhase(); ! 516: break; ! 517: case SCSI::Phase::MsgIn: ! 518: MsgInPhase(); ! 519: break; ! 520: } ! 521: } ! 522: ! 523: // セレクション成功。 ! 524: void ! 525: SCSITarget::Selected() ! 526: { ! 527: SetPhase(SCSI::Phase::Command); ! 528: SetREQ(true); ! 529: } ! 530: ! 531: void ! 532: SCSITarget::Ack() ! 533: { ! 534: lastdata = GetDATA(); ! 535: SetREQ(false); ! 536: putlog(3, "#%d data=%02x", ID, lastdata); ! 537: } ! 538: ! 539: // バスフリーフェーズ ! 540: void ! 541: SCSITarget::BusFreePhase() ! 542: { ! 543: lastdata = 0; ! 544: lastmsg = 0; ! 545: } ! 546: ! 547: void ! 548: SCSITarget::DataOutPhase() ! 549: { ! 550: SetMSG(false); ! 551: SetCD(false); ! 552: SetIO(false); ! 553: putlog(3, "#%d Target DataOutPhase", ID); ! 554: } ! 555: ! 556: void ! 557: SCSITarget::DataInPhase() ! 558: { ! 559: SetMSG(false); ! 560: SetCD(false); ! 561: SetIO(true); ! 562: putlog(3, "#%d Target DataInPhase", ID); ! 563: } ! 564: ! 565: void ! 566: SCSITarget::CommandPhase() ! 567: { ! 568: SetMSG(false); ! 569: SetCD(true); ! 570: SetIO(false); ! 571: putlog(3, "#%d Target CommandPhase", ID); ! 572: } ! 573: ! 574: void ! 575: SCSITarget::StatusPhase() ! 576: { ! 577: SetMSG(false); ! 578: SetCD(true); ! 579: SetIO(true); ! 580: putlog(3, "#%d Target StatusPhase", ID); ! 581: } ! 582: ! 583: void ! 584: SCSITarget::MsgOutPhase() ! 585: { ! 586: SetMSG(true); ! 587: SetCD(true); ! 588: SetIO(false); ! 589: putlog(3, "#%d Target MsgOutPhase", ID); ! 590: } ! 591: ! 592: void ! 593: SCSITarget::MsgInPhase() ! 594: { ! 595: SetMSG(true); ! 596: SetCD(true); ! 597: SetIO(true); ! 598: putlog(3, "#%d Target MsgInPhase", ID); ! 599: } ! 600: ! 601: // データインフェーズの処理。 ! 602: uint ! 603: SCSITarget::ExecDataIn(const uint8 **ptr) ! 604: { ! 605: // コマンド固有のデータインフェーズの処理 ! 606: uint len = cmd->DataInBegin(ptr); ! 607: ! 608: // ステータスフェーズに移行 ! 609: SetPhase(SCSI::Phase::Status); ! 610: ! 611: return len; ! 612: } ! 613: ! 614: // データアウトフェーズの処理。 ! 615: uint ! 616: SCSITarget::ExecDataOut(uint8 **ptr) ! 617: { ! 618: // コマンド固有のデータアウトフェーズの処理 ! 619: uint len = cmd->DataOutBegin(ptr); ! 620: ! 621: // ステータスフェーズに移行 ! 622: SetPhase(SCSI::Phase::Status); ! 623: ! 624: return len; ! 625: } ! 626: ! 627: // コマンドフェーズの処理。 ! 628: // イニシエータが必要な長さ分のコマンドをホスト OS から受信したところで ! 629: // イニシエータ側から呼ばれて、コマンドの処理を行う。 ! 630: // 処理後は次のフェーズに遷移する。 ! 631: void ! 632: SCSITarget::ExecCommand(const std::vector<uint8>& argcmds) ! 633: { ! 634: cmds = argcmds; ! 635: ! 636: const char *cmdname = SCSI::GetCommandName(cmds[0]); ! 637: if (cmdname != NULL) { ! 638: putlog(1, "#%d $%02x %s", ID, cmds[0], cmdname); ! 639: } else { ! 640: putlog(1, "#%d $%02x unknown command", ID, cmds[0]); ! 641: } ! 642: ! 643: // コマンドを選択。 ! 644: // まずデバイス固有のコマンドをサーチ。 ! 645: cmd = ExecDeviceCommand(); ! 646: // 派生クラス側で選択されなければ、こちらでサーチ。 ! 647: if (cmd == NULL) { ! 648: switch (cmds[0]) { ! 649: case SCSI::Command::TestUnitReady: ! 650: cmd = new SCSICmdTestUnitReady(this); ! 651: break; ! 652: ! 653: case SCSI::Command::RequestSense: ! 654: cmd = new SCSICmdRequestSense(this); ! 655: break; ! 656: ! 657: case SCSI::Command::ModeSelect6: ! 658: cmd = new SCSICmdModeSelect6(this); ! 659: break; ! 660: ! 661: default: ! 662: // サポートしていないコマンド ! 663: const char *cname = SCSI::GetCommandName(cmds[0]); ! 664: std::string name; ! 665: if (cname) { ! 666: name = string_format(" %s", cname); ! 667: } ! 668: putlog(0, "未実装 SCSI コマンド $%02x%s len=%zd", ! 669: cmds[0], name.c_str(), cmds.size()); ! 670: ! 671: cmd = new SCSICmdNotSupportedCommand(this); ! 672: break; ! 673: } ! 674: } ! 675: ! 676: uint newphase = cmd->Command(cmds); ! 677: SetPhase(newphase); ! 678: } ! 679: ! 680: SCSICmd * ! 681: SCSITarget::ExecDeviceCommand() ! 682: { ! 683: PANIC("should not reached"); ! 684: } ! 685: ! 686: // ステータスバイトを取得およびデータアウトフェーズ完了処理。 ! 687: uint8 ! 688: SCSITarget::GetStatusByte() ! 689: { ! 690: // データフェーズの完了処理をここで行う。 ! 691: cmd->DataDone(); ! 692: ! 693: // XXX まだコマンド側からログが出せないのでとりあえず ! 694: if (cmds[0] == SCSI::Command::ModeSelect6) { ! 695: putlog(2, "#%d Mode Select 論理ブロック長 = %d", ID, blocksize); ! 696: } ! 697: ! 698: // ステータスバイトを取得。 ! 699: uint statusbyte = cmd->Status(); ! 700: ! 701: // メッセージインフェーズに移行。 ! 702: SetPhase(SCSI::Phase::MsgIn); ! 703: return statusbyte; ! 704: } ! 705: ! 706: uint8 ! 707: SCSITarget::GetMessageByte() ! 708: { ! 709: // メッセージを取得。 ! 710: uint messagebyte = cmd->MsgIn(); ! 711: ! 712: // CommandComplete メッセージを正常に送信したらバスフリーフェーズに移行。 ! 713: // 実際には正常に送信できたら、だけど。 ! 714: if (messagebyte == SCSI::MsgByte::CommandComplete) { ! 715: SetPhase(SCSI::Phase::BusFree); ! 716: } ! 717: ! 718: // コマンドクラスを解放 ! 719: // ここでいいか。 ! 720: delete cmd; ! 721: cmd = NULL; ! 722: ! 723: return messagebyte; ! 724: } ! 725: ! 726: ! 727: // ! 728: // SCSI HD ! 729: // ! 730: ! 731: // コンストラクタ ! 732: SCSIHD::SCSIHD(SCSIHostDevice *h, int id) ! 733: : inherited(h, id, SCSI::HD) ! 734: { ! 735: devname = "SCSIHD"; ! 736: logname = "scsihd"; ! 737: ! 738: fd = -1; ! 739: } ! 740: ! 741: // デストラクタ ! 742: SCSIHD::~SCSIHD() ! 743: { ! 744: } ! 745: ! 746: // イメージファイルの読み込み ! 747: bool ! 748: SCSIHD::Init() ! 749: { ! 750: struct stat st; ! 751: ! 752: const std::string myname = string_format("%s(%s,ID%d)", ! 753: devname, host->GetConfigName(), ID); ! 754: const std::string keybody = string_format("%s_id%d_", ! 755: host->GetConfigName(), ID); ! 756: const std::string imgkey = string_format("%s%s", ! 757: keybody.c_str(), "image"); ! 758: const std::string wpkey = string_format("%s%s", ! 759: keybody.c_str(), "writeprotect"); ! 760: ! 761: // devtype があって image がないのは異常状態なのでエラー ! 762: const std::string& filename = gConfig->ReadStr(imgkey); ! 763: if (filename == "") { ! 764: gConfig->Err(imgkey, "not specified"); ! 765: return false; ! 766: } ! 767: ! 768: writeprotect = (bool)gConfig->ReadInt(wpkey); ! 769: if (writeprotect) { ! 770: putmsg(0, "%s: write protected", myname.c_str()); ! 771: } ! 772: ! 773: const std::string path = gConfig->GetConfigDir() + filename; ! 774: fd = open(path.c_str(), O_RDWR); ! 775: if (fd == -1) { ! 776: warn("%s cannot open %s", myname.c_str(), path.c_str()); ! 777: return false; ! 778: } ! 779: ! 780: if (fstat(fd, &st) == -1) { ! 781: warn("%s cannot stat %s", myname.c_str(), path.c_str()); ! 782: close(fd); ! 783: return false; ! 784: } ! 785: ! 786: memlen = st.st_size; ! 787: mem = (uint8 *)mmap(NULL, memlen, PROT_READ | PROT_WRITE, ! 788: MAP_SHARED, fd, 0); ! 789: if (mem == MAP_FAILED) { ! 790: warn("%s cannot mmap %s", myname.c_str(), path.c_str()); ! 791: close(fd); ! 792: return false; ! 793: } ! 794: ! 795: return true; ! 796: } ! 797: ! 798: // HD 固有のコマンドの処理。 ! 799: // こちらで処理すれば次フェーズを返す。そうでなければ None を返す。 ! 800: SCSICmd * ! 801: SCSIHD::ExecDeviceCommand() ! 802: { ! 803: switch (cmds[0]) { ! 804: case SCSI::Command::Read6: ! 805: return new SCSICmdRead6(this); ! 806: ! 807: case SCSI::Command::Write6: ! 808: return new SCSICmdWrite6(this); ! 809: ! 810: case SCSI::Command::Inquiry: ! 811: // これは共通コマンドだけど引数だけ違う ! 812: return new SCSICmdInquiry(this, inquiry_data, sizeof(inquiry_data)); ! 813: ! 814: case SCSI::Command::ReadCapacity: ! 815: return new SCSICmdReadCapacity(this); ! 816: ! 817: case SCSI::Command::Read10: ! 818: return new SCSICmdRead10(this); ! 819: ! 820: default: ! 821: // それ以外は基本クラス側で処理する。 ! 822: return NULL; ! 823: } ! 824: } ! 825: ! 826: // HD の inquiry データ ! 827: /*static*/ const uint8 ! 828: SCSIHD::inquiry_data[36] = { ! 829: 0x00, // 00 Qualifier + DeviceType ! 830: 0x00, // 01 RMB ! 831: 0x40, // 02 ISO version ! 832: 0x00, // 03 Response Data Format? ! 833: 36 - 4, // 04 追加データ長 ! 834: 0, // 05 Reserved ! 835: 0, // 06 Reserved ! 836: 0x00, // 07 ! 837: 'V', 'E', 'N', 'D', 'E', 'R', ' ', ' ', ! 838: 'P', 'R', 'O', 'D', 'U', 'C', 'T', ' ', ! 839: 'N', 'A', 'M', 'E', ' ', ' ', ' ', ' ', ! 840: '0', '1', '2', '3', ! 841: };
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.