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

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: 
1.1.1.2 ! root      779:        // モードページ
1.1       root      780:        if (pagecode == SCSI::ModePage::AllPages) {
                    781:                // サポートしているのを全部送る。
                    782:                if (parent->loglevel >= 1) {
                    783:                        log += " " + SCSI::GetModePageDisp(pagecode);
                    784:                        log += "->";
                    785:                }
1.1.1.2 ! root      786:                for (auto& pair : Pagelist) {
1.1       root      787:                        auto code = pair.first;
1.1.1.2 ! root      788:                        auto func = pair.second;
1.1       root      789: 
1.1.1.2 ! root      790:                        if ((this->*(func))() != ModePageResult::Failed) {
1.1       root      791:                                if (parent->loglevel >= 1) {
                    792:                                        log += " " + SCSI::GetModePageDisp(code);
                    793:                                }
                    794:                        }
                    795:                }
                    796:        } else {
                    797:                // 指定されたページコードを送る。
                    798:                ModePageResult r = ModePageResult::NotImplemented;
1.1.1.2 ! root      799:                for (auto& pair : Pagelist) {
1.1       root      800:                        auto code = pair.first;
1.1.1.2 ! root      801:                        auto func = pair.second;
1.1       root      802: 
                    803:                        if (pagecode == code) {
1.1.1.2 ! root      804:                                r = (this->*(func))();
1.1       root      805:                                break;
                    806:                        }
                    807:                }
                    808: 
                    809:                // Failed は対応しない/できないと分かっているページ、
                    810:                // NotImplemented は未実装や知らないページ。
                    811:                if (r <= ModePageResult::Failed) {
                    812:                        if (parent->loglevel >= 1) {
                    813:                                if (r == ModePageResult::NotImplemented) {
                    814:                                        parent->putlogn("%s 未実装", log.c_str());
                    815:                                } else {
                    816:                                        parent->putlogn("%s", log.c_str());
                    817:                                }
                    818:                        }
                    819:                        parent->sensekey = SCSI::SenseKey::IllegalRequest;
                    820:                        parent->senseasc = SCSI::ASC::InvalidFieldInCDB;
                    821:                        status_byte = SCSI::StatusByte::CheckCondition;
                    822:                        return SCSI::XferPhase::Status;
                    823:                }
                    824:        }
                    825: 
                    826:        parent->putlogf(1, [&] { return log; });
                    827: 
                    828:        // モードパラメータ長は自フィールドを含まない長さ
                    829:        if (cmd == SCSI::Command::ModeSelect10) {
                    830:                uint buflen = buf.size() - 2;
                    831:                buf[0] = buflen >> 8;
                    832:                buf[1] = buflen;
                    833:        } else {
                    834:                uint buflen = buf.size() - 1;
                    835:                buf[0] = buflen;
                    836:        }
                    837: 
                    838:        // 本来の応答データ長か reqlen の短いほうまで
                    839:        if (reqlen < buf.size()) {
                    840:                buf.resize(reqlen);
                    841:        }
                    842:        return SCSI::XferPhase::DataIn;
                    843: }
                    844: 
1.1.1.2 ! root      845: // ページを送信する順(=昇順)に (手動で) 並べること。
        !           846: // ただし 0x00 (VendorSpecific) は最後。
        !           847: #define PAGE(code, func)       \
        !           848:        { SCSI::ModePage::code, &SCSICmdModeSense::func }
        !           849: /*static*/ const std::vector<std::pair<uint8, SCSICmdModeSense::PageFunc>>
        !           850: SCSICmdModeSense::Pagelist {
        !           851:        PAGE(/*04*/RigidDiskGeometry,   AddNotSupportedPage),
        !           852:        PAGE(/*05*/FlexibleDisk,                AddNotSupportedPage),
        !           853:        PAGE(/*08*/CachingPage,                 AddCachingPage),
        !           854:        PAGE(/*00*/VendorSpecific,              AddEmptyPage),
        !           855: };
        !           856: 
