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 return (-1); 130 } 131 132 ent->isc_generic = gen_dst; 133 ent->isc_fru = fru_dst; 134 ent->isc_next = ihp->ih_sdr_cache; 135 ent->isc_type = sdr->is_type; 136 ihp->ih_sdr_cache = ent; 137 } 138 139 return (0); 140 } 141 142 void 143 ipmi_sdr_clear(ipmi_handle_t *ihp) 144 { 145 ipmi_sdr_cache_ent_t *ent, *next; 146 147 while ((ent = ihp->ih_sdr_cache) != NULL) { 148 next = ent->isc_next; 149 ipmi_free(ihp, ent->isc_generic); 150 ipmi_free(ihp, ent->isc_fru); 151 ipmi_free(ihp, ent); 152 ihp->ih_sdr_cache = next; 153 } 154 } 155 156 ipmi_sdr_t * 157 ipmi_sdr_get(ipmi_handle_t *ihp, uint16_t id, uint16_t *next) 158 { 159 ipmi_cmd_t cmd, *rsp; 160 ipmi_cmd_get_sdr_t req; 161 ipmi_rsp_get_sdr_t *sdr; 162 int i; 163 164 req.ic_gs_resid = ihp->ih_reservation; 165 req.ic_gs_recid = id; 166 req.ic_gs_offset = 0; 167 req.ic_gs_len = 0xFF; 168 169 cmd.ic_netfn = IPMI_NETFN_STORAGE; 170 cmd.ic_lun = 0; 171 cmd.ic_cmd = IPMI_CMD_GET_SDR; 172 cmd.ic_dlen = sizeof (req); 173 cmd.ic_data = &req; 174 175 for (i = 0; i < ihp->ih_retries; i++) { 176 if ((rsp = ipmi_send(ihp, &cmd)) == NULL) { 177 if (ipmi_errno(ihp) != EIPMI_INVALID_RESERVATION) 178 return (NULL); 179 180 if (ipmi_sdr_reserve_repository(ihp) != 0) 181 return (NULL); 182 req.ic_gs_resid = ihp->ih_reservation; 183 } 184 } 185 186 if (rsp == NULL) 187 return (NULL); 188 189 if (rsp->ic_dlen < sizeof (uint16_t) + sizeof (ipmi_sdr_t)) { 190 (void) ipmi_set_error(ihp, EIPMI_BAD_RESPONSE_LENGTH, NULL); 191 return (NULL); 192 } 193 194 sdr = rsp->ic_data; 195 *next = sdr->ir_gs_next; 196 197 return ((ipmi_sdr_t *)sdr->ir_gs_record); 198 } 199 200 ipmi_sdr_fru_locator_t * 201 ipmi_sdr_lookup_fru(ipmi_handle_t *ihp, const char *idstr) 202 { 203 ipmi_sdr_cache_ent_t *ent; 204 205 if (ihp->ih_sdr_cache == NULL && 206 ipmi_sdr_refresh(ihp) != 0) 207 return (NULL); 208 209 for (ent = ihp->ih_sdr_cache; ent != NULL; ent = ent->isc_next) { 210 if (ent->isc_type != IPMI_SDR_TYPE_FRU_LOCATOR) 211 continue; 212 213 if (strcmp(ent->isc_fru->is_fl_idstring, idstr) == 0) 214 return (ent->isc_fru); 215 } 216 217 (void) ipmi_set_error(ihp, EIPMI_NOT_PRESENT, NULL); 218 return (NULL); 219 } 220 221 ipmi_sdr_generic_locator_t * 222 ipmi_sdr_lookup_generic(ipmi_handle_t *ihp, const char *idstr) 223 { 224 ipmi_sdr_cache_ent_t *ent; 225 226 if (ihp->ih_sdr_cache == NULL && 227 ipmi_sdr_refresh(ihp) != 0) 228 return (NULL); 229 230 for (ent = ihp->ih_sdr_cache; ent != NULL; ent = ent->isc_next) { 231 if (ent->isc_type != IPMI_SDR_TYPE_GENERIC_LOCATOR) 232 continue; 233 234 if (strcmp(ent->isc_generic->is_gl_idstring, idstr) == 0) 235 return (ent->isc_generic); 236 } 237 238 (void) ipmi_set_error(ihp, EIPMI_NOT_PRESENT, NULL); 239 return (NULL); 240 } 241