ipmi_kcs.c revision 12950e8eb3edc5da750616c08afe6281bf554aee
/*
* Copyright (c) 2006 IronPort Systems Inc. <ambrisko@ironport.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
*/
/* $FreeBSD: src/sys/dev/ipmi/ipmi_kcs.c,v 1.3 2008/08/28 02:11:04 jhb */
/*
* Copyright 2013, Joyent, Inc. All rights reserved.
* Copyright 2013 Nexenta Systems, Inc. All rights reserved.
*/
#include "ipmivars.h"
static void kcs_clear_obf(struct ipmi_softc *, int);
static void kcs_error(struct ipmi_softc *);
static int kcs_wait_for_ibf(struct ipmi_softc *, int);
static int kcs_wait_for_obf(struct ipmi_softc *, int);
#define RETRY_USECS 100
static clock_t timeout_usecs;
static int
{
int status;
clock_t i;
if (state == 0) {
/* WAIT FOR IBF = 0 */
i += RETRY_USECS) {
}
} else {
/* WAIT FOR IBF = 1 */
i += RETRY_USECS) {
}
}
return (status);
}
static int
{
int status;
clock_t i;
if (state == 0) {
/* WAIT FOR OBF = 0 */
i += RETRY_USECS) {
}
} else {
/* WAIT FOR OBF = 1 */
i += RETRY_USECS) {
}
}
return (status);
}
static void
{
/* Clear OBF */
if (status & KCS_STATUS_OBF) {
}
}
static void
{
/* Wait for IBF = 0 */
/* ABORT */
/* Wait for IBF = 0 */
/* Clear OBF */
if (status & KCS_STATUS_OBF) {
if (data != 0)
"KCS Error Data %02x", data);
}
/* 0x00 to DATA_IN */
/* Wait for IBF = 0 */
/* Wait for OBF = 1 */
/* Read error status */
if (data != 0)
/* Write READ into Data_in */
/* Wait for IBF = 0 */
}
/* IDLE STATE */
/* Wait for OBF = 1 */
/* Clear OBF */
return;
}
}
}
/*
* Start to write a request. Waits for IBF to clear and then sends the
* WR_START command.
*/
static int
{
/* Wait for IBF = 0 */
/* Clear OBF */
/* Write start to command */
/* Wait for IBF = 0 */
break;
}
/* error state */
return (0);
/* Clear OBF */
return (1);
}
/*
* Write a byte of the request message, excluding the last byte of the
* message which requires special handling.
*/
static int
{
int status;
/* Data to Data */
/* Wait for IBF = 0 */
return (0);
/* Clear OBF */
return (1);
}
/*
* Write the last byte of a request message.
*/
static int
{
int status;
/* Write end to command */
/* Wait for IBF = 0 */
/* error state */
return (0);
/* Clear OBF */
/* Send data byte to DATA. */
return (1);
}
/*
* Read one byte of the reply message.
*/
static int
{
int status;
/* Wait for IBF = 0 */
/* Read State */
/* Wait for OBF = 1 */
/* Read Data_out */
/* Write READ into Data_in */
return (1);
}
/* Idle State */
/* Wait for OBF = 1 */
/* Read Dummy */
return (2);
}
/* Error State */
return (0);
}
/*
* Send a request message and collect the reply. Returns true if we
* succeed.
*/
static int
{
int i, state;
/* Send the request. */
if (!kcs_start_write(sc)) {
goto fail;
}
#ifdef KCS_DEBUG
#endif
goto fail;
}
#ifdef KCS_DEBUG
#endif
if (req->ir_requestlen == 0) {
"KCS: Failed to write command");
goto fail;
}
#ifdef KCS_DEBUG
req->ir_command);
#endif
} else {
"KCS: Failed to write command");
goto fail;
}
#ifdef KCS_DEBUG
req->ir_command);
#endif
"KCS: Failed to write data byte %d",
i + 1);
goto fail;
}
#ifdef KCS_DEBUG
cp[-1]);
#endif
}
"KCS: Failed to write last dta byte");
goto fail;
}
#ifdef KCS_DEBUG
*cp);
#endif
}
goto fail;
}
#ifdef KCS_DEBUG
#endif
goto fail;
}
/* Next we read the command. */
goto fail;
}
#ifdef KCS_DEBUG
#endif
goto fail;
}
/* Next we read the completion code. */
goto fail;
}
#ifdef KCS_DEBUG
req->ir_compcode);
#endif
/* Finally, read the reply from the BMC. */
i = 0;
for (;;) {
if (state == 0) {
"KCS: Read failed on byte %d", i + 1);
goto fail;
}
if (state == 2)
break;
if (i < req->ir_replybuflen) {
#ifdef KCS_DEBUG
data);
} else {
#endif
}
i++;
}
req->ir_replylen = i;
#ifdef KCS_DEBUG
if (req->ir_replybuflen < i)
#else
#endif
(int)(req->ir_replybuflen), i);
return (1);
fail:
return (0);
}
static void
{
struct ipmi_request *req;
int i, ok;
ok = 0;
for (i = 0; i < 3 && !ok; i++)
if (ok)
else
}
}
static int
{
return (1);
}
return (0);
}
int
{
int status;
/* Setup function pointers. */
/* See if we can talk to the controller. */
if (status == 0xff) {
return (ENXIO);
}
#ifdef KCS_DEBUG
#endif
if (status & KCS_STATUS_OBF ||
return (0);
}