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

1.1       root        1: //
                      2: // nono
                      3: // Copyright (C) 2021 nono project
                      4: // Licensed under nono-license.txt
                      5: //
                      6: 
1.1.1.3   root        7: //
1.1       root        8: // SCSI コマンド
1.1.1.3   root        9: //
1.1       root       10: 
                     11: #include "scsicmd.h"
                     12: #include "scsidev.h"
                     13: 
                     14: #define LUN    (cmdseq[1] >> 5)
                     15: 
                     16: // LUN != 0 のリクエストをエラーにする (Command() 内で使う)。
                     17: #define CheckLUN       do {    \
                     18:        if (LUN != 0) { \
                     19:                parent->sensekey = SCSI::SenseKey::NotReady;    \
                     20:                parent->senseasc = SCSI::ASC::LogicalUnitNotSupported;  \
                     21:                status_byte = SCSI::StatusByte::CheckCondition; \
                     22:                return SCSI::XferPhase::Status; \
                     23:        }       \
                     24: } while (0)
                     25: // メディアがなければエラーにする (Command() 内で使う)。
                     26: #define CheckMedium    do {    \
                     27:        if (disk->IsMediumLoaded() == false) {  \
                     28:                parent->sensekey = SCSI::SenseKey::NotReady;    \
                     29:                parent->senseasc = SCSI::ASC::MediumNotPresent; \
                     30:                status_byte = SCSI::StatusByte::CheckCondition; \
                     31:                return SCSI::XferPhase::Status; \
                     32:        }       \
                     33: } while (0)
                     34: 
                     35: 
                     36: //
                     37: // SCSI コマンドの基本クラス
                     38: //
                     39: 
                     40: // コンストラクタ
                     41: SCSICmd::SCSICmd(SCSITarget *parent_)
                     42:        : parent(parent_)
                     43: {
                     44: }
                     45: 
                     46: // デストラクタ
                     47: SCSICmd::~SCSICmd()
                     48: {
                     49: }
                     50: 
                     51: // コマンドフェーズ
                     52: SCSI::XferPhase
                     53: SCSICmd::Command(std::vector<uint8>& cmdseq)
                     54: {
                     55:        // コマンド開始前に直前のセンスデータをクリア
                     56:        parent->ClearSense();
                     57: 
                     58:        CheckLUN;
                     59: 
                     60:        return SCSI::XferPhase::Status;
                     61: }
                     62: 
                     63: 
                     64: //
                     65: // SCSI コマンド: サポートしていないコマンド
                     66: //
                     67: 
                     68: // コンストラクタ
                     69: SCSICmdNotSupportedCommand::SCSICmdNotSupportedCommand(SCSITarget *parent_)
                     70:        : inherited(parent_)
                     71: {
                     72: }
                     73: 
                     74: // デストラクタ
                     75: SCSICmdNotSupportedCommand::~SCSICmdNotSupportedCommand()
                     76: {
                     77: }
                     78: 
                     79: // コマンドフェーズ
                     80: SCSI::XferPhase
                     81: SCSICmdNotSupportedCommand::Command(std::vector<uint8>& cmdseq)
                     82: {
                     83:        // XXX センスキーよく分からんけどとりあえず
                     84:        parent->sensekey = SCSI::SenseKey::IllegalRequest;
                     85:        parent->senseasc = SCSI::ASC::InvalidCommandOperationCode;
                     86:        status_byte = SCSI::StatusByte::CheckCondition;
                     87: 
                     88:        return SCSI::XferPhase::Status;
                     89: }
                     90: 
                     91: 
                     92: //
                     93: // SCSI コマンド 0x03 RequestSense (共通)
                     94: //
                     95: //    +---+---+---+---+---+---+---+---+
                     96: //  0 |         Operation Code        |
                     97: //    +-----------+-------------------+
                     98: //  1 |    LUN    |         0         |
                     99: //    +-------+---+-------------------+
                    100: //  2 |               0               |
                    101: //  3 |               0               |
                    102: //    +-------------------------------+
                    103: //  4 |        アロケーション長       |
                    104: //    +-------------------------------+
                    105: //  5 |          Control Byte         |
                    106: //    +-------------------------------+
                    107: 
                    108: // コンストラクタ
                    109: SCSICmdRequestSense::SCSICmdRequestSense(SCSITarget *parent_)
                    110:        : inherited(parent_)
                    111: {
                    112: }
                    113: 
                    114: // デストラクタ
                    115: SCSICmdRequestSense::~SCSICmdRequestSense()
                    116: {
                    117: }
                    118: 
                    119: // コマンドフェーズ
                    120: SCSI::XferPhase
                    121: SCSICmdRequestSense::Command(std::vector<uint8>& cmdseq)
                    122: {
                    123:        CheckLUN;
                    124: 
                    125:        // 応答のセンスデータは SCSI-2 形式(最小18バイト) を実装。
                    126:        // 今の所、センスキー、ASC、ASCQ だけで返せる内容にだけ対応している。
                    127:        // これ以外のフィールドを返す必要が出来たらまた考えること。
                    128:        uint sensekey = parent->sensekey;
                    129:        uint senseasc = parent->senseasc;
                    130:        parent->putlogf(1, lstr("%s -> %s asc=$%04x",
                    131:                SCSI::GetCommandName(cmdseq[0]),
                    132:                SCSI::GetSenseKeyDisp(sensekey).c_str(),
                    133:                senseasc));
                    134: 
                    135:        // 送信用に取り出した後でセンスデータをクリア
                    136:        // (reqlen によって実際に送信したかどうかは問わない)
                    137:        parent->ClearSense();
                    138: 
                    139:        buf.clear();
                    140:        buf.resize(18);
                    141:        buf[0]  = 0x70;                         // Valid=0、エラーコード 0x70
                    142:        buf[1]  = 0;                            // セグメント番号(?)
                    143:        buf[2]  = sensekey;                     // センスキー (上位4ビットは今の所 0)
                    144:        buf[3]  = 0;                            // Information
                    145:        buf[4]  = 0;                            // Information
                    146:        buf[5]  = 0;                            // Information
                    147:        buf[6]  = 0;                            // Information
                    148:        buf[7]  = 0;                            // 追加センスデータ長 0
                    149:        buf[8]  = 0;                            // Command specific Information
                    150:        buf[9]  = 0;                            // Command specific Information
                    151:        buf[10] = 0;                            // Command specific Information
                    152:        buf[11] = 0;                            // Command specific Information
                    153:        buf[12] = senseasc >> 8;
                    154:        buf[13] = senseasc & 0xff;
                    155:        buf[14] = 0;                            // FRU
                    156:        buf[15] = 0;                            // センスキー固有情報
                    157:        buf[16] = 0;                            // センスキー固有情報
                    158:        buf[17] = 0;                            // センスキー固有情報
                    159:        // 追加センスデータなし
                    160: 
                    161:        // アロケーション長が 0 なら送信せずに終了。
                    162:        // XXX 送信せずにってステータスフェーズに移るってことだろうか?
                    163:        uint reqlen = cmdseq[4];
                    164:        if (reqlen == 0) {
                    165:                return SCSI::XferPhase::Status;
                    166:        }
                    167:        // 本来の応答データ長か reqlen の短いほうまで。
                    168:        if (reqlen < buf.size()) {
                    169:                buf.resize(reqlen);
                    170:        }
                    171:        return SCSI::XferPhase::DataIn;
                    172: }
                    173: 
                    174: 
                    175: //
                    176: // SCSI コマンド 0x08 Read(6)  (DA / CD-ROM)
                    177: //               0x28 Read(10) (DA / CD-ROM)
                    178: //
                    179: // Read(6):
                    180: //    +---+---+---+---+---+---+---+---+
                    181: //  0 |     Operation Code = 0x08     |
                    182: //    +-----------+-------------------+
                    183: //  1 |    LUN    |                   |
                    184: //    +-----------+                   |
                    185: //  2 |      論理ブロックアドレス     |
                    186: //  3 |                               |
                    187: //    +-------------------------------+
                    188: //  4 |    転送データ長 (0 なら 256)  |
                    189: //    +-------------------------------+
                    190: //  5 |          Control Byte         |
                    191: //    +-------------------------------+
                    192: //
                    193: // Read(10):
                    194: //    +---+---+---+---+---+---+---+---+
                    195: //  0 |     Operation Code = 0x28     |
                    196: //    +-----------+-----------+---+---+
                    197: //  1 |    LUN    |DPO|FUA|   0   |Rel|
                    198: //    +-----------+-----------+---+---+
                    199: //  2 |                               |
                    200: //  3 |      論理ブロックアドレス     |
                    201: //  4 |                               |
                    202: //  5 |                               |
                    203: //    +-------------------------------+
                    204: //  6 |               0               |
                    205: //    +-------------------------------+
                    206: //  7 |          転送データ長         |
                    207: //  8 |       (0 なら転送しない)      |
                    208: //    +-------------------------------+
                    209: //  9 |          Control Byte         |
                    210: //    +-------------------------------+
                    211: 
                    212: // コンストラクタ
                    213: SCSICmdRead::SCSICmdRead(SCSIDisk *parent_)
                    214:        : inherited(parent_)
                    215: {
                    216:        disk = parent_;
                    217: }
                    218: 
                    219: // デストラクタ
                    220: SCSICmdRead::~SCSICmdRead()
                    221: {
                    222: }
                    223: 
                    224: // コマンドフェーズ
                    225: SCSI::XferPhase
                    226: SCSICmdRead::Command(std::vector<uint8>& cmdseq)
                    227: {
                    228:        uint32 lba;
                    229:        uint32 blks;
                    230: 
                    231:        // コマンド開始前に直前のセンスデータをクリア
                    232:        parent->ClearSense();
                    233: 
                    234:        CheckLUN;
                    235:        CheckMedium;
                    236: 
1.1.1.5 ! root      237:        const uint8 cmd = cmdseq[0];
1.1       root      238:        if (cmd == SCSI::Command::Read10) {
                    239:                if ((cmdseq[1] & 0x01)) {
                    240:                        parent->putlogf(0, lstr("%s RelAdr not supported",
                    241:                                SCSI::GetCommandName(cmd)));
                    242:                }
                    243:                lba  = cmdseq[2] << 24;
                    244:                lba |= cmdseq[3] << 16;
                    245:                lba |= cmdseq[4] << 8;
                    246:                lba |= cmdseq[5];
                    247:                blks  = cmdseq[7] << 8;
                    248:                blks |= cmdseq[8];
                    249:        } else {
                    250:                lba  = (cmdseq[1] & 0x1f) << 16;
                    251:                lba |=  cmdseq[2] << 8;
                    252:                lba |=  cmdseq[3];
                    253:                blks =  cmdseq[4];
                    254:                // Read(6) の blks == 0 は 256 ブロック転送を意味する。
                    255:                if (blks == 0) {
                    256:                        blks = 256;
                    257:                }
                    258:        }
                    259: #if !defined(NO_READWRITE_LOG)
                    260:        parent->putlogf(1, lstr("%s LBA=0x%x blks=0x%x",
                    261:                SCSI::GetCommandName(cmd), lba, blks));
                    262: #endif
                    263: 
                    264:        uint64 start = (uint64)lba * parent->GetBlocksize();
                    265:        uint64 len = (uint64)blks * parent->GetBlocksize();
                    266:        uint64 end = start + len;
                    267: 
                    268:        if (end > disk->GetSize()) {
                    269:                parent->sensekey = SCSI::SenseKey::IllegalRequest;
                    270:                parent->senseasc = SCSI::ASC::InvalidFieldInCDB;
                    271:                status_byte = SCSI::StatusByte::CheckCondition;
                    272:                return SCSI::XferPhase::Status;
                    273:        }
                    274:        buf.resize(len);
                    275:        disk->Read(buf, start);
                    276: 
                    277:        // 平均シークタイム
                    278:        optime = disk->GetSeekTime();
                    279: 
                    280:        return SCSI::XferPhase::DataIn;
                    281: }
                    282: 
                    283: 
                    284: //
                    285: // SCSI コマンド 0x0a Write(6)  (DA / CD-ROM)
                    286: //               0x2a Write(10) (DA / CD-ROM)
                    287: //
                    288: // Write(6):
                    289: //    +---+---+---+---+---+---+---+---+
                    290: //  0 |     Operation Code = 0x0a     |
                    291: //    +-----------+-------------------+
                    292: //  1 |    LUN    |                   |
                    293: //    +-----------+                   |
                    294: //  2 |      論理ブロックアドレス     |
                    295: //  3 |                               |
                    296: //    +-------------------------------+
                    297: //  4 |    転送データ長 (0 なら 256)  |
                    298: //    +-------------------------------+
                    299: //  5 |          Control Byte         |
                    300: //    +-------------------------------+
                    301: //
                    302: // Write(10):
                    303: //    +---+---+---+---+---+---+---+---+
                    304: //  0 |     Operation Code = 0x2a     |
                    305: //    +-----------+-----------+---+---+
                    306: //  1 |    LUN    |DPO|FUA|   0   |Rel|
                    307: //    +-----------+-----------+---+---+
                    308: //  2 |                               |
                    309: //  3 |      論理ブロックアドレス     |
                    310: //  4 |                               |
                    311: //  5 |                               |
                    312: //    +-------------------------------+
                    313: //  6 |               0               |
                    314: //    +-------------------------------+
                    315: //  7 |          転送データ長         |
                    316: //  8 |       (0 なら転送しない)      |
                    317: //    +-------------------------------+
                    318: //  9 |          Control Byte         |
                    319: //    +-------------------------------+
                    320: 
                    321: // コンストラクタ
                    322: SCSICmdWrite::SCSICmdWrite(SCSIDisk *parent_)
                    323:        : inherited(parent_)
                    324: {
                    325:        disk = parent_;
                    326: }
                    327: 
                    328: // デストラクタ
                    329: SCSICmdWrite::~SCSICmdWrite()
                    330: {
                    331: }
                    332: 
                    333: // コマンドフェーズ
                    334: SCSI::XferPhase
                    335: SCSICmdWrite::Command(std::vector<uint8>& cmdseq)
                    336: {
                    337:        // コマンド開始前に直前のセンスデータをクリア
                    338:        parent->ClearSense();
                    339: 
                    340:        CheckLUN;
                    341:        CheckMedium;
                    342: 
                    343:        cmd = cmdseq[0];
                    344:        if (cmd == SCSI::Command::Write10) {
                    345:                lba  = cmdseq[2] << 24;
                    346:                lba |= cmdseq[3] << 16;
                    347:                lba |= cmdseq[4] << 8;
                    348:                lba |= cmdseq[5];
                    349:                blks  = cmdseq[7] << 8;
                    350:                blks |= cmdseq[8];
                    351:        } else {
                    352:                lba  = (cmdseq[1] & 0x1f) << 16;
                    353:                lba |=  cmdseq[2] << 8;
                    354:                lba |=  cmdseq[3];
                    355:                blks =  cmdseq[4];
                    356:                // Write(6) の blks == 0 は 256 ブロック転送を意味する。
                    357:                if (blks == 0) {
                    358:                        blks = 256;
                    359:                }
                    360:        }
                    361: 
                    362:        if (((uint64)lba + blks) * parent->GetBlocksize() > disk->GetSize()) {
                    363:                parent->sensekey = SCSI::SenseKey::IllegalRequest;
                    364:                parent->senseasc = SCSI::ASC::InvalidFieldInCDB;
                    365:                status_byte = SCSI::StatusByte::CheckCondition;
                    366:                return SCSI::XferPhase::Status;
                    367:        }
                    368: 
                    369:        // 平均シークタイム
                    370:        optime = disk->GetSeekTime();
                    371: 
                    372:        recvbytes = blks * parent->GetBlocksize();
                    373:        return SCSI::XferPhase::DataOut;
                    374: }
                    375: 
                    376: // データアウトフェーズ完了
                    377: SCSI::XferPhase
                    378: SCSICmdWrite::DoneDataOut()
                    379: {
                    380: #if !defined(NO_READWRITE_LOG)
                    381:        parent->putlogf(1, lstr("%s LBA=0x%x blks=0x%x",
                    382:                SCSI::GetCommandName(cmd), lba, blks));
                    383: #endif
                    384:        uint64 start = (uint64)lba * parent->GetBlocksize();
                    385:        if (disk->Write(buf, start) == false) {
                    386:                parent->sensekey = SCSI::SenseKey::HardwareError;
                    387:                parent->senseasc = SCSI::ASC::PeripheralDeviceWriteFault;
                    388:                status_byte = SCSI::StatusByte::CheckCondition;
                    389:        }
                    390:        return SCSI::XferPhase::Status;
                    391: }
                    392: 
                    393: 
                    394: //
                    395: // SCSI コマンド 0x12 Inquiry (共通)
                    396: //
                    397: //    +---+---+---+---+---+---+---+---+
                    398: //  0 |         Operation Code        |
                    399: //    +-----------+---------------+---+
                    400: //  1 |    LUN    |       0       | E | E:Enable Vital Product Data
                    401: //    +-----------+---------------+---+
                    402: //  2 |          ページコード         |
                    403: //    +-------------------------------+
                    404: //  3 |               0               |
                    405: //    +-------------------------------+
                    406: //  4 |        アロケーション長       |
                    407: //    +-------------------------------+
                    408: //  5 |          Control Byte         |
                    409: //    +-------------------------------+
                    410: //
                    411: // 応答
                    412: //    +---+---+---+---+---+---+---+---+
                    413: //  0 | Qualifier | Device Type Code  |
                    414: //    +---+-------+-------------------+
                    415: //  1 |RMB|    Device Type Modifier   |
                    416: //    +---+---+-----------+-----------+
                    417: //  2 |ISO ver| ECMA ver  | ANSI ver  |
                    418: //    +---+---+-------+---------------+
                    419: //  3 | A | T |   0   |ResponseFormat |
                    420: //    +---+---+-------+---------------+
                    421: //  4 |       追加データ長 (n-4)      |
                    422: //    +-------------------------------+
                    423: //  5 |               0               |
                    424: //  6 |               0               |
                    425: //    +---+---+---+---+---+---+---+---+
                    426: //  7 |Rel|W32|W16|Syn|Lnk| 0 |CQ |SR |
                    427: //    +---+---+---+---+---+---+---+---+
                    428: //  8 |      ベンダ文字列 (8Byte)     |
                    429: //    :                               :
                    430: // 15 |                               |
                    431: //    +-------------------------------+
                    432: // 16 |   プロダクト文字列 (16Byte)   |
                    433: //    :                               :
                    434: // 31 |                               |
                    435: //    +-------------------------------+
                    436: // 32 | プロダクト版数文字列 (4Byte)  |
                    437: //    :                               :
                    438: // 35 |                               |
                    439: //    +-------------------------------+
                    440: // 36         以下ベンダ固有
                    441: 
                    442: // コンストラクタ
                    443: SCSICmdInquiry::SCSICmdInquiry(SCSITarget *parent_)
                    444:        : inherited(parent_)
                    445: {
                    446: }
                    447: 
                    448: // デストラクタ
                    449: SCSICmdInquiry::~SCSICmdInquiry()
                    450: {
                    451: }
                    452: 
                    453: // コマンドフェーズ
                    454: SCSI::XferPhase
                    455: SCSICmdInquiry::Command(std::vector<uint8>& cmdseq)
                    456: {
                    457:        // コマンド開始前に直前のセンスデータをクリア
                    458:        parent->ClearSense();
                    459: 
                    460:        uint reqlen = (uint)cmdseq[4];
1.1.1.5 ! root      461:        parent->putlogf(1, lstr("%s LUN=%u reqlen=$%02x",
1.1       root      462:                SCSI::GetCommandName(cmdseq[0]), LUN, reqlen));
                    463: 
                    464:        // 基本の 36バイト分を用意した上でデバイスに問い合わせ。
                    465:        // これ以上必要ならデバイス側で伸ばしてもよい。
                    466:        buf.resize(36);
                    467:        std::fill(buf.begin(), buf.end(), 0);
                    468:        if (parent->Inquiry(buf, LUN) == false) {
                    469:                status_byte = SCSI::StatusByte::CheckCondition;
                    470:                return SCSI::XferPhase::Status;
                    471:        }
                    472: 
                    473:        // 本来の応答データ長か reqlen の短いほうまで。
1.1.1.5 ! root      474:        uint origlen = buf.size();
1.1       root      475:        if (reqlen < origlen) {
                    476:                buf.resize(reqlen);
                    477:        }
                    478: 
                    479:        if (parent->loglevel >= 2) {
                    480:                // 応答をダンプ、ここで表示する長さは本来の応答データ長
                    481:                std::string str = string_format("%s Response len=$%02x:",
                    482:                        SCSI::GetCommandName(cmdseq[0]), origlen);
                    483:                // 一方ダンプは実際の送信長
                    484:                for (int i = 0; i < buf.size(); i++) {
                    485:                        if (i % 8 == 0 && i != 0) {
                    486:                                str += " ";
                    487:                        }
                    488:                        str += string_format(" %02x", buf[i]);
                    489:                }
                    490:                parent->putlogn("%s", str.c_str());
                    491:        }
                    492: 
                    493:        return SCSI::XferPhase::DataIn;
                    494: }
                    495: 
                    496: 
                    497: //
                    498: // SCSI コマンド 0x15 ModeSelect(6)  (共通)
                    499: //               0x55 ModeSelect(10) (共通)
                    500: //
                    501: // ModeSelect(6):
                    502: //    +---+---+---+---+---+---+---+---+
                    503: //  0 |     Operation Code = 0x15     |
                    504: //    +-----------+---+-----------+---+
                    505: //  1 |    LUN    |PF |     0     |SP | PF:PageFormat, SP:SavePages
                    506: //    +-----------+---+-----------+---+
                    507: //  2 |               0               |
                    508: //  3 |               0               |
                    509: //    +-------------------------------+
                    510: //  4 |      パラメータリスト長       |
                    511: //    +-------------------------------+
                    512: //  5 |          Control Byte         |
                    513: //    +-------------------------------+
                    514: //
                    515: // ModeSelect(10):
                    516: //    +---+---+---+---+---+---+---+---+
                    517: //  0 |     Operation Code = 0x55     |
                    518: //    +-----------+---+-----------+---+
                    519: //  1 |    LUN    |PF |     0     |SP | PF:PageFormat, SP:SavePages
                    520: //    +-----------+---+-----------+---+
                    521: //  2 |                               |
                    522: //  3 |                               |
                    523: //  4 |               0               |
                    524: //  5 |                               |
                    525: //  6 |                               |
                    526: //    +-------------------------------+
                    527: //  7 |      パラメータリスト長       |
                    528: //  8 |               0               |
                    529: //    +-------------------------------+
                    530: //  9 |          Control Byte         |
                    531: //    +-------------------------------+
                    532: //
                    533: // 応答: (モードパラメータヘッダ、6の時)
                    534: //    +-------------------------------+
                    535: //  0 |      モードパラメータ長       | (このバイトを含まずこれ以降)
                    536: //    +-------------------------------+
                    537: //  1 |        メディアタイプ         |
                    538: //    +-------------------------------+
                    539: //  2 |     デバイス固有パラメータ    |
                    540: //    +-------------------------------+
                    541: //  3 |   ブロックディスクリプタ長 m  |
                    542: //    +-------------------------------+
                    543: //
                    544: //    (モードパラメータヘッダ、10の時)
                    545: //    +-------------------------------+
                    546: //  0 |      モードパラメータ長       | (このフィールドを含まずこれ以降?)
                    547: //  1 |                               |
                    548: //    +-------------------------------+
                    549: //  2 |        メディアタイプ         |
                    550: //    +-------------------------------+
                    551: //  3 |     デバイス固有パラメータ    |
                    552: //    +-------------------------------+
                    553: //  4 |               0               |
                    554: //  5 |               0               |
                    555: //    +-------------------------------+
                    556: //  6 |   ブロックディスクリプタ長 m  |
                    557: //  7 |                               |
                    558: //    +-------------------------------+
                    559: //
                    560: //    (ブロックディスクリプタ) * m 個
                    561: //    +-------------------------------+
                    562: //  0 |        デンシティコード       | (デバイスタイプごとに固有)
                    563: //    +-------------------------------+
                    564: //  1 |                               |
                    565: //  2 |          ブロック数           |
                    566: //  3 |                               |
                    567: //    +-------------------------------+
                    568: //  4 |               0               |
                    569: //    +-------------------------------+
                    570: //  5 |                               |
                    571: //  6 |          ブロック長           |
                    572: //  7 |                               |
                    573: //    +-------------------------------+ ブロックディスクリプタここまで
                    574: //
                    575: //    (パラメータページ) * ? 個
                    576: //    +---+---+-----------------------+
                    577: //  0 |PS | 0 |     ページコード      | PS:Parameter Savable
                    578: //    +---+---+-----------------------+
                    579: //  1 |           ページ長            | (このバイトを含まずこれ以降の長さ)
                    580: //    +-------------------------------+
                    581: //  2 |  ページコード固有のパラメータ |
                    582: //    :                               :
                    583: //    |                               |
                    584: //    +-------------------------------+
                    585: 
                    586: // コンストラクタ
                    587: SCSICmdModeSelect::SCSICmdModeSelect(SCSITarget *parent_)
                    588:        : inherited(parent_)
                    589: {
                    590: }
                    591: 
                    592: // デストラクタ
                    593: SCSICmdModeSelect::~SCSICmdModeSelect()
                    594: {
                    595: }
                    596: 
                    597: // コマンドフェーズ
                    598: SCSI::XferPhase
                    599: SCSICmdModeSelect::Command(std::vector<uint8>& cmdseq)
                    600: {
                    601:        // コマンド開始前に直前のセンスデータをクリア
                    602:        parent->ClearSense();
                    603: 
                    604:        CheckLUN;
                    605: 
                    606:        cmd = cmdseq[0];
                    607:        if (cmd == SCSI::Command::ModeSelect10) {
                    608:                recvbytes  = cmdseq[7] << 8;
                    609:                recvbytes |= cmdseq[8];
                    610:        } else {
                    611:                recvbytes = cmdseq[4];
                    612:        }
                    613: 
                    614:        parent->putlogf(1, lstr("%s len=$%02x",
                    615:                SCSI::GetCommandName(cmd), recvbytes));
                    616: 
                    617:        return SCSI::XferPhase::DataOut;
                    618: }
                    619: 
                    620: // データアウトフェーズ完了
                    621: SCSI::XferPhase
                    622: SCSICmdModeSelect::DoneDataOut()
                    623: {
                    624:        uint block_desc_len;
                    625:        const uint8 *desc;
                    626: 
                    627:        // ヘッダの構造と長さが ModeSelect(6)/(10) で違う
                    628:        if (cmd == SCSI::Command::ModeSelect10) {
                    629:                block_desc_len  = buf[6] << 8;
                    630:                block_desc_len |= buf[7];
                    631:                desc = &buf[8];
                    632:        } else {
                    633:                block_desc_len = buf[3];
                    634:                desc = &buf[4];
                    635:        }
                    636: 
                    637:        if (block_desc_len > 0) {
                    638:                // ブロックディスクリプタの構造は ModeSelect(6)/(10) で共通
                    639:                uint blocksize;
                    640:                blocksize  = desc[5] << 16;
                    641:                blocksize |= desc[6] << 8;
                    642:                blocksize |= desc[7];
                    643: 
                    644:                // ブロック長を書き戻す
                    645:                parent->SetBlocksize(blocksize);
                    646:        }
                    647: 
                    648:        return SCSI::XferPhase::Status;
                    649: }
                    650: 
                    651: 
                    652: //
                    653: // SCSI コマンド 0x1a ModeSense(6)  (共通)
                    654: //               0x5a ModeSense(10) (共通)
                    655: //
                    656: // ModeSense(6):
                    657: //    +---+---+---+---+---+---+---+---+
                    658: //  0 |     Operation Code = 0x1a     |
                    659: //    +-----------+---+---+-----------+
                    660: //  1 |    LUN    | 0 |DBD|     0     | DBD:Disable Block Descriptors
                    661: //    +-------+---+---+---+-----------+
                    662: //  2 |   PC  |       Page Code       | PC:Page Control
                    663: //    +-------+-----------------------+
                    664: //  3 |               0               |
                    665: //    +-------------------------------+
                    666: //  4 |        アロケーション長       |
                    667: //    +-------------------------------+
                    668: //  5 |          Control Byte         |
                    669: //    +-------------------------------+
                    670: //
                    671: // ModeSense(10):
                    672: //    +---+---+---+---+---+---+---+---+
                    673: //  0 |     Operation Code = 0x5a     |
                    674: //    +-----------+---+---+-----------+
                    675: //  1 |    LUN    |LLA|DBD|     0     | DBD:Disable Block Descriptors
                    676: //    +-------+---+---+---+-----------+ LLA:Long LBA Accepted
                    677: //  2 |   PC  |       Page Code       | PC:Page Control
                    678: //    +-------+-----------------------+
                    679: //  3 |           SubPageCode         |
                    680: //    +-------------------------------+
                    681: //  4 |                               |
                    682: //  5 |               0               |
                    683: //  6 |                               |
                    684: //    +-------------------------------+
                    685: //  7 |        アロケーション長       |
                    686: //  8 |                               |
                    687: //    +-------------------------------+
                    688: //  9 |          Control Byte         |
                    689: //    +-------------------------------+
                    690: 
                    691: // コンストラクタ
                    692: SCSICmdModeSense::SCSICmdModeSense(SCSITarget *parent_)
                    693:        : inherited(parent_)
                    694: {
                    695: }
                    696: 
                    697: // デストラクタ
                    698: SCSICmdModeSense::~SCSICmdModeSense()
                    699: {
                    700: }
                    701: 
                    702: // コマンドフェーズ
                    703: SCSI::XferPhase
                    704: SCSICmdModeSense::Command(std::vector<uint8>& cmdseq)
                    705: {
                    706:        uint reqlen;
                    707: 
                    708:        // コマンド開始前に直前のセンスデータをクリア
                    709:        parent->ClearSense();
                    710: 
                    711:        CheckLUN;
                    712: 
                    713:        uint cmd = cmdseq[0];
                    714:        pc = (PC)(cmdseq[2] >> 6);
                    715:        pagecode = (cmdseq[2] & 0x3f);
                    716:        if (cmd == SCSI::Command::ModeSense10) {
                    717:                reqlen  = cmdseq[7] << 8;
                    718:                reqlen |= cmdseq[8];
                    719:        } else {
                    720:                reqlen = cmdseq[4];
                    721:        }
                    722:        bool dbd = (cmdseq[1] & 0x08);
                    723: 
                    724:        if (parent->loglevel >= 1) {
                    725:                log = string_format("%s %s",
                    726:                        SCSI::GetCommandName(cmd),
                    727:                        SCSI::GetModePageDisp(pagecode).c_str());
                    728:                if (pc != PC::Current) {
1.1.1.5 ! root      729:                        log += string_format(" PC=%u", (uint)pc);
1.1       root      730:                }
                    731:        }
                    732: 
                    733:        // ヘッダを用意。
                    734: 
                    735:        // メディアタイプ。
                    736:        // XXX 実際にはデバイス種別ごとに定義があるが、とりあえず 0 でよさげ
                    737:        const uint8 mediatype = 0;
                    738:        // デバイス固有パラメータを取得
                    739:        uint8 devspec = parent->GetDeviceSpecificParam();
                    740:        // ブロックディスクリプタ長 (バイト数)
                    741:        uint8 bdlen = dbd ? 0 : 8;
                    742: 
                    743:        // ヘッダは (6) と (10) で形式が違う。
                    744:        // モードパラメータ長(全長)は最後に代入する。
                    745:        buf.clear();
                    746:        if (cmd == SCSI::Command::ModeSense10) {
                    747:                buf.resize(8);
                    748:                buf[2] = mediatype;
                    749:                buf[3] = devspec;
                    750:                buf[6] = bdlen >> 8;
                    751:                buf[7] = bdlen;
                    752:        } else {
                    753:                buf.resize(4);
                    754:                buf[1] = mediatype;
                    755:                buf[2] = devspec;
                    756:                buf[3] = bdlen;
                    757:        }
                    758: 
                    759:        // ブロックディスクリプタ
                    760:        if (dbd == false) {
                    761:                // ブロック数とブロックサイズ
                    762:                uint32 blocks = 0;
                    763:                uint32 blocklen = parent->GetBlocksize();
                    764:                const SCSIDisk *disk = dynamic_cast<const SCSIDisk*>(parent);
                    765:                if (disk) {
                    766:                        blocks = disk->GetSize() / blocklen;
                    767:                }
                    768: 
                    769:                // 1バイトずつ追加していくほうが楽…。
                    770:                // デンシティコードは実際にはデバイスごとだが、だいたい 0 でよさげ。
                    771:                buf.emplace_back(0);                                            // +0 デンシティコード
                    772:                buf.emplace_back((blocks >> 16) & 0xff);        // +1 ブロック数
                    773:                buf.emplace_back((blocks >>  8) & 0xff);        // +2 ブロック数
                    774:                buf.emplace_back( blocks        & 0xff);        // +3 ブロック数
                    775:                buf.emplace_back(0);                                            // +4 reserved
                    776:                buf.emplace_back((blocklen >> 16) & 0xff);      // +5 ブロック長
                    777:                buf.emplace_back((blocklen >>  8) & 0xff);      // +6 ブロック長
                    778:                buf.emplace_back( blocklen        & 0xff);      // +7 ブロック長
                    779:        }
                    780: 
1.1.1.2   root      781:        // モードページ
1.1       root      782:        if (pagecode == SCSI::ModePage::AllPages) {
                    783:                // サポートしているのを全部送る。
                    784:                if (parent->loglevel >= 1) {
                    785:                        log += " " + SCSI::GetModePageDisp(pagecode);
                    786:                        log += "->";
                    787:                }
1.1.1.2   root      788:                for (auto& pair : Pagelist) {
1.1       root      789:                        auto code = pair.first;
1.1.1.2   root      790:                        auto func = pair.second;
1.1       root      791: 
1.1.1.2   root      792:                        if ((this->*(func))() != ModePageResult::Failed) {
1.1       root      793:                                if (parent->loglevel >= 1) {
                    794:                                        log += " " + SCSI::GetModePageDisp(code);
                    795:                                }
                    796:                        }
                    797:                }
                    798:        } else {
                    799:                // 指定されたページコードを送る。
1.1.1.4   root      800:                ModePageResult r = ModePageResult::NotSupported;
1.1.1.2   root      801:                for (auto& pair : Pagelist) {
1.1       root      802:                        auto code = pair.first;
1.1.1.2   root      803:                        auto func = pair.second;
1.1       root      804: 
                    805:                        if (pagecode == code) {
1.1.1.2   root      806:                                r = (this->*(func))();
1.1       root      807:                                break;
                    808:                        }
                    809:                }
                    810: 
                    811:                // Failed は対応しない/できないと分かっているページ、
1.1.1.4   root      812:                // NotSupported は未実装や知らないページ。
1.1       root      813:                if (r <= ModePageResult::Failed) {
                    814:                        if (parent->loglevel >= 1) {
1.1.1.4   root      815:                                if (r == ModePageResult::NotSupported) {
                    816:                                        parent->putlogn("%s not supported", log.c_str());
1.1       root      817:                                } else {
                    818:                                        parent->putlogn("%s", log.c_str());
                    819:                                }
                    820:                        }
                    821:                        parent->sensekey = SCSI::SenseKey::IllegalRequest;
                    822:                        parent->senseasc = SCSI::ASC::InvalidFieldInCDB;
                    823:                        status_byte = SCSI::StatusByte::CheckCondition;
                    824:                        return SCSI::XferPhase::Status;
                    825:                }
                    826:        }
                    827: 
                    828:        parent->putlogf(1, [&] { return log; });
                    829: 
                    830:        // モードパラメータ長は自フィールドを含まない長さ
                    831:        if (cmd == SCSI::Command::ModeSelect10) {
                    832:                uint buflen = buf.size() - 2;
                    833:                buf[0] = buflen >> 8;
                    834:                buf[1] = buflen;
                    835:        } else {
                    836:                uint buflen = buf.size() - 1;
                    837:                buf[0] = buflen;
                    838:        }
                    839: 
                    840:        // 本来の応答データ長か reqlen の短いほうまで
                    841:        if (reqlen < buf.size()) {
                    842:                buf.resize(reqlen);
                    843:        }
                    844:        return SCSI::XferPhase::DataIn;
                    845: }
                    846: 
