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

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: 
1.1.1.14  root        7: //
                      8: // SCSI デバイス
                      9: //
                     10: 
1.1.1.11  root       11: // ログレベルは
                     12: // 1: SCSI コマンドの概要。
                     13: //    デバイスの動作のうち大きな変更のもの
                     14: // 2: SCSI コマンドの詳細、ダンプ。
                     15: //    デバイスの動作のうち些細なもの、あるいは頻繁なもの
                     16: // 3: フェーズ遷移
                     17: // 4: データも含める
1.1       root       18: 
1.1.1.11  root       19: #include "scsicmd.h"
1.1       root       20: #include "scsidev.h"
1.1.1.2   root       21: #include "config.h"
                     22: #include "mainapp.h"
1.1.1.14  root       23: #include "scheduler.h"
1.1.1.11  root       24: #include "uimessage.h"
1.1       root       25: 
                     26: //
1.1.1.11  root       27: // SCSI デバイス共通部分
1.1       root       28: //
                     29: 
                     30: // コンストラクタ
1.1.1.16! root       31: SCSIDevice::SCSIDevice(int objid_)
        !            32:        : inherited(objid_)
1.1       root       33: {
                     34: }
                     35: 
                     36: // デストラクタ
                     37: SCSIDevice::~SCSIDevice()
                     38: {
                     39: }
                     40: 
1.1.1.14  root       41: 
1.1       root       42: //
                     43: // SCSI ホストデバイス
                     44: //
                     45: 
                     46: // コンストラクタ
1.1.1.16! root       47: SCSIHostDevice::SCSIHostDevice(int objid_)
        !            48:        : inherited(objid_)
1.1       root       49: {
1.1.1.5   root       50:        devtype = SCSI::DevType::Initiator;
                     51: 
1.1.1.14  root       52:        monitor_devs.func = ToMonitorCallback(&SCSIHostDevice::MonitorUpdateDevs);
1.1.1.11  root       53:        // サイズは Create で決まる
                     54:        monitor_devs.Regist(ID_MONITOR_SCSIDEVS);
                     55: 
1.1       root       56:        // バスデバイスを作成する。
                     57:        // ただし自身がバスに参加するのは継承側で行う
                     58:        // (例えば SPC なら BDID 書き込みで ID が決まった後、など)。
                     59:        scsibus.reset(new SCSIBus());
                     60: }
                     61: 
                     62: // デストラクタ
                     63: SCSIHostDevice::~SCSIHostDevice()
                     64: {
                     65: }
                     66: 
1.1.1.2   root       67: // 設定ファイルに使われるこのホストデバイスを示す接頭語を設定する
                     68: // (継承クラス側のコンストラクタで config_name を設定後に呼ぶこと)
                     69: void
                     70: SCSIHostDevice::SetConfigName(const char *name_)
                     71: {
                     72:        config_name = name_;
                     73: }
                     74: 
1.1       root       75: bool
                     76: SCSIHostDevice::Create()
                     77: {
                     78:        // 設定を読み込む。
                     79:        for (int id = 0; id < 8; id++) {
1.1.1.2   root       80:                const std::string key = string_format("%s-id%d-image",
1.1       root       81:                        GetConfigName(), id);
1.1.1.3   root       82:                const ConfigItem& item = gConfig->Find(key);
1.1.1.2   root       83:                const std::string& image = item.AsString();
                     84: 
                     85:                // 空ならデバイスなし
                     86:                if (image.length() == 0) {
1.1.1.5   root       87:                        // 未接続部分のパラメータは減らしておくか。
                     88:                        // --show-config するとさすがに無駄に多くて邪魔なので。
1.1.1.11  root       89:                        const std::string wikey = string_format("%s-id%d-writeignore",
                     90:                                GetConfigName(), id);
1.1.1.5   root       91:                        const std::string wpkey = string_format("%s-id%d-writeprotect",
                     92:                                GetConfigName(), id);
                     93:                        const std::string stkey = string_format("%s-id%d-seektime",
                     94:                                GetConfigName(), id);
1.1.1.11  root       95:                        gConfig->Delete(wikey);
1.1.1.5   root       96:                        gConfig->Delete(wpkey);
                     97:                        gConfig->Delete(stkey);
1.1.1.2   root       98:                        continue;
                     99:                }
                    100: 
                    101:                // ',' より前がデバイス種別 (ここではパスは不要)
1.1.1.11  root      102:                auto v = string_split(image, ',');
                    103:                // 比較のため前後の空白を取り除いて小文字にする
                    104:                std::string type = string_trim(v[0]);
                    105:                type = string_tolower(type);
1.1.1.2   root      106: 
1.1.1.11  root      107:                SCSI::DevType target_devtype;
1.1.1.2   root      108:                if (type == "hd") {
1.1.1.11  root      109:                        target_devtype = SCSI::DevType::HD;
                    110:                } else if (type == "cd") {
                    111:                        target_devtype = SCSI::DevType::CD;
                    112:                } else if (type == "mo") {
                    113:                        target_devtype = SCSI::DevType::MO;
1.1.1.2   root      114:                } else {
1.1.1.16! root      115:                        item.Err("Invaild device type '%s'", type.c_str());
1.1.1.11  root      116:                        return false;
1.1       root      117:                }
1.1.1.11  root      118:                target[id].reset(new SCSIDisk(this, id, target_devtype));
                    119:                scsibus->Attach(target[id].get(), id);
1.1       root      120:        }
                    121: 
                    122:        return true;
                    123: }
                    124: 
1.1.1.11  root      125: // 初期化。
                    126: // 継承クラスが connected_devices をセットした後で呼ぶこと。
1.1       root      127: bool
                    128: SCSIHostDevice::Init()
                    129: {
1.1.1.16! root      130:        if (inherited::Init() == false) {
        !           131:                return false;
        !           132:        }
        !           133: 
1.1       root      134:        // 初期化ではないけどログレベルがセットできたここでデバッグ表示。
                    135:        // -L オプションの処理は Create() の後なので。
                    136:        if (loglevel >= 1) {
                    137:                for (int id = 0; id < 8; id++) {
                    138:                        std::string typestr;
                    139:                        if (target[id]) {
1.1.1.11  root      140:                                typestr = SCSI::GetDevTypeName(target[id]->GetDevType());
1.1.1.8   root      141:                                putmsgn("%s target #%d %s", GetConfigName(), id,
1.1       root      142:                                        typestr.c_str());
                    143:                        }
                    144:                }
                    145:        }
                    146: 
1.1.1.11  root      147:        // connected_devices によってモニタの大きさを決定。
1.1.1.14  root      148:        monitor_devs.SetSize(75, (connected_devices.size() - 1) * 4 + 1);
1.1.1.11  root      149: 
1.1       root      150:        return true;
                    151: }
                    152: 
                    153: // バスフリーコールバック (SCSIBus から呼ばれる)
                    154: void
                    155: SCSIHostDevice::BusFreeCB(int id)
                    156: {
                    157:        // 実際にはバスフリーを検出したデバイスは各自自身が送出している信号を
                    158:        // 下げるのだが、色々面倒なので、ここではホストのバスフリーコールバックが
                    159:        // 一括して全部の線を下げる。
                    160:        // ただしさすがにログがうるさいので、上がってる線だけ下げる。
                    161: 
                    162:        uint32 data;
                    163:        while ((data = GetBSY()) != 0) {
                    164:                bus->NegateBSY(DecodeID(data));
                    165:        }
                    166:        while ((data = GetSEL()) != 0) {
                    167:                bus->NegateSEL(DecodeID(data));
                    168:        }
                    169:        if (GetREQ()) {
                    170:                NegateREQ();
                    171:        }
                    172:        if (GetACK()) {
                    173:                NegateACK();
                    174:        }
                    175:        if (GetATN()) {
                    176:                NegateATN();
                    177:        }
                    178:        SetXfer(0);
                    179:        SetData(0);
                    180: }
                    181: 
