bmc_vc.c revision 147982cb800a90a2ac06d00d9a79ac50b0ca4ddb
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* IPMI: back-end to BMC access
*/
#include <sys/dditypes.h>
#include <sys/sysmacros.h>
#include <sys/bmc_intf.h>
#include "bmc_fe.h"
/*
* The VLDC (Virtual Logical Domain Channel) interface is used to
* send command request messages to, and receive command response
* messages from, the Service Processor (SP).
*
* Messages are transferred over the interface using Layered Driver
* Interface over the vldc driver.
*
* ------------------- .
* ------------------- .
* | .
* | .
* ============ . ------------------
* ============ . ------------------
* | . |
* | . |
* -------- virtual channel . --------
* | vldc |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~| vBSC |
* -------- . --------
* .
* H O S T . S P
*
*/
/*
* IPMI virtual channel name
*/
#define IPMI_VLDC \
"/devices/virtual-devices@100/channel-devices@200" \
"/virtual-channel@3:ipmi"
#define VLDC_MTU 0x400
/*
* Virtual channel LDI parameters
*/
static ldi_handle_t vc_lh;
static ldi_ident_t vc_li;
#define VC_MAGIC_NUM 0x4B59554E
/*
* Default Data limits for the virtual channel interface
*/
/* to be the full 255 bytes */
#define VC_SEND_NONDATA_SIZE 8
#define VC_SEND_MAX_PAYLOAD_SIZE (BMC_VC_MAX_REQUEST_SIZE \
#define VC_RECV_NONDATA_SIZE 11
#define VC_RECV_MAX_PAYLOAD_SIZE (BMC_VC_MAX_RESPONSE_SIZE \
/*
* Tunables
*/
/*
* Some interfaces can handle a massive amount of request data, e.g.
* when they're used to transfer flash images to the system service processor.
* To enable faster bulk-data transfer on such BMCs, allow the max send payload
* to be dynamically tunable.
*/
/*
* Private Data Structures
*/
/*
* data structure to send a message to BMC.
*/
typedef struct bmc_vc_send {
/*
* data structure to receive a message from BMC.
*/
typedef struct bmc_vc_recv {
int
{
int ret = BMC_SUCCESS;
ret = BMC_FAILURE;
return (ret);
}
void
{
}
void
{
uint_t i;
for (i = 0; i < sz; i++) {
"%d => 0x%x", i, buf[i]);
}
}
static void
vc_timer_handler(void *devp)
{
}
/*
* If the service processor takes a reset, the connection to the vldc channel
* could be lost and vldc_chpoll() might always return ENOTACTIVE or ECONNRESET.
* This may be fixed in vldc eventually, but it needs, for now, to provide
* workaround by closing and reopening the channel. Refer to CR 6629230.
*
* In vc_read() and vc_write(), if ldi_read() or ldi_write() returns ENOTACTIVE
* or ECONNRESET, it will be eventually caught by the call to ldi_poll(); and
* this function will be called at that time.
*
* Called with if_busy = B_TRUE.
*/
static void
{
"reconnect failed at ldi_open_by_name");
return;
}
return;
}
"reestablished connection with %s", IPMI_VLDC);
}
static int
{
uint8_t *p;
int chunksize;
int error;
int ret = BMC_FAILURE;
int anyyet = 0;
short reventsp;
int notready_count = 0;
/*
* send operations can take some time -- check to see if the
* user has gotten impatient.
*/
break;
}
}
continue;
}
/*
* We don't always expect the virtual channel to be
* reliable and responsive. For example, what if the
* channel unexpectedly resets and we end up polling
* forever for some reason? This kind of problem has
* been observed particulary with poll for write. We
* should be suspicious of excessive number of polls,
* and should take a recovery measure.
*/
if (++notready_count % 50 == 0) {
"excessive poll retries.");
}
continue;
}
}
/*
* Write to VLDC in MTU chunks at a time.
*/
uio.uio_loffset = 0;
if (!error) {
} else {
break;
}
}
if (!error)
ret = BMC_SUCCESS;
return (ret);
}
static int
{
int error;
int ret = BMC_FAILURE;
int anyyet = 0;
short reventsp;
*pktsz = 0;
/*
* receive operations can take some time -- check to see if the
* user has gotten impatient.
*/
break;
}
}
continue;
}
continue;
}
/*
* Read bytes from VLDC
*/
uio.uio_loffset = 0;
if (!error) {
/* Check datalen and magic_num. */
VC_RECV_NONDATA_SIZE != *pktsz ||
!= VC_MAGIC_NUM) {
"garbage was received");
break;
}
ret = BMC_SUCCESS;
break;
} else {
break;
}
}
#ifdef DEBUG
#endif
return (ret);
}
static void
discard_timeout_handler(void *arg)
{
}
static void
{
int rc;
char junk[1];
goto error_open;
goto error_ioctl;
while (!discard_timed_out) {
uio.uio_loffset = 0;
if (!rc) {
break;
}
}
(void) untimeout(discard_to);
}
/*
* Allocates a bmc_vc_send_t with enough space in the data member to
* fit `datalen' bytes and initializes it with the supplied values.
*/
static bmc_vc_send_t *
{
if (datalen > 0)
return (sendp);
}
/*
* Deallocates the resources associated with the send structure `sendp'
* of size `sendp_len'.
*/
static void
{
}
/*
* The only time this is not interruptable is during attach
*/
int
{
int send_bmc_len = 0;
recv_pkt->datalength = 0;
return (ret);
}
*interrupted = B_TRUE;
return (BMC_FAILURE);
}
}
"fn 0x%x lun 0x%x cmd 0x%x fnlun 0x%x len 0x%x",
/* Try to open the vldc channel. */
goto error_open;
}
goto error_ioctl;
}
while (retrycount-- != 0) {
break;
}
continue;
} else if (*interrupted) {
break;
}
continue;
} else if (*interrupted) {
break;
}
#if DEBUG
"SUMMARY 0x%x 0x%x resp: 0x%x req: 0x%x cmd 0x%x " \
"CMD 0x%x len %d",
/*
* only for driver debugging:
* check return data and repackage
*/
"return parameters are not expected");
"GET_NETFN(recv_bmc.fnlun) 0x%x " \
"RESP_NETFN(GET_NETFN(send_bmc->fnlun)) 0x%x " \
"recv cmd 0x%x send cmd 0x%x", \
}
#endif
/*
* Subtract the size of non-data fields from the receive packet
* size to get the amount of data in the data field.
*/
/*
* If the caller didn't provide enough data space to hold
* the response, return failure.
*/
recv_pkt->datalength = 0;
} else {
ret = BMC_SUCCESS;
}
break;
}
dev->timer_handle = 0;
/*
* If we were interrupted, discard the response packet which may
* have just arrived in response to the last request packet.
* There are some cases where the unread packet in the receive
* buffer still lingers after the channel has been closed and
* reopened.
*/
if (*interrupted)
return (ret);
}
/*
* Returns the size of the largest possible response payload.
*/
int
{
return (VC_RECV_MAX_PAYLOAD_SIZE);
}
/*
* Returns the size of the largest possible request payload.
*/
int
{
return (vc_max_send_payload);
}