/******************************************************************************* NAME $RCSfile: commIpcEthernet.c,v $ SUMMARY IPC APIs for inter-controller communication VERSION $Revision: 1.12 $ UPDATE DATE $Date: 2010/01/28 08:10:49 $ PROGRAMMER $Author: jim $ Copyright 2009 LSI Corporation. All Rights Reserved. DESCRIPTION: REFERENCE: *******************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "commIpcEthernet.h" /* EXTERN FUNCIONS*/ extern int ipcEthernetSend(EIPC_MSG *msg); extern void ipcEthernetDeregister(int app); extern void ipcEthernetRegister(int app, EIPC_NOTIFY notifyFunc); //extern int plxIpcInit(void); //extern void plxIpcExit(void); //extern int sensorGetTemperature(uint16_t *pcb, uint16_t *cpu); extern void fpgaPwrAltColdReboot(void); #if 0 extern bool qe8GetDynamoRunningStatus(void); extern void qe8GetLocalNum(uint32_t *); #endif extern void scsih_init_ioc(void); extern void scsih_init_ioc_fixture(void); //DVT3 extern void scsih_init_ioc_uut_target(void); //PVT extern int sasdiag_changeFirmware(u8 configId, u8 ioc_num, u8 fwIdx); extern void peerUUTSasIocInitReady(void); //PVT extern unsigned int g_fixture_sas_ready; extern unsigned int gHwValidationFlag; /* peer controller ip address */ static uint32_t eIpcServIP = 0; pid_t g_iotestd_pid = 0; /* user space pid of iotestd */ #define EIPC_NUM_TX 256 #define EIPC_NUM_RX 512 extern EIPC_CB eIpcCb; /* EIPC notify callback function */ extern EIPC_NOTIFY ipcEthernetNotifyFunc[IPC_APP_MAX]; int i2cEEpromRead(struct i2c_adapter *adap, uint16_t i2c_addr, uint16_t offset, uint8_t *buf, int count){ uint8_t __offset[2]; struct i2c_msg msg[2]; int ret; __offset[0] = (uint8_t) (offset >> 8); //MSB of word address __offset[1] = (uint8_t) (offset & 0xFF); //LSB of word address /* dummy write */ msg[0].addr = i2c_addr; msg[0].flags = 0; msg[0].len = 2; msg[0].buf = __offset; /* read op */ msg[1].addr = i2c_addr; msg[1].flags = 1; msg[1].len = (count + 2); msg[1].buf = buf; if ((ret = i2c_transfer(adap, msg, 2)) != 2) return (ret); return (0); } VOID ioTestStart(VOID) { #if 0 if (g_iotestd_pid) kill_proc(g_iotestd_pid, SIG_IO_TEST_START, 1); #endif if (g_iotestd_pid) { int result = 0; struct pid *pid = NULL; pid = find_get_pid(g_iotestd_pid); result = kill_pid(pid, SIG_IO_TEST_START, 1); if (result) { printk("[%s] Kill the signal 'SIG_IO_TEST_START' failed\n", __func__); } } } VOID ioTestStop(VOID) { #if 0 if (g_iotestd_pid) kill_proc(g_iotestd_pid, SIG_IO_TEST_STOP, 1); #endif if (g_iotestd_pid) { int result = 0; struct pid *pid = NULL; pid = find_get_pid(g_iotestd_pid); result = kill_pid(pid, SIG_IO_TEST_STOP, 1); if (result) { printk("[%s] Kill the signal 'SIG_IO_TEST_STOP' failed\n", __func__); } } } INT32 ioTestPeerStart(VOID) { EIPC_MSG msg; msg.hdr.app = IPC_APP_IO_TEST_RUN; msg.hdr.flag = IPC_APP_REQUEST; msg.hdr.len = 0; return (ipcEthernetSend(&msg)); } INT32 ioTestPeerStop(VOID) { EIPC_MSG msg; msg.hdr.app = IPC_APP_IO_TEST_STOP; msg.hdr.flag = IPC_APP_REQUEST; msg.hdr.len = 0; return (ipcEthernetSend(&msg)); } INT32 gCpuStressStopFlag; INT32 cpuStress(UINT32 delay) { UINT64 i, j; UINT64 pattern = 0x1010101010101010; gCpuStressStopFlag = 0; j = 0; for(i = 0; i < 0xFFFFFFFFFFFFFFFF; i++) { if(gCpuStressStopFlag == 1) { return 0; } if(i == 0xFFFFFFFFFFFFFFFD) { i = 0; j = 0; } pattern = ~pattern; if(gCpuStressStopFlag == 1) { return 0; } j++; if((j/delay) == 0) { msleep(1); } } return 0; } VOID cpuStressStop(VOID) { gCpuStressStopFlag = 1; } // ############################### /* * IP address of peer controller * 10.0.0.1, 11.0.0.1, 12,0.0.1 */ UINT32 nicRemoteHostIP[PIKES_PEAK_NIC_PORTS] = { 0x0a000001, 0x0b000001, 0x0c000001}; EXPORT_SYMBOL(nicRemoteHostIP); VOID setPeerHostIP(INT32 port, UINT32 ip) { if (port < 0 || port >= PIKES_PEAK_NIC_PORTS) { printk("Invalid ethernet port index(%d)\n", port); return; } nicRemoteHostIP[port] = ip; } VOID sysFixtureReadyRequest(VOID) { IPC_MSG msg; ipcEthernetRegister(IPC_APP_ALT_CTRL_READY_REQ, NULL); /* send request */ msg.hdr.app = IPC_APP_ALT_CTRL_READY_REQ; msg.hdr.flag = IPC_APP_REQUEST; msg.hdr.len = 0; ipcEthernetSend((EIPC_MSG*) &msg); ipcEthernetDeregister(IPC_APP_ALT_CTRL_READY_REQ); //printk("\n"); //printk("== Fixture Ready Check Request Send!! (through IPC Protocol) == \n"); //printk("\n"); } VOID sysFixtureReadyReply(VOID) { IPC_MSG msg; ipcEthernetRegister(IPC_APP_ALT_CTRL_READY_REPLY, NULL); /* send request */ msg.hdr.app = IPC_APP_ALT_CTRL_READY_REPLY; msg.hdr.flag = IPC_APP_REQUEST; msg.hdr.len = 0; ipcEthernetSend((EIPC_MSG*) &msg); ipcEthernetDeregister(IPC_APP_ALT_CTRL_READY_REPLY); //printk("\n"); //printk("== Fixture Ready Check Reply Send!! (through IPC Protocol) == \n"); //printk("\n"); } VOID sysHwValidation(VOID) { IPC_MSG msg; ipcEthernetRegister(IPC_APP_HW_VALIDATION, NULL); /* send request */ msg.hdr.app = IPC_APP_HW_VALIDATION; msg.hdr.flag = IPC_APP_REQUEST; msg.hdr.len = 0; ipcEthernetSend((EIPC_MSG*) &msg); ipcEthernetDeregister(IPC_APP_HW_VALIDATION); printk("\n"); printk("== HW Validation Flag Send!! (through IPC Protocol) == \n"); printk("\n"); } // ############################### static ssize_t ipcEthernetProcWrite(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) { EIPC_MSG *msg = NULL; DPRINTK("%s(%d) count(%d)\n", __func__, __LINE__, count); if (count > EIPC_MSG_LEN) return (-EINVAL); spin_lock(&eIpcCb.rxLock); if (!list_empty(&eIpcCb.freeRxQueue)) { msg = list_entry(eIpcCb.freeRxQueue.next, EIPC_MSG, list); list_del(&msg->list); } else { printk("[EIPC] out of free Rx resource\n"); spin_unlock(&eIpcCb.rxLock); return (-ENOMEM); } if (copy_from_user(msg, buffer, count)) { /* put back to free queue */ list_add_tail(&msg->list, &eIpcCb.freeRxQueue); spin_unlock(&eIpcCb.rxLock); return (-EFAULT); } /* put in working rx queue */ DPRINTK("%s(%d) put(%p) in rx queue\n", __func__, __LINE__, msg); list_add_tail(&msg->list, &eIpcCb.rxQueue); wake_up_process(eIpcCb.eTask); spin_unlock(&eIpcCb.rxLock); return (count); } static struct file_operations eIpcProcFops = { .write = ipcEthernetProcWrite, }; static int ipcEthernetPacketSend(struct socket *sock, uint8_t *buf, int len) { struct msghdr msg; struct iovec iov; mm_segment_t oldfs; int size = 0; if (sock->sk == NULL) return 0; iov.iov_base = buf; iov.iov_len = len; msg.msg_flags = 0; msg.msg_iov = &iov; msg.msg_iovlen = 1; oldfs = get_fs(); set_fs(KERNEL_DS); size = sock_sendmsg(sock, &msg, len); set_fs(oldfs); return (size); } static int ipcEthernetInitClient(void) { struct socket *sock; struct sockaddr_in des; int ret; ret = sock_create(PF_INET, SOCK_STREAM, IPPROTO_TCP, &sock); if (ret < 0) { printk("[EIPC] unable to create socket(%d)\n", ret); return (ret); } memset(&des, 0, sizeof(des)); des.sin_family = AF_INET; des.sin_port = htons(EIPC_DEFAULT_PORT); des.sin_addr.s_addr = htonl(eIpcServIP); /* Connect to server */ ret = sock->ops->connect(sock, (struct sockaddr*) &des, sizeof(des), 0); if (ret == -EINPROGRESS) ret = 0; if (ret < 0) { printk(KERN_DEBUG"[EIPC] connect failed(%d), IP(%x)\n", ret, eIpcServIP); goto release; } eIpcCb.txSocket = sock; return (0); release: sock_release(sock); return (ret); } static void ipcEthernetSendMsg(void) { EIPC_MSG *msg; int ret; if (!eIpcCb.txSocket) { ret = ipcEthernetInitClient(); if (ret) return; } spin_lock(&eIpcCb.txLock); while (!list_empty(&eIpcCb.txQueue)) { /* get from working queue */ msg = list_entry(eIpcCb.txQueue.next, EIPC_MSG, list); list_del(&msg->list); ret = ipcEthernetPacketSend(eIpcCb.txSocket, (uint8_t*) msg, IPC_HEADER_SIZE + msg->hdr.len); DPRINTK("%s(%d) send msg(%d) @%p\n", __func__, __LINE__, ret, msg); if (ret < 0) { printk("[EIPC] send packet err(%d)\n", ret); /* TODO error handling ??? */ } else { /* put back to free queue */ list_add_tail(&msg->list, &eIpcCb.freeTxQueue); } } spin_unlock(&eIpcCb.txLock); } static void ipcEthernetNotify(EIPC_MSG *msg) { int app; if( !msg ) return; app = msg->hdr.app; switch ( app ) { case IPC_APP_ECHO: case IPC_APP_GET_TEMP: case IPC_APP_START_PLX_IPC: case IPC_APP_STOP_PLX_IPC: case IPC_APP_REQUEST_POWER_CYCLE: case IPC_APP_IO_TEST_RUN: case IPC_APP_IO_TEST_STOP: case IPC_APP_GET_DYNAMO_STAT: case IPC_APP_GET_QE8_CNT: case IPC_APP_FIXTURE_SAS_INIT: case IPC_APP_FIXTURE_SAS_READY: case IPC_APP_ALT_CTRL_READY_REQ: case IPC_APP_ALT_CTRL_READY_REPLY: case IPC_APP_FIXTURE_FALCON_PHY_DISABLE_INIT: case IPC_APP_FIXTURE_FALCON_PHY_DISABLE_READY: case IPC_APP_FIXTURE_SAS_INIT_FORCE: //DVT3 case IPC_APP_UUT_SAS_INIT: //PVT case IPC_APP_UUT_SAS_READY: //PVT #include "IPCforStress_S.inc" case IPC_APP_HW_VALIDATION: if (ipcEthernetNotifyFunc[app]) ipcEthernetNotifyFunc[app](msg); else printk("[EIPC] unregistered notify, app(%d)\n", app); break; default: printk("[EIPC] notify unknown app(%d)\n", app); break; } } static void ipcEthernetProcessReq(EIPC_MSG *msg) { DPRINTK("%s(%d) app(%d)\n", __func__, __LINE__, msg->hdr.app); if( !msg ) return; switch(msg->hdr.app) { case IPC_APP_ECHO: msg->hdr.flag = IPC_APP_RESPONSE; ipcEthernetSend(msg); break; case IPC_APP_GET_TEMP: { #if 0 int cookie; uint16_t pcb, cpu; cookie = sensorGetTemperature(&pcb, &cpu); msg->hdr.flag = IPC_APP_RESPONSE; msg->hdr.cookie = (unsigned char) cookie; msg->hdr.len = 2*sizeof(uint16_t); memcpy(&msg->body[0], &pcb, sizeof(uint16_t)); memcpy(&msg->body[sizeof(uint16_t)], &cpu, sizeof(uint16_t)); ipcEthernetSend(msg); #endif } break; #if 0 case IPC_APP_START_PLX_IPC: { int cookie; cookie = plxIpcInit(); msg->hdr.flag = IPC_APP_RESPONSE; msg->hdr.cookie = (unsigned char) cookie; ipcEthernetSend(msg); break; } case IPC_APP_STOP_PLX_IPC: plxIpcExit(); msg->hdr.flag = IPC_APP_RESPONSE; ipcEthernetSend(msg); break; #endif case IPC_APP_REQUEST_POWER_CYCLE: fpgaPwrAltColdReboot(); break; case IPC_APP_IO_TEST_RUN: ioTestStart(); break; case IPC_APP_IO_TEST_STOP: ioTestStop(); break; case IPC_APP_GET_DYNAMO_STAT: { bool dynamo_running_bool; //dynamo_running_bool = qe8GetDynamoRunningStatus(); dynamo_running_bool = 0; memcpy(&msg->body[0], &dynamo_running_bool, sizeof(bool)); /* Send a IPC response */ msg->hdr.flag = IPC_APP_RESPONSE; ipcEthernetSend(msg); break; } #if 0 case IPC_APP_GET_QE8_CNT: { uint32_t local_qe8_phys; qe8GetLocalNum(&local_qe8_phys); memcpy(&msg->body[0], &local_qe8_phys, sizeof(UINT32)); /* Send a IPC response */ msg->hdr.flag = IPC_APP_RESPONSE; ipcEthernetSend(msg); break; } #endif case IPC_APP_FIXTURE_SAS_INIT: { printk("\n"); printk("\n"); printk("== Fixture SAS IOC Initialization Request Received!! (through IPC Protocol) == \n"); printk("\n"); scsih_init_ioc(); printk("Change Ctrl SAS Port Config to UUT narrow (0x%02x)\n", msg->body[0]); sasdiag_changeFirmware(msg->body[0], 0, 0); break; } case IPC_APP_FIXTURE_SAS_READY: { printk("\n"); printk("\n"); printk("== Fixture SAS IOC Initialization Ready Received!! (through IPC Protocol) == \n"); printk("\n"); g_fixture_sas_ready = 1; break; } case IPC_APP_ALT_CTRL_READY_REQ: { //printk("\n"); //printk("\n"); //printk("== Fixture Ready Check Request Received!! (through IPC Protocol) == \n"); //printk("\n"); printk(KERN_DEBUG"[BOARD_INFO] Dual controllers\n"); sysDualCtrl = DUAL_CONTROLLER; sysFixtureReadyReply(); break; } case IPC_APP_ALT_CTRL_READY_REPLY: { //printk("\n"); //printk("\n"); //printk("== Fixture Ready Check Reply Received!! (through IPC Protocol) == \n"); //printk("\n"); //printk("[BOARD_INFO] Dual controllers\n"); sysDualCtrl = DUAL_CONTROLLER; break; } case IPC_APP_HW_VALIDATION: { gHwValidationFlag = 1; printk("\n"); printk("== HW Validation Flag Received!! (through IPC Protocol) == \n"); printk("\n"); break; } case IPC_APP_FIXTURE_SAS_INIT_FORCE: //DVT3 { printk("\n"); printk("\n"); printk("== Start to initial SAS on Fixture to Initiator Mode== \n"); printk("\n"); scsih_init_ioc_fixture(); break; } case IPC_APP_UUT_SAS_INIT: //PVT { printk("\n"); printk("\n"); printk("== Start to initial SAS on UUT to Target Mode== \n"); printk("\n"); scsih_init_ioc_uut_target(); break; } case IPC_APP_UUT_SAS_READY: //PVT { printk("\n"); printk("\n"); printk("== UUT SAS IOC Initialization Ready Received!! (through IPC Protocol) == \n"); printk("\n"); g_fixture_sas_ready = 1; break; } #include "IPCforStress.inc" #include "IPCforStress-sas.inc" default: printk("[EIPC] unknown app(%d)\n", msg->hdr.app); } } static void ipcEthernetReceiveMsg(void) { EIPC_MSG *msg; spin_lock(&eIpcCb.rxLock); while (!list_empty(&eIpcCb.rxQueue)) { /* get working queue */ msg = list_entry(eIpcCb.rxQueue.next, EIPC_MSG, list); DPRINTK("%s(%d) receive msg @%p\n", __func__, __LINE__, msg); list_del(&msg->list); if (msg->hdr.flag == IPC_APP_REQUEST) { ipcEthernetProcessReq(msg); } else if (msg->hdr.flag == IPC_APP_RESPONSE) { ipcEthernetNotify(msg); } else { printk("[EIPC] receiving known message\n"); } /* put back to free queue */ list_add_tail(&msg->list, &eIpcCb.freeRxQueue); } spin_unlock(&eIpcCb.rxLock); } static int ipcEthernetTask(void *unused) { __set_current_state(TASK_RUNNING); do { ipcEthernetReceiveMsg(); ipcEthernetSendMsg(); /* go sleep */ __set_current_state(TASK_INTERRUPTIBLE); schedule(); __set_current_state(TASK_RUNNING); } while (!kthread_should_stop()); return (0); } static int ipcEthernetInitProc(void) { struct proc_dir_entry *entry; entry = create_proc_entry("eipc", 0644, NULL); if (!entry) return -ENOMEM; entry->proc_fops = &eIpcProcFops; return (0); } static int ipcEthernetInitQueue(void) { int i; INIT_LIST_HEAD(&eIpcCb.freeTxQueue); INIT_LIST_HEAD(&eIpcCb.freeRxQueue); INIT_LIST_HEAD(&eIpcCb.txQueue); INIT_LIST_HEAD(&eIpcCb.rxQueue); for (i = 0; i < EIPC_NUM_TX; i++) { EIPC_MSG *msg; msg = kmem_cache_zalloc(eIpcCb.eIpcCache, GFP_KERNEL); if (!msg) goto nomem; msg->hdr.type = IPC_TYPE_ETHERNET; list_add_tail(&msg->list, &eIpcCb.freeTxQueue); } for (i = 0; i < EIPC_NUM_RX; i++) { EIPC_MSG *msg; msg = kmem_cache_zalloc(eIpcCb.eIpcCache, GFP_KERNEL); if (!msg) goto nomem; msg->hdr.type = IPC_TYPE_ETHERNET; list_add_tail(&msg->list, &eIpcCb.freeRxQueue); } return (0); nomem: return (-ENOMEM); } static int ipcEthernetInitCb(void) { eIpcCb.txSocket = NULL; spin_lock_init(&eIpcCb.txLock); spin_lock_init(&eIpcCb.rxLock); eIpcCb.eIpcCache = kmem_cache_create("eIpc", sizeof(EIPC_MSG), 0, SLAB_HWCACHE_ALIGN, NULL); if (!eIpcCb.eIpcCache) return (-ENOMEM); return (ipcEthernetInitQueue()); } /******************************************************************************* * PROCEDURE * * NAME: ipcEthernetInit * SUMMARY: Init function for Inter-controller communication * * SCOPE: Public * * DESCRIPTION: * * RETURNS: * * NOTES: * input@ ip: peer controller IP address * for exsample: 10.0.0.1 -> 0x0a000001 */ void ipcEthernetInit(uint32_t ip) { int ret; if (!ip) return; eIpcServIP = ip; ret = ipcEthernetInitCb(); if (ret) { printk("EIPC init CB failed(%d)\n", ret); return; } /* create proc entry for receiving * request from user space */ ret = ipcEthernetInitProc(); if (ret) { printk("EIPC init proc entry failed(%d)\n", ret); return; } eIpcCb.eTask = kthread_run(ipcEthernetTask, NULL, "eipcTask"); } #ifndef ALANWANG // Alan Wang, 20100311 /*********************************************************** Name: sysRebootPeer Synopsis: Description: ask peer controller reboot Input Variables: Output Variables: Return Value: negative if failed Globals: ***********************************************************/ INT32 sysRebootPeer(VOID) { EIPC_MSG msg; msg.hdr.app = IPC_REBOOT_REQ; msg.hdr.flag = IPC_APP_REQUEST; msg.hdr.len = 0; return (ipcEthernetSend(&msg)); } #endif // ALANWANG MODULE_AUTHOR( "merck.hung@netapp.com" ); MODULE_DESCRIPTION( "Common IPC Interface Code" ); MODULE_LICENSE( "GPL" );