1.1.1.11  root      182: // SCSI デバイスモニタ
                    183: // (どこでやるのがいいか分からんけど、SCSI デバイスを一括して表示したいので
                    184: // とりあえずここで)
                    185: void
                    186: SCSIHostDevice::MonitorUpdateDevs(Monitor *, TextScreen& screen)
1.1       root      187: {
1.1.1.11  root      188:        int y;
1.1       root      189: 
1.1.1.14  root      190: // 012345678901234567890123456789012345678901234567890123456789012345678901234
                    191: // ID6: HD(2048MB)
                    192: //      MediumLoaded   Off      LogicalBlock 2048    ImageSize   2,147,483,648
                    193: //      RemovalPrevent Off      WriteProtected
                    194: 
                    195: 
1.1.1.11  root      196:        screen.Clear();
1.1.1.4   root      197: 
1.1.1.11  root      198:        y = 0;
                    199:        for (const auto dev : connected_devices) {
                    200:                std::string desc = SCSI::GetDevTypeName(dev->GetDevType());
                    201:                std::string pathname;
                    202: 
                    203:                SCSIDisk *disk = dynamic_cast<SCSIDisk*>(dev);
                    204:                if (disk && disk->IsMediumLoaded()) {
                    205:                        desc += string_format("(%dMB)",
                    206:                                (int)(disk->GetSize() / 1024 / 1024));
                    207:                        pathname = disk->GetPathName();
                    208:                }
                    209:                screen.Print(0, y, "ID%c: %s", '0' + dev->GetMyID(), desc.c_str());
                    210: 
                    211: #if 1
                    212:                (void)pathname;
                    213: #else
                    214:                // パス名の非ASCIIどうするか
                    215:                if (!pathname.empty()) {
                    216:                        if (pathname.size() > screen.GetCol() - 16 - 3) {
                    217:                                pathname = pathname.substr(0, screen.GetCol() - 16 - 3);
                    218:                                pathname += "...";
                    219:                        }
                    220:                        screen.Puts(16, y, pathname.c_str());
1.1.1.4   root      221:                }
1.1.1.11  root      222: #endif
                    223:                y++;
1.1       root      224: 
1.1.1.11  root      225:                // イニシエータならここまで。(今の所イニシエータとディスクしかない)
                    226:                if (disk == NULL) {
                    227:                        continue;
1.1.1.7   root      228:                }
                    229: 
1.1.1.14  root      230:                const int x1 = 5;
                    231:                const int x2 = 29;
                    232:                const int x3 = 50;
                    233: 
                    234:                // 1行目
                    235:                screen.Print(x1, y,
1.1.1.11  root      236:                        (disk->IsRemovableDevice() ? TA::Normal : TA::Disable),
                    237:                        "MediumLoaded   %s",
                    238:                        disk->IsMediumLoaded() ? "On" : "Off");
1.1.1.14  root      239:                screen.Print(x2, y, "LogicalBlock %d", disk->GetBlocksize());
                    240:                std::string imagesize = format_number(disk->GetSize());
                    241:                screen.Print(x3, y, "ImageSize   %13s", imagesize.c_str());
                    242:                y++;
                    243: 
                    244:                // 2行目
                    245:                screen.Print(x1, y,
1.1.1.11  root      246:                        (disk->IsRemovableDevice() ? TA::Normal : TA::Disable),
                    247:                        "RemovalPrevent %s",
                    248:                        disk->IsMediumRemovalPrevented() ? "On" : "Off");
                    249: 
1.1.1.14  root      250:                screen.Puts(x2, y,
                    251:                        (disk->IsMediumLoaded() ? TA::Normal : TA::Disable),
                    252:                        disk->GetWriteModeStr());
                    253:                y++;
1.1.1.7   root      254: 
1.1.1.14  root      255:                y++;
1.1       root      256:        }
1.1.1.11  root      257: }
1.1       root      258: 
                    259: 
                    260: //
                    261: // SCSI ターゲットデバイスの共通部分
                    262: //
                    263: 
1.1.1.16! root      264: // コンストラクタ。
        !           265: SCSITarget::SCSITarget(SCSIHostDevice *h, int id)
        !           266:        : inherited(OBJ_NONE)   // オブジェクト ID で検索することはない
1.1       root      267: {
                    268:        // ホストへのリンク (所有関係のないポインタ)
                    269:        host = h;
                    270:        myid = id;
                    271: }
                    272: 
                    273: // デストラクタ
                    274: SCSITarget::~SCSITarget()
                    275: {
                    276: }
                    277: 
1.1.1.9   root      278: // 電源オン
1.1.1.14  root      279: void
                    280: SCSITarget::ResetHard(bool poweron)
1.1.1.9   root      281: {
1.1.1.14  root      282:        if (poweron) {
                    283:                ClearSense();
                    284:                cmdseq.clear();
                    285:                cmdlen = 0;
                    286:                cmd.reset();
                    287:                bytecount = 0;
                    288:                lastbyte = false;
                    289:        }
1.1.1.9   root      290: }
                    291: 
1.1.1.4   root      292: // バスリセットされた (SCSIBus から呼ばれる)
                    293: void
                    294: SCSITarget::BusResetCB()
                    295: {
1.1.1.11  root      296:        // センスキーをクリア
                    297:        ClearSense();
                    298: 
1.1.1.5   root      299:        // リセットされたので持ってる信号を全部解放。
                    300:        // 一応自分が変えていい信号線だけを落とす。
                    301:        switch (GetPhase()) {
                    302:         case SCSI::Phase::BusFree:
                    303:                break;
                    304:         case SCSI::Phase::Arbitration:
                    305:         case SCSI::Phase::Selection:
                    306:         case SCSI::Phase::Reselection:
                    307:                NegateSEL();
                    308:                NegateBSY();
                    309:                break;
                    310:         case SCSI::Phase::Transfer:
                    311:                NegateBSY();
                    312:                break;
                    313:        }
1.1.1.4   root      314: }
                    315: 
