ipmitool/src/plugins/imb/imbapi.c
Patrick Venture 8ea6094118 cleanup all unused-parameter warnings
Cleanup all unused-parameter warnings.  Each warning was examined to
verify it wasn't simply a case of a build macro difference.

Partially resolves ipmitool/ipmitool#13

Signed-off-by: Patrick Venture <venture@google.com>
2018-11-23 16:41:06 +03:00

1405 lines
41 KiB
C

/*
* Copyright (c) 2002, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistribution of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* Redistribution 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.
*
* 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.
*/
/* 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
*/
/* Use -DLINUX_DEBUG_MAX in the Makefile, resp. CFLAGS if you want a dump of the
* memory to debug mmap system call in MapPhysicalMemory() below.
*/
#define IMB_API
#ifdef WIN32
# define NO_MACRO_ARGS 1
# include <stdio.h>
# include <windows.h>
#else /* LINUX, SCO_UW, UNIX */
# include <fcntl.h>
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <sys/ioctl.h>
# include <sys/mman.h>
# include <sys/param.h>
# include <sys/stat.h>
# include <sys/types.h>
# include <unistd.h>
#endif
#include "imbapi.h"
#include <sys/socket.h>
#include <ipmitool/helper.h>
#include <ipmitool/log.h>
#ifdef SCO_UW
# define NO_MACRO_ARGS 1
# define __FUNCTION__ "func"
# define IMB_DEVICE "/dev/instru/mismic"
#else
# define IMB_DEVICE "/dev/imb"
#endif
#if !defined(PAGESIZE) && defined(PAGE_SIZE)
# define PAGESIZE PAGE_SIZE
#endif
#if !defined(_SC_PAGESIZE) && defined(_SC_PAGE_SIZE)
# define _SC_PAGESIZE _SC_PAGE_SIZE
#endif
HANDLE AsyncEventHandle = 0;
static int IpmiVersion;
/* GLOBAL VARIABLES */
/* dummy place holder. See deviceiocontrol. */
IO_STATUS_BLOCK NTstatus;
static HANDLE hDevice1;
static HANDLE hDevice;
static int fDriverTyp; /* from ipmicmd.c */
/* open_imb - Open IMB device. 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.
*/
#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) {
return 1;
}
/* 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 || INVALID_HANDLE_VALUE == hDevice) {
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;
if ((SendTimedImbpRequest(&requestData, (DWORD)400, respBuffer,
&respLength, &completionCode) != ACCESN_OK)
|| (completionCode != 0)) {
CloseHandle(hDevice);
return 0;
}
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;
} /* 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) {
return 1;
}
lprintf(LOG_DEBUG, "%s: opening the driver", __FUNCTION__);
/* 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)) < 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;
lprintf(LOG_DEBUG, "%s: opened driver, getting IPMI version", __FUNCTION__);
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;
}
}
lprintf(LOG_DEBUG, "%s: IPMI version 0x%x", __FUNCTION__,
IpmiVersion);
return 1;
} /* end open_imb() */
#endif
/* ipmi_open_ia */
int
ipmi_open_ia(void)
{
int rc = 0;
/* sets hDevice1 */
rc = open_imb();
if (rc == 1) {
rc = 0;
} else {
rc = -1;
}
return rc;
}
/* ipmi_close_ia */
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 - Simulate NT DeviceIoControl using unix calls and structures.
*
* @dummy_hDevice - handle of device
* @dwIoControlCode - control code of operation to perform
* @lpvInBuffer, address of buffer for input data
* @cbInBuffer, size of input buffer
* @lpvOutBuffer, address of output buffer
* @cbOutBuffer, size of output buffer
* @lpcbBytesReturned, address of actual bytes of output
* @lpoOverlapped address of overlapped struct
*
* returns - FALSE for fail and TRUE for success. Same as standard NTOS call as
* it also sets Ntstatus.status.
*/
static BOOL
DeviceIoControl(HANDLE __UNUSED__(dummey_hDevice), DWORD dwIoControlCode, LPVOID
lpvInBuffer, DWORD cbInBuffer, LPVOID lpvOutBuffer,
DWORD cbOutBuffer, LPDWORD lpcbBytesReturned,
LPOVERLAPPED lpoOverlapped)
{
struct smi s;
int rc;
int ioctl_status;
rc = open_imb();
if (rc == 0) {
return FALSE;
}
lprintf(LOG_DEBUG, "%s: ioctl cmd = 0x%lx", __FUNCTION__,
dwIoControlCode);
lprintf(LOG_DEBUG, "cbInBuffer %d cbOutBuffer %d", cbInBuffer,
cbOutBuffer);
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;
/* dummy place holder. Linux IMB driver doesn't return status or info
* via it
*/
s.ntstatus = (LPVOID)&NTstatus;
if ((ioctl_status = ioctl(hDevice1, dwIoControlCode,&s)) < 0) {
lprintf(LOG_DEBUG, "%s %s: ioctl cmd = 0x%x failed",
__FILE__, __FUNCTION__, dwIoControlCode);
return FALSE;
}
lprintf(LOG_DEBUG, "%s: ioctl_status %d bytes returned = %d",
__FUNCTION__, ioctl_status, *lpcbBytesReturned);
if (ioctl_status == STATUS_SUCCESS) {
lprintf(LOG_DEBUG, "%s returning true", __FUNCTION__);
return (TRUE);
} else {
lprintf(LOG_DEBUG, "%s returning false", __FUNCTION__);
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;
lprintf(LOG_DEBUG, "%s: DeviceIoControl cmd = %x",
__FUNCTION__, IOCTL_IMB_POLL_ASYNC);
status = DeviceIoControl(hDevice, IOCTL_IMB_POLL_ASYNC, NULL, 0, NULL,
0, &retLength, 0);
lprintf(LOG_DEBUG, "%s: DeviceIoControl status = %d", __FUNCTION__,
status);
if (status == TRUE) {
return ACCESN_OK;
} else {
return ACCESN_ERROR;
}
}
/* SendTimedI2cRequest - This function sends a request to a I2C device. Used by
* Upper level agents (sis modules) to access dumb I2c devices.
*
* @reqPtr - pointer to I2C request
* timeOut - how long to wait, mSec units
* @respDataPtr - where to put response data
* @respDataLen - size of response buffer and size of returned data
* @completionCode - request status from BMC
*
* returns - ACCESN_OK else error status code
*/
ACCESN_STATUS
SendTimedI2cRequest(I2CREQUESTDATA *reqPtr, int timeOut, BYTE *respDataPtr,
int *respDataLen, BYTE *completionCode)
{
/* size of write/read request minus any data */
# define MIN_WRI2C_SIZE 3
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;
/* format of a write/read I2C request */
struct WriteReadI2C {
BYTE busType;
BYTE rsSa;
BYTE count;
BYTE data[1];
} *wrReq = (struct WriteReadI2C *)req->req.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;
/* convert to uSec units */
req->timeOut = timeOut * 1000;
status = DeviceIoControl(hDevice, IOCTL_IMB_SEND_MESSAGE, requestData,
sizeof(requestData), &responseData,
sizeof(responseData), &respLength, NULL);
lprintf(LOG_DEBUG, "%s: DeviceIoControl status = %d", __FUNCTION__,
status);
if (status != TRUE) {
DWORD error;
error = GetLastError();
return 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;
}
/* SendTimedEmpMessageResponse - This function sends a response message to the
* EMP port.
*
* @ptr - pointer to the original request from EMP
* @responseDataBuf
* @responseDataLen
* @timeOut - how long to wait, in mSec units
*
* returns - OK else error status code
*/
ACCESN_STATUS
SendTimedEmpMessageResponse (ImbPacket *ptr, char *responseDataBuf,
int responseDataLen, int timeOut)
{
BOOL status;
BYTE responseData[MAX_IMB_RESP_SIZE];
DWORD respLength = sizeof(responseData);
BYTE requestData[MAX_IMB_RESP_SIZE];
ImbRequestBuffer *req = (ImbRequestBuffer *)requestData;
int i;
int 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);
}
/* though software is responding, we have to provide BMCs slave address
* as responder address.
*/
req->req.data[i++] = BMC_SA;
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;
/* convert to uSec units */
req->timeOut = timeOut * 1000;
status = DeviceIoControl(hDevice, IOCTL_IMB_SEND_MESSAGE, requestData,
sizeof(requestData), responseData, sizeof(responseData),
&respLength, NULL);
lprintf(LOG_DEBUG, "%s: DeviceIoControl status = %d", __FUNCTION__,
status);
if ((status != TRUE) || (respLength != 1) || (responseData[0] != 0)) {
return ACCESN_ERROR;
}
return ACCESN_OK;
}
/* SendTimedEmpMessageResponse_Ex - sends response message to the EMP port.
*
* @ptr - pointer to the original request from EMP
* @responseDataBuf
* @responseDataLen
* @timeOut - how long to wait, in mSec units
* @sessionHandle - This is introduced in IPMI1.5,this is required to be sent in
* sendd message command as a parameter, which is then used by BMC
* to identify the correct DPC session to send the message to.
* @channelNumber - There are 3 different channels on which DPC communication
* goes on:
* * Emp - 1
* * Lan channel one - 6,
* * Lan channel two(primary channel) - 7
*
* returns - OK else error status code
*/
ACCESN_STATUS
SendTimedEmpMessageResponse_Ex (ImbPacket *ptr, char *responseDataBuf, int
responseDataLen, int timeOut, BYTE sessionHandle, BYTE
channelNumber)
{
BOOL status;
BYTE responseData[MAX_IMB_RESP_SIZE];
DWORD respLength = sizeof(responseData);
BYTE requestData[MAX_IMB_RESP_SIZE];
ImbRequestBuffer *req = (ImbRequestBuffer *)requestData;
int i;
int 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.
*/
/* though software is responding, we have to provide BMCs slave address
* as responder address.
*/
req->req.data[i++] = BMC_SA;
/* 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 retrieved 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;
/* convert to uSec units */
req->timeOut = timeOut * 1000;
status = DeviceIoControl(hDevice, IOCTL_IMB_SEND_MESSAGE, requestData,
sizeof(requestData), responseData, sizeof(responseData),
&respLength, NULL);
lprintf(LOG_DEBUG, "%s: DeviceIoControl status = %d", __FUNCTION__,
status);
if ((status != TRUE) || (respLength != 1) || (responseData[0] != 0)) {
return ACCESN_ERROR;
}
return ACCESN_OK;
}
/* SendTimedLanMessageResponse - sends a response message to the DPC Over Lan
*
* @ptr - pointer to the original request from EMP
* @responseDataBuf
* @responseDataLen,
* @timeOut - how long to wait, in mSec units
*
* returns: OK else error status code
*/
ACCESN_STATUS
SendTimedLanMessageResponse(ImbPacket *ptr, char *responseDataBuf,
int responseDataLen, int timeOut)
{
BOOL status;
BYTE responseData[MAX_IMB_RESP_SIZE];
DWORD respLength = sizeof(responseData);
BYTE requestData[MAX_IMB_RESP_SIZE];
ImbRequestBuffer *req = (ImbRequestBuffer *)requestData;
int i;
int 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);
}
/* Though software is responding, we have to provide BMCs slave address
* as responder address.
*/
req->req.data[i++] = BMC_SA;
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;
/* convert to uSec units */
req->timeOut = timeOut * 1000;
status = DeviceIoControl(hDevice, IOCTL_IMB_SEND_MESSAGE, requestData,
sizeof(requestData), responseData, sizeof(responseData),
&respLength, NULL);
lprintf(LOG_DEBUG, "%s: DeviceIoControl status = %d", __FUNCTION__,
status);
if ((status != TRUE) || (respLength != 1) || (responseData[0] != 0)) {
return ACCESN_ERROR;
}
return ACCESN_OK;
}
/* SendTimedLanMessageResponse_Ex - sends a response message to the DPC Over
* LAN.
*
* @ptr - pointer to the original request from EMP
* @responseDataBuf
* @responseDataLen
* @timeOut - how long to wait, in mSec units
* @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 message to.
* @channelNumber - There are 3 different channels on which DPC communication
* goes on:
* * Emp - 1
* * Lan channel one - 6
* * Lan channel two(primary channel) - 7
*
* returns: OK else error status code
*/
ACCESN_STATUS
SendTimedLanMessageResponse_Ex(ImbPacket *ptr, char *responseDataBuf, int
responseDataLen, int timeOut, BYTE sessionHandle, BYTE
channelNumber)
{
BOOL status;
BYTE responseData[MAX_IMB_RESP_SIZE];
DWORD respLength = sizeof(responseData);
BYTE requestData[MAX_IMB_RESP_SIZE];
ImbRequestBuffer *req = (ImbRequestBuffer *)requestData;
int i;
int 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.
*/
/* Though software is responding, we have to provide BMC's slave address
* as responder address.
*/
req->req.data[i++] = BMC_SA;
/* 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 retrieved 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;
/* convert to uSec units */
req->timeOut = timeOut * 1000;
status = DeviceIoControl(hDevice, IOCTL_IMB_SEND_MESSAGE, requestData,
sizeof(requestData), responseData, sizeof(responseData),
&respLength, NULL);
lprintf(LOG_DEBUG, "%s: DeviceIoControl status = %d", __FUNCTION__,
status);
if ((status != TRUE) || (respLength != 1) || (responseData[0] != 0)) {
return ACCESN_ERROR;
}
return ACCESN_OK;
}
/* SendTimedImbpRequest - This function sends a request for BMC implemented function
*
* @reqPtr - request info and data
* @timeOut - how long to wait, in mSec units
* @respDataPtr - where to put response data
* @respDataLen - how much response data there is
* @completionCode - request status from dest controller
*
* returns: OK else error status code
*/
ACCESN_STATUS
SendTimedImbpRequest(IMBPREQUESTDATA *reqPtr, int timeOut, BYTE *respDataPtr,
int *respDataLen, BYTE *completionCode)
{
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;
lprintf(LOG_DEBUG, "cmd=%02x, pdata=%p, datalen=%x", req->req.cmd,
reqPtr->data, reqPtr->dataLength);
memcpy(req->req.data, reqPtr->data, reqPtr->dataLength);
req->flags = 0;
/* convert to uSec units */
req->timeOut = timeOut * 1000;
lprintf(LOG_DEBUG, "%s: rsSa 0x%x cmd 0x%x netFn 0x%x rsLun 0x%x",
__FUNCTION__, req->req.rsSa, req->req.cmd,
req->req.netFn, req->req.rsLun);
status = DeviceIoControl(hDevice, IOCTL_IMB_SEND_MESSAGE, requestData,
sizeof(requestData), &responseData,
sizeof(responseData), &respLength, NULL);
lprintf(LOG_DEBUG, "%s: DeviceIoControl returned status = %d",
__FUNCTION__, status);
#ifdef DBG_IPMI
/* TODO */
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 error;
} else 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 - sends a request for Asynchronous IMB implemented function.
*
* @reqPtr - Pointer to Async IMB request
* @seqNo -Sequence Munber
*
* returns: OK else error status code
*/
ACCESN_STATUS
SendAsyncImbpRequest(IMBPREQUESTDATA *reqPtr, BYTE *seqNo)
{
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;
/* no timeouts for async sends */
req->timeOut = 0;
status = DeviceIoControl(hDevice, IOCTL_IMB_SEND_MESSAGE, requestData,
sizeof(requestData), &responseData,
sizeof(responseData), &respLength, NULL);
lprintf(LOG_DEBUG, "%s: DeviceIoControl status = %d", __FUNCTION__,
status);
if (status != TRUE) {
DWORD error;
error = GetLastError();
return error;
} else if (respLength != 2) {
return ACCESN_ERROR;
}
/* give the caller his sequence number */
*seqNo = resp->data[0];
return ACCESN_OK;
}
/* GetAsyncImbpMessage - 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.
*
* @msgPtr - request info and data
* @msgLen - IN - length of buffer, OUT - msg len
* @timeOut - how long to wait for the message
* @seqNo - previously returned seq number(or ASYNC_SEQ_START)
* @channelNumber
*
* returns: OK else error status code
*/
ACCESN_STATUS
GetAsyncImbpMessage (ImbPacket *msgPtr, DWORD *msgLen, DWORD timeOut,
ImbAsyncSeq *seqNo, DWORD channelNumber)
{
/* This function does exactly the same as GetAsuncImbpMessage_Ex(),
* but doesn't return session handle and privilege
*/
return GetAsyncImbpMessage_Ex(msgPtr, msgLen, timeOut,
seqNo, channelNumber,
NULL, NULL);
}
/* GetAsyncImbpMessage_Ex - 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.
*
* @msgPtr - request info and data
* @msgLen - IN - length of buffer, OUT - msg len
* @timeOut - how long to wait for the message
* @seqNo - previously returned seq number(or ASYNC_SEQ_START)
* @channelNumber
* @sessionHandle
* @privilege
*
* returns: OK else error status code
*/
ACCESN_STATUS
GetAsyncImbpMessage_Ex(ImbPacket *msgPtr, DWORD *msgLen, DWORD timeOut,
ImbAsyncSeq *seqNo, DWORD channelNumber, BYTE *sessionHandle,
BYTE *privilege)
{
BOOL status;
BYTE responseData[MAX_ASYNC_RESP_SIZE];
BYTE lun;
ImbAsyncResponse *resp = (ImbAsyncResponse *)responseData;
DWORD respLength = sizeof(responseData);
ImbAsyncRequest req;
while (1) {
if (!msgPtr || !msgLen || !seqNo) {
return ACCESN_ERROR;
}
/* convert to uSec units */
req.timeOut = timeOut * 1000;
req.lastSeq = *seqNo;
status = DeviceIoControl(hDevice, IOCTL_IMB_GET_ASYNC_MSG, &req,
sizeof(req), &responseData,
sizeof(responseData), &respLength, NULL);
lprintf(LOG_DEBUG, "%s: DeviceIoControl status = %d",
__FUNCTION__, status);
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;
break;
default:
return ACCESN_ERROR;
break;
}
} else 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 version 1.0 or better */
if ((resp->data[0] & 0x0f) != (BYTE)channelNumber) {
*seqNo = resp->thisSeq;
continue;
}
/* 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.
*/
if (sessionHandle && privilege) {
*privilege = (resp->data[0] & 0xf0) >> 4;
/* 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;
}
}
/* IsAsyncMessageAvailable - Waits for an Async Message. This call will block
* the calling thread if no Async events are are available in the queue.
*
* @dummy
* @respLength
* @status
*
* returns: OK else error status code
*/
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);
lprintf(LOG_DEBUG, "%s: DeviceIoControl status = %d", __FUNCTION__,
status);
if (status != TRUE) {
return ACCESN_ERROR;
}
return ACCESN_OK;
}
/* RegisterForImbAsyncMessageNotification - This function Registers the calling
* application for Asynchronous notification when a sms message is available
* with the IMB driver.
*
* Notes: The calling application should use the returned handle to
* get the Async messages..
*
* @handleId - pointer to the registration handle
*
* returns: OK else error status code
*/
ACCESN_STATUS
RegisterForImbAsyncMessageNotification(unsigned int *handleId)
{
BOOL status;
DWORD respLength ;
int dummy;
/*allow only one app to register */
if (!handleId || AsyncEventHandle) {
return ACCESN_ERROR;
}
status = DeviceIoControl(hDevice, IOCTL_IMB_REGISTER_ASYNC_OBJ, &dummy,
sizeof(int), &AsyncEventHandle, (DWORD)sizeof(HANDLE),
(LPDWORD)&respLength, NULL);
lprintf(LOG_DEBUG, "%s: DeviceIoControl status = %d", __FUNCTION__,
status);
if ((respLength != sizeof(int)) || (status != TRUE)) {
return ACCESN_ERROR;
}
/* printf("imbapi: Register handle = %x\n",AsyncEventHandle); *//*++++*/
*handleId = (unsigned int)AsyncEventHandle;
lprintf(LOG_DEBUG, "handleId = %x AsyncEventHandle %x", *handleId,
AsyncEventHandle);
return ACCESN_OK;
}
/* UnRegisterForImbAsyncMessageNotification - This function un-registers the
* calling application for Asynchronous notification when a sms message is
* available with the IMB driver. It is used by Upper level agents to
* un-register for async. notification of sms messages.
*
* @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.
*
* returns - status
*/
ACCESN_STATUS
UnRegisterForImbAsyncMessageNotification(unsigned int handleId, int iFlag)
{
BOOL status;
DWORD respLength ;
int dummy;
/* to keep compiler happy. We are not using this flag*/
iFlag = iFlag;
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 );
lprintf(LOG_DEBUG, "%s: DeviceIoControl status = %d", __FUNCTION__,
status);
if (status != TRUE) {
return ACCESN_ERROR;
}
return ACCESN_OK;
}
/* SetShutDownCode - To set the shutdown action code.
*
* @code - shutdown action code which can be either SD_NO_ACTION, SD_RESET,
* SD_POWER_OFF as defined in imb_if.h
* @delayTime - time to delay in 100ms units
*
* returns - status
*/
ACCESN_STATUS
SetShutDownCode(int delayTime, int code)
{
DWORD retLength;
BOOL status;
ShutdownCmdBuffer cmd;
/* If IMB interface isn't open, 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);
lprintf(LOG_DEBUG, "%s: DeviceIoControl status = %d", __FUNCTION__,
status);
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, int addressLength, int *virtualAddress)
{
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, 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;
char *startvAddress;
#if defined(PAGESIZE)
long int pagesize = PAGESIZE;
#elif defined(_SC_PAGESIZE)
long int pagesize = sysconf(_SC_PAGESIZE);
if (pagesize < 1) {
perror("Invalid pagesize");
}
#else
# error PAGESIZE unsupported
#endif
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(0, length, PROT_READ, MAP_SHARED, fd,
startpAddress)) == MAP_FAILED) {
char buf[128];
sprintf(buf, "%s %s: mmap failed", __FILE__, __FUNCTION__);
perror(buf);
close(fd);
return ACCESN_ERROR;
}
lprintf(LOG_DEBUG, "%s: mmap of 0x%x success", __FUNCTION__,
startpAddress);
#ifdef LINUX_DEBUG_MAX
for (int 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;
#if defined(PAGESIZE)
long int pagesize = PAGESIZE;
#elif defined(_SC_PAGESIZE)
long int pagesize = sysconf(_SC_PAGESIZE);
if (pagesize < 1) {
perror("Invalid pagesize");
}
#else
# error PAGESIZE unsupported
#endif
/* page align the virtual address and adjust length accordingly */
diff = ((unsigned int)virtualAddress) % pagesize;
virtualAddress -= diff;
Length += diff;
lprintf(LOG_DEBUG, "%s: calling munmap(0x%x,%d)", __FUNCTION__,
virtualAddress,Length);
if (munmap(&virtualAddress, Length) != 0) {
char buf[128];
sprintf(buf, "%s %s: munmap failed", __FILE__, __FUNCTION__);
perror(buf);
return ACCESN_ERROR;
}
lprintf(LOG_DEBUG, "%s: munmap(0x%x,%d) success", __FUNCTION__,
virtualAddress, Length);
return ACCESN_OK;
}
#endif /* unix */
/* GetIpmiVersion - returns current IPMI version. */
BYTE
GetIpmiVersion()
{
return IpmiVersion;
}