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 /* 28 * driver for accessing kernel devinfo tree. 29 */ 30 #include <sys/types.h> 31 #include <sys/pathname.h> 32 #include <sys/debug.h> 33 #include <sys/autoconf.h> 34 #include <sys/vmsystm.h> 35 #include <sys/conf.h> 36 #include <sys/file.h> 37 #include <sys/kmem.h> 38 #include <sys/modctl.h> 39 #include <sys/stat.h> 40 #include <sys/ddi.h> 41 #include <sys/sunddi.h> 42 #include <sys/sunldi_impl.h> 43 #include <sys/sunndi.h> 44 #include <sys/esunddi.h> 45 #include <sys/sunmdi.h> 46 #include <sys/ddi_impldefs.h> 47 #include <sys/ndi_impldefs.h> 48 #include <sys/mdi_impldefs.h> 49 #include <sys/devinfo_impl.h> 50 #include <sys/thread.h> 51 #include <sys/modhash.h> 52 #include <sys/bitmap.h> 53 #include <util/qsort.h> 54 #include <sys/disp.h> 55 #include <sys/kobj.h> 56 #include <sys/crc32.h> 57 #include <sys/ddi_hp.h> 58 #include <sys/ddi_hp_impl.h> 59 #include <sys/sysmacros.h> 60 #include <sys/list.h> 61 62 63 #ifdef DEBUG 64 static int di_debug; 65 #define dcmn_err(args) if (di_debug >= 1) cmn_err args 66 #define dcmn_err2(args) if (di_debug >= 2) cmn_err args 67 #define dcmn_err3(args) if (di_debug >= 3) cmn_err args 68 #else 69 #define dcmn_err(args) /* nothing */ 70 #define dcmn_err2(args) /* nothing */ 71 #define dcmn_err3(args) /* nothing */ 72 #endif 73 74 /* 75 * We partition the space of devinfo minor nodes equally between the full and 76 * unprivileged versions of the driver. The even-numbered minor nodes are the 77 * full version, while the odd-numbered ones are the read-only version. 78 */ 79 static int di_max_opens = 32; 80 81 static int di_prop_dyn = 1; /* enable dynamic property support */ 82 83 #define DI_FULL_PARENT 0 84 #define DI_READONLY_PARENT 1 85 #define DI_NODE_SPECIES 2 86 #define DI_UNPRIVILEGED_NODE(x) (((x) % 2) != 0) 87 88 #define IOC_IDLE 0 /* snapshot ioctl states */ 89 #define IOC_SNAP 1 /* snapshot in progress */ 90 #define IOC_DONE 2 /* snapshot done, but not copied out */ 91 #define IOC_COPY 3 /* copyout in progress */ 92 93 /* 94 * Keep max alignment so we can move snapshot to different platforms. 95 * 96 * NOTE: Most callers should rely on the di_checkmem return value 97 * being aligned, and reestablish *off_p with aligned value, instead 98 * of trying to align size of their allocations: this approach will 99 * minimize memory use. 100 */ 101 #define DI_ALIGN(addr) ((addr + 7l) & ~7l) 102 103 /* 104 * To avoid wasting memory, make a linked list of memory chunks. 105 * Size of each chunk is buf_size. 106 */ 107 struct di_mem { 108 struct di_mem *next; /* link to next chunk */ 109 char *buf; /* contiguous kernel memory */ 110 size_t buf_size; /* size of buf in bytes */ 111 devmap_cookie_t cook; /* cookie from ddi_umem_alloc */ 112 }; 113 114 /* 115 * This is a stack for walking the tree without using recursion. 116 * When the devinfo tree height is above some small size, one 117 * gets watchdog resets on sun4m. 118 */ 119 struct di_stack { 120 void *offset[MAX_TREE_DEPTH]; 121 struct dev_info *dip[MAX_TREE_DEPTH]; 122 int circ[MAX_TREE_DEPTH]; 123 int depth; /* depth of current node to be copied */ 124 }; 125 126 #define TOP_OFFSET(stack) \ 127 ((di_off_t *)(stack)->offset[(stack)->depth - 1]) 128 #define TOP_NODE(stack) \ 129 ((stack)->dip[(stack)->depth - 1]) 130 #define PARENT_OFFSET(stack) \ 131 ((di_off_t *)(stack)->offset[(stack)->depth - 2]) 132 #define EMPTY_STACK(stack) ((stack)->depth == 0) 133 #define POP_STACK(stack) { \ 134 ndi_devi_exit((dev_info_t *)TOP_NODE(stack), \ 135 (stack)->circ[(stack)->depth - 1]); \ 136 ((stack)->depth--); \ 137 } 138 #define PUSH_STACK(stack, node, off_p) { \ 139 ASSERT(node != NULL); \ 140 ndi_devi_enter((dev_info_t *)node, &(stack)->circ[(stack)->depth]); \ 141 (stack)->dip[(stack)->depth] = (node); \ 142 (stack)->offset[(stack)->depth] = (void *)(off_p); \ 143 ((stack)->depth)++; \ 144 } 145 146 #define DI_ALL_PTR(s) DI_ALL(di_mem_addr((s), 0)) 147 148 /* 149 * With devfs, the device tree has no global locks. The device tree is 150 * dynamic and dips may come and go if they are not locked locally. Under 151 * these conditions, pointers are no longer reliable as unique IDs. 152 * Specifically, these pointers cannot be used as keys for hash tables 153 * as the same devinfo structure may be freed in one part of the tree only 154 * to be allocated as the structure for a different device in another 155 * part of the tree. This can happen if DR and the snapshot are 156 * happening concurrently. 157 * The following data structures act as keys for devinfo nodes and 158 * pathinfo nodes. 159 */ 160 161 enum di_ktype { 162 DI_DKEY = 1, 163 DI_PKEY = 2 164 }; 165 166 struct di_dkey { 167 dev_info_t *dk_dip; 168 major_t dk_major; 169 int dk_inst; 170 pnode_t dk_nodeid; 171 }; 172 173 struct di_pkey { 174 mdi_pathinfo_t *pk_pip; 175 char *pk_path_addr; 176 dev_info_t *pk_client; 177 dev_info_t *pk_phci; 178 }; 179 180 struct di_key { 181 enum di_ktype k_type; 182 union { 183 struct di_dkey dkey; 184 struct di_pkey pkey; 185 } k_u; 186 }; 187 188 189 struct i_lnode; 190 191 typedef struct i_link { 192 /* 193 * If a di_link struct representing this i_link struct makes it 194 * into the snapshot, then self will point to the offset of 195 * the di_link struct in the snapshot 196 */ 197 di_off_t self; 198 199 int spec_type; /* block or char access type */ 200 struct i_lnode *src_lnode; /* src i_lnode */ 201 struct i_lnode *tgt_lnode; /* tgt i_lnode */ 202 struct i_link *src_link_next; /* next src i_link /w same i_lnode */ 203 struct i_link *tgt_link_next; /* next tgt i_link /w same i_lnode */ 204 } i_link_t; 205 206 typedef struct i_lnode { 207 /* 208 * If a di_lnode struct representing this i_lnode struct makes it 209 * into the snapshot, then self will point to the offset of 210 * the di_lnode struct in the snapshot 211 */ 212 di_off_t self; 213 214 /* 215 * used for hashing and comparing i_lnodes 216 */ 217 int modid; 218 219 /* 220 * public information describing a link endpoint 221 */ 222 struct di_node *di_node; /* di_node in snapshot */ 223 dev_t devt; /* devt */ 224 225 /* 226 * i_link ptr to links coming into this i_lnode node 227 * (this i_lnode is the target of these i_links) 228 */ 229 i_link_t *link_in; 230 231 /* 232 * i_link ptr to links going out of this i_lnode node 233 * (this i_lnode is the source of these i_links) 234 */ 235 i_link_t *link_out; 236 } i_lnode_t; 237 238 typedef struct i_hp { 239 di_off_t hp_off; /* Offset of di_hp_t in snapshot */ 240 dev_info_t *hp_child; /* Child devinfo node of the di_hp_t */ 241 list_node_t hp_link; /* List linkage */ 242 } i_hp_t; 243 244 /* 245 * Soft state associated with each instance of driver open. 246 */ 247 static struct di_state { 248 di_off_t mem_size; /* total # bytes in memlist */ 249 struct di_mem *memlist; /* head of memlist */ 250 uint_t command; /* command from ioctl */ 251 int di_iocstate; /* snapshot ioctl state */ 252 mod_hash_t *reg_dip_hash; 253 mod_hash_t *reg_pip_hash; 254 int lnode_count; 255 int link_count; 256 257 mod_hash_t *lnode_hash; 258 mod_hash_t *link_hash; 259 260 list_t hp_list; 261 } **di_states; 262 263 static kmutex_t di_lock; /* serialize instance assignment */ 264 265 typedef enum { 266 DI_QUIET = 0, /* DI_QUIET must always be 0 */ 267 DI_ERR, 268 DI_INFO, 269 DI_TRACE, 270 DI_TRACE1, 271 DI_TRACE2 272 } di_cache_debug_t; 273 274 static uint_t di_chunk = 32; /* I/O chunk size in pages */ 275 276 #define DI_CACHE_LOCK(c) (mutex_enter(&(c).cache_lock)) 277 #define DI_CACHE_UNLOCK(c) (mutex_exit(&(c).cache_lock)) 278 #define DI_CACHE_LOCKED(c) (mutex_owned(&(c).cache_lock)) 279 280 /* 281 * Check that whole device tree is being configured as a pre-condition for 282 * cleaning up /etc/devices files. 283 */ 284 #define DEVICES_FILES_CLEANABLE(st) \ 285 (((st)->command & DINFOSUBTREE) && ((st)->command & DINFOFORCE) && \ 286 strcmp(DI_ALL_PTR(st)->root_path, "/") == 0) 287 288 #define CACHE_DEBUG(args) \ 289 { if (di_cache_debug != DI_QUIET) di_cache_print args; } 290 291 typedef struct phci_walk_arg { 292 di_off_t off; 293 struct di_state *st; 294 } phci_walk_arg_t; 295 296 static int di_open(dev_t *, int, int, cred_t *); 297 static int di_ioctl(dev_t, int, intptr_t, int, cred_t *, int *); 298 static int di_close(dev_t, int, int, cred_t *); 299 static int di_info(dev_info_t *, ddi_info_cmd_t, void *, void **); 300 static int di_attach(dev_info_t *, ddi_attach_cmd_t); 301 static int di_detach(dev_info_t *, ddi_detach_cmd_t); 302 303 static di_off_t di_copyformat(di_off_t, struct di_state *, intptr_t, int); 304 static di_off_t di_snapshot_and_clean(struct di_state *); 305 static di_off_t di_copydevnm(di_off_t *, struct di_state *); 306 static di_off_t di_copytree(struct dev_info *, di_off_t *, struct di_state *); 307 static di_off_t di_copynode(struct dev_info *, struct di_stack *, 308 struct di_state *); 309 static di_off_t di_getmdata(struct ddi_minor_data *, di_off_t *, di_off_t, 310 struct di_state *); 311 static di_off_t di_getppdata(struct dev_info *, di_off_t *, struct di_state *); 312 static di_off_t di_getdpdata(struct dev_info *, di_off_t *, struct di_state *); 313 static di_off_t di_gethpdata(ddi_hp_cn_handle_t *, di_off_t *, 314 struct di_state *); 315 static di_off_t di_getprop(int, struct ddi_prop **, di_off_t *, 316 struct di_state *, struct dev_info *); 317 static void di_allocmem(struct di_state *, size_t); 318 static void di_freemem(struct di_state *); 319 static void di_copymem(struct di_state *st, caddr_t buf, size_t bufsiz); 320 static di_off_t di_checkmem(struct di_state *, di_off_t, size_t); 321 static void *di_mem_addr(struct di_state *, di_off_t); 322 static int di_setstate(struct di_state *, int); 323 static void di_register_dip(struct di_state *, dev_info_t *, di_off_t); 324 static void di_register_pip(struct di_state *, mdi_pathinfo_t *, di_off_t); 325 static di_off_t di_getpath_data(dev_info_t *, di_off_t *, di_off_t, 326 struct di_state *, int); 327 static di_off_t di_getlink_data(di_off_t, struct di_state *); 328 static int di_dip_find(struct di_state *st, dev_info_t *node, di_off_t *off_p); 329 330 static int cache_args_valid(struct di_state *st, int *error); 331 static int snapshot_is_cacheable(struct di_state *st); 332 static int di_cache_lookup(struct di_state *st); 333 static int di_cache_update(struct di_state *st); 334 static void di_cache_print(di_cache_debug_t msglevel, char *fmt, ...); 335 static int build_vhci_list(dev_info_t *vh_devinfo, void *arg); 336 static int build_phci_list(dev_info_t *ph_devinfo, void *arg); 337 static void di_hotplug_children(struct di_state *st); 338 339 extern int modrootloaded; 340 extern void mdi_walk_vhcis(int (*)(dev_info_t *, void *), void *); 341 extern void mdi_vhci_walk_phcis(dev_info_t *, 342 int (*)(dev_info_t *, void *), void *); 343 344 345 static struct cb_ops di_cb_ops = { 346 di_open, /* open */ 347 di_close, /* close */ 348 nodev, /* strategy */ 349 nodev, /* print */ 350 nodev, /* dump */ 351 nodev, /* read */ 352 nodev, /* write */ 353 di_ioctl, /* ioctl */ 354 nodev, /* devmap */ 355 nodev, /* mmap */ 356 nodev, /* segmap */ 357 nochpoll, /* poll */ 358 ddi_prop_op, /* prop_op */ 359 NULL, /* streamtab */ 360 D_NEW | D_MP /* Driver compatibility flag */ 361 }; 362 363 static struct dev_ops di_ops = { 364 DEVO_REV, /* devo_rev, */ 365 0, /* refcnt */ 366 di_info, /* info */ 367 nulldev, /* identify */ 368 nulldev, /* probe */ 369 di_attach, /* attach */ 370 di_detach, /* detach */ 371 nodev, /* reset */ 372 &di_cb_ops, /* driver operations */ 373 NULL /* bus operations */ 374 }; 375 376 /* 377 * Module linkage information for the kernel. 378 */ 379 static struct modldrv modldrv = { 380 &mod_driverops, 381 "DEVINFO Driver", 382 &di_ops 383 }; 384 385 static struct modlinkage modlinkage = { 386 MODREV_1, 387 &modldrv, 388 NULL 389 }; 390 391 int 392 _init(void) 393 { 394 int error; 395 396 mutex_init(&di_lock, NULL, MUTEX_DRIVER, NULL); 397 398 error = mod_install(&modlinkage); 399 if (error != 0) { 400 mutex_destroy(&di_lock); 401 return (error); 402 } 403 404 return (0); 405 } 406 407 int 408 _info(struct modinfo *modinfop) 409 { 410 return (mod_info(&modlinkage, modinfop)); 411 } 412 413 int 414 _fini(void) 415 { 416 int error; 417 418 error = mod_remove(&modlinkage); 419 if (error != 0) { 420 return (error); 421 } 422 423 mutex_destroy(&di_lock); 424 return (0); 425 } 426 427 static dev_info_t *di_dip; 428 429 /*ARGSUSED*/ 430 static int 431 di_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 432 { 433 int error = DDI_FAILURE; 434 435 switch (infocmd) { 436 case DDI_INFO_DEVT2DEVINFO: 437 *result = (void *)di_dip; 438 error = DDI_SUCCESS; 439 break; 440 case DDI_INFO_DEVT2INSTANCE: 441 /* 442 * All dev_t's map to the same, single instance. 443 */ 444 *result = (void *)0; 445 error = DDI_SUCCESS; 446 break; 447 default: 448 break; 449 } 450 451 return (error); 452 } 453 454 static int 455 di_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 456 { 457 int error = DDI_FAILURE; 458 459 switch (cmd) { 460 case DDI_ATTACH: 461 di_states = kmem_zalloc( 462 di_max_opens * sizeof (struct di_state *), KM_SLEEP); 463 464 if (ddi_create_minor_node(dip, "devinfo", S_IFCHR, 465 DI_FULL_PARENT, DDI_PSEUDO, NULL) == DDI_FAILURE || 466 ddi_create_minor_node(dip, "devinfo,ro", S_IFCHR, 467 DI_READONLY_PARENT, DDI_PSEUDO, NULL) == DDI_FAILURE) { 468 kmem_free(di_states, 469 di_max_opens * sizeof (struct di_state *)); 470 ddi_remove_minor_node(dip, NULL); 471 error = DDI_FAILURE; 472 } else { 473 di_dip = dip; 474 ddi_report_dev(dip); 475 476 error = DDI_SUCCESS; 477 } 478 break; 479 default: 480 error = DDI_FAILURE; 481 break; 482 } 483 484 return (error); 485 } 486 487 static int 488 di_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 489 { 490 int error = DDI_FAILURE; 491 492 switch (cmd) { 493 case DDI_DETACH: 494 ddi_remove_minor_node(dip, NULL); 495 di_dip = NULL; 496 kmem_free(di_states, di_max_opens * sizeof (struct di_state *)); 497 498 error = DDI_SUCCESS; 499 break; 500 default: 501 error = DDI_FAILURE; 502 break; 503 } 504 505 return (error); 506 } 507 508 /* 509 * Allow multiple opens by tweaking the dev_t such that it looks like each 510 * open is getting a different minor device. Each minor gets a separate 511 * entry in the di_states[] table. Based on the original minor number, we 512 * discriminate opens of the full and read-only nodes. If all of the instances 513 * of the selected minor node are currently open, we return EAGAIN. 514 */ 515 /*ARGSUSED*/ 516 static int 517 di_open(dev_t *devp, int flag, int otyp, cred_t *credp) 518 { 519 int m; 520 minor_t minor_parent = getminor(*devp); 521 522 if (minor_parent != DI_FULL_PARENT && 523 minor_parent != DI_READONLY_PARENT) 524 return (ENXIO); 525 526 mutex_enter(&di_lock); 527 528 for (m = minor_parent; m < di_max_opens; m += DI_NODE_SPECIES) { 529 if (di_states[m] != NULL) 530 continue; 531 532 di_states[m] = kmem_zalloc(sizeof (struct di_state), KM_SLEEP); 533 break; /* It's ours. */ 534 } 535 536 if (m >= di_max_opens) { 537 /* 538 * maximum open instance for device reached 539 */ 540 mutex_exit(&di_lock); 541 dcmn_err((CE_WARN, "devinfo: maximum devinfo open reached")); 542 return (EAGAIN); 543 } 544 mutex_exit(&di_lock); 545 546 ASSERT(m < di_max_opens); 547 *devp = makedevice(getmajor(*devp), (minor_t)(m + DI_NODE_SPECIES)); 548 549 dcmn_err((CE_CONT, "di_open: thread = %p, assigned minor = %d\n", 550 (void *)curthread, m + DI_NODE_SPECIES)); 551 552 return (0); 553 } 554 555 /*ARGSUSED*/ 556 static int 557 di_close(dev_t dev, int flag, int otype, cred_t *cred_p) 558 { 559 struct di_state *st; 560 int m = (int)getminor(dev) - DI_NODE_SPECIES; 561 562 if (m < 0) { 563 cmn_err(CE_WARN, "closing non-existent devinfo minor %d", 564 m + DI_NODE_SPECIES); 565 return (ENXIO); 566 } 567 568 st = di_states[m]; 569 ASSERT(m < di_max_opens && st != NULL); 570 571 di_freemem(st); 572 kmem_free(st, sizeof (struct di_state)); 573 574 /* 575 * empty slot in state table 576 */ 577 mutex_enter(&di_lock); 578 di_states[m] = NULL; 579 dcmn_err((CE_CONT, "di_close: thread = %p, assigned minor = %d\n", 580 (void *)curthread, m + DI_NODE_SPECIES)); 581 mutex_exit(&di_lock); 582 583 return (0); 584 } 585 586 587 /*ARGSUSED*/ 588 static int 589 di_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, int *rvalp) 590 { 591 int rv, error; 592 di_off_t off; 593 struct di_all *all; 594 struct di_state *st; 595 int m = (int)getminor(dev) - DI_NODE_SPECIES; 596 major_t i; 597 char *drv_name; 598 size_t map_size, size; 599 struct di_mem *dcp; 600 int ndi_flags; 601 602 if (m < 0 || m >= di_max_opens) { 603 return (ENXIO); 604 } 605 606 st = di_states[m]; 607 ASSERT(st != NULL); 608 609 dcmn_err2((CE_CONT, "di_ioctl: mode = %x, cmd = %x\n", mode, cmd)); 610 611 switch (cmd) { 612 case DINFOIDENT: 613 /* 614 * This is called from di_init to verify that the driver 615 * opened is indeed devinfo. The purpose is to guard against 616 * sending ioctl to an unknown driver in case of an 617 * unresolved major number conflict during bfu. 618 */ 619 *rvalp = DI_MAGIC; 620 return (0); 621 622 case DINFOLODRV: 623 /* 624 * Hold an installed driver and return the result 625 */ 626 if (DI_UNPRIVILEGED_NODE(m)) { 627 /* 628 * Only the fully enabled instances may issue 629 * DINFOLDDRV. 630 */ 631 return (EACCES); 632 } 633 634 drv_name = kmem_alloc(MAXNAMELEN, KM_SLEEP); 635 if (ddi_copyin((void *)arg, drv_name, MAXNAMELEN, mode) != 0) { 636 kmem_free(drv_name, MAXNAMELEN); 637 return (EFAULT); 638 } 639 640 /* 641 * Some 3rd party driver's _init() walks the device tree, 642 * so we load the driver module before configuring driver. 643 */ 644 i = ddi_name_to_major(drv_name); 645 if (ddi_hold_driver(i) == NULL) { 646 kmem_free(drv_name, MAXNAMELEN); 647 return (ENXIO); 648 } 649 650 ndi_flags = NDI_DEVI_PERSIST | NDI_CONFIG | NDI_NO_EVENT; 651 652 /* 653 * i_ddi_load_drvconf() below will trigger a reprobe 654 * via reset_nexus_flags(). NDI_DRV_CONF_REPROBE isn't 655 * needed here. 656 */ 657 modunload_disable(); 658 (void) i_ddi_load_drvconf(i); 659 (void) ndi_devi_config_driver(ddi_root_node(), ndi_flags, i); 660 kmem_free(drv_name, MAXNAMELEN); 661 ddi_rele_driver(i); 662 rv = i_ddi_devs_attached(i); 663 modunload_enable(); 664 665 i_ddi_di_cache_invalidate(); 666 667 return ((rv == DDI_SUCCESS)? 0 : ENXIO); 668 669 case DINFOUSRLD: 670 /* 671 * The case for copying snapshot to userland 672 */ 673 if (di_setstate(st, IOC_COPY) == -1) 674 return (EBUSY); 675 676 map_size = DI_ALL_PTR(st)->map_size; 677 if (map_size == 0) { 678 (void) di_setstate(st, IOC_DONE); 679 return (EFAULT); 680 } 681 682 /* 683 * copyout the snapshot 684 */ 685 map_size = (map_size + PAGEOFFSET) & PAGEMASK; 686 687 /* 688 * Return the map size, so caller may do a sanity 689 * check against the return value of snapshot ioctl() 690 */ 691 *rvalp = (int)map_size; 692 693 /* 694 * Copy one chunk at a time 695 */ 696 off = 0; 697 dcp = st->memlist; 698 while (map_size) { 699 size = dcp->buf_size; 700 if (map_size <= size) { 701 size = map_size; 702 } 703 704 if (ddi_copyout(di_mem_addr(st, off), 705 (void *)(arg + off), size, mode) != 0) { 706 (void) di_setstate(st, IOC_DONE); 707 return (EFAULT); 708 } 709 710 map_size -= size; 711 off += size; 712 dcp = dcp->next; 713 } 714 715 di_freemem(st); 716 (void) di_setstate(st, IOC_IDLE); 717 return (0); 718 719 default: 720 if ((cmd & ~DIIOC_MASK) != DIIOC) { 721 /* 722 * Invalid ioctl command 723 */ 724 return (ENOTTY); 725 } 726 /* 727 * take a snapshot 728 */ 729 st->command = cmd & DIIOC_MASK; 730 /*FALLTHROUGH*/ 731 } 732 733 /* 734 * Obtain enough memory to hold header + rootpath. We prevent kernel 735 * memory exhaustion by freeing any previously allocated snapshot and 736 * refusing the operation; otherwise we would be allowing ioctl(), 737 * ioctl(), ioctl(), ..., panic. 738 */ 739 if (di_setstate(st, IOC_SNAP) == -1) 740 return (EBUSY); 741 742 /* 743 * Initial memlist always holds di_all and the root_path - and 744 * is at least a page and size. 745 */ 746 size = sizeof (struct di_all) + 747 sizeof (((struct dinfo_io *)(NULL))->root_path); 748 if (size < PAGESIZE) 749 size = PAGESIZE; 750 off = di_checkmem(st, 0, size); 751 all = DI_ALL_PTR(st); 752 off += sizeof (struct di_all); /* real length of di_all */ 753 754 all->devcnt = devcnt; 755 all->command = st->command; 756 all->version = DI_SNAPSHOT_VERSION; 757 all->top_vhci_devinfo = 0; /* filled by build_vhci_list. */ 758 759 /* 760 * Note the endianness in case we need to transport snapshot 761 * over the network. 762 */ 763 #if defined(_LITTLE_ENDIAN) 764 all->endianness = DI_LITTLE_ENDIAN; 765 #else 766 all->endianness = DI_BIG_ENDIAN; 767 #endif 768 769 /* Copyin ioctl args, store in the snapshot. */ 770 if (copyinstr((void *)arg, all->root_path, 771 sizeof (((struct dinfo_io *)(NULL))->root_path), &size) != 0) { 772 di_freemem(st); 773 (void) di_setstate(st, IOC_IDLE); 774 return (EFAULT); 775 } 776 off += size; /* real length of root_path */ 777 778 if ((st->command & DINFOCLEANUP) && !DEVICES_FILES_CLEANABLE(st)) { 779 di_freemem(st); 780 (void) di_setstate(st, IOC_IDLE); 781 return (EINVAL); 782 } 783 784 error = 0; 785 if ((st->command & DINFOCACHE) && !cache_args_valid(st, &error)) { 786 di_freemem(st); 787 (void) di_setstate(st, IOC_IDLE); 788 return (error); 789 } 790 791 /* 792 * Only the fully enabled version may force load drivers or read 793 * the parent private data from a driver. 794 */ 795 if ((st->command & (DINFOPRIVDATA | DINFOFORCE)) != 0 && 796 DI_UNPRIVILEGED_NODE(m)) { 797 di_freemem(st); 798 (void) di_setstate(st, IOC_IDLE); 799 return (EACCES); 800 } 801 802 /* Do we need private data? */ 803 if (st->command & DINFOPRIVDATA) { 804 arg += sizeof (((struct dinfo_io *)(NULL))->root_path); 805 806 #ifdef _MULTI_DATAMODEL 807 switch (ddi_model_convert_from(mode & FMODELS)) { 808 case DDI_MODEL_ILP32: { 809 /* 810 * Cannot copy private data from 64-bit kernel 811 * to 32-bit app 812 */ 813 di_freemem(st); 814 (void) di_setstate(st, IOC_IDLE); 815 return (EINVAL); 816 } 817 case DDI_MODEL_NONE: 818 if ((off = di_copyformat(off, st, arg, mode)) == 0) { 819 di_freemem(st); 820 (void) di_setstate(st, IOC_IDLE); 821 return (EFAULT); 822 } 823 break; 824 } 825 #else /* !_MULTI_DATAMODEL */ 826 if ((off = di_copyformat(off, st, arg, mode)) == 0) { 827 di_freemem(st); 828 (void) di_setstate(st, IOC_IDLE); 829 return (EFAULT); 830 } 831 #endif /* _MULTI_DATAMODEL */ 832 } 833 834 all->top_devinfo = DI_ALIGN(off); 835 836 /* 837 * For cache lookups we reallocate memory from scratch, 838 * so the value of "all" is no longer valid. 839 */ 840 all = NULL; 841 842 if (st->command & DINFOCACHE) { 843 *rvalp = di_cache_lookup(st); 844 } else if (snapshot_is_cacheable(st)) { 845 DI_CACHE_LOCK(di_cache); 846 *rvalp = di_cache_update(st); 847 DI_CACHE_UNLOCK(di_cache); 848 } else 849 *rvalp = di_snapshot_and_clean(st); 850 851 if (*rvalp) { 852 DI_ALL_PTR(st)->map_size = *rvalp; 853 (void) di_setstate(st, IOC_DONE); 854 } else { 855 di_freemem(st); 856 (void) di_setstate(st, IOC_IDLE); 857 } 858 859 return (0); 860 } 861 862 /* 863 * Get a chunk of memory >= size, for the snapshot 864 */ 865 static void 866 di_allocmem(struct di_state *st, size_t size) 867 { 868 struct di_mem *mem = kmem_zalloc(sizeof (struct di_mem), KM_SLEEP); 869 870 /* 871 * Round up size to nearest power of 2. If it is less 872 * than st->mem_size, set it to st->mem_size (i.e., 873 * the mem_size is doubled every time) to reduce the 874 * number of memory allocations. 875 */ 876 size_t tmp = 1; 877 while (tmp < size) { 878 tmp <<= 1; 879 } 880 size = (tmp > st->mem_size) ? tmp : st->mem_size; 881 882 mem->buf = ddi_umem_alloc(size, DDI_UMEM_SLEEP, &mem->cook); 883 mem->buf_size = size; 884 885 dcmn_err2((CE_CONT, "di_allocmem: mem_size=%x\n", st->mem_size)); 886 887 if (st->mem_size == 0) { /* first chunk */ 888 st->memlist = mem; 889 } else { 890 /* 891 * locate end of linked list and add a chunk at the end 892 */ 893 struct di_mem *dcp = st->memlist; 894 while (dcp->next != NULL) { 895 dcp = dcp->next; 896 } 897 898 dcp->next = mem; 899 } 900 901 st->mem_size += size; 902 } 903 904 /* 905 * Copy upto bufsiz bytes of the memlist to buf 906 */ 907 static void 908 di_copymem(struct di_state *st, caddr_t buf, size_t bufsiz) 909 { 910 struct di_mem *dcp; 911 size_t copysz; 912 913 if (st->mem_size == 0) { 914 ASSERT(st->memlist == NULL); 915 return; 916 } 917 918 copysz = 0; 919 for (dcp = st->memlist; dcp; dcp = dcp->next) { 920 921 ASSERT(bufsiz > 0); 922 923 if (bufsiz <= dcp->buf_size) 924 copysz = bufsiz; 925 else 926 copysz = dcp->buf_size; 927 928 bcopy(dcp->buf, buf, copysz); 929 930 buf += copysz; 931 bufsiz -= copysz; 932 933 if (bufsiz == 0) 934 break; 935 } 936 } 937 938 /* 939 * Free all memory for the snapshot 940 */ 941 static void 942 di_freemem(struct di_state *st) 943 { 944 struct di_mem *dcp, *tmp; 945 946 dcmn_err2((CE_CONT, "di_freemem\n")); 947 948 if (st->mem_size) { 949 dcp = st->memlist; 950 while (dcp) { /* traverse the linked list */ 951 tmp = dcp; 952 dcp = dcp->next; 953 ddi_umem_free(tmp->cook); 954 kmem_free(tmp, sizeof (struct di_mem)); 955 } 956 st->mem_size = 0; 957 st->memlist = NULL; 958 } 959 960 ASSERT(st->mem_size == 0); 961 ASSERT(st->memlist == NULL); 962 } 963 964 /* 965 * Copies cached data to the di_state structure. 966 * Returns: 967 * - size of data copied, on SUCCESS 968 * - 0 on failure 969 */ 970 static int 971 di_cache2mem(struct di_cache *cache, struct di_state *st) 972 { 973 caddr_t pa; 974 975 ASSERT(st->mem_size == 0); 976 ASSERT(st->memlist == NULL); 977 ASSERT(!servicing_interrupt()); 978 ASSERT(DI_CACHE_LOCKED(*cache)); 979 980 if (cache->cache_size == 0) { 981 ASSERT(cache->cache_data == NULL); 982 CACHE_DEBUG((DI_ERR, "Empty cache. Skipping copy")); 983 return (0); 984 } 985 986 ASSERT(cache->cache_data); 987 988 di_allocmem(st, cache->cache_size); 989 990 pa = di_mem_addr(st, 0); 991 992 ASSERT(pa); 993 994 /* 995 * Verify that di_allocmem() allocates contiguous memory, 996 * so that it is safe to do straight bcopy() 997 */ 998 ASSERT(st->memlist != NULL); 999 ASSERT(st->memlist->next == NULL); 1000 bcopy(cache->cache_data, pa, cache->cache_size); 1001 1002 return (cache->cache_size); 1003 } 1004 1005 /* 1006 * Copies a snapshot from di_state to the cache 1007 * Returns: 1008 * - 0 on failure 1009 * - size of copied data on success 1010 */ 1011 static size_t 1012 di_mem2cache(struct di_state *st, struct di_cache *cache) 1013 { 1014 size_t map_size; 1015 1016 ASSERT(cache->cache_size == 0); 1017 ASSERT(cache->cache_data == NULL); 1018 ASSERT(!servicing_interrupt()); 1019 ASSERT(DI_CACHE_LOCKED(*cache)); 1020 1021 if (st->mem_size == 0) { 1022 ASSERT(st->memlist == NULL); 1023 CACHE_DEBUG((DI_ERR, "Empty memlist. Skipping copy")); 1024 return (0); 1025 } 1026 1027 ASSERT(st->memlist); 1028 1029 /* 1030 * The size of the memory list may be much larger than the 1031 * size of valid data (map_size). Cache only the valid data 1032 */ 1033 map_size = DI_ALL_PTR(st)->map_size; 1034 if (map_size == 0 || map_size < sizeof (struct di_all) || 1035 map_size > st->mem_size) { 1036 CACHE_DEBUG((DI_ERR, "cannot cache: bad size: 0x%x", map_size)); 1037 return (0); 1038 } 1039 1040 cache->cache_data = kmem_alloc(map_size, KM_SLEEP); 1041 cache->cache_size = map_size; 1042 di_copymem(st, cache->cache_data, cache->cache_size); 1043 1044 return (map_size); 1045 } 1046 1047 /* 1048 * Make sure there is at least "size" bytes memory left before 1049 * going on. Otherwise, start on a new chunk. 1050 */ 1051 static di_off_t 1052 di_checkmem(struct di_state *st, di_off_t off, size_t size) 1053 { 1054 dcmn_err3((CE_CONT, "di_checkmem: off=%x size=%x\n", 1055 off, (int)size)); 1056 1057 /* 1058 * di_checkmem() shouldn't be called with a size of zero. 1059 * But in case it is, we want to make sure we return a valid 1060 * offset within the memlist and not an offset that points us 1061 * at the end of the memlist. 1062 */ 1063 if (size == 0) { 1064 dcmn_err((CE_WARN, "di_checkmem: invalid zero size used")); 1065 size = 1; 1066 } 1067 1068 off = DI_ALIGN(off); 1069 if ((st->mem_size - off) < size) { 1070 off = st->mem_size; 1071 di_allocmem(st, size); 1072 } 1073 1074 /* verify that return value is aligned */ 1075 ASSERT(off == DI_ALIGN(off)); 1076 return (off); 1077 } 1078 1079 /* 1080 * Copy the private data format from ioctl arg. 1081 * On success, the ending offset is returned. On error 0 is returned. 1082 */ 1083 static di_off_t 1084 di_copyformat(di_off_t off, struct di_state *st, intptr_t arg, int mode) 1085 { 1086 di_off_t size; 1087 struct di_priv_data *priv; 1088 struct di_all *all = DI_ALL_PTR(st); 1089 1090 dcmn_err2((CE_CONT, "di_copyformat: off=%x, arg=%p mode=%x\n", 1091 off, (void *)arg, mode)); 1092 1093 /* 1094 * Copyin data and check version. 1095 * We only handle private data version 0. 1096 */ 1097 priv = kmem_alloc(sizeof (struct di_priv_data), KM_SLEEP); 1098 if ((ddi_copyin((void *)arg, priv, sizeof (struct di_priv_data), 1099 mode) != 0) || (priv->version != DI_PRIVDATA_VERSION_0)) { 1100 kmem_free(priv, sizeof (struct di_priv_data)); 1101 return (0); 1102 } 1103 1104 /* 1105 * Save di_priv_data copied from userland in snapshot. 1106 */ 1107 all->pd_version = priv->version; 1108 all->n_ppdata = priv->n_parent; 1109 all->n_dpdata = priv->n_driver; 1110 1111 /* 1112 * copyin private data format, modify offset accordingly 1113 */ 1114 if (all->n_ppdata) { /* parent private data format */ 1115 /* 1116 * check memory 1117 */ 1118 size = all->n_ppdata * sizeof (struct di_priv_format); 1119 all->ppdata_format = off = di_checkmem(st, off, size); 1120 if (ddi_copyin(priv->parent, di_mem_addr(st, off), size, 1121 mode) != 0) { 1122 kmem_free(priv, sizeof (struct di_priv_data)); 1123 return (0); 1124 } 1125 1126 off += size; 1127 } 1128 1129 if (all->n_dpdata) { /* driver private data format */ 1130 /* 1131 * check memory 1132 */ 1133 size = all->n_dpdata * sizeof (struct di_priv_format); 1134 all->dpdata_format = off = di_checkmem(st, off, size); 1135 if (ddi_copyin(priv->driver, di_mem_addr(st, off), size, 1136 mode) != 0) { 1137 kmem_free(priv, sizeof (struct di_priv_data)); 1138 return (0); 1139 } 1140 1141 off += size; 1142 } 1143 1144 kmem_free(priv, sizeof (struct di_priv_data)); 1145 return (off); 1146 } 1147 1148 /* 1149 * Return the real address based on the offset (off) within snapshot 1150 */ 1151 static void * 1152 di_mem_addr(struct di_state *st, di_off_t off) 1153 { 1154 struct di_mem *dcp = st->memlist; 1155 1156 dcmn_err3((CE_CONT, "di_mem_addr: dcp=%p off=%x\n", 1157 (void *)dcp, off)); 1158 1159 ASSERT(off < st->mem_size); 1160 1161 while (off >= dcp->buf_size) { 1162 off -= dcp->buf_size; 1163 dcp = dcp->next; 1164 } 1165 1166 dcmn_err3((CE_CONT, "di_mem_addr: new off=%x, return = %p\n", 1167 off, (void *)(dcp->buf + off))); 1168 1169 return (dcp->buf + off); 1170 } 1171 1172 /* 1173 * Ideally we would use the whole key to derive the hash 1174 * value. However, the probability that two keys will 1175 * have the same dip (or pip) is very low, so 1176 * hashing by dip (or pip) pointer should suffice. 1177 */ 1178 static uint_t 1179 di_hash_byptr(void *arg, mod_hash_key_t key) 1180 { 1181 struct di_key *dik = key; 1182 size_t rshift; 1183 void *ptr; 1184 1185 ASSERT(arg == NULL); 1186 1187 switch (dik->k_type) { 1188 case DI_DKEY: 1189 ptr = dik->k_u.dkey.dk_dip; 1190 rshift = highbit(sizeof (struct dev_info)); 1191 break; 1192 case DI_PKEY: 1193 ptr = dik->k_u.pkey.pk_pip; 1194 rshift = highbit(sizeof (struct mdi_pathinfo)); 1195 break; 1196 default: 1197 panic("devinfo: unknown key type"); 1198 /*NOTREACHED*/ 1199 } 1200 return (mod_hash_byptr((void *)rshift, ptr)); 1201 } 1202 1203 static void 1204 di_key_dtor(mod_hash_key_t key) 1205 { 1206 char *path_addr; 1207 struct di_key *dik = key; 1208 1209 switch (dik->k_type) { 1210 case DI_DKEY: 1211 break; 1212 case DI_PKEY: 1213 path_addr = dik->k_u.pkey.pk_path_addr; 1214 if (path_addr) 1215 kmem_free(path_addr, strlen(path_addr) + 1); 1216 break; 1217 default: 1218 panic("devinfo: unknown key type"); 1219 /*NOTREACHED*/ 1220 } 1221 1222 kmem_free(dik, sizeof (struct di_key)); 1223 } 1224 1225 static int 1226 di_dkey_cmp(struct di_dkey *dk1, struct di_dkey *dk2) 1227 { 1228 if (dk1->dk_dip != dk2->dk_dip) 1229 return (dk1->dk_dip > dk2->dk_dip ? 1 : -1); 1230 1231 if (dk1->dk_major != DDI_MAJOR_T_NONE && 1232 dk2->dk_major != DDI_MAJOR_T_NONE) { 1233 if (dk1->dk_major != dk2->dk_major) 1234 return (dk1->dk_major > dk2->dk_major ? 1 : -1); 1235 1236 if (dk1->dk_inst != dk2->dk_inst) 1237 return (dk1->dk_inst > dk2->dk_inst ? 1 : -1); 1238 } 1239 1240 if (dk1->dk_nodeid != dk2->dk_nodeid) 1241 return (dk1->dk_nodeid > dk2->dk_nodeid ? 1 : -1); 1242 1243 return (0); 1244 } 1245 1246 static int 1247 di_pkey_cmp(struct di_pkey *pk1, struct di_pkey *pk2) 1248 { 1249 char *p1, *p2; 1250 int rv; 1251 1252 if (pk1->pk_pip != pk2->pk_pip) 1253 return (pk1->pk_pip > pk2->pk_pip ? 1 : -1); 1254 1255 p1 = pk1->pk_path_addr; 1256 p2 = pk2->pk_path_addr; 1257 1258 p1 = p1 ? p1 : ""; 1259 p2 = p2 ? p2 : ""; 1260 1261 rv = strcmp(p1, p2); 1262 if (rv) 1263 return (rv > 0 ? 1 : -1); 1264 1265 if (pk1->pk_client != pk2->pk_client) 1266 return (pk1->pk_client > pk2->pk_client ? 1 : -1); 1267 1268 if (pk1->pk_phci != pk2->pk_phci) 1269 return (pk1->pk_phci > pk2->pk_phci ? 1 : -1); 1270 1271 return (0); 1272 } 1273 1274 static int 1275 di_key_cmp(mod_hash_key_t key1, mod_hash_key_t key2) 1276 { 1277 struct di_key *dik1, *dik2; 1278 1279 dik1 = key1; 1280 dik2 = key2; 1281 1282 if (dik1->k_type != dik2->k_type) { 1283 panic("devinfo: mismatched keys"); 1284 /*NOTREACHED*/ 1285 } 1286 1287 switch (dik1->k_type) { 1288 case DI_DKEY: 1289 return (di_dkey_cmp(&(dik1->k_u.dkey), &(dik2->k_u.dkey))); 1290 case DI_PKEY: 1291 return (di_pkey_cmp(&(dik1->k_u.pkey), &(dik2->k_u.pkey))); 1292 default: 1293 panic("devinfo: unknown key type"); 1294 /*NOTREACHED*/ 1295 } 1296 } 1297 1298 /* 1299 * This is the main function that takes a snapshot 1300 */ 1301 static di_off_t 1302 di_snapshot(struct di_state *st) 1303 { 1304 di_off_t off; 1305 struct di_all *all; 1306 dev_info_t *rootnode; 1307 char buf[80]; 1308 int plen; 1309 char *path; 1310 vnode_t *vp; 1311 1312 all = DI_ALL_PTR(st); 1313 dcmn_err((CE_CONT, "Taking a snapshot of devinfo tree...\n")); 1314 1315 /* 1316 * Verify path before entrusting it to e_ddi_hold_devi_by_path because 1317 * some platforms have OBP bugs where executing the NDI_PROMNAME code 1318 * path against an invalid path results in panic. The lookupnameat 1319 * is done relative to rootdir without a leading '/' on "devices/" 1320 * to force the lookup to occur in the global zone. 1321 */ 1322 plen = strlen("devices/") + strlen(all->root_path) + 1; 1323 path = kmem_alloc(plen, KM_SLEEP); 1324 (void) snprintf(path, plen, "devices/%s", all->root_path); 1325 if (lookupnameat(path, UIO_SYSSPACE, FOLLOW, NULLVPP, &vp, rootdir)) { 1326 dcmn_err((CE_CONT, "Devinfo node %s not found\n", 1327 all->root_path)); 1328 kmem_free(path, plen); 1329 return (0); 1330 } 1331 kmem_free(path, plen); 1332 VN_RELE(vp); 1333 1334 /* 1335 * Hold the devinfo node referred by the path. 1336 */ 1337 rootnode = e_ddi_hold_devi_by_path(all->root_path, 0); 1338 if (rootnode == NULL) { 1339 dcmn_err((CE_CONT, "Devinfo node %s not found\n", 1340 all->root_path)); 1341 return (0); 1342 } 1343 1344 (void) snprintf(buf, sizeof (buf), 1345 "devinfo registered dips (statep=%p)", (void *)st); 1346 1347 st->reg_dip_hash = mod_hash_create_extended(buf, 64, 1348 di_key_dtor, mod_hash_null_valdtor, di_hash_byptr, 1349 NULL, di_key_cmp, KM_SLEEP); 1350 1351 1352 (void) snprintf(buf, sizeof (buf), 1353 "devinfo registered pips (statep=%p)", (void *)st); 1354 1355 st->reg_pip_hash = mod_hash_create_extended(buf, 64, 1356 di_key_dtor, mod_hash_null_valdtor, di_hash_byptr, 1357 NULL, di_key_cmp, KM_SLEEP); 1358 1359 if (DINFOHP & st->command) { 1360 list_create(&st->hp_list, sizeof (i_hp_t), 1361 offsetof(i_hp_t, hp_link)); 1362 } 1363 1364 /* 1365 * copy the device tree 1366 */ 1367 off = di_copytree(DEVI(rootnode), &all->top_devinfo, st); 1368 1369 if (DINFOPATH & st->command) { 1370 mdi_walk_vhcis(build_vhci_list, st); 1371 } 1372 1373 if (DINFOHP & st->command) { 1374 di_hotplug_children(st); 1375 } 1376 1377 ddi_release_devi(rootnode); 1378 1379 /* 1380 * copy the devnames array 1381 */ 1382 all->devnames = off; 1383 off = di_copydevnm(&all->devnames, st); 1384 1385 1386 /* initialize the hash tables */ 1387 st->lnode_count = 0; 1388 st->link_count = 0; 1389 1390 if (DINFOLYR & st->command) { 1391 off = di_getlink_data(off, st); 1392 } 1393 1394 /* 1395 * Free up hash tables 1396 */ 1397 mod_hash_destroy_hash(st->reg_dip_hash); 1398 mod_hash_destroy_hash(st->reg_pip_hash); 1399 1400 /* 1401 * Record the timestamp now that we are done with snapshot. 1402 * 1403 * We compute the checksum later and then only if we cache 1404 * the snapshot, since checksumming adds some overhead. 1405 * The checksum is checked later if we read the cache file. 1406 * from disk. 1407 * 1408 * Set checksum field to 0 as CRC is calculated with that 1409 * field set to 0. 1410 */ 1411 all->snapshot_time = ddi_get_time(); 1412 all->cache_checksum = 0; 1413 1414 ASSERT(all->snapshot_time != 0); 1415 1416 return (off); 1417 } 1418 1419 /* 1420 * Take a snapshot and clean /etc/devices files if DINFOCLEANUP is set 1421 */ 1422 static di_off_t 1423 di_snapshot_and_clean(struct di_state *st) 1424 { 1425 di_off_t off; 1426 1427 modunload_disable(); 1428 off = di_snapshot(st); 1429 if (off != 0 && (st->command & DINFOCLEANUP)) { 1430 ASSERT(DEVICES_FILES_CLEANABLE(st)); 1431 /* 1432 * Cleanup /etc/devices files: 1433 * In order to accurately account for the system configuration 1434 * in /etc/devices files, the appropriate drivers must be 1435 * fully configured before the cleanup starts. 1436 * So enable modunload only after the cleanup. 1437 */ 1438 i_ddi_clean_devices_files(); 1439 /* 1440 * Remove backing store nodes for unused devices, 1441 * which retain past permissions customizations 1442 * and may be undesired for newly configured devices. 1443 */ 1444 dev_devices_cleanup(); 1445 } 1446 modunload_enable(); 1447 1448 return (off); 1449 } 1450 1451 /* 1452 * construct vhci linkage in the snapshot. 1453 */ 1454 static int 1455 build_vhci_list(dev_info_t *vh_devinfo, void *arg) 1456 { 1457 struct di_all *all; 1458 struct di_node *me; 1459 struct di_state *st; 1460 di_off_t off; 1461 phci_walk_arg_t pwa; 1462 1463 dcmn_err3((CE_CONT, "build_vhci list\n")); 1464 1465 dcmn_err3((CE_CONT, "vhci node %s%d\n", 1466 ddi_driver_name(vh_devinfo), ddi_get_instance(vh_devinfo))); 1467 1468 st = (struct di_state *)arg; 1469 if (di_dip_find(st, vh_devinfo, &off) != 0) { 1470 dcmn_err((CE_WARN, "di_dip_find error for the given node\n")); 1471 return (DDI_WALK_TERMINATE); 1472 } 1473 1474 dcmn_err3((CE_CONT, "st->mem_size: %d vh_devinfo off: 0x%x\n", 1475 st->mem_size, off)); 1476 1477 all = DI_ALL_PTR(st); 1478 if (all->top_vhci_devinfo == 0) { 1479 all->top_vhci_devinfo = off; 1480 } else { 1481 me = DI_NODE(di_mem_addr(st, all->top_vhci_devinfo)); 1482 1483 while (me->next_vhci != 0) { 1484 me = DI_NODE(di_mem_addr(st, me->next_vhci)); 1485 } 1486 1487 me->next_vhci = off; 1488 } 1489 1490 pwa.off = off; 1491 pwa.st = st; 1492 mdi_vhci_walk_phcis(vh_devinfo, build_phci_list, &pwa); 1493 1494 return (DDI_WALK_CONTINUE); 1495 } 1496 1497 /* 1498 * construct phci linkage for the given vhci in the snapshot. 1499 */ 1500 static int 1501 build_phci_list(dev_info_t *ph_devinfo, void *arg) 1502 { 1503 struct di_node *vh_di_node; 1504 struct di_node *me; 1505 phci_walk_arg_t *pwa; 1506 di_off_t off; 1507 1508 pwa = (phci_walk_arg_t *)arg; 1509 1510 dcmn_err3((CE_CONT, "build_phci list for vhci at offset: 0x%x\n", 1511 pwa->off)); 1512 1513 vh_di_node = DI_NODE(di_mem_addr(pwa->st, pwa->off)); 1514 if (di_dip_find(pwa->st, ph_devinfo, &off) != 0) { 1515 dcmn_err((CE_WARN, "di_dip_find error for the given node\n")); 1516 return (DDI_WALK_TERMINATE); 1517 } 1518 1519 dcmn_err3((CE_CONT, "phci node %s%d, at offset 0x%x\n", 1520 ddi_driver_name(ph_devinfo), ddi_get_instance(ph_devinfo), off)); 1521 1522 if (vh_di_node->top_phci == 0) { 1523 vh_di_node->top_phci = off; 1524 return (DDI_WALK_CONTINUE); 1525 } 1526 1527 me = DI_NODE(di_mem_addr(pwa->st, vh_di_node->top_phci)); 1528 1529 while (me->next_phci != 0) { 1530 me = DI_NODE(di_mem_addr(pwa->st, me->next_phci)); 1531 } 1532 me->next_phci = off; 1533 1534 return (DDI_WALK_CONTINUE); 1535 } 1536 1537 /* 1538 * Assumes all devinfo nodes in device tree have been snapshotted 1539 */ 1540 static void 1541 snap_driver_list(struct di_state *st, struct devnames *dnp, di_off_t *off_p) 1542 { 1543 struct dev_info *node; 1544 struct di_node *me; 1545 di_off_t off; 1546 1547 ASSERT(mutex_owned(&dnp->dn_lock)); 1548 1549 node = DEVI(dnp->dn_head); 1550 for (; node; node = node->devi_next) { 1551 if (di_dip_find(st, (dev_info_t *)node, &off) != 0) 1552 continue; 1553 1554 ASSERT(off > 0); 1555 me = DI_NODE(di_mem_addr(st, off)); 1556 ASSERT(me->next == 0 || me->next == -1); 1557 /* 1558 * Only nodes which were BOUND when they were 1559 * snapshotted will be added to per-driver list. 1560 */ 1561 if (me->next != -1) 1562 continue; 1563 1564 *off_p = off; 1565 off_p = &me->next; 1566 } 1567 1568 *off_p = 0; 1569 } 1570 1571 /* 1572 * Copy the devnames array, so we have a list of drivers in the snapshot. 1573 * Also makes it possible to locate the per-driver devinfo nodes. 1574 */ 1575 static di_off_t 1576 di_copydevnm(di_off_t *off_p, struct di_state *st) 1577 { 1578 int i; 1579 di_off_t off; 1580 size_t size; 1581 struct di_devnm *dnp; 1582 1583 dcmn_err2((CE_CONT, "di_copydevnm: *off_p = %p\n", (void *)off_p)); 1584 1585 /* 1586 * make sure there is some allocated memory 1587 */ 1588 size = devcnt * sizeof (struct di_devnm); 1589 *off_p = off = di_checkmem(st, *off_p, size); 1590 dnp = DI_DEVNM(di_mem_addr(st, off)); 1591 off += size; 1592 1593 dcmn_err((CE_CONT, "Start copying devnamesp[%d] at offset 0x%x\n", 1594 devcnt, off)); 1595 1596 for (i = 0; i < devcnt; i++) { 1597 if (devnamesp[i].dn_name == NULL) { 1598 continue; 1599 } 1600 1601 /* 1602 * dn_name is not freed during driver unload or removal. 1603 * 1604 * There is a race condition when make_devname() changes 1605 * dn_name during our strcpy. This should be rare since 1606 * only add_drv does this. At any rate, we never had a 1607 * problem with ddi_name_to_major(), which should have 1608 * the same problem. 1609 */ 1610 dcmn_err2((CE_CONT, "di_copydevnm: %s%d, off=%x\n", 1611 devnamesp[i].dn_name, devnamesp[i].dn_instance, off)); 1612 1613 size = strlen(devnamesp[i].dn_name) + 1; 1614 dnp[i].name = off = di_checkmem(st, off, size); 1615 (void) strcpy((char *)di_mem_addr(st, off), 1616 devnamesp[i].dn_name); 1617 off += size; 1618 1619 mutex_enter(&devnamesp[i].dn_lock); 1620 1621 /* 1622 * Snapshot per-driver node list 1623 */ 1624 snap_driver_list(st, &devnamesp[i], &dnp[i].head); 1625 1626 /* 1627 * This is not used by libdevinfo, leave it for now 1628 */ 1629 dnp[i].flags = devnamesp[i].dn_flags; 1630 dnp[i].instance = devnamesp[i].dn_instance; 1631 1632 /* 1633 * get global properties 1634 */ 1635 if ((DINFOPROP & st->command) && 1636 devnamesp[i].dn_global_prop_ptr) { 1637 dnp[i].global_prop = off; 1638 off = di_getprop(DI_PROP_GLB_LIST, 1639 &devnamesp[i].dn_global_prop_ptr->prop_list, 1640 &dnp[i].global_prop, st, NULL); 1641 } 1642 1643 /* 1644 * Bit encode driver ops: & bus_ops, cb_ops, & cb_ops->cb_str 1645 */ 1646 if (CB_DRV_INSTALLED(devopsp[i])) { 1647 if (devopsp[i]->devo_cb_ops) { 1648 dnp[i].ops |= DI_CB_OPS; 1649 if (devopsp[i]->devo_cb_ops->cb_str) 1650 dnp[i].ops |= DI_STREAM_OPS; 1651 } 1652 if (NEXUS_DRV(devopsp[i])) { 1653 dnp[i].ops |= DI_BUS_OPS; 1654 } 1655 } 1656 1657 mutex_exit(&devnamesp[i].dn_lock); 1658 } 1659 1660 dcmn_err((CE_CONT, "End copying devnamesp at offset 0x%x\n", off)); 1661 1662 return (off); 1663 } 1664 1665 /* 1666 * Copy the kernel devinfo tree. The tree and the devnames array forms 1667 * the entire snapshot (see also di_copydevnm). 1668 */ 1669 static di_off_t 1670 di_copytree(struct dev_info *root, di_off_t *off_p, struct di_state *st) 1671 { 1672 di_off_t off; 1673 struct dev_info *node; 1674 struct di_stack *dsp = kmem_zalloc(sizeof (struct di_stack), KM_SLEEP); 1675 1676 dcmn_err((CE_CONT, "di_copytree: root = %p, *off_p = %x\n", 1677 (void *)root, *off_p)); 1678 1679 /* force attach drivers */ 1680 if (i_ddi_devi_attached((dev_info_t *)root) && 1681 (st->command & DINFOSUBTREE) && (st->command & DINFOFORCE)) { 1682 (void) ndi_devi_config((dev_info_t *)root, 1683 NDI_CONFIG | NDI_DEVI_PERSIST | NDI_NO_EVENT | 1684 NDI_DRV_CONF_REPROBE); 1685 } 1686 1687 /* 1688 * Push top_devinfo onto a stack 1689 * 1690 * The stack is necessary to avoid recursion, which can overrun 1691 * the kernel stack. 1692 */ 1693 PUSH_STACK(dsp, root, off_p); 1694 1695 /* 1696 * As long as there is a node on the stack, copy the node. 1697 * di_copynode() is responsible for pushing and popping 1698 * child and sibling nodes on the stack. 1699 */ 1700 while (!EMPTY_STACK(dsp)) { 1701 node = TOP_NODE(dsp); 1702 off = di_copynode(node, dsp, st); 1703 } 1704 1705 /* 1706 * Free the stack structure 1707 */ 1708 kmem_free(dsp, sizeof (struct di_stack)); 1709 1710 return (off); 1711 } 1712 1713 /* 1714 * This is the core function, which copies all data associated with a single 1715 * node into the snapshot. The amount of information is determined by the 1716 * ioctl command. 1717 */ 1718 static di_off_t 1719 di_copynode(struct dev_info *node, struct di_stack *dsp, struct di_state *st) 1720 { 1721 di_off_t off; 1722 struct di_node *me; 1723 size_t size; 1724 struct dev_info *n; 1725 1726 dcmn_err2((CE_CONT, "di_copynode: depth = %x\n", dsp->depth)); 1727 ASSERT((node != NULL) && (node == TOP_NODE(dsp))); 1728 1729 /* 1730 * check memory usage, and fix offsets accordingly. 1731 */ 1732 size = sizeof (struct di_node); 1733 *(TOP_OFFSET(dsp)) = off = di_checkmem(st, *(TOP_OFFSET(dsp)), size); 1734 me = DI_NODE(di_mem_addr(st, off)); 1735 me->self = off; 1736 off += size; 1737 1738 dcmn_err((CE_CONT, "copy node %s, instance #%d, at offset 0x%x\n", 1739 node->devi_node_name, node->devi_instance, off)); 1740 1741 /* 1742 * Node parameters: 1743 * self -- offset of current node within snapshot 1744 * nodeid -- pointer to PROM node (tri-valued) 1745 * state -- hot plugging device state 1746 * node_state -- devinfo node state 1747 */ 1748 me->instance = node->devi_instance; 1749 me->nodeid = node->devi_nodeid; 1750 me->node_class = node->devi_node_class; 1751 me->attributes = node->devi_node_attributes; 1752 me->state = node->devi_state; 1753 me->flags = node->devi_flags; 1754 me->node_state = node->devi_node_state; 1755 me->next_vhci = 0; /* Filled up by build_vhci_list. */ 1756 me->top_phci = 0; /* Filled up by build_phci_list. */ 1757 me->next_phci = 0; /* Filled up by build_phci_list. */ 1758 me->multipath_component = MULTIPATH_COMPONENT_NONE; /* set default. */ 1759 me->user_private_data = NULL; 1760 1761 /* 1762 * Get parent's offset in snapshot from the stack 1763 * and store it in the current node 1764 */ 1765 if (dsp->depth > 1) { 1766 me->parent = *(PARENT_OFFSET(dsp)); 1767 } 1768 1769 /* 1770 * Save the offset of this di_node in a hash table. 1771 * This is used later to resolve references to this 1772 * dip from other parts of the tree (per-driver list, 1773 * multipathing linkages, layered usage linkages). 1774 * The key used for the hash table is derived from 1775 * information in the dip. 1776 */ 1777 di_register_dip(st, (dev_info_t *)node, me->self); 1778 1779 #ifdef DEVID_COMPATIBILITY 1780 /* check for devid as property marker */ 1781 if (node->devi_devid_str) { 1782 ddi_devid_t devid; 1783 1784 /* 1785 * The devid is now represented as a property. For 1786 * compatibility with di_devid() interface in libdevinfo we 1787 * must return it as a binary structure in the snapshot. When 1788 * (if) di_devid() is removed from libdevinfo then the code 1789 * related to DEVID_COMPATIBILITY can be removed. 1790 */ 1791 if (ddi_devid_str_decode(node->devi_devid_str, &devid, NULL) == 1792 DDI_SUCCESS) { 1793 size = ddi_devid_sizeof(devid); 1794 off = di_checkmem(st, off, size); 1795 me->devid = off; 1796 bcopy(devid, di_mem_addr(st, off), size); 1797 off += size; 1798 ddi_devid_free(devid); 1799 } 1800 } 1801 #endif /* DEVID_COMPATIBILITY */ 1802 1803 if (node->devi_node_name) { 1804 size = strlen(node->devi_node_name) + 1; 1805 me->node_name = off = di_checkmem(st, off, size); 1806 (void) strcpy(di_mem_addr(st, off), node->devi_node_name); 1807 off += size; 1808 } 1809 1810 if (node->devi_compat_names && (node->devi_compat_length > 1)) { 1811 size = node->devi_compat_length; 1812 me->compat_names = off = di_checkmem(st, off, size); 1813 me->compat_length = (int)size; 1814 bcopy(node->devi_compat_names, di_mem_addr(st, off), size); 1815 off += size; 1816 } 1817 1818 if (node->devi_addr) { 1819 size = strlen(node->devi_addr) + 1; 1820 me->address = off = di_checkmem(st, off, size); 1821 (void) strcpy(di_mem_addr(st, off), node->devi_addr); 1822 off += size; 1823 } 1824 1825 if (node->devi_binding_name) { 1826 size = strlen(node->devi_binding_name) + 1; 1827 me->bind_name = off = di_checkmem(st, off, size); 1828 (void) strcpy(di_mem_addr(st, off), node->devi_binding_name); 1829 off += size; 1830 } 1831 1832 me->drv_major = node->devi_major; 1833 1834 /* 1835 * If the dip is BOUND, set the next pointer of the 1836 * per-instance list to -1, indicating that it is yet to be resolved. 1837 * This will be resolved later in snap_driver_list(). 1838 */ 1839 if (me->drv_major != -1) { 1840 me->next = -1; 1841 } else { 1842 me->next = 0; 1843 } 1844 1845 /* 1846 * An optimization to skip mutex_enter when not needed. 1847 */ 1848 if (!((DINFOMINOR | DINFOPROP | DINFOPATH | DINFOHP) & st->command)) { 1849 goto priv_data; 1850 } 1851 1852 /* 1853 * LOCKING: We already have an active ndi_devi_enter to gather the 1854 * minor data, and we will take devi_lock to gather properties as 1855 * needed off di_getprop. 1856 */ 1857 if (!(DINFOMINOR & st->command)) { 1858 goto path; 1859 } 1860 1861 ASSERT(DEVI_BUSY_OWNED(node)); 1862 if (node->devi_minor) { /* minor data */ 1863 me->minor_data = off; 1864 off = di_getmdata(node->devi_minor, &me->minor_data, 1865 me->self, st); 1866 } 1867 1868 path: 1869 if (!(DINFOPATH & st->command)) { 1870 goto property; 1871 } 1872 1873 if (MDI_VHCI(node)) { 1874 me->multipath_component = MULTIPATH_COMPONENT_VHCI; 1875 } 1876 1877 if (MDI_CLIENT(node)) { 1878 me->multipath_component = MULTIPATH_COMPONENT_CLIENT; 1879 me->multipath_client = off; 1880 off = di_getpath_data((dev_info_t *)node, &me->multipath_client, 1881 me->self, st, 1); 1882 dcmn_err((CE_WARN, "me->multipath_client = %x for node %p " 1883 "component type = %d. off=%d", 1884 me->multipath_client, 1885 (void *)node, node->devi_mdi_component, off)); 1886 } 1887 1888 if (MDI_PHCI(node)) { 1889 me->multipath_component = MULTIPATH_COMPONENT_PHCI; 1890 me->multipath_phci = off; 1891 off = di_getpath_data((dev_info_t *)node, &me->multipath_phci, 1892 me->self, st, 0); 1893 dcmn_err((CE_WARN, "me->multipath_phci = %x for node %p " 1894 "component type = %d. off=%d", 1895 me->multipath_phci, 1896 (void *)node, node->devi_mdi_component, off)); 1897 } 1898 1899 property: 1900 if (!(DINFOPROP & st->command)) { 1901 goto hotplug_data; 1902 } 1903 1904 if (node->devi_drv_prop_ptr) { /* driver property list */ 1905 me->drv_prop = off; 1906 off = di_getprop(DI_PROP_DRV_LIST, &node->devi_drv_prop_ptr, 1907 &me->drv_prop, st, node); 1908 } 1909 1910 if (node->devi_sys_prop_ptr) { /* system property list */ 1911 me->sys_prop = off; 1912 off = di_getprop(DI_PROP_SYS_LIST, &node->devi_sys_prop_ptr, 1913 &me->sys_prop, st, node); 1914 } 1915 1916 if (node->devi_hw_prop_ptr) { /* hardware property list */ 1917 me->hw_prop = off; 1918 off = di_getprop(DI_PROP_HW_LIST, &node->devi_hw_prop_ptr, 1919 &me->hw_prop, st, node); 1920 } 1921 1922 if (node->devi_global_prop_list == NULL) { 1923 me->glob_prop = (di_off_t)-1; /* not global property */ 1924 } else { 1925 /* 1926 * Make copy of global property list if this devinfo refers 1927 * global properties different from what's on the devnames 1928 * array. It can happen if there has been a forced 1929 * driver.conf update. See mod_drv(1M). 1930 */ 1931 ASSERT(me->drv_major != -1); 1932 if (node->devi_global_prop_list != 1933 devnamesp[me->drv_major].dn_global_prop_ptr) { 1934 me->glob_prop = off; 1935 off = di_getprop(DI_PROP_GLB_LIST, 1936 &node->devi_global_prop_list->prop_list, 1937 &me->glob_prop, st, node); 1938 } 1939 } 1940 1941 hotplug_data: 1942 if (!(DINFOHP & st->command)) { 1943 goto priv_data; 1944 } 1945 1946 if (node->devi_hp_hdlp) { /* hotplug data */ 1947 me->hp_data = off; 1948 off = di_gethpdata(node->devi_hp_hdlp, &me->hp_data, st); 1949 } 1950 1951 priv_data: 1952 if (!(DINFOPRIVDATA & st->command)) { 1953 goto pm_info; 1954 } 1955 1956 if (ddi_get_parent_data((dev_info_t *)node) != NULL) { 1957 me->parent_data = off; 1958 off = di_getppdata(node, &me->parent_data, st); 1959 } 1960 1961 if (ddi_get_driver_private((dev_info_t *)node) != NULL) { 1962 me->driver_data = off; 1963 off = di_getdpdata(node, &me->driver_data, st); 1964 } 1965 1966 pm_info: /* NOT implemented */ 1967 1968 subtree: 1969 /* keep the stack aligned */ 1970 off = DI_ALIGN(off); 1971 1972 if (!(DINFOSUBTREE & st->command)) { 1973 POP_STACK(dsp); 1974 return (off); 1975 } 1976 1977 child: 1978 /* 1979 * If there is a visible child--push child onto stack. 1980 * Hold the parent (me) busy while doing so. 1981 */ 1982 if ((n = node->devi_child) != NULL) { 1983 /* skip hidden nodes */ 1984 while (n && ndi_dev_is_hidden_node((dev_info_t *)n)) 1985 n = n->devi_sibling; 1986 if (n) { 1987 me->child = off; 1988 PUSH_STACK(dsp, n, &me->child); 1989 return (me->child); 1990 } 1991 } 1992 1993 sibling: 1994 /* 1995 * Done with any child nodes, unroll the stack till a visible 1996 * sibling of a parent node is found or root node is reached. 1997 */ 1998 POP_STACK(dsp); 1999 while (!EMPTY_STACK(dsp)) { 2000 if ((n = node->devi_sibling) != NULL) { 2001 /* skip hidden nodes */ 2002 while (n && ndi_dev_is_hidden_node((dev_info_t *)n)) 2003 n = n->devi_sibling; 2004 if (n) { 2005 me->sibling = DI_ALIGN(off); 2006 PUSH_STACK(dsp, n, &me->sibling); 2007 return (me->sibling); 2008 } 2009 } 2010 node = TOP_NODE(dsp); 2011 me = DI_NODE(di_mem_addr(st, *(TOP_OFFSET(dsp)))); 2012 POP_STACK(dsp); 2013 } 2014 2015 /* 2016 * DONE with all nodes 2017 */ 2018 return (off); 2019 } 2020 2021 static i_lnode_t * 2022 i_lnode_alloc(int modid) 2023 { 2024 i_lnode_t *i_lnode; 2025 2026 i_lnode = kmem_zalloc(sizeof (i_lnode_t), KM_SLEEP); 2027 2028 ASSERT(modid != -1); 2029 i_lnode->modid = modid; 2030 2031 return (i_lnode); 2032 } 2033 2034 static void 2035 i_lnode_free(i_lnode_t *i_lnode) 2036 { 2037 kmem_free(i_lnode, sizeof (i_lnode_t)); 2038 } 2039 2040 static void 2041 i_lnode_check_free(i_lnode_t *i_lnode) 2042 { 2043 /* This lnode and its dip must have been snapshotted */ 2044 ASSERT(i_lnode->self > 0); 2045 ASSERT(i_lnode->di_node->self > 0); 2046 2047 /* at least 1 link (in or out) must exist for this lnode */ 2048 ASSERT(i_lnode->link_in || i_lnode->link_out); 2049 2050 i_lnode_free(i_lnode); 2051 } 2052 2053 static i_link_t * 2054 i_link_alloc(int spec_type) 2055 { 2056 i_link_t *i_link; 2057 2058 i_link = kmem_zalloc(sizeof (i_link_t), KM_SLEEP); 2059 i_link->spec_type = spec_type; 2060 2061 return (i_link); 2062 } 2063 2064 static void 2065 i_link_check_free(i_link_t *i_link) 2066 { 2067 /* This link must have been snapshotted */ 2068 ASSERT(i_link->self > 0); 2069 2070 /* Both endpoint lnodes must exist for this link */ 2071 ASSERT(i_link->src_lnode); 2072 ASSERT(i_link->tgt_lnode); 2073 2074 kmem_free(i_link, sizeof (i_link_t)); 2075 } 2076 2077 /*ARGSUSED*/ 2078 static uint_t 2079 i_lnode_hashfunc(void *arg, mod_hash_key_t key) 2080 { 2081 i_lnode_t *i_lnode = (i_lnode_t *)key; 2082 struct di_node *ptr; 2083 dev_t dev; 2084 2085 dev = i_lnode->devt; 2086 if (dev != DDI_DEV_T_NONE) 2087 return (i_lnode->modid + getminor(dev) + getmajor(dev)); 2088 2089 ptr = i_lnode->di_node; 2090 ASSERT(ptr->self > 0); 2091 if (ptr) { 2092 uintptr_t k = (uintptr_t)ptr; 2093 k >>= (int)highbit(sizeof (struct di_node)); 2094 return ((uint_t)k); 2095 } 2096 2097 return (i_lnode->modid); 2098 } 2099 2100 static int 2101 i_lnode_cmp(void *arg1, void *arg2) 2102 { 2103 i_lnode_t *i_lnode1 = (i_lnode_t *)arg1; 2104 i_lnode_t *i_lnode2 = (i_lnode_t *)arg2; 2105 2106 if (i_lnode1->modid != i_lnode2->modid) { 2107 return ((i_lnode1->modid < i_lnode2->modid) ? -1 : 1); 2108 } 2109 2110 if (i_lnode1->di_node != i_lnode2->di_node) 2111 return ((i_lnode1->di_node < i_lnode2->di_node) ? -1 : 1); 2112 2113 if (i_lnode1->devt != i_lnode2->devt) 2114 return ((i_lnode1->devt < i_lnode2->devt) ? -1 : 1); 2115 2116 return (0); 2117 } 2118 2119 /* 2120 * An lnode represents a {dip, dev_t} tuple. A link represents a 2121 * {src_lnode, tgt_lnode, spec_type} tuple. 2122 * The following callback assumes that LDI framework ref-counts the 2123 * src_dip and tgt_dip while invoking this callback. 2124 */ 2125 static int 2126 di_ldi_callback(const ldi_usage_t *ldi_usage, void *arg) 2127 { 2128 struct di_state *st = (struct di_state *)arg; 2129 i_lnode_t *src_lnode, *tgt_lnode, *i_lnode; 2130 i_link_t **i_link_next, *i_link; 2131 di_off_t soff, toff; 2132 mod_hash_val_t nodep = NULL; 2133 int res; 2134 2135 /* 2136 * if the source or target of this device usage information doesn't 2137 * correspond to a device node then we don't report it via 2138 * libdevinfo so return. 2139 */ 2140 if ((ldi_usage->src_dip == NULL) || (ldi_usage->tgt_dip == NULL)) 2141 return (LDI_USAGE_CONTINUE); 2142 2143 ASSERT(e_ddi_devi_holdcnt(ldi_usage->src_dip)); 2144 ASSERT(e_ddi_devi_holdcnt(ldi_usage->tgt_dip)); 2145 2146 /* 2147 * Skip the ldi_usage if either src or tgt dip is not in the 2148 * snapshot. This saves us from pruning bad lnodes/links later. 2149 */ 2150 if (di_dip_find(st, ldi_usage->src_dip, &soff) != 0) 2151 return (LDI_USAGE_CONTINUE); 2152 if (di_dip_find(st, ldi_usage->tgt_dip, &toff) != 0) 2153 return (LDI_USAGE_CONTINUE); 2154 2155 ASSERT(soff > 0); 2156 ASSERT(toff > 0); 2157 2158 /* 2159 * allocate an i_lnode and add it to the lnode hash 2160 * if it is not already present. For this particular 2161 * link the lnode is a source, but it may 2162 * participate as tgt or src in any number of layered 2163 * operations - so it may already be in the hash. 2164 */ 2165 i_lnode = i_lnode_alloc(ldi_usage->src_modid); 2166 i_lnode->di_node = DI_NODE(di_mem_addr(st, soff)); 2167 i_lnode->devt = ldi_usage->src_devt; 2168 2169 res = mod_hash_find(st->lnode_hash, i_lnode, &nodep); 2170 if (res == MH_ERR_NOTFOUND) { 2171 /* 2172 * new i_lnode 2173 * add it to the hash and increment the lnode count 2174 */ 2175 res = mod_hash_insert(st->lnode_hash, i_lnode, i_lnode); 2176 ASSERT(res == 0); 2177 st->lnode_count++; 2178 src_lnode = i_lnode; 2179 } else { 2180 /* this i_lnode already exists in the lnode_hash */ 2181 i_lnode_free(i_lnode); 2182 src_lnode = (i_lnode_t *)nodep; 2183 } 2184 2185 /* 2186 * allocate a tgt i_lnode and add it to the lnode hash 2187 */ 2188 i_lnode = i_lnode_alloc(ldi_usage->tgt_modid); 2189 i_lnode->di_node = DI_NODE(di_mem_addr(st, toff)); 2190 i_lnode->devt = ldi_usage->tgt_devt; 2191 2192 res = mod_hash_find(st->lnode_hash, i_lnode, &nodep); 2193 if (res == MH_ERR_NOTFOUND) { 2194 /* 2195 * new i_lnode 2196 * add it to the hash and increment the lnode count 2197 */ 2198 res = mod_hash_insert(st->lnode_hash, i_lnode, i_lnode); 2199 ASSERT(res == 0); 2200 st->lnode_count++; 2201 tgt_lnode = i_lnode; 2202 } else { 2203 /* this i_lnode already exists in the lnode_hash */ 2204 i_lnode_free(i_lnode); 2205 tgt_lnode = (i_lnode_t *)nodep; 2206 } 2207 2208 /* 2209 * allocate a i_link 2210 */ 2211 i_link = i_link_alloc(ldi_usage->tgt_spec_type); 2212 i_link->src_lnode = src_lnode; 2213 i_link->tgt_lnode = tgt_lnode; 2214 2215 /* 2216 * add this link onto the src i_lnodes outbound i_link list 2217 */ 2218 i_link_next = &(src_lnode->link_out); 2219 while (*i_link_next != NULL) { 2220 if ((i_lnode_cmp(tgt_lnode, (*i_link_next)->tgt_lnode) == 0) && 2221 (i_link->spec_type == (*i_link_next)->spec_type)) { 2222 /* this link already exists */ 2223 kmem_free(i_link, sizeof (i_link_t)); 2224 return (LDI_USAGE_CONTINUE); 2225 } 2226 i_link_next = &((*i_link_next)->src_link_next); 2227 } 2228 *i_link_next = i_link; 2229 2230 /* 2231 * add this link onto the tgt i_lnodes inbound i_link list 2232 */ 2233 i_link_next = &(tgt_lnode->link_in); 2234 while (*i_link_next != NULL) { 2235 ASSERT(i_lnode_cmp(src_lnode, (*i_link_next)->src_lnode) != 0); 2236 i_link_next = &((*i_link_next)->tgt_link_next); 2237 } 2238 *i_link_next = i_link; 2239 2240 /* 2241 * add this i_link to the link hash 2242 */ 2243 res = mod_hash_insert(st->link_hash, i_link, i_link); 2244 ASSERT(res == 0); 2245 st->link_count++; 2246 2247 return (LDI_USAGE_CONTINUE); 2248 } 2249 2250 struct i_layer_data { 2251 struct di_state *st; 2252 int lnode_count; 2253 int link_count; 2254 di_off_t lnode_off; 2255 di_off_t link_off; 2256 }; 2257 2258 /*ARGSUSED*/ 2259 static uint_t 2260 i_link_walker(mod_hash_key_t key, mod_hash_val_t *val, void *arg) 2261 { 2262 i_link_t *i_link = (i_link_t *)key; 2263 struct i_layer_data *data = arg; 2264 struct di_link *me; 2265 struct di_lnode *melnode; 2266 struct di_node *medinode; 2267 2268 ASSERT(i_link->self == 0); 2269 2270 i_link->self = data->link_off + 2271 (data->link_count * sizeof (struct di_link)); 2272 data->link_count++; 2273 2274 ASSERT(data->link_off > 0 && data->link_count > 0); 2275 ASSERT(data->lnode_count == data->st->lnode_count); /* lnodes done */ 2276 ASSERT(data->link_count <= data->st->link_count); 2277 2278 /* fill in fields for the di_link snapshot */ 2279 me = DI_LINK(di_mem_addr(data->st, i_link->self)); 2280 me->self = i_link->self; 2281 me->spec_type = i_link->spec_type; 2282 2283 /* 2284 * The src_lnode and tgt_lnode i_lnode_t for this i_link_t 2285 * are created during the LDI table walk. Since we are 2286 * walking the link hash, the lnode hash has already been 2287 * walked and the lnodes have been snapshotted. Save lnode 2288 * offsets. 2289 */ 2290 me->src_lnode = i_link->src_lnode->self; 2291 me->tgt_lnode = i_link->tgt_lnode->self; 2292 2293 /* 2294 * Save this link's offset in the src_lnode snapshot's link_out 2295 * field 2296 */ 2297 melnode = DI_LNODE(di_mem_addr(data->st, me->src_lnode)); 2298 me->src_link_next = melnode->link_out; 2299 melnode->link_out = me->self; 2300 2301 /* 2302 * Put this link on the tgt_lnode's link_in field 2303 */ 2304 melnode = DI_LNODE(di_mem_addr(data->st, me->tgt_lnode)); 2305 me->tgt_link_next = melnode->link_in; 2306 melnode->link_in = me->self; 2307 2308 /* 2309 * An i_lnode_t is only created if the corresponding dip exists 2310 * in the snapshot. A pointer to the di_node is saved in the 2311 * i_lnode_t when it is allocated. For this link, get the di_node 2312 * for the source lnode. Then put the link on the di_node's list 2313 * of src links 2314 */ 2315 medinode = i_link->src_lnode->di_node; 2316 me->src_node_next = medinode->src_links; 2317 medinode->src_links = me->self; 2318 2319 /* 2320 * Put this link on the tgt_links list of the target 2321 * dip. 2322 */ 2323 medinode = i_link->tgt_lnode->di_node; 2324 me->tgt_node_next = medinode->tgt_links; 2325 medinode->tgt_links = me->self; 2326 2327 return (MH_WALK_CONTINUE); 2328 } 2329 2330 /*ARGSUSED*/ 2331 static uint_t 2332 i_lnode_walker(mod_hash_key_t key, mod_hash_val_t *val, void *arg) 2333 { 2334 i_lnode_t *i_lnode = (i_lnode_t *)key; 2335 struct i_layer_data *data = arg; 2336 struct di_lnode *me; 2337 struct di_node *medinode; 2338 2339 ASSERT(i_lnode->self == 0); 2340 2341 i_lnode->self = data->lnode_off + 2342 (data->lnode_count * sizeof (struct di_lnode)); 2343 data->lnode_count++; 2344 2345 ASSERT(data->lnode_off > 0 && data->lnode_count > 0); 2346 ASSERT(data->link_count == 0); /* links not done yet */ 2347 ASSERT(data->lnode_count <= data->st->lnode_count); 2348 2349 /* fill in fields for the di_lnode snapshot */ 2350 me = DI_LNODE(di_mem_addr(data->st, i_lnode->self)); 2351 me->self = i_lnode->self; 2352 2353 if (i_lnode->devt == DDI_DEV_T_NONE) { 2354 me->dev_major = DDI_MAJOR_T_NONE; 2355 me->dev_minor = DDI_MAJOR_T_NONE; 2356 } else { 2357 me->dev_major = getmajor(i_lnode->devt); 2358 me->dev_minor = getminor(i_lnode->devt); 2359 } 2360 2361 /* 2362 * The dip corresponding to this lnode must exist in 2363 * the snapshot or we wouldn't have created the i_lnode_t 2364 * during LDI walk. Save the offset of the dip. 2365 */ 2366 ASSERT(i_lnode->di_node && i_lnode->di_node->self > 0); 2367 me->node = i_lnode->di_node->self; 2368 2369 /* 2370 * There must be at least one link in or out of this lnode 2371 * or we wouldn't have created it. These fields will be set 2372 * during the link hash walk. 2373 */ 2374 ASSERT((i_lnode->link_in != NULL) || (i_lnode->link_out != NULL)); 2375 2376 /* 2377 * set the offset of the devinfo node associated with this 2378 * lnode. Also update the node_next next pointer. this pointer 2379 * is set if there are multiple lnodes associated with the same 2380 * devinfo node. (could occure when multiple minor nodes 2381 * are open for one device, etc.) 2382 */ 2383 medinode = i_lnode->di_node; 2384 me->node_next = medinode->lnodes; 2385 medinode->lnodes = me->self; 2386 2387 return (MH_WALK_CONTINUE); 2388 } 2389 2390 static di_off_t 2391 di_getlink_data(di_off_t off, struct di_state *st) 2392 { 2393 struct i_layer_data data = {0}; 2394 size_t size; 2395 2396 dcmn_err2((CE_CONT, "di_copylyr: off = %x\n", off)); 2397 2398 st->lnode_hash = mod_hash_create_extended("di_lnode_hash", 32, 2399 mod_hash_null_keydtor, (void (*)(mod_hash_val_t))i_lnode_check_free, 2400 i_lnode_hashfunc, NULL, i_lnode_cmp, KM_SLEEP); 2401 2402 st->link_hash = mod_hash_create_ptrhash("di_link_hash", 32, 2403 (void (*)(mod_hash_val_t))i_link_check_free, sizeof (i_link_t)); 2404 2405 /* get driver layering information */ 2406 (void) ldi_usage_walker(st, di_ldi_callback); 2407 2408 /* check if there is any link data to include in the snapshot */ 2409 if (st->lnode_count == 0) { 2410 ASSERT(st->link_count == 0); 2411 goto out; 2412 } 2413 2414 ASSERT(st->link_count != 0); 2415 2416 /* get a pointer to snapshot memory for all the di_lnodes */ 2417 size = sizeof (struct di_lnode) * st->lnode_count; 2418 data.lnode_off = off = di_checkmem(st, off, size); 2419 off += size; 2420 2421 /* get a pointer to snapshot memory for all the di_links */ 2422 size = sizeof (struct di_link) * st->link_count; 2423 data.link_off = off = di_checkmem(st, off, size); 2424 off += size; 2425 2426 data.lnode_count = data.link_count = 0; 2427 data.st = st; 2428 2429 /* 2430 * We have lnodes and links that will go into the 2431 * snapshot, so let's walk the respective hashes 2432 * and snapshot them. The various linkages are 2433 * also set up during the walk. 2434 */ 2435 mod_hash_walk(st->lnode_hash, i_lnode_walker, (void *)&data); 2436 ASSERT(data.lnode_count == st->lnode_count); 2437 2438 mod_hash_walk(st->link_hash, i_link_walker, (void *)&data); 2439 ASSERT(data.link_count == st->link_count); 2440 2441 out: 2442 /* free up the i_lnodes and i_links used to create the snapshot */ 2443 mod_hash_destroy_hash(st->lnode_hash); 2444 mod_hash_destroy_hash(st->link_hash); 2445 st->lnode_count = 0; 2446 st->link_count = 0; 2447 2448 return (off); 2449 } 2450 2451 2452 /* 2453 * Copy all minor data nodes attached to a devinfo node into the snapshot. 2454 * It is called from di_copynode with active ndi_devi_enter to protect 2455 * the list of minor nodes. 2456 */ 2457 static di_off_t 2458 di_getmdata(struct ddi_minor_data *mnode, di_off_t *off_p, di_off_t node, 2459 struct di_state *st) 2460 { 2461 di_off_t off; 2462 struct di_minor *me; 2463 size_t size; 2464 2465 dcmn_err2((CE_CONT, "di_getmdata:\n")); 2466 2467 /* 2468 * check memory first 2469 */ 2470 off = di_checkmem(st, *off_p, sizeof (struct di_minor)); 2471 *off_p = off; 2472 2473 do { 2474 me = DI_MINOR(di_mem_addr(st, off)); 2475 me->self = off; 2476 me->type = mnode->type; 2477 me->node = node; 2478 me->user_private_data = NULL; 2479 2480 off += sizeof (struct di_minor); 2481 2482 /* 2483 * Split dev_t to major/minor, so it works for 2484 * both ILP32 and LP64 model 2485 */ 2486 me->dev_major = getmajor(mnode->ddm_dev); 2487 me->dev_minor = getminor(mnode->ddm_dev); 2488 me->spec_type = mnode->ddm_spec_type; 2489 2490 if (mnode->ddm_name) { 2491 size = strlen(mnode->ddm_name) + 1; 2492 me->name = off = di_checkmem(st, off, size); 2493 (void) strcpy(di_mem_addr(st, off), mnode->ddm_name); 2494 off += size; 2495 } 2496 2497 if (mnode->ddm_node_type) { 2498 size = strlen(mnode->ddm_node_type) + 1; 2499 me->node_type = off = di_checkmem(st, off, size); 2500 (void) strcpy(di_mem_addr(st, off), 2501 mnode->ddm_node_type); 2502 off += size; 2503 } 2504 2505 off = di_checkmem(st, off, sizeof (struct di_minor)); 2506 me->next = off; 2507 mnode = mnode->next; 2508 } while (mnode); 2509 2510 me->next = 0; 2511 2512 return (off); 2513 } 2514 2515 /* 2516 * di_register_dip(), di_find_dip(): The dip must be protected 2517 * from deallocation when using these routines - this can either 2518 * be a reference count, a busy hold or a per-driver lock. 2519 */ 2520 2521 static void 2522 di_register_dip(struct di_state *st, dev_info_t *dip, di_off_t off) 2523 { 2524 struct dev_info *node = DEVI(dip); 2525 struct di_key *key = kmem_zalloc(sizeof (*key), KM_SLEEP); 2526 struct di_dkey *dk; 2527 2528 ASSERT(dip); 2529 ASSERT(off > 0); 2530 2531 key->k_type = DI_DKEY; 2532 dk = &(key->k_u.dkey); 2533 2534 dk->dk_dip = dip; 2535 dk->dk_major = node->devi_major; 2536 dk->dk_inst = node->devi_instance; 2537 dk->dk_nodeid = node->devi_nodeid; 2538 2539 if (mod_hash_insert(st->reg_dip_hash, (mod_hash_key_t)key, 2540 (mod_hash_val_t)(uintptr_t)off) != 0) { 2541 panic( 2542 "duplicate devinfo (%p) registered during device " 2543 "tree walk", (void *)dip); 2544 } 2545 } 2546 2547 2548 static int 2549 di_dip_find(struct di_state *st, dev_info_t *dip, di_off_t *off_p) 2550 { 2551 /* 2552 * uintptr_t must be used because it matches the size of void *; 2553 * mod_hash expects clients to place results into pointer-size 2554 * containers; since di_off_t is always a 32-bit offset, alignment 2555 * would otherwise be broken on 64-bit kernels. 2556 */ 2557 uintptr_t offset; 2558 struct di_key key = {0}; 2559 struct di_dkey *dk; 2560 2561 ASSERT(st->reg_dip_hash); 2562 ASSERT(dip); 2563 ASSERT(off_p); 2564 2565 2566 key.k_type = DI_DKEY; 2567 dk = &(key.k_u.dkey); 2568 2569 dk->dk_dip = dip; 2570 dk->dk_major = DEVI(dip)->devi_major; 2571 dk->dk_inst = DEVI(dip)->devi_instance; 2572 dk->dk_nodeid = DEVI(dip)->devi_nodeid; 2573 2574 if (mod_hash_find(st->reg_dip_hash, (mod_hash_key_t)&key, 2575 (mod_hash_val_t *)&offset) == 0) { 2576 *off_p = (di_off_t)offset; 2577 return (0); 2578 } else { 2579 return (-1); 2580 } 2581 } 2582 2583 /* 2584 * di_register_pip(), di_find_pip(): The pip must be protected from deallocation 2585 * when using these routines. The caller must do this by protecting the 2586 * client(or phci)<->pip linkage while traversing the list and then holding the 2587 * pip when it is found in the list. 2588 */ 2589 2590 static void 2591 di_register_pip(struct di_state *st, mdi_pathinfo_t *pip, di_off_t off) 2592 { 2593 struct di_key *key = kmem_zalloc(sizeof (*key), KM_SLEEP); 2594 char *path_addr; 2595 struct di_pkey *pk; 2596 2597 ASSERT(pip); 2598 ASSERT(off > 0); 2599 2600 key->k_type = DI_PKEY; 2601 pk = &(key->k_u.pkey); 2602 2603 pk->pk_pip = pip; 2604 path_addr = mdi_pi_get_addr(pip); 2605 if (path_addr) 2606 pk->pk_path_addr = i_ddi_strdup(path_addr, KM_SLEEP); 2607 pk->pk_client = mdi_pi_get_client(pip); 2608 pk->pk_phci = mdi_pi_get_phci(pip); 2609 2610 if (mod_hash_insert(st->reg_pip_hash, (mod_hash_key_t)key, 2611 (mod_hash_val_t)(uintptr_t)off) != 0) { 2612 panic( 2613 "duplicate pathinfo (%p) registered during device " 2614 "tree walk", (void *)pip); 2615 } 2616 } 2617 2618 /* 2619 * As with di_register_pip, the caller must hold or lock the pip 2620 */ 2621 static int 2622 di_pip_find(struct di_state *st, mdi_pathinfo_t *pip, di_off_t *off_p) 2623 { 2624 /* 2625 * uintptr_t must be used because it matches the size of void *; 2626 * mod_hash expects clients to place results into pointer-size 2627 * containers; since di_off_t is always a 32-bit offset, alignment 2628 * would otherwise be broken on 64-bit kernels. 2629 */ 2630 uintptr_t offset; 2631 struct di_key key = {0}; 2632 struct di_pkey *pk; 2633 2634 ASSERT(st->reg_pip_hash); 2635 ASSERT(off_p); 2636 2637 if (pip == NULL) { 2638 *off_p = 0; 2639 return (0); 2640 } 2641 2642 key.k_type = DI_PKEY; 2643 pk = &(key.k_u.pkey); 2644 2645 pk->pk_pip = pip; 2646 pk->pk_path_addr = mdi_pi_get_addr(pip); 2647 pk->pk_client = mdi_pi_get_client(pip); 2648 pk->pk_phci = mdi_pi_get_phci(pip); 2649 2650 if (mod_hash_find(st->reg_pip_hash, (mod_hash_key_t)&key, 2651 (mod_hash_val_t *)&offset) == 0) { 2652 *off_p = (di_off_t)offset; 2653 return (0); 2654 } else { 2655 return (-1); 2656 } 2657 } 2658 2659 static di_path_state_t 2660 path_state_convert(mdi_pathinfo_state_t st) 2661 { 2662 switch (st) { 2663 case MDI_PATHINFO_STATE_ONLINE: 2664 return (DI_PATH_STATE_ONLINE); 2665 case MDI_PATHINFO_STATE_STANDBY: 2666 return (DI_PATH_STATE_STANDBY); 2667 case MDI_PATHINFO_STATE_OFFLINE: 2668 return (DI_PATH_STATE_OFFLINE); 2669 case MDI_PATHINFO_STATE_FAULT: 2670 return (DI_PATH_STATE_FAULT); 2671 default: 2672 return (DI_PATH_STATE_UNKNOWN); 2673 } 2674 } 2675 2676 static uint_t 2677 path_flags_convert(uint_t pi_path_flags) 2678 { 2679 uint_t di_path_flags = 0; 2680 2681 /* MDI_PATHINFO_FLAGS_HIDDEN nodes not in snapshot */ 2682 2683 if (pi_path_flags & MDI_PATHINFO_FLAGS_DEVICE_REMOVED) 2684 di_path_flags |= DI_PATH_FLAGS_DEVICE_REMOVED; 2685 2686 return (di_path_flags); 2687 } 2688 2689 2690 static di_off_t 2691 di_path_getprop(mdi_pathinfo_t *pip, di_off_t *off_p, 2692 struct di_state *st) 2693 { 2694 nvpair_t *prop = NULL; 2695 struct di_path_prop *me; 2696 int off; 2697 size_t size; 2698 char *str; 2699 uchar_t *buf; 2700 uint_t nelems; 2701 2702 off = *off_p; 2703 if (mdi_pi_get_next_prop(pip, NULL) == NULL) { 2704 *off_p = 0; 2705 return (off); 2706 } 2707 2708 off = di_checkmem(st, off, sizeof (struct di_path_prop)); 2709 *off_p = off; 2710 2711 while (prop = mdi_pi_get_next_prop(pip, prop)) { 2712 me = DI_PATHPROP(di_mem_addr(st, off)); 2713 me->self = off; 2714 off += sizeof (struct di_path_prop); 2715 2716 /* 2717 * property name 2718 */ 2719 size = strlen(nvpair_name(prop)) + 1; 2720 me->prop_name = off = di_checkmem(st, off, size); 2721 (void) strcpy(di_mem_addr(st, off), nvpair_name(prop)); 2722 off += size; 2723 2724 switch (nvpair_type(prop)) { 2725 case DATA_TYPE_BYTE: 2726 case DATA_TYPE_INT16: 2727 case DATA_TYPE_UINT16: 2728 case DATA_TYPE_INT32: 2729 case DATA_TYPE_UINT32: 2730 me->prop_type = DDI_PROP_TYPE_INT; 2731 size = sizeof (int32_t); 2732 off = di_checkmem(st, off, size); 2733 (void) nvpair_value_int32(prop, 2734 (int32_t *)di_mem_addr(st, off)); 2735 break; 2736 2737 case DATA_TYPE_INT64: 2738 case DATA_TYPE_UINT64: 2739 me->prop_type = DDI_PROP_TYPE_INT64; 2740 size = sizeof (int64_t); 2741 off = di_checkmem(st, off, size); 2742 (void) nvpair_value_int64(prop, 2743 (int64_t *)di_mem_addr(st, off)); 2744 break; 2745 2746 case DATA_TYPE_STRING: 2747 me->prop_type = DDI_PROP_TYPE_STRING; 2748 (void) nvpair_value_string(prop, &str); 2749 size = strlen(str) + 1; 2750 off = di_checkmem(st, off, size); 2751 (void) strcpy(di_mem_addr(st, off), str); 2752 break; 2753 2754 case DATA_TYPE_BYTE_ARRAY: 2755 case DATA_TYPE_INT16_ARRAY: 2756 case DATA_TYPE_UINT16_ARRAY: 2757 case DATA_TYPE_INT32_ARRAY: 2758 case DATA_TYPE_UINT32_ARRAY: 2759 case DATA_TYPE_INT64_ARRAY: 2760 case DATA_TYPE_UINT64_ARRAY: 2761 me->prop_type = DDI_PROP_TYPE_BYTE; 2762 (void) nvpair_value_byte_array(prop, &buf, &nelems); 2763 size = nelems; 2764 if (nelems != 0) { 2765 off = di_checkmem(st, off, size); 2766 bcopy(buf, di_mem_addr(st, off), size); 2767 } 2768 break; 2769 2770 default: /* Unknown or unhandled type; skip it */ 2771 size = 0; 2772 break; 2773 } 2774 2775 if (size > 0) { 2776 me->prop_data = off; 2777 } 2778 2779 me->prop_len = (int)size; 2780 off += size; 2781 2782 off = di_checkmem(st, off, sizeof (struct di_path_prop)); 2783 me->prop_next = off; 2784 } 2785 2786 me->prop_next = 0; 2787 return (off); 2788 } 2789 2790 2791 static void 2792 di_path_one_endpoint(struct di_path *me, di_off_t noff, di_off_t **off_pp, 2793 int get_client) 2794 { 2795 if (get_client) { 2796 ASSERT(me->path_client == 0); 2797 me->path_client = noff; 2798 ASSERT(me->path_c_link == 0); 2799 *off_pp = &me->path_c_link; 2800 me->path_snap_state &= 2801 ~(DI_PATH_SNAP_NOCLIENT | DI_PATH_SNAP_NOCLINK); 2802 } else { 2803 ASSERT(me->path_phci == 0); 2804 me->path_phci = noff; 2805 ASSERT(me->path_p_link == 0); 2806 *off_pp = &me->path_p_link; 2807 me->path_snap_state &= 2808 ~(DI_PATH_SNAP_NOPHCI | DI_PATH_SNAP_NOPLINK); 2809 } 2810 } 2811 2812 /* 2813 * off_p: pointer to the linkage field. This links pips along the client|phci 2814 * linkage list. 2815 * noff : Offset for the endpoint dip snapshot. 2816 */ 2817 static di_off_t 2818 di_getpath_data(dev_info_t *dip, di_off_t *off_p, di_off_t noff, 2819 struct di_state *st, int get_client) 2820 { 2821 di_off_t off; 2822 mdi_pathinfo_t *pip; 2823 struct di_path *me; 2824 mdi_pathinfo_t *(*next_pip)(dev_info_t *, mdi_pathinfo_t *); 2825 size_t size; 2826 2827 dcmn_err2((CE_WARN, "di_getpath_data: client = %d", get_client)); 2828 2829 /* 2830 * The naming of the following mdi_xyz() is unfortunately 2831 * non-intuitive. mdi_get_next_phci_path() follows the 2832 * client_link i.e. the list of pip's belonging to the 2833 * given client dip. 2834 */ 2835 if (get_client) 2836 next_pip = &mdi_get_next_phci_path; 2837 else 2838 next_pip = &mdi_get_next_client_path; 2839 2840 off = *off_p; 2841 2842 pip = NULL; 2843 while (pip = (*next_pip)(dip, pip)) { 2844 di_off_t stored_offset; 2845 2846 dcmn_err((CE_WARN, "marshalling pip = %p", (void *)pip)); 2847 2848 mdi_pi_lock(pip); 2849 2850 /* We don't represent hidden paths in the snapshot */ 2851 if (mdi_pi_ishidden(pip)) { 2852 dcmn_err((CE_WARN, "hidden, skip")); 2853 mdi_pi_unlock(pip); 2854 continue; 2855 } 2856 2857 if (di_pip_find(st, pip, &stored_offset) != -1) { 2858 /* 2859 * We've already seen this pathinfo node so we need to 2860 * take care not to snap it again; However, one endpoint 2861 * and linkage will be set here. The other endpoint 2862 * and linkage has already been set when the pip was 2863 * first snapshotted i.e. when the other endpoint dip 2864 * was snapshotted. 2865 */ 2866 me = DI_PATH(di_mem_addr(st, stored_offset)); 2867 *off_p = stored_offset; 2868 2869 di_path_one_endpoint(me, noff, &off_p, get_client); 2870 2871 /* 2872 * The other endpoint and linkage were set when this 2873 * pip was snapshotted. So we are done with both 2874 * endpoints and linkages. 2875 */ 2876 ASSERT(!(me->path_snap_state & 2877 (DI_PATH_SNAP_NOCLIENT|DI_PATH_SNAP_NOPHCI))); 2878 ASSERT(!(me->path_snap_state & 2879 (DI_PATH_SNAP_NOCLINK|DI_PATH_SNAP_NOPLINK))); 2880 2881 mdi_pi_unlock(pip); 2882 continue; 2883 } 2884 2885 /* 2886 * Now that we need to snapshot this pip, check memory 2887 */ 2888 size = sizeof (struct di_path); 2889 *off_p = off = di_checkmem(st, off, size); 2890 me = DI_PATH(di_mem_addr(st, off)); 2891 me->self = off; 2892 off += size; 2893 2894 me->path_snap_state = 2895 DI_PATH_SNAP_NOCLINK | DI_PATH_SNAP_NOPLINK; 2896 me->path_snap_state |= 2897 DI_PATH_SNAP_NOCLIENT | DI_PATH_SNAP_NOPHCI; 2898 2899 /* 2900 * Zero out fields as di_checkmem() doesn't guarantee 2901 * zero-filled memory 2902 */ 2903 me->path_client = me->path_phci = 0; 2904 me->path_c_link = me->path_p_link = 0; 2905 2906 di_path_one_endpoint(me, noff, &off_p, get_client); 2907 2908 /* 2909 * Note the existence of this pathinfo 2910 */ 2911 di_register_pip(st, pip, me->self); 2912 2913 me->path_state = path_state_convert(mdi_pi_get_state(pip)); 2914 me->path_flags = path_flags_convert(mdi_pi_get_flags(pip)); 2915 2916 me->path_instance = mdi_pi_get_path_instance(pip); 2917 2918 /* 2919 * Get intermediate addressing info. 2920 */ 2921 size = strlen(mdi_pi_get_addr(pip)) + 1; 2922 me->path_addr = off = di_checkmem(st, off, size); 2923 (void) strcpy(di_mem_addr(st, off), mdi_pi_get_addr(pip)); 2924 off += size; 2925 2926 /* 2927 * Get path properties if props are to be included in the 2928 * snapshot 2929 */ 2930 if (DINFOPROP & st->command) { 2931 me->path_prop = off; 2932 off = di_path_getprop(pip, &me->path_prop, st); 2933 } else { 2934 me->path_prop = 0; 2935 } 2936 2937 mdi_pi_unlock(pip); 2938 } 2939 2940 *off_p = 0; 2941 return (off); 2942 } 2943 2944 /* 2945 * Return driver prop_op entry point for the specified devinfo node. 2946 * 2947 * To return a non-NULL value: 2948 * - driver must be attached and held: 2949 * If driver is not attached we ignore the driver property list. 2950 * No one should rely on such properties. 2951 * - driver "cb_prop_op != ddi_prop_op": 2952 * If "cb_prop_op == ddi_prop_op", framework does not need to call driver. 2953 * XXX or parent's bus_prop_op != ddi_bus_prop_op 2954 */ 2955 static int 2956 (*di_getprop_prop_op(struct dev_info *dip)) 2957 (dev_t, dev_info_t *, ddi_prop_op_t, int, char *, caddr_t, int *) 2958 { 2959 struct dev_ops *ops; 2960 2961 /* If driver is not attached we ignore the driver property list. */ 2962 if ((dip == NULL) || !i_ddi_devi_attached((dev_info_t *)dip)) 2963 return (NULL); 2964 2965 /* 2966 * Some nexus drivers incorrectly set cb_prop_op to nodev, nulldev, 2967 * or even NULL. 2968 */ 2969 ops = dip->devi_ops; 2970 if (ops && ops->devo_cb_ops && 2971 (ops->devo_cb_ops->cb_prop_op != ddi_prop_op) && 2972 (ops->devo_cb_ops->cb_prop_op != nodev) && 2973 (ops->devo_cb_ops->cb_prop_op != nulldev) && 2974 (ops->devo_cb_ops->cb_prop_op != NULL)) 2975 return (ops->devo_cb_ops->cb_prop_op); 2976 return (NULL); 2977 } 2978 2979 static di_off_t 2980 di_getprop_add(int list, int dyn, struct di_state *st, struct dev_info *dip, 2981 int (*prop_op)(), 2982 char *name, dev_t devt, int aflags, int alen, caddr_t aval, 2983 di_off_t off, di_off_t **off_pp) 2984 { 2985 int need_free = 0; 2986 dev_t pdevt; 2987 int pflags; 2988 int rv; 2989 caddr_t val; 2990 int len; 2991 size_t size; 2992 struct di_prop *pp; 2993 2994 /* If we have prop_op function, ask driver for latest value */ 2995 if (prop_op) { 2996 ASSERT(dip); 2997 2998 /* Must search DDI_DEV_T_NONE with DDI_DEV_T_ANY */ 2999 pdevt = (devt == DDI_DEV_T_NONE) ? DDI_DEV_T_ANY : devt; 3000 3001 /* 3002 * We have type information in flags, but are invoking an 3003 * old non-typed prop_op(9E) interface. Since not all types are 3004 * part of DDI_PROP_TYPE_ANY (example is DDI_PROP_TYPE_INT64), 3005 * we set DDI_PROP_CONSUMER_TYPED - causing the framework to 3006 * expand type bits beyond DDI_PROP_TYPE_ANY. This allows us 3007 * to use the legacy prop_op(9E) interface to obtain updates 3008 * non-DDI_PROP_TYPE_ANY dynamic properties. 3009 */ 3010 pflags = aflags & ~DDI_PROP_TYPE_MASK; 3011 pflags |= DDI_PROP_DONTPASS | DDI_PROP_NOTPROM | 3012 DDI_PROP_CONSUMER_TYPED; 3013 3014 /* 3015 * Hold and exit across prop_op(9E) to avoid lock order 3016 * issues between 3017 * [ndi_devi_enter() ..prop_op(9E).. driver-lock] 3018 * .vs. 3019 * [..ioctl(9E).. driver-lock ..ddi_remove_minor_node(9F).. 3020 * ndi_devi_enter()] 3021 * ordering. 3022 */ 3023 ndi_hold_devi((dev_info_t *)dip); 3024 ndi_devi_exit((dev_info_t *)dip, dip->devi_circular); 3025 rv = (*prop_op)(pdevt, (dev_info_t *)dip, 3026 PROP_LEN_AND_VAL_ALLOC, pflags, name, &val, &len); 3027 ndi_devi_enter((dev_info_t *)dip, &dip->devi_circular); 3028 ndi_rele_devi((dev_info_t *)dip); 3029 3030 if (rv == DDI_PROP_SUCCESS) { 3031 need_free = 1; /* dynamic prop obtained */ 3032 } else if (dyn) { 3033 /* 3034 * A dynamic property must succeed prop_op(9E) to show 3035 * up in the snapshot - that is the only source of its 3036 * value. 3037 */ 3038 return (off); /* dynamic prop not supported */ 3039 } else { 3040 /* 3041 * In case calling the driver caused an update off 3042 * prop_op(9E) of a non-dynamic property (code leading 3043 * to ddi_prop_change), we defer picking up val and 3044 * len informatiojn until after prop_op(9E) to ensure 3045 * that we snapshot the latest value. 3046 */ 3047 val = aval; 3048 len = alen; 3049 3050 } 3051 } else { 3052 val = aval; 3053 len = alen; 3054 } 3055 3056 dcmn_err((CE_CONT, "di_getprop_add: list %d %s len %d val %p\n", 3057 list, name ? name : "NULL", len, (void *)val)); 3058 3059 size = sizeof (struct di_prop); 3060 **off_pp = off = di_checkmem(st, off, size); 3061 pp = DI_PROP(di_mem_addr(st, off)); 3062 pp->self = off; 3063 off += size; 3064 3065 pp->dev_major = getmajor(devt); 3066 pp->dev_minor = getminor(devt); 3067 pp->prop_flags = aflags; 3068 pp->prop_list = list; 3069 3070 /* property name */ 3071 if (name) { 3072 size = strlen(name) + 1; 3073 pp->prop_name = off = di_checkmem(st, off, size); 3074 (void) strcpy(di_mem_addr(st, off), name); 3075 off += size; 3076 } else { 3077 pp->prop_name = -1; 3078 } 3079 3080 pp->prop_len = len; 3081 if (val == NULL) { 3082 pp->prop_data = -1; 3083 } else if (len != 0) { 3084 size = len; 3085 pp->prop_data = off = di_checkmem(st, off, size); 3086 bcopy(val, di_mem_addr(st, off), size); 3087 off += size; 3088 } 3089 3090 pp->next = 0; /* assume tail for now */ 3091 *off_pp = &pp->next; /* return pointer to our next */ 3092 3093 if (need_free) /* free PROP_LEN_AND_VAL_ALLOC alloc */ 3094 kmem_free(val, len); 3095 return (off); 3096 } 3097 3098 3099 /* 3100 * Copy a list of properties attached to a devinfo node. Called from 3101 * di_copynode with active ndi_devi_enter. The major number is passed in case 3102 * we need to call driver's prop_op entry. The value of list indicates 3103 * which list we are copying. Possible values are: 3104 * DI_PROP_DRV_LIST, DI_PROP_SYS_LIST, DI_PROP_GLB_LIST, DI_PROP_HW_LIST 3105 */ 3106 static di_off_t 3107 di_getprop(int list, struct ddi_prop **pprop, di_off_t *off_p, 3108 struct di_state *st, struct dev_info *dip) 3109 { 3110 struct ddi_prop *prop; 3111 int (*prop_op)(); 3112 int off; 3113 struct ddi_minor_data *mn; 3114 i_ddi_prop_dyn_t *dp; 3115 struct plist { 3116 struct plist *pl_next; 3117 char *pl_name; 3118 int pl_flags; 3119 dev_t pl_dev; 3120 int pl_len; 3121 caddr_t pl_val; 3122 } *pl, *pl0, **plp; 3123 3124 ASSERT(st != NULL); 3125 3126 off = *off_p; 3127 *off_p = 0; 3128 dcmn_err((CE_CONT, "di_getprop: copy property list %d at addr %p\n", 3129 list, (void *)*pprop)); 3130 3131 /* get pointer to driver's prop_op(9E) implementation if DRV_LIST */ 3132 prop_op = (list == DI_PROP_DRV_LIST) ? di_getprop_prop_op(dip) : NULL; 3133 3134 /* 3135 * Form private list of properties, holding devi_lock for properties 3136 * that hang off the dip. 3137 */ 3138 if (dip) 3139 mutex_enter(&(dip->devi_lock)); 3140 for (pl0 = NULL, plp = &pl0, prop = *pprop; 3141 prop; plp = &pl->pl_next, prop = prop->prop_next) { 3142 pl = kmem_alloc(sizeof (*pl), KM_SLEEP); 3143 *plp = pl; 3144 pl->pl_next = NULL; 3145 if (prop->prop_name) 3146 pl->pl_name = i_ddi_strdup(prop->prop_name, KM_SLEEP); 3147 else 3148 pl->pl_name = NULL; 3149 pl->pl_flags = prop->prop_flags; 3150 pl->pl_dev = prop->prop_dev; 3151 if (prop->prop_len) { 3152 pl->pl_len = prop->prop_len; 3153 pl->pl_val = kmem_alloc(pl->pl_len, KM_SLEEP); 3154 bcopy(prop->prop_val, pl->pl_val, pl->pl_len); 3155 } else { 3156 pl->pl_len = 0; 3157 pl->pl_val = NULL; 3158 } 3159 } 3160 if (dip) 3161 mutex_exit(&(dip->devi_lock)); 3162 3163 /* 3164 * Now that we have dropped devi_lock, perform a second-pass to 3165 * add properties to the snapshot. We do this as a second pass 3166 * because we may need to call prop_op(9E) and we can't hold 3167 * devi_lock across that call. 3168 */ 3169 for (pl = pl0; pl; pl = pl0) { 3170 pl0 = pl->pl_next; 3171 off = di_getprop_add(list, 0, st, dip, prop_op, pl->pl_name, 3172 pl->pl_dev, pl->pl_flags, pl->pl_len, pl->pl_val, 3173 off, &off_p); 3174 if (pl->pl_val) 3175 kmem_free(pl->pl_val, pl->pl_len); 3176 if (pl->pl_name) 3177 kmem_free(pl->pl_name, strlen(pl->pl_name) + 1); 3178 kmem_free(pl, sizeof (*pl)); 3179 } 3180 3181 /* 3182 * If there is no prop_op or dynamic property support has been 3183 * disabled, we are done. 3184 */ 3185 if ((prop_op == NULL) || (di_prop_dyn == 0)) { 3186 *off_p = 0; 3187 return (off); 3188 } 3189 3190 /* Add dynamic driver properties to snapshot */ 3191 for (dp = i_ddi_prop_dyn_driver_get((dev_info_t *)dip); 3192 dp && dp->dp_name; dp++) { 3193 if (dp->dp_spec_type) { 3194 /* if spec_type, property of matching minor */ 3195 ASSERT(DEVI_BUSY_OWNED(dip)); 3196 for (mn = dip->devi_minor; mn; mn = mn->next) { 3197 if (mn->ddm_spec_type != dp->dp_spec_type) 3198 continue; 3199 off = di_getprop_add(list, 1, st, dip, prop_op, 3200 dp->dp_name, mn->ddm_dev, dp->dp_type, 3201 0, NULL, off, &off_p); 3202 } 3203 } else { 3204 /* property of devinfo node */ 3205 off = di_getprop_add(list, 1, st, dip, prop_op, 3206 dp->dp_name, DDI_DEV_T_NONE, dp->dp_type, 3207 0, NULL, off, &off_p); 3208 } 3209 } 3210 3211 /* Add dynamic parent properties to snapshot */ 3212 for (dp = i_ddi_prop_dyn_parent_get((dev_info_t *)dip); 3213 dp && dp->dp_name; dp++) { 3214 if (dp->dp_spec_type) { 3215 /* if spec_type, property of matching minor */ 3216 ASSERT(DEVI_BUSY_OWNED(dip)); 3217 for (mn = dip->devi_minor; mn; mn = mn->next) { 3218 if (mn->ddm_spec_type != dp->dp_spec_type) 3219 continue; 3220 off = di_getprop_add(list, 1, st, dip, prop_op, 3221 dp->dp_name, mn->ddm_dev, dp->dp_type, 3222 0, NULL, off, &off_p); 3223 } 3224 } else { 3225 /* property of devinfo node */ 3226 off = di_getprop_add(list, 1, st, dip, prop_op, 3227 dp->dp_name, DDI_DEV_T_NONE, dp->dp_type, 3228 0, NULL, off, &off_p); 3229 } 3230 } 3231 3232 *off_p = 0; 3233 return (off); 3234 } 3235 3236 /* 3237 * find private data format attached to a dip 3238 * parent = 1 to match driver name of parent dip (for parent private data) 3239 * 0 to match driver name of current dip (for driver private data) 3240 */ 3241 #define DI_MATCH_DRIVER 0 3242 #define DI_MATCH_PARENT 1 3243 3244 struct di_priv_format * 3245 di_match_drv_name(struct dev_info *node, struct di_state *st, int match) 3246 { 3247 int i, count, len; 3248 char *drv_name; 3249 major_t major; 3250 struct di_all *all; 3251 struct di_priv_format *form; 3252 3253 dcmn_err2((CE_CONT, "di_match_drv_name: node = %s, match = %x\n", 3254 node->devi_node_name, match)); 3255 3256 if (match == DI_MATCH_PARENT) { 3257 node = DEVI(node->devi_parent); 3258 } 3259 3260 if (node == NULL) { 3261 return (NULL); 3262 } 3263 3264 major = node->devi_major; 3265 if (major == (major_t)(-1)) { 3266 return (NULL); 3267 } 3268 3269 /* 3270 * Match the driver name. 3271 */ 3272 drv_name = ddi_major_to_name(major); 3273 if ((drv_name == NULL) || *drv_name == '\0') { 3274 return (NULL); 3275 } 3276 3277 /* Now get the di_priv_format array */ 3278 all = DI_ALL_PTR(st); 3279 if (match == DI_MATCH_PARENT) { 3280 count = all->n_ppdata; 3281 form = DI_PRIV_FORMAT(di_mem_addr(st, all->ppdata_format)); 3282 } else { 3283 count = all->n_dpdata; 3284 form = DI_PRIV_FORMAT(di_mem_addr(st, all->dpdata_format)); 3285 } 3286 3287 len = strlen(drv_name); 3288 for (i = 0; i < count; i++) { 3289 char *tmp; 3290 3291 tmp = form[i].drv_name; 3292 while (tmp && (*tmp != '\0')) { 3293 if (strncmp(drv_name, tmp, len) == 0) { 3294 return (&form[i]); 3295 } 3296 /* 3297 * Move to next driver name, skipping a white space 3298 */ 3299 if (tmp = strchr(tmp, ' ')) { 3300 tmp++; 3301 } 3302 } 3303 } 3304 3305 return (NULL); 3306 } 3307 3308 /* 3309 * The following functions copy data as specified by the format passed in. 3310 * To prevent invalid format from panicing the system, we call on_fault(). 3311 * A return value of 0 indicates an error. Otherwise, the total offset 3312 * is returned. 3313 */ 3314 #define DI_MAX_PRIVDATA (PAGESIZE >> 1) /* max private data size */ 3315 3316 static di_off_t 3317 di_getprvdata(struct di_priv_format *pdp, struct dev_info *node, 3318 void *data, di_off_t *off_p, struct di_state *st) 3319 { 3320 caddr_t pa; 3321 void *ptr; 3322 int i, size, repeat; 3323 di_off_t off, off0, *tmp; 3324 char *path; 3325 label_t ljb; 3326 3327 dcmn_err2((CE_CONT, "di_getprvdata:\n")); 3328 3329 /* 3330 * check memory availability. Private data size is 3331 * limited to DI_MAX_PRIVDATA. 3332 */ 3333 off = di_checkmem(st, *off_p, DI_MAX_PRIVDATA); 3334 *off_p = off; 3335 3336 if ((pdp->bytes == 0) || pdp->bytes > DI_MAX_PRIVDATA) { 3337 goto failure; 3338 } 3339 3340 if (!on_fault(&ljb)) { 3341 /* copy the struct */ 3342 bcopy(data, di_mem_addr(st, off), pdp->bytes); 3343 off0 = DI_ALIGN(pdp->bytes); /* XXX remove DI_ALIGN */ 3344 3345 /* dereferencing pointers */ 3346 for (i = 0; i < MAX_PTR_IN_PRV; i++) { 3347 3348 if (pdp->ptr[i].size == 0) { 3349 goto success; /* no more ptrs */ 3350 } 3351 3352 /* 3353 * first, get the pointer content 3354 */ 3355 if ((pdp->ptr[i].offset < 0) || 3356 (pdp->ptr[i].offset > pdp->bytes - sizeof (char *))) 3357 goto failure; /* wrong offset */ 3358 3359 pa = di_mem_addr(st, off + pdp->ptr[i].offset); 3360 3361 /* save a tmp ptr to store off_t later */ 3362 tmp = (di_off_t *)(intptr_t)pa; 3363 3364 /* get pointer value, if NULL continue */ 3365 ptr = *((void **) (intptr_t)pa); 3366 if (ptr == NULL) { 3367 continue; 3368 } 3369 3370 /* 3371 * next, find the repeat count (array dimension) 3372 */ 3373 repeat = pdp->ptr[i].len_offset; 3374 3375 /* 3376 * Positive value indicates a fixed sized array. 3377 * 0 or negative value indicates variable sized array. 3378 * 3379 * For variable sized array, the variable must be 3380 * an int member of the structure, with an offset 3381 * equal to the absolution value of struct member. 3382 */ 3383 if (repeat > pdp->bytes - sizeof (int)) { 3384 goto failure; /* wrong offset */ 3385 } 3386 3387 if (repeat >= 0) { 3388 repeat = *((int *) 3389 (intptr_t)((caddr_t)data + repeat)); 3390 } else { 3391 repeat = -repeat; 3392 } 3393 3394 /* 3395 * next, get the size of the object to be copied 3396 */ 3397 size = pdp->ptr[i].size * repeat; 3398 3399 /* 3400 * Arbitrarily limit the total size of object to be 3401 * copied (1 byte to 1/4 page). 3402 */ 3403 if ((size <= 0) || (size > (DI_MAX_PRIVDATA - off0))) { 3404 goto failure; /* wrong size or too big */ 3405 } 3406 3407 /* 3408 * Now copy the data 3409 */ 3410 *tmp = off0; 3411 bcopy(ptr, di_mem_addr(st, off + off0), size); 3412 off0 += DI_ALIGN(size); /* XXX remove DI_ALIGN */ 3413 } 3414 } else { 3415 goto failure; 3416 } 3417 3418 success: 3419 /* 3420 * success if reached here 3421 */ 3422 no_fault(); 3423 return (off + off0); 3424 /*NOTREACHED*/ 3425 3426 failure: 3427 /* 3428 * fault occurred 3429 */ 3430 no_fault(); 3431 path = kmem_alloc(MAXPATHLEN, KM_SLEEP); 3432 cmn_err(CE_WARN, "devinfo: fault on private data for '%s' at %p", 3433 ddi_pathname((dev_info_t *)node, path), data); 3434 kmem_free(path, MAXPATHLEN); 3435 *off_p = -1; /* set private data to indicate error */ 3436 3437 return (off); 3438 } 3439 3440 /* 3441 * get parent private data; on error, returns original offset 3442 */ 3443 static di_off_t 3444 di_getppdata(struct dev_info *node, di_off_t *off_p, struct di_state *st) 3445 { 3446 int off; 3447 struct di_priv_format *ppdp; 3448 3449 dcmn_err2((CE_CONT, "di_getppdata:\n")); 3450 3451 /* find the parent data format */ 3452 if ((ppdp = di_match_drv_name(node, st, DI_MATCH_PARENT)) == NULL) { 3453 off = *off_p; 3454 *off_p = 0; /* set parent data to none */ 3455 return (off); 3456 } 3457 3458 return (di_getprvdata(ppdp, node, 3459 ddi_get_parent_data((dev_info_t *)node), off_p, st)); 3460 } 3461 3462 /* 3463 * get parent private data; returns original offset 3464 */ 3465 static di_off_t 3466 di_getdpdata(struct dev_info *node, di_off_t *off_p, struct di_state *st) 3467 { 3468 int off; 3469 struct di_priv_format *dpdp; 3470 3471 dcmn_err2((CE_CONT, "di_getdpdata:")); 3472 3473 /* find the parent data format */ 3474 if ((dpdp = di_match_drv_name(node, st, DI_MATCH_DRIVER)) == NULL) { 3475 off = *off_p; 3476 *off_p = 0; /* set driver data to none */ 3477 return (off); 3478 } 3479 3480 return (di_getprvdata(dpdp, node, 3481 ddi_get_driver_private((dev_info_t *)node), off_p, st)); 3482 } 3483 3484 /* 3485 * Copy hotplug data associated with a devinfo node into the snapshot. 3486 */ 3487 static di_off_t 3488 di_gethpdata(ddi_hp_cn_handle_t *hp_hdl, di_off_t *off_p, 3489 struct di_state *st) 3490 { 3491 struct i_hp *hp; 3492 struct di_hp *me; 3493 size_t size; 3494 di_off_t off; 3495 3496 dcmn_err2((CE_CONT, "di_gethpdata:\n")); 3497 3498 /* 3499 * check memory first 3500 */ 3501 off = di_checkmem(st, *off_p, sizeof (struct di_hp)); 3502 *off_p = off; 3503 3504 do { 3505 me = DI_HP(di_mem_addr(st, off)); 3506 me->self = off; 3507 me->hp_name = 0; 3508 me->hp_connection = (int)hp_hdl->cn_info.cn_num; 3509 me->hp_depends_on = (int)hp_hdl->cn_info.cn_num_dpd_on; 3510 (void) ddihp_cn_getstate(hp_hdl); 3511 me->hp_state = (int)hp_hdl->cn_info.cn_state; 3512 me->hp_type = (int)hp_hdl->cn_info.cn_type; 3513 me->hp_type_str = 0; 3514 me->hp_last_change = (uint32_t)hp_hdl->cn_info.cn_last_change; 3515 me->hp_child = 0; 3516 3517 /* 3518 * Child links are resolved later by di_hotplug_children(). 3519 * Store a reference to this di_hp_t in the list used later 3520 * by di_hotplug_children(). 3521 */ 3522 hp = kmem_zalloc(sizeof (i_hp_t), KM_SLEEP); 3523 hp->hp_off = off; 3524 hp->hp_child = hp_hdl->cn_info.cn_child; 3525 list_insert_tail(&st->hp_list, hp); 3526 3527 off += sizeof (struct di_hp); 3528 3529 /* Add name of this di_hp_t to the snapshot */ 3530 if (hp_hdl->cn_info.cn_name) { 3531 size = strlen(hp_hdl->cn_info.cn_name) + 1; 3532 me->hp_name = off = di_checkmem(st, off, size); 3533 (void) strcpy(di_mem_addr(st, off), 3534 hp_hdl->cn_info.cn_name); 3535 off += size; 3536 } 3537 3538 /* Add type description of this di_hp_t to the snapshot */ 3539 if (hp_hdl->cn_info.cn_type_str) { 3540 size = strlen(hp_hdl->cn_info.cn_type_str) + 1; 3541 me->hp_type_str = off = di_checkmem(st, off, size); 3542 (void) strcpy(di_mem_addr(st, off), 3543 hp_hdl->cn_info.cn_type_str); 3544 off += size; 3545 } 3546 3547 /* 3548 * Set link to next in the chain of di_hp_t nodes, 3549 * or terminate the chain when processing the last node. 3550 */ 3551 if (hp_hdl->next != NULL) { 3552 off = di_checkmem(st, off, sizeof (struct di_hp)); 3553 me->next = off; 3554 } else { 3555 me->next = 0; 3556 } 3557 3558 /* Update pointer to next in the chain */ 3559 hp_hdl = hp_hdl->next; 3560 3561 } while (hp_hdl); 3562 3563 return (off); 3564 } 3565 3566 /* 3567 * The driver is stateful across DINFOCPYALL and DINFOUSRLD. 3568 * This function encapsulates the state machine: 3569 * 3570 * -> IOC_IDLE -> IOC_SNAP -> IOC_DONE -> IOC_COPY -> 3571 * | SNAPSHOT USRLD | 3572 * -------------------------------------------------- 3573 * 3574 * Returns 0 on success and -1 on failure 3575 */ 3576 static int 3577 di_setstate(struct di_state *st, int new_state) 3578 { 3579 int ret = 0; 3580 3581 mutex_enter(&di_lock); 3582 switch (new_state) { 3583 case IOC_IDLE: 3584 case IOC_DONE: 3585 break; 3586 case IOC_SNAP: 3587 if (st->di_iocstate != IOC_IDLE) 3588 ret = -1; 3589 break; 3590 case IOC_COPY: 3591 if (st->di_iocstate != IOC_DONE) 3592 ret = -1; 3593 break; 3594 default: 3595 ret = -1; 3596 } 3597 3598 if (ret == 0) 3599 st->di_iocstate = new_state; 3600 else 3601 cmn_err(CE_NOTE, "incorrect state transition from %d to %d", 3602 st->di_iocstate, new_state); 3603 mutex_exit(&di_lock); 3604 return (ret); 3605 } 3606 3607 /* 3608 * We cannot assume the presence of the entire 3609 * snapshot in this routine. All we are guaranteed 3610 * is the di_all struct + 1 byte (for root_path) 3611 */ 3612 static int 3613 header_plus_one_ok(struct di_all *all) 3614 { 3615 /* 3616 * Refuse to read old versions 3617 */ 3618 if (all->version != DI_SNAPSHOT_VERSION) { 3619 CACHE_DEBUG((DI_ERR, "bad version: 0x%x", all->version)); 3620 return (0); 3621 } 3622 3623 if (all->cache_magic != DI_CACHE_MAGIC) { 3624 CACHE_DEBUG((DI_ERR, "bad magic #: 0x%x", all->cache_magic)); 3625 return (0); 3626 } 3627 3628 if (all->snapshot_time == 0) { 3629 CACHE_DEBUG((DI_ERR, "bad timestamp: %ld", all->snapshot_time)); 3630 return (0); 3631 } 3632 3633 if (all->top_devinfo == 0) { 3634 CACHE_DEBUG((DI_ERR, "NULL top devinfo")); 3635 return (0); 3636 } 3637 3638 if (all->map_size < sizeof (*all) + 1) { 3639 CACHE_DEBUG((DI_ERR, "bad map size: %u", all->map_size)); 3640 return (0); 3641 } 3642 3643 if (all->root_path[0] != '/' || all->root_path[1] != '\0') { 3644 CACHE_DEBUG((DI_ERR, "bad rootpath: %c%c", 3645 all->root_path[0], all->root_path[1])); 3646 return (0); 3647 } 3648 3649 /* 3650 * We can't check checksum here as we just have the header 3651 */ 3652 3653 return (1); 3654 } 3655 3656 static int 3657 chunk_write(struct vnode *vp, offset_t off, caddr_t buf, size_t len) 3658 { 3659 rlim64_t rlimit; 3660 ssize_t resid; 3661 int error = 0; 3662 3663 3664 rlimit = RLIM64_INFINITY; 3665 3666 while (len) { 3667 resid = 0; 3668 error = vn_rdwr(UIO_WRITE, vp, buf, len, off, 3669 UIO_SYSSPACE, FSYNC, rlimit, kcred, &resid); 3670 3671 if (error || resid < 0) { 3672 error = error ? error : EIO; 3673 CACHE_DEBUG((DI_ERR, "write error: %d", error)); 3674 break; 3675 } 3676 3677 /* 3678 * Check if we are making progress 3679 */ 3680 if (resid >= len) { 3681 error = ENOSPC; 3682 break; 3683 } 3684 buf += len - resid; 3685 off += len - resid; 3686 len = resid; 3687 } 3688 3689 return (error); 3690 } 3691 3692 static void 3693 di_cache_write(struct di_cache *cache) 3694 { 3695 struct di_all *all; 3696 struct vnode *vp; 3697 int oflags; 3698 size_t map_size; 3699 size_t chunk; 3700 offset_t off; 3701 int error; 3702 char *buf; 3703 3704 ASSERT(DI_CACHE_LOCKED(*cache)); 3705 ASSERT(!servicing_interrupt()); 3706 3707 if (cache->cache_size == 0) { 3708 ASSERT(cache->cache_data == NULL); 3709 CACHE_DEBUG((DI_ERR, "Empty cache. Skipping write")); 3710 return; 3711 } 3712 3713 ASSERT(cache->cache_size > 0); 3714 ASSERT(cache->cache_data); 3715 3716 if (!modrootloaded || rootvp == NULL || vn_is_readonly(rootvp)) { 3717 CACHE_DEBUG((DI_ERR, "Can't write to rootFS. Skipping write")); 3718 return; 3719 } 3720 3721 all = (struct di_all *)cache->cache_data; 3722 3723 if (!header_plus_one_ok(all)) { 3724 CACHE_DEBUG((DI_ERR, "Invalid header. Skipping write")); 3725 return; 3726 } 3727 3728 ASSERT(strcmp(all->root_path, "/") == 0); 3729 3730 /* 3731 * The cache_size is the total allocated memory for the cache. 3732 * The map_size is the actual size of valid data in the cache. 3733 * map_size may be smaller than cache_size but cannot exceed 3734 * cache_size. 3735 */ 3736 if (all->map_size > cache->cache_size) { 3737 CACHE_DEBUG((DI_ERR, "map_size (0x%x) > cache_size (0x%x)." 3738 " Skipping write", all->map_size, cache->cache_size)); 3739 return; 3740 } 3741 3742 /* 3743 * First unlink the temp file 3744 */ 3745 error = vn_remove(DI_CACHE_TEMP, UIO_SYSSPACE, RMFILE); 3746 if (error && error != ENOENT) { 3747 CACHE_DEBUG((DI_ERR, "%s: unlink failed: %d", 3748 DI_CACHE_TEMP, error)); 3749 } 3750 3751 if (error == EROFS) { 3752 CACHE_DEBUG((DI_ERR, "RDONLY FS. Skipping write")); 3753 return; 3754 } 3755 3756 vp = NULL; 3757 oflags = (FCREAT|FWRITE); 3758 if (error = vn_open(DI_CACHE_TEMP, UIO_SYSSPACE, oflags, 3759 DI_CACHE_PERMS, &vp, CRCREAT, 0)) { 3760 CACHE_DEBUG((DI_ERR, "%s: create failed: %d", 3761 DI_CACHE_TEMP, error)); 3762 return; 3763 } 3764 3765 ASSERT(vp); 3766 3767 /* 3768 * Paranoid: Check if the file is on a read-only FS 3769 */ 3770 if (vn_is_readonly(vp)) { 3771 CACHE_DEBUG((DI_ERR, "cannot write: readonly FS")); 3772 goto fail; 3773 } 3774 3775 /* 3776 * Note that we only write map_size bytes to disk - this saves 3777 * space as the actual cache size may be larger than size of 3778 * valid data in the cache. 3779 * Another advantage is that it makes verification of size 3780 * easier when the file is read later. 3781 */ 3782 map_size = all->map_size; 3783 off = 0; 3784 buf = cache->cache_data; 3785 3786 while (map_size) { 3787 ASSERT(map_size > 0); 3788 /* 3789 * Write in chunks so that VM system 3790 * is not overwhelmed 3791 */ 3792 if (map_size > di_chunk * PAGESIZE) 3793 chunk = di_chunk * PAGESIZE; 3794 else 3795 chunk = map_size; 3796 3797 error = chunk_write(vp, off, buf, chunk); 3798 if (error) { 3799 CACHE_DEBUG((DI_ERR, "write failed: off=0x%x: %d", 3800 off, error)); 3801 goto fail; 3802 } 3803 3804 off += chunk; 3805 buf += chunk; 3806 map_size -= chunk; 3807 3808 /* If low on memory, give pageout a chance to run */ 3809 if (freemem < desfree) 3810 delay(1); 3811 } 3812 3813 /* 3814 * Now sync the file and close it 3815 */ 3816 if (error = VOP_FSYNC(vp, FSYNC, kcred, NULL)) { 3817 CACHE_DEBUG((DI_ERR, "FSYNC failed: %d", error)); 3818 } 3819 3820 if (error = VOP_CLOSE(vp, oflags, 1, (offset_t)0, kcred, NULL)) { 3821 CACHE_DEBUG((DI_ERR, "close() failed: %d", error)); 3822 VN_RELE(vp); 3823 return; 3824 } 3825 3826 VN_RELE(vp); 3827 3828 /* 3829 * Now do the rename 3830 */ 3831 if (error = vn_rename(DI_CACHE_TEMP, DI_CACHE_FILE, UIO_SYSSPACE)) { 3832 CACHE_DEBUG((DI_ERR, "rename failed: %d", error)); 3833 return; 3834 } 3835 3836 CACHE_DEBUG((DI_INFO, "Cache write successful.")); 3837 3838 return; 3839 3840 fail: 3841 (void) VOP_CLOSE(vp, oflags, 1, (offset_t)0, kcred, NULL); 3842 VN_RELE(vp); 3843 } 3844 3845 3846 /* 3847 * Since we could be called early in boot, 3848 * use kobj_read_file() 3849 */ 3850 static void 3851 di_cache_read(struct di_cache *cache) 3852 { 3853 struct _buf *file; 3854 struct di_all *all; 3855 int n; 3856 size_t map_size, sz, chunk; 3857 offset_t off; 3858 caddr_t buf; 3859 uint32_t saved_crc, crc; 3860 3861 ASSERT(modrootloaded); 3862 ASSERT(DI_CACHE_LOCKED(*cache)); 3863 ASSERT(cache->cache_data == NULL); 3864 ASSERT(cache->cache_size == 0); 3865 ASSERT(!servicing_interrupt()); 3866 3867 file = kobj_open_file(DI_CACHE_FILE); 3868 if (file == (struct _buf *)-1) { 3869 CACHE_DEBUG((DI_ERR, "%s: open failed: %d", 3870 DI_CACHE_FILE, ENOENT)); 3871 return; 3872 } 3873 3874 /* 3875 * Read in the header+root_path first. The root_path must be "/" 3876 */ 3877 all = kmem_zalloc(sizeof (*all) + 1, KM_SLEEP); 3878 n = kobj_read_file(file, (caddr_t)all, sizeof (*all) + 1, 0); 3879 3880 if ((n != sizeof (*all) + 1) || !header_plus_one_ok(all)) { 3881 kmem_free(all, sizeof (*all) + 1); 3882 kobj_close_file(file); 3883 CACHE_DEBUG((DI_ERR, "cache header: read error or invalid")); 3884 return; 3885 } 3886 3887 map_size = all->map_size; 3888 3889 kmem_free(all, sizeof (*all) + 1); 3890 3891 ASSERT(map_size >= sizeof (*all) + 1); 3892 3893 buf = di_cache.cache_data = kmem_alloc(map_size, KM_SLEEP); 3894 sz = map_size; 3895 off = 0; 3896 while (sz) { 3897 /* Don't overload VM with large reads */ 3898 chunk = (sz > di_chunk * PAGESIZE) ? di_chunk * PAGESIZE : sz; 3899 n = kobj_read_file(file, buf, chunk, off); 3900 if (n != chunk) { 3901 CACHE_DEBUG((DI_ERR, "%s: read error at offset: %lld", 3902 DI_CACHE_FILE, off)); 3903 goto fail; 3904 } 3905 off += chunk; 3906 buf += chunk; 3907 sz -= chunk; 3908 } 3909 3910 ASSERT(off == map_size); 3911 3912 /* 3913 * Read past expected EOF to verify size. 3914 */ 3915 if (kobj_read_file(file, (caddr_t)&sz, 1, off) > 0) { 3916 CACHE_DEBUG((DI_ERR, "%s: file size changed", DI_CACHE_FILE)); 3917 goto fail; 3918 } 3919 3920 all = (struct di_all *)di_cache.cache_data; 3921 if (!header_plus_one_ok(all)) { 3922 CACHE_DEBUG((DI_ERR, "%s: file header changed", DI_CACHE_FILE)); 3923 goto fail; 3924 } 3925 3926 /* 3927 * Compute CRC with checksum field in the cache data set to 0 3928 */ 3929 saved_crc = all->cache_checksum; 3930 all->cache_checksum = 0; 3931 CRC32(crc, di_cache.cache_data, map_size, -1U, crc32_table); 3932 all->cache_checksum = saved_crc; 3933 3934 if (crc != all->cache_checksum) { 3935 CACHE_DEBUG((DI_ERR, 3936 "%s: checksum error: expected=0x%x actual=0x%x", 3937 DI_CACHE_FILE, all->cache_checksum, crc)); 3938 goto fail; 3939 } 3940 3941 if (all->map_size != map_size) { 3942 CACHE_DEBUG((DI_ERR, "%s: map size changed", DI_CACHE_FILE)); 3943 goto fail; 3944 } 3945 3946 kobj_close_file(file); 3947 3948 di_cache.cache_size = map_size; 3949 3950 return; 3951 3952 fail: 3953 kmem_free(di_cache.cache_data, map_size); 3954 kobj_close_file(file); 3955 di_cache.cache_data = NULL; 3956 di_cache.cache_size = 0; 3957 } 3958 3959 3960 /* 3961 * Checks if arguments are valid for using the cache. 3962 */ 3963 static int 3964 cache_args_valid(struct di_state *st, int *error) 3965 { 3966 ASSERT(error); 3967 ASSERT(st->mem_size > 0); 3968 ASSERT(st->memlist != NULL); 3969 3970 if (!modrootloaded || !i_ddi_io_initialized()) { 3971 CACHE_DEBUG((DI_ERR, 3972 "cache lookup failure: I/O subsystem not inited")); 3973 *error = ENOTACTIVE; 3974 return (0); 3975 } 3976 3977 /* 3978 * No other flags allowed with DINFOCACHE 3979 */ 3980 if (st->command != (DINFOCACHE & DIIOC_MASK)) { 3981 CACHE_DEBUG((DI_ERR, 3982 "cache lookup failure: bad flags: 0x%x", 3983 st->command)); 3984 *error = EINVAL; 3985 return (0); 3986 } 3987 3988 if (strcmp(DI_ALL_PTR(st)->root_path, "/") != 0) { 3989 CACHE_DEBUG((DI_ERR, 3990 "cache lookup failure: bad root: %s", 3991 DI_ALL_PTR(st)->root_path)); 3992 *error = EINVAL; 3993 return (0); 3994 } 3995 3996 CACHE_DEBUG((DI_INFO, "cache lookup args ok: 0x%x", st->command)); 3997 3998 *error = 0; 3999 4000 return (1); 4001 } 4002 4003 static int 4004 snapshot_is_cacheable(struct di_state *st) 4005 { 4006 ASSERT(st->mem_size > 0); 4007 ASSERT(st->memlist != NULL); 4008 4009 if ((st->command & DI_CACHE_SNAPSHOT_FLAGS) != 4010 (DI_CACHE_SNAPSHOT_FLAGS & DIIOC_MASK)) { 4011 CACHE_DEBUG((DI_INFO, 4012 "not cacheable: incompatible flags: 0x%x", 4013 st->command)); 4014 return (0); 4015 } 4016 4017 if (strcmp(DI_ALL_PTR(st)->root_path, "/") != 0) { 4018 CACHE_DEBUG((DI_INFO, 4019 "not cacheable: incompatible root path: %s", 4020 DI_ALL_PTR(st)->root_path)); 4021 return (0); 4022 } 4023 4024 CACHE_DEBUG((DI_INFO, "cacheable snapshot request: 0x%x", st->command)); 4025 4026 return (1); 4027 } 4028 4029 static int 4030 di_cache_lookup(struct di_state *st) 4031 { 4032 size_t rval; 4033 int cache_valid; 4034 4035 ASSERT(cache_args_valid(st, &cache_valid)); 4036 ASSERT(modrootloaded); 4037 4038 DI_CACHE_LOCK(di_cache); 4039 4040 /* 4041 * The following assignment determines the validity 4042 * of the cache as far as this snapshot is concerned. 4043 */ 4044 cache_valid = di_cache.cache_valid; 4045 4046 if (cache_valid && di_cache.cache_data == NULL) { 4047 di_cache_read(&di_cache); 4048 /* check for read or file error */ 4049 if (di_cache.cache_data == NULL) 4050 cache_valid = 0; 4051 } 4052 4053 if (cache_valid) { 4054 /* 4055 * Ok, the cache was valid as of this particular 4056 * snapshot. Copy the cached snapshot. This is safe 4057 * to do as the cache cannot be freed (we hold the 4058 * cache lock). Free the memory allocated in di_state 4059 * up until this point - we will simply copy everything 4060 * in the cache. 4061 */ 4062 4063 ASSERT(di_cache.cache_data != NULL); 4064 ASSERT(di_cache.cache_size > 0); 4065 4066 di_freemem(st); 4067 4068 rval = 0; 4069 if (di_cache2mem(&di_cache, st) > 0) { 4070 /* 4071 * map_size is size of valid data in the 4072 * cached snapshot and may be less than 4073 * size of the cache. 4074 */ 4075 ASSERT(DI_ALL_PTR(st)); 4076 rval = DI_ALL_PTR(st)->map_size; 4077 4078 ASSERT(rval >= sizeof (struct di_all)); 4079 ASSERT(rval <= di_cache.cache_size); 4080 } 4081 } else { 4082 /* 4083 * The cache isn't valid, we need to take a snapshot. 4084 * Set the command flags appropriately 4085 */ 4086 ASSERT(st->command == (DINFOCACHE & DIIOC_MASK)); 4087 st->command = (DI_CACHE_SNAPSHOT_FLAGS & DIIOC_MASK); 4088 rval = di_cache_update(st); 4089 st->command = (DINFOCACHE & DIIOC_MASK); 4090 } 4091 4092 DI_CACHE_UNLOCK(di_cache); 4093 4094 /* 4095 * For cached snapshots, the devinfo driver always returns 4096 * a snapshot rooted at "/". 4097 */ 4098 ASSERT(rval == 0 || strcmp(DI_ALL_PTR(st)->root_path, "/") == 0); 4099 4100 return ((int)rval); 4101 } 4102 4103 /* 4104 * This is a forced update of the cache - the previous state of the cache 4105 * may be: 4106 * - unpopulated 4107 * - populated and invalid 4108 * - populated and valid 4109 */ 4110 static int 4111 di_cache_update(struct di_state *st) 4112 { 4113 int rval; 4114 uint32_t crc; 4115 struct di_all *all; 4116 4117 ASSERT(DI_CACHE_LOCKED(di_cache)); 4118 ASSERT(snapshot_is_cacheable(st)); 4119 4120 /* 4121 * Free the in-core cache and the on-disk file (if they exist) 4122 */ 4123 i_ddi_di_cache_free(&di_cache); 4124 4125 /* 4126 * Set valid flag before taking the snapshot, 4127 * so that any invalidations that arrive 4128 * during or after the snapshot are not 4129 * removed by us. 4130 */ 4131 atomic_or_32(&di_cache.cache_valid, 1); 4132 4133 rval = di_snapshot_and_clean(st); 4134 4135 if (rval == 0) { 4136 CACHE_DEBUG((DI_ERR, "can't update cache: bad snapshot")); 4137 return (0); 4138 } 4139 4140 DI_ALL_PTR(st)->map_size = rval; 4141 if (di_mem2cache(st, &di_cache) == 0) { 4142 CACHE_DEBUG((DI_ERR, "can't update cache: copy failed")); 4143 return (0); 4144 } 4145 4146 ASSERT(di_cache.cache_data); 4147 ASSERT(di_cache.cache_size > 0); 4148 4149 /* 4150 * Now that we have cached the snapshot, compute its checksum. 4151 * The checksum is only computed over the valid data in the 4152 * cache, not the entire cache. 4153 * Also, set all the fields (except checksum) before computing 4154 * checksum. 4155 */ 4156 all = (struct di_all *)di_cache.cache_data; 4157 all->cache_magic = DI_CACHE_MAGIC; 4158 all->map_size = rval; 4159 4160 ASSERT(all->cache_checksum == 0); 4161 CRC32(crc, di_cache.cache_data, all->map_size, -1U, crc32_table); 4162 all->cache_checksum = crc; 4163 4164 di_cache_write(&di_cache); 4165 4166 return (rval); 4167 } 4168 4169 static void 4170 di_cache_print(di_cache_debug_t msglevel, char *fmt, ...) 4171 { 4172 va_list ap; 4173 4174 if (di_cache_debug <= DI_QUIET) 4175 return; 4176 4177 if (di_cache_debug < msglevel) 4178 return; 4179 4180 switch (msglevel) { 4181 case DI_ERR: 4182 msglevel = CE_WARN; 4183 break; 4184 case DI_INFO: 4185 case DI_TRACE: 4186 default: 4187 msglevel = CE_NOTE; 4188 break; 4189 } 4190 4191 va_start(ap, fmt); 4192 vcmn_err(msglevel, fmt, ap); 4193 va_end(ap); 4194 } 4195 4196 static void 4197 di_hotplug_children(struct di_state *st) 4198 { 4199 di_off_t off; 4200 struct di_hp *hp; 4201 struct i_hp *hp_list_node; 4202 4203 while (hp_list_node = (struct i_hp *)list_remove_head(&st->hp_list)) { 4204 4205 if ((hp_list_node->hp_child != NULL) && 4206 (di_dip_find(st, hp_list_node->hp_child, &off) == 0)) { 4207 hp = DI_HP(di_mem_addr(st, hp_list_node->hp_off)); 4208 hp->hp_child = off; 4209 } 4210 4211 kmem_free(hp_list_node, sizeof (i_hp_t)); 4212 } 4213 4214 list_destroy(&st->hp_list); 4215 } 4216