1.1       root      316: // セレクションで選択された (SCSIBus から呼ばれる)
                    317: void
                    318: SCSITarget::SelectionCB()
                    319: {
                    320:        // ターゲットが、自身が選択されていることを認識してから BSY を
                    321:        // 立てるまでの時間はもうバス側でカウントしてあるので、ここでは
                    322:        // ただちに BSY を上げてよい。
                    323:        putlog(4, "Selection Callback");
                    324:        AssertBSY();
                    325: }
                    326: 
                    327: // 情報転送フェーズを開始する (SCSIBus から呼ばれる)
                    328: void
                    329: SCSITarget::StartTransferCB()
                    330: {
                    331:        // 最初はコマンドフェーズ。(ATN はとりあえず放置)
                    332:        putlog(4, "Start Command Phase");
                    333:        cmdseq.clear();
                    334:        cmdlen = 0;
                    335:        SetXfer(SCSI::XferPhase::Command);
                    336:        AssertREQ();
                    337: }
                    338: 
                    339: // 情報転送フェーズ間の遷移について
                    340: //
                    341: // 情報転送フェーズは TransferCB() で1バイトずつ転送を行い、所定のバイト数
                    342: // の転送が完了すればフェーズを遷移する。遷移方法は入出力方向別で6通り。
                    343: //  o IN  -> IN
                    344: //  o IN  -> OUT
                    345: //  o IN  -> END
                    346: //  o OUT -> OUT
                    347: //  o OUT -> IN
                    348: //  o OUT -> END
                    349: //
                    350: // IN -> IN の遷移。TransferCB() で前フェーズの最終バイト受信後、フェーズを
                    351: // 変更して REQ を立てるところまで。
                    352: //
                    353: // IN -> OUT の遷移。TransferCB() で前フェーズの最終バイト受信後、フェーズを
                    354: // 変更して (おそらく {Phase}Begin() を発行してから)、データをセットし REQ
                    355: // を立てる?
                    356: //
                    357: // IN -> END の遷移。TransferCB() で前フェーズの最終バイト受信後、BSY を
                    358: // 下げて終了。
                    359: //
                    360: // OUT -> OUT の遷移。前フェーズの最終バイトをイニシエータが受信後に
                    361: // TransferCB() が呼ばれるので、フェーズを変更して (おそらく {Phase}Begin()
                    362: // を発行してから)、データをセットし REQ を立てる?
                    363: //
                    364: // OUT -> IN の遷移。前フェーズの最終バイトをイニシエータが受信後に
                    365: // TransferCB() が呼ばれるので、フェーズを変更して (おそらく {Phase}Begin()
                    366: // を発行してから)、REQ を立てる?
                    367: //
                    368: // OUT -> END の遷移。前フェーズの最終バイトをイニシエータが受信後に
                    369: // TransferCB() が呼ばれるので、BSY を下げる?
                    370: 
                    371: // 情報転送フェーズでイニシエータが ACK を上げた。(SCSIBus から呼ばれる)
                    372: // OUT (イニシエータ → ターゲット方向) なら、ターゲットが上げた REQ に応答
                    373: // してイニシエータがデータをデータバスに乗せてからこれをコールしてくる。
                    374: // IN (ターゲット → イニシエータ方向) なら、ターゲットがデータをデータバスに
                    375: // 乗せて REQ を上げたのをイニシエータが受信した後でこれをコールしてくる。
                    376: void
                    377: SCSITarget::TransferCB()
                    378: {
                    379:        uint8 data;
                    380:        SCSI::XferPhase xfer;
                    381: 
                    382:        // このフェーズの最終バイトか
                    383:        lastbyte = false;
                    384: 
                    385:        // このフェーズの1バイト処理
                    386:        xfer = GetXfer();
                    387:        if (xfer == SCSI::XferPhase::Command) {
                    388:                // コマンドフェーズだけいろいろ特殊なので別処理。
                    389:                // 受信バッファが異なる、1バイト目で受信長が決まるなど。
                    390:                data = GetData();
                    391:                putlog(4, "TransferCB: cmdseq[%02d] = $%02x",
                    392:                        (int)cmdseq.size(), data);
                    393:                cmdseq.push_back(data);
                    394:                if (cmdseq.size() == 1) {
                    395:                        // 1バイト目ならこのコマンドが何バイトか調べる
                    396:                        switch (cmdseq[0] >> 5) {
                    397:                         case 0:        cmdlen =  6;    break;
                    398:                         case 1:        cmdlen = 10;    break;
                    399:                         case 2:        cmdlen = 10;    break;
                    400:                         case 5:        cmdlen = 12;    break;
                    401:                         default:
                    402:                                // 3,4 はリサーブ、6,7 はベンダー定義。XXX 来たらどうする?
                    403:                                cmdlen = 6;
                    404:                                break;
                    405:                        }
                    406:                } else if (cmdseq.size() >= cmdlen) {
1.1.1.11  root      407:                        if (loglevel >= 2
                    408: #if defined(NO_READWRITE_LOG)
                    409:                                && (cmdseq[0] != SCSI::Command::Read6 &&
                    410:                                    cmdseq[0] != SCSI::Command::Read10 &&
                    411:                                    cmdseq[0] != SCSI::Command::Write6 &&
                    412:                                    cmdseq[0] != SCSI::Command::Write10)
                    413: #endif
                    414:                        ) {
1.1       root      415:                                std::string cmdbuf;
                    416:                                const char *name = SCSI::GetCommandName(cmdseq[0]);
                    417:                                cmdbuf += string_format("Command \"%s\"", name ?: "?");
                    418:                                for (const auto& v : cmdseq) {
1.1.1.11  root      419:                                        cmdbuf += string_format(" %02x", v);
1.1       root      420:                                }
1.1.1.8   root      421:                                putlogn("%s", cmdbuf.c_str());
1.1       root      422:                        }
                    423:                        // 最終バイトを受信したらコマンドを選択
                    424:                        DispatchCmd();
                    425:                        lastbyte = true;
                    426:                }
                    427:        } else if (GetIO() == false) {
                    428:                // OUT 方向 (ターゲットが受信側)
                    429:                // bytecount は減算方向。
                    430:                cmd->buf.push_back(GetData());
                    431:                bytecount--;
                    432:                if (bytecount == 0) {
                    433:                        lastbyte = true;
                    434:                }
                    435:        } else {
                    436:                // IN 方向 (ターゲットが送信側)
                    437:                // bytecount は加算方向。
                    438:                // データは前のループの終わり (TransferAckCB()の下のほう) で
                    439:                // セットしているのでここでは引き取られた分をカウントする。
                    440:                bytecount++;
                    441:                if (bytecount >= cmd->buf.size()) {
                    442:                        lastbyte = true;
                    443:                }
                    444:        }
                    445: 
                    446:        NegateREQ();
                    447: }
                    448: 
                    449: // 情報転送フェーズでイニシエータが ACK を下げた。(SCSIBus から呼ばれる)
                    450: void
                    451: SCSITarget::TransferAckCB()
                    452: {
                    453:        SCSI::XferPhase xfer = GetXfer();
                    454: 
                    455:        // これが最終バイトだったら、フェーズ完了 → フェーズ切り替え。
                    456:        if (lastbyte) {
                    457:                SCSI::XferPhase next;
                    458:                // フェーズ完了
                    459:                switch (xfer) {
                    460:                 case SCSI::XferPhase::Command:
                    461:                        next = cmd->Command(cmdseq);
                    462:                        break;
                    463:                 case SCSI::XferPhase::DataOut:
                    464:                        next = cmd->DoneDataOut();
                    465:                        break;
                    466:                 case SCSI::XferPhase::DataIn:
                    467:                        next = cmd->DoneDataIn();
                    468:                        break;
                    469:                 case SCSI::XferPhase::MsgOut:
                    470:                        next = cmd->DoneMsgOut();
                    471:                        break;
                    472:                 case SCSI::XferPhase::MsgIn:
                    473:                        next = cmd->DoneMsgIn();
                    474:                        break;
                    475:                 case SCSI::XferPhase::Status:
                    476:                        next = cmd->DoneStatus();
                    477:                        break;
                    478:                 default:
                    479:                        PANIC("TransferCB unknown xfer done %d", (int)xfer);
                    480:                }
1.1.1.11  root      481:                putlog(3, "%s done", SCSI::GetXferPhaseName(xfer));
1.1       root      482: 
1.1.1.5   root      483:                // 簡略化のため、フェーズ完了時だけ REQ を引き伸ばすことができる
                    484:                if (cmd->optime != 0) {
                    485:                        bus->SetOneshotReqWait(cmd->optime);
                    486:                        cmd->optime = 0;
                    487:                }
                    488: 
1.1       root      489:                if (next != xfer) {
                    490:                        // End ならバスフリーにして終了。
                    491:                        if (next == SCSI::XferPhase::End) {
                    492:                                NegateBSY();
                    493:                                return;
                    494:                        }
                    495: 
                    496:                        // (必要なら)フェーズを更新
                    497:                        SetXfer(next);
                    498:                        xfer = next;
                    499: 
                    500:                        // 新しいフェーズの開始処理
                    501:                        // XXX ここで bytecount とかをリセットできればいいのだが
                    502:                        // Command フェーズで Data フェーズの準備をすることが多いので
                    503:                        // 悩ましい。
                    504:                        switch (xfer) {
                    505:                         case SCSI::XferPhase::DataOut:
                    506:                                cmd->buf.clear();
                    507:                                bytecount = cmd->recvbytes;
                    508:                                putlog(3, "DataOut begin (%d bytes)", bytecount);
                    509:                                break;
                    510:                         case SCSI::XferPhase::DataIn:
                    511:                                bytecount = 0;
                    512:                                putlog(3, "DataIn begin (%d bytes)", (int)cmd->buf.size());
                    513:                                break;
                    514:                         case SCSI::XferPhase::MsgOut:
                    515:                                cmd->BeginMsgOut();
                    516:                                cmd->buf.clear();
                    517:                                bytecount = cmd->recvbytes;
                    518:                                putlog(3, "MsgOut begin (%d bytes)", bytecount);
                    519:                                break;
                    520:                         case SCSI::XferPhase::MsgIn:
                    521:                                cmd->BeginMsgIn();
                    522:                                bytecount = 0;
                    523:                                putlog(3, "MsgIn begin (%d bytes)", (int)cmd->buf.size());
                    524:                                break;
                    525:                         case SCSI::XferPhase::Status:
                    526:                                cmd->BeginStatus();
                    527:                                bytecount = 0;
                    528:                                putlog(3, "Status begin (%d bytes)", (int)cmd->buf.size());
                    529:                                break;
                    530:                         default:
                    531:                                PANIC("TransferCB unknown xfer begin %d", (int)xfer);
                    532:                        }
                    533:                }
                    534:        }
                    535: 
                    536:        // IN 方向 (ターゲットが送信側) ならここでデータをバスにセット。
                    537:        if (GetIO()) {
                    538:                SetData(cmd->buf[bytecount]);
                    539:                putlog(4, "SetData $%02x", GetData());
                    540:        }
                    541: 
                    542:        // 次のバイト転送を行うために REQ を上げる。
                    543:        AssertREQ();
                    544: }
                    545: 
                    546: // SCSI コマンドのディスパッチャ
                    547: void
                    548: SCSITarget::DispatchCmd()
                    549: {
                    550:        switch (cmdseq[0]) {
                    551:         case SCSI::Command::TestUnitReady:     // 0x00
1.1.1.11  root      552:                cmd.reset(new SCSICmd(this));
1.1       root      553:                break;
                    554: 
1.1.1.2   root      555:         case SCSI::Command::RezeroUnit:        // 0x01
1.1.1.11  root      556:                cmd.reset(new SCSICmd(this));
1.1.1.2   root      557:                break;
                    558: 
1.1       root      559:         case SCSI::Command::RequestSense:      // 0x03
                    560:                cmd.reset(new SCSICmdRequestSense(this));
                    561:                break;
                    562: 
                    563:         case SCSI::Command::Inquiry:           // 0x12
                    564:                cmd.reset(new SCSICmdInquiry(this));
                    565:                break;
                    566: 
                    567:         case SCSI::Command::ModeSelect6:       // 0x15
1.1.1.11  root      568:         case SCSI::Command::ModeSelect10:      // 0x55
                    569:                cmd.reset(new SCSICmdModeSelect(this));
1.1       root      570:                break;
                    571: 
1.1.1.2   root      572:         case SCSI::Command::ModeSense6:        // 0x1a
1.1.1.11  root      573:         case SCSI::Command::ModeSense10:       // 0x5a
                    574:                cmd.reset(new SCSICmdModeSense(this));
1.1       root      575:                break;
                    576: 
                    577:         default:
                    578:                // サポートしていないコマンド
                    579:                const char *cname = SCSI::GetCommandName(cmdseq[0]);
                    580:                std::string name;
                    581:                if (cname) {
                    582:                        name = string_format(" %s", cname);
                    583:                }
1.1.1.15  root      584:                putlog(0, "SCSI Command $%02x%s len=%d not supported",
1.1       root      585:                        cmdseq[0], name.c_str(), (int)cmdseq.size());
                    586: 
                    587:                cmd.reset(new SCSICmdNotSupportedCommand(this));
                    588:                break;
                    589:        }
                    590: }
                    591: 
