Annotation of nono/vm/scsidomain.cpp, revision 1.1.1.3

1.1       root        1: //
                      2: // nono
                      3: // Copyright (C) 2025 nono project
                      4: // Licensed under nono-license.txt
                      5: //
                      6: 
                      7: //
                      8: // SCSI ドメイン
                      9: //
                     10: 
                     11: // SCSI ドメインは、1台のイニシエータとそれに繋がるターゲットからなるシステム
                     12: // 一式を指すことにする。ここには SCSIBus は含まない。
                     13: //
                     14: // HBA (SPCとか)
                     15: //  |
                     16: //  +----> .domain ................................................
                     17: //  |     (SCSIDomain)                                            :
                     18: //  |      :  +----------------+  +------------+  +------------+  :
                     19: //  | .parent |.initiator      |  |.target[0]  |  |.target[6]  |  :
                     20: //  |<--------|(SCSIHostDevice)|  |(SCSITarget)|  |(SCSITarget)|  :
                     21: //  |      :  +----------------+  +------------+  +------------+  :
                     22: //  |      :         ^ |               ^ |             ^ |        :
                     23: //  |      ..........|.|...............|.|.............|.|.........
                     24: //  |                | |               | |             | |
                     25: //  |                | |.bus           | |.bus         | |.bus
                     26: //  +----> .bus .....|.|...............|.|.............|.|.........
                     27: //        (SCSIBus)  | v               | v             | v        :
                     28: //         :     .device[7]        .device[0]      .device[6]     :
                     29: //         :     (SCSIDevice)      (SCSIDevice)    (SCSIDevice)   :
                     30: //         ........................................................
                     31: //
                     32: // 初期化 (Create) 時に SCSIDomain は設定ファイルから自分のドメインの
                     33: // 各 .target[] と .initiator を生成する。
                     34: // HBA が SCSIBus を持つタイプであれば Init 時に
                     35: // SCSIDomain::AttachTargets(bus)、SCSIBus::Refresh() ですべてのターゲットを
                     36: // バスに参加させる。
                     37: // HBA が SCSIBus を持たないタイプであれば GetDevices() でターゲット情報を
                     38: // 手元に持っておく。
                     39: //
                     40: // 電源オン後、イニシエータの SCSI ID が確定したら HBA は
                     41: // SCSIDomain::AttachInitiator(bus, id)、SCSIBus::Refresh() でイニシエータを
                     42: // バスに参加させる。
                     43: 
                     44: #include "scsidomain.h"
                     45: #include "scsi.h"
                     46: #include "scsibus.h"
                     47: #include "scsidev.h"
                     48: #include "config.h"
                     49: #include "monitor.h"
                     50: 
                     51: // コンストラクタ
1.1.1.3 ! root       52: SCSIDomain::SCSIDomain(IODevice *parent_,
        !            53:                const char *domain_name_, const char *config_name_)