1.1       root      857: // サポートしないページ
                    858: //
                    859: // ページコード 04 RigidDiskGeometry (DA)
                    860: //  -> 生イメージからジオメトリを求めるのは意味ないので実装しない。
                    861: // ページコード 05 FlexibleDisk (DA)
                    862: //  -> ジオメトリなどのパラメータがメインっぽいので実装しない。
1.1.1.2 ! root      863: SCSICmdModeSense::ModePageResult
1.1       root      864: SCSICmdModeSense::AddNotSupportedPage()
                    865: {
                    866:        return ModePageResult::Failed;
                    867: }
                    868: 
                    869: // 空のページ
1.1.1.2 ! root      870: SCSICmdModeSense::ModePageResult
1.1       root      871: SCSICmdModeSense::AddEmptyPage()
                    872: {
                    873:        std::vector<uint8> page(2);
                    874:        page[0] = pagecode;                             // +0 ページコード
                    875:        page[1] = page.size() - 2;              // +1 このバイト以降のページ長
                    876: 
                    877:        buf.insert(buf.end(), page.begin(), page.end());
                    878:        buf[0] += page.size();
                    879:        return ModePageResult::Success;
                    880: }
                    881: 
                    882: // ページコード 08 CachingPage (DA, MO, CD-ROM)
