diff --git a/GS_MockMode_Analysis.md b/GS_MockMode_Analysis.md new file mode 100644 index 0000000..b69d19d --- /dev/null +++ b/GS_MockMode_Analysis.md @@ -0,0 +1,520 @@ +# GS Mock Mode 模擬模式分析 + +## 概述 + +為 GS (DtrGuiSrv) 新增 Mock 模擬模式,無需 RAID Driver 即可運行,用於: +- 開發測試 +- CI/CD 自動化測試 +- 離線 Demo +- 功能驗證 + +## 需要模擬的關鍵函數 + +### 1. Driver I/O 層 + +| 函數 | 用途 | 模擬難度 | +|------|------|----------| +| `DevIoControl()` | I/O Control 與 Driver 通訊 | 高 | +| `QuaryDTR()` | 查詢 RAID 控制器資訊 | 中 | +| `GetCtlrEvent()` | 取得控制器事件 | 中 | + +### 2. 共享記憶體層 + +| 函數 | 用途 | 模擬難度 | +|------|------|----------| +| `InitialSHMForAllCtlr()` | 初始化共享記憶體 | 高 | +| 相關 SHM 函數 | 共享記憶體操作 | 高 | + +## 模擬模式架構 + +``` +┌─────────────────────────────────────────────────────────────────────┐ +│ GS Mock Mode 架構 │ +├─────────────────────────────────────────────────────────────────────┤ +│ │ +│ ┌─────────────────────────────────────────────────────────────┐ │ +│ │ GS (DtrGuiSrv) │ │ +│ │ │ │ +│ │ ┌─────────────────────────────────────────────────────┐ │ │ +│ │ │ Mock Mode 開關 │ │ │ +│ │ │ #define ENABLE_MOCK_MODE │ │ │ +│ │ └─────────────────────────────────────────────────────┘ │ │ +│ │ │ │ │ +│ │ ┌──────────────────┼──────────────────┐ │ │ +│ │ ▼ ▼ ▼ │ │ +│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │ +│ │ │ Real Driver │ │ Mock Driver │ │ Mock Data │ │ │ +│ │ │ (Production)│ │ (Dev/Mock) │ │ (Static) │ │ │ +│ │ └─────────────┘ └─────────────┘ └─────────────┘ │ │ +│ └─────────────────────────────────────────────────────────────┘ │ +│ │ +└─────────────────────────────────────────────────────────────────────┘ +``` + +## 實現方案 + +### 方案 1: 編譯時開關 (推薦) + +```c +// hInclude.h +#ifdef ENABLE_MOCK_MODE + #include "mock_driver.h" + #define DevIoControl mock_DevIoControl + #define QuaryDTR mock_QuaryDTR + #define GetCtlrEvent mock_GetCtlrEvent +#endif +``` + +### 方案 2: 執行時開關 + +```c +// runtime_config.h +extern BOOL g_bMockMode; + +// 初始化時檢查 +if (g_bMockMode) { + initMockDriver(); +} else { + initRealDriver(); +} +``` + +### 方案 3: 環境變數 + +```bash +# 啟動時設定 +export DTR_GUI_MOCK_MODE=1 +./DtrGuiSrv01 +``` + +## 需要實現的 Mock 函數 + +### 1. mock_driver.h + +```c +#ifndef MOCK_DRIVER_H +#define MOCK_DRIVER_H + +#include "hInclude.h" + +// Mock 初始化 +void mock_init(void); +void mock_cleanup(void); + +// Mock 控制器數據 +typedef struct { + UCHAR bStatus; + UCHAR bCtlrSN[16]; + UCHAR bModelName[32]; + UCHAR bPage0Data[1024]; // Controller Info Page + UCHAR bPage1Data[1024]; // RAID Snapshot + // ... +} MOCK_CTRL_INFO; + +// Mock DevIoControl +UCHAR mock_DevIoControl( + UCHAR bDevNo, + ULONG lControlCode, + ULONG lInSize, + PCHAR pInBuf, + ULONG lOutSize, + PCHAR pOutBuf, + USHORT *pusInBandErrCode +); + +// Mock QuaryDTR +CHAR mock_QuaryDTR( + UCHAR ucCtlrIndex, + UCHAR *bPageBuf, + UCHAR *pbHeatsink +); + +// Mock GetCtlrEvent +UCHAR mock_GetCtlrEvent( + UCHAR bCtlrNo, + PEVENT_INFO pEvent_info +); + +// 設定模擬事件 +void mock_set_event(UCHAR *eventData, int length); +void mock_clear_events(void); + +// 控制器狀態控制 +void mock_set_controller_online(BOOL online); +void mock_set_controller_count(int count); + +#endif +``` + +### 2. mock_driver.c + +```c +#include "mock_driver.h" + +// 單例 Mock 控制器資訊 +static MOCK_CTRL_INFO g_mockCtrl[MAX_DTR_IN_HOST]; +static BOOL g_bMockInitialized = FALSE; + +// 模擬的事件佇列 +static UCHAR g_mockEventQueue[100][512]; +static int g_mockEventCount = 0; + +void mock_init(void) { + if (g_bMockInitialized) return; + + // 初始化 Mock 控制器 + memset(g_mockCtrl, 0, sizeof(g_mockCtrl)); + + // 預設控制器 1 台,狀態上線 + g_mockCtrl[0].bStatus = CTLR_STATUS_ALIVE; + memcpy(g_mockCtrl[0].bCtlrSN, "MOCK00000001", 16); + memcpy(g_mockCtrl[0].bModelName, "Accusys Mock RAID", 32); + + // 填充 Page 0 資料 (Controller Info) + fill_mock_page0(g_mockCtrl[0].bPage0Data); + + g_bMockInitialized = TRUE; + + printf("[MOCK] Driver initialized\n"); +} + +UCHAR mock_DevIoControl(...) { + if (!g_bMockInitialized) mock_init(); + + // 根據 Control Code 處理 + switch (lControlCode) { + case IOCTL_DTR_GET_CONTROLLER_INFO: + // 回傳控制器資訊 + break; + + case IOCTL_DTR_GET_INBAND_EVENT: + // 回傳模擬事件 + break; + + case IOCTL_DTR_SET_INBAND_COMMAND: + // 處理命令,回傳成功 + break; + + default: + // 預設回傳成功 + *pusInBandErrCode = 0; + return SYSOK; + } + + return SYSOK; +} + +CHAR mock_QuaryDTR(UCHAR ucCtlrIndex, UCHAR *bPageBuf, UCHAR *pbHeatsink) { + if (!g_bMockInitialized) mock_init(); + + if (ucCtlrIndex >= MAX_DTR_IN_HOST) { + return FALSE; + } + + // 複製 Mock 資料 + memcpy(bPageBuf, g_mockCtrl[ucCtlrIndex].bPage0Data, 1024); + *pbHeatsink = 0x00; + + return TRUE; +} + +UCHAR mock_GetCtlrEvent(UCHAR bCtlrNo, PEVENT_INFO pEvent_info) { + if (!g_bMockInitialized) mock_init(); + + // 從佇列取出事件 + if (g_mockEventCount > 0) { + memcpy(pEvent_info->bEventBuf, g_mockEventQueue[0], 512); + pEvent_info->bStatus = TRUE; + + // 移除已取出的事件 + g_mockEventCount--; + // ... 佇列搬移 + + return SYSOK; + } + + pEvent_info->bStatus = FALSE; + return SYSFAIL_EVENT_EMPTY; +} +``` + +## 模擬的 Page 資料 + +### Page 0: Controller Info + +```c +void fill_mock_page0(UCHAR *buf) { + // Offset 0-31: Serial Number + memcpy(buf + 0, "MOCK00000001", 16); + + // Offset 32-63: Model Name + memcpy(buf + 32, "Accusys Mock RAID", 20); + + // Offset 64-95: Firmware Version + memcpy(buf + 64, "1.0.0.0", 8); + + // 其他欄位... + // 需要完整對應 Java GUI 解析的格式 +} +``` + +### 需要的 Page + +| Page | 大小 | 用途 | +|------|------|------| +| 0x00 | 1024 | Controller Info | +| 0x01 | 1024 | RAID Snapshot | +| 0x07 | 512 | LUN Map Table | +| 0x0A-0x0E | 1024 | RAID Info | +| 0x10-0x11 | 512 | Disk/Slice Names | +| 0x14 | 512 | Array Info | +| 0x1A | 512 | Enclosure Info | +| 0x1B | 512 | Disk List | + +## 模擬事件 + +### 預設模擬事件 + +```c +// 初始化時註冊一些模擬事件 +void mock_register_default_events(void) { + // 磁碟上線事件 + UCHAR diskOnlineEvent[] = { + 0x01, 0x00, 0x00, 0x00, // Event Type + 0x00, 0x00, 0x00, 0x00, // Timestamp + 0x01, 0x02, 0x00, 0x00, // Slot 1, Online + // ... + }; + mock_set_event(diskOnlineEvent, 32); + + // RAID 重建完成事件 + UCHAR rebuildDoneEvent[] = { + 0x02, 0x00, 0x00, 0x00, // Event Type + // ... + }; + mock_set_event(rebuildDoneEvent, 32); +} +``` + +## 配置檔案 + +### mock_config.json + +```json +{ + "mock_mode": true, + "controller_count": 2, + "controllers": [ + { + "serial_number": "MOCK00000001", + "model_name": "Accusys GEN2", + "firmware_version": "3.8.0", + "status": "online", + "raid_arrays": [ + { + "id": 0, + "level": "RAID5", + "disks": [0, 1, 2, 3], + "status": "Normal", + "capacity": 10000000 + } + ], + "disks": [ + {"slot": 0, "status": "Online", "capacity": 4000000}, + {"slot": 1, "status": "Online", "capacity": 4000000}, + {"slot": 2, "status": "Online", "capacity": 4000000}, + {"slot": 3, "status": "Online", "capacity": 4000000}, + {"slot": 4, "status": "Online", "capacity": 4000000, "spare": true} + ] + }, + { + "serial_number": "MOCK00000002", + "model_name": "Accusys GEN2", + "status": "online" + } + ], + "events": [ + { + "type": "DiskOnline", + "slot": 2, + "timestamp": 1234567890 + } + ] +} +``` + +## 編譯選項 + +### Makefile + +```makefile +# 一般編譯 +build: + gcc -o DtrGuiSrv01 *.c -lpthread -lm + +# Mock 模式編譯 +build-mock: + gcc -o DtrGuiSrv01_mock *.c -DENABLE_MOCK_MODE -lpthread -lm + +# 兩者區別 +ifdef ENABLE_MOCK_MODE + CFLAGS += -DENABLE_MOCK_MODE + SRCS += mock_driver.c +endif +``` + +### CMake + +```cmake +option(ENABLE_MOCK "Enable mock mode for testing" OFF) + +if(ENABLE_MOCK) + add_definitions(-DENABLE_MOCK_MODE) + set(MOCK_SOURCES mock_driver.c) +endif() + +add_executable(DtrGuiSrv01 ${SOURCES} ${MOCK_SOURCES}) +``` + +## 執行模式 + +### 1. 環境變數 + +```bash +# 啟用 Mock 模式 +export DTR_GUI_MOCK_MODE=1 +./DtrGuiSrv01 + +# 指定 Mock 設定檔 +export DTR_GUI_MOCK_CONFIG=./mock_config.json +./DtrGuiSrv01 +``` + +### 2. 命令列參數 + +```bash +./DtrGuiSrv01 --mock +./DtrGuiSrv01 -m +./DtrGuiSrv01 --mock-config ./mock_config.json +``` + +### 3. 設定檔 + +```ini +# dtr_guiconf.ini +[Server] +Port=8922 +MockMode=1 +MockConfig=./mock_config.json +``` + +## 測試案例 + +### 1. 基本連線測試 + +```python +import socket + +def test_connection(): + s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + s.connect(('localhost', 8922)) + + # 發送 GET_PAGE 請求 + request = build_get_page_request(page_code=0x00) + s.send(request) + + # 驗證回應 + response = s.recv(4096) + assert response[0] == 0x50 # Success + + s.close() +``` + +### 2. 控制器查詢測試 + +```python +def test_query_controller(): + # 查詢控制器資訊 + response = send_inband_command(opcode=0x01, page=0x00) + + # 驗證資料格式 + assert response['serial_number'] == 'MOCK00000001' + assert response['model_name'] == 'Accusys Mock RAID' +``` + +### 3. 事件測試 + +```python +def test_event_polling(): + # 設定模擬事件 + mock_set_event(disk_online_event) + + # 取得事件 + response = send_event_request(opcode=0x02) + + # 驗證事件 + assert response['event_type'] == 'DiskOnline' +``` + +## 實作時間評估 + +| 工作項目 | 時間 | +|----------|------| +| 建立 mock_driver.h/c 框架 | 1 天 | +| 實作基本 DevIoControl | 2 天 | +| 實作 QuaryDTR / GetCtlrEvent | 1 天 | +| 實作 Page 0 (Controller Info) | 1 天 | +| 實作其他 Page 資料 | 2-3 天 | +| 模擬事件系統 | 1 天 | +| JSON 設定檔支援 | 1 天 | +| 測試與除錯 | 2 天 | +| **總計** | **9-10 天** | + +## 風險與限制 + +### 已知限制 + +1. **不完整模擬**: 無法完全模擬所有 RAID 操作 +2. **狀態有限**: 只能模擬基本狀態 +3. **Driver 特定**: 某些低層級錯誤無法模擬 + +### 風險控制 + +1. **清晰標記**: Mock 模式下顯示明顯標識 +2. **日誌區分**: Mock 日誌使用不同前綴 `[MOCK]` +3. **版本標記**: 回應中包含 Mock 標記 + +```c +// 回應中加入 Mock 標記 +UCHAR mock_page0[] = { + // ... + 'M', 'O', 'C', 'K', // 識別碼 + // ... +}; +``` + +## 結論 + +### 可行性: ✅ 高 + +**結論**: 完全可行,預估 9-10 天可完成。 + +### 實作策略 + +1. **先實現基本框架**: 快速建立可運行的 Mock 骨架 +2. **逐步完善**: 按需求添加更多 Page 支援 +3. **測試驅動**: 先寫測試案例,再實作對應 Mock + +### 優點 + +- 開發期不需要實際 RAID 硬體 +- CI/CD 可自動化測試 +- 容易重現問題 +- 教學演示方便 + +### 產出 + +- `mock_driver.h` - Mock 驅動介面 +- `mock_driver.c` - Mock 驅動實作 +- `mock_config.json` - 模擬設定檔範例 +- 編譯腳本更新