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

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

unix.superglobalmegacorp.com

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