SAM-5 核心模型 C++ Demo 程序

SAM-5 核心模型 C++ Demo 程序

以下 Demo 程序基于 SAM-5 标准的架构模型(SCSI 类、Nexus、LUN)、命令模型(命令执行、状态)、事件与通知模型、任务管理功能、任务集管理五大核心模块设计,通过面向对象思想封装关键组件,模拟 SCSI 设备的命令交互、任务管理与事件处理流程。

1. 头文件(SAM5_Core.h)

#include <iostream>
#include <vector>
#include <string>
#include <map>
#include <cstdint>
#include <algorithm>

// -------------------------- 通用枚举与常量定义 --------------------------
enum class CommandState {
    NEW,        // 新命令
    DORMANT,    // 休眠状态
    ENABLED,    // 启用状态
    BLOCKED,    // 阻塞状态(ACA 生效)
    COMPLETED   // 完成状态
};

enum class TaskAttribute {
    SIMPLE,         // 普通属性
    ORDERED,         // 有序属性
    HEAD_OF_QUEUE,   // 队列头部属性
    ACA              // ACA 专属属性
};

enum class CommandStatus {
    GOOD,                // 无错误完成
    CHECK_CONDITION,     // 需返回 Sense Data
    BUSY,                // 逻辑单元忙
    RESERVATION_CONFLICT,// 预留冲突
    TASK_SET_FULL,       // 任务集资源不足
    ACA_ACTIVE,          // ACA 生效
    TASK_ABORTED         // 命令被中止
};

enum class ServiceResponse {
    COMMAND_COMPLETE,                  // 命令完成
    SERVICE_DELIVERY_OR_TARGET_FAILURE,// 服务交付失败
    FUNCTION_COMPLETE,                 // 任务管理功能完成
    FUNCTION_SUCCEEDED,                // 任务管理功能成功
    FUNCTION_REJECTED                  // 任务管理功能拒绝
};

enum class ScsiEvent {
    POWER_ON,          // 电源开启
    HARD_RESET,        // 硬重置
    LOGICAL_UNIT_RESET,// 逻辑单元重置
    I_T_NEXUS_LOSS,   // I_T Nexus 丢失
    POWER_LOSS_EXPECTED// 预期电源丢失
};

// -------------------------- 核心数据结构 --------------------------
struct SenseData {
    uint8_t senseKey;                // 错误键
    uint8_t additionalSenseCode;     // 附加错误码
    uint8_t additionalSenseQualifier;// 附加错误限定符
    std::string description;         // 错误描述

    SenseData() : senseKey(0), additionalSenseCode(0), additionalSenseQualifier(0) {}
    SenseData(uint8_t sk, uint8_t asc, uint8_t asq, const std::string& desc)
        : senseKey(sk), additionalSenseCode(asc), additionalSenseQualifier(asq), description(desc) {}
};

struct CDB {
    uint8_t operationCode;  // 操作码(命令类型)
    uint8_t controlByte;    // 控制字节(含 NACA 位)
    std::vector<uint8_t> parameters; // 命令参数

    bool isNacaSet() const {
        return (controlByte & 0x02) != 0; // NACA 位为第 1 位(bit 1)
    }
};

class LUN {
private:
    uint64_t value;          // 64 位 LUN 值
    std::string addressMethod; // 寻址方式(peripheral/flat/extended)

public:
    LUN(uint64_t val, const std::string& method) : value(val), addressMethod(method) {}

    uint64_t getValue() const { return value; }
    std::string getAddressMethod() const { return addressMethod; }
    bool isValid() const {
        return value != 0 && (addressMethod == "peripheral" || addressMethod == "flat" || addressMethod == "extended");
    }
};

class Nexus {
public:
    std::string initiatorPortId;  // 发起方端口标识
    std::string targetPortId;    // 目标方端口标识
    LUN* lun;                    // 逻辑单元(I_T_L/I_T_L_Q 需包含)
    uint32_t commandId;           // 命令标识(仅 I_T_L_Q 需包含)

    // I_T Nexus(仅发起方+目标方端口)
    Nexus(const std::string& initPort, const std::string& targetPort)
        : initiatorPortId(initPort), targetPortId(targetPort), lun(nullptr), commandId(0) {}

    // I_T_L Nexus(发起方+目标方端口+LUN)
    Nexus(const std::string& initPort, const std::string& targetPort, LUN* l)
        : initiatorPortId(initPort), targetPortId(targetPort), lun(l), commandId(0) {}

    // I_T_L_Q Nexus(完整关系:含命令标识)
    Nexus(const std::string& initPort, const std::string& targetPort, LUN* l, uint32_t cmdId)
        : initiatorPortId(initPort), targetPortId(targetPort), lun(l), commandId(cmdId) {}

    bool isITLQ() const { return lun != nullptr && commandId != 0; }
    std::string getUniqueId() const {
        std::string id = initiatorPortId + "-" + targetPortId;
        if (lun != nullptr) id += "-" + std::to_string(lun->getValue());
        if (commandId != 0) id += "-" + std::to_string(commandId);
        return id;
    }
};