1.1       root       54:        : inherited(OBJ_SCSI)
                     55: {
                     56:        parent = parent_;
1.1.1.3 ! root       57:        domain_name = domain_name_;
1.1       root       58:        config_name = config_name_;
                     59: 
                     60:        monitor = gMonitorManager->Regist(ID_MONITOR_SCSIDEVS, this);
1.1.1.3 ! root       61:        monitor->SetCallback(&SCSIDomain::MonitorScreen);
1.1       root       62:        // サイズは Create で決まる
                     63: }
                     64: 
                     65: // デストラクタ
                     66: SCSIDomain::~SCSIDomain()
                     67: {
                     68: }
                     69: 
                     70: // 動的なコンストラクション
                     71: bool
                     72: SCSIDomain::Create()
                     73: {
                     74:        // 設定を読み込む。
                     75:        for (int id = 0; id < MaxDevices; id++) {
                     76:                const std::string key = string_format("%s-id%u-image",
                     77:                        config_name, id);
                     78:                const ConfigItem& item = gConfig->Find(key);
                     79:                const std::string& image = item.AsString();
                     80: 
                     81:                // 空ならデバイスなし
                     82:                if (image.empty()) {
                     83:                        // 未接続部分のパラメータは減らしておくか。
                     84:                        // --show-config するとさすがに無駄に多くて邪魔なので。
                     85:                        const std::string wikey = string_format("%s-id%u-writeignore",
                     86:                                config_name, id);
                     87:                        gConfig->Delete(wikey);
                     88: 
                     89:                        // -seektime は virtio-scsi にはない。
                     90:                        if (strncmp(config_name, "virtio", 6) != 0) {
                     91:                                const std::string stkey = string_format("%s-id%u-seektime",
                     92:                                        config_name, id);
                     93:                                gConfig->Delete(stkey);
                     94:                        }
                     95:                        continue;
                     96:                }
                     97: 
                     98:                // ',' より前がデバイス種別 (ここではパスは不要)
                     99:                auto v = string_split(image, ',');
                    100:                // 比較のため前後の空白を取り除いて小文字にする
                    101:                std::string type = string_trim(v[0]);
                    102:                type = string_tolower(type);
                    103: 
                    104:                SCSI::DevType target_devtype;
                    105:                if (type == "hd") {
                    106:                        target_devtype = SCSI::DevType::HD;
                    107:                } else if (type == "cd") {
                    108:                        target_devtype = SCSI::DevType::CD;
                    109:                } else if (type == "mo") {
                    110:                        target_devtype = SCSI::DevType::MO;
                    111:                } else {
                    112:                        item.Err("Invaild device type '%s'", type.c_str());
                    113:                        return false;
                    114:                }
                    115: 
                    116:                try {
                    117:                        target[id].reset(new SCSIDisk(this, id, target_devtype));
                    118:                } catch (...) { }
                    119:                if ((bool)target[id] == false) {
                    120:                        warnx("Failed to initialize target[%u] at %s", id, __method__);
                    121:                        return false;
                    122:                }
                    123:                putlog(3, "Attach #%u", id);
                    124:        }
                    125: 
                    126:        // イニシエータを生成。
                    127:        try {
                    128:                initiator.reset(new SCSIHostDevice(this, parent));
                    129:        } catch (...) { }
                    130:        if ((bool)initiator == false) {
                    131:                warnx("Failed to initialize SCSHostDevice at %s", __method__);
                    132:                return false;
                    133:        }
                    134: 
                    135:        // この時点ではイニシエータに ID がないため失敗しないはず。
                    136:        bool r = RefreshDevices();
                    137:        assert(r == true);
                    138: 
                    139:        // イニシエータだけ必要な行数が異なるが、この時点の
                    140:        // connected_devices はイニシエータを含まないので都合がいい。
                    141:        monitor->SetSize(75, connected_devices.size() * 4 + 1);
                    142: 
                    143:        return true;
                    144: }
                    145: 
                    146: // 初期化。
                    147: bool
                    148: SCSIDomain::Init()
                    149: {
                    150:        // 初期化ではないけど、ログが使えるようになったここでデバッグ表示。
                    151:        if (loglevel >= 1) {
                    152:                const auto& conn = GetConnectedDevices();
                    153:                for (const auto dev : conn) {
1.1.1.3 ! root      154:                        putmsgn("%s target #%u %s", domain_name, dev->GetMyID(),
1.1       root      155:                                SCSI::GetDevTypeName(dev->GetDevType()));
                    156:                }
                    157:        }
                    158: 
                    159:        return true;
                    160: }
                    161: 
                    162: // すべてのターゲットをバスに参加させる。
                    163: // バスを持つホストデバイスが Init() 時に呼ぶ。
                    164: void
                    165: SCSIDomain::AttachTargets(SCSIBus *bus)
                    166: {
                    167:        for (uint id = 0; id < MaxDevices; id++) {
1.1.1.2   root      168:                if ((bool)target[id]) {
1.1       root      169:                        target[id]->Attach(bus);
                    170:                }
                    171:        }
                    172: }
                    173: 
                    174: // イニシエータに ID を付与し、(あれば)バスに参加させる。
                    175: // bus は NULL でもよい。
                    176: // 成功すれば true を返す。
                    177: // 失敗すればイニシエータの ID を -1 に設定して false を返す。
                    178: bool
                    179: SCSIDomain::AttachInitiator(SCSIBus *bus, uint id_)
                    180: {
                    181:        initiator->SetID(id_);
                    182: 
                    183:        // ドメインに反映させる。
                    184:        if (RefreshDevices() == false) {
                    185:                // 失敗したらイニシエータを切り離しておく。
                    186:                initiator->SetID(-1);
                    187:                RefreshDevices();
                    188:                return false;
                    189:        }
                    190: 
                    191:        if (bus) {
                    192:                initiator->Attach(bus);
                    193:        }
                    194: 
                    195:        return true;
                    196: }
                    197: 
                    198: // initiator と target[] から device[] と connected_devices を作り直す。
                    199: // target[] はイニシエータを含まないターゲットデバイス。
                    200: // device[] はターゲットと ID の確定したイニシエータを指す穴あきの配列。
                    201: // connected_devices はイニシエータも含む ID 順の可変長リスト。
                    202: // initiator か target[] に増減があるか、initiator の ID が確定した時に
                    203: // 呼ぶこと。
                    204: // initiator の ID が他と衝突すれば false を返す。この場合 device[] と
                    205: // connected_devices の状態は不定。
                    206: bool
                    207: SCSIDomain::RefreshDevices()
                    208: {
                    209:        // initiator と taget[] から device[] を作る。
                    210:        device.fill(NULL);
                    211:        for (int id = 0; id < MaxDevices; id++) {
                    212:                if ((bool)target[id]) {
                    213:                        device[id] = target[id].get();
                    214:                }
                    215:                if (initiator->GetMyID() == id) {
                    216:                        if (device[id]) {
                    217:                                return false;
                    218:                        }
                    219:                        device[id] = initiator.get();
                    220:                }
                    221:        }
                    222: 
                    223:        // device[] から connected_devices を作る。
                    224:        connected_devices.clear();
                    225:        for (uint id = 0; id < MaxDevices; id++) {
                    226:                if (device[id]) {
                    227:                        connected_devices.push_back(device[id]);
                    228:                }
                    229:        }
                    230: 
                    231:        return true;
                    232: }
                    233: 
                    234: // (イニシエータを除く) デバイス数を返す。
                    235: uint
                    236: SCSIDomain::GetTargetCount() const
                    237: {
                    238:        uint count = 0;
                    239: 
                    240:        for (const auto& t : target) {
                    241:                if ((bool)t) {
                    242:                        count++;
                    243:                }
                    244:        }
                    245: 
                    246:        return count;
                    247: }
                    248: 
                    249: // SCSI デバイスモニタ
                    250: // (どこでやるのがいいか分からんけど、SCSI デバイスを一括して表示したいので
                    251: // とりあえずここで)
                    252: void