1.1.1.2   root      847: // ページを送信する順(=昇順)に (手動で) 並べること。
                    848: // ただし 0x00 (VendorSpecific) は最後。
                    849: #define PAGE(code, func)       \
                    850:        { SCSI::ModePage::code, &SCSICmdModeSense::func }
                    851: /*static*/ const std::vector<std::pair<uint8, SCSICmdModeSense::PageFunc>>
                    852: SCSICmdModeSense::Pagelist {
                    853:        PAGE(/*04*/RigidDiskGeometry,   AddNotSupportedPage),
                    854:        PAGE(/*05*/FlexibleDisk,                AddNotSupportedPage),
                    855:        PAGE(/*08*/CachingPage,                 AddCachingPage),
                    856:        PAGE(/*00*/VendorSpecific,              AddEmptyPage),
                    857: };
                    858: 
1.1       root      859: // サポートしないページ
                    860: //
                    861: // ページコード 04 RigidDiskGeometry (DA)
                    862: //  -> 生イメージからジオメトリを求めるのは意味ないので実装しない。
                    863: // ページコード 05 FlexibleDisk (DA)
                    864: //  -> ジオメトリなどのパラメータがメインっぽいので実装しない。
1.1.1.2   root      865: SCSICmdModeSense::ModePageResult
1.1       root      866: SCSICmdModeSense::AddNotSupportedPage()
                    867: {
                    868:        return ModePageResult::Failed;
                    869: }
                    870: 
                    871: // 空のページ