// -------------------------- 事件监听接口(SAM-5 6.4) --------------------------
class IEventListener {
public:
    virtual ~IEventListener() = default;
    virtual void onEvent(ScsiEvent event, const Nexus& nexus) = 0; // 纯虚函数
};

// -------------------------- 命令类(SAM-5 5.1/8.5) --------------------------
class Command {
private:
    Nexus itlqNexus;    // I_T_L_Q Nexus(命令唯一标识)
    CDB cdb;            // 命令描述块
    TaskAttribute attr; // 任务属性
    CommandState state; // 命令状态
    CommandStatus status;// 命令完成状态
    SenseData senseData;// 错误/异常数据
    uint32_t crn;       // 命令参考号(I_T_L Nexus 内递增)

public:
    Command(const Nexus& nexus, const CDB& c, TaskAttribute ta, uint32_t crnVal)
        : itlqNexus(nexus), cdb(c), attr(ta), state(CommandState::NEW),
        status(CommandStatus::GOOD), crn(crnVal) {}

    std::string getUniqueId() const { return itlqNexus.getUniqueId(); }
    TaskAttribute getTaskAttribute() const { return attr; }
    CommandState getState() const { return state; }
    void setState(CommandState s) { state = s; }
    CommandStatus getStatus() const { return status; }
    void setCompletionStatus(CommandStatus s, const SenseData& sd) {
        status = s;
        senseData = sd;
        setState(CommandState::COMPLETED);
    }
    bool needEstablishACA() const { return cdb.isNacaSet(); }
    uint8_t getOpCode() const { return cdb.operationCode; }
};

// -------------------------- 任务集类(SAM-5 4.6.23/8.9) --------------------------
class TaskSet {
private:
    std::vector<Command*> commands; // 任务集中的命令
    bool isACAActive;              // ACA 是否生效
    std::string itlNexusId;        // 关联的 I_T_L Nexus ID

public:
    TaskSet(const std::string& nexusId) : isACAActive(false), itlNexusId(nexusId) {}
    ~TaskSet() {
        for (auto cmd : commands) delete cmd;
    }

    void addCommand(Command* cmd) {
        if (isACAActive && cmd->getTaskAttribute() != TaskAttribute::ACA) {
            cmd->setState(CommandState::BLOCKED);
        } else {
            switch (cmd->getTaskAttribute()) {
            case TaskAttribute::SIMPLE:
            case TaskAttribute::ORDERED:
                cmd->setState(CommandState::DORMANT);
                break;
            case TaskAttribute::HEAD_OF_QUEUE:
            case TaskAttribute::ACA:
                cmd->setState(CommandState::ENABLED);
                break;
            }
        }
        commands.push_back(cmd);
        std::cout << "[TaskSet] 命令 " << cmd->getUniqueId() << " 添加到任务集 " << itlNexusId << std::endl;
    }

    Command* findCommand(const std::string& cmdUniqueId) {
        for (auto cmd : commands) {
            if (cmd->getUniqueId() == cmdUniqueId) return cmd;
        }
        return nullptr;
    }

    ServiceResponse abortCommand(const std::string& cmdUniqueId) {
        Command* cmd = findCommand(cmdUniqueId);
        if (!cmd) return ServiceResponse::FUNCTION_COMPLETE;

        cmd->setCompletionStatus(CommandStatus::TASK_ABORTED, SenseData(0x0B, 0x00, 0x00, "Command aborted by task management"));
        std::cout << "[TaskSet] 命令 " << cmdUniqueId << " 已中止" << std::endl;
        return ServiceResponse::FUNCTION_COMPLETE;
    }

    ServiceResponse abortAllCommands() {
        for (auto cmd : commands) {
            if (cmd->getState() != CommandState::COMPLETED) {
                cmd->setCompletionStatus(CommandStatus::TASK_ABORTED, SenseData(0x0B, 0x00, 0x00, "Command aborted by ABORT TASK SET"));
            }
        }
        std::cout << "[TaskSet] 任务集 " << itlNexusId << " 所有命令已中止" << std::endl;
        return ServiceResponse::FUNCTION_COMPLETE;
    }

    void establishACA() {
        isACAActive = true;
        for (auto cmd : commands) {
            if (cmd->getState() == CommandState::ENABLED && cmd->getTaskAttribute() != TaskAttribute::ACA) {
                cmd->setState(CommandState::BLOCKED);
                std::cout << "[TaskSet] 命令 " << cmd->getUniqueId() << " 因 ACA 进入阻塞状态" << std::endl;
            }
        }
        std::cout << "[TaskSet] 任务集 " << itlNexusId << " ACA 条件已建立" << std::endl;
    }