1.1.1.3 ! root      253: SCSIDomain::MonitorScreen(Monitor *, TextScreen& screen)
1.1       root      254: {
                    255:        int y;
                    256: 
                    257: // 012345678901234567890123456789012345678901234567890123456789012345678901234
                    258: // ID6: HD(2048MB)
                    259: //      MediumLoaded   Off      LogicalBlock 2048    ImageSize   2,147,483,648
                    260: //      RemovalPrevent Off      WriteProtected
                    261: 
                    262: 
                    263:        screen.Clear();
                    264: 
                    265:        y = 0;
                    266:        for (const auto dev : connected_devices) {
                    267:                std::string desc = SCSI::GetDevTypeName(dev->GetDevType());
                    268:                std::string pathname;
                    269: 
                    270:                const SCSIDisk *disk = dynamic_cast<const SCSIDisk*>(dev);
                    271:                if (disk && disk->IsMediumLoaded()) {
                    272:                        desc += string_format("(%uMB)",
                    273:                                (uint)(disk->GetSize() / 1024 / 1024));
                    274:                        pathname = disk->GetPathName();
                    275:                }
                    276:                screen.Print(0, y, "ID%c: %s", '0' + dev->GetMyID(), desc.c_str());
                    277: 
                    278: #if 1
                    279:                (void)pathname;
                    280: #else
                    281:                // パス名の非ASCIIどうするか
                    282:                if (!pathname.empty()) {
                    283:                        if (pathname.size() > screen.GetCol() - 16 - 3) {
                    284:                                pathname = pathname.substr(0, screen.GetCol() - 16 - 3);
                    285:                                pathname += "...";
                    286:                        }
                    287:                        screen.Puts(16, y, pathname.c_str());
                    288:                }
                    289: #endif
                    290:                y++;
                    291: 
                    292:                // イニシエータならここまで。(今の所イニシエータとディスクしかない)
                    293:                if (disk == NULL) {
                    294:                        continue;
                    295:                }
                    296: 
                    297:                const int x1 = 5;
                    298:                const int x2 = 29;
                    299:                const int x3 = 50;
                    300: 
                    301:                // 1行目
                    302:                screen.Print(x1, y,
                    303:                        (disk->IsRemovableDevice() ? TA::Normal : TA::Disable),
                    304:                        "MediumLoaded   %s",
                    305:                        disk->IsMediumLoaded() ? "On" : "Off");
                    306:                screen.Print(x2, y, "LogicalBlock %u", disk->GetBlocksize());
                    307:                std::string imagesize = format_number(disk->GetSize());
                    308:                screen.Print(x3, y, "ImageSize %15s", imagesize.c_str());
                    309:                y++;
                    310: 
                    311:                // 2行目
                    312:                screen.Print(x1, y,
                    313:                        (disk->IsRemovableDevice() ? TA::Normal : TA::Disable),
                    314:                        "RemovalPrevent %s",
                    315:                        disk->IsMediumRemovalPrevented() ? "On" : "Off");
                    316: 
                    317:                screen.Puts(x2, y,
                    318:                        (disk->IsMediumLoaded() ? TA::Normal : TA::Disable),
                    319:                        disk->GetWriteModeStr());
                    320:                y++;
                    321: 
                    322:                y++;
                    323:        }
                    324: }

unix.superglobalmegacorp.com

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