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 2009 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #include <assert.h> 28 #include <alloca.h> 29 #include <string.h> 30 #include <strings.h> 31 #include <limits.h> 32 #include <sys/types.h> 33 #include <sys/pci.h> 34 #include <sys/pcie.h> 35 #include <sys/fm/protocol.h> 36 #include <fm/topo_mod.h> 37 #include <fm/topo_hc.h> 38 #include <libdevinfo.h> 39 #include <hostbridge.h> 40 #include <pcibus.h> 41 #include <did.h> 42 #include <did_props.h> 43 #include <fm/libtopo.h> 44 45 static int ASRU_set(tnode_t *, did_t *, 46 const char *, const char *, const char *); 47 static int FRU_set(tnode_t *, did_t *, 48 const char *, const char *, const char *); 49 static int DEVprop_set(tnode_t *, did_t *, 50 const char *, const char *, const char *); 51 static int DRIVERprop_set(tnode_t *, did_t *, 52 const char *, const char *, const char *); 53 static int MODULEprop_set(tnode_t *, did_t *, 54 const char *, const char *, const char *); 55 static int EXCAP_set(tnode_t *, did_t *, 56 const char *, const char *, const char *); 57 static int BDF_set(tnode_t *, did_t *, 58 const char *, const char *, const char *); 59 static int label_set(tnode_t *, did_t *, 60 const char *, const char *, const char *); 61 static int maybe_di_chars_copy(tnode_t *, did_t *, 62 const char *, const char *, const char *); 63 static int maybe_di_uint_to_str(tnode_t *, did_t *, 64 const char *, const char *, const char *); 65 static int maybe_di_uint_to_dec_str(tnode_t *, did_t *, 66 const char *, const char *, const char *); 67 static int AADDR_set(tnode_t *, did_t *, 68 const char *, const char *, const char *); 69 70 /* 71 * Arrays of "property translation routines" to set the properties a 72 * given type of topology node should have. 73 * 74 * Note that the label_set translation *MUST COME BEFORE* the FRU 75 * translation. For the near term we're setting the FRU fmri to 76 * be a legacy-hc style FMRI based on the label, so the label needs 77 * to have been set before we do the FRU translation. 78 * 79 */ 80 81 static const topo_pgroup_info_t io_pgroup = 82 { TOPO_PGROUP_IO, TOPO_STABILITY_PRIVATE, TOPO_STABILITY_PRIVATE, 1 }; 83 static const topo_pgroup_info_t pci_pgroup = 84 { TOPO_PGROUP_PCI, TOPO_STABILITY_PRIVATE, TOPO_STABILITY_PRIVATE, 1 }; 85 86 static const topo_pgroup_info_t protocol_pgroup = { 87 TOPO_PGROUP_PROTOCOL, 88 TOPO_STABILITY_PRIVATE, 89 TOPO_STABILITY_PRIVATE, 90 1 91 }; /* Request to create protocol will be ignored by libtopo */ 92 93 txprop_t Fn_common_props[] = { 94 { NULL, &io_pgroup, TOPO_IO_DEV, DEVprop_set }, 95 { DI_DEVTYPPROP, &io_pgroup, TOPO_IO_DEVTYPE, maybe_di_chars_copy }, 96 { DI_DEVIDPROP, &pci_pgroup, TOPO_PCI_DEVID, maybe_di_uint_to_str }, 97 { NULL, &io_pgroup, TOPO_IO_DRIVER, DRIVERprop_set }, 98 { NULL, &io_pgroup, TOPO_IO_MODULE, MODULEprop_set }, 99 { "serd_io_device_nonfatal_n", &io_pgroup, "serd_io_device_nonfatal_n", 100 maybe_di_uint_to_dec_str }, 101 { "serd_io_device_nonfatal_t", &io_pgroup, "serd_io_device_nonfatal_t", 102 maybe_di_chars_copy }, 103 { "serd_io_device_nonfatal_btlp_n", &io_pgroup, 104 "serd_io_device_nonfatal_btlp_n", maybe_di_uint_to_dec_str }, 105 { "serd_io_device_nonfatal_btlp_t", &io_pgroup, 106 "serd_io_device_nonfatal_btlp_t", maybe_di_chars_copy }, 107 { "serd_io_device_nonfatal_bdllp_n", &io_pgroup, 108 "serd_io_device_nonfatal_bdllp_n", maybe_di_uint_to_dec_str }, 109 { "serd_io_device_nonfatal_bdllp_t", &io_pgroup, 110 "serd_io_device_nonfatal_bdllp_t", maybe_di_chars_copy }, 111 { "serd_io_device_nonfatal_re_n", &io_pgroup, 112 "serd_io_device_nonfatal_re_n", maybe_di_uint_to_dec_str }, 113 { "serd_io_device_nonfatal_re_t", &io_pgroup, 114 "serd_io_device_nonfatal_re_t", maybe_di_chars_copy }, 115 { "serd_io_device_nonfatal_rto_n", &io_pgroup, 116 "serd_io_device_nonfatal_rto_n", maybe_di_uint_to_dec_str }, 117 { "serd_io_device_nonfatal_rto_t", &io_pgroup, 118 "serd_io_device_nonfatal_rto_t", maybe_di_chars_copy }, 119 { "serd_io_device_nonfatal_rnr_n", &io_pgroup, 120 "serd_io_device_nonfatal_rnr_n", maybe_di_uint_to_dec_str }, 121 { "serd_io_device_nonfatal_rnr_t", &io_pgroup, 122 "serd_io_pciex_corrlink-bus_rnr_t", maybe_di_chars_copy }, 123 { "serd_io_pciex_corrlink-bus_btlp_n", &io_pgroup, 124 "serd_io_pciex_corrlink-bus_btlp_n", maybe_di_uint_to_dec_str }, 125 { "serd_io_pciex_corrlink-bus_btlp_t", &io_pgroup, 126 "serd_io_pciex_corrlink-bus_btlp_t", maybe_di_chars_copy }, 127 { "serd_io_pciex_corrlink-bus_bdllp_n", &io_pgroup, 128 "serd_io_pciex_corrlink-bus_bdllp_n", maybe_di_uint_to_dec_str }, 129 { "serd_io_pciex_corrlink-bus_bdllp_t", &io_pgroup, 130 "serd_io_pciex_corrlink-bus_bdllp_t", maybe_di_chars_copy }, 131 { "serd_io_pciex_corrlink-bus_re_n", &io_pgroup, 132 "serd_io_pciex_corrlink-bus_re_n", maybe_di_uint_to_dec_str }, 133 { "serd_io_pciex_corrlink-bus_re_t", &io_pgroup, 134 "serd_io_pciex_corrlink-bus_re_t", maybe_di_chars_copy }, 135 { "serd_io_pciex_corrlink-bus_rto_n", &io_pgroup, 136 "serd_io_pciex_corrlink-bus_rto_n", maybe_di_uint_to_dec_str }, 137 { "serd_io_pciex_corrlink-bus_rto_t", &io_pgroup, 138 "serd_io_pciex_corrlink-bus_rto_t", maybe_di_chars_copy }, 139 { "serd_io_pciex_corrlink-bus_rnr_n", &io_pgroup, 140 "serd_io_pciex_corrlink-bus_rnr_n", maybe_di_uint_to_dec_str }, 141 { "serd_io_pciex_corrlink-bus_rnr_t", &io_pgroup, 142 "serd_io_pciex_corrlink-bus_rnr_t", maybe_di_chars_copy }, 143 { NULL, &pci_pgroup, TOPO_PCI_EXCAP, EXCAP_set }, 144 { DI_CLASSPROP, &pci_pgroup, TOPO_PCI_CLASS, maybe_di_uint_to_str }, 145 { DI_VENDIDPROP, &pci_pgroup, TOPO_PCI_VENDID, maybe_di_uint_to_str }, 146 { DI_AADDRPROP, &pci_pgroup, TOPO_PCI_AADDR, AADDR_set }, 147 { NULL, &protocol_pgroup, TOPO_PROP_LABEL, label_set }, 148 { NULL, &protocol_pgroup, TOPO_PROP_FRU, FRU_set }, 149 { NULL, &protocol_pgroup, TOPO_PROP_ASRU, ASRU_set } 150 }; 151 152 txprop_t Dev_common_props[] = { 153 { NULL, &protocol_pgroup, TOPO_PROP_LABEL, label_set }, 154 { NULL, &protocol_pgroup, TOPO_PROP_FRU, FRU_set }, 155 { NULL, &protocol_pgroup, TOPO_PROP_ASRU, ASRU_set } 156 }; 157 158 txprop_t Bus_common_props[] = { 159 { DI_DEVTYPPROP, &io_pgroup, TOPO_IO_DEVTYPE, maybe_di_chars_copy }, 160 { NULL, &io_pgroup, TOPO_IO_DRIVER, DRIVERprop_set }, 161 { NULL, &io_pgroup, TOPO_IO_MODULE, MODULEprop_set }, 162 { NULL, &protocol_pgroup, TOPO_PROP_LABEL, label_set }, 163 { NULL, &protocol_pgroup, TOPO_PROP_FRU, FRU_set }, 164 { NULL, &protocol_pgroup, TOPO_PROP_ASRU, ASRU_set } 165 }; 166 167 txprop_t RC_common_props[] = { 168 { NULL, &io_pgroup, TOPO_IO_DEV, DEVprop_set }, 169 { DI_DEVTYPPROP, &io_pgroup, TOPO_IO_DEVTYPE, maybe_di_chars_copy }, 170 { NULL, &io_pgroup, TOPO_IO_DRIVER, DRIVERprop_set }, 171 { NULL, &io_pgroup, TOPO_IO_MODULE, MODULEprop_set }, 172 { NULL, &pci_pgroup, TOPO_PCI_EXCAP, EXCAP_set }, 173 { NULL, &pci_pgroup, TOPO_PCI_BDF, BDF_set }, 174 { NULL, &protocol_pgroup, TOPO_PROP_ASRU, ASRU_set }, 175 /* 176 * These props need to be put at the end of table. x86pi has its 177 * own way to set them. 178 */ 179 { NULL, &protocol_pgroup, TOPO_PROP_LABEL, label_set }, 180 { NULL, &protocol_pgroup, TOPO_PROP_FRU, FRU_set } 181 }; 182 183 txprop_t ExHB_common_props[] = { 184 { NULL, &protocol_pgroup, TOPO_PROP_ASRU, ASRU_set }, 185 /* 186 * These props need to be put at the end of table. x86pi has its 187 * own way to set them. 188 */ 189 { NULL, &protocol_pgroup, TOPO_PROP_LABEL, label_set }, 190 { NULL, &protocol_pgroup, TOPO_PROP_FRU, FRU_set } 191 }; 192 193 txprop_t IOB_common_props[] = { 194 { NULL, &protocol_pgroup, TOPO_PROP_LABEL, label_set }, 195 { NULL, &protocol_pgroup, TOPO_PROP_FRU, FRU_set }, 196 { NULL, &protocol_pgroup, TOPO_PROP_ASRU, ASRU_set } 197 }; 198 199 txprop_t HB_common_props[] = { 200 { NULL, &io_pgroup, TOPO_IO_DEV, DEVprop_set }, 201 { NULL, &io_pgroup, TOPO_IO_DRIVER, DRIVERprop_set }, 202 { NULL, &io_pgroup, TOPO_IO_MODULE, MODULEprop_set }, 203 { NULL, &protocol_pgroup, TOPO_PROP_ASRU, ASRU_set }, 204 /* 205 * These props need to be put at the end of table. x86pi has its 206 * own way to set them. 207 */ 208 { NULL, &protocol_pgroup, TOPO_PROP_LABEL, label_set }, 209 { NULL, &protocol_pgroup, TOPO_PROP_FRU, FRU_set } 210 }; 211 212 int Bus_propcnt = sizeof (Bus_common_props) / sizeof (txprop_t); 213 int Dev_propcnt = sizeof (Dev_common_props) / sizeof (txprop_t); 214 int ExHB_propcnt = sizeof (ExHB_common_props) / sizeof (txprop_t); 215 int HB_propcnt = sizeof (HB_common_props) / sizeof (txprop_t); 216 int IOB_propcnt = sizeof (IOB_common_props) / sizeof (txprop_t); 217 int RC_propcnt = sizeof (RC_common_props) / sizeof (txprop_t); 218 int Fn_propcnt = sizeof (Fn_common_props) / sizeof (txprop_t); 219 220 /* 221 * If this devinfo node came originally from OBP data, we'll have prom 222 * properties associated with the node where we can find properties of 223 * interest. We ignore anything after the the first four bytes of the 224 * property, and interpet those first four bytes as our unsigned 225 * integer. If we don't find the property or it's not large enough, 226 * 'val' will remained unchanged and we'll return -1. Otherwise 'val' 227 * gets updated with the property value and we return 0. 228 */ 229 static int 230 promprop2uint(topo_mod_t *mod, di_node_t n, const char *propnm, uint_t *val) 231 { 232 di_prom_handle_t ptp = DI_PROM_HANDLE_NIL; 233 di_prom_prop_t pp = DI_PROM_PROP_NIL; 234 uchar_t *buf; 235 236 if ((ptp = topo_mod_prominfo(mod)) == DI_PROM_HANDLE_NIL) 237 return (-1); 238 239 while ((pp = di_prom_prop_next(ptp, n, pp)) != DI_PROM_PROP_NIL) { 240 if (strcmp(di_prom_prop_name(pp), propnm) == 0) { 241 if (di_prom_prop_data(pp, &buf) < sizeof (uint_t)) 242 continue; 243 bcopy(buf, val, sizeof (uint_t)); 244 return (0); 245 } 246 } 247 return (-1); 248 } 249 250 /* 251 * If this devinfo node was added by the PCI hotplug framework it 252 * doesn't have the PROM properties, but hopefully has the properties 253 * we're looking for attached directly to the devinfo node. We only 254 * care about the first four bytes of the property, which we read as 255 * our unsigned integer. The remaining bytes are ignored. If we 256 * don't find the property we're looking for, or can't get its value, 257 * 'val' remains unchanged and we return -1. Otherwise 'val' gets the 258 * property value and we return 0. 259 */ 260 static int 261 hwprop2uint(di_node_t n, const char *propnm, uint_t *val) 262 { 263 di_prop_t hp = DI_PROP_NIL; 264 uchar_t *buf; 265 266 while ((hp = di_prop_next(n, hp)) != DI_PROP_NIL) { 267 if (strcmp(di_prop_name(hp), propnm) == 0) { 268 if (di_prop_bytes(hp, &buf) < sizeof (uint_t)) 269 continue; 270 bcopy(buf, val, sizeof (uint_t)); 271 return (0); 272 } 273 } 274 return (-1); 275 } 276 277 int 278 di_uintprop_get(topo_mod_t *mod, di_node_t n, const char *pnm, uint_t *pv) 279 { 280 if (hwprop2uint(n, pnm, pv) < 0) 281 if (promprop2uint(mod, n, pnm, pv) < 0) 282 return (-1); 283 return (0); 284 } 285 286 int 287 di_bytes_get(topo_mod_t *mod, di_node_t n, const char *pnm, int *sz, 288 uchar_t **db) 289 { 290 di_prom_handle_t ptp = DI_PROM_HANDLE_NIL; 291 di_prom_prop_t pp = DI_PROM_PROP_NIL; 292 di_prop_t hp = DI_PROP_NIL; 293 294 if ((ptp = topo_mod_prominfo(mod)) == DI_PROM_HANDLE_NIL) 295 return (-1); 296 297 *sz = -1; 298 while ((hp = di_prop_next(n, hp)) != DI_PROP_NIL) { 299 if (strcmp(di_prop_name(hp), pnm) == 0) { 300 if ((*sz = di_prop_bytes(hp, db)) < 0) 301 continue; 302 break; 303 } 304 } 305 if (*sz < 0) { 306 while ((pp = di_prom_prop_next(ptp, n, pp)) != 307 DI_PROM_PROP_NIL) { 308 if (strcmp(di_prom_prop_name(pp), pnm) == 0) { 309 *sz = di_prom_prop_data(pp, db); 310 if (*sz < 0) 311 continue; 312 break; 313 } 314 } 315 } 316 317 if (*sz < 0) 318 return (-1); 319 return (0); 320 } 321 322 /* 323 * fix_dev_prop -- sometimes di_devfs_path() doesn't tell the whole 324 * story, leaving off the device and function number. Chances are if 325 * devfs doesn't put these on then we'll never see this device as an 326 * error detector called out in an ereport. Unfortunately, there are 327 * races and we sometimes do get ereports from devices that devfs 328 * decides aren't there. For example, the error injector card seems 329 * to bounce in and out of existence according to devfs. We tack on 330 * the missing dev and fn here so that the DEV property used to look 331 * up the topology node is correct. 332 */ 333 static char * 334 dev_path_fix(topo_mod_t *mp, char *path, int devno, int fnno) 335 { 336 char *lastslash; 337 char *newpath; 338 int need; 339 340 /* 341 * We only care about the last component of the dev path. If 342 * we don't find a slash, something is weird. 343 */ 344 lastslash = strrchr(path, '/'); 345 assert(lastslash != NULL); 346 347 /* 348 * If an @ sign is present in the last component, the 349 * di_devfs_path() result had the device,fn unit-address. 350 * In that case there's nothing we need do. 351 */ 352 if (strchr(lastslash, '@') != NULL) 353 return (path); 354 355 if (fnno == 0) 356 need = snprintf(NULL, 0, "%s@%x", path, devno); 357 else 358 need = snprintf(NULL, 0, "%s@%x,%x", path, devno, fnno); 359 need++; 360 361 if ((newpath = topo_mod_alloc(mp, need)) == NULL) { 362 topo_mod_strfree(mp, path); 363 return (NULL); 364 } 365 366 if (fnno == 0) 367 (void) snprintf(newpath, need, "%s@%x", path, devno); 368 else 369 (void) snprintf(newpath, need, "%s@%x,%x", path, devno, fnno); 370 371 topo_mod_strfree(mp, path); 372 return (newpath); 373 } 374 375 /* 376 * dev_for_hostbridge() -- For hostbridges we truncate the devfs path 377 * after the first element in the bus address. 378 */ 379 static char * 380 dev_for_hostbridge(topo_mod_t *mp, char *path) 381 { 382 char *lastslash; 383 char *newpath; 384 char *comma; 385 int plen; 386 387 plen = strlen(path) + 1; 388 389 /* 390 * We only care about the last component of the dev path. If 391 * we don't find a slash, something is weird. 392 */ 393 lastslash = strrchr(path, '/'); 394 assert(lastslash != NULL); 395 396 /* 397 * Find the comma in the last component component@x,y, and 398 * truncate the comma and any following number. 399 */ 400 comma = strchr(lastslash, ','); 401 assert(comma != NULL); 402 403 *comma = '\0'; 404 if ((newpath = topo_mod_strdup(mp, path)) == NULL) { 405 topo_mod_free(mp, path, plen); 406 return (NULL); 407 } 408 409 *comma = ','; 410 topo_mod_free(mp, path, plen); 411 return (newpath); 412 } 413 414 /*ARGSUSED*/ 415 static int 416 ASRU_set(tnode_t *tn, did_t *pd, 417 const char *dpnm, const char *tpgrp, const char *tpnm) 418 { 419 topo_mod_t *mp; 420 nvlist_t *fmri; 421 char *dnpath, *path, *fpath, *nm; 422 int d, e, f; 423 424 /* 425 * If this topology node represents a function of device, 426 * set the ASRU to a dev scheme FMRI based on the value of 427 * di_devfs_path(). If that path is NULL, set the ASRU to 428 * be the resource describing this topology node. If this 429 * isn't a function, inherit any ASRU from the parent. 430 */ 431 mp = did_mod(pd); 432 nm = topo_node_name(tn); 433 if ((strcmp(nm, PCI_BUS) == 0 && did_gettnode(pd) && 434 strcmp(topo_node_name(did_gettnode(pd)), HOSTBRIDGE) == 0) || 435 strcmp(nm, PCI_FUNCTION) == 0 || strcmp(nm, PCIEX_FUNCTION) == 0 || 436 strcmp(nm, PCIEX_ROOT) == 0) { 437 if ((dnpath = di_devfs_path(did_dinode(pd))) != NULL) { 438 /* 439 * Dup the path, dev_path_fix() may replace it and 440 * dev_path_fix() wouldn't know to use 441 * di_devfs_path_free() 442 */ 443 if ((path = topo_mod_strdup(mp, dnpath)) == NULL) { 444 di_devfs_path_free(dnpath); 445 return (topo_mod_seterrno(mp, EMOD_NOMEM)); 446 } 447 di_devfs_path_free(dnpath); 448 did_BDF(pd, NULL, &d, &f); 449 if ((fpath = dev_path_fix(mp, path, d, f)) == NULL) 450 return (topo_mod_seterrno(mp, EMOD_NOMEM)); 451 452 fmri = topo_mod_devfmri(mp, FM_DEV_SCHEME_VERSION, 453 fpath, NULL); 454 if (fmri == NULL) { 455 topo_mod_dprintf(mp, 456 "dev:///%s fmri creation failed.\n", fpath); 457 topo_mod_strfree(mp, fpath); 458 return (-1); 459 } 460 topo_mod_strfree(mp, fpath); 461 } else { 462 topo_mod_dprintf(mp, "NULL di_devfs_path.\n"); 463 if (topo_prop_get_fmri(tn, TOPO_PGROUP_PROTOCOL, 464 TOPO_PROP_RESOURCE, &fmri, &e) < 0) 465 return (topo_mod_seterrno(mp, e)); 466 } 467 if (topo_node_asru_set(tn, fmri, 0, &e) < 0) { 468 nvlist_free(fmri); 469 return (topo_mod_seterrno(mp, e)); 470 } 471 nvlist_free(fmri); 472 return (0); 473 } 474 (void) topo_node_asru_set(tn, NULL, 0, &e); 475 476 return (0); 477 } 478 479 /* 480 * Set the FRU property to the hc fmri of this tnode 481 */ 482 int 483 FRU_fmri_set(topo_mod_t *mp, tnode_t *tn) 484 { 485 nvlist_t *fmri; 486 int err, e; 487 488 if (topo_node_resource(tn, &fmri, &err) < 0 || 489 fmri == NULL) { 490 topo_mod_dprintf(mp, "FRU_fmri_set error: %s\n", 491 topo_strerror(topo_mod_errno(mp))); 492 return (topo_mod_seterrno(mp, err)); 493 } 494 e = topo_node_fru_set(tn, fmri, 0, &err); 495 nvlist_free(fmri); 496 if (e < 0) 497 return (topo_mod_seterrno(mp, err)); 498 return (0); 499 } 500 501 tnode_t * 502 find_predecessor(tnode_t *tn, char *mod_name) 503 { 504 tnode_t *pnode = topo_node_parent(tn); 505 506 while (pnode && (strcmp(topo_node_name(pnode), mod_name) != 0)) { 507 pnode = topo_node_parent(pnode); 508 } 509 return (pnode); 510 } 511 512 static int 513 use_predecessor_fru(tnode_t *tn, char *mod_name) 514 { 515 tnode_t *pnode = NULL; 516 nvlist_t *fru = NULL; 517 int err = 0; 518 519 if ((pnode = find_predecessor(tn, mod_name)) == NULL) 520 return (-1); 521 if ((pnode = topo_node_parent(pnode)) == NULL) 522 return (-1); 523 if (topo_node_fru(pnode, &fru, NULL, &err) != 0) 524 return (-1); 525 526 (void) topo_node_fru_set(tn, fru, 0, &err); 527 nvlist_free(fru); 528 529 return (0); 530 } 531 532 static int 533 use_predecessor_label(topo_mod_t *mod, tnode_t *tn, char *mod_name) 534 { 535 tnode_t *pnode = NULL; 536 int err = 0; 537 char *plabel = NULL; 538 539 if ((pnode = find_predecessor(tn, mod_name)) == NULL) 540 return (-1); 541 if ((pnode = topo_node_parent(pnode)) == NULL) 542 return (-1); 543 if (topo_node_label(pnode, &plabel, &err) != 0 || plabel == NULL) 544 return (-1); 545 546 (void) topo_node_label_set(tn, plabel, &err); 547 548 topo_mod_strfree(mod, plabel); 549 550 return (0); 551 } 552 553 554 /*ARGSUSED*/ 555 static int 556 FRU_set(tnode_t *tn, did_t *pd, 557 const char *dpnm, const char *tpgrp, const char *tpnm) 558 { 559 topo_mod_t *mp; 560 char *nm; 561 int e = 0, err = 0; 562 563 nm = topo_node_name(tn); 564 mp = did_mod(pd); 565 566 /* 567 * If this is a PCIEX_BUS and its parent is a PCIEX_ROOT, 568 * check for a CPUBOARD predecessor. If found, inherit its 569 * parent's FRU. Otherwise, continue with FRU set. 570 */ 571 if ((strcmp(nm, PCIEX_BUS) == 0) && 572 (strcmp(topo_node_name(topo_node_parent(tn)), PCIEX_ROOT) == 0)) { 573 574 if (use_predecessor_fru(tn, CPUBOARD) == 0) 575 return (0); 576 } 577 /* 578 * If this topology node represents something other than an 579 * ioboard or a device that implements a slot, inherit the 580 * parent's FRU value. If there is no label, inherit our 581 * parent's FRU value. Otherwise, munge up an fmri based on 582 * the label. 583 */ 584 if (strcmp(nm, IOBOARD) != 0 && strcmp(nm, PCI_DEVICE) != 0 && 585 strcmp(nm, PCIEX_DEVICE) != 0 && strcmp(nm, PCIEX_BUS) != 0) { 586 (void) topo_node_fru_set(tn, NULL, 0, &e); 587 return (0); 588 } 589 590 /* 591 * If ioboard, set fru fmri to hc fmri 592 */ 593 if (strcmp(nm, IOBOARD) == 0) { 594 e = FRU_fmri_set(mp, tn); 595 return (e); 596 } else if (strcmp(nm, PCI_DEVICE) == 0 || 597 strcmp(nm, PCIEX_DEVICE) == 0 || strcmp(nm, PCIEX_BUS) == 0) { 598 nvlist_t *in, *out; 599 600 mp = did_mod(pd); 601 if (topo_mod_nvalloc(mp, &in, NV_UNIQUE_NAME) != 0) 602 return (topo_mod_seterrno(mp, EMOD_FMRI_NVL)); 603 if (nvlist_add_uint64(in, "nv1", (uintptr_t)pd) != 0) { 604 nvlist_free(in); 605 return (topo_mod_seterrno(mp, EMOD_NOMEM)); 606 } 607 if (topo_method_invoke(tn, 608 TOPO_METH_FRU_COMPUTE, TOPO_METH_FRU_COMPUTE_VERSION, 609 in, &out, &err) != 0) { 610 nvlist_free(in); 611 return (topo_mod_seterrno(mp, err)); 612 } 613 nvlist_free(in); 614 (void) topo_node_fru_set(tn, out, 0, &err); 615 nvlist_free(out); 616 } else 617 (void) topo_node_fru_set(tn, NULL, 0, &err); 618 619 return (0); 620 } 621 622 /*ARGSUSED*/ 623 static int 624 label_set(tnode_t *tn, did_t *pd, 625 const char *dpnm, const char *tpgrp, const char *tpnm) 626 { 627 topo_mod_t *mp; 628 nvlist_t *in, *out; 629 char *label; 630 int err; 631 632 mp = did_mod(pd); 633 /* 634 * If this is a PCIEX_BUS and its parent is a PCIEX_ROOT, 635 * check for a CPUBOARD predecessor. If found, inherit its 636 * parent's Label. Otherwise, continue with label set. 637 */ 638 if ((strcmp(topo_node_name(tn), PCIEX_BUS) == 0) && 639 (strcmp(topo_node_name(topo_node_parent(tn)), PCIEX_ROOT) == 0)) { 640 641 if (use_predecessor_label(mp, tn, CPUBOARD) == 0) 642 return (0); 643 } 644 if (topo_mod_nvalloc(mp, &in, NV_UNIQUE_NAME) != 0) 645 return (topo_mod_seterrno(mp, EMOD_FMRI_NVL)); 646 if (nvlist_add_uint64(in, TOPO_METH_LABEL_ARG_NVL, (uintptr_t)pd) != 647 0) { 648 nvlist_free(in); 649 return (topo_mod_seterrno(mp, EMOD_NOMEM)); 650 } 651 if (topo_method_invoke(tn, 652 TOPO_METH_LABEL, TOPO_METH_LABEL_VERSION, in, &out, &err) != 0) { 653 nvlist_free(in); 654 return (topo_mod_seterrno(mp, err)); 655 } 656 nvlist_free(in); 657 if (out != NULL && 658 nvlist_lookup_string(out, TOPO_METH_LABEL_RET_STR, &label) == 0) { 659 if (topo_prop_set_string(tn, TOPO_PGROUP_PROTOCOL, 660 TOPO_PROP_LABEL, TOPO_PROP_IMMUTABLE, label, &err) != 0) { 661 nvlist_free(out); 662 return (topo_mod_seterrno(mp, err)); 663 } 664 nvlist_free(out); 665 } 666 return (0); 667 } 668 669 /*ARGSUSED*/ 670 static int 671 EXCAP_set(tnode_t *tn, did_t *pd, 672 const char *dpnm, const char *tpgrp, const char *tpnm) 673 { 674 int excap = did_excap(pd); 675 int err; 676 int e = 0; 677 678 switch (excap & PCIE_PCIECAP_DEV_TYPE_MASK) { 679 case PCIE_PCIECAP_DEV_TYPE_ROOT: 680 e = topo_prop_set_string(tn, TOPO_PGROUP_PCI, 681 TOPO_PCI_EXCAP, TOPO_PROP_IMMUTABLE, PCIEX_ROOT, &err); 682 break; 683 case PCIE_PCIECAP_DEV_TYPE_UP: 684 e = topo_prop_set_string(tn, TOPO_PGROUP_PCI, 685 TOPO_PCI_EXCAP, TOPO_PROP_IMMUTABLE, PCIEX_SWUP, &err); 686 break; 687 case PCIE_PCIECAP_DEV_TYPE_DOWN: 688 e = topo_prop_set_string(tn, TOPO_PGROUP_PCI, 689 TOPO_PCI_EXCAP, TOPO_PROP_IMMUTABLE, PCIEX_SWDWN, &err); 690 break; 691 case PCIE_PCIECAP_DEV_TYPE_PCI2PCIE: 692 e = topo_prop_set_string(tn, TOPO_PGROUP_PCI, 693 TOPO_PCI_EXCAP, TOPO_PROP_IMMUTABLE, PCIEX_BUS, &err); 694 break; 695 case PCIE_PCIECAP_DEV_TYPE_PCIE2PCI: 696 e = topo_prop_set_string(tn, TOPO_PGROUP_PCI, 697 TOPO_PCI_EXCAP, TOPO_PROP_IMMUTABLE, PCI_BUS, &err); 698 break; 699 case PCIE_PCIECAP_DEV_TYPE_PCIE_DEV: 700 e = topo_prop_set_string(tn, TOPO_PGROUP_PCI, 701 TOPO_PCI_EXCAP, TOPO_PROP_IMMUTABLE, PCIEX_DEVICE, &err); 702 break; 703 } 704 if (e != 0) 705 return (topo_mod_seterrno(did_mod(pd), err)); 706 return (0); 707 } 708 709 /*ARGSUSED*/ 710 static int 711 DEVprop_set(tnode_t *tn, did_t *pd, 712 const char *dpnm, const char *tpgrp, const char *tpnm) 713 { 714 topo_mod_t *mp; 715 char *dnpath; 716 char *path, *fpath; 717 int d, f; 718 int err, e; 719 720 mp = did_mod(pd); 721 if ((dnpath = di_devfs_path(did_dinode(pd))) == NULL) { 722 topo_mod_dprintf(mp, "NULL di_devfs_path.\n"); 723 return (topo_mod_seterrno(mp, ETOPO_PROP_NOENT)); 724 } 725 if ((path = topo_mod_strdup(mp, dnpath)) == NULL) { 726 di_devfs_path_free(dnpath); 727 return (-1); 728 } 729 di_devfs_path_free(dnpath); 730 731 /* The DEV path is modified for hostbridges */ 732 if (strcmp(topo_node_name(tn), HOSTBRIDGE) == 0) { 733 fpath = dev_for_hostbridge(did_mod(pd), path); 734 } else { 735 did_BDF(pd, NULL, &d, &f); 736 fpath = dev_path_fix(mp, path, d, f); 737 } 738 if (fpath == NULL) 739 return (-1); 740 e = topo_prop_set_string(tn, 741 tpgrp, tpnm, TOPO_PROP_IMMUTABLE, fpath, &err); 742 topo_mod_strfree(mp, fpath); 743 if (e != 0) 744 return (topo_mod_seterrno(mp, err)); 745 return (0); 746 } 747 748 /*ARGSUSED*/ 749 static int 750 DRIVERprop_set(tnode_t *tn, did_t *pd, 751 const char *dpnm, const char *tpgrp, const char *tpnm) 752 { 753 char *dnm; 754 int err; 755 756 if ((dnm = di_driver_name(did_dinode(pd))) == NULL) 757 return (0); 758 if (topo_prop_set_string(tn, 759 tpgrp, tpnm, TOPO_PROP_IMMUTABLE, dnm, &err) < 0) 760 return (topo_mod_seterrno(did_mod(pd), err)); 761 762 return (0); 763 } 764 765 /*ARGSUSED*/ 766 static int 767 MODULEprop_set(tnode_t *tn, did_t *pd, 768 const char *dpnm, const char *tpgrp, const char *tpnm) 769 { 770 nvlist_t *mod; 771 topo_mod_t *mp; 772 char *dnm; 773 int err; 774 775 if ((dnm = di_driver_name(did_dinode(pd))) == NULL) 776 return (0); 777 778 mp = did_mod(pd); 779 if ((mod = topo_mod_modfmri(mp, FM_MOD_SCHEME_VERSION, dnm)) == NULL) 780 return (0); /* driver maybe detached, return success */ 781 782 if (topo_prop_set_fmri(tn, tpgrp, tpnm, TOPO_PROP_IMMUTABLE, mod, 783 &err) < 0) { 784 nvlist_free(mod); 785 return (topo_mod_seterrno(mp, err)); 786 } 787 nvlist_free(mod); 788 789 return (0); 790 } 791 792 /*ARGSUSED*/ 793 static int 794 maybe_di_chars_copy(tnode_t *tn, did_t *pd, 795 const char *dpnm, const char *tpgrp, const char *tpnm) 796 { 797 topo_mod_t *mp; 798 uchar_t *typbuf; 799 char *tmpbuf; 800 int sz = -1; 801 int err, e; 802 803 if (di_bytes_get(did_mod(pd), did_dinode(pd), dpnm, &sz, &typbuf) < 0) 804 return (0); 805 mp = did_mod(pd); 806 807 if ((tmpbuf = topo_mod_alloc(mp, sz + 1)) == NULL) 808 return (topo_mod_seterrno(mp, EMOD_NOMEM)); 809 810 bcopy(typbuf, tmpbuf, sz); 811 tmpbuf[sz] = 0; 812 e = topo_prop_set_string(tn, 813 tpgrp, tpnm, TOPO_PROP_IMMUTABLE, tmpbuf, &err); 814 topo_mod_free(mp, tmpbuf, sz + 1); 815 if (e != 0) 816 return (topo_mod_seterrno(mp, err)); 817 return (0); 818 } 819 820 static int 821 uint_to_strprop(topo_mod_t *mp, uint_t v, tnode_t *tn, 822 const char *tpgrp, const char *tpnm) 823 { 824 char str[21]; /* sizeof (UINT64_MAX) + '\0' */ 825 int e; 826 827 (void) snprintf(str, 21, "%x", v); 828 if (topo_prop_set_string(tn, 829 tpgrp, tpnm, TOPO_PROP_IMMUTABLE, str, &e) < 0) 830 return (topo_mod_seterrno(mp, e)); 831 return (0); 832 } 833 834 static int 835 maybe_di_uint_to_str(tnode_t *tn, did_t *pd, 836 const char *dpnm, const char *tpgrp, const char *tpnm) 837 { 838 uint_t v; 839 840 if (di_uintprop_get(did_mod(pd), did_dinode(pd), dpnm, &v) < 0) 841 return (0); 842 843 return (uint_to_strprop(did_mod(pd), v, tn, tpgrp, tpnm)); 844 } 845 846 static int 847 uint_to_dec_strprop(topo_mod_t *mp, uint_t v, tnode_t *tn, 848 const char *tpgrp, const char *tpnm) 849 { 850 char str[21]; /* sizeof (UINT64_MAX) + '\0' */ 851 int e; 852 853 (void) snprintf(str, 21, "%d", v); 854 if (topo_prop_set_string(tn, 855 tpgrp, tpnm, TOPO_PROP_IMMUTABLE, str, &e) < 0) 856 return (topo_mod_seterrno(mp, e)); 857 return (0); 858 } 859 860 static int 861 maybe_di_uint_to_dec_str(tnode_t *tn, did_t *pd, 862 const char *dpnm, const char *tpgrp, const char *tpnm) 863 { 864 uint_t v; 865 866 if (di_uintprop_get(did_mod(pd), did_dinode(pd), dpnm, &v) < 0) 867 return (0); 868 869 return (uint_to_dec_strprop(did_mod(pd), v, tn, tpgrp, tpnm)); 870 } 871 872 static int 873 AADDR_set(tnode_t *tn, did_t *pd, const char *dpnm, const char *tpgrp, 874 const char *tpnm) 875 { 876 topo_mod_t *mp; 877 uchar_t *typbuf; 878 int sz = -1; 879 int err, e; 880 881 if (di_bytes_get(did_mod(pd), did_dinode(pd), dpnm, &sz, &typbuf) < 0) 882 return (0); 883 884 mp = did_mod(pd); 885 886 e = topo_prop_set_uint32_array(tn, tpgrp, tpnm, TOPO_PROP_IMMUTABLE, 887 /*LINTED*/ 888 (uint32_t *)typbuf, sz/4, &err); 889 890 if (e != 0) 891 return (topo_mod_seterrno(mp, err)); 892 return (0); 893 } 894 895 /*ARGSUSED*/ 896 static int 897 BDF_set(tnode_t *tn, did_t *pd, const char *dpnm, const char *tpgrp, 898 const char *tpnm) 899 { 900 int bdf; 901 char str[23]; /* '0x' + sizeof (UINT64_MAX) + '\0' */ 902 int e; 903 904 if ((bdf = did_bdf(pd)) <= 0) 905 return (0); 906 907 (void) snprintf(str, 23, "0x%x", bdf); 908 if (topo_prop_set_string(tn, 909 tpgrp, tpnm, TOPO_PROP_IMMUTABLE, str, &e) < 0) 910 return (topo_mod_seterrno(did_mod(pd), e)); 911 return (0); 912 } 913 914 int 915 did_props_set(tnode_t *tn, did_t *pd, txprop_t txarray[], int txnum) 916 { 917 topo_mod_t *mp; 918 int i, r, e; 919 920 mp = did_mod(pd); 921 for (i = 0; i < txnum; i++) { 922 /* 923 * Ensure the property group has been created. 924 */ 925 if (txarray[i].tx_tpgroup != NULL) { 926 if (topo_pgroup_create(tn, txarray[i].tx_tpgroup, &e) 927 < 0) { 928 if (e != ETOPO_PROP_DEFD) 929 return (topo_mod_seterrno(mp, e)); 930 } 931 } 932 933 topo_mod_dprintf(mp, 934 "Setting property %s in group %s.\n", 935 txarray[i].tx_tprop, txarray[i].tx_tpgroup->tpi_name); 936 r = txarray[i].tx_xlate(tn, pd, 937 txarray[i].tx_diprop, txarray[i].tx_tpgroup->tpi_name, 938 txarray[i].tx_tprop); 939 if (r != 0) { 940 topo_mod_dprintf(mp, "failed.\n"); 941 topo_mod_dprintf(mp, "Error was %s.\n", 942 topo_strerror(topo_mod_errno(mp))); 943 return (-1); 944 } 945 topo_mod_dprintf(mp, "succeeded.\n"); 946 } 947 return (0); 948 } 949