    ServiceResponse clearACA() {
        if (!isACAActive) return ServiceResponse::FUNCTION_COMPLETE;

        isACAActive = false;
        for (auto cmd : commands) {
            if (cmd->getState() == CommandState::BLOCKED) {
                cmd->setState(CommandState::ENABLED);
                std::cout << "[TaskSet] 命令 " << cmd->getUniqueId() << " 因 ACA 清除进入启用状态" << std::endl;
            }
        }
        std::cout << "[TaskSet] 任务集 " << itlNexusId << " ACA 条件已清除" << std::endl;
        return ServiceResponse::FUNCTION_COMPLETE;
    }

    bool isACAEnabled() const { return isACAActive; }
    std::string getITLNexusId() const { return itlNexusId; }
};

// -------------------------- SCSI 目标设备类(SAM-5 4.6.14) --------------------------
class ScsiTargetDevice : public IEventListener {
private:
    std::string deviceName;                  // SCSI 设备名称(全球唯一)
    std::map<std::string, LUN*> logicalUnits; // 逻辑单元(LUN 值 -> LUN 对象)
    std::map<std::string, TaskSet*> taskSets; // 任务集(I_T_L Nexus ID -> 任务集)
    std::vector<IEventListener*> eventListeners; // 事件监听器
    uint32_t nextCommandId;                  // 下一个命令标识(自增)
    uint32_t nextCRN;                        // 下一个命令参考号(I_T_L Nexus 内自增)

public:
    ScsiTargetDevice(const std::string& name) : deviceName(name), nextCommandId(1), nextCRN(1) {
        // 初始化默认逻辑单元(LUN 0,flat 寻址)
        LUN* defaultLUN = new LUN(0, "flat");
        logicalUnits[std::to_string(defaultLUN->getValue())] = defaultLUN;
        std::cout << "[ScsiTargetDevice] 设备 " << deviceName << " 初始化,默认 LUN 0 已创建" << std::endl;
    }

    ~ScsiTargetDevice() {
        for (auto& lu : logicalUnits) delete lu.second;
        for (auto& ts : taskSets) delete ts.second;
    }

    // 新增:获取逻辑单元(main.cpp 调用)
    LUN* getLogicalUnit(uint64_t lunValue) {
        auto iter = logicalUnits.find(std::to_string(lunValue));
        return (iter != logicalUnits.end()) ? iter->second : nullptr;
    }

    // 新增:获取设备名称(ScsiInitiatorDevice 调用)
    std::string getDeviceName() const {
        return deviceName;
    }

    // 注册事件监听器
    void registerEventListener(IEventListener* listener) {
        eventListeners.push_back(listener);
    }

    void notifyEvent(ScsiEvent event, const Nexus& nexus)
    {
        std::cout << "[ScsiTargetDevice] 设备 " << "notifyEvent to be implmented"<< std::endl;
    }

    // 实现 IEventListener 的 onEvent 纯虚函数(关键修复)
    void onEvent(ScsiEvent event, const Nexus& nexus) override {
        std::cout << "[ScsiTargetDevice] 设备 " << deviceName << " 触发事件:";
        switch (event) {
        case ScsiEvent::POWER_ON: std::cout << "POWER_ON"; break;
        case ScsiEvent::HARD_RESET: std::cout << "HARD_RESET"; break;
        case ScsiEvent::LOGICAL_UNIT_RESET: std::cout << "LOGICAL_UNIT_RESET"; break;
        case ScsiEvent::I_T_NEXUS_LOSS: std::cout << "I_T_NEXUS_LOSS"; break;
        case ScsiEvent::POWER_LOSS_EXPECTED: std::cout << "POWER_LOSS_EXPECTED"; break;
        }
        std::cout << "(Nexus: " << nexus.getUniqueId() << ")" << std::endl;

        // 通知所有监听器
        for (auto listener : eventListeners) {
            listener->onEvent(event, nexus);
        }

        // 事件处理:硬重置 -> 中止所有任务集命令
        if (event == ScsiEvent::HARD_RESET) {
            for (auto& ts : taskSets) {
                ts.second->abortAllCommands();
            }
        }
    }

