/******************************************************************************* NAME $RCSfile: ssFun.c,v $ SUMMARY Report mechanism for PikesPeak VERSION $Revision: 1.4 $ UPDATE DATE $Date: 2010/08/03 09:31:37 $ PROGRAMMER $Author: alan $ Copyright 2009 Quanta Computer Inc,. All Rights Reserved. DESCRIPTION: The functions used to serve system stress program and MAPI commands for LSI REFERENCE: *******************************************************************************/ /*** INCLUDES ***/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "commFWInfo.h" #include "commPciChip.h" #ifndef BIT #define BIT(i) (1<<(i)) #endif #include "fpgaRegLib.h" #include "pchDiag.h" #include "ssFun.h" #if defined(CHASSIS_WSAS) #include "wemblySAS.h" #endif #define DAUGHTER_DIAG 1 #define MAINBOARD_DIAG 0 UINT32 sysDiagPart = MAINBOARD_DIAG; #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30) static DECLARE_MUTEX(ssFun_logMutex); #else static DEFINE_SEMAPHORE(ssFun_logMutex); #endif UINT32 sysDualCtrl = 0; // SINGLE CONTROLLER EXPORT_SYMBOL(sysDualCtrl); EXTERN VOID* gFpgaBar2VirtualP; int ssCPU_Cores=0; EXPORT_SYMBOL(ssCPU_Cores); int ss_EnclosureID=-1; EXPORT_SYMBOL(ss_EnclosureID); int g_sysStressInitFlag=0; EXPORT_SYMBOL(g_sysStressInitFlag); void ssGetEnclosureID(void) { ss_EnclosureID=(int)fpgaRegisterRead(FPGA_SUBSYSTEM_ID) & 0x0F; } int i2cSMbusReadByte(struct i2c_adapter *adap, uint16_t i2c_addr, uint8_t command, uint8_t *byte) { union i2c_smbus_data data; int status; status = i2c_smbus_xfer(adap, i2c_addr, 0, I2C_SMBUS_READ, command, I2C_SMBUS_BYTE_DATA, &data); if (status < 0) return (status); *byte = data.byte; return (0); } int i2cSMbusWriteByte(struct i2c_adapter *adap, uint16_t i2c_addr, uint8_t command, uint8_t byte) { union i2c_smbus_data data; data.byte = byte; return (i2c_smbus_xfer(adap, i2c_addr, 0, I2C_SMBUS_WRITE, command, I2C_SMBUS_BYTE_DATA,&data)); } int ssFun_SeqRelease(struct inode *inode, struct file *file) { struct seq_file *p = file->private_data; if(p->buf) { kfree(p->buf); p->buf=NULL; } kfree(p); file->private_data=NULL; return 0; } #define ssFun_LogUnitS struct ssFun_LogUnitStructure ssFun_LogUnitS { char data[SSFUN_LOGUNITSIZE]; }; //#define ssFun_LogInfoS struct ssFun_LogInfoSStructure //ssFun_LogInfoS{ // ssFun_LogUnitS *array; // INT32 start; // The start idx to sysLog[] // INT32 count; //}; #define ssFun_LogHeadS struct ssFun_LogStructure ssFun_LogHeadS{ INT32 magicNum; INT32 flags; ssFun_LogUnitS *array; INT32 start; // The start idx to sysLog[] INT32 count; INT32 sysErrCnt; INT32 pciErrCnt; INT32 memErrCnt; INT32 chkSum; }; static ssFun_LogUnitS *ssFun_Log; // point to NVSRAM static ssFun_LogHeadS ssFun_LogHead; // in RAM static void ssFunUpdateLogHead(void) { INT32 csum=0, i, *p; ssFun_LogHead.chkSum = 0; csum=0; p=(INT32 *)&ssFun_LogHead; for(i=0; issBYTE_LogHeadMaxSize) { printk(KERN_ERR "SS LOG HEAD SIZE > %d !!!\n", ssBYTE_LogHeadMaxSize); for(;;); } ssFun_Log=(ssFun_LogUnitS *)(gFpgaBar2VirtualP+SSFUN_LOG_START); memcpy ((void *)&ssFun_LogHead, gFpgaBar2VirtualP+SSFUN_LOG_HEAD, sizeof(ssFun_LogHeadS)); if (ssFun_LogHead.magicNum == SSFUN_MAGICNUM) { csum=0; p=(INT32 *)&ssFun_LogHead; for(i=0; i SSFUN_LOGUNITSIZE-9); // for [SYS] and '\0' argBuf[SSFUN_LOGUNITSIZE-9]='\0'; strcat (buf, argBuf); ssFunLog(buf); ssFun_LogHead.sysErrCnt++; ssFunUpdateLogHead(); } void ssFunPCIErrLog(char *argBuf) { char buf[SSFUN_LOGUNITSIZE]; strcpy (buf, "[PCILOG]"); if(strlen(argBuf) > SSFUN_LOGUNITSIZE-9); // for [PCI] and '\0' argBuf[SSFUN_LOGUNITSIZE-9]='\0'; strcat (buf, argBuf); ssFunLog(buf); ssFun_LogHead.pciErrCnt++; ssFunUpdateLogHead(); } void ssFunMemErrLog(char *argBuf) { char buf[SSFUN_LOGUNITSIZE]; strcpy (buf, "[MEMLOG]"); if(strlen(argBuf) > SSFUN_LOGUNITSIZE-9); // for [MEM] and '\0' argBuf[SSFUN_LOGUNITSIZE-9]='\0'; strcat (buf, argBuf); ssFunLog(buf); ssFun_LogHead.memErrCnt++; ssFunUpdateLogHead(); } void ssNvsramClear(int clearLvl) { // int clearLvl; // INT8 *nvram; // printk("%s(%s) is running\n", __FUNCTION__, argBuf); if (gFpgaBar2VirtualP == NULL) { printk(KERN_EMERG "FAILED\n"); return; } // Level 1 clear - To clear all error log area memset(gFpgaBar2VirtualP+SSFUN_LOG_HEAD, 0, SSFUN_LOG_AREA_SIZE); ssFun_LogHead.magicNum =0; ssFun_LogHeadCheck(); // clearLvl=simple_strtoul(argBuf, NULL, 10); if(clearLvl == 2) { // Level 2 clear - To clear all nvram memset(gFpgaBar2VirtualP, 0, SSFUN_LOG_HEAD); } return; } void ssErrorLogClear(void) { // INT8 *nvram; // printk("%s(%s) is running\n", __FUNCTION__, argBuf); // Level 1 clear - To clear all error log area memset(gFpgaBar2VirtualP+SSFUN_LOG_HEAD, 0, SSFUN_LOG_AREA_SIZE); ssFun_LogHead.magicNum =0; ssFun_LogHeadCheck(); return; } /* ssLogHead start #define proc_ssLogHead_S struct proc_ssLogHead_Structure proc_ssLogHead_S{ int flags; }; static proc_ssLogHead_S ssLogHead; */ static void *ssLogHead_start(struct seq_file *m, loff_t *pos) { if (*pos == 0) return &ssFun_LogHead; *pos=0; return NULL; } static void *ssLogHead_next(struct seq_file *m, void *v, loff_t *pos) { (*pos)++; return (ssLogHead_start(m,pos)); } static void ssLogHead_stop(struct seq_file *m, void *v) { } static int ssLogHead_show(struct seq_file *m, void *v) { seq_printf(m, "System Log Head\n"); seq_printf(m, "------------------------------\n"); seq_printf(m, "Magic Number:0x%08x\n", ssFun_LogHead.magicNum); seq_printf(m, "Flags :0x%08x\n", ssFun_LogHead.flags); // printk(m, "array :0x%p\n", ssFun_LogHead.array); seq_printf(m, "start :%5d\n", ssFun_LogHead.start); seq_printf(m, "count :%5d\n", ssFun_LogHead.count); seq_printf(m, "total :%5d\n", SSFUN_LOG_TOTAL); seq_printf(m, "sysErrCnt :%5d\n", ssFun_LogHead.sysErrCnt); seq_printf(m, "pciErrCnt :%5d\n", ssFun_LogHead.pciErrCnt); seq_printf(m, "memErrCnt :%5d\n", ssFun_LogHead.pciErrCnt); return 0; } const struct seq_operations ssLogHead_op = { .start = ssLogHead_start, .next = ssLogHead_next, .stop = ssLogHead_stop, .show = ssLogHead_show }; static int ssLogHead_open(struct inode *inode, struct file *file) { return seq_open(file, &ssLogHead_op); } static const struct file_operations proc_ssLogHead_operations = { .open = ssLogHead_open, .release = ssFun_SeqRelease, .read = seq_read }; static int ssLogHead_ProcInit(void) { struct proc_dir_entry *entry; entry = proc_create("ssLogHead", 0444, NULL, &proc_ssLogHead_operations); if (!entry) return -ENOMEM; return 0; } /*ssLogHead end*/ /* ssSysInfo start */ #define proc_ssSysInfo_S struct proc_ssSysInfo_Structure proc_ssSysInfo_S{ int flags; }; static proc_ssSysInfo_S ssSysInfo; static void *ssSysInfo_start(struct seq_file *m, loff_t *pos) { if (*pos == 0) return &ssSysInfo; *pos=0; return NULL; } static void *ssSysInfo_next(struct seq_file *m, void *v, loff_t *pos) { (*pos)++; return (ssSysInfo_start(m,pos)); } static void ssSysInfo_stop(struct seq_file *m, void *v) { } extern int number_of_disks; static int ssSysInfo_show(struct seq_file *m, void *v) { unsigned char SLR; int reg, hdd, i; for (reg=0, hdd=1; reg<3; reg++){ SLR = fpgaRegisterRead(FPGA_DRIVE_INPLACE_0+reg); for(i=0; i<8; i++, hdd++){ if(hdd >= number_of_disks) break; seq_printf(m, "HDD%d=%s\n", hdd, ( SLR & BIT(i) )?"INSTALLED":"ABSENT"); } } SLR = fpgaRegisterRead(FPGA_SUBSYSTEM_STATUS_LINES_1); //0x64 seq_printf(m, "DCPower=%s\n", ( SLR & BIT(0) )?"FAILED":"OK"); seq_printf(m, "ACPower=%s\n", ( SLR & BIT(1) )?"GOOD":"FAILED"); SLR = fpgaRegisterRead(FPGA_SUBSYSTEM_STATUS_LINES_2); //0x65 seq_printf(m, "PSU0Status=%s\n", ( SLR & BIT(0) )?"FAILED":"OK"); seq_printf(m, "PSU1Status=%s\n", ( SLR & BIT(1) )?"FAILED":"OK"); seq_printf(m, "CPUTempStatus=%s\n", ( SLR & BIT(2) )?"OVERHEAT":"OK"); seq_printf(m, "BoardTempStatus=%s\n", ( SLR & BIT(3) )?"OVERHEAT":"OK"); seq_printf(m, "PSU0TempStatus=%s\n", ( SLR & BIT(6) )?"OVERHEAT":"OK"); seq_printf(m, "PSU1TempStatus=%s\n", ( SLR & BIT(7) )?"OVERHEAT":"OK"); SLR = fpgaRegisterRead(FPGA_SUBSYSTEM_STATUS_LINES_3); //0x66 seq_printf(m, "PSU0Present=%s\n", ( SLR & BIT(0) )?"INSTALLED":"ABSENT"); seq_printf(m, "PSU1Present=%s\n", ( SLR & BIT(1) )?"INSTALLED":"ABSENT"); seq_printf(m, "BBUCRUPresent=%s\n", ( SLR & BIT(2) )?"INSTALLED":"ABSENT"); seq_printf(m, "AltCtlrPresent=%s\n", ( SLR & BIT(3) )?"INSTALLED":"ABSENT"); return 0; } const struct seq_operations ssSysInfo_op = { .start = ssSysInfo_start, .next = ssSysInfo_next, .stop = ssSysInfo_stop, .show = ssSysInfo_show }; static int ssSysInfo_open(struct inode *inode, struct file *file) { return seq_open(file, &ssSysInfo_op); } static const struct file_operations proc_ssSysInfo_operations = { .open = ssSysInfo_open, .release = ssFun_SeqRelease, .read = seq_read }; static int ssSysInfo_ProcInit(void) { struct proc_dir_entry *entry; entry = proc_create("ssSysInfo", 0444, NULL, &proc_ssSysInfo_operations); if (!entry) return -ENOMEM; return 0; } /*ssSysInfo end*/ /* ssSysConfig start */ #define proc_ssSysConfig_S struct proc_ssSysConfig_Structure proc_ssSysConfig_S{ int flags; }; static proc_ssSysConfig_S ssSysConfig; static void *ssSysConfig_start(struct seq_file *m, loff_t *pos) { if (*pos == 0) return &ssSysConfig; *pos=0; return NULL; } static void *ssSysConfig_next(struct seq_file *m, void *v, loff_t *pos) { (*pos)++; return (ssSysConfig_start(m,pos)); } static void ssSysConfig_stop(struct seq_file *m, void *v) { } //extern uint32_t ssNTBCPU_TestErrCnt; //extern uint32_t ssNTBDMA_TestErrCnt; //extern uint32_t ssDMA_TestErrCnt; static int ssSysConfig_show(struct seq_file *m, void *v) { unsigned char SLR; seq_printf(m, "sysDualCtrl=%d\n", sysDualCtrl); seq_printf(m, "sysCtrlRole=%d\n", sysCtrlRole); seq_printf(m, "sysHostCardType=%d\n", sysHostCardType); seq_printf(m, "sysEnclosureID=%d\n", ss_EnclosureID); seq_printf(m, "sysNumOfDisks=%d\n", number_of_disks); // seq_printf(m, "ntbCPUtestErrCnt=%d\n", ssNTBCPU_TestErrCnt); // seq_printf(m, "ntbDMAtestErrCnt=%d\n", ssNTBDMA_TestErrCnt); // seq_printf(m, "dmaTestErrCnt=%d\n", ssDMA_TestErrCnt); SLR = fpgaRegisterRead(FPGA_SUBSYSTEM_STATUS_LINES_3); //0x65 seq_printf(m, "AltCtlrPresent=%s\n", ( SLR & BIT(3) )?"INSTALLED":"ABSENT"); //printk("%s: Yes, I'm here!!!, count=%ld, size=%ld\n", __FUNCTION__, m->count, m->size); return 0; } const struct seq_operations ssSysConfig_op = { .start = ssSysConfig_start, .next = ssSysConfig_next, .stop = ssSysConfig_stop, .show = ssSysConfig_show }; static int ssSysConfig_open(struct inode *inode, struct file *file) { return seq_open(file, &ssSysConfig_op); } static const struct file_operations proc_ssSysConfig_operations = { .open = ssSysConfig_open, .release = ssFun_SeqRelease, .read = seq_read, }; static int ssSysConfig_ProcInit(void) { struct proc_dir_entry *entry; entry = proc_create("ssSysConfig", 0444, NULL, &proc_ssSysConfig_operations); if (!entry) return -ENOMEM; return 0; } /*ssSysConfig end*/ UINT32 fpgaDriveInPlace(VOID) { //Read register UINT32 driveInpl0 = fpgaRegisterRead(FPGA_DRIVE_INPLACE_0); UINT32 driveInpl1 = fpgaRegisterRead(FPGA_DRIVE_INPLACE_1); UINT32 driveInpl2 = fpgaRegisterRead(FPGA_DRIVE_INPLACE_2); //Set the highest byte as 0xff return (0xFF000000 | (driveInpl2 << 16) | (driveInpl1 << 8) | driveInpl0); } uint32_t ssAllDrvInPlace; uint8_t ssDrv2BitLoc_24A[]= { 0, 1, 2, 3, 4, 5, 6, 7, 13,12,11,10,16, 8, 9,15, 17,14,18,22,23,21,20,19}; uint8_t ssDrv2BitLoc_24B[]= { 5, 4, 3, 0, 1, 2, 6, 7, 8,11,10, 9,12,13,14,15, 16,17,18,19,20,21,23,22}; uint8_t ssDrv2BitLoc_12A[]= { 0, 1, 6,11, 3, 4, 7,10, 4, 5, 8, 9}; uint8_t ssDrv2BitLoc_12B[]= { 5, 9,10,11, 1, 6, 7, 8, 0, 2, 3, 4}; #if defined(CHASSIS_WSAS) // dummy bit map for compatibility uint8_t ssDrv2BitLoc_60[]= {0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0}; #endif uint8_t *ssDrv2BitLoc; void ssDrvInPlaceInit(void) { uint8_t id=fpgaRegisterRead(FPGA_BOARD_ID); if( ss_EnclosureID == 0x0F ) { printk( "%s: Test Midplane in use, no drives in place\n", __func__ ); return; } #define isCtrlA() (id == 0x14) #define isCtrlB() (id == 0x94) #define is24Bay() (ss_EnclosureID==2) #define is12Bay() (ss_EnclosureID==4) #if defined(CHASSIS_WSAS) #define is60Bay() ((ss_EnclosureID==9) || (ss_EnclosureID == 1)) #endif ssAllDrvInPlace = fpgaDriveInPlace(); if( is24Bay() && isCtrlA()) ssDrv2BitLoc=ssDrv2BitLoc_24A; else if( is24Bay() && isCtrlB()) ssDrv2BitLoc=ssDrv2BitLoc_24B; else if( is12Bay() && isCtrlA()) ssDrv2BitLoc=ssDrv2BitLoc_12A; else if( is12Bay() && isCtrlB()) ssDrv2BitLoc=ssDrv2BitLoc_12B; #if defined(CHASSIS_WSAS) else if((is60Bay() && isCtrlA()) || (is60Bay() && isCtrlB())){ ssDrv2BitLoc=ssDrv2BitLoc_60; printk("%s: Enclosure wemblySAS, ssDrvInPlace is invalidated\n",__FUNCTION__); } #endif else printk("%s: Controller(0x%x) or Enclosure(0x%x) error!!!\n", __FUNCTION__, id, ss_EnclosureID); } int ssDrvInPlace; void ssIsDrvInPlace(uint32_t drv) { uint32_t loc=(uint32_t)ssDrv2BitLoc[drv]; ssAllDrvInPlace = fpgaDriveInPlace(); // printk("%s: AllDrvInPlace=0x%x, BitLocal=%d, %s\n", __FUNCTION__, ssAllDrvInPlace, loc, (ssAllDrvInPlace&BIT(loc))? "YES":"NO"); ssDrvInPlace=(ssAllDrvInPlace & BIT(loc))? 1:0; } //extern void fpgaI2cMdpl1Select(void); //extern void fpgaI2cMdpl2Select(void); uint32_t ssAllDrvPowerState, ssDrvBitmap; int ssDrvPower; void ssIsDrvPowerON(uint32_t drv) { ssDrvPower=(ssAllDrvPowerState & BIT(drv))? 1:0; } // // Drive Power Op // void ssDrvPowerOp(uint32_t drv, uint32_t onOff) { struct i2c_adapter *adap; uint32_t i, idx=drv/8; uint16_t addr= 0x40+idx*2; uint8_t bitMap=BIT(drv%8); uint8_t *data = (uint8_t *)&ssAllDrvPowerState; uint32_t array[2][2]={{5, 12},{12,5}}; for(i=0; i<2; i++){ if(array[onOff][i]==5){ // For 5V adap = zebulonAdapter[ZEBULON_I2C_BUS_2]; //fpgaI2cMdpl2Select(); } else /* if(array[onOff][i]==12) */{ // For 12V adap = zebulonAdapter[ZEBULON_I2C_BUS_1]; //fpgaI2cMdpl1Select(); } mdelay(10); i2cSMbusReadByte (adap, (addr >> 1), 1, &data[idx]); mdelay(10); if(onOff == 1) // ON data[idx] |= bitMap; else // OFF data[idx] &= ~bitMap; i2cSMbusWriteByte(adap, (addr >> 1), 1, data[idx]); // printk("%s(%dv): drv=%d, data=0x%x\n", __FUNCTION__, array[onOff][i], drv, data[idx]); } } void ssAllDrvPowerOp(uint32_t onOff) { struct i2c_adapter *adap; uint16_t addr; int i, idx, Nidx=((ss_EnclosureID==2)?3:2); uint8_t data; // = (onOff == 1)?0xFF:0; uint32_t array[2][2]={{5, 12},{12,5}}; uint8_t *onBitmap=(uint8_t *) &ssDrvBitmap; for(i=0; i<2; i++){ if(array[onOff][i]==5){ // For 5V adap = zebulonAdapter[ZEBULON_I2C_BUS_2]; //fpgaI2cMdpl2Select(); } else /*if(array[onOff][i]==12)*/{ // For 12V adap = zebulonAdapter[ZEBULON_I2C_BUS_1]; //fpgaI2cMdpl1Select(); } // mdelay(10); for (idx=0; idx> 1), 1, data); } } ssAllDrvPowerState=(onOff == 1)?ssDrvBitmap:0; } // void ssDrvPowerOpInit(void) { struct i2c_adapter *adap; uint16_t addr; int idx, Nidx=((ss_EnclosureID==2)?3:2); if( ss_EnclosureID == 0x0F ) { printk( "%s: Test Midplane in use, no drives power\n", __func__ ); return; } ssDrvBitmap=(ss_EnclosureID==2)?0xFFFFFF:0xFFF; // for 12V adap = zebulonAdapter[ZEBULON_I2C_BUS_1]; //fpgaI2cMdpl1Select(); mdelay(10); for (idx=0; idx> 1), 3, 0); // Set up configure of OUTPUT mdelay(20); } // for 5V adap = zebulonAdapter[ZEBULON_I2C_BUS_2]; //fpgaI2cMdpl2Select(); mdelay(10); for (idx=0; idx> 1), 3, 0); // Set up configure of OUTPUT mdelay(20); } ssAllDrvPowerOp(1); // Turn on all drives } int ssFunRTCBatteryExist=0; void ssFun_RdRTCBatterySts(void) { uint16_t regData; struct pci_dev* pdev = NULL; pdev = pci_get_device(INTEL_VENDOR_ID, INTEL_PATSBURG_LPC_DEVICE_ID, NULL); if(pdev != NULL) { pci_read_config_word(pdev, PCH_PCIE_PORT_PMCS_OFFSET, ®Data); // printk("[%s] regData:0x%04x\n", __FUNCTION__, regData); ssFunRTCBatteryExist=0x80|((regData & BIT(2))?0:1); } } int ssFun_ReadFile( char *fn, char *buf, int len) { struct file *ofp = NULL; mm_segment_t old; // size_t len=strlen(buf); int rr; old = get_fs(); set_fs(KERNEL_DS); ofp = filp_open(fn, O_RDONLY, 0); if(IS_ERR(ofp)) { // printk("FAILED - FAILED TO OPEN FILE\n"); return 1; } memset(buf, 0, len); rr = ofp->f_op->read(ofp, buf, len, &ofp->f_pos); if(rr < 0) { // printk("FAILED - FILE READ OP ERROR\n"); filp_close(ofp, NULL); set_fs(old); return 1; } filp_close(ofp, NULL); set_fs(old); return 0; } int ssFun_WriteFile( char *fn, char *buf) { struct file *ofp = NULL; mm_segment_t old; size_t len=strlen(buf); int rr; old = get_fs(); set_fs(KERNEL_DS); ofp = filp_open(fn, O_RDWR | O_CREAT | O_APPEND, S_IRUSR); if(IS_ERR(ofp)){ // printk("FAILED - FAILED TO OPEN FILE\n"); return 1; } rr = ofp->f_op->write(ofp, buf, len, &ofp->f_pos); if(rr < 0) { // printk("FAILED - FILE WRITE OP ERROR\n"); filp_close(ofp, NULL); set_fs(old); return 1; } filp_close(ofp, NULL); set_fs(old); return 0; } #define ssLED_S struct ssLED_Structure ssLED_S { struct task_struct *task; char ledState[4]; int ms; }; ssLED_S ssLED; extern void scsih_ShowExpLED(int mode); /* Loc=1: Exp Active LED, Loc=2: Exp Fault LED * op=0: ON, op=1:OFF */ void ssLEDOp(int loc, int state, int ms) { ssLED.ledState[loc] = state; if(ms) ssLED.ms=ms; } EXPORT_SYMBOL(ssLEDOp); int ssLEDTaskRun(void *ltr) { ssLED_S *pd=(ssLED_S *)ltr; while (! kthread_should_stop()) { if(pd->ledState[1]) scsih_ShowExpLED(1); if(pd->ledState[2]) scsih_ShowExpLED(2); msleep(pd->ms); } return 0; } int ssLEDStart(void) { if(ssLED.task != NULL) return 0; ssLED.task = kthread_run(ssLEDTaskRun, &ssLED, "ssLEDTask"); if (IS_ERR(ssLED.task)) { printk("Create ssFun LED Task Failed!!!\n"); /* TODO */ return (-EFAULT); } return (0); } EXPORT_SYMBOL(ssLEDStart); void ssLEDStop(void) { int ret; if(ssLED.task != NULL) { ret = kthread_stop(ssLED.task); ssLED.task=NULL; } } void ssLEDInit(void) { ssLED.ledState[1]=0; ssLED.ledState[2]=0; ssLED.ms=5; ssLED.task = NULL; } extern void _scsih_init(void); void scsih_init(void) { _scsih_init(); } //extern void psfan_SpeedSet(uint32_t location, uint32_t speed); extern void sasInitMapping(void); //extern void ibLED_Init(void); static int __init ssFun_Init(void) { // psfan_SpeedSet((uint32_t)-1, 3600); ssGetEnclosureID(); ssFun_LogHead.magicNum =0; ssFun_LogHeadCheck(); ssSysConfig_ProcInit(); //mapiResult_ProcInit(); ssSysInfo_ProcInit(); ssLogHead_ProcInit(); ssLogData_ProcInit(); ssDrvInPlaceInit(); //ssDrvPowerOpInit(); sasInitMapping(); ssLEDInit(); //ibLED_Init(); return 0; } static void __exit ssFun_Exit(void) { } module_init( ssFun_Init ); module_exit( ssFun_Exit ); MODULE_AUTHOR( "merck.hung@netapp.com" ); MODULE_DESCRIPTION( "SSFUN Code" ); MODULE_LICENSE( "GPL" );