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 if (out != NULL) 616 nvlist_free(out); 617 } else 618 (void) topo_node_fru_set(tn, NULL, 0, &err); 619 620 return (0); 621 } 622 623 /*ARGSUSED*/ 624 static int 625 label_set(tnode_t *tn, did_t *pd, 626 const char *dpnm, const char *tpgrp, const char *tpnm) 627 { 628 topo_mod_t *mp; 629 nvlist_t *in, *out; 630 char *label; 631 int err; 632 633 mp = did_mod(pd); 634 /* 635 * If this is a PCIEX_BUS and its parent is a PCIEX_ROOT, 636 * check for a CPUBOARD predecessor. If found, inherit its 637 * parent's Label. Otherwise, continue with label set. 638 */ 639 if ((strcmp(topo_node_name(tn), PCIEX_BUS) == 0) && 640 (strcmp(topo_node_name(topo_node_parent(tn)), PCIEX_ROOT) == 0)) { 641 642 if (use_predecessor_label(mp, tn, CPUBOARD) == 0) 643 return (0); 644 } 645 if (topo_mod_nvalloc(mp, &in, NV_UNIQUE_NAME) != 0) 646 return (topo_mod_seterrno(mp, EMOD_FMRI_NVL)); 647 if (nvlist_add_uint64(in, TOPO_METH_LABEL_ARG_NVL, (uintptr_t)pd) != 648 0) { 649 nvlist_free(in); 650 return (topo_mod_seterrno(mp, EMOD_NOMEM)); 651 } 652 if (topo_method_invoke(tn, 653 TOPO_METH_LABEL, TOPO_METH_LABEL_VERSION, in, &out, &err) != 0) { 654 nvlist_free(in); 655 return (topo_mod_seterrno(mp, err)); 656 } 657 nvlist_free(in); 658 if (out != NULL && 659 nvlist_lookup_string(out, TOPO_METH_LABEL_RET_STR, &label) == 0) { 660 if (topo_prop_set_string(tn, TOPO_PGROUP_PROTOCOL, 661 TOPO_PROP_LABEL, TOPO_PROP_IMMUTABLE, label, &err) != 0) { 662 nvlist_free(out); 663 return (topo_mod_seterrno(mp, err)); 664 } 665 nvlist_free(out); 666 } 667 return (0); 668 } 669 670 /*ARGSUSED*/ 671 static int 672 EXCAP_set(tnode_t *tn, did_t *pd, 673 const char *dpnm, const char *tpgrp, const char *tpnm) 674 { 675 int excap = did_excap(pd); 676 int err; 677 int e = 0; 678 679 switch (excap & PCIE_PCIECAP_DEV_TYPE_MASK) { 680 case PCIE_PCIECAP_DEV_TYPE_ROOT: 681 e = topo_prop_set_string(tn, TOPO_PGROUP_PCI, 682 TOPO_PCI_EXCAP, TOPO_PROP_IMMUTABLE, PCIEX_ROOT, &err); 683 break; 684 case PCIE_PCIECAP_DEV_TYPE_UP: 685 e = topo_prop_set_string(tn, TOPO_PGROUP_PCI, 686 TOPO_PCI_EXCAP, TOPO_PROP_IMMUTABLE, PCIEX_SWUP, &err); 687 break; 688 case PCIE_PCIECAP_DEV_TYPE_DOWN: 689 e = topo_prop_set_string(tn, TOPO_PGROUP_PCI, 690 TOPO_PCI_EXCAP, TOPO_PROP_IMMUTABLE, PCIEX_SWDWN, &err); 691 break; 692 case PCIE_PCIECAP_DEV_TYPE_PCI2PCIE: 693 e = topo_prop_set_string(tn, TOPO_PGROUP_PCI, 694 TOPO_PCI_EXCAP, TOPO_PROP_IMMUTABLE, PCIEX_BUS, &err); 695 break; 696 case PCIE_PCIECAP_DEV_TYPE_PCIE2PCI: 697 e = topo_prop_set_string(tn, TOPO_PGROUP_PCI, 698 TOPO_PCI_EXCAP, TOPO_PROP_IMMUTABLE, PCI_BUS, &err); 699 break; 700 case PCIE_PCIECAP_DEV_TYPE_PCIE_DEV: 701 e = topo_prop_set_string(tn, TOPO_PGROUP_PCI, 702 TOPO_PCI_EXCAP, TOPO_PROP_IMMUTABLE, PCIEX_DEVICE, &err); 703 break; 704 } 705 if (e != 0) 706 return (topo_mod_seterrno(did_mod(pd), err)); 707 return (0); 708 } 709 710 /*ARGSUSED*/ 711 static int 712 DEVprop_set(tnode_t *tn, did_t *pd, 713 const char *dpnm, const char *tpgrp, const char *tpnm) 714 { 715 topo_mod_t *mp; 716 char *dnpath; 717 char *path, *fpath; 718 int d, f; 719 int err, e; 720 721 mp = did_mod(pd); 722 if ((dnpath = di_devfs_path(did_dinode(pd))) == NULL) { 723 topo_mod_dprintf(mp, "NULL di_devfs_path.\n"); 724 return (topo_mod_seterrno(mp, ETOPO_PROP_NOENT)); 725 } 726 if ((path = topo_mod_strdup(mp, dnpath)) == NULL) { 727 di_devfs_path_free(dnpath); 728 return (-1); 729 } 730 di_devfs_path_free(dnpath); 731 732 /* The DEV path is modified for hostbridges */ 733 if (strcmp(topo_node_name(tn), HOSTBRIDGE) == 0) { 734 fpath = dev_for_hostbridge(did_mod(pd), path); 735 } else { 736 did_BDF(pd, NULL, &d, &f); 737 fpath = dev_path_fix(mp, path, d, f); 738 } 739 if (fpath == NULL) 740 return (-1); 741 e = topo_prop_set_string(tn, 742 tpgrp, tpnm, TOPO_PROP_IMMUTABLE, fpath, &err); 743 topo_mod_strfree(mp, fpath); 744 if (e != 0) 745 return (topo_mod_seterrno(mp, err)); 746 return (0); 747 } 748 749 /*ARGSUSED*/ 750 static int 751 DRIVERprop_set(tnode_t *tn, did_t *pd, 752 const char *dpnm, const char *tpgrp, const char *tpnm) 753 { 754 char *dnm; 755 int err; 756 757 if ((dnm = di_driver_name(did_dinode(pd))) == NULL) 758 return (0); 759 if (topo_prop_set_string(tn, 760 tpgrp, tpnm, TOPO_PROP_IMMUTABLE, dnm, &err) < 0) 761 return (topo_mod_seterrno(did_mod(pd), err)); 762 763 return (0); 764 } 765 766 /*ARGSUSED*/ 767 static int 768 MODULEprop_set(tnode_t *tn, did_t *pd, 769 const char *dpnm, const char *tpgrp, const char *tpnm) 770 { 771 nvlist_t *mod; 772 topo_mod_t *mp; 773 char *dnm; 774 int err; 775 776 if ((dnm = di_driver_name(did_dinode(pd))) == NULL) 777 return (0); 778 779 mp = did_mod(pd); 780 if ((mod = topo_mod_modfmri(mp, FM_MOD_SCHEME_VERSION, dnm)) == NULL) 781 return (0); /* driver maybe detached, return success */ 782 783 if (topo_prop_set_fmri(tn, tpgrp, tpnm, TOPO_PROP_IMMUTABLE, mod, 784 &err) < 0) { 785 nvlist_free(mod); 786 return (topo_mod_seterrno(mp, err)); 787 } 788 nvlist_free(mod); 789 790 return (0); 791 } 792 793 /*ARGSUSED*/ 794 static int 795 maybe_di_chars_copy(tnode_t *tn, did_t *pd, 796 const char *dpnm, const char *tpgrp, const char *tpnm) 797 { 798 topo_mod_t *mp; 799 uchar_t *typbuf; 800 char *tmpbuf; 801 int sz = -1; 802 int err, e; 803 804 if (di_bytes_get(did_mod(pd), did_dinode(pd), dpnm, &sz, &typbuf) < 0) 805 return (0); 806 mp = did_mod(pd); 807 808 if ((tmpbuf = topo_mod_alloc(mp, sz + 1)) == NULL) 809 return (topo_mod_seterrno(mp, EMOD_NOMEM)); 810 811 bcopy(typbuf, tmpbuf, sz); 812 tmpbuf[sz] = 0; 813 e = topo_prop_set_string(tn, 814 tpgrp, tpnm, TOPO_PROP_IMMUTABLE, tmpbuf, &err); 815 topo_mod_free(mp, tmpbuf, sz + 1); 816 if (e != 0) 817 return (topo_mod_seterrno(mp, err)); 818 return (0); 819 } 820 821 static int 822 uint_to_strprop(topo_mod_t *mp, uint_t v, tnode_t *tn, 823 const char *tpgrp, const char *tpnm) 824 { 825 char str[21]; /* sizeof (UINT64_MAX) + '\0' */ 826 int e; 827 828 (void) snprintf(str, 21, "%x", v); 829 if (topo_prop_set_string(tn, 830 tpgrp, tpnm, TOPO_PROP_IMMUTABLE, str, &e) < 0) 831 return (topo_mod_seterrno(mp, e)); 832 return (0); 833 } 834 835 static int 836 maybe_di_uint_to_str(tnode_t *tn, did_t *pd, 837 const char *dpnm, const char *tpgrp, const char *tpnm) 838 { 839 uint_t v; 840 841 if (di_uintprop_get(did_mod(pd), did_dinode(pd), dpnm, &v) < 0) 842 return (0); 843 844 return (uint_to_strprop(did_mod(pd), v, tn, tpgrp, tpnm)); 845 } 846 847 static int 848 uint_to_dec_strprop(topo_mod_t *mp, uint_t v, tnode_t *tn, 849 const char *tpgrp, const char *tpnm) 850 { 851 char str[21]; /* sizeof (UINT64_MAX) + '\0' */ 852 int e; 853 854 (void) snprintf(str, 21, "%d", v); 855 if (topo_prop_set_string(tn, 856 tpgrp, tpnm, TOPO_PROP_IMMUTABLE, str, &e) < 0) 857 return (topo_mod_seterrno(mp, e)); 858 return (0); 859 } 860 861 static int 862 maybe_di_uint_to_dec_str(tnode_t *tn, did_t *pd, 863 const char *dpnm, const char *tpgrp, const char *tpnm) 864 { 865 uint_t v; 866 867 if (di_uintprop_get(did_mod(pd), did_dinode(pd), dpnm, &v) < 0) 868 return (0); 869 870 return (uint_to_dec_strprop(did_mod(pd), v, tn, tpgrp, tpnm)); 871 } 872 873 static int 874 AADDR_set(tnode_t *tn, did_t *pd, const char *dpnm, const char *tpgrp, 875 const char *tpnm) 876 { 877 topo_mod_t *mp; 878 uchar_t *typbuf; 879 int sz = -1; 880 int err, e; 881 882 if (di_bytes_get(did_mod(pd), did_dinode(pd), dpnm, &sz, &typbuf) < 0) 883 return (0); 884 885 mp = did_mod(pd); 886 887 e = topo_prop_set_uint32_array(tn, tpgrp, tpnm, TOPO_PROP_IMMUTABLE, 888 /*LINTED*/ 889 (uint32_t *)typbuf, sz/4, &err); 890 891 if (e != 0) 892 return (topo_mod_seterrno(mp, err)); 893 return (0); 894 } 895 896 /*ARGSUSED*/ 897 static int 898 BDF_set(tnode_t *tn, did_t *pd, const char *dpnm, const char *tpgrp, 899 const char *tpnm) 900 { 901 int bdf; 902 char str[23]; /* '0x' + sizeof (UINT64_MAX) + '\0' */ 903 int e; 904 905 if ((bdf = did_bdf(pd)) <= 0) 906 return (0); 907 908 (void) snprintf(str, 23, "0x%x", bdf); 909 if (topo_prop_set_string(tn, 910 tpgrp, tpnm, TOPO_PROP_IMMUTABLE, str, &e) < 0) 911 return (topo_mod_seterrno(did_mod(pd), e)); 912 return (0); 913 } 914 915 int 916 did_props_set(tnode_t *tn, did_t *pd, txprop_t txarray[], int txnum) 917 { 918 topo_mod_t *mp; 919 int i, r, e; 920 921 mp = did_mod(pd); 922 for (i = 0; i < txnum; i++) { 923 /* 924 * Ensure the property group has been created. 925 */ 926 if (txarray[i].tx_tpgroup != NULL) { 927 if (topo_pgroup_create(tn, txarray[i].tx_tpgroup, &e) 928 < 0) { 929 if (e != ETOPO_PROP_DEFD) 930 return (topo_mod_seterrno(mp, e)); 931 } 932 } 933 934 topo_mod_dprintf(mp, 935 "Setting property %s in group %s.\n", 936 txarray[i].tx_tprop, txarray[i].tx_tpgroup->tpi_name); 937 r = txarray[i].tx_xlate(tn, pd, 938 txarray[i].tx_diprop, txarray[i].tx_tpgroup->tpi_name, 939 txarray[i].tx_tprop); 940 if (r != 0) { 941 topo_mod_dprintf(mp, "failed.\n"); 942 topo_mod_dprintf(mp, "Error was %s.\n", 943 topo_strerror(topo_mod_errno(mp))); 944 return (-1); 945 } 946 topo_mod_dprintf(mp, "succeeded.\n"); 947 } 948 return (0); 949 } 950