Add GS Event handling mechanism analysis

This commit is contained in:
accusys
2026-03-29 13:58:19 +08:00
parent f7e7e3eb72
commit 20008f09d0
+327
View File
@@ -0,0 +1,327 @@
# 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; 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 - 儲存事件到記憶體
```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 異步觸發