Add GS Event handling mechanism analysis
This commit is contained in:
@@ -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 異步觸發
|
||||||
Reference in New Issue
Block a user