598 lines
17 KiB
C
598 lines
17 KiB
C
/*
|
|
* mock_driver.c
|
|
*
|
|
* Mock Driver for RAIDGuard X GUI Server
|
|
* Provides simulated RAID controller for testing without hardware
|
|
*/
|
|
|
|
#include "mock_driver.h"
|
|
#include <time.h>
|
|
|
|
// =============================================================================
|
|
// Global Variables
|
|
// =============================================================================
|
|
|
|
static MOCK_CTRL_INFO g_mockCtrl[MAX_DTR_IN_HOST];
|
|
static UCHAR g_mockEventQueue[100][MAX_EDB_SZ];
|
|
static int g_mockEventHead = 0;
|
|
static int g_mockEventTail = 0;
|
|
static int g_mockEventCount = 0;
|
|
static bool g_bInitialized = false;
|
|
|
|
// Configuration
|
|
static int g_controllerCount = 1;
|
|
static bool g_verbose = false;
|
|
|
|
// =============================================================================
|
|
// Initialization
|
|
// =============================================================================
|
|
|
|
void mock_set_verbose(bool verbose) {
|
|
g_verbose = verbose;
|
|
}
|
|
|
|
bool mock_is_verbose(void) {
|
|
return g_verbose;
|
|
}
|
|
|
|
void mock_init(void) {
|
|
if (g_bInitialized) return;
|
|
|
|
memset(g_mockCtrl, 0, sizeof(g_mockCtrl));
|
|
memset(g_mockEventQueue, 0, sizeof(g_mockEventQueue));
|
|
g_mockEventHead = 0;
|
|
g_mockEventTail = 0;
|
|
g_mockEventCount = 0;
|
|
|
|
// Initialize default controller
|
|
g_controllerCount = 1;
|
|
g_mockCtrl[0].bStatus = CTLR_STATUS_ALIVE;
|
|
memcpy(g_mockCtrl[0].bCtlrSN, "MOCK00000001\0", 16);
|
|
memcpy(g_mockCtrl[0].bModelName, "Accusys GEN2\0", 20);
|
|
|
|
// Fill mock page data
|
|
mock_fill_page0(0);
|
|
mock_fill_page1(0);
|
|
mock_fill_page7(0);
|
|
mock_fill_page10(0);
|
|
mock_fill_page11(0);
|
|
mock_fill_page14(0);
|
|
mock_fill_page20(0);
|
|
mock_fill_page27(0);
|
|
|
|
// Register default events
|
|
mock_register_default_events();
|
|
|
|
g_bInitialized = true;
|
|
|
|
if (g_verbose) {
|
|
printf("[MOCK] Driver initialized\n");
|
|
}
|
|
}
|
|
|
|
void mock_cleanup(void) {
|
|
if (!g_bInitialized) return;
|
|
|
|
memset(g_mockCtrl, 0, sizeof(g_mockCtrl));
|
|
memset(g_mockEventQueue, 0, sizeof(g_mockEventQueue));
|
|
g_mockEventCount = 0;
|
|
g_bInitialized = false;
|
|
|
|
if (g_verbose) {
|
|
printf("[MOCK] Driver cleanup complete\n");
|
|
}
|
|
}
|
|
|
|
// =============================================================================
|
|
// Page Data Fillers
|
|
// =============================================================================
|
|
|
|
void mock_fill_page0(int ctrlIndex) {
|
|
MOCK_CTRL_INFO *ctrl = &g_mockCtrl[ctrlIndex];
|
|
unsigned char *buf = ctrl->bPage0Data;
|
|
|
|
memset(buf, 0, 1024);
|
|
|
|
// Serial Number (Offset 0-15, 16 bytes)
|
|
memcpy(buf + 0, ctrl->bCtlrSN, 16);
|
|
|
|
// Model Name (Offset 16-47, 32 bytes)
|
|
memcpy(buf + 16, ctrl->bModelName, 20);
|
|
|
|
// Firmware Version (Offset 64-71, 8 bytes)
|
|
memcpy(buf + 64, "3.8.0.0\0", 8);
|
|
|
|
// BIOS Version (Offset 72-79, 8 bytes)
|
|
memcpy(buf + 72, "1.2.3.4\0", 8);
|
|
|
|
// Status (Offset 96)
|
|
buf[96] = 0x01; // Online
|
|
|
|
// Number of RAID Ports (Offset 104)
|
|
buf[104] = 4;
|
|
|
|
// Number of Disks (Offset 105)
|
|
buf[105] = 8;
|
|
|
|
// Controller Number (Offset 106)
|
|
buf[106] = ctrlIndex;
|
|
|
|
if (g_verbose) {
|
|
printf("[MOCK] Page 0 filled for controller %d\n", ctrlIndex);
|
|
}
|
|
}
|
|
|
|
void mock_fill_page1(int ctrlIndex) {
|
|
unsigned char *buf = g_mockCtrl[ctrlIndex].bPage1Data;
|
|
memset(buf, 0, 1024);
|
|
|
|
// RAID 0: Normal
|
|
buf[0] = 0x01; // Status: Normal
|
|
buf[1] = 0x05; // RAID Level: RAID 5
|
|
buf[2] = 0x04; // Disk Count
|
|
|
|
// RAID 1: Normal
|
|
buf[128] = 0x01;
|
|
buf[129] = 0x06; // RAID 6
|
|
buf[130] = 0x06; // 6 disks
|
|
|
|
if (g_verbose) {
|
|
printf("[MOCK] Page 1 filled for controller %d\n", ctrlIndex);
|
|
}
|
|
}
|
|
|
|
void mock_fill_page7(int ctrlIndex) {
|
|
unsigned char *buf = g_mockCtrl[ctrlIndex].bPage7Data;
|
|
memset(buf, 0, 512);
|
|
|
|
// LUN 0 mapping
|
|
buf[0] = 0x00; // LUN 0
|
|
buf[1] = 0x00; // RAID ID 0
|
|
buf[2] = 0x01; // Enable
|
|
|
|
if (g_verbose) {
|
|
printf("[MOCK] Page 7 filled for controller %d\n", ctrlIndex);
|
|
}
|
|
}
|
|
|
|
void mock_fill_page10(int ctrlIndex) {
|
|
unsigned char *buf = g_mockCtrl[ctrlIndex].bPage10Data;
|
|
memset(buf, 0, 1024);
|
|
|
|
// RAID Info Block 0
|
|
buf[0] = 0x01; // Status: Normal
|
|
buf[1] = 0x05; // RAID 5
|
|
buf[2] = 0x04; // 4 disks
|
|
buf[3] = 0x00; // Stripe Size
|
|
|
|
// Capacity (Offset 8-15, 8 bytes)
|
|
buf[8] = 0x00;
|
|
buf[9] = 0x00;
|
|
buf[10] = 0x00;
|
|
buf[11] = 0x10; // 1 TB
|
|
buf[12] = 0x00;
|
|
buf[13] = 0x00;
|
|
buf[14] = 0x00;
|
|
buf[15] = 0x00;
|
|
|
|
if (g_verbose) {
|
|
printf("[MOCK] Page 10 filled for controller %d\n", ctrlIndex);
|
|
}
|
|
}
|
|
|
|
void mock_fill_page11(int ctrlIndex) {
|
|
memset(g_mockCtrl[ctrlIndex].bPage11Data, 0, 1024);
|
|
g_mockCtrl[ctrlIndex].bPage11Data[0] = 0x01;
|
|
}
|
|
|
|
void mock_fill_page14(int ctrlIndex) {
|
|
unsigned char *buf = g_mockCtrl[ctrlIndex].bPage14Data;
|
|
memset(buf, 0, 1024);
|
|
|
|
// Event Log Structure (16 events, 64 bytes each)
|
|
// Each event: 32 bytes data + 32 bytes message
|
|
// Offset 0-15: Event Type (4 bytes), Timestamp (4 bytes), Slot/EID (4 bytes), Status (4 bytes)
|
|
// Offset 16-31: Reserved
|
|
// Offset 32-63: Event Message (32 bytes)
|
|
|
|
time_t now = time(NULL);
|
|
|
|
// Event 0: Controller started
|
|
buf[0] = 0x01; // Event Type: System
|
|
buf[1] = 0x00;
|
|
buf[2] = 0x00;
|
|
buf[3] = 0x00;
|
|
*(unsigned int*)(buf + 4) = (unsigned int)(now - 3600); // 1 hour ago
|
|
*(unsigned int*)(buf + 8) = 0xFFFFFFFF; // Controller
|
|
buf[12] = 0x01; // Status: Info
|
|
memcpy(buf + 32, "Controller started successfully ", 32);
|
|
|
|
// Event 1: Disk online
|
|
buf[64] = 0x02; // Event Type: Disk
|
|
buf[65] = 0x00;
|
|
buf[66] = 0x00;
|
|
buf[67] = 0x00;
|
|
*(unsigned int*)(buf + 68) = (unsigned int)(now - 1800); // 30 min ago
|
|
*(unsigned int*)(buf + 72) = 0x02; // Slot 2
|
|
buf[76] = 0x01; // Status: Info
|
|
memcpy(buf + 96, "Disk online ", 32);
|
|
|
|
// Event 2: RAID normal
|
|
buf[128] = 0x03; // Event Type: RAID
|
|
buf[129] = 0x00;
|
|
buf[130] = 0x00;
|
|
buf[131] = 0x00;
|
|
*(unsigned int*)(buf + 132) = (unsigned int)(now - 900); // 15 min ago
|
|
*(unsigned int*)(buf + 136) = 0x00; // RAID ID 0
|
|
buf[140] = 0x01; // Status: Info
|
|
memcpy(buf + 160, "RAID-01 status: Normal ", 32);
|
|
|
|
// Event 3: Temperature warning
|
|
buf[192] = 0x02; // Event Type: Disk
|
|
buf[193] = 0x00;
|
|
buf[194] = 0x00;
|
|
buf[195] = 0x00;
|
|
*(unsigned int*)(buf + 196) = (unsigned int)(now - 600); // 10 min ago
|
|
*(unsigned int*)(buf + 200) = 0x03; // Slot 3
|
|
buf[204] = 0x02; // Status: Warning
|
|
memcpy(buf + 224, "Disk temperature warning: 45C ", 32);
|
|
|
|
// Event 4: Power supply normal
|
|
buf[256] = 0x05; // Event Type: Power
|
|
buf[257] = 0x00;
|
|
buf[258] = 0x00;
|
|
buf[259] = 0x00;
|
|
*(unsigned int*)(buf + 260) = (unsigned int)(now - 300); // 5 min ago
|
|
*(unsigned int*)(buf + 264) = 0x00; // PS 0
|
|
buf[268] = 0x01; // Status: Info
|
|
memcpy(buf + 288, "Power supply 1 online ", 32);
|
|
|
|
// Event 5: Fan normal
|
|
buf[320] = 0x04; // Event Type: Enclosure
|
|
buf[321] = 0x00;
|
|
buf[322] = 0x00;
|
|
buf[323] = 0x00;
|
|
*(unsigned int*)(buf + 324) = (unsigned int)(now - 120); // 2 min ago
|
|
*(unsigned int*)(buf + 328) = 0x00; // Fan 0
|
|
buf[332] = 0x01; // Status: Info
|
|
memcpy(buf + 352, "Fan speed normal: 5200 RPM ", 32);
|
|
|
|
// Event 6: Network up
|
|
buf[384] = 0x06; // Event Type: Network
|
|
buf[385] = 0x00;
|
|
buf[386] = 0x00;
|
|
buf[387] = 0x00;
|
|
*(unsigned int*)(buf + 388) = (unsigned int)(now - 60); // 1 min ago
|
|
*(unsigned int*)(buf + 392) = 0x00; // Port 0
|
|
buf[396] = 0x01; // Status: Info
|
|
memcpy(buf + 416, "Network port link up ", 32);
|
|
|
|
// Event 7: Battery OK
|
|
buf[448] = 0x01; // Event Type: System
|
|
buf[449] = 0x00;
|
|
buf[450] = 0x00;
|
|
buf[451] = 0x00;
|
|
*(unsigned int*)(buf + 452) = (unsigned int)now; // Now
|
|
*(unsigned int*)(buf + 456) = 0xFFFFFFFF; // Controller
|
|
buf[460] = 0x01; // Status: Info
|
|
memcpy(buf + 480, "Battery backup unit initialized ", 32);
|
|
|
|
// Event count at offset 960 (0x3C0)
|
|
buf[960] = 8; // 8 events stored
|
|
|
|
if (g_verbose) {
|
|
printf("[MOCK] Page 14 filled for controller %d (8 events)\n", ctrlIndex);
|
|
}
|
|
}
|
|
|
|
void mock_fill_page20(int ctrlIndex) {
|
|
unsigned char *buf = g_mockCtrl[ctrlIndex].bPage20Data;
|
|
memset(buf, 0, 512);
|
|
|
|
buf[0] = 2; // Fan Count
|
|
buf[1] = 2; // Power Supply Count
|
|
buf[2] = 4; // Temperature Sensor Count
|
|
buf[3] = 1; // Heat Sink Count
|
|
buf[4] = 1; // Power Supply Fan Count
|
|
|
|
buf[0x10] = 0x50;
|
|
buf[0x11] = 0x14;
|
|
buf[0x12] = 0x40;
|
|
buf[0x13] = 0x13;
|
|
|
|
buf[0x18] = 0xA0;
|
|
buf[0x19] = 0x0F;
|
|
|
|
buf[0x20] = 35;
|
|
buf[0x21] = 32;
|
|
buf[0x22] = 38;
|
|
buf[0x23] = 30;
|
|
|
|
buf[0x40] = 0x00;
|
|
buf[0x41] = 0x00;
|
|
buf[0x42] = 0x01;
|
|
buf[0x43] = 0x00;
|
|
|
|
buf[0x50] = 0x00;
|
|
buf[0x51] = 0x00;
|
|
|
|
buf[0x60] = 0x01;
|
|
buf[0x61] = 0x64;
|
|
buf[0x62] = 0x00;
|
|
|
|
buf[0x00] = 0x00;
|
|
|
|
if (g_verbose) {
|
|
printf("[MOCK] Page 20 filled for controller %d (Enclosure Info)\n", ctrlIndex);
|
|
}
|
|
}
|
|
|
|
void mock_fill_page27(int ctrlIndex) {
|
|
unsigned char *buf = g_mockCtrl[ctrlIndex].bPage27Data;
|
|
memset(buf, 0, 512);
|
|
|
|
// Disk 0
|
|
buf[0] = 0x00; // Slot 0
|
|
buf[1] = 0x01; // Status: Online
|
|
buf[2] = 0x00; // Type: HDD
|
|
|
|
// Disk 1
|
|
buf[16] = 0x01; // Slot 1
|
|
buf[17] = 0x01; // Status: Online
|
|
|
|
// Disk 2
|
|
buf[32] = 0x02;
|
|
buf[33] = 0x01;
|
|
|
|
// Disk 3
|
|
buf[48] = 0x03;
|
|
buf[49] = 0x01;
|
|
|
|
// Disk 4 (Spare)
|
|
buf[64] = 0x04;
|
|
buf[65] = 0x01;
|
|
buf[66] = 0x02; // Spare
|
|
|
|
// Disk 5-7 Offline
|
|
buf[80] = 0x05;
|
|
buf[81] = 0x00; // Offline
|
|
|
|
if (g_verbose) {
|
|
printf("[MOCK] Page 27 filled for controller %d\n", ctrlIndex);
|
|
}
|
|
}
|
|
|
|
void mock_register_default_events(void) {
|
|
// Disk Online Event (Slot 2)
|
|
UCHAR diskOnline[] = {
|
|
0x01, 0x00, 0x00, 0x00, // Event Type: Disk Online
|
|
0x00, 0x00, 0x00, 0x00, // Timestamp
|
|
0x02, 0x00, 0x00, 0x00, // Slot 2
|
|
0x01, 0x00, 0x00, 0x00 // Status: OK
|
|
};
|
|
mock_push_event(diskOnline, 16);
|
|
}
|
|
|
|
// =============================================================================
|
|
// Driver Functions
|
|
// =============================================================================
|
|
|
|
UCHAR mock_DevIoControl(
|
|
UCHAR bDevNo,
|
|
ULONG lControlCode,
|
|
ULONG lInSize,
|
|
char *pInBuf,
|
|
ULONG lOutSize,
|
|
char *pOutBuf,
|
|
USHORT *pusInBandErrCode) {
|
|
|
|
if (!g_bInitialized) mock_init();
|
|
|
|
if (bDevNo >= MAX_DTR_IN_HOST) {
|
|
*pusInBandErrCode = 0xFF;
|
|
return 0x01;
|
|
}
|
|
|
|
// Handle different IOCTL codes
|
|
switch (lControlCode) {
|
|
case 0x9001: // GET_CONTROLLER_INFO
|
|
if (g_verbose) {
|
|
printf("[MOCK] IOCTL: GET_CONTROLLER_INFO ctrl=%d\n", bDevNo);
|
|
}
|
|
memcpy(pOutBuf, g_mockCtrl[bDevNo].bPage0Data,
|
|
lOutSize > 1024 ? 1024 : lOutSize);
|
|
break;
|
|
|
|
case 0x9002: // GET_RAID_INFO
|
|
if (g_verbose) {
|
|
printf("[MOCK] IOCTL: GET_RAID_INFO ctrl=%d\n", bDevNo);
|
|
}
|
|
memcpy(pOutBuf, g_mockCtrl[bDevNo].bPage1Data,
|
|
lOutSize > 1024 ? 1024 : lOutSize);
|
|
break;
|
|
|
|
case 0x9020: // GET_INBAND_EVENT
|
|
if (g_verbose) {
|
|
printf("[MOCK] IOCTL: GET_INBAND_EVENT ctrl=%d\n", bDevNo);
|
|
}
|
|
{
|
|
EVENT_INFO evt;
|
|
UCHAR result = mock_GetCtlrEvent(bDevNo, &evt);
|
|
if (result == SYSOK) {
|
|
memcpy(pOutBuf, evt.bEventBuf,
|
|
lOutSize > 512 ? 512 : lOutSize);
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
if (g_verbose) {
|
|
printf("[MOCK] IOCTL: 0x%04lx (not handled, returning success)\n",
|
|
lControlCode);
|
|
}
|
|
// Return success for unknown codes
|
|
break;
|
|
}
|
|
|
|
*pusInBandErrCode = 0x0000;
|
|
return SYSOK;
|
|
}
|
|
|
|
CHAR mock_QuaryDTR(UCHAR ucCtlrIndex, UCHAR *bPageBuf, UCHAR *pbHeatsink) {
|
|
if (!g_bInitialized) mock_init();
|
|
|
|
if (ucCtlrIndex >= g_controllerCount) {
|
|
return 0; // FALSE
|
|
}
|
|
|
|
// Return controller info
|
|
memcpy(bPageBuf, g_mockCtrl[ucCtlrIndex].bPage0Data, 1024);
|
|
*pbHeatsink = 0x00;
|
|
|
|
if (g_verbose) {
|
|
printf("[MOCK] QuaryDTR: controller %d, SN: %s\n",
|
|
ucCtlrIndex, g_mockCtrl[ucCtlrIndex].bCtlrSN);
|
|
}
|
|
|
|
return 1; // TRUE
|
|
}
|
|
|
|
UCHAR mock_GetCtlrEvent(UCHAR bCtlrNo, EVENT_INFO *pEvent_info) {
|
|
if (!g_bInitialized) mock_init();
|
|
|
|
if (g_mockEventCount <= 0) {
|
|
pEvent_info->bStatus = 0;
|
|
return 0x02; // SYSFAIL_EVENT_EMPTY
|
|
}
|
|
|
|
// Get event from queue
|
|
memcpy(pEvent_info->bEventBuf, g_mockEventQueue[g_mockEventHead], MAX_EDB_SZ);
|
|
pEvent_info->bStatus = 1;
|
|
|
|
// Move head
|
|
g_mockEventHead = (g_mockEventHead + 1) % 100;
|
|
g_mockEventCount--;
|
|
|
|
if (g_verbose) {
|
|
printf("[MOCK] GetCtlrEvent: event retrieved, remaining: %d\n",
|
|
g_mockEventCount);
|
|
}
|
|
|
|
return SYSOK;
|
|
}
|
|
|
|
// =============================================================================
|
|
// Configuration Functions
|
|
// =============================================================================
|
|
|
|
void mock_set_controller_count(int count) {
|
|
if (count < 1) count = 1;
|
|
if (count > MAX_DTR_IN_HOST) count = MAX_DTR_IN_HOST;
|
|
g_controllerCount = count;
|
|
}
|
|
|
|
void mock_set_controller_serial(int index, const char *sn) {
|
|
if (index < 0 || index >= MAX_DTR_IN_HOST) return;
|
|
memcpy(g_mockCtrl[index].bCtlrSN, sn, 16);
|
|
}
|
|
|
|
void mock_set_controller_model(int index, const char *model) {
|
|
if (index < 0 || index >= MAX_DTR_IN_HOST) return;
|
|
memcpy(g_mockCtrl[index].bModelName, model, 32);
|
|
}
|
|
|
|
void mock_set_controller_status(int index, UCHAR status) {
|
|
if (index < 0 || index >= MAX_DTR_IN_HOST) return;
|
|
g_mockCtrl[index].bStatus = status;
|
|
}
|
|
|
|
// =============================================================================
|
|
// Event Simulation
|
|
// =============================================================================
|
|
|
|
void mock_push_event(UCHAR *eventData, int length) {
|
|
if (length > MAX_EDB_SZ) length = MAX_EDB_SZ;
|
|
if (g_mockEventCount >= 100) {
|
|
// Queue full, remove oldest
|
|
g_mockEventHead = (g_mockEventHead + 1) % 100;
|
|
g_mockEventCount--;
|
|
}
|
|
|
|
memcpy(g_mockEventQueue[g_mockEventTail], eventData, length);
|
|
g_mockEventTail = (g_mockEventTail + 1) % 100;
|
|
g_mockEventCount++;
|
|
|
|
if (g_verbose) {
|
|
printf("[MOCK] Event pushed, count: %d\n", g_mockEventCount);
|
|
}
|
|
}
|
|
|
|
void mock_clear_events(void) {
|
|
g_mockEventHead = 0;
|
|
g_mockEventTail = 0;
|
|
g_mockEventCount = 0;
|
|
|
|
if (g_verbose) {
|
|
printf("[MOCK] Events cleared\n");
|
|
}
|
|
}
|
|
|
|
void mock_generate_disk_event(int slot, int eventType) {
|
|
UCHAR event[16];
|
|
memset(event, 0, 16);
|
|
|
|
event[0] = eventType & 0xFF; // Event Type
|
|
event[3] = slot & 0xFF; // Slot Number
|
|
|
|
mock_push_event(event, 16);
|
|
}
|
|
|
|
void mock_generate_raid_event(int raidId, int eventType) {
|
|
UCHAR event[16];
|
|
memset(event, 0, 16);
|
|
|
|
event[0] = eventType & 0xFF; // Event Type
|
|
event[3] = raidId & 0xFF; // RAID ID
|
|
|
|
mock_push_event(event, 16);
|
|
}
|
|
|
|
// =============================================================================
|
|
// Configuration File (Stub)
|
|
// =============================================================================
|
|
|
|
int mock_load_config(const char *filename) {
|
|
// TODO: Parse JSON config file
|
|
if (g_verbose) {
|
|
printf("[MOCK] Config file loading not implemented: %s\n", filename);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void mock_print_config(void) {
|
|
printf("=== Mock Configuration ===\n");
|
|
printf("Controller Count: %d\n", g_controllerCount);
|
|
for (int i = 0; i < g_controllerCount; i++) {
|
|
printf("Controller %d:\n", i);
|
|
printf(" SN: %s\n", g_mockCtrl[i].bCtlrSN);
|
|
printf(" Model: %s\n", g_mockCtrl[i].bModelName);
|
|
printf(" Status: %s\n",
|
|
g_mockCtrl[i].bStatus == CTLR_STATUS_ALIVE ? "Online" : "Offline");
|
|
}
|
|
printf("Pending Events: %d\n", g_mockEventCount);
|
|
printf("=========================\n");
|
|
}
|
|
|
|
// =============================================================================
|
|
// Accessors for testing
|
|
// =============================================================================
|
|
|
|
MOCK_CTRL_INFO* mock_get_ctrl_info(int index) {
|
|
if (index < 0 || index >= MAX_DTR_IN_HOST) return NULL;
|
|
return &g_mockCtrl[index];
|
|
}
|
|
|
|
int mock_get_event_queue_count(void) {
|
|
return g_mockEventCount;
|
|
}
|