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

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

unix.superglobalmegacorp.com

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