13798Seschrock /*
23798Seschrock  * CDDL HEADER START
33798Seschrock  *
43798Seschrock  * The contents of this file are subject to the terms of the
53798Seschrock  * Common Development and Distribution License (the "License").
63798Seschrock  * You may not use this file except in compliance with the License.
73798Seschrock  *
83798Seschrock  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
93798Seschrock  * or http://www.opensolaris.org/os/licensing.
103798Seschrock  * See the License for the specific language governing permissions
113798Seschrock  * and limitations under the License.
123798Seschrock  *
133798Seschrock  * When distributing Covered Code, include this CDDL HEADER in each
143798Seschrock  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
153798Seschrock  * If applicable, add the following below this CDDL HEADER, with the
163798Seschrock  * fields enclosed by brackets "[]" replaced with your own identifying
173798Seschrock  * information: Portions Copyright [yyyy] [name of copyright owner]
183798Seschrock  *
193798Seschrock  * CDDL HEADER END
203798Seschrock  */
213798Seschrock /*
223798Seschrock  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
233798Seschrock  * Use is subject to license terms.
243798Seschrock  */
253798Seschrock 
263798Seschrock #pragma ident	"%Z%%M%	%I%	%E% SMI"
273798Seschrock 
283798Seschrock #include <libipmi.h>
293798Seschrock #include <string.h>
303798Seschrock 
313798Seschrock #include <sys/bmc_intf.h>
323798Seschrock 
333798Seschrock #include "ipmi_impl.h"
343798Seschrock 
353798Seschrock ipmi_handle_t *
363798Seschrock ipmi_open(int *errp, char **msg)
373798Seschrock {
383798Seschrock 	ipmi_handle_t *ihp;
393798Seschrock 
403798Seschrock 	if (msg)
413798Seschrock 		*msg = NULL;
423798Seschrock 
433798Seschrock 	if ((ihp = calloc(sizeof (ipmi_handle_t), 1)) == NULL) {
443798Seschrock 		*errp = EIPMI_NOMEM;
453798Seschrock 		if (msg)
463798Seschrock 			*msg = "memory allocation failure";
473798Seschrock 		return (NULL);
483798Seschrock 	}
493798Seschrock 
503798Seschrock 	/* /dev/bmc is the only currently available transport */
513798Seschrock 	ihp->ih_transport = &ipmi_transport_bmc;
523798Seschrock 
533798Seschrock 	ihp->ih_retries = 3;
543798Seschrock 
553798Seschrock 	if ((ihp->ih_tdata = ihp->ih_transport->it_open(ihp)) == NULL) {
563798Seschrock 		*errp = ihp->ih_errno;
573798Seschrock 		if (msg) {
583798Seschrock 			if ((*msg = strdup(ipmi_errmsg(ihp))) == NULL)
593798Seschrock 				*msg = "memory allocation failure";
603798Seschrock 		}
613798Seschrock 		ipmi_close(ihp);
623798Seschrock 		return (NULL);
633798Seschrock 	}
643798Seschrock 
653798Seschrock 	return (ihp);
663798Seschrock }
673798Seschrock 
683798Seschrock void
693798Seschrock ipmi_close(ipmi_handle_t *ihp)
703798Seschrock {
713798Seschrock 	if (ihp->ih_transport && ihp->ih_tdata)
723798Seschrock 		ihp->ih_transport->it_close(ihp->ih_tdata);
735017Seschrock 	ipmi_sdr_clear(ihp);
74*5345Seschrock 	ipmi_user_clear(ihp);
753798Seschrock 	free(ihp);
763798Seschrock }
773798Seschrock 
783798Seschrock /*
793798Seschrock  * See section 5.2 for a description of the completion codes.
803798Seschrock  */
813798Seschrock static struct ipmi_err_conv {
823798Seschrock 	int	bmc_err;
833798Seschrock 	int	ipmi_err;
843798Seschrock } ipmi_errtable[] = {
853798Seschrock 	{ 0xC0,			EIPMI_BUSY },
863798Seschrock 	{ 0xC1,			EIPMI_INVALID_COMMAND },
873798Seschrock 	{ 0xC2,			EIPMI_INVALID_COMMAND },
883798Seschrock 	{ 0xC3,			EIPMI_COMMAND_TIMEOUT },
893798Seschrock 	{ 0xC4,			EIPMI_NOSPACE },
903798Seschrock 	{ 0xC5,			EIPMI_INVALID_RESERVATION },
913798Seschrock 	{ 0xC6,			EIPMI_INVALID_REQUEST },
923798Seschrock 	{ 0xC7,			EIPMI_INVALID_REQUEST },
933798Seschrock 	{ 0xC8,			EIPMI_INVALID_REQUEST },
943798Seschrock 	{ 0xC9,			EIPMI_INVALID_REQUEST },
953798Seschrock 	{ 0xCA,			EIPMI_DATA_LENGTH_EXCEEDED },
963798Seschrock 	{ 0xCB,			EIPMI_NOT_PRESENT },
973798Seschrock 	{ 0xCC,			EIPMI_INVALID_REQUEST },
983798Seschrock 	{ 0xCD,			EIPMI_INVALID_COMMAND },
993798Seschrock 	{ 0xCE,			EIPMI_UNAVAILABLE },
1003798Seschrock 	{ 0xCF,			EIPMI_UNAVAILABLE },
1013798Seschrock 	{ 0xD0,			EIPMI_BUSY },
1023798Seschrock 	{ 0xD1,			EIPMI_BUSY },
1033798Seschrock 	{ 0xD2,			EIPMI_BUSY },
1043798Seschrock 	{ 0xD3,			EIPMI_NOT_PRESENT },
1053798Seschrock 	{ 0xD4,			EIPMI_ACCESS },
1063798Seschrock 	{ 0xD5,			EIPMI_UNAVAILABLE },
1073798Seschrock 	{ 0xD6,			EIPMI_UNAVAILABLE },
1083798Seschrock 	{ 0xFF,			EIPMI_UNSPECIFIED },
1093798Seschrock 	{ BMC_IPMI_OEM_FAILURE_SENDBMC,	EIPMI_SEND_FAILED },
1103798Seschrock };
1113798Seschrock 
1123798Seschrock #define	IPMI_ERROR_COUNT \
1133798Seschrock 	(sizeof (ipmi_errtable) / sizeof (ipmi_errtable[0]))
1143798Seschrock 
1153798Seschrock ipmi_cmd_t *
1163798Seschrock ipmi_send(ipmi_handle_t *ihp, ipmi_cmd_t *cmd)
1173798Seschrock {
1183798Seschrock 	int completion;
1193798Seschrock 	int i;
1203798Seschrock 
1213798Seschrock 	if (ihp->ih_transport->it_send(ihp->ih_tdata, cmd, &ihp->ih_response,
1223798Seschrock 	    &completion) != 0)
1233798Seschrock 		return (NULL);
1243798Seschrock 
1253798Seschrock 	if (completion != 0) {
1263798Seschrock 		for (i = 0; i < IPMI_ERROR_COUNT; i++) {
1273798Seschrock 			if (completion == ipmi_errtable[i].bmc_err) {
1283798Seschrock 				(void) ipmi_set_error(ihp,
1293798Seschrock 				    ipmi_errtable[i].ipmi_err,
1303798Seschrock 				    "IPMI completion code 0x%x", completion);
1313798Seschrock 				return (NULL);
1323798Seschrock 			}
1333798Seschrock 		}
1343798Seschrock 
1353798Seschrock 		(void) ipmi_set_error(ihp, EIPMI_UNKNOWN,
1363798Seschrock 		    "IPMI completion code 0x%x", completion);
1373798Seschrock 		return (NULL);
1383798Seschrock 	}
1393798Seschrock 
1403798Seschrock 	return (&ihp->ih_response);
1413798Seschrock }
142