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  * Copyright (c) 2018, Joyent, Inc.
  26  */
  27 
  28 #include <libipmi.h>
  29 #include <string.h>
  30 
  31 #include "ipmi_impl.h"
  32 
  33 ipmi_handle_t *
  34 ipmi_open(int *errp, char **msg, uint_t xport_type, nvlist_t *params)
  35 {
  36         ipmi_handle_t *ihp;
  37         static char errmsg[48];
  38 
  39         if (msg)
  40                 *msg = NULL;
  41 
  42         if ((ihp = calloc(1, sizeof (ipmi_handle_t))) == NULL) {
  43                 *errp = EIPMI_NOMEM;
  44                 if (msg)
  45                         *msg = "memory allocation failure";
  46                 return (NULL);
  47         }
  48 
  49         switch (xport_type) {
  50         case IPMI_TRANSPORT_BMC:
  51                 ihp->ih_transport = &ipmi_transport_bmc;
  52                 break;
  53         case IPMI_TRANSPORT_LAN:
  54                 ihp->ih_transport = &ipmi_transport_lan;
  55                 break;
  56         default:
  57                 *msg = "invalid transport type specified";
  58                 return (NULL);
  59         }
  60 
  61         ihp->ih_retries = 3;
  62 
  63         if ((ihp->ih_tdata = ihp->ih_transport->it_open(ihp, params)) == NULL ||
  64             ipmi_sdr_init(ihp) != 0 || ipmi_entity_init(ihp) != 0) {
  65                 *errp = ihp->ih_errno;
  66                 if (msg) {
  67                         (void) strncpy(errmsg, ipmi_errmsg(ihp), 47);
  68                         errmsg[47] = '\0';
  69                         *msg = errmsg;
  70                 }
  71                 ipmi_close(ihp);
  72                 return (NULL);
  73         }
  74 
  75         return (ihp);
  76 }
  77 
  78 void
  79 ipmi_close(ipmi_handle_t *ihp)
  80 {
  81         if (ihp->ih_transport && ihp->ih_tdata)
  82                 ihp->ih_transport->it_close(ihp->ih_tdata);
  83         ipmi_free(ihp, ihp->ih_deviceid);
  84         ipmi_free(ihp, ihp->ih_firmware_rev);
  85         ipmi_user_clear(ihp);
  86         ipmi_sdr_fini(ihp);
  87         ipmi_entity_fini(ihp);
  88         free(ihp);
  89 }
  90 
  91 /*
  92  * See section 5.2 for a description of the completion codes.
  93  */
  94 static struct ipmi_err_conv {
  95         int     bmc_err;
  96         int     ipmi_err;
  97 } ipmi_errtable[] = {
  98         { 0xC0,                 EIPMI_BUSY },
  99         { 0xC1,                 EIPMI_INVALID_COMMAND },
 100         { 0xC2,                 EIPMI_INVALID_COMMAND },
 101         { 0xC3,                 EIPMI_COMMAND_TIMEOUT },
 102         { 0xC4,                 EIPMI_NOSPACE },
 103         { 0xC5,                 EIPMI_INVALID_RESERVATION },
 104         { 0xC6,                 EIPMI_INVALID_REQUEST },
 105         { 0xC7,                 EIPMI_INVALID_REQUEST },
 106         { 0xC8,                 EIPMI_INVALID_REQUEST },
 107         { 0xC9,                 EIPMI_INVALID_REQUEST },
 108         { 0xCA,                 EIPMI_DATA_LENGTH_EXCEEDED },
 109         { 0xCB,                 EIPMI_NOT_PRESENT },
 110         { 0xCC,                 EIPMI_INVALID_REQUEST },
 111         { 0xCD,                 EIPMI_INVALID_COMMAND },
 112         { 0xCE,                 EIPMI_UNAVAILABLE },
 113         { 0xCF,                 EIPMI_UNAVAILABLE },
 114         { 0xD0,                 EIPMI_BUSY },
 115         { 0xD1,                 EIPMI_BUSY },
 116         { 0xD2,                 EIPMI_BUSY },
 117         { 0xD3,                 EIPMI_NOT_PRESENT },
 118         { 0xD4,                 EIPMI_ACCESS },
 119         { 0xD5,                 EIPMI_UNAVAILABLE },
 120         { 0xD6,                 EIPMI_UNAVAILABLE },
 121         { 0xFF,                 EIPMI_UNSPECIFIED },
 122 };
 123 
 124 #define IPMI_ERROR_COUNT \
 125         (sizeof (ipmi_errtable) / sizeof (ipmi_errtable[0]))
 126 
 127 ipmi_cmd_t *
 128 ipmi_send(ipmi_handle_t *ihp, ipmi_cmd_t *cmd)
 129 {
 130         int i;
 131 
 132         if (ihp->ih_transport->it_send(ihp->ih_tdata, cmd, &ihp->ih_response,
 133             &ihp->ih_completion) != 0)
 134                 return (NULL);
 135 
 136         if (ihp->ih_completion != 0) {
 137                 for (i = 0; i < IPMI_ERROR_COUNT; i++) {
 138                         if (ihp->ih_completion == ipmi_errtable[i].bmc_err) {
 139                                 (void) ipmi_set_error(ihp,
 140                                     ipmi_errtable[i].ipmi_err,
 141                                     "IPMI completion code 0x%x",
 142                                     ihp->ih_completion);
 143                                 return (NULL);
 144                         }
 145                 }
 146 
 147                 (void) ipmi_set_error(ihp, EIPMI_UNKNOWN,
 148                     "IPMI completion code 0x%x", ihp->ih_completion);
 149                 return (NULL);
 150         }
 151 
 152         return (&ihp->ih_response);
 153 }