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 /*
226070Srobj  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
233798Seschrock  * Use is subject to license terms.
243798Seschrock  */
253798Seschrock 
263798Seschrock #include <libipmi.h>
273798Seschrock #include <string.h>
283798Seschrock 
293798Seschrock #include <sys/bmc_intf.h>
303798Seschrock 
313798Seschrock #include "ipmi_impl.h"
323798Seschrock 
333798Seschrock ipmi_handle_t *
343798Seschrock ipmi_open(int *errp, char **msg)
353798Seschrock {
363798Seschrock 	ipmi_handle_t *ihp;
376070Srobj 	static char errmsg[48];
383798Seschrock 
393798Seschrock 	if (msg)
403798Seschrock 		*msg = NULL;
413798Seschrock 
423798Seschrock 	if ((ihp = calloc(sizeof (ipmi_handle_t), 1)) == NULL) {
433798Seschrock 		*errp = EIPMI_NOMEM;
443798Seschrock 		if (msg)
453798Seschrock 			*msg = "memory allocation failure";
463798Seschrock 		return (NULL);
473798Seschrock 	}
483798Seschrock 
493798Seschrock 	/* /dev/bmc is the only currently available transport */
503798Seschrock 	ihp->ih_transport = &ipmi_transport_bmc;
513798Seschrock 
523798Seschrock 	ihp->ih_retries = 3;
533798Seschrock 
546070Srobj 	if ((ihp->ih_tdata = ihp->ih_transport->it_open(ihp)) == NULL ||
556070Srobj 	    ipmi_sdr_init(ihp) != 0 || ipmi_entity_init(ihp) != 0) {
563798Seschrock 		*errp = ihp->ih_errno;
573798Seschrock 		if (msg) {
586070Srobj 			(void) strncpy(errmsg, ipmi_errmsg(ihp), 47);
596070Srobj 			errmsg[47] = '\0';
606070Srobj 			*msg = errmsg;
613798Seschrock 		}
623798Seschrock 		ipmi_close(ihp);
633798Seschrock 		return (NULL);
643798Seschrock 	}
653798Seschrock 
663798Seschrock 	return (ihp);
673798Seschrock }
683798Seschrock 
693798Seschrock void
703798Seschrock ipmi_close(ipmi_handle_t *ihp)
713798Seschrock {
723798Seschrock 	if (ihp->ih_transport && ihp->ih_tdata)
733798Seschrock 		ihp->ih_transport->it_close(ihp->ih_tdata);
746070Srobj 	ipmi_free(ihp, ihp->ih_deviceid);
756070Srobj 	ipmi_free(ihp, ihp->ih_firmware_rev);
765345Seschrock 	ipmi_user_clear(ihp);
776070Srobj 	ipmi_sdr_fini(ihp);
786070Srobj 	ipmi_entity_fini(ihp);
793798Seschrock 	free(ihp);
803798Seschrock }
813798Seschrock 
823798Seschrock /*
833798Seschrock  * See section 5.2 for a description of the completion codes.
843798Seschrock  */
853798Seschrock static struct ipmi_err_conv {
863798Seschrock 	int	bmc_err;
873798Seschrock 	int	ipmi_err;
883798Seschrock } ipmi_errtable[] = {
893798Seschrock 	{ 0xC0,			EIPMI_BUSY },
903798Seschrock 	{ 0xC1,			EIPMI_INVALID_COMMAND },
913798Seschrock 	{ 0xC2,			EIPMI_INVALID_COMMAND },
923798Seschrock 	{ 0xC3,			EIPMI_COMMAND_TIMEOUT },
933798Seschrock 	{ 0xC4,			EIPMI_NOSPACE },
943798Seschrock 	{ 0xC5,			EIPMI_INVALID_RESERVATION },
953798Seschrock 	{ 0xC6,			EIPMI_INVALID_REQUEST },
963798Seschrock 	{ 0xC7,			EIPMI_INVALID_REQUEST },
973798Seschrock 	{ 0xC8,			EIPMI_INVALID_REQUEST },
983798Seschrock 	{ 0xC9,			EIPMI_INVALID_REQUEST },
993798Seschrock 	{ 0xCA,			EIPMI_DATA_LENGTH_EXCEEDED },
1003798Seschrock 	{ 0xCB,			EIPMI_NOT_PRESENT },
1013798Seschrock 	{ 0xCC,			EIPMI_INVALID_REQUEST },
1023798Seschrock 	{ 0xCD,			EIPMI_INVALID_COMMAND },
1033798Seschrock 	{ 0xCE,			EIPMI_UNAVAILABLE },
1043798Seschrock 	{ 0xCF,			EIPMI_UNAVAILABLE },
1053798Seschrock 	{ 0xD0,			EIPMI_BUSY },
1063798Seschrock 	{ 0xD1,			EIPMI_BUSY },
1073798Seschrock 	{ 0xD2,			EIPMI_BUSY },
1083798Seschrock 	{ 0xD3,			EIPMI_NOT_PRESENT },
1093798Seschrock 	{ 0xD4,			EIPMI_ACCESS },
1103798Seschrock 	{ 0xD5,			EIPMI_UNAVAILABLE },
1113798Seschrock 	{ 0xD6,			EIPMI_UNAVAILABLE },
1123798Seschrock 	{ 0xFF,			EIPMI_UNSPECIFIED },
1133798Seschrock 	{ BMC_IPMI_OEM_FAILURE_SENDBMC,	EIPMI_SEND_FAILED },
1143798Seschrock };
1153798Seschrock 
1163798Seschrock #define	IPMI_ERROR_COUNT \
1173798Seschrock 	(sizeof (ipmi_errtable) / sizeof (ipmi_errtable[0]))
1183798Seschrock 
1193798Seschrock ipmi_cmd_t *
1203798Seschrock ipmi_send(ipmi_handle_t *ihp, ipmi_cmd_t *cmd)
1213798Seschrock {
1223798Seschrock 	int i;
1233798Seschrock 
1243798Seschrock 	if (ihp->ih_transport->it_send(ihp->ih_tdata, cmd, &ihp->ih_response,
125*8339SEric.Schrock@Sun.COM 	    &ihp->ih_completion) != 0)
1263798Seschrock 		return (NULL);
1273798Seschrock 
128*8339SEric.Schrock@Sun.COM 	if (ihp->ih_completion != 0) {
1293798Seschrock 		for (i = 0; i < IPMI_ERROR_COUNT; i++) {
130*8339SEric.Schrock@Sun.COM 			if (ihp->ih_completion == ipmi_errtable[i].bmc_err) {
1313798Seschrock 				(void) ipmi_set_error(ihp,
1323798Seschrock 				    ipmi_errtable[i].ipmi_err,
133*8339SEric.Schrock@Sun.COM 				    "IPMI completion code 0x%x",
134*8339SEric.Schrock@Sun.COM 				    ihp->ih_completion);
1353798Seschrock 				return (NULL);
1363798Seschrock 			}
1373798Seschrock 		}
1383798Seschrock 
1393798Seschrock 		(void) ipmi_set_error(ihp, EIPMI_UNKNOWN,
140*8339SEric.Schrock@Sun.COM 		    "IPMI completion code 0x%x", ihp->ih_completion);
1413798Seschrock 		return (NULL);
1423798Seschrock 	}
1433798Seschrock 
1443798Seschrock 	return (&ihp->ih_response);
1453798Seschrock }
146