1.1.1.2   root      872: SCSICmdModeSense::ModePageResult
1.1       root      873: SCSICmdModeSense::AddEmptyPage()
                    874: {
                    875:        std::vector<uint8> page(2);
                    876:        page[0] = pagecode;                             // +0 ページコード
                    877:        page[1] = page.size() - 2;              // +1 このバイト以降のページ長
                    878: 
                    879:        buf.insert(buf.end(), page.begin(), page.end());
                    880:        buf[0] += page.size();
                    881:        return ModePageResult::Success;
                    882: }
                    883: 
                    884: // ページコード 08 CachingPage (DA, MO, CD-ROM)
1.1.1.2   root      885: SCSICmdModeSense::ModePageResult
1.1       root      886: SCSICmdModeSense::AddCachingPage()
                    887: {
1.1.1.3   root      888:        // XXX この assert いる?
                    889:        assert(dynamic_cast<const SCSIDisk*>(parent) != NULL);
1.1       root      890: 
                    891:        // とりあえずパラメータはなんもなし。
                    892:        // PC::Changeable でも全部 0 なのでこのままでいい。
                    893:        std::vector<uint8> page(12);
                    894:        page[0] = pagecode;                             // +0 ページコード
                    895:        page[1] = page.size() - 2;              // +1 このバイト以降のページ長
                    896:        // +2 WCE, MF, RCD フラグ
                    897:        // +3 データの保持優先度
                    898:        // +4 プリフェッチ抑止ブロック数
                    899:        // +6 最小プリフェッチ
                    900:        // +8 最大プリフェッチ
                    901:        // +10 最大プリフェッチ制限ブロック数
                    902: 
                    903:        buf.insert(buf.end(), page.begin(), page.end());
                    904:        buf[0] += page.size();
                    905:        return ModePageResult::Success;
                    906: }
                    907: 
                    908: 
                    909: //
                    910: // SCSI コマンド 0x1b StartStopUnit (DA / CD-ROM)
                    911: //
                    912: //    +---+---+---+---+---+---+---+---+
                    913: //  0 |         Operation Code        |
                    914: //    +-----------+---------------+---+
                    915: //  1 |    LUN    |         0     | I | I:Immediate
                    916: //    +-----------+---------------+---+
                    917: //  2 |               0               |
                    918: //  3 |               0               |
                    919: //    +-----------------------+---+---+
                    920: //  4 |               0       |L/E| S | L/E:Load/Eject, S:Start
                    921: //    +-----------------------+---+---+
                    922: //  5 |          Control Byte         |
                    923: //    +-------------------------------+
                    924: 
                    925: // コンストラクタ
                    926: SCSICmdStartStopUnit::SCSICmdStartStopUnit(SCSIDisk *parent_)
                    927:        : inherited(parent_)
                    928: {
                    929:        disk = parent_;
                    930: }
                    931: 
                    932: // デストラクタ
                    933: SCSICmdStartStopUnit::~SCSICmdStartStopUnit()
                    934: {
                    935: }
                    936: 
                    937: // コマンドフェーズ
                    938: SCSI::XferPhase
                    939: SCSICmdStartStopUnit::Command(std::vector<uint8>& cmdseq)
                    940: {
                    941:        bool immed = (cmdseq[1] & 0x01);
                    942:        if (immed) {
                    943:                parent->putlogf(1, lstr("%s Immed=1 not supported",
                    944:                        SCSI::GetCommandName(cmdseq[0])));
                    945:        }
                    946: 
                    947:        bool loej  = (cmdseq[4] & 0x02);
                    948:        bool start = (cmdseq[4] & 0x01);
1.1.1.5 ! root      949:        parent->putlogf(1, lstr("%s LoEj=%u Start=%u",
1.1       root      950:                SCSI::GetCommandName(cmdseq[0]), (loej ? 1 : 0), (start ? 1 : 0)));
                    951: 
                    952:        if (disk->IsRemovableDevice()) {
                    953:                // LoEj Start
                    954:                // x    0               媒体へのアクセスを不可にする?
                    955:                // x    1               媒体へのアクセスを可にする?
                    956:                // 1    0               媒体のアンロード
                    957:                // 1    1               媒体のロード
                    958:                //
                    959:                // らしいけど、イジェクトのみ対応
                    960:                if (loej) {
                    961:                        if (disk->IsMediumLoaded()) {
                    962:                                disk->UnloadDisk();
                    963:                        } else {
                    964:                                // メディアがロードされてない時にトレイを開ける動作に
                    965:                                // 相当するのは「ファイルダイアログを出す」だが伝わるだろうか
                    966:                                parent->putlogf(0, lstr("%s Loading not supported",
                    967:                                        SCSI::GetCommandName(cmdseq[0])));
                    968:                        }
                    969:                } else {
                    970:                        parent->putlogf(0, lstr("%s LoEj=0 not supported",
                    971:                                SCSI::GetCommandName(cmdseq[0])));
                    972:                }
                    973:        } else {
                    974:                // 固定デバイスなら黙って成功しておく?
                    975:        }
                    976:        return inherited::Command(cmdseq);
                    977: }
                    978: 
                    979: 
                    980: //
                    981: // SCSI コマンド 0x1e PreventAllowMediumRemoval (DA / CD-ROM)
                    982: //
                    983: //    +---+---+---+---+---+---+---+---+
                    984: //  0 |         Operation Code        |
                    985: //    +-----------+-------------------+
                    986: //  1 |    LUN    |         0         |
                    987: //    +-----------+-------------------+
                    988: //  2 |               0               |
                    989: //  3 |               0               |
                    990: //    +---------------------------+---+
                    991: //  4 |               0           | P | P:Prevent
                    992: //    +---------------------------+---+
                    993: //  5 |          Control Byte         |
                    994: //    +-------------------------------+
                    995: 
                    996: // XXX コマンドとしてはダイレクトアクセスデバイスに対しても発行できるが、
                    997: // その時どう応答すべきかは要調査
                    998: 
                    999: // コンストラクタ
                   1000: SCSICmdPreventAllowMediumRemoval::SCSICmdPreventAllowMediumRemoval(
                   1001:        SCSIDisk *parent_)
                   1002:        : inherited(parent_)
                   1003: {
                   1004:        disk = parent_;
                   1005: }
                   1006: 
                   1007: // デストラクタ
                   1008: SCSICmdPreventAllowMediumRemoval::~SCSICmdPreventAllowMediumRemoval()
                   1009: {
                   1010: }
                   1011: 
                   1012: // コマンドフェーズ
                   1013: SCSI::XferPhase
                   1014: SCSICmdPreventAllowMediumRemoval::Command(std::vector<uint8>& cmdseq)
                   1015: {
                   1016:        // コマンド開始前に直前のセンスデータをクリア
                   1017:        parent->ClearSense();
                   1018: 
                   1019:        CheckLUN;
                   1020:        CheckMedium;
                   1021: 
                   1022:        // PreventMediumRemoval() は状態変化でログレベル 1 で表示してるので、
                   1023:        // ここではログレベル 2 で常に表示にしておく。
                   1024:        uint prevent = cmdseq[4] & 1;
1.1.1.5 ! root     1025:        parent->putlogf(2, lstr("%s prevent=%u",
1.1       root     1026:                SCSI::GetCommandName(cmdseq[0]), prevent));
                   1027: 
                   1028:        disk->PreventMediumRemoval(prevent);
                   1029:        return SCSI::XferPhase::Status;
                   1030: }
                   1031: 
                   1032: 
                   1033: //
                   1034: // SCSI コマンド 0x25 ReadCapacity      (DA)
                   1035: //               0x25 ReadCDROMCapacity (CD-ROM)
                   1036: //
                   1037: //    +---+---+---+---+---+---+---+---+
                   1038: //  0 |         Operation Code        |
                   1039: //    +-----------+---------------+---+
                   1040: //  1 |    LUN    |       0       |Rel|
                   1041: //    +-----------+---------------+---+
                   1042: //  2 |                               |
                   1043: //  3 |      論理ブロックアドレス     |
                   1044: //  4 |      (PMI=0 なら 0)           |
                   1045: //  5 |                               |
                   1046: //    +-------------------------------+
                   1047: //  6 |               0               |
                   1048: //  7 |               0               |
                   1049: //    +---------------------------+---+
                   1050: //  8 |               0           |PMI|
                   1051: //    +---------------------------+---+
                   1052: //  9 |          Control Byte         |
                   1053: //    +-------------------------------+
                   1054: //
                   1055: // CD-ROM デバイスでは同じ 0x25 で Read CDROM Capacity というコマンド名。
                   1056: // Read CDROM Capacity のほうはオーディオ CD の場合の意味分けが追加されて
                   1057: // いるが、たぶんデータ CD だけを扱ううちはダイレクトアクセスデバイスの
                   1058: // Read Capacity と同じでいいはず。
                   1059: 
                   1060: // コンストラクタ
                   1061: SCSICmdReadCapacity::SCSICmdReadCapacity(SCSIDisk *parent_)
                   1062:        : inherited(parent_)
                   1063: {
                   1064:        disk = parent_;
                   1065: }
                   1066: 
                   1067: // デストラクタ
                   1068: SCSICmdReadCapacity::~SCSICmdReadCapacity()
                   1069: {
                   1070: }
                   1071: 
                   1072: // コマンドフェーズ
                   1073: SCSI::XferPhase
                   1074: SCSICmdReadCapacity::Command(std::vector<uint8>& cmdseq)
                   1075: {
                   1076:        // コマンド開始前に直前のセンスデータをクリア
                   1077:        parent->ClearSense();
                   1078: 
                   1079:        CheckLUN;
                   1080:        CheckMedium;
                   1081: 
                   1082:        // PMI=1 は未サポート
                   1083:        if ((cmdseq[8] & 0x01) != 0) {
                   1084:                parent->putlogf(0, lstr("%s PMI=1 not supported",
                   1085:                        SCSI::GetCommandName(cmdseq[0])));
                   1086:        }
                   1087: 
                   1088:        // 応答データは
                   1089:        // +00.L 最終論理ブロックアドレス
                   1090:        // +04.L ブロック長
                   1091:        uint32 blksize = parent->GetBlocksize();
                   1092:        uint32 lastblk = (disk->GetSize() / blksize) - 1;
                   1093:        parent->putlogf(1, lstr("%s -> lastblk=$%x blksize=$%x",
                   1094:                SCSI::GetCommandName(cmdseq[0]), lastblk, blksize));
                   1095:        buf.resize(8);
                   1096:        buf[0] = lastblk >> 24;
                   1097:        buf[1] = lastblk >> 16;
                   1098:        buf[2] = lastblk >> 8;
                   1099:        buf[3] = lastblk;
                   1100:        buf[4] = blksize >> 24;
                   1101:        buf[5] = blksize >> 16;
                   1102:        buf[6] = blksize >> 8;
                   1103:        buf[7] = blksize;
                   1104: 
                   1105:        return SCSI::XferPhase::DataIn;
                   1106: }
                   1107: 
                   1108: 
                   1109: //
                   1110: // SCSI コマンド 0x43 ReadTOC (CD-ROM)
                   1111: //
                   1112: //    +---+---+---+---+---+---+---+---+
                   1113: //  0 |         Operation Code        |
                   1114: //    +-----------+-----------+---+---+
                   1115: //  1 |    LUN    |     0     |MSF| 0 |
                   1116: //    +-----------+-----------+---+---+
                   1117: //  2 |               0               |
                   1118: //  3 |               0               |
                   1119: //  4 |               0               |
                   1120: //  5 |               0               |
                   1121: //    +-------------------------------+
                   1122: //  6 |          開始トラック         |
                   1123: //    +-------------------------------+
                   1124: //  7 |        アロケーション長       |
                   1125: //  8 |                               |
                   1126: //    +-------------------------------+
                   1127: //  9 |          Control Byte         |
                   1128: //    +-------------------------------+
                   1129: 
                   1130: // コンストラクタ
                   1131: SCSICmdReadTOC::SCSICmdReadTOC(SCSIDisk *parent_)
                   1132:        : inherited(parent_)
                   1133: {
                   1134:        disk = parent_;
                   1135: }
                   1136: 
                   1137: // デストラクタ
                   1138: SCSICmdReadTOC::~SCSICmdReadTOC()
                   1139: {
                   1140: }
                   1141: 
                   1142: // コマンドフェーズ
                   1143: SCSI::XferPhase
                   1144: SCSICmdReadTOC::Command(std::vector<uint8>& cmdseq)
                   1145: {
                   1146:        // コマンド開始前に直前のセンスデータをクリア
                   1147:        parent->ClearSense();
                   1148: 
                   1149:        CheckLUN;
                   1150:        CheckMedium;
                   1151: 
                   1152:        // MSF 形式は未実装
                   1153:        if ((cmdseq[1] & 0x02)) {
1.1.1.4   root     1154:                parent->putlogf(0, lstr("ReadTOC MSF=1 (NOT IMPLEMENTED)"));
1.1       root     1155:        }
                   1156: 
                   1157:        // 開始トラックが 0 なら、媒体上の先頭トラックからを意味する。
                   1158:        // ここでは1トラック目から始まることにしてみる。
1.1.1.5 ! root     1159:        const uint TrackStart = 1;
        !          1160:        const uint TrackMax = 1;
1.1       root     1161: 
1.1.1.5 ! root     1162:        uint start = cmdseq[6];
1.1       root     1163:        if (start == 0) {
                   1164:                start = TrackStart;
                   1165:        }
                   1166: 
                   1167:        // イニシエータが用意しているバッファ長
1.1.1.5 ! root     1168:        uint reqlen = (cmdseq[7] << 8) | cmdseq[8];
1.1       root     1169: 
                   1170:        // start は送られてきた情報が知りたいだろう
                   1171:        parent->putlogf(1, lstr("%s start=$%x len=$%x",
                   1172:                SCSI::GetCommandName(cmdseq[0]), cmdseq[6], reqlen));
                   1173: 
                   1174:        // ヘッダ4バイト + トラックディスクリプタ(8バイト) * トラック数で、
                   1175:        // ここではトラックは常に1つ。
                   1176:        buf.clear();
                   1177:        buf.resize(4 + 8 * 1);
                   1178: 
                   1179:        // TOC データ長はこの2バイトのフィールドを含まないバイト数で、
                   1180:        // 開始トラック以降の有効な全トラック数。
1.1.1.5 ! root     1181:        uint tocdatalen = 2;
1.1       root     1182:        if (start <= TrackMax) {
                   1183:                tocdatalen += (TrackMax - start) * 8;
                   1184:        }
                   1185:        // 開始論理アドレス
                   1186:        uint32 address = 0;
                   1187: 
                   1188:        // ヘッダ
                   1189:        buf[0]  = tocdatalen >> 8;      // TOC データ長
                   1190:        buf[1]  = tocdatalen;           // TOC データ長
                   1191:        buf[2]  = start;                        // 先頭トラック番号
                   1192:        buf[3]  = TrackMax;                     // 最終トラック番号
                   1193:        // トラック1
                   1194:        buf[4]  = 0;                            // Reserved
                   1195:        buf[5]  = 0x06;                         // ADR=0(?)、データトラック
                   1196:        buf[6]  = 1;                            // トラック番号
                   1197:        buf[7]  = 0;                            // Reserved
                   1198:        buf[8]  = address >> 24;        // 論理アドレス
                   1199:        buf[9]  = address >> 16;        // 論理アドレス
                   1200:        buf[10] = address >> 8;         // 論理アドレス
                   1201:        buf[11] = address;                      // 論理アドレス
                   1202: 
                   1203:        // 本来の応答データ長か reqlen の短いほうまで
                   1204:        if (reqlen < buf.size()) {
                   1205:                buf.resize(reqlen);
                   1206:        }
                   1207: 
                   1208:        return SCSI::XferPhase::DataIn;
                   1209: }

unix.superglobalmegacorp.com

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