/* * Brief: Implement IPMB send and receive function in this file, include primary IPMB and secondary IPMB. * Author: Jimbo_Zhang@outlook.com * Date: 2019-9-9 */ /* Standard includes. */ #include #include #include #include #include #include #include #include "com_IPMI_LANIfc.h" #include "com_IPMI_RMCP.h" #include "RMCP.h" #include "LANIfc.h" #include "com_IPMIDefs.h" #include "RMCP.h" #include "MD.h" #include /* getaddrinfo(3) et al. */ #include /* sockaddr_in & sockaddr_in6 definition. */ #include #include #include "main.h" #include "Session.h" #include "com_IPMI_SDR.h" #include "com_IPMI_Storage.h" #include "SDR.h" //static int sendIPMBPkt(uint32_t ipmb_bus, uint8_t* i2c_send_buf, uint8_t size); static uint8_t ValidateIPMBChkSums ( uint8_t* Data, uint8_t Size); static void ProcessIPMBReq ( MsgPkt_T* pReq); uint8_t IsResponseMatch (MsgPkt_T* pReq, MsgPkt_T* pRes); static void* RecvIPMBPkt (void *pArg); int gFd_PrimaryIpmbIfcQ, gFd_PrimaryIpmbResQ; int gFd_SecondaryIpmbIfcQ, gFd_SecondaryIpmbResQ; int gFd_Primary, gFd_Secondary; /*! \brief IPMB Task. Generating primary_IPMB task and secondary_IPMB task in this task. \param: 0: primary ipmb, 1: secondary ipmb \retval none */ void *IPMBIfcTask(void *Param) { // int i; MsgPkt_T RcvMsgPkt; uint8_t dev_name[10] = {0}; uint8_t IPMB_IFC_Q[32] = {0}; uint8_t IPMB_RES_Q[32] = {0}; uint8_t OwnerAddr; int fd_IpmbDev; int fd_IpmbIfcQ, fd_IpmbResQ; uint8_t ipmbSelect = *(uint8_t*)Param; //printf("ipmbSelect: %d\n", ipmbSelect); //Primary IPMB if((ipmbSelect == 0) && g_BMCInfo.IpmiConfig.PrimaryIPMBSupport) { printf("Primary IPMBIfcTask start...\n"); strcpy(IPMB_IFC_Q, PRIMARY_IPMB_IFC_Q); strcpy(IPMB_RES_Q, PRIMARY_IPMB_RES_Q); sprintf(dev_name, "/dev/i2c%d", g_BMCInfo.IpmiConfig.PrimaryIPMBBus); OwnerAddr = g_BMCInfo.IpmiConfig.PrimaryIPMBAddr; } //Secondary IPMB else if((ipmbSelect == 1) && g_BMCInfo.IpmiConfig.SecondaryIPMBSupport) { printf("Secondary IPMBIfcTask start...\n"); strcpy(IPMB_IFC_Q, SECONDARY_IPMB_IFC_Q); strcpy(IPMB_RES_Q, SECONDARY_IPMB_RES_Q); sprintf(dev_name, "/dev/i2c%d", g_BMCInfo.IpmiConfig.SecondaryIPMBBus); OwnerAddr = g_BMCInfo.IpmiConfig.SecondaryIPMBAddr; } else { printf("Invalid param! %d\n", ipmbSelect); return (void *)-1; } //create IPMB_IFC_Q if(-1 != access(IPMB_IFC_Q, F_OK)) { remove(IPMB_IFC_Q); } if(0 != mkfifo (IPMB_IFC_Q, 0777)) { printf("%s: Create %s fifo failed! %s\n", __FUNCTION__, IPMB_IFC_Q, strerror(errno)); return (void*)-1; } fd_IpmbIfcQ = open (IPMB_IFC_Q, O_RDWR); if(-1 == fd_IpmbIfcQ) { printf("%s: Open %s fifo failed! %s\n", __FUNCTION__, IPMB_IFC_Q, strerror(errno)); return (void*)-1; } //create IPMB_RES_Q if(-1 != access(IPMB_RES_Q, F_OK)) { remove(IPMB_RES_Q); } if(0 != mkfifo (IPMB_RES_Q, 0777)) { printf("%s: Create %s fifo failed! %s\n", __FUNCTION__, IPMB_RES_Q, strerror(errno)); return (void*)-1; } fd_IpmbResQ = open (IPMB_RES_Q, O_RDWR); if(-1 == fd_IpmbResQ) { printf("%s: Open %s fifo failed! %s\n", __FUNCTION__, IPMB_RES_Q, strerror(errno)); return (void*)-1; } fd_IpmbDev = open (dev_name, O_RDWR); if(-1 == fd_IpmbDev) { printf("%s: Open IPMB failed! %s\n", __FUNCTION__, strerror(errno)); return (void*)-1; } //set IPMB address if(0 != stm32_i2c_set_addr(fd_IpmbDev, OwnerAddr)) printf("Set ipmb address fail.\n"); if(ipmbSelect == 0) { gFd_PrimaryIpmbIfcQ = fd_IpmbIfcQ; gFd_PrimaryIpmbResQ = fd_IpmbResQ; gFd_Primary = fd_IpmbDev; } else if(ipmbSelect == 1) { gFd_SecondaryIpmbIfcQ = fd_IpmbIfcQ; gFd_SecondaryIpmbResQ = fd_IpmbResQ; gFd_Secondary = fd_IpmbDev; } /*Create a thread to recv IPMB Pkt */ gThreadIndex++; if(0 != pthread_create(&gThreadIDs[gThreadIndex],NULL,RecvIPMBPkt,Param)) { printf("%s: Create RecvIPMBPkt thread failed! %s\n", __FUNCTION__, strerror(errno)); return (void *)-1; } while(1) { while(GetMsg(fd_IpmbIfcQ, &RcvMsgPkt, WAIT_INFINITE) != 0); switch(RcvMsgPkt.Param) { case PARAM_REQUEST: ProcessIPMBReq (&RcvMsgPkt); break; case PARAM_BRIDGE: break; default: printf("Unknow message param %#x\r\n", RcvMsgPkt.Param); break; } } } /** * @brief Process the request posted by IPMB driver. * @param pReq - Request message pointer. **/ static void ProcessIPMBReq ( MsgPkt_T* pReq) { MsgPkt_T ResPkt; uint8_t ReqLen; IPMIMsgHdr_T* pIPMIMsgReq = (IPMIMsgHdr_T*) pReq->Data; int RetVal = 0; ReqLen = pReq->Size; /* Validate Checksums */ if (TRUE != ValidateIPMBChkSums ((uint8_t*)pIPMIMsgReq, ReqLen)) { printf ("IPMBIfc.c : IPMB Checksum validation failed\r\n"); return; } pReq->Param = PARAM_IFC; pReq->Cmd = pIPMIMsgReq->Cmd; pReq->NetFnLUN = pIPMIMsgReq->NetFnLUN; if(pReq->Channel == PRIMARY_IPMB_CHANNEL) pReq->SrcQ = gFd_PrimaryIpmbResQ; else pReq->SrcQ = gFd_SecondaryIpmbResQ; /* Post the message to message handler Task */ PostMsg (gFd_MsgHndlrIfc, pReq); if(pReq->ResTimeOut < 1) pReq->ResTimeOut = 10; do { if(pReq->Channel == PRIMARY_IPMB_CHANNEL) RetVal = GetMsg (gFd_PrimaryIpmbResQ, &ResPkt, pReq->ResTimeOut); else RetVal = GetMsg (gFd_SecondaryIpmbResQ, &ResPkt, pReq->ResTimeOut); }while(!RetVal && !IsResponseMatch(pReq, &ResPkt) ); if (0 != RetVal) { printf("Warning: Process IPMB request fail, return timeout.\r\n"); ResPkt.Param = PARAM_NORMAL_RESPONSE; ResPkt.Size = sizeof(IPMIMsgHdr_T)+2; SwapIPMIMsgHdr(((IPMIMsgHdr_T*)pReq->Data), ((IPMIMsgHdr_T*)ResPkt.Data)); ResPkt.Data[sizeof(IPMIMsgHdr_T)] = CC_TIMEOUT; ResPkt.Data[sizeof(IPMIMsgHdr_T)+1] = CalculateCheckSum2(ResPkt.Data, sizeof(IPMIMsgHdr_T)+1); } /* If its not normal IPMI Response just return */ if (PARAM_NO_RESPONSE == ResPkt.Param) { printf ("IPMBIfc.c : IPMB request packet dropped, not processed\n"); return; } /* Send the response */ if(pReq->Channel == PRIMARY_IPMB_CHANNEL) { RetVal = stm32_i2c_master_write(gFd_Primary, ResPkt.Data[0], &ResPkt.Data[1], ResPkt.Size); } else if(pReq->Channel == SECONDARY_IPMB_CHANNEL) { RetVal = stm32_i2c_master_write(gFd_Secondary, ResPkt.Data[0], &ResPkt.Data[1], ResPkt.Size); } else { printf("IPMBIfc.c: IPMB channel error. %#x\r\n", pReq->Channel); } if (0 != RetVal) { printf ("IPMBIfc.c : Unable to send a IPMI Response\n"); } return; } /** * @brief Validate IPMB Checksums. * @param Data - Buffer to be validated. * @param Size - Size of the buffer. * @return TRUE if valid, FALSE if error. **/ static uint8_t ValidateIPMBChkSums ( uint8_t* Data, uint8_t Size) { uint8_t i; uint8_t chksum; /* Check IPMB message min size */ if (Size < MIN_IPMB_MSG_LENGTH) { printf("IPMBIfc.c: Invalid IPMB Message Length\r\n"); return FALSE; } /* Validate the checksum1 */ chksum = 0; for (i = 0; i < 3; i++) { chksum += *(Data + i); } if (chksum != 0) { printf ("IPMBIfc.c: Invalid checksum 1, size = %d\n",Size); for(i = 0; i < Size;i++) printf("%x ",Data[i]); printf("\n"); return FALSE; } /* Validate the checksum2 */ chksum = 0; for (i = 3; i < Size; i++) { chksum += *(Data + i); } if (chksum != 0) { printf("IPMBIfc.c: Invalid checksum 2, size = %d\n",Size); for(i = 0; i < Size;i++) printf("%x ",Data[i]); printf("\n"); return FALSE; } return TRUE; } /*----------------------------------------------------- * @fn IsResponseMatch * @brief Checks if the Response Message corresponds to * the Request Message * * @param pReq : IPMI Request Message Packet * @param pRes : IPMI Response Message Packet * * @return 1 if match * 0 if mismatch *----------------------------------------------------*/ uint8_t IsResponseMatch (MsgPkt_T* pReq, MsgPkt_T* pRes) { if( ( ((((IPMIMsgHdr_T*)pRes->Data)->RqSeqLUN) >> 2) != ((((IPMIMsgHdr_T*)pReq->Data)->RqSeqLUN) >> 2) ) && ( (pReq->NetFnLUN & 0x4) && (PARAM_NO_RESPONSE != pRes->Param) ) ) { return FALSE; } return TRUE; } /** * @fn RecvIPMBPkt * @brief This function receives IPMB request packet and post the message to * IPMB interface queue **/ static void* RecvIPMBPkt (void *Param) { MsgPkt_T IPMBReqPkt; int IPMBSlaveFd; int retval; uint8_t ipmbSelect = *(uint8_t*)Param; prctl(PR_SET_NAME, __FUNCTION__, 0, 0, 0); int curThreadIndex = 0; memset(&IPMBReqPkt,0,sizeof(MsgPkt_T)); if(0 == ipmbSelect) { printf ("Primary IPMB Receiver Started...\n"); IPMBReqPkt.Data [0] = g_BMCInfo.IpmiConfig.PrimaryIPMBAddr; IPMBReqPkt.Channel = PRIMARY_IPMB_CHANNEL; IPMBSlaveFd = gFd_Primary; } else if(1 == ipmbSelect) { printf ("Secondary IPMB Receiver Started...\n"); IPMBReqPkt.Data [0] = g_BMCInfo.IpmiConfig.SecondaryIPMBAddr; IPMBReqPkt.Channel = SECONDARY_IPMB_CHANNEL; IPMBSlaveFd = gFd_Secondary; } /* Loop forever */ while (1) { retval = stm32_i2c_slave_recv(IPMBSlaveFd, &IPMBReqPkt.Data[1]); if( retval > 5) { IPMBReqPkt.Param = PARAM_REQUEST; IPMBReqPkt.Size = retval + 1; /* +1 to include BMC Slave address */ /* Post the IPMB Request message to IPMBIfc Queue */ if(ipmbSelect == 0) { if (0 != PostMsg (gFd_PrimaryIpmbIfcQ, &IPMBReqPkt)) { printf ("IPMBIfc.c : Error posting message to IPMBIfc_Q\n"); } } else { if (0 != PostMsg (gFd_SecondaryIpmbIfcQ, &IPMBReqPkt)) { printf ("IPMBIfc.c : Error posting message to IPMBIfc_Q\n"); } } } int cnt; if(0 == ipmbSelect) printf("---> Primary IPMB Recv: "); else printf("---> Secondary IPMB Recv: "); for(cnt=0;cnt < IPMBReqPkt.Size; cnt++) printf("%#x ", IPMBReqPkt.Data[cnt]); printf("\n"); } return (void*)-1; }