    // 执行命令(SAM-5 5.1)
    ServiceResponse executeCommand(const Nexus& itlNexus, const CDB& cdb, TaskAttribute ta, SenseData& outSenseData) {
        // 1. 验证 LUN 有效性
        if (!itlNexus.lun || !itlNexus.lun->isValid()) {
            outSenseData = SenseData(0x05, 0x25, 0x00, "Logical unit not supported");
            return ServiceResponse::COMMAND_COMPLETE;
        }

        // 2. 获取或创建任务集(I_T_L Nexus 唯一)
        std::string itlNexusId = itlNexus.getUniqueId();
        if (taskSets.find(itlNexusId) == taskSets.end()) {
            taskSets[itlNexusId] = new TaskSet(itlNexusId);
            std::cout << "[ScsiTargetDevice] 为 Nexus " << itlNexusId << " 创建新任务集" << std::endl;
        }
        TaskSet* taskSet = taskSets[itlNexusId];

        // 3. 创建 I_T_L_Q Nexus(含命令标识)
        Nexus itlqNexus(itlNexus.initiatorPortId, itlNexus.targetPortId, itlNexus.lun, nextCommandId++);

        // 4. 创建命令(CRN 自增)
        Command* cmd = new Command(itlqNexus, cdb, ta, nextCRN++);
        if (nextCRN > 0xFF) nextCRN = 1; // CRN 最大 0xFF,循环使用

        // 5. 检查任务集是否满或 ACA 生效
        if (taskSet->findCommand(cmd->getUniqueId()) != nullptr || (taskSet->isACAEnabled() && ta != TaskAttribute::ACA)) {
            outSenseData = SenseData(0x05, 0x04, 0x00, "Task set full");
            delete cmd;
            return ServiceResponse::COMMAND_COMPLETE;
        }

        // 6. 添加命令到任务集
        taskSet->addCommand(cmd);

        // 7. 模拟命令执行
        switch (cdb.operationCode) {
        case 0x08: // READ 命令
            std::cout << "[ScsiTargetDevice] 执行 READ 命令,LUN: " << itlNexus.lun->getValue() << std::endl;
            if (cmd->needEstablishACA()) {
                taskSet->establishACA();
                outSenseData = SenseData(0x02, 0x00, 0x00, "ACA established after command completion");
                cmd->setCompletionStatus(CommandStatus::CHECK_CONDITION, outSenseData);
            } else {
                cmd->setCompletionStatus(CommandStatus::GOOD, SenseData());
            }
            break;
        case 0x0A: // WRITE 命令
            std::cout << "[ScsiTargetDevice] 执行 WRITE 命令,LUN: " << itlNexus.lun->getValue() << std::endl;
            cmd->setCompletionStatus(CommandStatus::GOOD, SenseData());
            break;
        default: // 未知命令
            outSenseData = SenseData(0x05, 0x20, 0x00, "Invalid command operation code");
            cmd->setCompletionStatus(CommandStatus::CHECK_CONDITION, outSenseData);
            break;
        }

        return ServiceResponse::COMMAND_COMPLETE;
    }

    // 任务管理功能:中止指定命令(SAM-5 7.2)
    ServiceResponse abortTask(const Nexus& itlqNexus) {
        if (!itlqNexus.isITLQ()) return ServiceResponse::FUNCTION_REJECTED;

        // 提取 I_T_L Nexus ID(去掉命令 ID 部分)
        std::string itlqId = itlqNexus.getUniqueId();
        size_t lastDashPos = itlqId.rfind("-");
        if (lastDashPos == std::string::npos) return ServiceResponse::FUNCTION_REJECTED;
        std::string itlNexusId = itlqId.substr(0, lastDashPos);

        auto tsIter = taskSets.find(itlNexusId);
        if (tsIter == taskSets.end()) return ServiceResponse::FUNCTION_COMPLETE;

        return tsIter->second->abortCommand(itlqId);
    }

    // 任务管理功能:清除 ACA(SAM-5 7.4)
    ServiceResponse clearACA(const Nexus& itlNexus) {
        std::string itlNexusId = itlNexus.getUniqueId();
        auto tsIter = taskSets.find(itlNexusId);
        if (tsIter == taskSets.end()) return ServiceResponse::FUNCTION_REJECTED;

        return tsIter->second->clearACA();
    }

    // 任务管理功能:逻辑单元重置(SAM-5 7.7)
    ServiceResponse logicalUnitReset(const Nexus& itlNexus) {
        notifyEvent(ScsiEvent::LOGICAL_UNIT_RESET, itlNexus);

        std::string itlNexusId = itlNexus.getUniqueId();
        auto tsIter = taskSets.find(itlNexusId);
        if (tsIter != taskSets.end()) {
            tsIter->second->abortAllCommands();
        }

        return ServiceResponse::FUNCTION_COMPLETE;
    }
};

// -------------------------- SCSI 发起方设备类(SAM-5 4.6.9) --------------------------
class ScsiInitiatorDevice : public IEventListener {
private:
    std::string deviceName;          // 发起方设备名称
    std::string initiatorPortId;     // 发起方端口标识
    ScsiTargetDevice* targetDevice;  // 关联的目标设备

public:
    ScsiInitiatorDevice(const std::string& name, const std::string& portId)
        : deviceName(name), initiatorPortId(portId), targetDevice(nullptr) {}

    // 关联目标设备
    void attachTargetDevice(ScsiTargetDevice* target) {
        targetDevice = target;
        target->registerEventListener(this);
        std::cout << "[ScsiInitiatorDevice] 发起方 " << deviceName << " 已关联目标设备 " << target->getDeviceName() << std::endl;
    }