1.1.1.15  root      592: // コマンド列を指定して対応するコマンドを選択する。なければ NULL を返す。
                    593: // ROM30 エミュレーション用。
                    594: SCSICmd *
                    595: SCSITarget::SelectCommand(const std::vector<uint8>& cmdseq_)
                    596: {
                    597:        cmdseq = cmdseq_;
                    598:        DispatchCmd();
                    599:        return cmd.get();
                    600: }
                    601: 
1.1.1.11  root      602: 
1.1       root      603: //
1.1.1.11  root      604: // SCSI Disk
1.1       root      605: //
                    606: 
                    607: // コンストラクタ
1.1.1.11  root      608: SCSIDisk::SCSIDisk(SCSIHostDevice *h, int id, SCSI::DevType devtype_)
1.1.1.16! root      609:        : inherited(h, id)
1.1       root      610: {
1.1.1.11  root      611:        devtype = devtype_;
                    612: 
                    613:        const char *devtypename = SCSI::GetDevTypeName(devtype);
                    614: 
                    615:        // コンストラクタの初期化子では devtypename を組み込みにくいので、
                    616:        // コンストラクタ本文でログ名などを設定する。その時の作法に
                    617:        // 従っているのですこし面倒な手法が必要。
                    618:        // lib/object.h 参照。
                    619:        SetName(string_format("SCSI%s%d", devtypename, id));
                    620:        ClearAlias();
1.1.1.16! root      621:        AddAlias(string_format("SCSI%s%d", devtypename, id));
1.1.1.12  root      622:        AddAlias(string_format("SCSI%d", id));
1.1.1.11  root      623:        AddAlias(string_format("%s%d", devtypename, id));
                    624: 
                    625:        switch (devtype) {
                    626:         case SCSI::DevType::HD:
                    627:                removable_device = false;
                    628:                writeable_device = true;
                    629:                blocksize = 512;
                    630:                break;
                    631:         case SCSI::DevType::CD:
                    632:                removable_device = true;
                    633:                writeable_device = false;
                    634:                blocksize = 2048;
                    635:                break;
                    636:         case SCSI::DevType::MO:
                    637:                removable_device = true;
                    638:                writeable_device = true;
                    639:                blocksize = 512;
                    640:                break;
                    641:         default:
1.1.1.16! root      642:                PANIC("corrupted devtype=%d", (int)devtype);
1.1.1.11  root      643:        }
1.1.1.10  root      644: 
1.1       root      645: }
                    646: 
                    647: // デストラクタ
