1*26947304SEvan Yan /* 2*26947304SEvan Yan * CDDL HEADER START 3*26947304SEvan Yan * 4*26947304SEvan Yan * The contents of this file are subject to the terms of the 5*26947304SEvan Yan * Common Development and Distribution License (the "License"). 6*26947304SEvan Yan * You may not use this file except in compliance with the License. 7*26947304SEvan Yan * 8*26947304SEvan Yan * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*26947304SEvan Yan * or http://www.opensolaris.org/os/licensing. 10*26947304SEvan Yan * See the License for the specific language governing permissions 11*26947304SEvan Yan * and limitations under the License. 12*26947304SEvan Yan * 13*26947304SEvan Yan * When distributing Covered Code, include this CDDL HEADER in each 14*26947304SEvan Yan * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*26947304SEvan Yan * If applicable, add the following below this CDDL HEADER, with the 16*26947304SEvan Yan * fields enclosed by brackets "[]" replaced with your own identifying 17*26947304SEvan Yan * information: Portions Copyright [yyyy] [name of copyright owner] 18*26947304SEvan Yan * 19*26947304SEvan Yan * CDDL HEADER END 20*26947304SEvan Yan */ 21*26947304SEvan Yan /* 22*26947304SEvan Yan * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23*26947304SEvan Yan * Use is subject to license terms. 24*26947304SEvan Yan */ 25*26947304SEvan Yan 26*26947304SEvan Yan #include <stdio.h> 27*26947304SEvan Yan #include <stdlib.h> 28*26947304SEvan Yan #include <string.h> 29*26947304SEvan Yan #include <errno.h> 30*26947304SEvan Yan #include <libdevinfo.h> 31*26947304SEvan Yan #include <libhotplug.h> 32*26947304SEvan Yan #include <libhotplug_impl.h> 33*26947304SEvan Yan #include <sys/sunddi.h> 34*26947304SEvan Yan #include <sys/ddi_hp.h> 35*26947304SEvan Yan #include "hotplugd_impl.h" 36*26947304SEvan Yan 37*26947304SEvan Yan /* 38*26947304SEvan Yan * Define a list of hotplug nodes. 39*26947304SEvan Yan * (Only used within this module.) 40*26947304SEvan Yan */ 41*26947304SEvan Yan typedef struct { 42*26947304SEvan Yan hp_node_t head; 43*26947304SEvan Yan hp_node_t prev; 44*26947304SEvan Yan } hp_node_list_t; 45*26947304SEvan Yan 46*26947304SEvan Yan /* 47*26947304SEvan Yan * Local functions. 48*26947304SEvan Yan */ 49*26947304SEvan Yan static int copy_devinfo(const char *, const char *, uint_t, 50*26947304SEvan Yan hp_node_t *); 51*26947304SEvan Yan static int copy_devices(hp_node_t, di_node_t, uint_t, hp_node_t *); 52*26947304SEvan Yan static int copy_hotplug(hp_node_t, di_node_t, const char *, uint_t, 53*26947304SEvan Yan hp_node_t *); 54*26947304SEvan Yan static char *base_path(const char *); 55*26947304SEvan Yan static int search_cb(di_node_t, void *); 56*26947304SEvan Yan static int check_search(di_node_t, uint_t); 57*26947304SEvan Yan static hp_node_t new_device_node(hp_node_t, di_node_t); 58*26947304SEvan Yan static hp_node_t new_hotplug_node(hp_node_t, di_hp_t); 59*26947304SEvan Yan static void node_list_add(hp_node_list_t *, hp_node_t); 60*26947304SEvan Yan 61*26947304SEvan Yan /* 62*26947304SEvan Yan * getinfo() 63*26947304SEvan Yan * 64*26947304SEvan Yan * Build a hotplug information snapshot. The path, connection, 65*26947304SEvan Yan * and flags indicate what information should be included. 66*26947304SEvan Yan */ 67*26947304SEvan Yan int 68*26947304SEvan Yan getinfo(const char *path, const char *connection, uint_t flags, hp_node_t *retp) 69*26947304SEvan Yan { 70*26947304SEvan Yan hp_node_t root = NULL; 71*26947304SEvan Yan hp_node_t child; 72*26947304SEvan Yan char *basepath; 73*26947304SEvan Yan int rv; 74*26947304SEvan Yan 75*26947304SEvan Yan if ((path == NULL) || (retp == NULL)) 76*26947304SEvan Yan return (EINVAL); 77*26947304SEvan Yan 78*26947304SEvan Yan dprintf("getinfo: path=%s, connection=%s, flags=0x%x\n", path, 79*26947304SEvan Yan (connection == NULL) ? "NULL" : connection, flags); 80*26947304SEvan Yan 81*26947304SEvan Yan /* Allocate the base path */ 82*26947304SEvan Yan if ((basepath = base_path(path)) == NULL) 83*26947304SEvan Yan return (ENOMEM); 84*26947304SEvan Yan 85*26947304SEvan Yan /* Copy in device and hotplug nodes from libdevinfo */ 86*26947304SEvan Yan if ((rv = copy_devinfo(basepath, connection, flags, &root)) != 0) { 87*26947304SEvan Yan hp_fini(root); 88*26947304SEvan Yan free(basepath); 89*26947304SEvan Yan return (rv); 90*26947304SEvan Yan } 91*26947304SEvan Yan 92*26947304SEvan Yan /* Check if there were no connections */ 93*26947304SEvan Yan if (root == NULL) { 94*26947304SEvan Yan dprintf("getinfo: no hotplug connections.\n"); 95*26947304SEvan Yan free(basepath); 96*26947304SEvan Yan return (ENOENT); 97*26947304SEvan Yan } 98*26947304SEvan Yan 99*26947304SEvan Yan /* Special case: exclude root nexus from snapshot */ 100*26947304SEvan Yan if (strcmp(basepath, "/") == 0) { 101*26947304SEvan Yan child = root->hp_child; 102*26947304SEvan Yan if (root->hp_name != NULL) 103*26947304SEvan Yan free(root->hp_name); 104*26947304SEvan Yan free(root); 105*26947304SEvan Yan root = child; 106*26947304SEvan Yan for (child = root; child; child = child->hp_sibling) 107*26947304SEvan Yan child->hp_parent = NULL; 108*26947304SEvan Yan } 109*26947304SEvan Yan 110*26947304SEvan Yan /* Store a pointer to the base path in each root node */ 111*26947304SEvan Yan for (child = root; child != NULL; child = child->hp_sibling) 112*26947304SEvan Yan child->hp_basepath = basepath; 113*26947304SEvan Yan 114*26947304SEvan Yan /* Copy in usage information from RCM */ 115*26947304SEvan Yan if (flags & HPINFOUSAGE) { 116*26947304SEvan Yan if ((rv = copy_usage(root)) != 0) { 117*26947304SEvan Yan (void) hp_fini(root); 118*26947304SEvan Yan return (rv); 119*26947304SEvan Yan } 120*26947304SEvan Yan } 121*26947304SEvan Yan 122*26947304SEvan Yan *retp = root; 123*26947304SEvan Yan return (0); 124*26947304SEvan Yan } 125*26947304SEvan Yan 126*26947304SEvan Yan /* 127*26947304SEvan Yan * copy_devinfo() 128*26947304SEvan Yan * 129*26947304SEvan Yan * Copy information about device and hotplug nodes from libdevinfo. 130*26947304SEvan Yan * 131*26947304SEvan Yan * When path is set to "/", the results need to be limited only to 132*26947304SEvan Yan * branches that contain hotplug information. An initial search 133*26947304SEvan Yan * is performed to mark which branches contain hotplug nodes. 134*26947304SEvan Yan */ 135*26947304SEvan Yan static int 136*26947304SEvan Yan copy_devinfo(const char *path, const char *connection, uint_t flags, 137*26947304SEvan Yan hp_node_t *rootp) 138*26947304SEvan Yan { 139*26947304SEvan Yan hp_node_t hp_root = NULL; 140*26947304SEvan Yan di_node_t di_root; 141*26947304SEvan Yan int rv; 142*26947304SEvan Yan 143*26947304SEvan Yan /* Get libdevinfo snapshot */ 144*26947304SEvan Yan if ((di_root = di_init(path, DINFOSUBTREE | DINFOHP)) == DI_NODE_NIL) 145*26947304SEvan Yan return (errno); 146*26947304SEvan Yan 147*26947304SEvan Yan /* Do initial search pass, if required */ 148*26947304SEvan Yan if (strcmp(path, "/") == 0) { 149*26947304SEvan Yan flags |= HPINFOSEARCH; 150*26947304SEvan Yan (void) di_walk_node(di_root, DI_WALK_CLDFIRST, NULL, search_cb); 151*26947304SEvan Yan } 152*26947304SEvan Yan 153*26947304SEvan Yan /* 154*26947304SEvan Yan * If a connection is specified, just copy immediate hotplug info. 155*26947304SEvan Yan * Else, copy the device tree normally. 156*26947304SEvan Yan */ 157*26947304SEvan Yan if (connection != NULL) 158*26947304SEvan Yan rv = copy_hotplug(NULL, di_root, connection, flags, &hp_root); 159*26947304SEvan Yan else 160*26947304SEvan Yan rv = copy_devices(NULL, di_root, flags, &hp_root); 161*26947304SEvan Yan 162*26947304SEvan Yan /* Destroy devinfo snapshot */ 163*26947304SEvan Yan di_fini(di_root); 164*26947304SEvan Yan 165*26947304SEvan Yan *rootp = (rv == 0) ? hp_root : NULL; 166*26947304SEvan Yan return (rv); 167*26947304SEvan Yan } 168*26947304SEvan Yan 169*26947304SEvan Yan /* 170*26947304SEvan Yan * copy_devices() 171*26947304SEvan Yan * 172*26947304SEvan Yan * Copy a full branch of device nodes. Used by copy_devinfo() and 173*26947304SEvan Yan * copy_hotplug(). 174*26947304SEvan Yan */ 175*26947304SEvan Yan static int 176*26947304SEvan Yan copy_devices(hp_node_t parent, di_node_t dev, uint_t flags, hp_node_t *rootp) 177*26947304SEvan Yan { 178*26947304SEvan Yan hp_node_list_t children; 179*26947304SEvan Yan hp_node_t self, branch; 180*26947304SEvan Yan di_node_t child; 181*26947304SEvan Yan int rv = 0; 182*26947304SEvan Yan 183*26947304SEvan Yan /* Initialize results */ 184*26947304SEvan Yan *rootp = NULL; 185*26947304SEvan Yan 186*26947304SEvan Yan /* Enforce search semantics */ 187*26947304SEvan Yan if (check_search(dev, flags) == 0) 188*26947304SEvan Yan return (0); 189*26947304SEvan Yan 190*26947304SEvan Yan /* Allocate new node for current device */ 191*26947304SEvan Yan if ((self = new_device_node(parent, dev)) == NULL) 192*26947304SEvan Yan return (ENOMEM); 193*26947304SEvan Yan 194*26947304SEvan Yan /* 195*26947304SEvan Yan * If the device has hotplug nodes, then use copy_hotplug() 196*26947304SEvan Yan * instead to build the branch associated with current device. 197*26947304SEvan Yan */ 198*26947304SEvan Yan if (di_hp_next(dev, DI_HP_NIL) != DI_HP_NIL) { 199*26947304SEvan Yan if ((rv = copy_hotplug(self, dev, NULL, flags, 200*26947304SEvan Yan &self->hp_child)) != 0) { 201*26947304SEvan Yan free(self); 202*26947304SEvan Yan return (rv); 203*26947304SEvan Yan } 204*26947304SEvan Yan *rootp = self; 205*26947304SEvan Yan return (0); 206*26947304SEvan Yan } 207*26947304SEvan Yan 208*26947304SEvan Yan /* 209*26947304SEvan Yan * The device does not have hotplug nodes. Use normal 210*26947304SEvan Yan * approach of iterating through its child device nodes. 211*26947304SEvan Yan */ 212*26947304SEvan Yan (void) memset(&children, 0, sizeof (hp_node_list_t)); 213*26947304SEvan Yan for (child = di_child_node(dev); child != DI_NODE_NIL; 214*26947304SEvan Yan child = di_sibling_node(child)) { 215*26947304SEvan Yan branch = NULL; 216*26947304SEvan Yan if ((rv = copy_devices(self, child, flags, &branch)) != 0) { 217*26947304SEvan Yan (void) hp_fini(children.head); 218*26947304SEvan Yan free(self); 219*26947304SEvan Yan return (rv); 220*26947304SEvan Yan } 221*26947304SEvan Yan if (branch != NULL) 222*26947304SEvan Yan node_list_add(&children, branch); 223*26947304SEvan Yan } 224*26947304SEvan Yan self->hp_child = children.head; 225*26947304SEvan Yan 226*26947304SEvan Yan /* Done */ 227*26947304SEvan Yan *rootp = self; 228*26947304SEvan Yan return (0); 229*26947304SEvan Yan } 230*26947304SEvan Yan 231*26947304SEvan Yan /* 232*26947304SEvan Yan * copy_hotplug() 233*26947304SEvan Yan * 234*26947304SEvan Yan * Copy a full branch of hotplug nodes. Used by copy_devinfo() 235*26947304SEvan Yan * and copy_devices(). 236*26947304SEvan Yan * 237*26947304SEvan Yan * If a connection is specified, the results are limited only 238*26947304SEvan Yan * to the branch associated with that specific connection. 239*26947304SEvan Yan */ 240*26947304SEvan Yan static int 241*26947304SEvan Yan copy_hotplug(hp_node_t parent, di_node_t dev, const char *connection, 242*26947304SEvan Yan uint_t flags, hp_node_t *retp) 243*26947304SEvan Yan { 244*26947304SEvan Yan hp_node_list_t connections, ports; 245*26947304SEvan Yan hp_node_t node, port_node; 246*26947304SEvan Yan di_node_t child_dev; 247*26947304SEvan Yan di_hp_t hp, port_hp; 248*26947304SEvan Yan uint_t child_flags; 249*26947304SEvan Yan int rv, physnum; 250*26947304SEvan Yan 251*26947304SEvan Yan /* Stop implementing the HPINFOSEARCH flag */ 252*26947304SEvan Yan child_flags = flags & ~(HPINFOSEARCH); 253*26947304SEvan Yan 254*26947304SEvan Yan /* Clear lists of discovered ports and connections */ 255*26947304SEvan Yan (void) memset(&ports, 0, sizeof (hp_node_list_t)); 256*26947304SEvan Yan (void) memset(&connections, 0, sizeof (hp_node_list_t)); 257*26947304SEvan Yan 258*26947304SEvan Yan /* 259*26947304SEvan Yan * Scan virtual ports. 260*26947304SEvan Yan * 261*26947304SEvan Yan * If a connection is specified and it matches a virtual port, 262*26947304SEvan Yan * this will build the branch associated with that connection. 263*26947304SEvan Yan * Else, this will only build branches for virtual ports that 264*26947304SEvan Yan * are not associated with a physical connector. 265*26947304SEvan Yan */ 266*26947304SEvan Yan for (hp = DI_HP_NIL; (hp = di_hp_next(dev, hp)) != DI_HP_NIL; ) { 267*26947304SEvan Yan 268*26947304SEvan Yan /* Ignore connectors */ 269*26947304SEvan Yan if (di_hp_type(hp) != DDI_HP_CN_TYPE_VIRTUAL_PORT) 270*26947304SEvan Yan continue; 271*26947304SEvan Yan 272*26947304SEvan Yan /* 273*26947304SEvan Yan * Ignore ports associated with connectors, unless 274*26947304SEvan Yan * a specific connection is being sought. 275*26947304SEvan Yan */ 276*26947304SEvan Yan if ((connection == NULL) && (di_hp_depends_on(hp) != -1)) 277*26947304SEvan Yan continue; 278*26947304SEvan Yan 279*26947304SEvan Yan /* If a connection is specified, ignore non-matching ports */ 280*26947304SEvan Yan if ((connection != NULL) && 281*26947304SEvan Yan (strcmp(di_hp_name(hp), connection) != 0)) 282*26947304SEvan Yan continue; 283*26947304SEvan Yan 284*26947304SEvan Yan /* Create a new port node */ 285*26947304SEvan Yan if ((node = new_hotplug_node(parent, hp)) == NULL) { 286*26947304SEvan Yan rv = ENOMEM; 287*26947304SEvan Yan goto fail; 288*26947304SEvan Yan } 289*26947304SEvan Yan 290*26947304SEvan Yan /* Add port node to connection list */ 291*26947304SEvan Yan node_list_add(&connections, node); 292*26947304SEvan Yan 293*26947304SEvan Yan /* Add branch of child devices to port node */ 294*26947304SEvan Yan if ((child_dev = di_hp_child(hp)) != DI_NODE_NIL) 295*26947304SEvan Yan if ((rv = copy_devices(node, child_dev, child_flags, 296*26947304SEvan Yan &node->hp_child)) != 0) 297*26947304SEvan Yan goto fail; 298*26947304SEvan Yan } 299*26947304SEvan Yan 300*26947304SEvan Yan /* 301*26947304SEvan Yan * Scan physical connectors. 302*26947304SEvan Yan * 303*26947304SEvan Yan * If a connection is specified, the results will be limited 304*26947304SEvan Yan * only to the branch associated with that connection. 305*26947304SEvan Yan */ 306*26947304SEvan Yan for (hp = DI_HP_NIL; (hp = di_hp_next(dev, hp)) != DI_HP_NIL; ) { 307*26947304SEvan Yan 308*26947304SEvan Yan /* Ignore ports */ 309*26947304SEvan Yan if (di_hp_type(hp) == DDI_HP_CN_TYPE_VIRTUAL_PORT) 310*26947304SEvan Yan continue; 311*26947304SEvan Yan 312*26947304SEvan Yan /* If a connection is specified, ignore non-matching ports */ 313*26947304SEvan Yan if ((connection != NULL) && 314*26947304SEvan Yan (strcmp(di_hp_name(hp), connection) != 0)) 315*26947304SEvan Yan continue; 316*26947304SEvan Yan 317*26947304SEvan Yan /* Create a new connector node */ 318*26947304SEvan Yan if ((node = new_hotplug_node(parent, hp)) == NULL) { 319*26947304SEvan Yan rv = ENOMEM; 320*26947304SEvan Yan goto fail; 321*26947304SEvan Yan } 322*26947304SEvan Yan 323*26947304SEvan Yan /* Add connector node to connection list */ 324*26947304SEvan Yan node_list_add(&connections, node); 325*26947304SEvan Yan 326*26947304SEvan Yan /* Add branches of associated port nodes */ 327*26947304SEvan Yan physnum = di_hp_connection(hp); 328*26947304SEvan Yan port_hp = DI_HP_NIL; 329*26947304SEvan Yan while ((port_hp = di_hp_next(dev, port_hp)) != DI_HP_NIL) { 330*26947304SEvan Yan 331*26947304SEvan Yan /* Ignore irrelevant connections */ 332*26947304SEvan Yan if (di_hp_depends_on(port_hp) != physnum) 333*26947304SEvan Yan continue; 334*26947304SEvan Yan 335*26947304SEvan Yan /* Add new port node to port list */ 336*26947304SEvan Yan if ((port_node = new_hotplug_node(node, 337*26947304SEvan Yan port_hp)) == NULL) { 338*26947304SEvan Yan rv = ENOMEM; 339*26947304SEvan Yan goto fail; 340*26947304SEvan Yan } 341*26947304SEvan Yan node_list_add(&ports, port_node); 342*26947304SEvan Yan 343*26947304SEvan Yan /* Add branch of child devices */ 344*26947304SEvan Yan if ((child_dev = di_hp_child(port_hp)) != DI_NODE_NIL) { 345*26947304SEvan Yan if ((rv = copy_devices(port_node, child_dev, 346*26947304SEvan Yan child_flags, &port_node->hp_child)) != 0) 347*26947304SEvan Yan goto fail; 348*26947304SEvan Yan } 349*26947304SEvan Yan } 350*26947304SEvan Yan node->hp_child = ports.head; 351*26947304SEvan Yan (void) memset(&ports, 0, sizeof (hp_node_list_t)); 352*26947304SEvan Yan } 353*26947304SEvan Yan 354*26947304SEvan Yan if (connections.head == NULL) 355*26947304SEvan Yan return (ENXIO); 356*26947304SEvan Yan *retp = connections.head; 357*26947304SEvan Yan return (0); 358*26947304SEvan Yan 359*26947304SEvan Yan fail: 360*26947304SEvan Yan (void) hp_fini(ports.head); 361*26947304SEvan Yan (void) hp_fini(connections.head); 362*26947304SEvan Yan return (rv); 363*26947304SEvan Yan } 364*26947304SEvan Yan 365*26947304SEvan Yan /* 366*26947304SEvan Yan * base_path() 367*26947304SEvan Yan * 368*26947304SEvan Yan * Normalize the base path of a hotplug information snapshot. 369*26947304SEvan Yan * The caller must free the string that is allocated. 370*26947304SEvan Yan */ 371*26947304SEvan Yan static char * 372*26947304SEvan Yan base_path(const char *path) 373*26947304SEvan Yan { 374*26947304SEvan Yan char *base_path; 375*26947304SEvan Yan size_t devices_len; 376*26947304SEvan Yan 377*26947304SEvan Yan devices_len = strlen(S_DEVICES); 378*26947304SEvan Yan 379*26947304SEvan Yan if (strncmp(path, S_DEVICES, devices_len) == 0) 380*26947304SEvan Yan base_path = strdup(&path[devices_len]); 381*26947304SEvan Yan else 382*26947304SEvan Yan base_path = strdup(path); 383*26947304SEvan Yan 384*26947304SEvan Yan return (base_path); 385*26947304SEvan Yan } 386*26947304SEvan Yan 387*26947304SEvan Yan /* 388*26947304SEvan Yan * search_cb() 389*26947304SEvan Yan * 390*26947304SEvan Yan * Callback function used by di_walk_node() to search for branches 391*26947304SEvan Yan * of the libdevinfo snapshot that contain hotplug nodes. 392*26947304SEvan Yan */ 393*26947304SEvan Yan /*ARGSUSED*/ 394*26947304SEvan Yan static int 395*26947304SEvan Yan search_cb(di_node_t node, void *arg) 396*26947304SEvan Yan { 397*26947304SEvan Yan di_node_t parent; 398*26947304SEvan Yan uint_t flags; 399*26947304SEvan Yan 400*26947304SEvan Yan (void) di_node_private_set(node, (void *)(uintptr_t)0); 401*26947304SEvan Yan 402*26947304SEvan Yan if (di_hp_next(node, DI_HP_NIL) == DI_HP_NIL) 403*26947304SEvan Yan return (DI_WALK_CONTINUE); 404*26947304SEvan Yan 405*26947304SEvan Yan for (parent = node; parent != DI_NODE_NIL; 406*26947304SEvan Yan parent = di_parent_node(parent)) { 407*26947304SEvan Yan flags = (uint_t)(uintptr_t)di_node_private_get(parent); 408*26947304SEvan Yan flags |= HPINFOSEARCH; 409*26947304SEvan Yan (void) di_node_private_set(parent, (void *)(uintptr_t)flags); 410*26947304SEvan Yan } 411*26947304SEvan Yan 412*26947304SEvan Yan return (DI_WALK_CONTINUE); 413*26947304SEvan Yan } 414*26947304SEvan Yan 415*26947304SEvan Yan /* 416*26947304SEvan Yan * check_search() 417*26947304SEvan Yan * 418*26947304SEvan Yan * Check if a device node was marked by an initial search pass. 419*26947304SEvan Yan */ 420*26947304SEvan Yan static int 421*26947304SEvan Yan check_search(di_node_t dev, uint_t flags) 422*26947304SEvan Yan { 423*26947304SEvan Yan uint_t dev_flags; 424*26947304SEvan Yan 425*26947304SEvan Yan if (flags & HPINFOSEARCH) { 426*26947304SEvan Yan dev_flags = (uint_t)(uintptr_t)di_node_private_get(dev); 427*26947304SEvan Yan if ((dev_flags & HPINFOSEARCH) == 0) 428*26947304SEvan Yan return (0); 429*26947304SEvan Yan } 430*26947304SEvan Yan 431*26947304SEvan Yan return (1); 432*26947304SEvan Yan } 433*26947304SEvan Yan 434*26947304SEvan Yan /* 435*26947304SEvan Yan * node_list_add() 436*26947304SEvan Yan * 437*26947304SEvan Yan * Utility function to append one node to a list of hotplug nodes. 438*26947304SEvan Yan */ 439*26947304SEvan Yan static void 440*26947304SEvan Yan node_list_add(hp_node_list_t *listp, hp_node_t node) 441*26947304SEvan Yan { 442*26947304SEvan Yan if (listp->prev != NULL) 443*26947304SEvan Yan listp->prev->hp_sibling = node; 444*26947304SEvan Yan else 445*26947304SEvan Yan listp->head = node; 446*26947304SEvan Yan 447*26947304SEvan Yan listp->prev = node; 448*26947304SEvan Yan } 449*26947304SEvan Yan 450*26947304SEvan Yan /* 451*26947304SEvan Yan * new_device_node() 452*26947304SEvan Yan * 453*26947304SEvan Yan * Build a new hotplug node based on a specified devinfo node. 454*26947304SEvan Yan */ 455*26947304SEvan Yan static hp_node_t 456*26947304SEvan Yan new_device_node(hp_node_t parent, di_node_t dev) 457*26947304SEvan Yan { 458*26947304SEvan Yan hp_node_t node; 459*26947304SEvan Yan char *node_name, *bus_addr; 460*26947304SEvan Yan char name[MAXPATHLEN]; 461*26947304SEvan Yan 462*26947304SEvan Yan node = (hp_node_t)calloc(1, sizeof (struct hp_node)); 463*26947304SEvan Yan 464*26947304SEvan Yan if (node != NULL) { 465*26947304SEvan Yan node->hp_parent = parent; 466*26947304SEvan Yan node->hp_type = HP_NODE_DEVICE; 467*26947304SEvan Yan 468*26947304SEvan Yan node_name = di_node_name(dev); 469*26947304SEvan Yan bus_addr = di_bus_addr(dev); 470*26947304SEvan Yan if (bus_addr && (strlen(bus_addr) > 0)) { 471*26947304SEvan Yan if (snprintf(name, sizeof (name), "%s@%s", node_name, 472*26947304SEvan Yan bus_addr) >= sizeof (name)) { 473*26947304SEvan Yan log_err("Path too long for device node.\n"); 474*26947304SEvan Yan free(node); 475*26947304SEvan Yan return (NULL); 476*26947304SEvan Yan } 477*26947304SEvan Yan node->hp_name = strdup(name); 478*26947304SEvan Yan } else 479*26947304SEvan Yan node->hp_name = strdup(node_name); 480*26947304SEvan Yan } 481*26947304SEvan Yan 482*26947304SEvan Yan return (node); 483*26947304SEvan Yan } 484*26947304SEvan Yan 485*26947304SEvan Yan /* 486*26947304SEvan Yan * new_hotplug_node() 487*26947304SEvan Yan * 488*26947304SEvan Yan * Build a new hotplug node based on a specified devinfo hotplug node. 489*26947304SEvan Yan */ 490*26947304SEvan Yan static hp_node_t 491*26947304SEvan Yan new_hotplug_node(hp_node_t parent, di_hp_t hp) 492*26947304SEvan Yan { 493*26947304SEvan Yan hp_node_t node; 494*26947304SEvan Yan char *s; 495*26947304SEvan Yan 496*26947304SEvan Yan node = (hp_node_t)calloc(1, sizeof (struct hp_node)); 497*26947304SEvan Yan 498*26947304SEvan Yan if (node != NULL) { 499*26947304SEvan Yan node->hp_parent = parent; 500*26947304SEvan Yan node->hp_state = di_hp_state(hp); 501*26947304SEvan Yan node->hp_last_change = di_hp_last_change(hp); 502*26947304SEvan Yan if ((s = di_hp_name(hp)) != NULL) 503*26947304SEvan Yan node->hp_name = strdup(s); 504*26947304SEvan Yan if ((s = di_hp_description(hp)) != NULL) 505*26947304SEvan Yan node->hp_description = strdup(s); 506*26947304SEvan Yan if (di_hp_type(hp) == DDI_HP_CN_TYPE_VIRTUAL_PORT) 507*26947304SEvan Yan node->hp_type = HP_NODE_PORT; 508*26947304SEvan Yan else 509*26947304SEvan Yan node->hp_type = HP_NODE_CONNECTOR; 510*26947304SEvan Yan } 511*26947304SEvan Yan 512*26947304SEvan Yan return (node); 513*26947304SEvan Yan } 514