Files
rust_raidguardx/GS_EventHandling.md
T
2026-03-29 13:58:19 +08:00

12 KiB

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 - 事件輪詢執行緒

// cPollingEvent.c:1397
UCHAR PollingCtlrEvent(pid_t pid2) {
    while(1) {
        for(i=0; i<MAX_DTR_IN_HOST-1; i++) {
            pCtrlInfo = pGetgloDTRInfo(i);
            
            // 只處理線上的控制器
            if(pCtrlInfo->bStatus != 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 - 儲存事件到記憶體

// 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 - 寫入事件檔案

// 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 請求處理

// 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

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     // 每個事件大小

輪詢週期

// cPollingEvent.c
#define MAX_EVENT_POLLING_THREAD_TIME_DELAY 30  // 30 秒

sleep(MAX_EVENT_POLLING_THREAD_TIME_DELAY);

Email 通知

// 事件觸發 Email
void RecEventToFile(UCHAR bCtlrNo, PEVENT_INFO pEvent_info) {
    // 解析事件
    ParseEvent2(pEvent_info->bEventBuf, EventStrBuf, EventMailBuf);
    
    // 建立 Email 通知檔案
    // IssueMailOut(bCtlrNo, ...);
}

GC 端對應

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

關鍵變數

// 全域變數
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 異步觸發