1.1.1.11  root      648: SCSIDisk::~SCSIDisk()
1.1       root      649: {
                    650: }
                    651: 
                    652: // 初期化
                    653: bool
1.1.1.11  root      654: SCSIDisk::Init()
1.1       root      655: {
1.1.1.16! root      656:        if (inherited::Init() == false) {
        !           657:                return false;
        !           658:        }
        !           659: 
1.1.1.2   root      660:        const std::string keybody = string_format("%s-id%d-",
1.1       root      661:                host->GetConfigName(), myid);
                    662:        const std::string imgkey = keybody + "image";
1.1.1.11  root      663:        const std::string wikey  = keybody + "writeignore";
1.1       root      664:        const std::string wpkey  = keybody + "writeprotect";
1.1.1.5   root      665:        const std::string stkey  = keybody + "seektime";
1.1       root      666: 
1.1.1.11  root      667:        // デバイス種別(v[0])とパス(v[1])に分解。
                    668:        // デバイス種別はすでにチェックしてあるのでここでは不要。
1.1.1.3   root      669:        const ConfigItem& itemimg = gConfig->Find(imgkey);
1.1.1.11  root      670:        const std::string& imageval = itemimg.AsString();
                    671:        auto v = string_split(imageval, ',', 2);
                    672:        std::string filename;
                    673:        if (v.size() > 1) {
                    674:                filename = string_trim(v[1]);
                    675:        }
                    676: 
                    677:        // 固定デバイス(HD)ならファイル名は省略不可
                    678:        if (!IsRemovableDevice() && filename.empty()) {
1.1.1.2   root      679:                itemimg.Err("imagefile not specified");
1.1       root      680:                return false;
                    681:        }
                    682: 
1.1.1.14  root      683:        // リムーバブルデバイスのみ UI からの通知を受け取るイベントを用意
                    684:        if (IsRemovableDevice()) {
1.1.1.16! root      685:                scheduler->ConnectMessage(MessageID::SCSIDEV_LOAD(myid), this,
1.1.1.14  root      686:                        ToMessageCallback(&SCSIDisk::LoadCallback));
1.1.1.16! root      687:                scheduler->ConnectMessage(MessageID::SCSIDEV_UNLOAD(myid), this,
1.1.1.14  root      688:                        ToMessageCallback(&SCSIDisk::UnloadCallback));
                    689:        }
                    690: 
1.1.1.11  root      691:        // オープン前に writeignore をチェック。
                    692:        // この後パス名を処理するとすぐに UI に通知を出すため、それより前で
                    693:        // 行わないといけない。うーん。
                    694:        //
                    695:        // 変数名は元々 -writeprotect だったが -writeignore に変更した。
                    696:        // 単にリネームするだけだと、開発中に古いバージョンを二分探索とかする
                    697:        // 必要が出来た場合に面倒なので、当面は古いほうも面倒を見る。
                    698:        // 十分いらなくなった頃に削除する。
                    699:        //
                    700:        // wi指定     wp指定
                    701:        // なし               なし  wi を採用。
                    702:        // なし               あり  wp を採用。ただし警告
                    703:        // あり               なし  wi を採用。
                    704:        // あり               あり  wi を採用。ここは警告不要でいいだろう
                    705:        //
                    706:        const ConfigItem& wi = gConfig->Find(wikey);
                    707:        const ConfigItem& wp = gConfig->Find(wpkey);
                    708:        if (wi.GetFrom() == ConfigItem::FromInitial &&
                    709:            wp.GetFrom() != ConfigItem::FromInitial   )
                    710:        {
                    711:                // -writeignore (新)がなく -writeprotect (旧) だけが指定されると警告。
                    712:                // エラー停止まではしなくていいか。
                    713:                warnx("Warning: '%s' is obsolete. Use new '%s'",
                    714:                        wpkey.c_str(), wikey.c_str());
                    715: 
                    716:                write_ignore = wp.AsInt();
                    717:        } else {
                    718:                write_ignore = wi.AsInt();
1.1       root      719:        }
                    720: 
1.1.1.11  root      721:        // 設定時点でファイルが指定されていればオープン
                    722:        if (filename.empty() == false) {
1.1.1.14  root      723:                std::string path;
                    724:                if (filename[0] == '/') {
                    725:                        path = filename;
                    726:                } else {
                    727:                        // 相対パスなら VM ディレクトリから
                    728:                        path = gMainApp.GetVMDir() + filename;
                    729:                }
                    730: 
1.1.1.11  root      731:                if (LoadDisk(path) == false) {
                    732:                        return false;
                    733:                }
                    734:        } else {
                    735:                // メディアがロードされないままでも起動時は必ず通知を投げる。
                    736:                // ステータスパネルはこの UIMessage でのみ状態を更新するため。
                    737:                MediaChanged();
1.1       root      738:        }
                    739: 
1.1.1.5   root      740:        // 設定は [msec]、変数は [nsec]。
                    741:        seektime = gConfig->Find(stkey).AsInt();
                    742:        seektime *= 1_msec;
                    743: 
1.1       root      744:        return true;
                    745: }
                    746: 
1.1.1.11  root      747: // 電源オン
1.1.1.14  root      748: void
                    749: SCSIDisk::ResetHard(bool poweron)