    // 发送命令到目标设备
    void sendCommand(const std::string& targetPortId, LUN* lun, const CDB& cdb, TaskAttribute ta) {
        if (!targetDevice) {
            std::cout << "[ScsiInitiatorDevice] 未关联目标设备,无法发送命令" << std::endl;
            return;
        }

        Nexus itlNexus(initiatorPortId, targetPortId, lun);
        SenseData senseData;

        ServiceResponse resp = targetDevice->executeCommand(itlNexus, cdb, ta, senseData);
        std::cout << "[ScsiInitiatorDevice] 命令发送完成,服务响应: ";
        switch (resp) {
        case ServiceResponse::COMMAND_COMPLETE:
            std::cout << "COMMAND_COMPLETE";
            if (senseData.senseKey != 0) {
                std::cout << ",Sense Data: " << senseData.description;
            }
            break;
        case ServiceResponse::SERVICE_DELIVERY_OR_TARGET_FAILURE:
            std::cout << "SERVICE_DELIVERY_OR_TARGET_FAILURE";
            break;
        default:
            std::cout << "未知响应";
            break;
        }
        std::cout << std::endl;
    }

    // 发送任务管理请求:中止命令
    void sendAbortTaskRequest(const std::string& targetPortId, LUN* lun, uint32_t commandId) {
        if (!targetDevice) {
            std::cout << "[ScsiInitiatorDevice] 未关联目标设备,无法发送中止请求" << std::endl;
            return;
        }

        Nexus itlqNexus(initiatorPortId, targetPortId, lun, commandId);
        ServiceResponse resp = targetDevice->abortTask(itlqNexus);
        std::cout << "[ScsiInitiatorDevice] 中止命令请求完成,服务响应: " <<
            (resp == ServiceResponse::FUNCTION_COMPLETE ? "FUNCTION_COMPLETE" : "FUNCTION_REJECTED") << std::endl;
    }

    // 接收目标设备事件通知
    void onEvent(ScsiEvent event, const Nexus& nexus) override {
        std::cout << "[ScsiInitiatorDevice] 发起方 " << deviceName << " 收到事件通知:";
        switch (event) {
        case ScsiEvent::LOGICAL_UNIT_RESET:
            std::cout << "逻辑单元重置,Nexus: " << nexus.getUniqueId();
            break;
        case ScsiEvent::I_T_NEXUS_LOSS:
            std::cout << "I_T Nexus 丢失,Nexus: " << nexus.getUniqueId();
            break;
        default:
            std::cout << "其他事件";
            break;
        }
        std::cout << std::endl;
    }
};

2. 源文件(SAM5_Demo.cpp)

#include "SAM5_Core.h"

int main() {
    setlocale(LC_ALL, ".UTF-8");
    // -------------------------- 1. 初始化设备 --------------------------
    ScsiTargetDevice targetDevice("TargetDisk01");
    ScsiInitiatorDevice initiatorDevice("InitiatorHost01", "InitPort001");
    initiatorDevice.attachTargetDevice(&targetDevice);

    // 获取默认 LUN(LUN 0)
    LUN* defaultLUN = targetDevice.getLogicalUnit(0);
    if (!defaultLUN) {
        std::cerr << "默认 LUN 0 不存在,程序退出" << std::endl;
        return -1;
    }

    // -------------------------- 2. 场景1:发送 READ 命令(建立 ACA) --------------------------
    std::cout << "\n===== 场景1:发送 READ 命令(NACA=1,建立 ACA) =====" << std::endl;
    CDB readCDB;
    readCDB.operationCode = 0x08;          // READ 命令操作码
    readCDB.controlByte = 0x02;           // NACA 位=1(建立 ACA)
    readCDB.parameters = {0x00, 0x00, 0x01};// 参数:读取 1 个块
    initiatorDevice.sendCommand("TargetPort001", defaultLUN, readCDB, TaskAttribute::SIMPLE);

    // -------------------------- 3. 场景2:发送 WRITE 命令(ACA 生效,命令阻塞) --------------------------
    std::cout << "\n===== 场景2:发送 WRITE 命令(ACA 生效,非 ACA 属性命令被阻塞) =====" << std::endl;
    CDB writeCDB;
    writeCDB.operationCode = 0x0A;          // WRITE 命令操作码
    writeCDB.controlByte = 0x00;           // NACA 位=0
    writeCDB.parameters = {0x00, 0x00, 0x01};// 参数:写入 1 个块
    initiatorDevice.sendCommand("TargetPort001", defaultLUN, writeCDB, TaskAttribute::SIMPLE);

    // -------------------------- 4. 场景3:发送 ACA 属性命令(可执行) --------------------------
    std::cout << "\n===== 场景3:发送 ACA 属性命令(ACA 生效时可执行) =====" << std::endl;
    CDB acaCDB;
    acaCDB.operationCode = 0x08;           // READ 命令(ACA 属性)
    acaCDB.controlByte = 0x00;            // NACA 位=0
    acaCDB.parameters = {0x00, 0x00, 0x01};// 参数:读取 1 个块
    initiatorDevice.sendCommand("TargetPort001", defaultLUN, acaCDB, TaskAttribute::ACA);

    // -------------------------- 5. 场景4:执行 CLEAR ACA 任务管理功能 --------------------------
    std::cout << "\n===== 场景4:执行 CLEAR ACA 任务管理功能 =====" << std::endl;
    Nexus itlNexus("InitPort001", "TargetPort001", defaultLUN);
    ServiceResponse clearResp = targetDevice.clearACA(itlNexus);
    std::cout << "CLEAR ACA 响应: " << (clearResp == ServiceResponse::FUNCTION_COMPLETE ? "FUNCTION_COMPLETE" : "FUNCTION_REJECTED") << std::endl;

    // -------------------------- 6. 场景5:执行 LOGICAL UNIT RESET 任务管理功能 --------------------------
    std::cout << "\n===== 场景5:执行 LOGICAL UNIT RESET 任务管理功能 =====" << std::endl;
    ServiceResponse resetResp = targetDevice.logicalUnitReset(itlNexus);
    std::cout << "LOGICAL UNIT RESET 响应: " << (resetResp == ServiceResponse::FUNCTION_COMPLETE ? "FUNCTION_COMPLETE" : "FUNCTION_REJECTED") << std::endl;

    // -------------------------- 7. 场景6:发送 ABORT TASK 请求(中止命令 ID=3) --------------------------
    std::cout << "\n===== 场景6:发送 ABORT TASK 请求(中止命令 ID=3) =====" << std::endl;
    initiatorDevice.sendAbortTaskRequest("TargetPort001", defaultLUN, 3);

    std::cout << "\n===== 所有场景执行完成 =====" << std::endl;
    return 0;
}

