1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 
  26 #include <libipmi.h>
  27 #include <string.h>
  28 
  29 #include "ipmi_impl.h"
  30 
  31 ipmi_handle_t *
  32 ipmi_open(int *errp, char **msg, uint_t xport_type, nvlist_t *params)
  33 {
  34         ipmi_handle_t *ihp;
  35         static char errmsg[48];
  36 
  37         if (msg)
  38                 *msg = NULL;
  39 
  40         if ((ihp = calloc(sizeof (ipmi_handle_t), 1)) == NULL) {
  41                 *errp = EIPMI_NOMEM;
  42                 if (msg)
  43                         *msg = "memory allocation failure";
  44                 return (NULL);
  45         }
  46 
  47         switch (xport_type) {
  48         case IPMI_TRANSPORT_BMC:
  49                 ihp->ih_transport = &ipmi_transport_bmc;
  50                 break;
  51         case IPMI_TRANSPORT_LAN:
  52                 ihp->ih_transport = &ipmi_transport_lan;
  53                 break;
  54         default:
  55                 *msg = "invalid transport type specified";
  56                 return (NULL);
  57         }
  58 
  59         ihp->ih_retries = 3;
  60 
  61         if ((ihp->ih_tdata = ihp->ih_transport->it_open(ihp, params)) == NULL ||
  62             ipmi_sdr_init(ihp) != 0 || ipmi_entity_init(ihp) != 0) {
  63                 *errp = ihp->ih_errno;
  64                 if (msg) {
  65                         (void) strncpy(errmsg, ipmi_errmsg(ihp), 47);
  66                         errmsg[47] = '\0';
  67                         *msg = errmsg;
  68                 }
  69                 ipmi_close(ihp);
  70                 return (NULL);
  71         }
  72 
  73         return (ihp);
  74 }
  75 
  76 void
  77 ipmi_close(ipmi_handle_t *ihp)
  78 {
  79         if (ihp->ih_transport && ihp->ih_tdata)
  80                 ihp->ih_transport->it_close(ihp->ih_tdata);
  81         ipmi_free(ihp, ihp->ih_deviceid);
  82         ipmi_free(ihp, ihp->ih_firmware_rev);
  83         ipmi_user_clear(ihp);
  84         ipmi_sdr_fini(ihp);
  85         ipmi_entity_fini(ihp);
  86         free(ihp);
  87 }
  88 
  89 /*
  90  * See section 5.2 for a description of the completion codes.
  91  */
  92 static struct ipmi_err_conv {
  93         int     bmc_err;
  94         int     ipmi_err;
  95 } ipmi_errtable[] = {
  96         { 0xC0,                 EIPMI_BUSY },
  97         { 0xC1,                 EIPMI_INVALID_COMMAND },
  98         { 0xC2,                 EIPMI_INVALID_COMMAND },
  99         { 0xC3,                 EIPMI_COMMAND_TIMEOUT },
 100         { 0xC4,                 EIPMI_NOSPACE },
 101         { 0xC5,                 EIPMI_INVALID_RESERVATION },
 102         { 0xC6,                 EIPMI_INVALID_REQUEST },
 103         { 0xC7,                 EIPMI_INVALID_REQUEST },
 104         { 0xC8,                 EIPMI_INVALID_REQUEST },
 105         { 0xC9,                 EIPMI_INVALID_REQUEST },
 106         { 0xCA,                 EIPMI_DATA_LENGTH_EXCEEDED },
 107         { 0xCB,                 EIPMI_NOT_PRESENT },
 108         { 0xCC,                 EIPMI_INVALID_REQUEST },
 109         { 0xCD,                 EIPMI_INVALID_COMMAND },
 110         { 0xCE,                 EIPMI_UNAVAILABLE },
 111         { 0xCF,                 EIPMI_UNAVAILABLE },
 112         { 0xD0,                 EIPMI_BUSY },
 113         { 0xD1,                 EIPMI_BUSY },
 114         { 0xD2,                 EIPMI_BUSY },
 115         { 0xD3,                 EIPMI_NOT_PRESENT },
 116         { 0xD4,                 EIPMI_ACCESS },
 117         { 0xD5,                 EIPMI_UNAVAILABLE },
 118         { 0xD6,                 EIPMI_UNAVAILABLE },
 119         { 0xFF,                 EIPMI_UNSPECIFIED },
 120 };
 121 
 122 #define IPMI_ERROR_COUNT \
 123         (sizeof (ipmi_errtable) / sizeof (ipmi_errtable[0]))
 124 
 125 ipmi_cmd_t *
 126 ipmi_send(ipmi_handle_t *ihp, ipmi_cmd_t *cmd)
 127 {
 128         int i;
 129 
 130         if (ihp->ih_transport->it_send(ihp->ih_tdata, cmd, &ihp->ih_response,
 131             &ihp->ih_completion) != 0)
 132                 return (NULL);
 133 
 134         if (ihp->ih_completion != 0) {
 135                 for (i = 0; i < IPMI_ERROR_COUNT; i++) {
 136                         if (ihp->ih_completion == ipmi_errtable[i].bmc_err) {
 137                                 (void) ipmi_set_error(ihp,
 138                                     ipmi_errtable[i].ipmi_err,
 139                                     "IPMI completion code 0x%x",
 140                                     ihp->ih_completion);
 141                                 return (NULL);
 142                         }
 143                 }
 144 
 145                 (void) ipmi_set_error(ihp, EIPMI_UNKNOWN,
 146                     "IPMI completion code 0x%x", ihp->ih_completion);
 147                 return (NULL);
 148         }
 149 
 150         return (&ihp->ih_response);
 151 }