1.1.1.11  root      750: {
1.1.1.14  root      751:        inherited::ResetHard(poweron);
1.1.1.11  root      752: 
1.1.1.14  root      753:        if (poweron) {
                    754:                // メディアの取り出し禁止を解除
                    755:                PreventMediumRemoval(false);
                    756:        }
1.1.1.11  root      757: }
                    758: 
                    759: // バスリセット
                    760: void
                    761: SCSIDisk::BusResetCB()
                    762: {
                    763:        // メディアの取り出し禁止を解除
                    764:        PreventMediumRemoval(false);
                    765: 
                    766:        inherited::BusResetCB();
                    767: }
                    768: 
                    769: // バックエンドのディスクイメージを開く。
                    770: // 成功すれば true、失敗すれば false を返す。(ロードされれば true を返す
                    771: // のではないが、medium_loaded が同じ値になるので使いまわしている)
                    772: bool
                    773: SCSIDisk::LoadDisk(const std::string& pathname_)
                    774: {
1.1.1.15  root      775:        bool unloaded;
1.1.1.11  root      776:        off_t size;
                    777:        bool w_ok;
                    778:        bool read_only;
                    779: 
                    780:        // すでにあればクローズ (ここでは通知は行わない)
1.1.1.15  root      781:        unloaded = UnloadDisk_internal();
1.1.1.11  root      782: 
                    783:        // 新しいイメージをオープン(する準備)
                    784:        pathname = pathname_;
1.1.1.12  root      785:        if (image.CreateHandler(pathname) == false) {
1.1.1.11  root      786:                goto done;
                    787:        }
                    788: 
1.1.1.12  root      789:        if (image.GetInfo(&size, &w_ok) == false) {
1.1.1.11  root      790:                goto done;
                    791:        }
                    792: 
                    793:        // セクタ単位になっていること
                    794:        if (size % blocksize != 0) {
                    795:                warnx("%s: Bad image size(%ju): Not a multiple of blocksize(%d)",
                    796:                        pathname.c_str(), (uintmax_t)size, blocksize);
                    797:                goto done;
                    798:        }
                    799:        // メディアごとの最大サイズを越えていないこと
                    800:        switch (GetDevType()) {
                    801:         case SCSI::DevType::HD:
                    802:                // LBA (32bit) * 512 byte/sector
                    803:                if (size >= 0x200'0000'0000ULL) {
                    804:                        warnx("%s: Bad image size(%ju): Too large",
                    805:                                pathname.c_str(), (uintmax_t)size);
                    806:                        goto done;
                    807:                }
                    808:                break;
                    809:         case SCSI::DevType::CD:
                    810:                // https://cdrfaq.org/faq07.html#S7-6
                    811:                // 63min = 283,500 [sect] = 553.7MB CD-ROM = 635.9MB CD-DA
                    812:                // 74min = 333,000 [sect] = 650.3MB CD-ROM = 746.9MB CD-DA
                    813:                // 80min = 360,000 [sect] = 703.1MB CD-ROM = 807.4MB CD-DA
                    814:                // 90min = 405,000 [sect] = 791.0MB CD-ROM = 908.4MB CD-DA
                    815:                // 99min = 445,500 [sect] = 870.1MB CD-ROM = 999.3MB CD-DA
                    816:                if (size >= 445500 * 2048) {
                    817:                        warnx("%s: Bad image size(%ju): Too Large",
                    818:                                pathname.c_str(), (uintmax_t)size);
                    819:                        goto done;
                    820:                }
                    821:                break;
                    822:         case SCSI::DevType::MO:
                    823:                // 128M は 25 [sect] * 10,000 [sect/track] * 512 [byte/sect]
                    824:                // 230M は 25 [sect] * 17,853 [sect/track] * 512 [byte/sect]
                    825:                // 540M は 25 [sect] * 41,660 [sect/track] * 512 [byte/sect]
                    826:                // 640M は 17 [sect] * 18,256 [sect/track] * 2048 [byte/sect]
                    827:                // 1.3G は 17 [sect] * 35,638 [sect/track] * 2048 [byte/sect]
                    828:                // 2.3G は 17 [sect] * 62,538 [sect/track] * 2048 [byte/sect]
                    829:                //
                    830:                // 今の所 512 byte/sector フォーマットのみ対応しておく。
                    831:                if (size >= 25 * 41660 * 512) {
                    832:                        warnx("%s: Bad image size(%ju): 640M or larger MO not supported",
                    833:                                pathname.c_str(), (uintmax_t)size);
                    834:                        goto done;
                    835:                }
                    836:                break;
                    837:         default:
1.1.1.16! root      838:                PANIC("corrupted devtype=%d", (int)devtype);
1.1.1.11  root      839:        }
                    840: 
                    841:        // 書き込みモードをここで確定
                    842:        if (IsWriteableDevice()) {
                    843:                // 書き込み可能デバイスの場合
                    844:                if (w_ok) {
                    845:                        if (write_ignore) {
                    846:                                write_mode = RW::WriteIgnore;
                    847:                        } else {
                    848:                                write_mode = RW::Writeable;
                    849:                        }
                    850:                } else {
                    851:                        write_mode = RW::WriteProtect;
                    852:                }
                    853:        } else {
                    854:                // 読み込み専用デバイスの場合
                    855:                write_mode = RW::ReadOnly;
                    856:        }
                    857: 
                    858:        // ここでオープン
                    859:        read_only = (GetWriteMode() != RW::Writeable);
1.1.1.12  root      860:        if (image.Open(read_only, write_ignore) == false) {
1.1.1.11  root      861:                goto done;
                    862:        }
                    863: 
                    864:        // 書き込み無視なら一応ログ出力
                    865:        if (GetWriteMode() == RW::WriteIgnore) {
                    866:                putmsg(0, "write is ignored");
                    867:        }
                    868: 
                    869:        medium_loaded = true;
1.1.1.15  root      870:        // リムーバブルデバイスでだけログを出す
                    871:        if (IsRemovableDevice()) {
                    872:                putlog(1, "Medium loaded");
1.1.1.11  root      873:        }
1.1.1.15  root      874: 
                    875:  done:
1.1.1.11  root      876:        if (medium_loaded == false) {
                    877:                // ここで状態をクリアする
                    878:                Clear();
                    879:        }
1.1.1.15  root      880: 
                    881:        // 変化があれば通知
                    882:        if (unloaded || medium_loaded) {
                    883:                MediaChanged();
                    884:        }
1.1.1.11  root      885:        return medium_loaded;
                    886: }
                    887: 
                    888: // バックエンドのディスクイメージを閉じる。
                    889: // オープンされてなければ何もしない。
                    890: void
                    891: SCSIDisk::UnloadDisk(bool force)
                    892: {
                    893:        if (IsMediumRemovalAllowed() || force) {
                    894:                if (UnloadDisk_internal()) {
                    895:                        // 実際に閉じたら通知
                    896:                        MediaChanged();
                    897:                }
                    898:        }
                    899: }
                    900: 
                    901: // バックエンドのディスクイメージを閉じる (内部用)。
                    902: // 実際に閉じれば true を返す。オープンされてなければ何もせず false を返す。
                    903: // ここでは通知は行わない。
                    904: bool
                    905: SCSIDisk::UnloadDisk_internal()
                    906: {
                    907:        if ((bool)image == false) {
                    908:                return false;
                    909:        }
                    910: 
                    911:        Clear();
                    912: 
                    913:        // 取り出し禁止はされてても解除する
                    914:        if (IsMediumRemovalPrevented()) {
                    915:                // XXX PreventMediumRemoval() を呼ぶかどうするか
                    916:                medium_removal_prevented = false;
                    917:        }
                    918: 
                    919:        putlog(1, "Medium unloaded");
                    920:        return true;
                    921: }
                    922: 
                    923: // ディスク状態をクリアする
                    924: // (メディアを取り外した時など)
                    925: void
                    926: SCSIDisk::Clear()
                    927: {
                    928:        medium_loaded = false;
1.1.1.12  root      929:        image.Close();
1.1.1.11  root      930:        pathname.clear();
                    931:        write_mode = RW::Writeable;
                    932: }
                    933: 
                    934: // メディア状態変更を UI に通知する
                    935: void
                    936: SCSIDisk::MediaChanged() const
                    937: {
                    938:        UIMessage::Post(UIMessage::SCSI_MEDIA_CHANGE, GetMyID());
                    939: }
                    940: 
                    941: // メディアを挿入する。
                    942: // UI スレッドで実行されるので、VM スレッドに通知するだけ。
                    943: void
                    944: SCSIDisk::LoadDiskUI(const std::string& pathname_)
                    945: {
                    946:        new_pathname = pathname_;
1.1.1.16! root      947:        scheduler->SendMessage(MessageID::SCSIDEV_LOAD(GetMyID()));
1.1.1.11  root      948: }
                    949: 
                    950: // メディアを排出する。
                    951: // UI スレッドで実行されるので、VM スレッドに通知するだけ。
                    952: void
                    953: SCSIDisk::UnloadDiskUI(bool force)
                    954: {
1.1.1.16! root      955:        scheduler->SendMessage(MessageID::SCSIDEV_UNLOAD(GetMyID()), force);
1.1.1.11  root      956: }
                    957: 