1.1.1.2 ! root      883: SCSICmdModeSense::ModePageResult
1.1       root      884: SCSICmdModeSense::AddCachingPage()
                    885: {
                    886:        const SCSIDisk *disk = dynamic_cast<const SCSIDisk*>(parent);
                    887:        assert(disk);
                    888: 
                    889:        // とりあえずパラメータはなんもなし。
                    890:        // PC::Changeable でも全部 0 なのでこのままでいい。
                    891:        std::vector<uint8> page(12);
                    892:        page[0] = pagecode;                             // +0 ページコード
                    893:        page[1] = page.size() - 2;              // +1 このバイト以降のページ長
                    894:        // +2 WCE, MF, RCD フラグ
                    895:        // +3 データの保持優先度
                    896:        // +4 プリフェッチ抑止ブロック数
                    897:        // +6 最小プリフェッチ
                    898:        // +8 最大プリフェッチ
                    899:        // +10 最大プリフェッチ制限ブロック数
                    900: 
                    901:        buf.insert(buf.end(), page.begin(), page.end());
                    902:        buf[0] += page.size();
                    903:        return ModePageResult::Success;
                    904: }
                    905: 
                    906: 
                    907: //
                    908: // SCSI コマンド 0x1b StartStopUnit (DA / CD-ROM)
                    909: //
                    910: //    +---+---+---+---+---+---+---+---+
                    911: //  0 |         Operation Code        |
                    912: //    +-----------+---------------+---+
                    913: //  1 |    LUN    |         0     | I | I:Immediate
                    914: //    +-----------+---------------+---+
                    915: //  2 |               0               |
                    916: //  3 |               0               |
                    917: //    +-----------------------+---+---+
                    918: //  4 |               0       |L/E| S | L/E:Load/Eject, S:Start
                    919: //    +-----------------------+---+---+
                    920: //  5 |          Control Byte         |
                    921: //    +-------------------------------+
                    922: 
                    923: // コンストラクタ
                    924: SCSICmdStartStopUnit::SCSICmdStartStopUnit(SCSIDisk *parent_)
                    925:        : inherited(parent_)
                    926: {
                    927:        disk = parent_;
                    928: }
                    929: 
                    930: // デストラクタ
                    931: SCSICmdStartStopUnit::~SCSICmdStartStopUnit()
                    932: {
                    933: }
                    934: 
                    935: // コマンドフェーズ
                    936: SCSI::XferPhase
                    937: SCSICmdStartStopUnit::Command(std::vector<uint8>& cmdseq)
                    938: {
                    939:        bool immed = (cmdseq[1] & 0x01);
                    940:        if (immed) {
                    941:                parent->putlogf(1, lstr("%s Immed=1 not supported",
                    942:                        SCSI::GetCommandName(cmdseq[0])));
                    943:        }
                    944: 
                    945:        bool loej  = (cmdseq[4] & 0x02);
                    946:        bool start = (cmdseq[4] & 0x01);
                    947:        parent->putlogf(1, lstr("%s LoEj=%d Start=%d",
                    948:                SCSI::GetCommandName(cmdseq[0]), (loej ? 1 : 0), (start ? 1 : 0)));
                    949: 
                    950:        if (disk->IsRemovableDevice()) {
                    951:                // LoEj Start
                    952:                // x    0               媒体へのアクセスを不可にする?
                    953:                // x    1               媒体へのアクセスを可にする?
                    954:                // 1    0               媒体のアンロード
                    955:                // 1    1               媒体のロード
                    956:                //
                    957:                // らしいけど、イジェクトのみ対応
                    958:                if (loej) {
                    959:                        if (disk->IsMediumLoaded()) {
                    960:                                disk->UnloadDisk();
                    961:                        } else {
                    962:                                // メディアがロードされてない時にトレイを開ける動作に
                    963:                                // 相当するのは「ファイルダイアログを出す」だが伝わるだろうか
                    964:                                parent->putlogf(0, lstr("%s Loading not supported",
                    965:                                        SCSI::GetCommandName(cmdseq[0])));
                    966:                        }
                    967:                } else {
                    968:                        parent->putlogf(0, lstr("%s LoEj=0 not supported",
                    969:                                SCSI::GetCommandName(cmdseq[0])));
                    970:                }
                    971:        } else {
                    972:                // 固定デバイスなら黙って成功しておく?
                    973:        }
                    974:        return inherited::Command(cmdseq);
                    975: }
                    976: 
                    977: 
                    978: //
                    979: // SCSI コマンド 0x1e PreventAllowMediumRemoval (DA / CD-ROM)
                    980: //
                    981: //    +---+---+---+---+---+---+---+---+
                    982: //  0 |         Operation Code        |
                    983: //    +-----------+-------------------+
                    984: //  1 |    LUN    |         0         |
                    985: //    +-----------+-------------------+
                    986: //  2 |               0               |
                    987: //  3 |               0               |
                    988: //    +---------------------------+---+
                    989: //  4 |               0           | P | P:Prevent
                    990: //    +---------------------------+---+
                    991: //  5 |          Control Byte         |
                    992: //    +-------------------------------+
                    993: 
                    994: // XXX コマンドとしてはダイレクトアクセスデバイスに対しても発行できるが、
                    995: // その時どう応答すべきかは要調査
                    996: 
                    997: // コンストラクタ
                    998: SCSICmdPreventAllowMediumRemoval::SCSICmdPreventAllowMediumRemoval(
                    999:        SCSIDisk *parent_)
                   1000:        : inherited(parent_)
                   1001: {
                   1002:        disk = parent_;
                   1003: }
                   1004: 
                   1005: // デストラクタ
                   1006: SCSICmdPreventAllowMediumRemoval::~SCSICmdPreventAllowMediumRemoval()
                   1007: {
                   1008: }
                   1009: 
                   1010: // コマンドフェーズ
                   1011: SCSI::XferPhase
                   1012: SCSICmdPreventAllowMediumRemoval::Command(std::vector<uint8>& cmdseq)
                   1013: {
                   1014:        // コマンド開始前に直前のセンスデータをクリア
                   1015:        parent->ClearSense();
                   1016: 
                   1017:        CheckLUN;
                   1018:        CheckMedium;
                   1019: 
                   1020:        // PreventMediumRemoval() は状態変化でログレベル 1 で表示してるので、
                   1021:        // ここではログレベル 2 で常に表示にしておく。
                   1022:        uint prevent = cmdseq[4] & 1;
                   1023:        parent->putlogf(2, lstr("%s prevent=%d",
                   1024:                SCSI::GetCommandName(cmdseq[0]), prevent));
                   1025: 
                   1026:        disk->PreventMediumRemoval(prevent);
                   1027:        return SCSI::XferPhase::Status;
                   1028: }
                   1029: 
                   1030: 
                   1031: //
                   1032: // SCSI コマンド 0x25 ReadCapacity      (DA)
                   1033: //               0x25 ReadCDROMCapacity (CD-ROM)
                   1034: //
                   1035: //    +---+---+---+---+---+---+---+---+
                   1036: //  0 |         Operation Code        |
                   1037: //    +-----------+---------------+---+
                   1038: //  1 |    LUN    |       0       |Rel|
                   1039: //    +-----------+---------------+---+
                   1040: //  2 |                               |
                   1041: //  3 |      論理ブロックアドレス     |
                   1042: //  4 |      (PMI=0 なら 0)           |
                   1043: //  5 |                               |
                   1044: //    +-------------------------------+
                   1045: //  6 |               0               |
                   1046: //  7 |               0               |
                   1047: //    +---------------------------+---+
                   1048: //  8 |               0           |PMI|
                   1049: //    +---------------------------+---+
                   1050: //  9 |          Control Byte         |
                   1051: //    +-------------------------------+
                   1052: //
                   1053: // CD-ROM デバイスでは同じ 0x25 で Read CDROM Capacity というコマンド名。
                   1054: // Read CDROM Capacity のほうはオーディオ CD の場合の意味分けが追加されて
                   1055: // いるが、たぶんデータ CD だけを扱ううちはダイレクトアクセスデバイスの
                   1056: // Read Capacity と同じでいいはず。
                   1057: 
                   1058: // コンストラクタ
                   1059: SCSICmdReadCapacity::SCSICmdReadCapacity(SCSIDisk *parent_)
                   1060:        : inherited(parent_)
                   1061: {
                   1062:        disk = parent_;
                   1063: }
                   1064: 
                   1065: // デストラクタ
                   1066: SCSICmdReadCapacity::~SCSICmdReadCapacity()
                   1067: {
                   1068: }
                   1069: 
                   1070: // コマンドフェーズ
                   1071: SCSI::XferPhase
                   1072: SCSICmdReadCapacity::Command(std::vector<uint8>& cmdseq)
                   1073: {
                   1074:        // コマンド開始前に直前のセンスデータをクリア
                   1075:        parent->ClearSense();
                   1076: 
                   1077:        CheckLUN;
                   1078:        CheckMedium;
                   1079: 
                   1080:        // PMI=1 は未サポート
                   1081:        if ((cmdseq[8] & 0x01) != 0) {
                   1082:                parent->putlogf(0, lstr("%s PMI=1 not supported",
                   1083:                        SCSI::GetCommandName(cmdseq[0])));
                   1084:        }
                   1085: 
                   1086:        // 応答データは
                   1087:        // +00.L 最終論理ブロックアドレス
                   1088:        // +04.L ブロック長
                   1089:        uint32 blksize = parent->GetBlocksize();
                   1090:        uint32 lastblk = (disk->GetSize() / blksize) - 1;
                   1091:        parent->putlogf(1, lstr("%s -> lastblk=$%x blksize=$%x",
                   1092:                SCSI::GetCommandName(cmdseq[0]), lastblk, blksize));
                   1093:        buf.resize(8);
                   1094:        buf[0] = lastblk >> 24;
                   1095:        buf[1] = lastblk >> 16;
                   1096:        buf[2] = lastblk >> 8;
                   1097:        buf[3] = lastblk;
                   1098:        buf[4] = blksize >> 24;
                   1099:        buf[5] = blksize >> 16;
                   1100:        buf[6] = blksize >> 8;
                   1101:        buf[7] = blksize;
                   1102: 
                   1103:        return SCSI::XferPhase::DataIn;
                   1104: }
                   1105: 
                   1106: 
                   1107: //
                   1108: // SCSI コマンド 0x43 ReadTOC (CD-ROM)
                   1109: //
                   1110: //    +---+---+---+---+---+---+---+---+
                   1111: //  0 |         Operation Code        |
                   1112: //    +-----------+-----------+---+---+
                   1113: //  1 |    LUN    |     0     |MSF| 0 |
                   1114: //    +-----------+-----------+---+---+
                   1115: //  2 |               0               |
                   1116: //  3 |               0               |
                   1117: //  4 |               0               |
                   1118: //  5 |               0               |
                   1119: //    +-------------------------------+
                   1120: //  6 |          開始トラック         |
                   1121: //    +-------------------------------+
                   1122: //  7 |        アロケーション長       |
                   1123: //  8 |                               |
                   1124: //    +-------------------------------+
                   1125: //  9 |          Control Byte         |
                   1126: //    +-------------------------------+
                   1127: 
                   1128: // コンストラクタ
                   1129: SCSICmdReadTOC::SCSICmdReadTOC(SCSIDisk *parent_)
                   1130:        : inherited(parent_)
                   1131: {
                   1132:        disk = parent_;
                   1133: }
                   1134: 
                   1135: // デストラクタ
                   1136: SCSICmdReadTOC::~SCSICmdReadTOC()
                   1137: {
                   1138: }
                   1139: 
                   1140: // コマンドフェーズ
                   1141: SCSI::XferPhase
                   1142: SCSICmdReadTOC::Command(std::vector<uint8>& cmdseq)
                   1143: {
                   1144:        // コマンド開始前に直前のセンスデータをクリア
                   1145:        parent->ClearSense();
                   1146: 
                   1147:        CheckLUN;
                   1148:        CheckMedium;
                   1149: 
                   1150:        // MSF 形式は未実装
                   1151:        if ((cmdseq[1] & 0x02)) {
                   1152:                parent->putlogf(0, lstr("ReadTOC MSF=1 未実装"));
                   1153:        }
                   1154: 
                   1155:        // 開始トラックが 0 なら、媒体上の先頭トラックからを意味する。
                   1156:        // ここでは1トラック目から始まることにしてみる。
                   1157:        const int TrackStart = 1;
                   1158:        const int TrackMax = 1;
                   1159: 
                   1160:        int start = cmdseq[6];
                   1161:        if (start == 0) {
                   1162:                start = TrackStart;
                   1163:        }
                   1164: 
                   1165:        // イニシエータが用意しているバッファ長
                   1166:        int reqlen = (cmdseq[7] << 8) | cmdseq[8];
                   1167: 
                   1168:        // start は送られてきた情報が知りたいだろう
                   1169:        parent->putlogf(1, lstr("%s start=$%x len=$%x",
                   1170:                SCSI::GetCommandName(cmdseq[0]), cmdseq[6], reqlen));
                   1171: 
                   1172:        // ヘッダ4バイト + トラックディスクリプタ(8バイト) * トラック数で、
                   1173:        // ここではトラックは常に1つ。
                   1174:        buf.clear();
                   1175:        buf.resize(4 + 8 * 1);
                   1176: 
                   1177:        // TOC データ長はこの2バイトのフィールドを含まないバイト数で、
                   1178:        // 開始トラック以降の有効な全トラック数。
                   1179:        int tocdatalen = 2;
                   1180:        if (start <= TrackMax) {
                   1181:                tocdatalen += (TrackMax - start) * 8;
                   1182:        }
                   1183:        // 開始論理アドレス
                   1184:        uint32 address = 0;
                   1185: 
                   1186:        // ヘッダ
                   1187:        buf[0]  = tocdatalen >> 8;      // TOC データ長
                   1188:        buf[1]  = tocdatalen;           // TOC データ長
                   1189:        buf[2]  = start;                        // 先頭トラック番号
                   1190:        buf[3]  = TrackMax;                     // 最終トラック番号
                   1191:        // トラック1
                   1192:        buf[4]  = 0;                            // Reserved
                   1193:        buf[5]  = 0x06;                         // ADR=0(?)、データトラック
                   1194:        buf[6]  = 1;                            // トラック番号
                   1195:        buf[7]  = 0;                            // Reserved
                   1196:        buf[8]  = address >> 24;        // 論理アドレス
                   1197:        buf[9]  = address >> 16;        // 論理アドレス
                   1198:        buf[10] = address >> 8;         // 論理アドレス
                   1199:        buf[11] = address;                      // 論理アドレス
                   1200: 
                   1201:        // 本来の応答データ長か reqlen の短いほうまで
                   1202:        if (reqlen < buf.size()) {
                   1203:                buf.resize(reqlen);
                   1204:        }
                   1205: 
                   1206:        return SCSI::XferPhase::DataIn;
                   1207: }

unix.superglobalmegacorp.com

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