diff options
Diffstat (limited to 'util/imbapi.c')
-rw-r--r-- | util/imbapi.c | 2594 |
1 files changed, 2594 insertions, 0 deletions
diff --git a/util/imbapi.c b/util/imbapi.c new file mode 100644 index 0000000..cbc8fa1 --- /dev/null +++ b/util/imbapi.c @@ -0,0 +1,2594 @@ +/*M* +// PVCS: +// $Workfile: imbapi.c $ +// $Revision: 1.12 $ +// $Modtime: 06 Aug 2001 13:16:56 $ +// +// Purpose: This file contains the entry point that opens the IMB device +// in order to issue the IMB driver API related IOCTLs. +// This file implements the IMB driver API for the Server +// Management Agents. +// +// $Log: //epg-scc/sst/projectdatabases/isc/isc3x/LNWORK/SRC/imbapi/imbapi.c.v $ +// +// 04/04/02 ARCress - Mods for open-source & various compile cleanup mods +// 05/28/02 ARCress - fixed buffer size error +// 04/08/03 ARCress - misc cleanup +// 01/20/04 ARCress - added WIN32 flags +// 05/24/05 ARCress - added LINK_LANDESK flags +// 08/24/06 ARCress - mods for addtl DEBUG (dbgmsg) +// 03/19/08 ARCress - fix for SendTimedLan(IpmiVersion) if IPMI 2.0 +*M*/ +/*----------------------------------------------------------------------* +The BSD License +Copyright (c) 2002-2006, Intel Corporation +Copyright (c) 2009 Kontron America, Inc. +All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + a.. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + b.. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + c.. Neither the name of Intel Corporation nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *----------------------------------------------------------------------*/ + +#if defined(SOLARIS) || defined(BSD) +#undef IMB_API +#else +/* Ok for WIN32, LINUX, SCO_UW, etc., but not Solaris */ +#define IMB_API 1 +#endif + +#ifdef IMB_API + +#ifdef WIN32 +#define NO_MACRO_ARGS 1 +#include <windows.h> +#include <stdio.h> +#define uint unsigned int + +#else /* LINUX, SCO_UW, UNIX */ +#include <unistd.h> +#include <sys/param.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/mman.h> +#include <sys/ioctl.h> +#include <stdio.h> +#include <stdlib.h> +#include <fcntl.h> +#include <string.h> +#include <errno.h> +#endif +#include "imb_api.h" + +#ifdef SCO_UW +#define NO_MACRO_ARGS 1 +#define __FUNCTION__ "func" +#define IMB_DEVICE "/dev/instru/mismic" +#else +#define IMB_DEVICE "/dev/imb" +#define PAGESIZE EXEC_PAGESIZE +#endif + +/*Just to make the DEBUG code cleaner.*/ +#if defined(DBG_IPMI) || defined(LINUX_DEBUG) +#include <stdarg.h> +static void dbgmsg( char *pattn, ... ) +{ + va_list arglist; + FILE *fdlog; + + fdlog = fopen( "imbdbg.log", "a+" ); + if (fdlog == NULL) fdlog = stdout; + va_start( arglist, pattn ); + vfprintf( fdlog, pattn, arglist ); + va_end( arglist ); + fclose(fdlog); +} +#endif +#ifdef NO_MACRO_ARGS +#define DEBUG(format, args) /*not_debug*/ +#else +#ifdef LINUX_DEBUG +#define DEBUG(format, args...) dbgmsg(format, ##args) +// #define DEBUG(format, args...) printf(format, ##args) +#else +#define DEBUG(format, args...) /*not_debug*/ +#endif +#endif + +#define IMB_OPEN_TIMEOUT 400 +#define IMB_MAX_RETRIES 2 +#define IMB_DEFAULT_TIMEOUT (1000) /*timeout for SendTimedImb in msec*/ +#define ERR_NO_DRV -16 /*cannot open IPMI driver*/ + +#define LOCAL_IPMB 1 /*instead of METACOMMAND_IPMB*/ + +int ipmi_timeout_ia = IMB_DEFAULT_TIMEOUT; /* in msec */ +#ifdef METACOMMAND_IPMB /*++++ not used*/ +extern int ipmi_cmd_ipmb(BYTE cmd, BYTE netfn, BYTE sa, BYTE bus, BYTE lun, + BYTE *pdata, int sdata, BYTE *presp, + int *sresp, BYTE *pcc, char fdebugcmd); /*ipmilan.c*/ +#endif +#ifdef METACOMMAND +extern FILE *fpdbg; +extern FILE *fperr; +#else +static FILE *fpdbg = NULL; +static FILE *fperr = NULL; +#endif + +/* uncomment out the #define below or use -DLINUX_DEBUG_MAX in the makefile +// if you want a dump of the memory to debug mmap system call in +// MapPhysicalMemory() below. +// +//#define LINUX_DEBUG_MAX 1 */ +//#define IMB_MEMORY 1 */ + +/*keep it simple. use global varibles for event objects and handles +//pai 10/8 */ + +/* UnixWare should eventually have its own source code file. Right now +// new code has been added based on the existing policy of using +// pre-processor directives to separate os-specific code (pai 11/21) */ + +static int IpmiVersion; +static HandleType AsyncEventHandle = 0; +// static void * AsyncEventObject = 0; + +/*//////////////////////////////////////////////////////////////////////////// +// GLOBAL VARIABLES +///////////////////////////////////////////////////////////////////////////// */ + +#if defined(__i386__) || defined(__i586__) || defined(__i686__) +// static DWORD ioctl_sendmsg = 0x1082; /* force 0x1082 if 32-bit */ +static DWORD ioctl_sendmsg = IOCTL_IMB_SEND_MESSAGE; +#else +static DWORD ioctl_sendmsg = IOCTL_IMB_SEND_MESSAGE; +#endif + +static IO_STATUS_BLOCK NTstatus; /*dummy place holder. See deviceiocontrol. */ +static HandleType hDevice1; /*used in open_imb() */ +static HandleType hDevice; /*used to call DeviceIoControl()*/ +/*mutex_t deviceMutex; */ +#ifdef LINUX_DEBUG +static char fdebug = 1; +#else +static char fdebug = 0; +#endif + +#ifdef LINK_LANDESK +#define SendTimedImbpRequest ia_SendTimedImbpRequest +#define StartAsyncMesgPoll ia_StartAsyncMesgPoll +#define SendTimedI2cRequest ia_SendTimedI2cRequest +#define SendTimedEmpMessageResponse ia_SendTimedEmpMessageResponse +#define SendTimedEmpMessageResponse_Ex ia_SendTimedEmpMessageResponse_Ex +#define SendTimedLanMessageResponse ia_SendTimedLanMessageResponse +#define SendTimedLanMessageResponse_Ex ia_SendTimedLanMessageResponse_Ex +#define SendAsyncImbpRequest ia_SendAsyncImbpRequest +#define GetAsyncImbpMessage ia_GetAsyncImbpMessage +#define GetAsyncImbpMessage_Ex ia_GetAsyncImbpMessage_Ex +#define IsAsyncMessageAvailable ia_IsAsyncMessageAvailable +#define RegisterForImbAsyncMessageNotification ia_RegisterForImbAsyncMessageNotification +#define UnRegisterForImbAsyncMessageNotification ia_UnRegisterForImbAsyncMessageNotification +#define SetShutDownCode ia_SetShutDownCode +#define GetIpmiVersion ia_GetIpmiVersion +#endif + +int open_imb(int fskipcmd); + +void set_fps(void) +{ + if (fpdbg == NULL) fpdbg = stdout; + if (fperr == NULL) fperr = stdout; +} + +#ifndef WIN32 +DWORD GetLastError(void) { return(NTstatus.Status); } + +/*/////////////////////////////////////////////////////////////////////////// +// DeviceIoControl +///////////////////////////////////////////////////////////////////////////// */ +/*F* +// Name: DeviceIoControl +// Purpose: Simulate NT DeviceIoControl using unix calls and structures. +// Context: called for every NT DeviceIoControl +// Returns: FALSE for fail and TRUE for success. Same as standarad NTOS call +// as it also sets Ntstatus.status. +// Parameters: Standard NT call parameters, see below. +// Notes: none +*F*/ +static BOOL +DeviceIoControl( + HandleType dummy_hDevice, /* handle of device */ + DWORD dwIoControlCode, /* control code of operation to perform*/ + LPVOID lpvInBuffer, /* address of buffer for input data */ + DWORD cbInBuffer, /* size of input buffer */ + LPVOID lpvOutBuffer, /* address of output buffer */ + DWORD cbOutBuffer, /* size of output buffer */ + LPDWORD lpcbBytesReturned, /* address of actual bytes of output */ + LPOVERLAPPED lpoOverlapped /* address of overlapped struct */ + ) +{ + struct smi s; + int rc, max_i; + int ioctl_status; + + DEBUG("DeviceIoControl: hDevice1=%x hDevice=%x ioctl=%x\n", + hDevice1,hDevice,dwIoControlCode); + rc = open_imb(1); /*open if needed, set fskipcmd to avoid recursion*/ + if (rc == 0) { +#ifdef DBG_IPMI + dbgmsg("DeviceIoControl: open_imb failed %d\n", rc); +#endif + return FALSE; + } + + /*-------------dont use locking-------------- + //lock the mutex, before making the request.... + if(mutex_lock(&deviceMutex) != 0) { + return(FALSE); + } + *-------------------------------------------*/ +#ifndef NO_MACRO_ARGS + DEBUG("%s: ioctl cmd = 0x%lx ", __FUNCTION__,dwIoControlCode); + DEBUG("cbInBuffer %d cbOutBuffer %d\n", cbInBuffer, cbOutBuffer); +#endif + /* Test for Intel imb driver max buf size */ + /* Max was 41, too small. Calculate real max - ARCress 6/01/05 */ + max_i = MAX_IMB_PACKET_SIZE + MIN_IMB_REQ_BUF_SIZE; /*33 + 13*/ + if (cbInBuffer > max_i) cbInBuffer = max_i; + + s.lpvInBuffer = lpvInBuffer; + s.cbInBuffer = cbInBuffer; + s.lpvOutBuffer = lpvOutBuffer; + s.cbOutBuffer = cbOutBuffer; + s.lpcbBytesReturned = lpcbBytesReturned; + s.lpoOverlapped = lpoOverlapped; + s.ntstatus = (LPVOID)&NTstatus; /*dummy place holder. Linux IMB driver + //doesnt return status or info via it.*/ +#ifdef IMB_DEBUG + if (fdebug) { + int j, n; + char *tag; + unsigned int *bi; + unsigned char *b; + + printf("ioctl %x smi buffer:\n",dwIoControlCode); + /* show arg/smi structure */ + bi = (unsigned int *)&s; + n = ( sizeof(struct smi) / sizeof(int) ); + printf("smi(%p), (sz=%d/szint=%d)->%d:\n", bi, sizeof(struct smi), + sizeof(int),n); + for (j = 0; j < n; j++) { + switch(j) { + case 0: tag = "version "; break; + case 2: tag = "reserved1"; break; + case 4: tag = "reserved2"; break; + case 6: tag = "ntstatus "; break; + case 8: tag = "pinbuf "; break; + case 10: tag = "sinbuf "; break; + case 12: tag = "poutbuf"; break; + case 14: tag = "soutbuf"; break; + case 16: tag = "cbRet "; break; + case 18: tag = "pOverlap"; break; + default: tag = "other "; + } + printf("bi[%d]%s: %08x \n",j,tag,bi[j]); + } /*end for*/ + } +#endif + + if ( (ioctl_status = ioctl(hDevice1, dwIoControlCode,&s) ) <0) { +#ifndef NO_MACRO_ARGS + DEBUG("%s %s: ioctl cmd = 0x%x failed %d \n", + __FILE__,__FUNCTION__,dwIoControlCode,ioctl_status); +#endif +#ifdef DBG_IPMI + dbgmsg("DeviceIoControl: ioctl cmd = 0x%x failed %d \n", + dwIoControlCode,ioctl_status); +#endif + /* mutex_unlock(&deviceMutex); */ + return FALSE; + } + /*-------------dont use locking-------------- + mutex_unlock(&deviceMutex); + *-------------------------------------------*/ + +#ifndef NO_MACRO_ARGS + DEBUG("%s: ioctl_status %d bytes returned = %d \n", + __FUNCTION__, ioctl_status, *lpcbBytesReturned); +#endif + +/*MR commented this just as in Sol1.10. lpcbBytesReturned has the right data +// *lpcbBytesReturned = NTstatus.Information; */ + + if (ioctl_status == STATUS_SUCCESS) { +#ifndef NO_MACRO_ARGS + DEBUG("%s returning true\n", __FUNCTION__); +#endif + return (TRUE); + } + else { +#ifndef NO_MACRO_ARGS + DEBUG("%s returning false\n", __FUNCTION__); +#endif + return (FALSE); + } +} +#endif + +static void _dump_buf(char *tag, BYTE *pbuf, int sz, char fshowascii) +{ + BYTE line[17]; + BYTE a; + int i, j; + char *stag; + FILE *fpdbg1; + +#ifdef DBG_IPMI + fpdbg1 = fopen( "imbdbg.log", "a+" ); + if (fpdbg1 == NULL) fpdbg1 = stdout; +#else + fpdbg1 = stdout; +#endif + if (tag == NULL) stag = "dump_buf"; /*safety valve*/ + else stag = tag; + fprintf(fpdbg1,"%s (len=%d): ", stag,sz); + line[0] = 0; line[16] = 0; + j = 0; + if (sz < 0) { fprintf(fpdbg1,"\n"); return; } /*safety valve*/ + for (i = 0; i < sz; i++) { + if (i % 16 == 0) { + line[j] = 0; + j = 0; + fprintf(fpdbg1,"%s\n %04x: ",line,i); + } + if (fshowascii) { + a = pbuf[i]; + if (a < 0x20 || a > 0x7f) a = '.'; + line[j++] = a; + } + fprintf(fpdbg1,"%02x ",pbuf[i]); + } + if (fshowascii) { + if ((j > 0) && (j < 16)) { + /* space over the remaining number of hex bytes */ + for (i = 0; i < (16-j); i++) fprintf(fpdbg1," "); + } + else j = 16; + line[j] = 0; + } + fprintf(fpdbg1,"%s\n",line); +#ifdef DBG_IPMI + if (fpdbg1 != stdout) fclose(fpdbg1); +#endif + return; +} + +#ifdef LOCAL_IPMB +#define SMS_MSG_LUN 0x02 +extern void os_usleep(int s, int u); /*subs.c*/ +static int sendSeq = 1; +static BYTE cksum(const BYTE *buf, register int len) +{ /* 8-bit 2s compliment checksum */ + register BYTE csum; + register int i; + csum = 0; + for (i = 0; i < len; i++) csum = (csum + buf[i]) % 256; + csum = -csum; + return(csum); +} + +// SendTimedIpmbpRequest +ACCESN_STATUS +SendTimedIpmbpRequest ( + IMBPREQUESTDATA *reqPtr, /* request info and data */ + int timeOut, /* how long to wait, in mSec units */ + BYTE *respDataPtr, /* where to put response data */ + int *respDataLen, /* how much response data there is */ + BYTE *completionCode /* request status from bmc controller*/ + ) +{ + BYTE responseData[MAX_IMB_REQ_SIZE]; + ImbResponseBuffer * resp = (ImbResponseBuffer *) responseData; + DWORD respLength = sizeof( responseData ); + DWORD reqLength; + BYTE requestData[MAX_IMB_RESP_SIZE]; + ImbRequestBuffer * req = (ImbRequestBuffer *) requestData; + BOOL status; + int i; + + req->req.rsSa = BMC_SA; + req->req.cmd = SEND_MESSAGE; + req->req.netFn = APP_NETFN; + req->req.rsLun = BMC_LUN; /*=0*/ + req->req.data[0] = reqPtr->busType; + req->req.data[1] = reqPtr->rsSa; + req->req.data[2] = ((reqPtr->netFn << 2) | (reqPtr->rsLun & 0x03)); + req->req.data[3] = cksum(&req->req.data[1],2); + req->req.data[4] = BMC_SA; + req->req.data[5] = ((sendSeq << 2) | (SMS_MSG_LUN & 0x03)); + req->req.data[6] = reqPtr->cmdType; + for (i = 0; i < reqPtr->dataLength; i++) + req->req.data[7+i] = reqPtr->data[i]; + req->req.data[7+i] = cksum(&req->req.data[4], reqPtr->dataLength + 3); + req->req.dataLength = reqPtr->dataLength + 8; + + req->flags = 0; + req->timeOut = timeOut * 1000; /* convert to uSec units */ + reqLength = req->req.dataLength + MIN_IMB_REQ_BUF_SIZE; + status = DeviceIoControl( hDevice, + ioctl_sendmsg, + requestData, + reqLength, + & responseData, + sizeof( responseData ), + & respLength, + NULL); + if (fdebug) printf("sendIpmb: send_message status=%d rlen=%d cc=%x\n", + status,respLength,resp->cCode); + if ( status != TRUE ) { + DWORD error; + error = GetLastError(); + return ACCESN_ERROR; + } + if ( respLength == 0 ) { + return ACCESN_ERROR; + } + sendSeq++; + if ( resp->cCode != 0) { + *completionCode = resp->cCode; + *respDataLen = 0; + return ACCESN_OK; + } + + /* + * Sent ok, wait for GetMessage response + */ + for (i=0; i < 10; i++) /* RETRIES=10 for GetMessage */ + { + //req->req.busType = PUBLIC_BUS; /*=0*/ + req->req.rsSa = BMC_SA; + req->req.cmd = GET_MESSAGE; + req->req.netFn = APP_NETFN; + req->req.rsLun = BMC_LUN; /*=0*/ + req->req.dataLength = 0; + reqLength = req->req.dataLength + MIN_IMB_REQ_BUF_SIZE; + status = DeviceIoControl( hDevice, + ioctl_sendmsg, + requestData, + reqLength, + & responseData, + sizeof( responseData ), + & respLength, + NULL); + if (fdebug) printf("sendIpmb: get_message status=%d rlen=%d cc=%x\n", + status,respLength,resp->cCode); + if ( status != TRUE ) { + DWORD error; + error = GetLastError(); + return ACCESN_ERROR; + } + if ( respLength == 0 ) { + return ACCESN_ERROR; + } + if ( (resp->cCode != 0x80) && (resp->cCode != 0x83) ) + break; /*success, exit loop*/ + os_usleep(0,1000); /* 1 msec*/ + } /*end-for*/ + + /* + * give the caller his response + */ + *completionCode = resp->cCode; + *respDataLen = 0; + if (( respLength > 1 ) && ( respDataPtr)) { + /* check that resp cmd & netfn match */ + *respDataLen = respLength - 7; + memcpy( respDataPtr, &resp->data[7], *respDataLen); + } + return ACCESN_OK; +} +#endif + +/*/////////////////////////////////////////////////////////////////////////// +// SendTimedImbpRequest +///////////////////////////////////////////////////////////////////////////// */ +/*F* +// Name: SendTimedImbpRequest +// Purpose: This function sends a request for BMC implemented function +// Context: Used by Upper level agents (sis modules) to access BMC implemented functionality. +// Returns: OK else error status code +// Parameters: +// reqPtr +// timeOut +// respDataPtr +// respLen +// Notes: none +*F*/ +ACCESN_STATUS +SendTimedImbpRequest ( + IMBPREQUESTDATA *reqPtr, /* request info and data */ + int timeOut, /* how long to wait, in mSec units */ + BYTE *respDataPtr, /* where to put response data */ + int *respDataLen, /* how much response data there is */ + BYTE *completionCode /* request status from bmc controller*/ + ) +{ + BYTE responseData[MAX_IMB_REQ_SIZE]; + ImbResponseBuffer * resp = (ImbResponseBuffer *) responseData; + DWORD respLength = sizeof( responseData ); + DWORD reqLength; + BYTE requestData[MAX_IMB_RESP_SIZE]; + ImbRequestBuffer * req = (ImbRequestBuffer *) requestData; + BOOL status; + + + req->req.rsSa = reqPtr->rsSa; + req->req.cmd = reqPtr->cmdType; + req->req.netFn = reqPtr->netFn; + req->req.rsLun = reqPtr->rsLun; + req->req.dataLength = (BYTE)reqPtr->dataLength; + +#ifndef NO_MACRO_ARGS + DEBUG("cmd=%02x, pdata=%p, datalen=%d, size=%d\n", req->req.cmd, + reqPtr->data, reqPtr->dataLength, sizeof(requestData)); +#endif + memcpy( req->req.data, reqPtr->data, reqPtr->dataLength ); + + req->flags = 0; + req->timeOut = timeOut * 1000; /* convert to uSec units */ + +#ifndef NO_MACRO_ARGS + DEBUG("%s: rsSa 0x%x cmd 0x%x netFn 0x%x rsLun 0x%x\n", __FUNCTION__, + req->req.rsSa, req->req.cmd, req->req.netFn, req->req.rsLun); +#endif + reqLength = req->req.dataLength + MIN_IMB_REQ_BUF_SIZE; + + status = DeviceIoControl( hDevice, + ioctl_sendmsg, + requestData, + reqLength, + & responseData, + sizeof( responseData ), + & respLength, + NULL + ); +#ifndef NO_MACRO_ARGS + DEBUG("%s: DeviceIoControl returned status = %d\n",__FUNCTION__, status); +#endif +#ifdef DBG_IPMI + printf("%s: rsSa %x cmd %x netFn %x lun %x, status=%d, cc=%x, rlen=%d\n", + __FUNCTION__, req->req.rsSa, req->req.cmd, req->req.netFn, + req->req.rsLun, status, resp->cCode, respLength ); + dbgmsg("SendTimedImb: rsSa %x cmd %x netFn %x lun %x, status=%d, cc=%x, rlen=%d\n", + req->req.rsSa, req->req.cmd, req->req.netFn, + req->req.rsLun, status, resp->cCode, respLength ); + if (req->req.cmd == 0x34) { + _dump_buf("requestData",requestData,reqLength,0); //if DBG_IPMI + _dump_buf("responseData",responseData,respLength,0); //if DBG_IPMI + } +#endif + + if( status != TRUE ) { + DWORD error; + error = GetLastError(); + return ACCESN_ERROR; + } + if( respLength == 0 ) { + return ACCESN_ERROR; + } + + /* + * give the caller his response + */ + *completionCode = resp->cCode; + *respDataLen = 0; + + if(( respLength > 1 ) && ( respDataPtr)) + { + *respDataLen = respLength - 1; + memcpy( respDataPtr, resp->data, *respDataLen); + } + + + return ACCESN_OK; +} + + +/*//////////////////////////////////////////////////////////////////// +// open_imb +////////////////////////////////////////////////////////////////////// */ +/*F* +// Name: open_imb +// Purpose: To open imb device +// Context: Called from each routine to make sure that open is done. +// Returns: returns 0 for Fail and 1 for Success, sets hDevice to open +// handle. +// Parameters: none +// Notes: none +*F*/ +#ifdef WIN32 +#define IMB_DEVICE_WIN "\\\\.\\Imb" +int open_imb(int fskipcmd) +{ +/* This routine will be called from all other routines before doing any + interfacing with imb driver. It will open only once. */ + IMBPREQUESTDATA requestData; + BYTE respBuffer[MAX_IMB_RESP_SIZE]; + DWORD respLength; + BYTE completionCode; + int ret; + + set_fps(); + if (hDevice1 == 0) /*INVALID_HANDLE_VALUE*/ + { + // + // Open IMB driver device + // + hDevice = CreateFile( IMB_DEVICE_WIN, + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL + ); + if (hDevice == NULL || hDevice == INVALID_HANDLE_VALUE) { + if (fdebug) printf("ipmi_open_ia: error opening %s to imbdrv.sys\n", + IMB_DEVICE_WIN); + return (0); /*FALSE*/ + } + + if (fskipcmd) { + IpmiVersion = IPMI_15_VERSION; + return (1); /*TRUE*/ + } + // Detect the IPMI version for processing requests later. + // This is a crude but most reliable method to differentiate + // between old IPMI versions and the 1.0 version. If we had used the + // version field instead then we would have had to revalidate all the + // older platforms (pai 4/27/99) + requestData.cmdType = GET_DEVICE_ID; + requestData.rsSa = BMC_SA; + requestData.rsLun = BMC_LUN; + requestData.netFn = APP_NETFN ; + requestData.busType = PUBLIC_BUS; + requestData.data = NULL; + requestData.dataLength = 0; + respLength = sizeof(respBuffer); + ret = SendTimedImbpRequest ( &requestData, IMB_OPEN_TIMEOUT, + respBuffer, &respLength, &completionCode); + if ( (ret != ACCESN_OK ) || ( completionCode != 0) ) + { + if (fdebug) /*GetDeviceId failed*/ + printf("ipmi_open_ia: imbdrv request error, ret=%d ccode=%x\n", + ret,completionCode); + CloseHandle(hDevice); + return (0); /*FALSE*/ + } + hDevice1 = hDevice; + + if (respLength < (IPMI10_GET_DEVICE_ID_RESP_LENGTH-1)) + IpmiVersion = IPMI_09_VERSION; + else { + if ( respBuffer[4] == 0x01 ) + IpmiVersion = IPMI_10_VERSION; + else /* IPMI 1.5 or 2.0 */ + IpmiVersion = IPMI_15_VERSION; + } + } + return (1); /*TRUE*/ + +} /*end open_imb for Win32 */ + +#else /* LINUX, SCO_UW, etc. */ + +int open_imb(int fskipcmd) +{ +/* This routine will be called from all other routines before doing any + interfacing with imb driver. It will open only once. */ + IMBPREQUESTDATA requestData; + BYTE respBuffer[MAX_IMB_RESP_SIZE]; + int respLength; + BYTE completionCode; + + int ret_code; + + set_fps(); + + if (hDevice1 == 0) + { +#ifndef NO_MACRO_ARGS + DEBUG("%s: opening the driver, ioctl_sendmsg = %x\n", + __FUNCTION__, ioctl_sendmsg); +#endif + /* %%%%* IOCTL_IMB_SEND_MESSAGE = 0x1082 + printf("ipmi_open_ia: " + "IOCTL_IMB_SEND_MESSAGE =%x \n" "IOCTL_IMB_GET_ASYNC_MSG=%x \n" + "IOCTL_IMB_MAP_MEMORY = %x \n" "IOCTL_IMB_UNMAP_MEMORY= %x \n" + "IOCTL_IMB_SHUTDOWN_CODE=%x \n" "IOCTL_IMB_REGISTER_ASYNC_OBJ =%x \n" + "IOCTL_IMB_DEREGISTER_ASYNC_OBJ=%x \n" + "IOCTL_IMB_CHECK_EVENT =%x \n" "IOCTL_IMB_POLL_ASYNC =%x \n", + IOCTL_IMB_SEND_MESSAGE, IOCTL_IMB_GET_ASYNC_MSG, + IOCTL_IMB_MAP_MEMORY, IOCTL_IMB_UNMAP_MEMORY, IOCTL_IMB_SHUTDOWN_CODE, + IOCTL_IMB_REGISTER_ASYNC_OBJ, IOCTL_IMB_DEREGISTER_ASYNC_OBJ, + IOCTL_IMB_CHECK_EVENT , IOCTL_IMB_POLL_ASYNC); *%%%%*/ + + /*O_NDELAY flag will cause problems later when driver makes + //you wait. Hence removing it. */ + /*if ((hDevice1 = open(IMB_DEVICE,O_RDWR|O_NDELAY)) <0) */ + if ((hDevice1 = open(IMB_DEVICE,O_RDWR)) <0) + { + hDevice1 = 0; +#ifndef WIN32 + /* dont always display open errors if Linux */ + if (fdebug) +#endif + { + /*debug or not 1st time */ + printf("imbapi ipmi_open_ia: open(%s) failed, %s\n", + IMB_DEVICE,strerror(errno)); + } + return (0); + } + + if (fskipcmd) { + IpmiVersion = IPMI_15_VERSION; + return (1); /*TRUE*/ + } + /* Detect the IPMI version for processing requests later. + // This is a crude but most reliable method to differentiate + // between old IPMI versions and the 1.0 version. If we had used the + // version field instead then we would have had to revalidate all + // the older platforms (pai 4/27/99) */ + requestData.cmdType = GET_DEVICE_ID; + requestData.rsSa = BMC_SA; + requestData.rsLun = BMC_LUN; + requestData.netFn = APP_NETFN ; + requestData.busType = PUBLIC_BUS; + requestData.data = NULL; + requestData.dataLength = 0; + respLength = sizeof(respBuffer); +#ifndef NO_MACRO_ARGS + DEBUG("%s: opened driver, getting IPMI version\n", __FUNCTION__); +#endif + ret_code = SendTimedImbpRequest(&requestData, + IMB_OPEN_TIMEOUT, respBuffer, &respLength, + &completionCode); + if ( (ret_code != ACCESN_OK) || (completionCode != 0) ) + { + printf("ipmi_open_ia: SendTimedImbpRequest error. Ret = %d CC = 0x%02X\n", + ret_code, completionCode); + close(hDevice1); + hDevice1 = 0; + return (0); + } + + if (respLength < (IPMI10_GET_DEVICE_ID_RESP_LENGTH-1)) + IpmiVersion = IPMI_09_VERSION; + else { + if ( respBuffer[4] == 0x01 ) + IpmiVersion = IPMI_10_VERSION; + else /* IPMI 1.5 or 2.0 */ + IpmiVersion = IPMI_15_VERSION; + } +#ifndef NO_MACRO_ARGS + DEBUG("%s: IPMI version 0x%x\n", __FUNCTION__, IpmiVersion); +#endif + +/* +//initialise a mutex + if(mutex_init(&deviceMutex , USYNC_THREAD, NULL) != 0) + { + return(0); + } +*/ + + } + + return (1); +} /*end open_imb()*/ + +#endif + +int close_imb(void) +{ + int rc = 0; + if (hDevice1 != 0) { +#ifdef WIN32 + CloseHandle(hDevice1); +#else + rc = close(hDevice1); +#endif + } + return(rc); +} + +#ifndef LINK_LANDESK +/* If there is not a LANDESK lib, provide these 2 functions for apps + * that may be already be coded to that interface. + */ +int initIPMI(void) +{ /* for compatibility with LanDesk programs*/ + int rc; + rc = open_imb(0); /*sets hDevice1*/ + if (rc == 1) rc = 0; + else rc = -1; + return(rc); +} +int termIPMI(void) +{ /* for compatibility with LanDesk programs*/ + return(close_imb()); +} +#endif + +/*---------------------------------------------------------------------* + * ipmi_open_ia & ipmi_close_ia + *---------------------------------------------------------------------*/ +int ipmi_open_ia(char fdebugcmd) +{ + int rc = 0; + fdebug = fdebugcmd; + rc = open_imb(0); /*sets hDevice1*/ + if (rc == 1) rc = 0; + else rc = -1; + return(rc); +} + +int ipmi_close_ia(void) +{ + int rc = 0; + rc = close_imb(); + return(rc); +} + + +int ipmi_cmdraw_ia(BYTE cmd, BYTE netfn, BYTE lun, BYTE sa, BYTE bus, + BYTE *pdata, BYTE sdata, BYTE *presp, int *sresp, + BYTE *pcc, char fdebugcmd) +{ + IMBPREQUESTDATA requestData; + int status = 0; + char *imbDev; + BYTE * pc; + int sz, i; +#ifndef WIN32 + struct stat stbuf; +#endif + + if (fdebug) printf("ipmi_cmdraw_ia(%02x,%02x,%02x,%02x,bus=%02x)\n", + cmd,netfn,lun,sa,bus); +#ifdef METACOMMAND_IPMB /*++++ not used*/ + if (bus != PUBLIC_BUS) { + if (fdebug) printf("ipmi_cmdraw_ia: bus=%x, using ipmb\n",bus); + status = ipmi_cmd_ipmb(cmd,netfn,lun,sa,bus,pdata,sdata,presp,sresp, + pcc,fdebugcmd); + return(status); + } +#endif + set_fps(); + + requestData.cmdType = cmd; + requestData.rsSa = sa; + requestData.busType = bus; + requestData.netFn = netfn; + requestData.rsLun = lun; + requestData.dataLength = sdata; + requestData.data = pdata; + + if (fdebugcmd) { + sz = sizeof(IMBPREQUESTDATA); + pc = (BYTE *)&requestData.cmdType; + fprintf(fpdbg,"ipmi_cmdraw_ia: request (len=%d): ",sz); + for (i = 0; i < sz; i++) fprintf(fpdbg,"%02x ",pc[i]); + fprintf(fpdbg,"\n"); + pc = requestData.data; + sz = requestData.dataLength; + fprintf(fpdbg," req.data=%p, dlen=%d: ", pc, sz); + for (i = 0; i < sz; i++) fprintf(fpdbg,"%02x ",pc[i]); + fprintf(fpdbg,"\n"); + } + +#ifdef WIN32 + imbDev = "[imbdrv]"; + if (1) +#else + imbDev = "/dev/imb"; + if (stat(imbDev, &stbuf) == -1) { + fprintf(fperr,"ipmi_cmdraw_ia: No IMB driver found (%s)\n",imbDev); + return(ERR_NO_DRV); + } else /* imb device node is there */ +#endif + { + sz = *sresp; /* note that sresp must be pre-set */ + memset(presp, 0, sz); + for ( i =0 ; i < IMB_MAX_RETRIES; i++) + { + *sresp = sz; /* retries may need to re-init *sresp */ +#ifdef LOCAL_IPMB + if (bus != PUBLIC_BUS) + status = SendTimedIpmbpRequest(&requestData, ipmi_timeout_ia, presp, sresp, pcc); + else +#endif + status = SendTimedImbpRequest(&requestData, ipmi_timeout_ia, presp, sresp, pcc); + if((status) == 0 ) { break; } + if (fdebugcmd) // only gets here if error + fprintf(fpdbg,"ipmi_cmdraw_ia: sendImbRequest error status=%x, ccode=%x\n", + (uint)status, *pcc); + } + } + + if (fdebugcmd) { /* if debug, show both good and bad statuses */ + fprintf(fpdbg,"ipmi_cmdraw_ia: sendImbRequest status=%x, ccode=%x\n", + (uint)status, *pcc); + if (status == 0) { + BYTE * pc; int sz; + sz = *sresp; + pc = (BYTE *)presp; + fprintf(fpdbg,"ipmi_cmdraw_ia: response (len=%d): ",sz); + for (i = 0; i < sz; i++) fprintf(fpdbg,"%02x ",pc[i]); + fprintf(fpdbg,"\n"); + } + } + if (status == 1) status = -3; /*LAN_ERR_RECV_FAIL, a meaningful error*/ + return(status); +} /* end ipmi_cmdraw_ia() */ + +/*---------------------------------------------------------------------*/ +/*Used only by UW. Left here for now. IMB driver will not accept this +//ioctl. */ +ACCESN_STATUS +StartAsyncMesgPoll() +{ + + DWORD retLength; + BOOL status; + +#ifndef NO_MACRO_ARGS + DEBUG("%s: DeviceIoControl cmd = %x\n",__FUNCTION__,IOCTL_IMB_POLL_ASYNC); +#endif + status = DeviceIoControl ( hDevice, + IOCTL_IMB_POLL_ASYNC, + NULL, + 0, + NULL, + 0, + & retLength, + 0 + ); + +#ifndef NO_MACRO_ARGS + DEBUG("%s: DeviceIoControl status = %d\n",__FUNCTION__, status); +#endif + + if( status == TRUE ) { + return ACCESN_OK; + } else { + return ACCESN_ERROR; + } + +} + +/*///////////////////////////////////////////////////////////////////////////// +// SendTimedI2cRequest +///////////////////////////////////////////////////////////////////////////// */ +/*F* +// Name: SendTimedI2cRequest +// Purpose: This function sends a request to a I2C device +// Context: Used by Upper level agents (sis modules) to access dumb I2c devices +// Returns: ACCESN_OK else error status code +// Parameters: +// reqPtr +// timeOut +// respDataPtr +// respLen +// Notes: none +*F*/ + +ACCESN_STATUS +SendTimedI2cRequest ( + I2CREQUESTDATA *reqPtr, /* I2C request */ + int timeOut, /* how long to wait, mSec units */ + BYTE *respDataPtr, /* where to put response data */ + int *respDataLen, /* size of response buffer and */ + /* size of returned data */ + BYTE *completionCode /* request status from BMC */ + ) +{ + BOOL status; + BYTE responseData[MAX_IMB_RESP_SIZE]; + ImbResponseBuffer * resp = (ImbResponseBuffer *) responseData; + DWORD respLength = sizeof( responseData ); + BYTE requestData[MAX_IMB_RESP_SIZE]; + ImbRequestBuffer * req = (ImbRequestBuffer *) requestData; + + struct WriteReadI2C { /* format of a write/read I2C request */ + BYTE busType; + BYTE rsSa; + BYTE count; + BYTE data[1]; + } * wrReq = (struct WriteReadI2C *) req->req.data; + +#define MIN_WRI2C_SIZE 3 /* size of write/read request minus any data */ + + + /* + // If the Imb driver is not present return AccessFailed + */ + + req->req.rsSa = BMC_SA; + req->req.cmd = WRITE_READ_I2C; + req->req.netFn = APP_NETFN; + req->req.rsLun = BMC_LUN; + req->req.dataLength = reqPtr->dataLength + MIN_WRI2C_SIZE; + + wrReq->busType = reqPtr->busType; + wrReq->rsSa = reqPtr->rsSa; + wrReq->count = reqPtr->numberOfBytesToRead; + + memcpy( wrReq->data, reqPtr->data, reqPtr->dataLength ); + + req->flags = 0; + req->timeOut = timeOut * 1000; /* convert to uSec units */ + + status = DeviceIoControl( hDevice, + ioctl_sendmsg, + requestData, + sizeof( requestData ), + & responseData, + sizeof( responseData ), + & respLength, + NULL + ); +#ifndef NO_MACRO_ARGS + DEBUG("%s: DeviceIoControl status = %d\n",__FUNCTION__, status); +#endif + + if( status != TRUE ) { + DWORD error; + error = GetLastError(); + return ACCESN_ERROR; + } + if( respLength == 0 ) { + return ACCESN_ERROR; + } + + /* + // give the caller his response + */ + *completionCode = resp->cCode; + *respDataLen = respLength - 1; + + if(( *respDataLen ) && (respDataPtr)) + memcpy( respDataPtr, resp->data, *respDataLen); + + return ACCESN_OK; + +} + +/*This is not a API exported by the driver in stricter sense. It is +//added to support EMP functionality. Upper level software could have +//implemented this function.(pai 5/4/99) */ +/*///////////////////////////////////////////////////////////////////////////// +// SendTimedEmpMessageResponse +///////////////////////////////////////////////////////////////////////////// */ + +/*F* +// Name: SendTimedEmpMessageResponse +// Purpose: This function sends a response message to the EMP port +// Context: +// Returns: OK else error status code +// Parameters: +// +// Notes: none +*F*/ + +ACCESN_STATUS +SendTimedEmpMessageResponse ( + ImbPacket *ptr, /* pointer to the original request from EMP */ + char *responseDataBuf, + int responseDataLen, + int timeOut /* how long to wait, in mSec units */ + ) +{ + BOOL status; + BYTE responseData[MAX_IMB_RESP_SIZE]; + /*ImbResponseBuffer * resp = (ImbResponseBuffer *) responseData; */ + DWORD respLength = sizeof( responseData ); + BYTE requestData[MAX_IMB_RESP_SIZE]; + ImbRequestBuffer * req = (ImbRequestBuffer *) requestData; + int i,j; + + /*form the response packet first */ + req->req.rsSa = BMC_SA; + if (IpmiVersion == IPMI_09_VERSION) + req->req.cmd = WRITE_EMP_BUFFER; + else + req->req.cmd = SEND_MESSAGE; + req->req.netFn = APP_NETFN; + req->req.rsLun = 0; + + i = 0; + if (IpmiVersion != IPMI_09_VERSION) + req->req.data[i++] = EMP_CHANNEL; + + req->req.data[i++] = ptr->rqSa; + req->req.data[i++] = (((ptr->nfLn & 0xfc) | 0x4) | ((ptr->seqLn) & 0x3)); + if (IpmiVersion == IPMI_09_VERSION) + req->req.data[i++] = ((~(req->req.data[0] + req->req.data[1])) +1); + else + req->req.data[i++] = ((~(req->req.data[1] + req->req.data[2])) +1); + + req->req.data[i++] = BMC_SA; /*though software is responding, we have to + //provide BMCs slave address as responder + //address. */ + + req->req.data[i++] = ( (ptr->seqLn & 0xfc) | (ptr->nfLn & 0x3) ); + + req->req.data[i++] = ptr->cmd; + for ( j = 0 ; j < responseDataLen ; ++j,++i) + req->req.data[i] = responseDataBuf[j]; + + req->req.data[i] = 0; + if (IpmiVersion == IPMI_09_VERSION) + j = 0; + else + j = 1; + for ( ; j < ( i -3); ++j) + req->req.data[i] += req->req.data[j+3]; + req->req.data[i] = ~(req->req.data[i]) +1; + ++i; + req->req.dataLength = (BYTE)i; + + req->flags = 0; + req->timeOut = timeOut * 1000; /* convert to uSec units */ + + + status = DeviceIoControl( hDevice, + ioctl_sendmsg, + requestData, + sizeof(requestData), + responseData, + sizeof( responseData ), + & respLength, + NULL + ); + +#ifndef NO_MACRO_ARGS + DEBUG("%s: DeviceIoControl status = %d\n",__FUNCTION__, status); +#endif + + + if ( (status != TRUE) || (respLength != 1) || (responseData[0] != 0) ) + { + return ACCESN_ERROR; + } + return ACCESN_OK; +} + + +/*This is not a API exported by the driver in stricter sense. It is added to support +// EMP functionality. Upper level software could have implemented this function.(pai 5/4/99) */ +/*/////////////////////////////////////////////////////////////////////////// +// SendTimedEmpMessageResponse_Ex +//////////////////////////////////////////////////////////////////////////// */ + +/*F* +// Name: SendTimedEmpMessageResponse_Ex +// Purpose: This function sends a response message to the EMP port +// Context: +// Returns: OK else error status code +// Parameters: +// +// Notes: none +*F*/ + +ACCESN_STATUS +SendTimedEmpMessageResponse_Ex ( + + ImbPacket * ptr, /* pointer to the original request from EMP */ + char *responseDataBuf, + int responseDataLen, + int timeOut, /* how long to wait, in mSec units*/ + BYTE sessionHandle, /*This is introduced in IPMI1.5,this is required to be sent in + //send message command as a parameter,which is then used by BMC + //to identify the correct DPC session to send the mesage to. */ + BYTE channelNumber /*There are 3 different channels on which DPC communication goes on + //Emp - 1,Lan channel one - 6,Lan channel two(primary channel) - 7. */ + ) +{ + BOOL status; + BYTE responseData[MAX_IMB_RESP_SIZE]; + /* ImbResponseBuffer * resp = (ImbResponseBuffer *) responseData; */ + DWORD respLength = sizeof( responseData ); + BYTE requestData[MAX_IMB_RESP_SIZE]; + ImbRequestBuffer * req = (ImbRequestBuffer *) requestData; + int i,j; + + /*form the response packet first */ + req->req.rsSa = BMC_SA; + if (IpmiVersion == IPMI_09_VERSION) + req->req.cmd = WRITE_EMP_BUFFER; + else + req->req.cmd = SEND_MESSAGE; + req->req.netFn = APP_NETFN; + req->req.rsLun = 0; + + i = 0; + + /*checking for the IPMI version & then assigning the channel number for EMP + //Actually the channel number is same in both the versions.This is just to + //maintain the consistancy with the same method for LAN. + //This is the 1st byte of the SEND MESSAGE command. */ + if (IpmiVersion == IPMI_10_VERSION) + req->req.data[i++] = EMP_CHANNEL; + else if (IpmiVersion == IPMI_15_VERSION) + req->req.data[i++] = channelNumber; + + /*The second byte of data for SEND MESSAGE starts with session handle */ + req->req.data[i++] = sessionHandle; + + /*Then it is the response slave address for SEND MESSAGE. */ + req->req.data[i++] = ptr->rqSa; + + /*Then the net function + lun for SEND MESSAGE command. */ + req->req.data[i++] = (((ptr->nfLn & 0xfc) | 0x4) | ((ptr->seqLn) & 0x3)); + + /*Here the checksum is calculated.The checksum calculation starts after the channel number. + //so for the IPMI 1.5 version its a checksum of 3 bytes that is session handle,response slave + //address & netfun+lun. */ + if (IpmiVersion == IPMI_09_VERSION) + req->req.data[i++] = ((~(req->req.data[0] + req->req.data[1])) +1); + else + { + if (IpmiVersion == IPMI_10_VERSION) + req->req.data[i++] = ((~(req->req.data[1] + req->req.data[2])) +1); + else + req->req.data[i++] = ((~(req->req.data[2]+ req->req.data[3])) +1); + } + + /*This is the next byte of the message data for SEND MESSAGE command.It is the request + //slave address. */ + req->req.data[i++] = BMC_SA; /*though software is responding, we have to + //provide BMCs slave address as responder + //address. */ + + /*This is just the sequence number,which is the next byte of data for SEND MESSAGE */ + req->req.data[i++] = ( (ptr->seqLn & 0xfc) | (ptr->nfLn & 0x3) ); + + /*The next byte is the command like get software ID(00).*/ + req->req.data[i++] = ptr->cmd; + + /*after the cmd the data ,which is sent by DPC & is retrived using the get message earlier + // is sent back to DPC. */ + for ( j = 0 ; j < responseDataLen ; ++j,++i) + req->req.data[i] = responseDataBuf[j]; + + req->req.data[i] = 0; + + /*The last byte of data for SEND MESSAGE command is the check sum ,which is calculated + //from the next byte of the previous checksum that is the request slave address. */ + if (IpmiVersion == IPMI_09_VERSION) + j = 0; + else + { + if (IpmiVersion == IPMI_10_VERSION) + j = 1; + else + j = 2; + } + for ( ; j < ( i -3); ++j) + req->req.data[i] += req->req.data[j+3]; + req->req.data[i] = ~(req->req.data[i]) +1; + ++i; + req->req.dataLength = (BYTE)i; + + /*The flags & timeouts are used by the driver internally. */ + req->flags = 0; + req->timeOut = timeOut * 1000; /* convert to uSec units */ + + status = DeviceIoControl( hDevice, + ioctl_sendmsg, + requestData, + sizeof(requestData), + responseData, + sizeof( responseData ), + & respLength, + NULL + ); + + +#ifndef NO_MACRO_ARGS + DEBUG("%s: DeviceIoControl status = %d\n",__FUNCTION__, status); +#endif + + if (fdebug) { + printf("SendTimedEmp(%x,%x): status=%d cc=%x rlen=%d i=%d\n", + sessionHandle, channelNumber, + status,responseData[0],respLength,i); + _dump_buf("requestData",requestData,sizeof(requestData),0); + } + if ( (status != TRUE) || (respLength != 1) || (responseData[0] != 0) ) + { + return ACCESN_ERROR; + } + return ACCESN_OK; + + +} + +/*This is not a API exported by the driver in stricter sense. It is +//added to support EMP functionality. Upper level software could have +//implemented this function.(pai 5/4/99) */ +/*/////////////////////////////////////////////////////////////////////////// +// SendTimedLanMessageResponse +///////////////////////////////////////////////////////////////////////////// */ + +/*F* +// Name: SendTimedLanMessageResponse +// Purpose: This function sends a response message to the DPC Over Lan +// Context: +// Returns: OK else error status code +// Parameters: +// +// Notes: none +*F*/ + +ACCESN_STATUS +SendTimedLanMessageResponse( + ImbPacket *ptr, /* pointer to the original request from EMP */ + char *responseDataBuf, + int responseDataLen, + int timeOut /* how long to wait, in mSec units */ + ) +{ + BOOL status; + BYTE responseData[MAX_IMB_RESP_SIZE]; + /* ImbResponseBuffer * resp = (ImbResponseBuffer *) responseData; */ + DWORD respLength = sizeof( responseData ); + BYTE requestData[MAX_IMB_RESP_SIZE]; + ImbRequestBuffer * req = (ImbRequestBuffer *) requestData; + int i,j; + + /*form the response packet first */ + req->req.rsSa = BMC_SA; + if (IpmiVersion == IPMI_09_VERSION) + req->req.cmd = WRITE_EMP_BUFFER; + else + req->req.cmd = SEND_MESSAGE; + req->req.netFn = APP_NETFN; + + /* After discussion with firmware team (Shailendra), the lun number needs to stay at 0 + // even though the DPC over Lan firmware EPS states that the lun should be 1 for DPC + // Over Lan. - Simont (5/17/00) */ + req->req.rsLun = 0; + + i = 0; + if (IpmiVersion != IPMI_09_VERSION) + req->req.data[i++] = LAN_CHANNEL; + + req->req.data[i++] = ptr->rqSa; + req->req.data[i++] = (((ptr->nfLn & 0xfc) | 0x4) | ((ptr->seqLn) & 0x3)); + if (IpmiVersion == IPMI_09_VERSION) + req->req.data[i++] = ((~(req->req.data[0] + req->req.data[1])) +1); + else + req->req.data[i++] = ((~(req->req.data[1] + req->req.data[2])) +1); + + req->req.data[i++] = BMC_SA; /*though software is responding, we have to + //provide BMCs slave address as responder + //address. */ + + req->req.data[i++] = ( (ptr->seqLn & 0xfc) | (ptr->nfLn & 0x3) ); + + req->req.data[i++] = ptr->cmd; + for ( j = 0 ; j < responseDataLen ; ++j,++i) + req->req.data[i] = responseDataBuf[j]; + + req->req.data[i] = 0; + if (IpmiVersion == IPMI_09_VERSION) + j = 0; + else + j = 1; + for ( ; j < ( i -3); ++j) + req->req.data[i] += req->req.data[j+3]; + req->req.data[i] = ~(req->req.data[i]) +1; + ++i; + req->req.dataLength = (BYTE)i; + + req->flags = 0; + req->timeOut = timeOut * 1000; /* convert to uSec units */ + + status = DeviceIoControl( hDevice, + ioctl_sendmsg, + requestData, + sizeof(requestData), + responseData, + sizeof( responseData ), + & respLength, + NULL + ); + + if (fdebug) { + printf("SendTimedLan(): status=%d cc=%x rlen=%d i=%d\n", + status, responseData[0],respLength,i); + _dump_buf("requestData",requestData,sizeof(requestData),0); + } +#ifndef NO_MACRO_ARGS + DEBUG("%s: DeviceIoControl status = %d\n",__FUNCTION__, status); +#endif + + if ( (status != TRUE) || (respLength != 1) || (responseData[0] != 0) ) + { + return ACCESN_ERROR; + } + return ACCESN_OK; +} + + +/*This is not a API exported by the driver in stricter sense. It is +//added to support EMP functionality. Upper level software could have +//implemented this function.(pai 5/4/99) */ +/*/////////////////////////////////////////////////////////////////////////// +// SendTimedLanMessageResponse_Ex +///////////////////////////////////////////////////////////////////////////// */ + +/*F* +// Name: SendTimedLanMessageResponse_Ex +// Purpose: This function sends a response message to the DPC Over Lan +// Context: +// Returns: OK else error status code +// Parameters: +// +// Notes: none +*F*/ + +ACCESN_STATUS +SendTimedLanMessageResponse_Ex( + ImbPacket *ptr, /* pointer to the original request from EMP */ + char *responseDataBuf, + int responseDataLen, + int timeOut , /* how long to wait, in mSec units */ + BYTE sessionHandle, /*This is introduced in IPMI1.5,this is required to be sent in + //send message command as a parameter,which is then used by BMC + //to identify the correct DPC session to send the mesage to. */ + BYTE channelNumber /*There are 3 different channels on which DPC communication goes on + //Emp - 1,Lan channel one - 6,Lan channel two(primary channel) - 7. */ + ) +{ + BOOL status; + BYTE responseData[MAX_IMB_RESP_SIZE]; + /* ImbResponseBuffer * resp = (ImbResponseBuffer *) responseData; */ + DWORD respLength = sizeof( responseData ); + BYTE requestData[MAX_IMB_RESP_SIZE]; + ImbRequestBuffer * req = (ImbRequestBuffer *) requestData; + int i,j; + + /*form the response packet first */ + req->req.rsSa = BMC_SA; + if (IpmiVersion == IPMI_09_VERSION) + req->req.cmd = WRITE_EMP_BUFFER; + else + req->req.cmd = SEND_MESSAGE; + req->req.netFn = APP_NETFN; + + /* After discussion with firmware team (Shailendra), the lun number needs to stay at 0 + // even though the DPC over Lan firmware EPS states that the lun should be 1 for DPC + // Over Lan. - Simont (5/17/00) */ + req->req.rsLun = 0; + + i = 0; + + /*checking for the IPMI version & then assigning the channel number for Lan accordingly. + //This is the 1st byte of the SEND MESSAGE command. */ + if (IpmiVersion == IPMI_10_VERSION) + req->req.data[i++] = LAN_CHANNEL; + else if (IpmiVersion == IPMI_15_VERSION) + req->req.data[i++] = channelNumber; + + /*The second byte of data for SEND MESSAGE starts with session handle */ + req->req.data[i++] = sessionHandle; + + /*Then it is the response slave address for SEND MESSAGE. */ + req->req.data[i++] = ptr->rqSa; + + /*Then the net function + lun for SEND MESSAGE command. */ + req->req.data[i++] = (((ptr->nfLn & 0xfc) | 0x4) | ((ptr->seqLn) & 0x3)); + + /*Here the checksum is calculated.The checksum calculation starts after the channel number. + //so for the IPMI 1.5 version its a checksum of 3 bytes that is session handle,response slave + //address & netfun+lun. */ + if (IpmiVersion == IPMI_09_VERSION) + req->req.data[i++] = ((~(req->req.data[0] + req->req.data[1])) +1); + else + { + if (IpmiVersion == IPMI_10_VERSION) + req->req.data[i++] = ((~(req->req.data[1] + req->req.data[2])) +1); + else + req->req.data[i++] = ((~(req->req.data[2]+ req->req.data[3])) +1); + } + + /*This is the next byte of the message data for SEND MESSAGE command.It is the request + //slave address. */ + req->req.data[i++] = BMC_SA; /*though software is responding, we have to + //provide BMC's slave address as responder + //address. */ + + /*This is just the sequence number,which is the next byte of data for SEND MESSAGE */ + req->req.data[i++] = ( (ptr->seqLn & 0xfc) | (ptr->nfLn & 0x3) ); + + /*The next byte is the command like get software ID(00). */ + req->req.data[i++] = ptr->cmd; + + /*after the cmd the data ,which is sent by DPC & is retrived using the get message earlier + // is sent back to DPC. */ + for ( j = 0 ; j < responseDataLen ; ++j,++i) + req->req.data[i] = responseDataBuf[j]; + + req->req.data[i] = 0; + + /*The last byte of data for SEND MESSAGE command is the check sum ,which is calculated + //from the next byte of the previous checksum that is the request slave address. */ + if (IpmiVersion == IPMI_09_VERSION) + j = 0; + else + { + if (IpmiVersion == IPMI_10_VERSION) + j = 1; + else + j = 2; + } + for ( ; j < ( i -3); ++j) + req->req.data[i] += req->req.data[j+3]; + req->req.data[i] = ~(req->req.data[i]) +1; + ++i; + req->req.dataLength = (BYTE)i; + + /*The flags & timeouts are used by the driver internally */ + req->flags = 0; + req->timeOut = timeOut * 1000; /* convert to uSec units */ + + status = DeviceIoControl( hDevice, + ioctl_sendmsg, + requestData, + sizeof(requestData), + responseData, + sizeof( responseData ), + & respLength, + NULL + ); +#ifndef NO_MACRO_ARGS + DEBUG("%s: DeviceIoControl status = %d\n",__FUNCTION__, status); +#endif + if (fdebug) { + printf("SendTimedLan(%x,%x): status=%d cc=%x rlen=%d i=%d\n", + sessionHandle, channelNumber, + status,responseData[0],respLength,i); + if (responseData[0] != 0) /*0xcc == invalid request data*/ + { + BYTE *pb; + pb = (BYTE *)req->req.data; + printf("SendMessage data: %02x %02x %02x %02x %02x %02x %02x %02x\n", + pb[0], pb[1], pb[2], pb[3], pb[4], pb[5], pb[6], pb[7]); + _dump_buf("requestData",requestData,sizeof(requestData),0); + } + } + + if ( (status != TRUE) || (respLength != 1) || (responseData[0] != 0) ) + { + return ACCESN_ERROR; + } + return ACCESN_OK; +} + + + +/*///////////////////////////////////////////////////////////////////////// +//SendAsyncImbpRequest +/////////////////////////////////////////////////////////////////////////// */ +/*F* +// Name: SendAsyncImbpRequest +// Purpose: This function sends a request for Asynchronous IMB implemented function +// Context: Used by Upper level agents (sis modules) to access Asynchronous IMB implemented functionality. +// Returns: OK else error status code +// Parameters: +// reqPtr Pointer to Async IMB request +// seqNo Sequence Munber +// Notes: none +*F*/ +ACCESN_STATUS +SendAsyncImbpRequest ( + IMBPREQUESTDATA *reqPtr, /* request info and data */ + BYTE * seqNo /* sequence number used in creating IMB msg */ + ) +{ + + BOOL status; + BYTE responseData[MAX_IMB_RESP_SIZE]; + ImbResponseBuffer * resp = (ImbResponseBuffer *) responseData; + DWORD respLength = sizeof( responseData ); + BYTE requestData[MAX_IMB_RESP_SIZE]; + ImbRequestBuffer * req = (ImbRequestBuffer *) requestData; + + req->req.rsSa = reqPtr->rsSa; + req->req.cmd = reqPtr->cmdType; + req->req.netFn = reqPtr->netFn; + req->req.rsLun = reqPtr->rsLun; + req->req.dataLength = (BYTE)reqPtr->dataLength; + + memcpy( req->req.data, reqPtr->data, reqPtr->dataLength ); + + req->flags = NO_RESPONSE_EXPECTED; + req->timeOut = 0; /* no timeouts for async sends */ + + status = DeviceIoControl( hDevice, + ioctl_sendmsg, + requestData, + sizeof( requestData ), + & responseData, + sizeof( responseData ), + & respLength, + NULL + ); +#ifndef NO_MACRO_ARGS + DEBUG("%s: DeviceIoControl status = %d\n",__FUNCTION__, status); +#endif + + if( status != TRUE ) { + DWORD error; + error = GetLastError(); + return ACCESN_ERROR; + } + if( respLength != 2 ) { + return ACCESN_ERROR; + } + /* + // give the caller his sequence number + */ + *seqNo = resp->data[0]; + + return ACCESN_OK; + +} + +/*/////////////////////////////////////////////////////////////////////////// +//GetAsyncImbpMessage +///////////////////////////////////////////////////////////////////////////// */ +/*F* +// Name: GetAsyncImbpMessage +// Purpose: This function gets the next available async message with a message id +// greater than SeqNo. The message looks like an IMB packet +// and the length and Sequence number is returned +// Context: Used by Upper level agents (sis modules) to access Asynchronous IMB implemented functionality. +// Returns: OK else error status code +// Parameters: +// msgPtr Pointer to Async IMB request +// msgLen Length +// timeOut Time to wait +// seqNo Sequence Munber +// Notes: none +*F*/ + +ACCESN_STATUS +GetAsyncImbpMessage ( + ImbPacket * msgPtr, /* request info and data */ + DWORD *msgLen, /* IN - length of buffer, OUT - msg len */ + DWORD timeOut, /* how long to wait for the message */ + ImbAsyncSeq *seqNo, /* previously returned seq number */ + /* (or ASYNC_SEQ_START) */ + DWORD channelNumber + ) +{ + + BOOL status; + BYTE responseData[MAX_ASYNC_RESP_SIZE], lun, b; + ImbAsyncResponse * resp = (ImbAsyncResponse *) responseData; + DWORD respLength = sizeof( responseData ); + ImbAsyncRequest req; + BYTE *msgb; + + while(1) + { + + + if( (msgPtr == NULL) || (msgLen == NULL) || ( seqNo == NULL) ) + return ACCESN_ERROR; + + msgb = (BYTE *)msgPtr; + req.timeOut = timeOut * 1000; /* convert to uSec units */ + req.lastSeq = *seqNo; + + + status = DeviceIoControl( hDevice, + IOCTL_IMB_GET_ASYNC_MSG, + & req, + sizeof( req ), + & responseData, + sizeof( responseData ), + & respLength, + NULL + ); + +#ifndef NO_MACRO_ARGS + DEBUG("%s: DeviceIoControl status = %d\n",__FUNCTION__, status); +#endif + + if( status != TRUE ) { + DWORD error = GetLastError(); + /* + // handle "msg not available" specially. it is + // different from a random old error. + */ + switch( error ) { + case IMB_MSG_NOT_AVAILABLE: + return ACCESN_END_OF_DATA; + default: + return ACCESN_ERROR; + } + return ACCESN_ERROR; + } + if( respLength < MIN_ASYNC_RESP_SIZE ) { + return ACCESN_ERROR; + } + respLength -= MIN_ASYNC_RESP_SIZE; + + if( *msgLen < respLength ) { + return ACCESN_ERROR; + } + + + /*same code as in NT section */ + if ( IpmiVersion == IPMI_09_VERSION) + { + + switch( channelNumber) { + case IPMB_CHANNEL: + lun = IPMB_LUN; + break; + + case EMP_CHANNEL: + lun = EMP_LUN; + break; + + default: + lun = RESERVED_LUN; + break; + } + + b = (((ImbPacket *)(resp->data))->nfLn) & 0x3; + if (channelNumber != ANY_CHANNEL) { + if ( (lun == RESERVED_LUN) || + (lun != b) ) + { + *seqNo = resp->thisSeq; + continue; + } + } + + memcpy( msgPtr, resp->data, respLength ); + *msgLen = respLength; + /* Hack to return actual lun */ + if (channelNumber == ANY_CHANNEL) + msgb[respLength] = b; + } + else + { + /* it is a 1.0 or above version */ + + b = resp->data[0]; + if ((channelNumber != ANY_CHANNEL) && + (channelNumber != b)) + { + *seqNo = resp->thisSeq; + continue; + } + + memcpy(msgPtr, &(resp->data[1]), respLength-1); + *msgLen = respLength-1; + /* Hack to return actual channel */ + if (channelNumber == ANY_CHANNEL) + msgb[respLength-1] = b; + + } + + /* + // give the caller his sequence number + */ + *seqNo = resp->thisSeq; + + return ACCESN_OK; + + } /*while (1) */ +} + + +/*/////////////////////////////////////////////////////////////////////////// +//GetAsyncImbpMessage_Ex +///////////////////////////////////////////////////////////////////////////// */ +/*F* +// Name: GetAsyncImbpMessage_Ex +// Purpose: This function gets the next available async message with a message id +// greater than SeqNo. The message looks like an IMB packet +// and the length and Sequence number is returned +// Context: Used by Upper level agents (sis modules) to access Asynchronous IMB implemented functionality. +// Returns: OK else error status code +// Parameters: +// msgPtr Pointer to Async IMB request +// msgLen Length +// timeOut Time to wait +// seqNo Sequence Munber +// Notes: none +*F*/ + +ACCESN_STATUS +GetAsyncImbpMessage_Ex ( + ImbPacket * msgPtr, /* request info and data */ + DWORD *msgLen, /* IN - length of buffer, OUT - msg len */ + DWORD timeOut, /* how long to wait for the message */ + ImbAsyncSeq *seqNo, /* previously returned seq number */ + /* (or ASYNC_SEQ_START) */ + DWORD channelNumber, + BYTE * sessionHandle, + BYTE * privilege + ) +{ + + BOOL status; + BYTE responseData[MAX_ASYNC_RESP_SIZE], lun, b; + ImbAsyncResponse * resp = (ImbAsyncResponse *) responseData; + DWORD respLength = sizeof( responseData ); + ImbAsyncRequest req; + BYTE *msgb; + + while(1) + { + + + if( (msgPtr == NULL) || (msgLen == NULL) || ( seqNo == NULL) ) + return ACCESN_ERROR; + + msgb = (BYTE *)msgPtr; + req.timeOut = timeOut * 1000; /* convert to uSec units */ + req.lastSeq = *seqNo; + + + status = DeviceIoControl( hDevice, + IOCTL_IMB_GET_ASYNC_MSG, + & req, + sizeof( req ), + & responseData, + sizeof( responseData ), + & respLength, + NULL + ); + +#ifndef NO_MACRO_ARGS + DEBUG("%s: DeviceIoControl status = %d\n",__FUNCTION__, status); +#endif + + if( status != TRUE ) { + DWORD error = GetLastError(); + /* + // handle "msg not available" specially. it is + // different from a random old error. + */ + switch( error ) { + case IMB_MSG_NOT_AVAILABLE: + return ACCESN_END_OF_DATA; + default: + return ACCESN_ERROR; + } + return ACCESN_ERROR; + } + if( respLength < MIN_ASYNC_RESP_SIZE ) { + return ACCESN_ERROR; + } + respLength -= MIN_ASYNC_RESP_SIZE; + + if( *msgLen < respLength ) { + return ACCESN_ERROR; + } + + + /*same code as in NT section */ + if ( IpmiVersion == IPMI_09_VERSION) + { + + switch( channelNumber) { + case IPMB_CHANNEL: + lun = IPMB_LUN; + break; + + case EMP_CHANNEL: + lun = EMP_LUN; + break; + + default: + lun = RESERVED_LUN; + break; + } + + b = ((((ImbPacket *)(resp->data))->nfLn) & 0x3); + if (channelNumber != ANY_CHANNEL) { + if ( (lun == RESERVED_LUN) || + (lun != b) ) + { + *seqNo = resp->thisSeq; + continue; + } + } + + memcpy( msgPtr, resp->data, respLength ); + *msgLen = respLength; + /* Hack to return actual lun */ + if (channelNumber == ANY_CHANNEL) + msgb[respLength] = b; + + } + else + { + if((sessionHandle ==NULL) || (privilege ==NULL)) + return ACCESN_ERROR; + + /*With the new IPMI version the get message command returns the + //channel number along with the privileges.The 1st 4 bits of the + //second byte of the response data for get message command represent + //the channel number & the last 4 bits are the privileges. */ + *privilege = (resp->data[0] & 0xf0)>> 4; + +#ifndef NO_MACRO_ARGS + DEBUG("GetAsy: chan=%x chan_parm=%x\n",resp->data[0],channelNumber); +#endif + b = (resp->data[0] & 0x0f); + if ((channelNumber != ANY_CHANNEL) && + (channelNumber != b) ) + { + *seqNo = resp->thisSeq; + continue; + } + + + /*The get message command according to IPMI 1.5 spec now even + //returns the session handle.This is required to be captured + //as it is required as request data for send message command. */ + *sessionHandle = resp->data[1]; + memcpy( msgPtr, &(resp->data[2]), respLength-1 ); + *msgLen = respLength-1; + + /* Hack to return actual channel */ + if (channelNumber == ANY_CHANNEL) + msgb[respLength-1] = b; + + } + + /* + // give the caller his sequence number + */ + *seqNo = resp->thisSeq; + + return ACCESN_OK; + + } /*while (1) */ +} + + + +/*////////////////////////////////////////////////////////////////////////////// +//IsAsyncMessageAvailable +///////////////////////////////////////////////////////////////////////////// */ +/*F* +// Name: IsMessageAvailable +// Purpose: This function waits for an Async Message +// +// Context: Used by Upper level agents access Asynchronous IMB based +// messages +// Returns: OK else error status code +// Parameters: +// eventId +// +// Notes: This call will block the calling thread if no Async events are +// are available in the queue. +// +*F*/ +ACCESN_STATUS +IsAsyncMessageAvailable (HandleType eventId ) +{ + int dummy; + int respLength = 0; + BOOL status; + + /* confirm that app is not using a bad Id */ + + + if ( AsyncEventHandle != eventId) { +#ifdef LINUX + printf("Invalid AsyncHandle %x!=%x\n",AsyncEventHandle,eventId); +#endif + return ACCESN_ERROR; + } + + dummy = 0; + status = DeviceIoControl(hDevice, + IOCTL_IMB_CHECK_EVENT, + &AsyncEventHandle, + sizeof(HandleType), + &dummy, + sizeof(int), + (LPDWORD) & respLength, + NULL + ); + // if (fdebug) + // printf("IsAsyncMessageAvail: status=%d rlen=%d dummy=%x\n", + // status, respLength, dummy); +#ifndef NO_MACRO_ARGS + DEBUG("%s: DeviceIoControl status = %d\n",__FUNCTION__, status); +#endif + + if( status != TRUE ) + return ACCESN_ERROR; + + + return ACCESN_OK; +} + + +/*I have retained this commented code because later we may want to use +//DPC message specific Processing (pai 11/21) */ + +#ifdef NOT_COMPILED_BUT_LEFT_HERE_FOR_NOW + +/*////////////////////////////////////////////////////////////////////////////// +//GetAsyncDpcMessage +///////////////////////////////////////////////////////////////////////////// */ +/*F* +// Name: GetAsyncDpcMessage +// Purpose: This function gets the next available async message from +// the DPC client. +// +// Context: Used by Upper level agents access Asynchronous IMB based +// messages sent by the DPC client. +// Returns: OK else error status code +// Parameters: +// msgPtr Pointer to Async IMB request +// msgLen Length +// timeOut Time to wait +// seqNo Sequence Munber +// Notes: This call will block the calling thread if no Async events are +// are available in the queue. +// +*F*/ + +ACCESN_STATUS +GetAsyncDpcMessage ( + ImbPacket * msgPtr, /* request info and data */ + DWORD * msgLen, /* IN - length of buffer, OUT - msg len */ + DWORD timeOut, /* how long to wait for the message */ + ImbAsyncSeq * seqNo, /* previously returned seq number (or ASYNC_SEQ_START) */ + ) +{ + BOOL status; + BYTE responseData[MAX_ASYNC_RESP_SIZE]; + ImbAsyncResponse * resp = (ImbAsyncResponse *) responseData; + DWORD respLength = sizeof( responseData ); + ImbAsyncRequest req; + + if( msgPtr == NULL || msgLen == NULL || seqNo == NULL ) + return ACCESN_ERROR; + + req.lastSeq = *seqNo; + + + hEvt = CreateEvent (NULL, TRUE, FALSE, NULL) ; + if (!hEvt) { + return ACCESN_ERROR; + } + + status = DeviceIoControl( hDevice, + IOCTL_IMB_GET_DPC_MSG, + & req, + sizeof( req ), + & responseData, + sizeof( responseData ), + & respLength, + &ovl + ); + + if( status != TRUE ) { + DWORD error = GetLastError(); + /* + // handle "msg not available" specially. it is different from + // a random old error. + // + */ + if (!status) + { + switch (error ) + { + case ERROR_IO_PENDING: + + WaitForSingleObject (hEvt, INFINITE) ; + ResetEvent (hEvt) ; + break; + + case IMB_MSG_NOT_AVAILABLE: + + CloseHandle(hEvt); + return ACCESN_END_OF_DATA; + + default: + CloseHandle(hEvt); + return ACCESN_ERROR; + + } + } + + + + if ( + ( GetOverlappedResult(hDevice, + &ovl, + (LPDWORD)&respLength, + TRUE + ) == 0 ) || (respLength <= 0) + ) + + { + + CloseHandle(hEvt); + return ACCESN_ERROR; + + } + + + } + + if( respLength < MIN_ASYNC_RESP_SIZE ) { + CloseHandle(hEvt); + return ACCESN_ERROR; + } + + respLength -= MIN_ASYNC_RESP_SIZE; + + if( *msgLen < respLength ) { + + /* The following code should have been just return ACCESN_out_of_range */ + CloseHandle(hEvt); + return ACCESN_ERROR; + } + + memcpy( msgPtr, resp->data, respLength ); + + *msgLen = respLength; + /* + // give the caller his sequence number + */ + *seqNo = resp->thisSeq; + + CloseHandle(hEvt); + + + return ACCESN_OK; + +} +#endif /*NOT_COMPILED_BUT_LEFT_HERE_FOR_NOW*/ + + + +/*///////////////////////////////////////////////////////////////////////////// +//RegisterForImbAsyncMessageNotification +///////////////////////////////////////////////////////////////////////////// */ +/*F* +// Name: RegisterForImbAsyncMessageNotification +// Purpose: This function Registers the calling application +// for Asynchronous notification when a sms message +// is available with the IMB driver. +// +// Context: Used by Upper level agents to know that an async +// SMS message is available with the driver. +// Returns: OK else error status code +// Parameters: +// handleId pointer to the registration handle +// +// Notes: The calling application should use the returned handle to +// get the Async messages.. +*F*/ +ACCESN_STATUS +RegisterForImbAsyncMessageNotification (HandleType *handleId) + +{ + BOOL status; + DWORD respLength ; + int dummy; + + /*allow only one app to register */ + + if( (handleId == NULL ) || (AsyncEventHandle) ) + return ACCESN_ERROR; + + + status = DeviceIoControl(hDevice, + IOCTL_IMB_REGISTER_ASYNC_OBJ, + &dummy, + sizeof( int ), + &AsyncEventHandle, + sizeof(HandleType), + (LPDWORD) & respLength, + NULL + ); +#ifndef NO_MACRO_ARGS + DEBUG("%s: DeviceIoControl status = %d\n",__FUNCTION__, status); +#endif + + if( (respLength != sizeof(int)) || (status != TRUE )) { + if (fdebug) { + printf("RegisterForImbAsync error status=%d, len=%d sizeint=%d\n", status, respLength, sizeof(int)); + if( respLength != sizeof(int)) printf("Async len err\n"); + if( status != TRUE) printf("Async status err\n"); + } + return ACCESN_ERROR; + } + + *handleId = AsyncEventHandle; + +#ifndef NO_MACRO_ARGS + DEBUG("handleId = %x AsyncEventHandle %x\n", *handleId, AsyncEventHandle); +#endif + return ACCESN_OK; +} + + + + + +/*///////////////////////////////////////////////////////////////////////////// +//UnRegisterForImbAsyncMessageNotification +///////////////////////////////////////////////////////////////////////////// */ +/*F* +// Name: UnRegisterForImbAsyncMessageNotification +// Purpose: This function un-registers the calling application +// for Asynchronous notification when a sms message +// is available with the IMB driver. +// +// Context: Used by Upper level agents to un-register +// for async. notification of sms messages +// Returns: OK else error status code +// Parameters: +// handleId pointer to the registration handle +// iFlag value used to determine where this function was called from +// _it is used currently on in NetWare environment_ +// +// Notes: +*F*/ +ACCESN_STATUS +UnRegisterForImbAsyncMessageNotification (HandleType handleId, int iFlag) + +{ + BOOL status; + DWORD respLength ; + int dummy; + + iFlag = iFlag; /* to keep compiler happy We are not using this flag*/ + + if ( AsyncEventHandle != handleId) + return ACCESN_ERROR; + + status = DeviceIoControl(hDevice, + IOCTL_IMB_DEREGISTER_ASYNC_OBJ, + &AsyncEventHandle, + sizeof(HandleType), + &dummy, + (DWORD)sizeof(int ), + (LPDWORD) & respLength, + NULL + ); +#ifndef NO_MACRO_ARGS + DEBUG("%s: DeviceIoControl status = %d\n",__FUNCTION__, status); +#endif + + if( status != TRUE ) + return ACCESN_ERROR; + + return ACCESN_OK; +} + + +/*/////////////////////////////////////////////////////////////////////////// +// SetShutDownCode +///////////////////////////////////////////////////////////////////////////// */ +/*F* +// Name: SetShutDownCode +// Purpose: To set the shutdown action code +// Context: Called by the System Control Subsystem +// Returns: none +// Parameters: +// code shutdown action code which can be either +// SD_NO_ACTION, SD_RESET, SD_POWER_OFF as defined in imb_if.h +*F*/ + +ACCESN_STATUS +SetShutDownCode ( + int delayTime, /* time to delay in 100ms units */ + int code /* what to do when time expires */ + ) +{ + DWORD retLength; + BOOL status; + ShutdownCmdBuffer cmd; + + /* + // If Imb driver is not present return AccessFailed + */ + if(hDevice == INVALID_HANDLE_VALUE) + return ACCESN_ERROR; + + cmd.code = code; + cmd.delayTime = delayTime; + + status = DeviceIoControl( hDevice, + IOCTL_IMB_SHUTDOWN_CODE, + & cmd, + sizeof( cmd ), + NULL, + 0, + & retLength, + NULL + ); +#ifndef NO_MACRO_ARGS + DEBUG("%s: DeviceIoControl status = %d\n",__FUNCTION__, status); +#endif + + if(status == TRUE) + return ACCESN_OK; + else + return ACCESN_ERROR; +} + +#ifdef IMB_MEMORY +/*///////////////////////////////////////////////////////////////////////// +// MapPhysicalMemory +/////////////////////////////////////////////////////////////////////////// */ +/*F* +// Name: MapPhysicalMemory +// Purpose: This function maps specified range of physical memory in calling +// pocesse's address space +// Context: Used by Upper level agents (sis modules) to access +// system physical memory +// Returns: ACCESN_OK else error status code +// Parameters: +// +// startAddress starting physical address of the memory to be mapped +// addressLength length of the physical memory to be mapped +// virtualAddress pointer to the mapped virtual address +// Notes: none +*F*/ +/*/////////////////////////////////////////////////////////////////////////// +// UnmapPhysicalMemory +//////////////////////////////////////////////////////////////////////////// */ +/*F* +// Name: UnMapPhysicalMemory +// Purpose: This function unmaps the previously mapped physical memory +// Context: Used by Upper level agents (sis modules) +// Returns: ACCESN_OK else error status code +// Parameters: +// +// addressLength length of the physical memory to be mapped +// virtualAddress pointer to the mapped virtual address +// Notes: none +*F*/ +#ifdef WIN32 +ACCESN_STATUS +MapPhysicalMemory ( + int startAddress, // physical address to map in + int addressLength, // how much to map + int *virtualAddress // where it got mapped to + ) +{ + DWORD retLength; + BOOL status; + PHYSICAL_MEMORY_INFO pmi; + + if ( startAddress == (int) NULL || addressLength <= 0 ) + return ACCESN_OUT_OF_RANGE; + + pmi.InterfaceType = Internal; + pmi.BusNumber = 0; + pmi.BusAddress.HighPart = (LONG)0x0; + pmi.BusAddress.LowPart = (LONG)startAddress; + pmi.AddressSpace = (LONG) 0; + pmi.Length = addressLength; + + status = DeviceIoControl ( hDevice, + IOCTL_IMB_MAP_MEMORY, + & pmi, + sizeof(PHYSICAL_MEMORY_INFO), + virtualAddress, + sizeof(PVOID), + & retLength, + 0 + ); + if( status == TRUE ) { + return ACCESN_OK; + } else { + return ACCESN_ERROR; + } +} + +ACCESN_STATUS +UnmapPhysicalMemory ( + int virtualAddress, // what memory to unmap + int Length ) +{ + DWORD retLength; + BOOL status; + + status = DeviceIoControl ( hDevice, + IOCTL_IMB_UNMAP_MEMORY, + & virtualAddress, + sizeof(PVOID), + NULL, + 0, + & retLength, + 0 + ); + + if( status == TRUE ) { + return ACCESN_OK; + } else { + return ACCESN_ERROR; + } +} + +#else /*Linux, SCO, UNIX, etc.*/ + +ACCESN_STATUS +MapPhysicalMemory(int startAddress,int addressLength, int *virtualAddress ) +{ + int fd, i; + unsigned int length = addressLength; + off_t startpAddress = (off_t)startAddress; + unsigned int diff; + caddr_t startvAddress; + + if ((startAddress == (int) NULL) || (addressLength <= 0)) + return ACCESN_ERROR; + + if ( (fd = open("/dev/mem", O_RDONLY)) < 0) { + char buf[128]; + + sprintf(buf,"%s %s: open(%s) failed", + __FILE__,__FUNCTION__,"/dev/mem"); + perror(buf); + return ACCESN_ERROR ; + } + + /* aliging the offset to a page boundary and adjusting the length */ + diff = (int)startpAddress % PAGESIZE; + startpAddress -= diff; + length += diff; + + if ( (startvAddress = mmap( (caddr_t)0, + length, + PROT_READ, + MAP_SHARED, + fd, + startpAddress + ) ) == (caddr_t)-1) + { + char buf[128]; + + sprintf(buf,"%s %s: mmap failed", __FILE__,__FUNCTION__); + perror(buf); + close(fd); + return ACCESN_ERROR; + } +#ifndef NO_MACRO_ARGS + DEBUG("%s: mmap of 0x%x success\n",__FUNCTION__,startpAddress); +#endif +#ifdef LINUX_DEBUG_MAX +/* dont want this memory dump for normal level of debugging. +// So, I have put it under a stronger debug symbol. mahendra */ + + for(i=0; i < length; i++) + { + printf("0x%x ", (startvAddress[i])); + if(isascii(startvAddress[i])) { + printf("%c ", (startvAddress[i])); + } + } +#endif /*LINUX_DEBUG_MAX */ + + *virtualAddress = (int)(startvAddress + diff); + return ACCESN_OK; +} + +ACCESN_STATUS +UnmapPhysicalMemory( int virtualAddress, int Length ) +{ + unsigned int diff = 0; + + /* page align the virtual address and adjust length accordingly */ + diff = ((unsigned int) virtualAddress) % PAGESIZE; + virtualAddress -= diff; + Length += diff; +#ifndef NO_MACRO_ARGS + DEBUG("%s: calling munmap(0x%x,%d)\n",__FUNCTION__,virtualAddress,Length); +#endif + + if(munmap((caddr_t)virtualAddress, Length) != 0) + { + char buf[128]; + + sprintf(buf,"%s %s: munmap failed", __FILE__,__FUNCTION__); + perror(buf); + return ACCESN_ERROR; + + } +#ifndef NO_MACRO_ARGS + DEBUG("%s: munmap(0x%x,%d) success\n",__FUNCTION__,virtualAddress,Length); +#endif + + return ACCESN_OK; +} +#endif /*unix*/ + +#endif /*IMB_MEMORY*/ + + +/*///////////////////////////////////////////////////////////////////////////// +// GetIpmiVersion +//////////////////////////////////////////////////////////////////////////// */ + +/*F* +// Name: GetIpmiVersion +// Purpose: This function returns current IPMI version +// Context: +// Returns: IPMI version +// Parameters: +// reqPtr +// timeOut +// respDataPtr +// respLen +// Notes: svuppula +*F*/ +BYTE GetIpmiVersion() +{ + return ((BYTE)IpmiVersion); +} + +#ifdef IMBDLL +/* Inlude this routine if building WIN32 imbapi.dll */ +BOOL WINAPI DllMain(HINSTANCE hInstance, ULONG ulReason, LPVOID pvReserved) +{ + switch(ulReason) + { + case DLL_PROCESS_ATTACH: + case DLL_THREAD_ATTACH: + break; + case DLL_PROCESS_DETACH: + case DLL_THREAD_DETACH: + break; + default: + return FALSE; + } + return TRUE; +} +#endif + +#endif +/*end of imbapi.c*/ |