Annotation of nono/vm/scsidev.cpp, revision 1.1.1.4

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

unix.superglobalmegacorp.com

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