3. 代码说明

(1)核心模块映射

SAM-5 核心模块代码对应组件功能说明
架构模型ScsiTargetDevice/ScsiInitiatorDevice(设备)、LUN(逻辑单元)、Nexus(关系)模拟 SCSI 设备、逻辑单元与端口关系,实现设备间关联
命令模型Command(命令)、CDB(命令描述块)、SenseData(错误信息)封装命令执行流程,支持命令状态(NEW/DORMANT/ENABLED 等)与状态码(GOOD/CHECK_CONDITION 等)
事件与通知模型IEventListener(监听器接口)、ScsiEvent(事件类型)实现事件触发与通知机制,支持电源开启、硬重置等事件处理
任务管理功能ScsiTargetDevice::abortTask/clearACA/logicalUnitReset实现 ABORT TASK、CLEAR ACA、LOGICAL UNIT RESET 等核心任务管理功能
任务集管理TaskSet(任务集)管理命令生命周期,处理 ACA 建立 / 清除、命令阻塞 / 启用等逻辑

(2)关键功能模拟

  1. ACA 机制:通过 TaskSet::establishACA() 和 clearACA() 模拟 ACA 建立(阻塞非 ACA 命令)与清除(恢复命令执行);
  2. 命令状态流转:命令创建时根据任务属性设置初始状态(SIMPLE→DORMANT、HEAD_OF_QUEUE→ENABLED),ACA 生效时转为 BLOCKED;
  3. 事件通知:目标设备触发事件(如逻辑单元重置)后,通过 notifyEvent() 通知所有注册的监听器(如发起方设备);
  4. 任务管理:支持中止指定命令、清除 ACA、逻辑单元重置等操作,符合 SAM-5 7.x 章节规范。

(3)编译与运行

  • 依赖:C++11 及以上标准(支持 STL 容器与智能指针);
  • 编译命令:g++ SAM5_Demo.cpp -o SAM5_Demo -std=c++11
  • 运行输出:将依次执行 6 个场景,打印命令执行、事件触发、任务管理操作的详细日志,展示 SAM-5 核心模型的交互流程。

4. 扩展建议

  1. 完善传输协议支持:当前 Demo 未涉及具体传输协议(如 FCP-4、iSCSI),可扩展 ScsiTransport 类封装传输层服务(如 Send SCSI Command、Task Management Request);
  2. 增加错误处理细节:扩展 SenseData 以支持更多 SAM-5 定义的错误码(如附加错误码 0x29 表示 I_T NEXUS LOSS);
  3. 多任务集并发:当前任务集与 I_T_L Nexus 一一对应,可扩展支持多 I_T Nexus 并发管理;
  4. 单元测试:基于 Google Test 等框架,为命令执行、任务管理等核心功能编写单元测试,验证是否符合 SAM-5 规范。