1.1.1.14  root      958: // メディア挿入メッセージコールバック
1.1.1.11  root      959: void
1.1.1.14  root      960: SCSIDisk::LoadCallback(MessageID msgid, uint32 arg)
1.1.1.11  root      961: {
                    962:        if (LoadDisk(new_pathname) == false) {
                    963:                // 失敗したら UI に通知
                    964:                UIMessage::Post(UIMessage::SCSI_MEDIA_FAILED);
                    965:        }
                    966: }
                    967: 
1.1.1.14  root      968: // メディア排出メッセージコールバック
1.1.1.11  root      969: void
1.1.1.14  root      970: SCSIDisk::UnloadCallback(MessageID msgid, uint32 arg)
1.1.1.11  root      971: {
1.1.1.14  root      972:        bool force = arg;
1.1.1.11  root      973:        UnloadDisk(force);
                    974: }
                    975: 
1.1       root      976: // SCSI コマンドのディスパッチャ
                    977: void
1.1.1.11  root      978: SCSIDisk::DispatchCmd()
1.1       root      979: {
                    980:        switch (cmdseq[0]) {
                    981:         case SCSI::Command::Read6:                     // 0x08
1.1.1.11  root      982:         case SCSI::Command::Read10:            // 0x28
                    983:                cmd.reset(new SCSICmdRead(this));
1.1       root      984:                break;
                    985: 
                    986:         case SCSI::Command::Write6:            // 0x0a
1.1.1.11  root      987:         case SCSI::Command::Write10:           // 0x2a
                    988:                if (IsWriteableDevice()) {
                    989:                        cmd.reset(new SCSICmdWrite(this));
                    990:                } else {
                    991:                        cmd.reset(new SCSICmdNotSupportedCommand(this));
                    992:                }
1.1       root      993:                break;
                    994: 
1.1.1.4   root      995:         case SCSI::Command::StartStopUnit:     // 0x1b
                    996:                cmd.reset(new SCSICmdStartStopUnit(this));
                    997:                break;
                    998: 
1.1.1.11  root      999:         case SCSI::Command::PreventAllowMediumRemoval: // 0x1e
                   1000:                if (IsRemovableDevice() == false) {
                   1001:                        // HD は取り出せないので、とりあえず。
                   1002:                        // XXX 要調査
                   1003:                        cmd.reset(new SCSICmdNotSupportedCommand(this));
                   1004:                        return;
                   1005:                }
                   1006:                cmd.reset(new SCSICmdPreventAllowMediumRemoval(this));
                   1007:                break;
                   1008: 
1.1       root     1009:         case SCSI::Command::ReadCapacity:      // 0x25
1.1.1.11  root     1010:                // DA デバイスでは Read Capacity (0x25)、
                   1011:                // CD-ROM デバイスでは Read CDROM Capacity (0x25) だが
                   1012:                // 今の所同じ動作なので区別せず処理する。
1.1       root     1013:                cmd.reset(new SCSICmdReadCapacity(this));
                   1014:                break;
                   1015: 
1.1.1.11  root     1016:         case SCSI::Command::SynchronizeCache:  // 0x35
                   1017:                // このクラスは、物理ドライブにあるようなディスクとの間の
                   1018:                // キャッシュ機構は持っていないので、そのキャッシュをフラッシュ
                   1019:                // しろという指示に対しては、黙って成功するだけでいい気がする。
                   1020:                // このコマンドはオプションだが NetBSD カーネルが使う。
                   1021:                //
                   1022:                // CD-ROM でキャッシュの同期とは読み出し側のことだろうか?
                   1023:                // とりあえず黙って成功しておく。
                   1024:                cmd.reset(new SCSICmd(this));
1.1       root     1025:                break;
                   1026: 
1.1.1.11  root     1027:         case SCSI::Command::ReadTOC:           // 0x43
                   1028:                if (devtype == SCSI::DevType::CD) {
                   1029:                        cmd.reset(new SCSICmdReadTOC(this));
                   1030:                } else {
                   1031:                        cmd.reset(new SCSICmdNotSupportedCommand(this));
                   1032:                }
                   1033:                break;
                   1034: 
                   1035:         case SCSI::Command::ReadFormatCapacities:      // 0x23
                   1036:                // SCSI-2 規格でないので詳細不明。
                   1037:                // ディスク用か共通かも分からないけど、とりあえず
                   1038:         case SCSI::Command::ReadDiscInformation:       // 0x51
                   1039:                // CD-ROM デバイスのオプションコマンドで
                   1040:                // CD-R ライター用(?)らしいので無視する。
                   1041:                cmd.reset(new SCSICmdNotSupportedCommand(this));
1.1.1.7   root     1042:                break;
                   1043: 
1.1       root     1044:         default:
                   1045:                // 見付からなければ基本クラス側に任せる
                   1046:                inherited::DispatchCmd();
                   1047:                break;
                   1048:        }
                   1049: }
                   1050: 
