Annotation of nono/vm/scsicmd.cpp, revision 1.1

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.