在验证安装路径时系统反应C:\Users\29386\.conda\envs\grounded_sam\lib\site-packages\timm\models\layers\__init__.py:48: FutureWarning: Importing from timm.models.layers is deprecated, please import via timm.layers warnings.warn(f"Importing from {__name__} is deprecated, please import via timm.layers", FutureWarning) C:\Users\29386\.conda\envs\grounded_sam\lib\site-packages\timm\models\registry.py:4: FutureWarning: Importing from timm.models.registry is deprecated, please import via timm.models warnings.warn(f"Importing from {__name__} is deprecated, please import via timm.models", FutureWarning) C:\Users\29386\segment-anything\Grounded-Segment-Anything\sam-hq\segment_anything\modeling\tiny_vit_sam.py:662: UserWarning: Overwriting tiny_vit_5m_224 in registry with segment_anything.modeling.tiny_vit_sam.tiny_vit_5m_224. This is because the name being registered conflicts with an existing name. Please check if this is not expected. return register_model(fn_wrapper) C:\Users\29386\segment-anything\Grounded-Segment-Anything\sam-hq\segment_anything\modeling\tiny_vit_sam.py:662: UserWarning: Overwriting tiny_vit_11m_224 in registry with segment_anything.modeling.tiny_vit_sam.tiny_vit_11m_224. This is because the name being registered conflicts with an existing name. Please check if this is not expected. return register_model(fn_wrapper) C:\Users\29386\segment-anything\Grounded-Segment-Anything\sam-hq\segment_anything\modeling\tiny_vit_sam.py:662: UserWarning: Overwriting tiny_vit_21m_224 in registry with segment_anything.modeling.tiny_vit_sam.tiny_vit_21m_224. This is because the name being registered conflicts with an existing name. Please check if this is not expected. return register_model(fn_wrapper) C:\Users\29386\segment-anything\Grounded-Segment-Anything\sam-hq\segment_anything\modeling\tiny_vit_sam.py:662: UserWarning: Overwriting tiny_vit_21m_384 in registry with segment_anything.modeling.tiny_vit_sam.tiny_vit_21m_384. This is because the name being registered conflicts with an existing name. Please check if this is not expected. return register_model(fn_wrapper) C:\Users\29386\segment-anything\Grounded-Segment-Anything\sam-hq\segment_anything\modeling\tiny_vit_sam.py:662: UserWarning: Overwriting tiny_vit_21m_512 in registry with segment_anything.modeling.tiny_vit_sam.tiny_vit_21m_512. This is because the name being registered conflicts with an existing name. Please check if this is not expected. return register_model(fn_wrapper) C:\Users\29386\segment-anything\Grounded-Segment-Anything\sam-hq\segment_anything\__init__.py
07-24
<think>我们正在处理两个问题: 1. timm 模块的导入警告:FutureWarning: Importing from timm.models.layers is deprecated, please import via timm.layers 2. 无法导入 'sam_hq_model_registry',因为当前安装的 segment_anything 包是原版(来自facebookresearch)而不是 sam-hq 版本(来自SysCV)。 根据用户提供的引用[1],我们了解到用户可能已经安装了CUDA和cuDNN,但当前问题与这些无关。我们需要解决的是Python包的问题。 解决方案: 1. 对于timm的警告: 这个警告是提示性的,不会导致程序终止。它只是告诉我们timm库的导入路径发生了变化,建议我们使用新的路径(`timm.layers`代替`timm.models.layers`)。但是,这个警告来自第三方库,我们无法直接修改其代码。不过,我们可以通过升级timm库来解决,因为新版本中可能已经修复了这个问题。 我们可以尝试升级timm: ```bash pip install --upgrade timm ``` 如果升级后仍然存在警告,我们可以选择忽略,因为这只是弃用警告,不影响程序运行。或者,我们可以通过设置环境变量来忽略警告: ```bash export PYTHONWARNINGS="ignore::FutureWarning" ``` 在Windows中设置环境变量的方式(在运行脚本前): ```cmd set PYTHONWARNINGS=ignore::FutureWarning ``` 或者,在Python代码开头添加: ```python import warnings warnings.filterwarnings("ignore", category=FutureWarning, module="timm") ``` 2. 对于无法导入'sam_hq_model_registry'的问题: 这是因为我们当前安装的segment_anything包是原版(facebookresearch)的,而不是sam-hq版本(SysCV)。我们需要卸载原版并安装sam-hq版本。 步骤: a. 卸载原版segment-anything: ```bash pip uninstall segment-anything ``` b. 安装sam-hq版本(从GitHub仓库直接安装): ```bash pip install git+https://github.com/SysCV/sam-hq.git ``` 3. 另外,请注意项目Grounded-Segment-Anything要求使用sam-hq版本,因此安装sam-hq版本是必须的。 4. 如果之前安装过segment-anything-hq(通过pip install segment-anything-hq),那么也需要卸载: ```bash pip uninstall segment-anything-hq ``` 然后重新安装sam-hq的GitHub版本。 5. 安装完成后,我们可以验证一下是否能够导入sam_hq_model_registry: ```python from segment_anything import sam_hq_model_registry ``` 如果没有报错,则安装成功。 6. 最后,重新运行grounded_sam_demo.py脚本。 注意:由于项目可能依赖其他库,请确保在虚拟环境中操作,以避免包冲突。 如果以上步骤完成后仍然出现导入错误,请检查Python路径(sys.path)中是否包含其他地方的segment_anything包(比如项目目录下的segment_anything文件夹)。如果有,请删除或重命名,确保优先使用安装的sam-hq包。 另外,用户之前运行命令时指定了--sam_checkpoint为sam_vit_h_4b8939.pth,这个模型文件是原版SAM模型,而sam-hq有自己对应的模型。如果使用sam-hq,需要下载对应的模型文件,并在命令行中指定。项目文档中应该提供了sam-hq模型的下载链接。因此,用户需要下载sam-hq的模型并更新--sam_checkpoint参数。 例如,sam-hq的模型命名可能类似于sam_hq_vit_h.pth,所以命令应该改为: ```bash python grounded_sam_demo.py --config GroundingDINO/groundingdino/config/GroundingDINO_SwinT_OGC.py --grounded_checkpoint weights/groundingdino_swint_ogc.pth --sam_checkpoint weights/sam_hq_vit_h.pth --input_image assets/demo1.jpg --output_dir outputs ``` 总结步骤: 1. 升级timm(可选,主要是为了消除警告,如果不在意警告可以跳过) 2. 卸载segment-anything和segment-anything-hq(如果存在) 3. 安装sam-hq:pip install git+https://github.com/SysCV/sam-hq.git 4. 下载sam-hq的模型文件(如sam_hq_vit_h.pth)并放到weights目录下 5. 修改运行命令中的--sam_checkpoint参数指向新的模型文件 6. 重新运行脚本 如果用户仍然遇到问题,可以检查安装的包版本和路径。 验证安装的包: ```bash pip list | findstr "segment-anything" ``` 应该显示包名为sam-hq,版本号类似于0.0.0(因为是从GitHub直接安装,可能没有版本号,但会显示安装路径来自GitHub)。 如果用户无法访问GitHub,可以尝试从镜像安装,或者手动下载sam-hq仓库,然后通过本地安装: ```bash git clone https://github.com/SysCV/sam-hq.git cd sam-hq pip install -e . ``` 注意:在Windows系统上,可能需要安装C++构建工具(如Visual Studio Build Tools)来编译一些依赖项。如果安装过程中出现编译错误,请安装相应的构建工具。 最后,关于timm的警告,如果升级后仍然存在,可以忽略,因为它不影响程序运行。或者按照上述方法设置忽略警告。 希望这些步骤能帮助用户解决问题。</think>### Windows 系统上解决 timm 导入警告和模型注册冲突的完整方案 #### 问题分析 1. **timm 导入警告**:表明 `timm.models.layers` 的导入方式已弃用,需改用 `timm.layers` 2. **模型注册冲突**:`sam_hq_model_registry` 导入失败,根本原因是: - 安装了错误的 segment-anything 包(Facebook 原版而非 SysCV 的 HQ 版本) - 环境变量未正确配置导致路径冲突 --- ### 解决方案步骤 #### 步骤 1:解决 timm 导入警告(可选) ```powershell # 升级 timm 到最新版 pip install --upgrade timm # 临时忽略警告(不影响功能) $env:PYTHONWARNINGS = "ignore::FutureWarning" ``` > 此警告不影响程序运行,升级 timm 可消除[^1] #### 步骤 2:修复模型注册冲突(核心问题) ```powershell # 卸载冲突包 pip uninstall -y segment-anything segment-anything-hq # 安装正确版本 pip install git+https://github.com/SysCV/sam-hq.git # 验证安装 python -c "from segment_anything import sam_hq_model_registry; print('导入成功!')" ``` #### 步骤 3:配置环境变量(关键) ```powershell # 添加项目路径到 PYTHONPATH(临时) $env:PYTHONPATH = "C:\Users\29386\segment-anything\Grounded-Segment-Anything;$env:PYTHONPATH" # 永久配置(管理员运行) [Environment]::SetEnvironmentVariable( "PYTHONPATH", "C:\Users\29386\segment-anything\Grounded-Segment-Anything;$env:PYTHONPATH", "Machine" ) ``` #### 步骤 4:验证安装路径 ```powershell # 检查 segment_anything 来源 python -c "import segment_anything; print(segment_anything.__file__)" # 正确输出应包含 "site-packages/sam_hq" # 若显示 "facebookresearch" 需重新执行步骤2 ``` #### 步骤 5:更新模型文件(重要) 从 [SAM-HQ 官方发布页](https://github.com/SysCV/sam-hq/releases) 下载 HQ 模型: 1. 下载 `sam_hq_vit_h.pth` 替换原 `sam_vit_h_4b8939.pth` 2. 更新运行命令: ```bash python grounded_sam_demo.py \ --config GroundingDINO/groundingdino/config/GroundingDINO_SwinT_OGC.py \ --grounded_checkpoint weights/groundingdino_swint_ogc.pth \ --sam_checkpoint weights/sam_hq_vit_h.pth \ # 更新此处 --input_image assets/demo1.jpg \ --output_dir outputs ``` --- ### 技术原理说明 1. **路径冲突机制**: ```mermaid graph LR A[Python导入搜索路径] --> B(site-packages/sam_hq) A --> C(facebookresearch/segment_anything) D{优先级} --> |PYTHONPATH控制| B ``` 2. **版本差异**: - 原版 SAM:无 `sam_hq_model_registry` - SAM-HQ:扩展了 HQ 模型注册功能 > 通过路径修正可解决 99% 的导入冲突问题[^1]
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值