summaryrefslogtreecommitdiff
path: root/src/plugins/imb/imbapi.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/imb/imbapi.c')
-rw-r--r--src/plugins/imb/imbapi.c2090
1 files changed, 2090 insertions, 0 deletions
diff --git a/src/plugins/imb/imbapi.c b/src/plugins/imb/imbapi.c
new file mode 100644
index 0000000..37d3abe
--- /dev/null
+++ b/src/plugins/imb/imbapi.c
@@ -0,0 +1,2090 @@
+/*M*
+// PVCS:
+// $Workfile: imbapi.c $
+// $Revision: 1.5 $
+// $Modtime: 06 Aug 2001 13:16:56 $
+// $Author: stybla $
+//
+// 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
+//
+//
+*M*/
+/*----------------------------------------------------------------------*
+The BSD License
+Copyright (c) 2002, Intel Corporation
+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.
+ *----------------------------------------------------------------------*/
+/*
+ * $Log: imbapi.c,v $
+ * Revision 1.5 2013/07/22 08:35:23 stybla
+ * ID: 65 - Fixes for configure.in for cross compilation
+ *
+ * 'src/plugins/imb/imbapi.c' - don't cast NULL to int, ever!!!
+ *
+ * Revision 1.4 2013/07/21 11:33:57 stybla
+ * ID: 65 - Fixes for configure.in for cross compilation
+ *
+ * NULL should never be cast to an int.
+ *
+ * Commit for Dan Gora
+ *
+ * Revision 1.3 2013/01/18 12:46:52 ledva
+ * 3600962 descriptor leaks
+ *
+ * Revision 1.2 2004/08/31 23:52:58 iceblink
+ * fix lots of little errors that show up with -Werror -Wall
+ *
+ * Revision 1.1 2004/08/27 16:33:25 iceblink
+ * add support for Intel IMB kernel driver (for legacy kernel support)
+ * imbapi.[ch] code is BSD licensed and taken from panicsel.sf.net
+ *
+ *
+ * Rev 1.12ac 04 Apr 2002 13:17:58 arcress
+ * Mods for open-source & various compile cleanup mods
+ *
+ * Rev 1.12 06 Aug 2001 13:17:58 spoola
+ * Fixed tracker items #15667, #15666, #15664
+ *
+ * Rev 1.0 05 Sep 1999 17:20:30 mramacha
+ * Linux checkin
+ *
+ * Note: This file is derived from the NTWORK version of the imbapi.c
+ * It was decided to create OS specific ones for Linux and Solaris.
+ * It has all the fixes that went into the imbapi.c up to Rev 1.12
+ * in the 2.2 NTWORK branch.
+ */
+
+#define IMB_API
+
+#ifdef WIN32
+#define NO_MACRO_ARGS 1
+#include <windows.h>
+#include <stdio.h>
+
+#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>
+#endif
+#include "imbapi.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.*/
+#ifndef NO_MACRO_ARGS
+#ifdef LINUX_DEBUG
+#define DEBUG(format, args...) printf(format, ##args)
+#else
+#define DEBUG(format, args...)
+#endif
+#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 */
+
+
+/*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 exsisting policy of using
+// pre-processor directives to separate os-specific code (pai 11/21) */
+
+HANDLE AsyncEventHandle = 0;
+//static void * AsyncEventObject = 0;
+static int IpmiVersion;
+
+/*////////////////////////////////////////////////////////////////////////////
+// GLOBAL VARIABLES
+///////////////////////////////////////////////////////////////////////////// */
+
+IO_STATUS_BLOCK NTstatus; /*dummy place holder. See deviceiocontrol. */
+static HANDLE hDevice1;
+static HANDLE hDevice;
+/*mutex_t deviceMutex; */
+static int fDriverTyp; /*from ipmicmd.c*/
+
+/*////////////////////////////////////////////////////////////////////
+// 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
+int open_imb(void)
+{
+/* 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[16];
+ DWORD respLength;
+ BYTE completionCode;
+
+ if (hDevice1 == 0) /*INVALID_HANDLE_VALUE*/
+ {
+ //
+ // Open IMB driver device
+ //
+ hDevice = CreateFile( "\\\\.\\Imb",
+ GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL
+ );
+ if (hDevice == NULL || hDevice == INVALID_HANDLE_VALUE)
+ return (0); /*FALSE*/
+
+ // 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 = 16;
+ if ( (SendTimedImbpRequest ( &requestData, (DWORD)400,
+ respBuffer, &respLength, &completionCode
+ ) != ACCESN_OK ) || ( completionCode != 0) )
+ {
+ CloseHandle(hDevice);
+ return (0); /*FALSE*/
+ }
+ hDevice1 = hDevice;
+
+ if (respLength < (IPMI10_GET_DEVICE_ID_RESP_LENGTH-1))
+ IpmiVersion = IPMI_09_VERSION;
+ else {
+ if ( respBuffer[4] == 0x51 )
+ IpmiVersion = IPMI_15_VERSION;
+ else
+ IpmiVersion = IPMI_10_VERSION;
+ }
+ }
+ return (1); /*TRUE*/
+
+} /*end open_imb for Win32 */
+
+#else /* LINUX, SCO_UW, etc. */
+
+int open_imb(void)
+{
+/* 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[16];
+ DWORD respLength;
+ BYTE completionCode;
+
+ int my_ret_code;
+
+ if (hDevice1 == 0)
+ {
+#ifndef NO_MACRO_ARGS
+ DEBUG("%s: opening the driver\n", __FUNCTION__);
+#endif
+ /*
+ printf("open_imb: "
+ "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)
+ {
+ char buf[128];
+
+ hDevice1 = 0;
+ if (fDriverTyp != 0) { /*not 1st time*/
+ sprintf(buf,"%s %s: open(%s) failed",
+ __FILE__,__FUNCTION__,IMB_DEVICE);
+ perror(buf);
+ }
+ return (0);
+ }
+
+ /* 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 = 16;
+#ifndef NO_MACRO_ARGS
+ DEBUG("%s: opened driver, getting IPMI version\n", __FUNCTION__);
+#endif
+ if ( ((my_ret_code = SendTimedImbpRequest(&requestData, (DWORD)400,
+ respBuffer, (int *)&respLength, &completionCode)
+ ) != ACCESN_OK ) || ( completionCode != 0) )
+ {
+ printf("%s: SendTimedImbpRequest error. Ret = %d CC = 0x%X\n",
+ __FUNCTION__, my_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] == 0x51 )
+ IpmiVersion = IPMI_15_VERSION;
+ else
+ IpmiVersion = IPMI_10_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
+
+/*---------------------------------------------------------------------*
+ * ipmi_open_ia & ipmi_close_ia
+ *---------------------------------------------------------------------*/
+int ipmi_open_ia(void)
+{
+ int rc = 0;
+ rc = open_imb(); /*sets hDevice1*/
+ if (rc == 1) rc = 0;
+ else rc = -1;
+ return(rc);
+}
+
+int ipmi_close_ia(void)
+{
+ int rc = 0;
+ if (hDevice1 != 0) {
+#ifdef WIN32
+ CloseHandle(hDevice1);
+#else
+ rc = close(hDevice1);
+#endif
+ }
+ return(rc);
+}
+
+#ifndef WIN32
+/*///////////////////////////////////////////////////////////////////////////
+// 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(
+ HANDLE dummey_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;
+ int ioctl_status;
+
+ rc = open_imb();
+ if (rc == 0) {
+ return FALSE;
+ }
+
+ /*
+ //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
+ if (cbInBuffer > 41) cbInBuffer = 41; /* Intel driver max buf */
+
+ 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.*/
+
+ if ( (ioctl_status = ioctl(hDevice1, dwIoControlCode,&s) ) <0) {
+#ifndef NO_MACRO_ARGS
+ DEBUG("%s %s: ioctl cmd = 0x%x failed",
+ __FILE__,__FUNCTION__,dwIoControlCode);
+#endif
+ /* mutex_unlock(&deviceMutex); */
+ return FALSE;
+ }
+ /* 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
+
+/*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_IMB_SEND_MESSAGE,
+ 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 = i;
+
+ req->flags = 0;
+ req->timeOut = timeOut * 1000; /* convert to uSec units */
+
+
+ status = DeviceIoControl( hDevice,
+ IOCTL_IMB_SEND_MESSAGE,
+ 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 = 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_IMB_SEND_MESSAGE,
+ 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) */
+/*///////////////////////////////////////////////////////////////////////////
+// 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 = i;
+
+ req->flags = 0;
+ req->timeOut = timeOut * 1000; /* convert to uSec units */
+
+
+ status = DeviceIoControl( hDevice,
+ IOCTL_IMB_SEND_MESSAGE,
+ 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) */
+/*///////////////////////////////////////////////////////////////////////////
+// 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 = 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_IMB_SEND_MESSAGE,
+ 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;
+}
+
+/*///////////////////////////////////////////////////////////////////////////
+// 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 dest controller */
+ )
+{
+ BYTE responseData[MAX_BUFFER_SIZE];
+ ImbResponseBuffer * resp = (ImbResponseBuffer *) responseData;
+ DWORD respLength = sizeof( responseData );
+ BYTE requestData[MAX_BUFFER_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 = reqPtr->dataLength;
+
+#ifndef NO_MACRO_ARGS
+ DEBUG("cmd=%02x, pdata=%p, datalen=%x\n", req->req.cmd,
+ reqPtr->data, reqPtr->dataLength );
+#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
+
+
+ status = DeviceIoControl( hDevice,
+ IOCTL_IMB_SEND_MESSAGE,
+ requestData,
+ sizeof( requestData ),
+ & 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 );
+#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;
+}
+
+
+/*/////////////////////////////////////////////////////////////////////////
+//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 = 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_IMB_SEND_MESSAGE,
+ 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;
+ ImbAsyncResponse * resp = (ImbAsyncResponse *) responseData;
+ DWORD respLength = sizeof( responseData );
+ ImbAsyncRequest req;
+
+ while(1)
+ {
+
+
+ if( (msgPtr == NULL) || (msgLen == NULL) || ( seqNo == NULL) )
+ return ACCESN_ERROR;
+
+ 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;
+ }
+
+ if ( (lun == RESERVED_LUN) ||
+ (lun != ((((ImbPacket *)(resp->data))->nfLn) & 0x3 ))
+ )
+ {
+ *seqNo = resp->thisSeq;
+ continue;
+ }
+
+
+ memcpy( msgPtr, resp->data, respLength );
+ *msgLen = respLength;
+
+ }
+ else
+ {
+ /* it is a 1.0 or above version */
+
+ if (resp->data[0] != (BYTE)channelNumber)
+ {
+ *seqNo = resp->thisSeq;
+ continue;
+ }
+
+ memcpy( msgPtr, &(resp->data[1]), respLength-1 );
+ *msgLen = respLength-1;
+
+
+ }
+
+ /*
+ // 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;
+ ImbAsyncResponse * resp = (ImbAsyncResponse *) responseData;
+ DWORD respLength = sizeof( responseData );
+ ImbAsyncRequest req;
+
+ while(1)
+ {
+
+
+ if( (msgPtr == NULL) || (msgLen == NULL) || ( seqNo == NULL) )
+ return ACCESN_ERROR;
+
+ 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;
+ }
+
+ if ( (lun == RESERVED_LUN) ||
+ (lun != ((((ImbPacket *)(resp->data))->nfLn) & 0x3 ))
+ )
+ {
+ *seqNo = resp->thisSeq;
+ continue;
+ }
+
+
+ memcpy( msgPtr, resp->data, respLength );
+ *msgLen = respLength;
+
+ }
+ 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;
+
+ if ((resp->data[0] & 0x0f) != (BYTE)channelNumber)
+ {
+ *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;
+
+
+ }
+
+ /*
+ // 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 (unsigned int eventId )
+{
+ int dummy;
+ int respLength = 0;
+ BOOL status;
+
+ /* confirm that app is not using a bad Id */
+
+
+ if ( AsyncEventHandle != (HANDLE) eventId)
+ return ACCESN_ERROR;
+
+ status = DeviceIoControl(hDevice,
+ IOCTL_IMB_CHECK_EVENT,
+ &AsyncEventHandle,
+ sizeof(HANDLE ),
+ &dummy,
+ 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;
+}
+
+
+/*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 (unsigned int *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,
+ (DWORD)sizeof(HANDLE ),
+ (LPDWORD) & respLength,
+ NULL
+ );
+#ifndef NO_MACRO_ARGS
+ DEBUG("%s: DeviceIoControl status = %d\n",__FUNCTION__, status);
+#endif
+
+ if( (respLength != sizeof(int)) || (status != TRUE ))
+ return ACCESN_ERROR;
+
+ /* printf("imbapi: Register handle = %x\n",AsyncEventHandle); *//*++++*/
+ *handleId = (unsigned int) 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 (unsigned int handleId, int iFlag)
+
+{
+ BOOL status;
+ DWORD respLength ;
+ int dummy;
+
+ iFlag = iFlag; /* to keep compiler happy We are not using this flag*/
+
+ if ( AsyncEventHandle != (HANDLE) handleId)
+ return ACCESN_ERROR;
+
+ status = DeviceIoControl(hDevice,
+ IOCTL_IMB_DEREGISTER_ASYNC_OBJ,
+ &AsyncEventHandle,
+ (DWORD)sizeof(HANDLE ),
+ &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;
+}
+
+/*/////////////////////////////////////////////////////////////////////////
+// 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 == 0 || 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;
+ unsigned int length = addressLength;
+ off_t startpAddress = (off_t)startAddress;
+ unsigned int diff;
+ caddr_t startvAddress;
+
+ if ((startAddress == 0) || (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__,IMB_DEVICE);
+ 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 = (long)(startvAddress + diff);
+ close(fd);
+ 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(&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*/
+
+
+/*/////////////////////////////////////////////////////////////////////////////
+// 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 IpmiVersion;
+}
+