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 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include <fm/fmd_api.h> 29 #include <fm/libtopo.h> 30 #include <sys/fm/protocol.h> 31 #include <cmd.h> 32 #include <string.h> 33 #include <cmd_hc_sun4v.h> 34 35 nvlist_t *mb_nvl; 36 37 nvlist_t * 38 cmd_fault_add_location(fmd_hdl_t *hdl, nvlist_t *flt, const char *locstr) { 39 40 char *t, *s; 41 42 if (nvlist_lookup_string(flt, FM_FAULT_LOCATION, &t) == 0) 43 return (flt); /* already has location value */ 44 45 /* Replace occurrence of ": " with "/" to avoid confusing ILOM. */ 46 t = fmd_hdl_zalloc(hdl, strlen(locstr) + 1, FMD_SLEEP); 47 s = strstr(locstr, ": "); 48 if (s != NULL) { 49 (void) strncpy(t, locstr, s - locstr); 50 (void) strcat(t, "/"); 51 (void) strcat(t, s + 2); 52 } else { 53 (void) strcpy(t, locstr); 54 } 55 56 /* Also, remove any J number from end of this string. */ 57 s = strstr(t, "/J"); 58 if (s != NULL) 59 *s = '\0'; 60 61 if (nvlist_add_string(flt, FM_FAULT_LOCATION, t) != 0) 62 fmd_hdl_error(hdl, "unable to alloc location for fault\n"); 63 fmd_hdl_free(hdl, t, strlen(locstr) + 1); 64 return (flt); 65 } 66 67 typedef struct tr_ent { 68 const char *nac_component; 69 const char *hc_component; 70 } tr_ent_t; 71 72 static tr_ent_t tr_tbl[] = { 73 { "MB", "motherboard" }, 74 { "CPU", "cpuboard" }, 75 { "MEM", "memboard" }, 76 { "CMP", "chip" }, 77 { "BR", "branch" }, 78 { "CH", "dram-channel" }, 79 { "R", "rank" }, 80 { "D", "dimm" } 81 }; 82 83 #define tr_tbl_n sizeof (tr_tbl) / sizeof (tr_ent_t) 84 85 int 86 map_name(const char *p) { 87 int i; 88 89 for (i = 0; i < tr_tbl_n; i++) { 90 if (strncmp(p, tr_tbl[i].nac_component, 91 strlen(tr_tbl[i].nac_component)) == 0) 92 return (i); 93 } 94 return (-1); 95 } 96 97 int 98 cmd_count_components(const char *str, char sep) 99 { 100 int num = 0; 101 const char *cptr = str; 102 103 if (*cptr == sep) cptr++; /* skip initial sep */ 104 if (strlen(cptr) > 0) num = 1; 105 while ((cptr = strchr(cptr, sep)) != NULL) { 106 cptr++; 107 if (cptr == NULL || strcmp(cptr, "") == 0) break; 108 if (map_name(cptr) >= 0) num++; 109 } 110 return (num); 111 } 112 113 /* 114 * This version of breakup_components assumes that all component names which 115 * it sees are of the form: <nonnumeric piece><numeric piece> 116 * i.e. no embedded numerals in component name which have to be spelled out. 117 */ 118 119 int 120 cmd_breakup_components(char *str, char *sep, nvlist_t **hc_nvl) 121 { 122 char namebuf[64], instbuf[64]; 123 char *token, *tokbuf; 124 int i, j, namelen, instlen; 125 126 i = 0; 127 for (token = strtok_r(str, sep, &tokbuf); 128 token != NULL; 129 token = strtok_r(NULL, sep, &tokbuf)) { 130 namelen = strcspn(token, "0123456789"); 131 instlen = strspn(token+namelen, "0123456789"); 132 (void) strncpy(namebuf, token, namelen); 133 namebuf[namelen] = '\0'; 134 135 if ((j = map_name(namebuf)) < 0) 136 continue; /* skip names that don't map */ 137 138 if (instlen == 0) { 139 (void) strncpy(instbuf, "0", 2); 140 } else { 141 (void) strncpy(instbuf, token+namelen, instlen); 142 instbuf[instlen] = '\0'; 143 } 144 if (nvlist_add_string(hc_nvl[i], FM_FMRI_HC_NAME, 145 tr_tbl[j].hc_component) != 0 || 146 nvlist_add_string(hc_nvl[i], FM_FMRI_HC_ID, instbuf) != 0) 147 return (-1); 148 i++; 149 } 150 return (1); 151 } 152 153 char * 154 cmd_getfru_loc(fmd_hdl_t *hdl, nvlist_t *asru) { 155 156 char *fru_loc, *cpufru; 157 if (nvlist_lookup_string(asru, FM_FMRI_CPU_CPUFRU, &cpufru) == 0) { 158 fru_loc = strstr(cpufru, "MB"); 159 if (fru_loc != NULL) { 160 fmd_hdl_debug(hdl, "cmd_getfru_loc: fruloc=%s\n", 161 fru_loc); 162 return (fmd_hdl_strdup(hdl, fru_loc, FMD_SLEEP)); 163 } 164 } 165 fmd_hdl_debug(hdl, "cmd_getfru_loc: Default fruloc=empty string\n"); 166 return (fmd_hdl_strdup(hdl, EMPTY_STR, FMD_SLEEP)); 167 } 168 169 nvlist_t * 170 cmd_mkboard_fru(fmd_hdl_t *hdl, char *frustr, char *serialstr, char *partstr) { 171 172 char *nac, *nac_name; 173 int n, i, len; 174 nvlist_t *fru, **hc_list; 175 176 if (frustr == NULL) 177 return (NULL); 178 179 if ((nac_name = strstr(frustr, "MB")) == NULL) 180 return (NULL); 181 182 len = strlen(nac_name) + 1; 183 184 nac = fmd_hdl_zalloc(hdl, len, FMD_SLEEP); 185 (void) strcpy(nac, nac_name); 186 187 n = cmd_count_components(nac, '/'); 188 189 fmd_hdl_debug(hdl, "cmd_mkboard_fru: nac=%s components=%d\n", nac, n); 190 191 hc_list = fmd_hdl_zalloc(hdl, sizeof (nvlist_t *)*n, FMD_SLEEP); 192 193 for (i = 0; i < n; i++) { 194 (void) nvlist_alloc(&hc_list[i], 195 NV_UNIQUE_NAME|NV_UNIQUE_NAME_TYPE, 0); 196 } 197 198 if (cmd_breakup_components(nac, "/", hc_list) < 0) { 199 for (i = 0; i < n; i++) { 200 if (hc_list[i] != NULL) 201 nvlist_free(hc_list[i]); 202 } 203 fmd_hdl_free(hdl, hc_list, sizeof (nvlist_t *)*n); 204 fmd_hdl_free(hdl, nac, len); 205 return (NULL); 206 } 207 208 if (nvlist_alloc(&fru, NV_UNIQUE_NAME, 0) != 0) { 209 for (i = 0; i < n; i++) { 210 if (hc_list[i] != NULL) 211 nvlist_free(hc_list[i]); 212 } 213 fmd_hdl_free(hdl, hc_list, sizeof (nvlist_t *)*n); 214 fmd_hdl_free(hdl, nac, len); 215 return (NULL); 216 } 217 218 if (nvlist_add_uint8(fru, FM_VERSION, FM_HC_SCHEME_VERSION) != 0 || 219 nvlist_add_string(fru, FM_FMRI_SCHEME, FM_FMRI_SCHEME_HC) != 0 || 220 nvlist_add_string(fru, FM_FMRI_HC_ROOT, "") != 0 || 221 nvlist_add_uint32(fru, FM_FMRI_HC_LIST_SZ, n) != 0 || 222 nvlist_add_nvlist_array(fru, FM_FMRI_HC_LIST, hc_list, n) != 0) { 223 for (i = 0; i < n; i++) { 224 if (hc_list[i] != NULL) 225 nvlist_free(hc_list[i]); 226 } 227 fmd_hdl_free(hdl, hc_list, sizeof (nvlist_t *)*n); 228 fmd_hdl_free(hdl, nac, len); 229 nvlist_free(fru); 230 return (NULL); 231 } 232 233 for (i = 0; i < n; i++) { 234 if (hc_list[i] != NULL) 235 nvlist_free(hc_list[i]); 236 } 237 fmd_hdl_free(hdl, hc_list, sizeof (nvlist_t *)*n); 238 fmd_hdl_free(hdl, nac, len); 239 240 if ((serialstr != NULL && 241 nvlist_add_string(fru, FM_FMRI_HC_SERIAL_ID, serialstr) != 0) || 242 (partstr != NULL && 243 nvlist_add_string(fru, FM_FMRI_HC_PART, partstr) != 0)) { 244 nvlist_free(fru); 245 return (NULL); 246 } 247 248 return (fru); 249 } 250 251 nvlist_t * 252 cmd_boardfru_create_fault(fmd_hdl_t *hdl, nvlist_t *asru, const char *fltnm, 253 uint_t cert, char *loc) 254 { 255 nvlist_t *flt, *nvlfru; 256 char *serialstr, *partstr; 257 258 if ((loc == NULL) || (strcmp(loc, EMPTY_STR) == 0)) 259 return (NULL); 260 261 if (nvlist_lookup_string(asru, FM_FMRI_HC_SERIAL_ID, &serialstr) != 0) 262 serialstr = NULL; 263 if (nvlist_lookup_string(asru, FM_FMRI_HC_PART, &partstr) != 0) 264 partstr = NULL; 265 266 nvlfru = cmd_mkboard_fru(hdl, loc, serialstr, partstr); 267 if (nvlfru == NULL) 268 return (NULL); 269 270 flt = cmd_nvl_create_fault(hdl, fltnm, cert, nvlfru, nvlfru, NULL); 271 flt = cmd_fault_add_location(hdl, flt, loc); 272 if (nvlfru != NULL) 273 nvlist_free(nvlfru); 274 return (flt); 275 } 276 277 /* find_mb -- find hardware platform motherboard within libtopo */ 278 279 /* ARGSUSED */ 280 static int 281 find_mb(topo_hdl_t *thp, tnode_t *node, void *arg) 282 { 283 int err; 284 nvlist_t *rsrc, **hcl; 285 char *name; 286 uint_t n; 287 288 if (topo_node_resource(node, &rsrc, &err) < 0) { 289 return (TOPO_WALK_NEXT); /* no resource, try next */ 290 } 291 292 if (nvlist_lookup_nvlist_array(rsrc, FM_FMRI_HC_LIST, &hcl, &n) < 0) { 293 nvlist_free(rsrc); 294 return (TOPO_WALK_NEXT); 295 } 296 297 if (nvlist_lookup_string(hcl[0], FM_FMRI_HC_NAME, &name) != 0) { 298 nvlist_free(rsrc); 299 return (TOPO_WALK_NEXT); 300 } 301 302 if (strcmp(name, "motherboard") != 0) { 303 nvlist_free(rsrc); 304 return (TOPO_WALK_NEXT); /* not MB hc list, try next */ 305 } 306 307 (void) nvlist_dup(rsrc, &mb_nvl, NV_UNIQUE_NAME); 308 309 nvlist_free(rsrc); 310 return (TOPO_WALK_TERMINATE); /* if no space, give up */ 311 } 312 313 /* init_mb -- read hardware platform motherboard from libtopo */ 314 315 nvlist_t * 316 init_mb(fmd_hdl_t *hdl) 317 { 318 topo_hdl_t *thp; 319 topo_walk_t *twp; 320 int err; 321 322 if ((thp = fmd_hdl_topo_hold(hdl, TOPO_VERSION)) == NULL) 323 return (NULL); 324 if ((twp = topo_walk_init(thp, 325 FM_FMRI_SCHEME_HC, find_mb, NULL, &err)) 326 == NULL) { 327 fmd_hdl_topo_rele(hdl, thp); 328 return (NULL); 329 } 330 (void) topo_walk_step(twp, TOPO_WALK_CHILD); 331 topo_walk_fini(twp); 332 fmd_hdl_topo_rele(hdl, thp); 333 return (mb_nvl); 334 } 335