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

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

unix.superglobalmegacorp.com

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