mirror of
https://github.com/ipmitool/ipmitool.git
synced 2026-01-21 16:42:19 +08:00
2119 lines
60 KiB
C
2119 lines
60 KiB
C
/*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 <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>
|
|
|
|
#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
|
|
|
|
/*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 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 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 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;
|
|
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;
|
|
}
|
|
#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;
|
|
#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;
|
|
#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;
|
|
}
|
|
|