/* * mock_driver.c * * Mock Driver for RAIDGuard X GUI Server * Provides simulated RAID controller for testing without hardware */ #include "mock_driver.h" #include // ============================================================================= // 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; }