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 ipmi_sdr_clear(ihp); 82 83 /* 84 * Iterate over all existing SDRs and add them to the cache. 85 */ 86 id = IPMI_SDR_FIRST; 87 while (id != IPMI_SDR_LAST) { 88 if ((sdr = ipmi_sdr_get(ihp, id, &id)) == NULL) 89 return (-1); 90 91 /* 92 * We currently only understand FRU and generic device records. 93 */ 94 if (sdr->is_type != IPMI_SDR_TYPE_GENERIC_LOCATOR && 95 sdr->is_type != IPMI_SDR_TYPE_FRU_LOCATOR) 96 continue; 97 98 /* 99 * Create a copy of the SDR-specific data. 100 */ 101 gen_dst = NULL; 102 fru_dst = NULL; 103 switch (sdr->is_type) { 104 case IPMI_SDR_TYPE_GENERIC_LOCATOR: 105 gen_src = (ipmi_sdr_generic_locator_t *)sdr->is_record; 106 len = offsetof(ipmi_sdr_generic_locator_t, 107 is_gl_idstring) + gen_src->is_gl_idlen + 1; 108 if ((gen_dst = ipmi_alloc(ihp, len)) == NULL) 109 return (-1); 110 (void) memcpy(gen_dst, gen_src, len - 1); 111 ((char *)gen_dst)[len - 1] = '\0'; 112 break; 113 114 case IPMI_SDR_TYPE_FRU_LOCATOR: 115 fru_src = (ipmi_sdr_fru_locator_t *)sdr->is_record; 116 len = offsetof(ipmi_sdr_fru_locator_t, 117 is_fl_idstring) + fru_src->is_fl_idlen + 1; 118 if ((fru_dst = ipmi_alloc(ihp, len)) == NULL) 119 return (-1); 120 (void) memcpy(fru_dst, fru_src, len - 1); 121 ((char *)fru_dst)[len - 1] = '\0'; 122 break; 123 } 124 125 if ((ent = ipmi_alloc(ihp, 126 sizeof (ipmi_sdr_cache_ent_t))) == NULL) { 127 ipmi_free(ihp, gen_dst); 128 ipmi_free(ihp, fru_dst); 129 } 130 131 ent->isc_generic = gen_dst; 132 ent->isc_fru = fru_dst; 133 ent->isc_next = ihp->ih_sdr_cache; 134 ent->isc_type = sdr->is_type; 135 ihp->ih_sdr_cache = ent; 136 } 137 138 return (0); 139 } 140 141 void 142 ipmi_sdr_clear(ipmi_handle_t *ihp) 143 { 144 ipmi_sdr_cache_ent_t *ent, *next; 145 146 while ((ent = ihp->ih_sdr_cache) != NULL) { 147 next = ent->isc_next; 148 ipmi_free(ihp, ent->isc_generic); 149 ipmi_free(ihp, ent->isc_fru); 150 ipmi_free(ihp, ent); 151 ihp->ih_sdr_cache = next; 152 } 153 } 154 155 ipmi_sdr_t * 156 ipmi_sdr_get(ipmi_handle_t *ihp, uint16_t id, uint16_t *next) 157 { 158 ipmi_cmd_t cmd, *rsp; 159 ipmi_cmd_get_sdr_t req; 160 ipmi_rsp_get_sdr_t *sdr; 161 int i; 162 163 req.ic_gs_resid = ihp->ih_reservation; 164 req.ic_gs_recid = id; 165 req.ic_gs_offset = 0; 166 req.ic_gs_len = 0xFF; 167 168 cmd.ic_netfn = IPMI_NETFN_STORAGE; 169 cmd.ic_lun = 0; 170 cmd.ic_cmd = IPMI_CMD_GET_SDR; 171 cmd.ic_dlen = sizeof (req); 172 cmd.ic_data = &req; 173 174 for (i = 0; i < ihp->ih_retries; i++) { 175 if ((rsp = ipmi_send(ihp, &cmd)) == NULL) { 176 if (ipmi_errno(ihp) != EIPMI_INVALID_RESERVATION) 177 return (NULL); 178 179 if (ipmi_sdr_reserve_repository(ihp) != 0) 180 return (NULL); 181 req.ic_gs_resid = ihp->ih_reservation; 182 } 183 } 184 185 if (rsp == NULL) 186 return (NULL); 187 188 if (rsp->ic_dlen < sizeof (uint16_t) + sizeof (ipmi_sdr_t)) { 189 (void) ipmi_set_error(ihp, EIPMI_BAD_RESPONSE_LENGTH, NULL); 190 return (NULL); 191 } 192 193 sdr = rsp->ic_data; 194 *next = sdr->ir_gs_next; 195 196 return ((ipmi_sdr_t *)sdr->ir_gs_record); 197 } 198 199 ipmi_sdr_fru_locator_t * 200 ipmi_sdr_lookup_fru(ipmi_handle_t *ihp, const char *idstr) 201 { 202 ipmi_sdr_cache_ent_t *ent; 203 204 if (ihp->ih_sdr_cache == NULL && 205 ipmi_sdr_refresh(ihp) != 0) 206 return (NULL); 207 208 for (ent = ihp->ih_sdr_cache; ent != NULL; ent = ent->isc_next) { 209 if (ent->isc_type != IPMI_SDR_TYPE_FRU_LOCATOR) 210 continue; 211 212 if (strcmp(ent->isc_fru->is_fl_idstring, idstr) == 0) 213 return (ent->isc_fru); 214 } 215 216 (void) ipmi_set_error(ihp, EIPMI_NOT_PRESENT, NULL); 217 return (NULL); 218 } 219 220 ipmi_sdr_generic_locator_t * 221 ipmi_sdr_lookup_generic(ipmi_handle_t *ihp, const char *idstr) 222 { 223 ipmi_sdr_cache_ent_t *ent; 224 225 if (ihp->ih_sdr_cache == NULL && 226 ipmi_sdr_refresh(ihp) != 0) 227 return (NULL); 228 229 for (ent = ihp->ih_sdr_cache; ent != NULL; ent = ent->isc_next) { 230 if (ent->isc_type != IPMI_SDR_TYPE_GENERIC_LOCATOR) 231 continue; 232 233 if (strcmp(ent->isc_generic->is_gl_idstring, idstr) == 0) 234 return (ent->isc_generic); 235 } 236 237 (void) ipmi_set_error(ihp, EIPMI_NOT_PRESENT, NULL); 238 return (NULL); 239 } 240