1.1.1.11  root     1051: // Inquiry データを返す
                   1052: bool
                   1053: SCSIDisk::Inquiry(std::vector<uint8>& buf, int lun)
                   1054: {
                   1055:        uint8 inqtype;
                   1056:        const char *prodname;
                   1057: 
                   1058:        switch (devtype) {
                   1059:         case SCSI::DevType::HD:
                   1060:                inqtype = SCSI::InquiryDeviceType::DirectAccess;
                   1061:                prodname = "SCSIHD";
                   1062:                break;
                   1063:         case SCSI::DevType::CD:
                   1064:                inqtype = SCSI::InquiryDeviceType::CDROM;
                   1065:                prodname = "SCSICD";
                   1066:                break;
                   1067:         case SCSI::DevType::MO:
                   1068:                inqtype = SCSI::InquiryDeviceType::MO;
                   1069:                prodname = "SCSIMO";
                   1070:                break;
                   1071:         default:
1.1.1.14  root     1072:                PANIC("Unexpected devtype=%d", (int)devtype);
1.1.1.11  root     1073:        }
                   1074: 
                   1075:        buf[0] = inqtype;
                   1076:        if (lun != 0) {
                   1077:                buf[0] |= SCSI::InquiryQualifier::LU_NotPreseted;
                   1078:        }
                   1079:        buf[1] = 0;
                   1080:        if (IsRemovableDevice()) {
                   1081:                buf[1] |= 0x80;
                   1082:        }
                   1083:        buf[2] = 2;             // SCSI-2
                   1084:        buf[3] = 2;             // Response Data Format = SCSI-2
                   1085:        buf[4] = buf.size() - 4;        // 追加データ長
                   1086: 
                   1087:        // 文字列はゼロ終端ではなく、余りは空白で埋める
                   1088:        memset(&buf[8], ' ', 36 - 8);
                   1089:        memcpy(&buf[8],  "NONO", 4);
                   1090:        memcpy(&buf[16], prodname, strlen(prodname));
                   1091:        memcpy(&buf[32], "0", 1);
                   1092: 
                   1093:        return true;
                   1094: }
                   1095: 
                   1096: // ModeSense コマンドのデバイス固有パラメータを返す
                   1097: uint8
                   1098: SCSIDisk::GetDeviceSpecificParam() const
                   1099: {
                   1100:        uint8 param = 0;
                   1101: 
                   1102:        // DA, MO, CD のデバイス固有パラメータは以下のようになっている。
                   1103:        // DPOFUA はキャッシュ制御フラグのサポート(%1)かどうかなので %0 でいい。
                   1104:        //
                   1105:        //      7   6   5     4    3   2   1   0
                   1106:        //    +---+---+---+------+---+---+---+---+
                   1107:        // DA |WP |   0   |DPOFUA|       0       | WP: Write Protect
                   1108:        //    +---+---+---+------+---+---+---+---+
                   1109:        //
                   1110:        //    +---+---+---+------+---+---+---+---+
                   1111:        // MO |WP |   0   |DPOFUA|     0     |EBC| EBC: Enable Blank Check
                   1112:        //    +---+---+---+------+---+---+---+---+
                   1113:        //
                   1114:        //    +---+---+---+------+---+---+---+---+
                   1115:        // CD |     0     |DPOFUA|       0       |
                   1116:        //    +---+---+---+------+---+---+---+---+
                   1117: 
                   1118:        if (GetDevType() == SCSI::DevType::CD) {
                   1119:                // CD には WP ビットの定義がない
                   1120:        } else {
                   1121:                // DA, MO は WP ビットの定義がある。
                   1122:                if (IsMediumLoaded() && GetWriteMode() == RW::WriteProtect) {
                   1123:                        param |= 0x80;
                   1124:                }
                   1125:        }
                   1126: 
                   1127:        return param;
                   1128: }
                   1129: 
                   1130: bool
                   1131: SCSIDisk::Read(std::vector<uint8>& buf, uint64 start)
                   1132: {
                   1133:        if (__predict_false((bool)image == false)) {
                   1134:                return false;
                   1135:        }
1.1.1.12  root     1136:        return image.Read(buf.data(), start, buf.size());
1.1.1.11  root     1137: }
                   1138: 
                   1139: bool
                   1140: SCSIDisk::Write(const std::vector<uint8>& buf, uint64 start)
                   1141: {
                   1142:        if (__predict_false((bool)image == false)) {
                   1143:                return false;
                   1144:        }
                   1145: 
1.1.1.12  root     1146:        if (GetWriteMode() >= RW::WriteProtect) {
1.1.1.11  root     1147:                // 書き込み不可
                   1148:                return false;
                   1149:        }
1.1.1.12  root     1150:        return image.Write(buf.data(), start, buf.size());
1.1.1.11  root     1151: }
                   1152: 
                   1153: off_t
                   1154: SCSIDisk::GetSize() const
                   1155: {
                   1156:        if (__predict_false((bool)image == false)) {
                   1157:                return 0;
                   1158:        }
1.1.1.12  root     1159:        return image.GetSize();
1.1.1.11  root     1160: }
                   1161: 
1.1.1.2   root     1162: // 指定の場所を自由に読み出す
                   1163: // (エミュレータ特権アクセス)
                   1164: bool
1.1.1.11  root     1165: SCSIDisk::Peek(void *buf, uint64 start, uint32 len) const
1.1.1.2   root     1166: {
1.1.1.11  root     1167:        if (__predict_false((bool)image == false)) {
1.1.1.2   root     1168:                return false;
                   1169:        }
1.1.1.12  root     1170:        return image.Read(buf, start, len);
1.1.1.2   root     1171: }
                   1172: 
1.1.1.11  root     1173: // メディアの取り出し可否(取り出し禁止)を設定する
                   1174: void
                   1175: SCSIDisk::PreventMediumRemoval(bool val)
                   1176: {
                   1177:        // 状態が変わったところでログを表示
                   1178:        if (medium_removal_prevented == false && val == true) {
                   1179:                putlog(1, "Medium removal prevented");
                   1180:        } else if (medium_removal_prevented == true && val == false) {
                   1181:                putlog(1, "Medium removal allowed");
                   1182:        }
                   1183:        medium_removal_prevented = val;
                   1184: }
1.1.1.14  root     1185: 
                   1186: // メディアの書き込みモードを文字列で返す
                   1187: const char *
                   1188: SCSIDisk::GetWriteModeStr() const
                   1189: {
                   1190:        switch (write_mode) {
                   1191:         case RW::ReadOnly:             return "ReadOnly";
                   1192:         case RW::WriteProtect: return "WriteProtected";
                   1193:         case RW::Writeable:    return "Writeable";
                   1194:         case RW::WriteIgnore:  return "WriteIgnore";
                   1195:         default:
1.1.1.16! root     1196:                PANIC("corrupted write_mode=%d", (int)write_mode);
1.1.1.14  root     1197:        }
                   1198: }

unix.superglobalmegacorp.com

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