|
|
1.1 ! root 1: // ! 2: // nono ! 3: // Copyright (C) 2020 [email protected] ! 4: // ! 5: ! 6: // SCSI デバイス共通部分 ! 7: ! 8: #include "scsidev.h" ! 9: #include "configfile.h" ! 10: #include "mystring.h" ! 11: #include <fcntl.h> ! 12: #include <sys/mman.h> ! 13: #include <sys/stat.h> ! 14: ! 15: // ! 16: // SCSI デバイス ! 17: // ! 18: ! 19: // コンストラクタ ! 20: SCSIDevice::SCSIDevice() ! 21: { ! 22: } ! 23: ! 24: // デストラクタ ! 25: SCSIDevice::~SCSIDevice() ! 26: { ! 27: } ! 28: ! 29: // ! 30: // SCSI ホストデバイス ! 31: // ! 32: ! 33: // コンストラクタ ! 34: SCSIHostDevice::SCSIHostDevice() ! 35: { ! 36: // バスデバイスを作成する。 ! 37: // ただし自身がバスに参加するのは継承側で行う ! 38: // (例えば SPC なら BDID 書き込みで ID が決まった後、など)。 ! 39: scsibus.reset(new SCSIBus()); ! 40: } ! 41: ! 42: // デストラクタ ! 43: SCSIHostDevice::~SCSIHostDevice() ! 44: { ! 45: } ! 46: ! 47: bool ! 48: SCSIHostDevice::Create() ! 49: { ! 50: // 設定を読み込む。 ! 51: for (int id = 0; id < 8; id++) { ! 52: const std::string key = string_format("%s_id%d_devtype", ! 53: GetConfigName(), id); ! 54: int devtype = gConfig->ReadInt(key); ! 55: switch (devtype) { ! 56: case SCSI::HD: ! 57: target[id].reset(new SCSIHD(this, id)); ! 58: scsibus->Attach(target[id].get(), id); ! 59: break; ! 60: } ! 61: } ! 62: ! 63: return true; ! 64: } ! 65: ! 66: bool ! 67: SCSIHostDevice::Init() ! 68: { ! 69: // 初期化ではないけどログレベルがセットできたここでデバッグ表示。 ! 70: // -L オプションの処理は Create() の後なので。 ! 71: ! 72: if (loglevel >= 1) { ! 73: for (int id = 0; id < 8; id++) { ! 74: std::string typestr; ! 75: if (target[id]) { ! 76: switch (target[id]->GetDevType()) { ! 77: case SCSI::None: ! 78: break; ! 79: case SCSI::HD: ! 80: typestr = "HD"; ! 81: break; ! 82: } ! 83: } ! 84: if (!typestr.empty()) { ! 85: putmsg("%s target #%d %s", GetConfigName(), id, ! 86: typestr.c_str()); ! 87: } ! 88: } ! 89: } ! 90: ! 91: return true; ! 92: } ! 93: ! 94: // バスフリーコールバック (SCSIBus から呼ばれる) ! 95: void ! 96: SCSIHostDevice::BusFreeCB(int id) ! 97: { ! 98: // 実際にはバスフリーを検出したデバイスは各自自身が送出している信号を ! 99: // 下げるのだが、色々面倒なので、ここではホストのバスフリーコールバックが ! 100: // 一括して全部の線を下げる。 ! 101: // ただしさすがにログがうるさいので、上がってる線だけ下げる。 ! 102: ! 103: uint32 data; ! 104: while ((data = GetBSY()) != 0) { ! 105: bus->NegateBSY(DecodeID(data)); ! 106: } ! 107: while ((data = GetSEL()) != 0) { ! 108: bus->NegateSEL(DecodeID(data)); ! 109: } ! 110: if (GetREQ()) { ! 111: NegateREQ(); ! 112: } ! 113: if (GetACK()) { ! 114: NegateACK(); ! 115: } ! 116: if (GetATN()) { ! 117: NegateATN(); ! 118: } ! 119: SetXfer(0); ! 120: SetData(0); ! 121: } ! 122: ! 123: // ! 124: // SCSI コマンドの共通部分 ! 125: // ! 126: class SCSICmd ! 127: { ! 128: public: ! 129: SCSICmd(SCSITarget *p) { ! 130: parent = p; ! 131: } ! 132: virtual ~SCSICmd() { } ! 133: ! 134: // 転送バッファと転送バイト数。 ! 135: // IN (ターゲットが送出側)なら、各フェーズ開始までに送出バイト数分の ! 136: // バッファを buf に用意すること。recvbytes は操作不要。 ! 137: // ! 138: // OUT(ターゲットが受信側)なら、各フェーズ開始前までに受信バイト数を ! 139: // recvbytes にセットすること。buf は操作不要。 ! 140: // なお parent は OUT(受信)フェーズ中にこの recvbytes を変更しない。 ! 141: std::vector<uint8> buf; ! 142: uint32 recvbytes; ! 143: ! 144: // 以下いずれも戻り値は遷移先のフェーズ。 ! 145: ! 146: // コマンドフェーズを処理する。 ! 147: // コマンドが確定したところで呼ばれる。遷移先フェーズを返すこと。 ! 148: virtual SCSI::XferPhase Command(std::vector<uint8>& cmdseq) { ! 149: return SCSI::XferPhase::Status; ! 150: } ! 151: ! 152: // データインフェーズを開始する。 ! 153: virtual void BeginDataIn() { } ! 154: ! 155: // データインフェーズを完了する。 ! 156: virtual SCSI::XferPhase DoneDataIn() { return SCSI::XferPhase::Status; } ! 157: ! 158: // データアウトフェーズを開始する。 ! 159: virtual void BeginDataOut() { } ! 160: ! 161: // データアウトフェーズを完了する。 ! 162: virtual SCSI::XferPhase DoneDataOut() { return SCSI::XferPhase::Status; } ! 163: ! 164: // ステータスフェーズを開始する。 ! 165: // デフォルトでは Good を返す実装を用意しておく。 ! 166: virtual void BeginStatus() { ! 167: buf.clear(); ! 168: buf.push_back((uint8)SCSI::StatusByte::Good); ! 169: } ! 170: ! 171: // ステータスフェーズを完了する。 ! 172: virtual SCSI::XferPhase DoneStatus() { return SCSI::XferPhase::MsgIn; } ! 173: ! 174: // メッセージインフェーズを開始する。 ! 175: // デフォルトでは Command Complete を返す実装を用意しておく。 ! 176: virtual void BeginMsgIn() { ! 177: buf.clear(); ! 178: buf.push_back((uint8)SCSI::MsgByte::CommandComplete); ! 179: } ! 180: ! 181: // メッセージインフェーズを完了する。 ! 182: virtual SCSI::XferPhase DoneMsgIn() { return SCSI::XferPhase::End; } ! 183: ! 184: // メッセージアウトフェーズを開始する。 ! 185: virtual void BeginMsgOut() { } ! 186: ! 187: // メッセージアウトフェーズを完了する。 ! 188: virtual SCSI::XferPhase DoneMsgOut() { return SCSI::XferPhase::End; } ! 189: ! 190: protected: ! 191: // このコマンドを実行しているターゲットデバイス。 ! 192: SCSITarget *parent; ! 193: }; ! 194: ! 195: // ! 196: // SCSI コマンド 0x00: TestUnitReady (共通) ! 197: // ! 198: class SCSICmdTestUnitReady : public SCSICmd ! 199: { ! 200: typedef SCSICmd inherited; ! 201: public: ! 202: SCSICmdTestUnitReady(SCSITarget *p) : inherited(p) { } ! 203: virtual ~SCSICmdTestUnitReady() { } ! 204: }; ! 205: ! 206: // ! 207: // SCSI コマンド 0x03: RequestSense (共通) ! 208: // ! 209: class SCSICmdRequestSense : public SCSICmd ! 210: { ! 211: typedef SCSICmd inherited; ! 212: public: ! 213: SCSICmdRequestSense(SCSITarget *p) : inherited(p) { } ! 214: virtual ~SCSICmdRequestSense() { } ! 215: ! 216: virtual SCSI::XferPhase Command(std::vector<uint8>& cmdseq) { ! 217: // この内容は全く不正。でっちあげである。 ! 218: // まず 8バイトのバッファに応答を作成 ! 219: buf.clear(); ! 220: buf.resize(8); ! 221: buf[0] = 0xf0; // Valid, エラークラス7, エラーコード0 ! 222: buf[1] = 0; ! 223: buf[2] = 0; // No Sense ! 224: buf[3] = 0; ! 225: buf[4] = 0; ! 226: buf[5] = 0; ! 227: buf[6] = 0; ! 228: buf[7] = 0; // 追加センスデータ長 0 ! 229: ! 230: // それからバッファを指定の長さに変更 ! 231: buf.resize((uint)cmdseq[4]); ! 232: ! 233: return SCSI::XferPhase::DataIn; ! 234: } ! 235: }; ! 236: ! 237: // ! 238: // SCSI コマンド 0x08: Read(6) (共通) ! 239: // ! 240: class SCSICmdRead6 : public SCSICmd ! 241: { ! 242: typedef SCSICmd inherited; ! 243: public: ! 244: SCSICmdRead6(SCSITarget *p) : inherited(p) { } ! 245: virtual ~SCSICmdRead6() { } ! 246: ! 247: virtual SCSI::XferPhase Command(std::vector<uint8>& cmdseq) { ! 248: SCSIHD *hdparent = dynamic_cast<SCSIHD*>(parent); ! 249: uint32 lba; ! 250: uint32 blks; ! 251: ! 252: lba = (cmdseq[1] & 0x1f) << 16; ! 253: lba |= cmdseq[2] << 8; ! 254: lba |= cmdseq[3]; ! 255: blks = cmdseq[4]; ! 256: ! 257: // blks == 0 は 256 ブロック転送を意味する。 ! 258: if (blks == 0) { ! 259: blks = 256; ! 260: } ! 261: uint8 *start = hdparent->mem + lba * hdparent->blocksize; ! 262: uint8 *end = start + blks * hdparent->blocksize; ! 263: buf.assign(start, end); ! 264: ! 265: parent->putlog(1, "READ6 LBA=0x%x blks=0x%x", lba, blks); ! 266: return SCSI::XferPhase::DataIn; ! 267: } ! 268: }; ! 269: ! 270: // ! 271: // SCSI コマンド 0x0a: Write(6) (共通) ! 272: // ! 273: class SCSICmdWrite6 : public SCSICmd ! 274: { ! 275: typedef SCSICmd inherited; ! 276: public: ! 277: SCSICmdWrite6(SCSITarget *p) : inherited(p) { ! 278: hdparent = dynamic_cast<SCSIHD*>(parent); ! 279: } ! 280: virtual ~SCSICmdWrite6() { } ! 281: ! 282: virtual SCSI::XferPhase Command(std::vector<uint8>& cmdseq) { ! 283: lba = (cmdseq[1] & 0x1f) << 16; ! 284: lba |= cmdseq[2] << 8; ! 285: lba |= cmdseq[3]; ! 286: blks = cmdseq[4]; ! 287: ! 288: // blks == 0 は 256 ブロック転送を意味する。 ! 289: if (blks == 0) { ! 290: blks = 256; ! 291: } ! 292: recvbytes = blks * hdparent->blocksize; ! 293: ! 294: return SCSI::XferPhase::DataOut; ! 295: } ! 296: ! 297: virtual SCSI::XferPhase DoneDataOut() { ! 298: parent->putlog(1, "WRITE6 LBA=0x%x blks=0x%x", lba, blks); ! 299: if (hdparent->writeprotect == false) { ! 300: memcpy(hdparent->mem + (lba * hdparent->blocksize), ! 301: buf.data(), buf.size()); ! 302: } ! 303: return SCSI::XferPhase::Status; ! 304: } ! 305: ! 306: private: ! 307: SCSIHD *hdparent; ! 308: uint32 lba; ! 309: uint32 blks; ! 310: }; ! 311: ! 312: // ! 313: // SCSI コマンド 0x12: Inquiry (共通) ! 314: // ! 315: class SCSICmdInquiry : public SCSICmd ! 316: { ! 317: typedef SCSICmd inherited; ! 318: public: ! 319: SCSICmdInquiry(SCSITarget *p) : inherited(p) { } ! 320: virtual ~SCSICmdInquiry() { } ! 321: ! 322: virtual SCSI::XferPhase Command(std::vector<uint8>& cmdseq) { ! 323: // 応答データはターゲットデバイスが持っている ! 324: buf = parent->inquiry_data; ! 325: ! 326: // 本来の応答データ長か reqlen の短いほうまで。 ! 327: uint reqlen = (uint)cmdseq[4]; ! 328: if (reqlen < buf.size()) { ! 329: buf.resize(reqlen); ! 330: } ! 331: return SCSI::XferPhase::DataIn; ! 332: } ! 333: }; ! 334: ! 335: // ! 336: // SCSI コマンド 0x15 ModeSelect(6) (共通) ! 337: // ! 338: class SCSICmdModeSelect6 : public SCSICmd ! 339: { ! 340: typedef SCSICmd inherited; ! 341: public: ! 342: SCSICmdModeSelect6(SCSITarget *p) : inherited(p) { } ! 343: virtual ~SCSICmdModeSelect6() { } ! 344: ! 345: virtual SCSI::XferPhase Command(std::vector<uint8>& cmdseq) { ! 346: recvbytes = cmdseq[4]; ! 347: return SCSI::XferPhase::DataOut; ! 348: } ! 349: ! 350: virtual SCSI::XferPhase DoneDataOut() { ! 351: // Mode Select(6) のデータは以下の構造で並んでいる。 ! 352: // ヘッダ ! 353: // ブロックディスクリプタ#1 ! 354: // : ! 355: // ブロックディスクリプタ#n ! 356: // パラメータページ #1 ! 357: // : ! 358: // パラメータページ #m ! 359: ! 360: const SCSI::ModeParamHdr *hdr = (const SCSI::ModeParamHdr *)buf.data(); ! 361: ! 362: if (hdr->block_desc_len > 0) { ! 363: const SCSI::BlockDesc *desc = ! 364: (const SCSI::BlockDesc *)(buf.data() + sizeof(*hdr)); ! 365: uint blocksize; ! 366: blocksize = (desc->block_size[0]) << 16; ! 367: blocksize |= (desc->block_size[1]) << 8; ! 368: blocksize |= (desc->block_size[2]); ! 369: ! 370: // ブロック長を書き戻す ! 371: parent->blocksize = blocksize; ! 372: } ! 373: return SCSI::XferPhase::Status; ! 374: } ! 375: }; ! 376: ! 377: // ! 378: // SCSI コマンド 0x25 ReadCapacity (ダイレクトアクセスデバイス) ! 379: // ! 380: class SCSICmdReadCapacity : public SCSICmd ! 381: { ! 382: typedef SCSICmd inherited; ! 383: public: ! 384: SCSICmdReadCapacity(SCSITarget *p) : inherited(p) { } ! 385: virtual ~SCSICmdReadCapacity() { } ! 386: ! 387: virtual SCSI::XferPhase Command(std::vector<uint8>& cmdseq) { ! 388: SCSIHD *hdparent = dynamic_cast<SCSIHD*>(parent); ! 389: ! 390: // PMI=1 は未サポート ! 391: if ((cmdseq[8] & 0x01) != 0) { ! 392: parent->putmsg("SCSI ReadCapacity PMI=1 not supported"); ! 393: } ! 394: ! 395: // 応答データは ! 396: // +00.L 最終論理ブロックアドレス ! 397: // +04.L ブロック長 ! 398: uint32 blksize = hdparent->blocksize; ! 399: uint32 lastblk = (hdparent->memlen / blksize) - 1; ! 400: buf.resize(8); ! 401: buf[0] = lastblk >> 24; ! 402: buf[1] = lastblk >> 16; ! 403: buf[2] = lastblk >> 8; ! 404: buf[3] = lastblk; ! 405: buf[4] = blksize >> 24; ! 406: buf[5] = blksize >> 16; ! 407: buf[6] = blksize >> 8; ! 408: buf[7] = blksize; ! 409: ! 410: return SCSI::XferPhase::DataIn; ! 411: } ! 412: }; ! 413: ! 414: // ! 415: // SCSI コマンド 0x28 Read(10) (ダイレクトアクセスデバイス) ! 416: // ! 417: class SCSICmdRead10 : public SCSICmd ! 418: { ! 419: typedef SCSICmd inherited; ! 420: public: ! 421: SCSICmdRead10(SCSITarget *p) : inherited(p) { } ! 422: virtual ~SCSICmdRead10() { } ! 423: ! 424: virtual SCSI::XferPhase Command(std::vector<uint8>& cmdseq) { ! 425: SCSIHD *hdparent = dynamic_cast<SCSIHD*>(parent); ! 426: uint32 lba; ! 427: uint32 blks; ! 428: ! 429: if ((cmdseq[1] & 0x01)) { ! 430: parent->putmsg("SCSI Read(10) RelAdr not supported"); ! 431: } ! 432: ! 433: lba = cmdseq[2] << 24; ! 434: lba |= cmdseq[3] << 16; ! 435: lba |= cmdseq[4] << 8; ! 436: lba |= cmdseq[5]; ! 437: blks = cmdseq[7] << 8; ! 438: blks |= cmdseq[8]; ! 439: ! 440: // XXX 範囲チェック ! 441: uint8 *start = hdparent->mem + lba * hdparent->blocksize; ! 442: uint8 *end = start + blks * hdparent->blocksize; ! 443: buf.assign(start, end); ! 444: ! 445: parent->putlog(1, "READ10 LBA=0x%x blks=0x%x", lba, blks); ! 446: return SCSI::XferPhase::DataIn; ! 447: } ! 448: }; ! 449: ! 450: // ! 451: // SCSI コマンド サポートしていないコマンド ! 452: // ! 453: class SCSICmdNotSupportedCommand : public SCSICmd ! 454: { ! 455: typedef SCSICmd inherited; ! 456: public: ! 457: SCSICmdNotSupportedCommand(SCSITarget *p) : inherited(p) { } ! 458: virtual ~SCSICmdNotSupportedCommand() { } ! 459: ! 460: // Command は何もせずステータスに移るだけなので基底のやつでいい ! 461: ! 462: virtual void BeginStatus() { ! 463: buf.clear(); ! 464: buf.push_back((uint8)SCSI::StatusByte::CheckCondition); ! 465: } ! 466: }; ! 467: ! 468: ! 469: // ! 470: // SCSI ターゲットデバイスの共通部分 ! 471: // ! 472: ! 473: // コンストラクタ ! 474: SCSITarget::SCSITarget(SCSIHostDevice *h, int id, std::vector<uint8>& inq) ! 475: { ! 476: logname = "scsitarget"; ! 477: devname = "SCSITarget"; ! 478: ! 479: inquiry_data = inq; ! 480: // ホストへのリンク (所有関係のないポインタ) ! 481: host = h; ! 482: myid = id; ! 483: } ! 484: ! 485: // デストラクタ ! 486: SCSITarget::~SCSITarget() ! 487: { ! 488: } ! 489: ! 490: // セレクションで選択された (SCSIBus から呼ばれる) ! 491: void ! 492: SCSITarget::SelectionCB() ! 493: { ! 494: // ターゲットが、自身が選択されていることを認識してから BSY を ! 495: // 立てるまでの時間はもうバス側でカウントしてあるので、ここでは ! 496: // ただちに BSY を上げてよい。 ! 497: putlog(4, "Selection Callback"); ! 498: AssertBSY(); ! 499: } ! 500: ! 501: // 情報転送フェーズを開始する (SCSIBus から呼ばれる) ! 502: void ! 503: SCSITarget::StartTransferCB() ! 504: { ! 505: // 最初はコマンドフェーズ。(ATN はとりあえず放置) ! 506: putlog(4, "Start Command Phase"); ! 507: cmdseq.clear(); ! 508: cmdlen = 0; ! 509: SetXfer(SCSI::XferPhase::Command); ! 510: AssertREQ(); ! 511: } ! 512: ! 513: // 情報転送フェーズ間の遷移について ! 514: // ! 515: // 情報転送フェーズは TransferCB() で1バイトずつ転送を行い、所定のバイト数 ! 516: // の転送が完了すればフェーズを遷移する。遷移方法は入出力方向別で6通り。 ! 517: // o IN -> IN ! 518: // o IN -> OUT ! 519: // o IN -> END ! 520: // o OUT -> OUT ! 521: // o OUT -> IN ! 522: // o OUT -> END ! 523: // ! 524: // IN -> IN の遷移。TransferCB() で前フェーズの最終バイト受信後、フェーズを ! 525: // 変更して REQ を立てるところまで。 ! 526: // ! 527: // IN -> OUT の遷移。TransferCB() で前フェーズの最終バイト受信後、フェーズを ! 528: // 変更して (おそらく {Phase}Begin() を発行してから)、データをセットし REQ ! 529: // を立てる? ! 530: // ! 531: // IN -> END の遷移。TransferCB() で前フェーズの最終バイト受信後、BSY を ! 532: // 下げて終了。 ! 533: // ! 534: // OUT -> OUT の遷移。前フェーズの最終バイトをイニシエータが受信後に ! 535: // TransferCB() が呼ばれるので、フェーズを変更して (おそらく {Phase}Begin() ! 536: // を発行してから)、データをセットし REQ を立てる? ! 537: // ! 538: // OUT -> IN の遷移。前フェーズの最終バイトをイニシエータが受信後に ! 539: // TransferCB() が呼ばれるので、フェーズを変更して (おそらく {Phase}Begin() ! 540: // を発行してから)、REQ を立てる? ! 541: // ! 542: // OUT -> END の遷移。前フェーズの最終バイトをイニシエータが受信後に ! 543: // TransferCB() が呼ばれるので、BSY を下げる? ! 544: ! 545: // 情報転送フェーズでイニシエータが ACK を上げた。(SCSIBus から呼ばれる) ! 546: // OUT (イニシエータ → ターゲット方向) なら、ターゲットが上げた REQ に応答 ! 547: // してイニシエータがデータをデータバスに乗せてからこれをコールしてくる。 ! 548: // IN (ターゲット → イニシエータ方向) なら、ターゲットがデータをデータバスに ! 549: // 乗せて REQ を上げたのをイニシエータが受信した後でこれをコールしてくる。 ! 550: void ! 551: SCSITarget::TransferCB() ! 552: { ! 553: uint8 data; ! 554: SCSI::XferPhase xfer; ! 555: ! 556: // このフェーズの最終バイトか ! 557: lastbyte = false; ! 558: ! 559: // このフェーズの1バイト処理 ! 560: xfer = GetXfer(); ! 561: if (xfer == SCSI::XferPhase::Command) { ! 562: // コマンドフェーズだけいろいろ特殊なので別処理。 ! 563: // 受信バッファが異なる、1バイト目で受信長が決まるなど。 ! 564: data = GetData(); ! 565: putlog(4, "TransferCB: cmdseq[%02d] = $%02x", ! 566: (int)cmdseq.size(), data); ! 567: cmdseq.push_back(data); ! 568: if (cmdseq.size() == 1) { ! 569: // 1バイト目ならこのコマンドが何バイトか調べる ! 570: switch (cmdseq[0] >> 5) { ! 571: case 0: cmdlen = 6; break; ! 572: case 1: cmdlen = 10; break; ! 573: case 2: cmdlen = 10; break; ! 574: case 5: cmdlen = 12; break; ! 575: default: ! 576: // 3,4 はリサーブ、6,7 はベンダー定義。XXX 来たらどうする? ! 577: cmdlen = 6; ! 578: break; ! 579: } ! 580: } else if (cmdseq.size() >= cmdlen) { ! 581: if (loglevel >= 1) { ! 582: std::string cmdbuf; ! 583: const char *name = SCSI::GetCommandName(cmdseq[0]); ! 584: cmdbuf += string_format("Command \"%s\"", name ?: "?"); ! 585: for (const auto& v : cmdseq) { ! 586: cmdbuf += string_format(" $%02x", v); ! 587: } ! 588: putlog("%s", cmdbuf.c_str()); ! 589: } ! 590: // 最終バイトを受信したらコマンドを選択 ! 591: DispatchCmd(); ! 592: lastbyte = true; ! 593: } ! 594: } else if (GetIO() == false) { ! 595: // OUT 方向 (ターゲットが受信側) ! 596: // bytecount は減算方向。 ! 597: cmd->buf.push_back(GetData()); ! 598: bytecount--; ! 599: if (bytecount == 0) { ! 600: lastbyte = true; ! 601: } ! 602: } else { ! 603: // IN 方向 (ターゲットが送信側) ! 604: // bytecount は加算方向。 ! 605: // データは前のループの終わり (TransferAckCB()の下のほう) で ! 606: // セットしているのでここでは引き取られた分をカウントする。 ! 607: bytecount++; ! 608: if (bytecount >= cmd->buf.size()) { ! 609: lastbyte = true; ! 610: } ! 611: } ! 612: ! 613: NegateREQ(); ! 614: } ! 615: ! 616: // 情報転送フェーズでイニシエータが ACK を下げた。(SCSIBus から呼ばれる) ! 617: void ! 618: SCSITarget::TransferAckCB() ! 619: { ! 620: SCSI::XferPhase xfer = GetXfer(); ! 621: ! 622: // これが最終バイトだったら、フェーズ完了 → フェーズ切り替え。 ! 623: if (lastbyte) { ! 624: SCSI::XferPhase next; ! 625: // フェーズ完了 ! 626: switch (xfer) { ! 627: case SCSI::XferPhase::Command: ! 628: next = cmd->Command(cmdseq); ! 629: break; ! 630: case SCSI::XferPhase::DataOut: ! 631: next = cmd->DoneDataOut(); ! 632: break; ! 633: case SCSI::XferPhase::DataIn: ! 634: next = cmd->DoneDataIn(); ! 635: break; ! 636: case SCSI::XferPhase::MsgOut: ! 637: next = cmd->DoneMsgOut(); ! 638: break; ! 639: case SCSI::XferPhase::MsgIn: ! 640: next = cmd->DoneMsgIn(); ! 641: break; ! 642: case SCSI::XferPhase::Status: ! 643: next = cmd->DoneStatus(); ! 644: break; ! 645: default: ! 646: PANIC("TransferCB unknown xfer done %d", (int)xfer); ! 647: } ! 648: putlog(2, "%s done", SCSI::GetXferPhaseName(xfer)); ! 649: ! 650: if (next != xfer) { ! 651: // End ならバスフリーにして終了。 ! 652: if (next == SCSI::XferPhase::End) { ! 653: NegateBSY(); ! 654: return; ! 655: } ! 656: ! 657: // (必要なら)フェーズを更新 ! 658: SetXfer(next); ! 659: xfer = next; ! 660: ! 661: // 新しいフェーズの開始処理 ! 662: // XXX ここで bytecount とかをリセットできればいいのだが ! 663: // Command フェーズで Data フェーズの準備をすることが多いので ! 664: // 悩ましい。 ! 665: switch (xfer) { ! 666: case SCSI::XferPhase::DataOut: ! 667: cmd->BeginDataOut(); ! 668: cmd->buf.clear(); ! 669: bytecount = cmd->recvbytes; ! 670: putlog(3, "DataOut begin (%d bytes)", bytecount); ! 671: break; ! 672: case SCSI::XferPhase::DataIn: ! 673: cmd->BeginDataIn(); ! 674: bytecount = 0; ! 675: putlog(3, "DataIn begin (%d bytes)", (int)cmd->buf.size()); ! 676: break; ! 677: case SCSI::XferPhase::MsgOut: ! 678: cmd->BeginMsgOut(); ! 679: cmd->buf.clear(); ! 680: bytecount = cmd->recvbytes; ! 681: putlog(3, "MsgOut begin (%d bytes)", bytecount); ! 682: break; ! 683: case SCSI::XferPhase::MsgIn: ! 684: cmd->BeginMsgIn(); ! 685: bytecount = 0; ! 686: putlog(3, "MsgIn begin (%d bytes)", (int)cmd->buf.size()); ! 687: break; ! 688: case SCSI::XferPhase::Status: ! 689: cmd->BeginStatus(); ! 690: bytecount = 0; ! 691: putlog(3, "Status begin (%d bytes)", (int)cmd->buf.size()); ! 692: break; ! 693: default: ! 694: PANIC("TransferCB unknown xfer begin %d", (int)xfer); ! 695: } ! 696: } ! 697: } ! 698: ! 699: // IN 方向 (ターゲットが送信側) ならここでデータをバスにセット。 ! 700: if (GetIO()) { ! 701: SetData(cmd->buf[bytecount]); ! 702: putlog(4, "SetData $%02x", GetData()); ! 703: } ! 704: ! 705: // 次のバイト転送を行うために REQ を上げる。 ! 706: AssertREQ(); ! 707: } ! 708: ! 709: // SCSI コマンドのディスパッチャ ! 710: void ! 711: SCSITarget::DispatchCmd() ! 712: { ! 713: switch (cmdseq[0]) { ! 714: case SCSI::Command::TestUnitReady: // 0x00 ! 715: cmd.reset(new SCSICmdTestUnitReady(this)); ! 716: break; ! 717: ! 718: case SCSI::Command::RequestSense: // 0x03 ! 719: cmd.reset(new SCSICmdRequestSense(this)); ! 720: break; ! 721: ! 722: case SCSI::Command::Inquiry: // 0x12 ! 723: cmd.reset(new SCSICmdInquiry(this)); ! 724: break; ! 725: ! 726: case SCSI::Command::ModeSelect6: // 0x15 ! 727: cmd.reset(new SCSICmdModeSelect6(this)); ! 728: break; ! 729: ! 730: case SCSI::Command::ReadCapacity: // 0x25 ! 731: cmd.reset(new SCSICmdTestUnitReady(this)); ! 732: break; ! 733: ! 734: default: ! 735: // サポートしていないコマンド ! 736: const char *cname = SCSI::GetCommandName(cmdseq[0]); ! 737: std::string name; ! 738: if (cname) { ! 739: name = string_format(" %s", cname); ! 740: } ! 741: putlog(0, "未実装 SCSI コマンド $%02x%s len=%d", ! 742: cmdseq[0], name.c_str(), (int)cmdseq.size()); ! 743: ! 744: cmd.reset(new SCSICmdNotSupportedCommand(this)); ! 745: break; ! 746: } ! 747: } ! 748: ! 749: // ! 750: // SCSI HD ! 751: // ! 752: ! 753: // コンストラクタ ! 754: SCSIHD::SCSIHD(SCSIHostDevice *h, int id) ! 755: : inherited(h, id, inquiry_data) ! 756: { ! 757: devname = "SCSIHD"; ! 758: devtype = SCSI::HD; ! 759: fd = -1; ! 760: mem = NULL; ! 761: } ! 762: ! 763: // デストラクタ ! 764: SCSIHD::~SCSIHD() ! 765: { ! 766: if (mem) { ! 767: munmap(mem, memlen); ! 768: mem = NULL; ! 769: } ! 770: if (fd >= 0) { ! 771: close(fd); ! 772: fd = -1; ! 773: } ! 774: } ! 775: ! 776: // 初期化 ! 777: bool ! 778: SCSIHD::Init() ! 779: { ! 780: struct stat st; ! 781: ! 782: const std::string myname = string_format("%s:ID%d", ! 783: host->GetConfigName(), myid); ! 784: const std::string keybody = string_format("%s_id%d_", ! 785: host->GetConfigName(), myid); ! 786: const std::string imgkey = keybody + "image"; ! 787: const std::string wpkey = keybody + "writeprotect"; ! 788: ! 789: // devtype があって image がないのは異常状態なのでエラー ! 790: const std::string& filename = gConfig->ReadStr(imgkey); ! 791: if (filename == "") { ! 792: gConfig->Err(imgkey, "not specified"); ! 793: return false; ! 794: } ! 795: ! 796: const std::string path = gConfig->GetConfigDir() + filename; ! 797: fd = open(path.c_str(), O_RDWR); ! 798: if (fd == -1) { ! 799: warn("%s \"%s\" open failed", myname.c_str(), path.c_str()); ! 800: return false; ! 801: } ! 802: ! 803: if (fstat(fd, &st) == -1) { ! 804: warn("%s \"%s\" fstat failed", myname.c_str(), path.c_str()); ! 805: close(fd); ! 806: return false; ! 807: } ! 808: ! 809: memlen = st.st_size; ! 810: mem = (uint8 *)mmap(NULL, memlen, PROT_READ | PROT_WRITE, ! 811: MAP_SHARED, fd, 0); ! 812: if (mem == MAP_FAILED) { ! 813: warn("%s \"%s\" mmap failed", myname.c_str(), path.c_str()); ! 814: close(fd); ! 815: return false; ! 816: } ! 817: ! 818: writeprotect = (bool)gConfig->ReadInt(wpkey); ! 819: if (writeprotect) { ! 820: putmsg(0, "%s: write protected", myname.c_str()); ! 821: } ! 822: ! 823: return true; ! 824: } ! 825: ! 826: // SCSI コマンドのディスパッチャ ! 827: void ! 828: SCSIHD::DispatchCmd() ! 829: { ! 830: switch (cmdseq[0]) { ! 831: case SCSI::Command::Read6: // 0x08 ! 832: cmd.reset(new SCSICmdRead6(this)); ! 833: break; ! 834: ! 835: case SCSI::Command::Write6: // 0x0a ! 836: cmd.reset(new SCSICmdWrite6(this)); ! 837: break; ! 838: ! 839: case SCSI::Command::ReadCapacity: // 0x25 ! 840: cmd.reset(new SCSICmdReadCapacity(this)); ! 841: break; ! 842: ! 843: case SCSI::Command::Read10: // 0x28 ! 844: cmd.reset(new SCSICmdRead10(this)); ! 845: break; ! 846: ! 847: default: ! 848: // 見付からなければ基本クラス側に任せる ! 849: inherited::DispatchCmd(); ! 850: break; ! 851: } ! 852: } ! 853: ! 854: // HD の inquiry データ ! 855: /*static*/ std::vector<uint8> ! 856: SCSIHD::inquiry_data = { ! 857: 0x00, // 00 Qualifier + DeviceType ! 858: 0x00, // 01 RMB ! 859: 0x40, // 02 ISO version ! 860: 0x00, // 03 Response Data Format? ! 861: 36 - 4, // 04 追加データ長 ! 862: 0, // 05 Reserved ! 863: 0, // 06 Reserved ! 864: 0x00, // 07 ! 865: 'N', 'O', 'N', 'O', ' ', ' ', ' ', ' ', ! 866: 'S', 'C', 'S', 'I', 'H', 'D', ' ', ' ', ! 867: ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ! 868: 'r', 'e', 'v', '0', ! 869: };
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.