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 /* 23 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <libipmi.h> 30 #include <stddef.h> 31 #include <string.h> 32 33 #include "ipmi_impl.h" 34 35 typedef struct ipmi_cmd_get_sdr { 36 uint16_t ic_gs_resid; 37 uint16_t ic_gs_recid; 38 uint8_t ic_gs_offset; 39 uint8_t ic_gs_len; 40 } ipmi_cmd_get_sdr_t; 41 42 typedef struct ipmi_rsp_get_sdr { 43 uint16_t ir_gs_next; 44 uint8_t ir_gs_record[1]; 45 } ipmi_rsp_get_sdr_t; 46 47 /* 48 * Issue the "Reserve SDR Repository" command. 49 */ 50 static int 51 ipmi_sdr_reserve_repository(ipmi_handle_t *ihp) 52 { 53 ipmi_cmd_t cmd, *rsp; 54 55 cmd.ic_netfn = IPMI_NETFN_STORAGE; 56 cmd.ic_lun = 0; 57 cmd.ic_cmd = IPMI_CMD_RESERVE_SDR_REPOSITORY; 58 cmd.ic_dlen = 0; 59 cmd.ic_data = NULL; 60 61 if ((rsp = ipmi_send(ihp, &cmd)) == NULL) 62 return (-1); 63 64 ihp->ih_reservation = *((uint16_t *)rsp->ic_data); 65 return (0); 66 } 67 68 /* 69 * Refresh the cache of sensor data records. 70 */ 71 static int 72 ipmi_sdr_refresh(ipmi_handle_t *ihp) 73 { 74 size_t len; 75 uint16_t id; 76 ipmi_sdr_t *sdr; 77 ipmi_sdr_cache_ent_t *ent; 78 ipmi_sdr_generic_locator_t *gen_src, *gen_dst; 79 ipmi_sdr_fru_locator_t *fru_src, *fru_dst; 80 81 /* 82 * Free any existing SDRs. 83 */ 84 while (ihp->ih_sdr_cache != NULL) { 85 ent = ihp->ih_sdr_cache->isc_next; 86 ipmi_free(ihp, ent->isc_generic); 87 ipmi_free(ihp, ent->isc_fru); 88 ipmi_free(ihp, ent); 89 ihp->ih_sdr_cache = ent; 90 } 91 92 /* 93 * Iterate over all existing SDRs and add them to the cache. 94 */ 95 id = IPMI_SDR_FIRST; 96 while (id != IPMI_SDR_LAST) { 97 if ((sdr = ipmi_sdr_get(ihp, id, &id)) == NULL) 98 return (-1); 99 100 /* 101 * We currently only understand FRU and generic device records. 102 */ 103 if (sdr->is_type != IPMI_SDR_TYPE_GENERIC_LOCATOR && 104 sdr->is_type != IPMI_SDR_TYPE_FRU_LOCATOR) 105 continue; 106 107 /* 108 * Create a copy of the SDR-specific data. 109 */ 110 gen_dst = NULL; 111 fru_dst = NULL; 112 switch (sdr->is_type) { 113 case IPMI_SDR_TYPE_GENERIC_LOCATOR: 114 gen_src = (ipmi_sdr_generic_locator_t *)sdr->is_record; 115 len = offsetof(ipmi_sdr_generic_locator_t, 116 is_gl_idstring) + gen_src->is_gl_idlen + 1; 117 if ((gen_dst = ipmi_alloc(ihp, len)) == NULL) 118 return (-1); 119 (void) memcpy(gen_dst, gen_src, len - 1); 120 ((char *)gen_dst)[len - 1] = '\0'; 121 break; 122 123 case IPMI_SDR_TYPE_FRU_LOCATOR: 124 fru_src = (ipmi_sdr_fru_locator_t *)sdr->is_record; 125 len = offsetof(ipmi_sdr_fru_locator_t, 126 is_fl_idstring) + fru_src->is_fl_idlen + 1; 127 if ((fru_dst = ipmi_alloc(ihp, len)) == NULL) 128 return (-1); 129 (void) memcpy(fru_dst, fru_src, len - 1); 130 ((char *)fru_dst)[len - 1] = '\0'; 131 break; 132 } 133 134 if ((ent = ipmi_alloc(ihp, 135 sizeof (ipmi_sdr_cache_ent_t))) == NULL) { 136 ipmi_free(ihp, gen_dst); 137 ipmi_free(ihp, fru_dst); 138 } 139 140 ent->isc_generic = gen_dst; 141 ent->isc_fru = fru_dst; 142 ent->isc_next = ihp->ih_sdr_cache; 143 ent->isc_type = sdr->is_type; 144 ihp->ih_sdr_cache = ent; 145 } 146 147 return (0); 148 } 149 150 ipmi_sdr_t * 151 ipmi_sdr_get(ipmi_handle_t *ihp, uint16_t id, uint16_t *next) 152 { 153 ipmi_cmd_t cmd, *rsp; 154 ipmi_cmd_get_sdr_t req; 155 ipmi_rsp_get_sdr_t *sdr; 156 int i; 157 158 req.ic_gs_resid = ihp->ih_reservation; 159 req.ic_gs_recid = id; 160 req.ic_gs_offset = 0; 161 req.ic_gs_len = 0xFF; 162 163 cmd.ic_netfn = IPMI_NETFN_STORAGE; 164 cmd.ic_lun = 0; 165 cmd.ic_cmd = IPMI_CMD_GET_SDR; 166 cmd.ic_dlen = sizeof (req); 167 cmd.ic_data = &req; 168 169 for (i = 0; i < ihp->ih_retries; i++) { 170 if ((rsp = ipmi_send(ihp, &cmd)) == NULL) { 171 if (ipmi_errno(ihp) != EIPMI_INVALID_RESERVATION) 172 return (NULL); 173 174 if (ipmi_sdr_reserve_repository(ihp) != 0) 175 return (NULL); 176 req.ic_gs_resid = ihp->ih_reservation; 177 } 178 } 179 180 if (rsp == NULL) 181 return (NULL); 182 183 if (rsp->ic_dlen < sizeof (uint16_t) + sizeof (ipmi_sdr_t)) { 184 (void) ipmi_set_error(ihp, EIPMI_BAD_RESPONSE_LENGTH, NULL); 185 return (NULL); 186 } 187 188 sdr = rsp->ic_data; 189 *next = sdr->ir_gs_next; 190 191 return ((ipmi_sdr_t *)sdr->ir_gs_record); 192 } 193 194 ipmi_sdr_fru_locator_t * 195 ipmi_sdr_lookup_fru(ipmi_handle_t *ihp, const char *idstr) 196 { 197 ipmi_sdr_cache_ent_t *ent; 198 199 if (ihp->ih_sdr_cache == NULL && 200 ipmi_sdr_refresh(ihp) != 0) 201 return (NULL); 202 203 for (ent = ihp->ih_sdr_cache; ent != NULL; ent = ent->isc_next) { 204 if (ent->isc_type != IPMI_SDR_TYPE_FRU_LOCATOR) 205 continue; 206 207 if (strcmp(ent->isc_fru->is_fl_idstring, idstr) == 0) 208 return (ent->isc_fru); 209 } 210 211 (void) ipmi_set_error(ihp, EIPMI_NOT_PRESENT, NULL); 212 return (NULL); 213 } 214 215 ipmi_sdr_generic_locator_t * 216 ipmi_sdr_lookup_generic(ipmi_handle_t *ihp, const char *idstr) 217 { 218 ipmi_sdr_cache_ent_t *ent; 219 220 if (ihp->ih_sdr_cache == NULL && 221 ipmi_sdr_refresh(ihp) != 0) 222 return (NULL); 223 224 for (ent = ihp->ih_sdr_cache; ent != NULL; ent = ent->isc_next) { 225 if (ent->isc_type != IPMI_SDR_TYPE_GENERIC_LOCATOR) 226 continue; 227 228 if (strcmp(ent->isc_generic->is_gl_idstring, idstr) == 0) 229 return (ent->isc_generic); 230 } 231 232 (void) ipmi_set_error(ihp, EIPMI_NOT_PRESENT, NULL); 233 return (NULL); 234 } 235