# GS Event 處理機制分析 ## 概述 GS (DtrGuiSrv) 的事件處理機制負責: - 定期輪詢 RAID 控制器的事件 - 儲存事件到記憶體佇列 - 記錄事件到檔案 - 觸發 Email / SNMP 通知 ## 架構流程 ``` ┌─────────────────────────────────────────────────────────────────────┐ │ GS Event 處理架構 │ ├─────────────────────────────────────────────────────────────────────┤ │ │ │ ┌─────────────────────────────────────────────────────────────┐ │ │ │ PollingCtlrEvent (Thread) │ │ │ │ ┌─────────────────────────────────────────────────────┐ │ │ │ │ │ while(1) { │ │ │ │ │ │ for (每個控制器) { │ │ │ │ │ │ GetCtlrEvent() ──► 取得 RAID 事件 │ │ │ │ │ │ │ │ │ │ │ │ │ ▼ │ │ │ │ │ │ SaveInBandEvent() ──► 儲存到記憶體佇列 │ │ │ │ │ │ │ │ │ │ │ │ │ ▼ │ │ │ │ │ │ RecEventToFile() ──► 寫入 Event Log 檔案 │ │ │ │ │ │ } │ │ │ │ │ │ sleep(30秒) │ │ │ │ │ │ } │ │ │ │ │ └─────────────────────────────────────────────────────┘ │ │ │ └─────────────────────────────────────────────────────────────┘ │ │ │ │ │ ▼ │ │ ┌─────────────────────────────────────────────────────────────┐ │ │ │ HandleInBandEventReq (GC 請求) │ │ │ │ - 0x01: 取得單一事件 (Remove_InBand_Event) │ │ │ │ - 0x02: 取得所有事件 │ │ │ └─────────────────────────────────────────────────────────────┘ │ │ │ │ │ ▼ │ │ ┌─────────────────────────────────────────────────────────────┐ │ │ │ 事件處理動作 │ │ │ │ - Email 通知 (IssueMailOut) │ │ │ │ - SNMP Trap 發送 │ │ │ │ - UI 更新 │ │ │ └─────────────────────────────────────────────────────────────┘ │ │ │ └─────────────────────────────────────────────────────────────────────┘ ``` ## 主要函數 ### 1. PollingCtlrEvent - 事件輪詢執行緒 ```c // cPollingEvent.c:1397 UCHAR PollingCtlrEvent(pid_t pid2) { while(1) { for(i=0; ibStatus != CTLR_STATUS_ALIVE) { continue; } // 取得控制器事件 bStatus = GetCtlrEvent(i, &event_info); // 處理每個事件 while(event_info.bStatus) { // FW 更新事件處理 if(event_info.bEventBuf[0] == FW_FLUSH_EVENT) { // 設定 FW 狀態 } // 儲存事件 SaveInBandEvent(i, &event_info); // 寫入檔案 RecEventToFile(i, &event_info); } } sleep(MAX_EVENT_POLLING_THREAD_TIME_DELAY); // 30秒 } } ``` ### 2. SaveInBandEvent - 儲存事件到記憶體 ```c // cPollingEvent.c:1095 UCHAR SaveInBandEvent(UCHAR bCtlrNo, PEVENT_INFO pEvent_info) { // 取得控制器的事件佇列 sCtlrEvent = pGetEventFreeQ(bCtlrNo); // 從空閒佇列取得一個 entry CurQ = sCtlrEvent->InBandFreeQ; // 複製事件資料 memcpy(CurQ->bEventBuf, pEvent_info->bEventBuf, MAX_EDB_SZ); // 標記為有效 CurQ->bStatus = TRUE; return SYSOK; } ``` ### 3. RecEventToFile - 寫入事件檔案 ```c // cPollingEvent.c:1145 void RecEventToFile(UCHAR bCtlrNo, PEVENT_INFO pEvent_info) { // 取得時間 GetSystemDateTime(DateTimeBuf); // 解析事件 ParseEvent2(pEvent_info->bEventBuf, EventStrBuf, EventMailBuf); // 寫入 Event Log 檔案 pFile_EM = fopen(FileNameBuf, "a+"); fprintf(pFile_EM, "%s\t%s\n", DateTimeBuf, EventStrBuf); fclose(pFile_EM); // 建立 Email 通知檔案 // (供 Email 發送服務讀取) } ``` ### 4. HandleInBandEventReq - GC 請求處理 ```c // cPollingEvent.c:1478 UCHAR HandleInBandEventReq(PNET_REQ_PACKAGE pReqPackage, SHORT iCtlrIndex) { switch(pReqPackage->pInBuffer[INBAND_EVENT_REQ_F_CMD_CODE]) { case 0x01: // 取得單一事件 bStatus = Remove_InBand_Event(iCtlrIndex, &EventInfo); // 回傳事件資料 break; case 0x02: // 取得所有事件 pEMH = pGetEventMsgHeader(iCtlrIndex); // 回傳所有事件 + 事件數量 break; } } ``` ## 事件結構 ### EVENT_INFO ```c typedef struct _EVENT_INFO { UCHAR bStatus; // 事件狀態 (TRUE=有事件) UCHAR bEventBuf[MAX_EDB_SZ]; // 事件資料 (512 bytes) } EVENT_INFO, *PEVENT_INFO; ``` ### 事件類型 | Event Code | 說明 | |-----------|------| | FW_FLASH_EVENT | 韌體更新事件 | | 0x00-0xFF | 其他事件 | ## 事件命令碼 | Command | 值 | 說明 | |---------|-----|------| | Get InBand Event | 0x01 | 取得並移除一個事件 | | Get All InBand Event | 0x02 | 取得所有事件 | ## 通訊協議 ### GC 請求 ``` Offset 0: Phase Code (0xFF) Offset 1: Request Code (0x00) Offset 2: Controller No Offset 3: Event Command (0x01/0x02) ``` ### GS 回應 ``` Offset 0-2: Phase/Request/Controller Offset 3: Status (0x50=Success) Offset 4: InBand Event Status Offset 5-8: Event Count (for 0x02) Offset 9+: Event Data ``` ## 資料結構 ### 事件佇列 ``` ┌─────────────────────────────────────────────────────────────┐ │ InBand Event Queue │ ├─────────────────────────────────────────────────────────────┤ │ ┌─────────────┐ │ │ │ Free Q │ ──► Event Entry 1 ──► Event Entry 2 │ │ └─────────────┘ │ │ │ │ ┌─────────────────────────────────────────────────────────┐│ │ │ Event Q Head ─────────────────────────► Tail ││ │ │ [Event1] -> [Event2] -> [Event3] -> ... ││ │ └─────────────────────────────────────────────────────────┘│ └─────────────────────────────────────────────────────────────┘ ``` ### MAX_EVENT_NO ``` #define MAX_EVENT_NO 512 // 每個控制器最大事件數 #define MAX_EDB_SZ 512 // 每個事件大小 ``` ## 輪詢週期 ```c // cPollingEvent.c #define MAX_EVENT_POLLING_THREAD_TIME_DELAY 30 // 30 秒 sleep(MAX_EVENT_POLLING_THREAD_TIME_DELAY); ``` ## Email 通知 ```c // 事件觸發 Email void RecEventToFile(UCHAR bCtlrNo, PEVENT_INFO pEvent_info) { // 解析事件 ParseEvent2(pEvent_info->bEventBuf, EventStrBuf, EventMailBuf); // 建立 Email 通知檔案 // IssueMailOut(bCtlrNo, ...); } ``` ## GC 端對應 ### Java 請求 ```java // frmMain.java - EventPollingForSNMP() // 發送請求 bCmds[0] = (byte) 0xFF; // Phase Code bCmds[1] = (byte) 0x00; // Request Code bCmds[2] = (byte) 0x00; // Controller No bCmds[3] = (byte) 0x02; // Get InBand Event ``` ## 關鍵變數 ```c // 全域變數 PCTLR_EVENT glo_sCtlrEvent[MAX_DTR_IN_HOST]; // 每個控制器的事件 PINBAND_EVENT_Q glo_sCtlrEventEntry[MAX_EVENT_NO]; // 事件 entry UCHAR bPopEventMsg = FALSE; // 是否取出事件 UCHAR bIssueMail = FALSE; // 是否發送郵件 ``` ## 處理流程圖 ``` RAID Controller │ │ In-Band Protocol ▼ ┌─────────────────────┐ │ GetCtlrEvent() │ 取得事件 └──────────┬──────────┘ │ ▼ ┌─────────────────────┐ │ event_info.bStatus │ = TRUE? └──────────┬──────────┘ Yes │ ▼ ┌─────┴─────┐ │ │ ▼ ▼ SaveInBand RecEventToFile │ │ │ ├──► Event Log File │ │ │ └──► Email File (for IssueMailOut) │ ▼ Event Queue (Memory) │ ▼ ┌─────────────────────┐ │ HandleInBandEventReq│ GC 讀取事件 │ (0x01 / 0x02) │ └──────────┬──────────┘ │ ▼ GC Client ``` ## 常見錯誤碼 | 錯誤碼 | 說明 | |--------|------| | SYSOK | 成功 | | SYSFAIL_EVENT_EMPTY | 無事件 | | SYSFAIL_EVENT_NO_FREE_Q | 事件佇列已滿 | | SYSFAIL_EVENT_INVALID | 無效事件 | ## 實作重點 1. **記憶體佇列**: 使用 linked list 儲存事件 2. **線程安全**: 使用 Semaphore 保護共享資源 3. **事件去重**: 每個事件只處理一次 4. **檔案記錄**: 所有事件寫入 Event Log 5. **異步通知**: Email/SNMP 異步觸發