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.
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.
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]
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
34 #include <libnvpair.h>
35 #include <libhotplug.h>
36 #include <libhotplug_impl.h>
37 #include <sys/sunddi.h>
38 #include <sys/ddi_hp.h>
40 static void i_hp_dprintf(const char *fmt
, ...);
41 static int i_hp_pack_branch(hp_node_t
, char **, size_t *);
42 static int i_hp_pack_node(hp_node_t
, char **, size_t *);
43 static int i_hp_unpack_node(char *, size_t, hp_node_t
, hp_node_t
*);
44 static int i_hp_unpack_branch(char *, size_t, hp_node_t
, hp_node_t
*);
45 static int i_hp_call_hotplugd(nvlist_t
*, nvlist_t
**);
46 static nvlist_t
*i_hp_set_args(hp_cmd_t
, const char *, const char *, uint_t
,
48 static int i_hp_parse_results(nvlist_t
*, hp_node_t
*, char **);
51 * Global flag to enable debug features.
53 int libhotplug_debug
= 0;
58 * Initialize a hotplug information snapshot.
61 hp_init(const char *path
, const char *connection
, uint_t flags
)
65 hp_node_t root
= NULL
;
68 i_hp_dprintf("hp_init: path=%p, connection=%p, flags=0x%x\n",
69 (void *)path
, (void *)connection
, flags
);
72 if ((path
== NULL
) || !HP_INIT_FLAGS_VALID(flags
)) {
73 i_hp_dprintf("hp_init: invalid arguments.\n");
78 /* Build arguments for door call */
79 if ((args
= i_hp_set_args(HP_CMD_GETINFO
, path
, connection
, flags
,
81 i_hp_dprintf("hp_init: cannot build arguments nvlist.\n");
86 /* Make the door call to hotplugd */
87 rv
= i_hp_call_hotplugd(args
, &results
);
89 /* Arguments no longer needed */
92 /* Parse additional results, if any */
93 if ((rv
== 0) && (results
!= NULL
)) {
94 rv
= i_hp_parse_results(results
, &root
, NULL
);
98 /* Check for errors */
100 i_hp_dprintf("hp_init: failure (%s).\n", strerror(rv
));
107 /* Success requires an info snapshot */
109 i_hp_dprintf("hp_init: missing info snapshot.\n");
121 * Terminate and clean-up a hotplug information snapshot.
124 hp_fini(hp_node_t root
)
130 i_hp_dprintf("hp_fini: root=%p\n", (void *)root
);
133 i_hp_dprintf("hp_fini: invalid arguments.\n");
137 /* Extract and free base path */
138 if (root
->hp_basepath
) {
139 basepath
= root
->hp_basepath
;
140 for (node
= root
; node
!= NULL
; node
= node
->hp_sibling
)
141 node
->hp_basepath
= NULL
;
145 /* Destroy the nodes */
148 sibling
= node
->hp_sibling
;
150 hp_fini(node
->hp_child
);
152 free(node
->hp_usage
);
153 free(node
->hp_description
);
162 * Walk a graph of hotplug nodes, executing a callback on each node.
165 hp_traverse(hp_node_t root
, void *arg
, int (*hp_callback
)(hp_node_t
, void *arg
))
170 i_hp_dprintf("hp_traverse: root=%p, arg=%p, hp_callback=%p\n",
171 (void *)root
, arg
, (void *)hp_callback
);
173 /* Check arguments */
174 if ((root
== NULL
) || (hp_callback
== NULL
)) {
175 i_hp_dprintf("hp_traverse: invalid arguments.\n");
180 for (node
= root
; node
; node
= node
->hp_sibling
) {
181 rv
= hp_callback(node
, arg
);
183 if (rv
== HP_WALK_TERMINATE
) {
184 i_hp_dprintf("hp_traverse: walk terminated.\n");
185 return (HP_WALK_TERMINATE
);
188 if (node
->hp_child
&& (rv
!= HP_WALK_PRUNECHILD
))
189 if (hp_traverse(node
->hp_child
, arg
, hp_callback
) ==
191 i_hp_dprintf("hp_traverse: walk terminated.\n");
192 return (HP_WALK_TERMINATE
);
195 if (rv
== HP_WALK_PRUNESIBLING
)
205 * Return a node's type.
208 hp_type(hp_node_t node
)
210 i_hp_dprintf("hp_type: node=%p\n", (void *)node
);
213 i_hp_dprintf("hp_type: invalid arguments.\n");
218 return (node
->hp_type
);
224 * Return a node's name.
227 hp_name(hp_node_t node
)
229 i_hp_dprintf("hp_name: node=%p\n", (void *)node
);
232 i_hp_dprintf("hp_name: invalid arguments.\n");
237 if (node
->hp_name
== NULL
) {
238 i_hp_dprintf("hp_name: missing name value.\n");
242 return (node
->hp_name
);
248 * Return a node's current state.
251 hp_state(hp_node_t node
)
253 i_hp_dprintf("hp_state: node=%p\n", (void *)node
);
256 i_hp_dprintf("hp_state: invalid arguments.\n");
261 if ((node
->hp_type
!= HP_NODE_CONNECTOR
) &&
262 (node
->hp_type
!= HP_NODE_PORT
)) {
263 i_hp_dprintf("hp_state: operation not supported.\n");
268 return (node
->hp_state
);
274 * Return a usage description for usage nodes.
277 hp_usage(hp_node_t node
)
279 i_hp_dprintf("hp_usage: node=%p\n", (void *)node
);
282 i_hp_dprintf("hp_usage: invalid arguments.\n");
287 if (node
->hp_type
!= HP_NODE_USAGE
) {
288 i_hp_dprintf("hp_usage: operation not supported.\n");
293 if (node
->hp_usage
== NULL
) {
294 i_hp_dprintf("hp_usage: missing usage value.\n");
298 return (node
->hp_usage
);
304 * Return a type description (e.g. "PCI slot") for connection nodes.
307 hp_description(hp_node_t node
)
309 i_hp_dprintf("hp_description: node=%p\n", (void *)node
);
312 i_hp_dprintf("hp_description: invalid arguments.\n");
317 if ((node
->hp_type
!= HP_NODE_CONNECTOR
) &&
318 (node
->hp_type
!= HP_NODE_PORT
)) {
319 i_hp_dprintf("hp_description: operation not supported.\n");
324 if (node
->hp_description
== NULL
) {
325 i_hp_dprintf("hp_description: missing description value.\n");
329 return (node
->hp_description
);
335 * Return when the state of a connection was last changed.
338 hp_last_change(hp_node_t node
)
340 i_hp_dprintf("hp_last_change: node=%p\n", (void *)node
);
343 i_hp_dprintf("hp_last_change: invalid arguments.\n");
348 if ((node
->hp_type
!= HP_NODE_CONNECTOR
) &&
349 (node
->hp_type
!= HP_NODE_PORT
)) {
350 i_hp_dprintf("hp_last_change: operation not supported.\n");
355 return (node
->hp_last_change
);
361 * Return a node's parent node.
364 hp_parent(hp_node_t node
)
366 i_hp_dprintf("hp_parent: node=%p\n", (void *)node
);
369 i_hp_dprintf("hp_parent: invalid arguments.\n");
374 if (node
->hp_parent
== NULL
) {
375 i_hp_dprintf("hp_parent: node has no parent.\n");
379 return (node
->hp_parent
);
385 * Return a node's first child node.
388 hp_child(hp_node_t node
)
390 i_hp_dprintf("hp_child: node=%p\n", (void *)node
);
393 i_hp_dprintf("hp_child: invalid arguments.\n");
398 if (node
->hp_child
== NULL
) {
399 i_hp_dprintf("hp_child: node has no child.\n");
403 return (node
->hp_child
);
409 * Return a node's next sibling node.
412 hp_sibling(hp_node_t node
)
414 i_hp_dprintf("hp_sibling: node=%p\n", (void *)node
);
417 i_hp_dprintf("hp_sibling: invalid arguments.\n");
422 if (node
->hp_sibling
== NULL
) {
423 i_hp_dprintf("hp_sibling: node has no sibling.\n");
427 return (node
->hp_sibling
);
433 * Return the path (and maybe connection name) of a node.
434 * The caller must supply two buffers, each MAXPATHLEN size.
437 hp_path(hp_node_t node
, char *path
, char *connection
)
439 hp_node_t root
= NULL
;
443 char components
[MAXPATHLEN
];
445 i_hp_dprintf("hp_path: node=%p, path=%p, connection=%p\n", (void *)node
,
446 (void *)path
, (void *)connection
);
448 if ((node
== NULL
) || (path
== NULL
) || (connection
== NULL
)) {
449 i_hp_dprintf("hp_path: invalid arguments.\n");
453 (void) memset(path
, 0, MAXPATHLEN
);
454 (void) memset(connection
, 0, MAXPATHLEN
);
455 (void) memset(components
, 0, MAXPATHLEN
);
457 /* Set 'connection' only for connectors and ports */
458 if ((node
->hp_type
== HP_NODE_CONNECTOR
) ||
459 (node
->hp_type
== HP_NODE_PORT
))
460 (void) strlcpy(connection
, node
->hp_name
, MAXPATHLEN
);
462 /* Trace back to the root node, accumulating components */
463 for (parent
= node
, root
= parent
; parent
!= NULL
;
464 root
= parent
, parent
= parent
->hp_parent
) {
465 if (parent
->hp_type
== HP_NODE_DEVICE
) {
466 (void) strlcat(components
, "/", MAXPATHLEN
);
467 (void) strlcat(components
, parent
->hp_name
, MAXPATHLEN
);
471 /* Ensure the snapshot actually contains a base path */
472 if (root
->hp_basepath
== NULL
) {
473 i_hp_dprintf("hp_path: missing base pathname.\n");
478 * Construct the path. Start with the base path from the root
479 * node, then append the accumulated components in reverse order.
481 if (strcmp(root
->hp_basepath
, "/") != 0) {
482 (void) strlcat(path
, root
->hp_basepath
, MAXPATHLEN
);
483 if ((root
->hp_type
== HP_NODE_DEVICE
) &&
484 ((s
= strrchr(path
, '/')) != NULL
))
487 for (i
= strlen(components
) - 1; i
>= 0; i
--) {
488 if (components
[i
] == '/') {
489 (void) strlcat(path
, &components
[i
], MAXPATHLEN
);
490 components
[i
] = '\0';
500 * Initiate a state change operation on a node.
503 hp_set_state(hp_node_t node
, uint_t flags
, int state
, hp_node_t
*resultsp
)
505 hp_node_t root
= NULL
;
509 char path
[MAXPATHLEN
];
510 char connection
[MAXPATHLEN
];
512 i_hp_dprintf("hp_set_state: node=%p, flags=0x%x, state=0x%x, "
513 "resultsp=%p\n", (void *)node
, flags
, state
, (void *)resultsp
);
515 /* Check arguments */
516 if ((node
== NULL
) || (resultsp
== NULL
) ||
517 !HP_SET_STATE_FLAGS_VALID(flags
)) {
518 i_hp_dprintf("hp_set_state: invalid arguments.\n");
522 /* Check node type */
523 if ((node
->hp_type
!= HP_NODE_CONNECTOR
) &&
524 (node
->hp_type
!= HP_NODE_PORT
)) {
525 i_hp_dprintf("hp_set_state: operation not supported.\n");
529 /* Check that target state is valid */
531 case DDI_HP_CN_STATE_PRESENT
:
532 case DDI_HP_CN_STATE_POWERED
:
533 case DDI_HP_CN_STATE_ENABLED
:
534 if (node
->hp_type
!= HP_NODE_CONNECTOR
) {
535 i_hp_dprintf("hp_set_state: mismatched target.\n");
539 case DDI_HP_CN_STATE_PORT_PRESENT
:
540 case DDI_HP_CN_STATE_OFFLINE
:
541 case DDI_HP_CN_STATE_ONLINE
:
542 if (node
->hp_type
!= HP_NODE_PORT
) {
543 i_hp_dprintf("hp_set_state: mismatched target.\n");
548 i_hp_dprintf("hp_set_state: invalid target state.\n");
552 /* Get path and connection of specified node */
553 if ((rv
= hp_path(node
, path
, connection
)) != 0)
556 /* Build arguments for door call */
557 if ((args
= i_hp_set_args(HP_CMD_CHANGESTATE
, path
, connection
, flags
,
558 NULL
, state
)) == NULL
)
561 /* Make the door call to hotplugd */
562 rv
= i_hp_call_hotplugd(args
, &results
);
564 /* Arguments no longer needed */
567 /* Parse additional results, if any */
568 if ((rv
== 0) && (results
!= NULL
)) {
569 rv
= i_hp_parse_results(results
, &root
, NULL
);
570 nvlist_free(results
);
581 * Set bus private options on the hotplug connection
582 * indicated by the given hotplug information node.
585 hp_set_private(hp_node_t node
, const char *options
, char **resultsp
)
591 char path
[MAXPATHLEN
];
592 char connection
[MAXPATHLEN
];
594 i_hp_dprintf("hp_set_private: node=%p, options=%p, resultsp=%p\n",
595 (void *)node
, (void *)options
, (void *)resultsp
);
597 /* Check arguments */
598 if ((node
== NULL
) || (options
== NULL
) || (resultsp
== NULL
)) {
599 i_hp_dprintf("hp_set_private: invalid arguments.\n");
603 /* Check node type */
604 if (node
->hp_type
!= HP_NODE_CONNECTOR
) {
605 i_hp_dprintf("hp_set_private: operation not supported.\n");
609 /* Initialize results */
612 /* Get path and connection of specified node */
613 if ((rv
= hp_path(node
, path
, connection
)) != 0)
616 /* Build arguments for door call */
617 if ((args
= i_hp_set_args(HP_CMD_SETPRIVATE
, path
, connection
, 0,
618 options
, 0)) == NULL
)
621 /* Make the door call to hotplugd */
622 rv
= i_hp_call_hotplugd(args
, &results
);
624 /* Arguments no longer needed */
627 /* Parse additional results, if any */
628 if ((rv
== 0) && (results
!= NULL
)) {
629 rv
= i_hp_parse_results(results
, NULL
, &values
);
630 nvlist_free(results
);
641 * Get bus private options on the hotplug connection
642 * indicated by the given hotplug information node.
645 hp_get_private(hp_node_t node
, const char *options
, char **resultsp
)
651 char path
[MAXPATHLEN
];
652 char connection
[MAXPATHLEN
];
654 i_hp_dprintf("hp_get_private: node=%p, options=%p, resultsp=%p\n",
655 (void *)node
, (void *)options
, (void *)resultsp
);
657 /* Check arguments */
658 if ((node
== NULL
) || (options
== NULL
) || (resultsp
== NULL
)) {
659 i_hp_dprintf("hp_get_private: invalid arguments.\n");
663 /* Check node type */
664 if (node
->hp_type
!= HP_NODE_CONNECTOR
) {
665 i_hp_dprintf("hp_get_private: operation not supported.\n");
669 /* Initialize results */
672 /* Get path and connection of specified node */
673 if ((rv
= hp_path(node
, path
, connection
)) != 0)
676 /* Build arguments for door call */
677 if ((args
= i_hp_set_args(HP_CMD_GETPRIVATE
, path
, connection
, 0,
678 options
, 0)) == NULL
)
681 /* Make the door call to hotplugd */
682 rv
= i_hp_call_hotplugd(args
, &results
);
684 /* Arguments no longer needed */
687 /* Parse additional results, if any */
688 if ((rv
== 0) && (results
!= NULL
)) {
689 rv
= i_hp_parse_results(results
, NULL
, &values
);
690 nvlist_free(results
);
701 * Given the root of a hotplug information snapshot, pack
702 * it into a contiguous byte array so that it is suitable
703 * for network transport.
706 hp_pack(hp_node_t root
, char **bufp
, size_t *lenp
)
714 i_hp_dprintf("hp_pack: root=%p, bufp=%p, lenp=%p\n", (void *)root
,
715 (void *)bufp
, (void *)lenp
);
717 if ((root
== NULL
) || (bufp
== NULL
) || (lenp
== NULL
)) {
718 i_hp_dprintf("hp_pack: invalid arguments.\n");
725 if (nvlist_alloc(&nvl
, 0, 0) != 0) {
726 i_hp_dprintf("hp_pack: nvlist_alloc() failed (%s).\n",
731 if (root
->hp_basepath
!= NULL
) {
732 rv
= nvlist_add_string(nvl
, HP_INFO_BASE
, root
->hp_basepath
);
739 for (node
= root
; node
!= NULL
; node
= node
->hp_sibling
) {
740 if ((rv
= i_hp_pack_branch(node
, &buf
, &len
)) == 0) {
741 rv
= nvlist_add_byte_array(nvl
, HP_INFO_BRANCH
,
742 (uchar_t
*)buf
, len
);
753 if ((rv
= nvlist_pack(nvl
, &buf
, &len
, NV_ENCODE_NATIVE
, 0)) == 0) {
766 * Unpack a hotplug information snapshot for normal usage.
769 hp_unpack(char *packed_buf
, size_t packed_len
, hp_node_t
*retp
)
772 hp_node_t root_list
= NULL
;
773 hp_node_t prev_root
= NULL
;
774 nvlist_t
*nvl
= NULL
;
776 char *basepath
= NULL
;
779 i_hp_dprintf("hp_unpack: packed_buf=%p, packed_len=%u, retp=%p\n",
780 (void *)packed_buf
, (uint32_t)packed_len
, (void *)retp
);
782 if ((packed_buf
== NULL
) || (packed_len
== 0) || (retp
== NULL
)) {
783 i_hp_dprintf("hp_unpack: invalid arguments.\n");
787 if ((rv
= nvlist_unpack(packed_buf
, packed_len
, &nvl
, 0)) != 0)
790 if (nvlist_next_nvpair(nvl
, NULL
) == NULL
) {
796 for (nvp
= NULL
; nvp
= nvlist_next_nvpair(nvl
, nvp
); ) {
800 if (strcmp(nvpair_name(nvp
), HP_INFO_BASE
) == 0) {
803 if ((rv
= nvpair_value_string(nvp
, &val_string
)) == 0) {
804 if ((basepath
= strdup(val_string
)) == NULL
)
808 } else if (strcmp(nvpair_name(nvp
), HP_INFO_BRANCH
) == 0) {
812 if ((rv
= nvpair_value_byte_array(nvp
,
813 (uchar_t
**)&buf
, (uint_t
*)&len
)) == 0) {
814 rv
= i_hp_unpack_branch(buf
, len
, NULL
, &root
);
819 prev_root
->hp_sibling
= root
;
836 /* Store the base path in each root node */
838 for (root
= root_list
; root
; root
= root
->hp_sibling
)
839 root
->hp_basepath
= basepath
;
850 * Print debug messages to stderr, but only when the debug flag
851 * (libhotplug_debug) is set.
855 i_hp_dprintf(const char *fmt
, ...)
859 if (libhotplug_debug
) {
861 (void) vfprintf(stderr
, fmt
, ap
);
869 * Pack an individual branch of a hotplug information snapshot.
872 i_hp_pack_branch(hp_node_t root
, char **bufp
, size_t *lenp
)
883 /* Allocate an nvlist for this branch */
884 if (nvlist_alloc(&nvl
, 0, 0) != 0)
887 /* Pack the root of the branch and add it to the nvlist */
888 if ((rv
= i_hp_pack_node(root
, &buf
, &len
)) == 0) {
889 rv
= nvlist_add_byte_array(nvl
, HP_INFO_NODE
,
890 (uchar_t
*)buf
, len
);
898 /* Pack each subordinate branch, and add it to the nvlist */
899 for (child
= root
->hp_child
; child
!= NULL
; child
= child
->hp_sibling
) {
900 if ((rv
= i_hp_pack_branch(child
, &buf
, &len
)) == 0) {
901 rv
= nvlist_add_byte_array(nvl
, HP_INFO_BRANCH
,
902 (uchar_t
*)buf
, len
);
911 /* Pack the resulting nvlist into a single buffer */
914 if ((rv
= nvlist_pack(nvl
, &buf
, &len
, NV_ENCODE_NATIVE
, 0)) == 0) {
919 /* Free the nvlist */
928 * Pack an individual node of a hotplug information snapshot.
931 i_hp_pack_node(hp_node_t node
, char **bufp
, size_t *lenp
)
938 if (nvlist_alloc(&nvl
, 0, 0) != 0)
941 if ((rv
= nvlist_add_uint32(nvl
, HP_INFO_TYPE
,
942 (uint32_t)node
->hp_type
)) != 0)
945 if ((node
->hp_name
) &&
946 ((rv
= nvlist_add_string(nvl
, HP_INFO_NAME
, node
->hp_name
)) != 0))
949 if ((node
->hp_usage
) &&
950 ((rv
= nvlist_add_string(nvl
, HP_INFO_USAGE
, node
->hp_usage
)) != 0))
953 if ((node
->hp_description
) &&
954 ((rv
= nvlist_add_string(nvl
, HP_INFO_DESC
,
955 node
->hp_description
)) != 0))
958 if ((rv
= nvlist_add_uint32(nvl
, HP_INFO_STATE
, node
->hp_state
)) != 0)
961 if ((node
->hp_last_change
!= 0) &&
962 ((rv
= nvlist_add_uint32(nvl
, HP_INFO_TIME
,
963 node
->hp_last_change
)) != 0))
966 if ((rv
= nvlist_pack(nvl
, &buf
, &len
, NV_ENCODE_NATIVE
, 0)) != 0)
982 * i_hp_unpack_branch()
984 * Unpack a branch of hotplug information nodes.
987 i_hp_unpack_branch(char *packed_buf
, size_t packed_len
, hp_node_t parent
,
990 hp_node_t node
= NULL
;
992 hp_node_t prev_child
= NULL
;
993 nvlist_t
*nvl
= NULL
;
999 /* Initialize results */
1002 /* Unpack the nvlist for this branch */
1003 if ((rv
= nvlist_unpack(packed_buf
, packed_len
, &nvl
, 0)) != 0)
1007 * Unpack the branch. The first item in the nvlist is
1008 * always the root node. And zero or more subordinate
1009 * branches may be packed afterward.
1011 for (nvp
= NULL
; nvp
= nvlist_next_nvpair(nvl
, nvp
); ) {
1016 if (strcmp(nvpair_name(nvp
), HP_INFO_NODE
) == 0) {
1018 /* Check that there is only one root node */
1025 if ((rv
= nvpair_value_byte_array(nvp
, (uchar_t
**)&buf
,
1026 (uint_t
*)&len
)) == 0)
1027 rv
= i_hp_unpack_node(buf
, len
, parent
, &node
);
1034 } else if (strcmp(nvpair_name(nvp
), HP_INFO_BRANCH
) == 0) {
1036 if ((rv
= nvpair_value_byte_array(nvp
, (uchar_t
**)&buf
,
1037 (uint_t
*)&len
)) == 0)
1038 rv
= i_hp_unpack_branch(buf
, len
, node
, &child
);
1047 prev_child
->hp_sibling
= child
;
1049 node
->hp_child
= child
;
1061 * i_hp_unpack_node()
1063 * Unpack an individual hotplug information node.
1066 i_hp_unpack_node(char *buf
, size_t len
, hp_node_t parent
, hp_node_t
*retp
)
1071 uint32_t val_uint32
;
1075 /* Initialize results */
1078 /* Unpack node into an nvlist */
1079 if ((nvlist_unpack(buf
, len
, &nvl
, 0) != 0))
1082 /* Allocate the new node */
1083 if ((node
= (hp_node_t
)calloc(1, sizeof (struct hp_node
))) == NULL
) {
1088 /* Iterate through nvlist, unpacking each field */
1089 for (nvp
= NULL
; nvp
= nvlist_next_nvpair(nvl
, nvp
); ) {
1091 if ((strcmp(nvpair_name(nvp
), HP_INFO_TYPE
) == 0) &&
1092 (nvpair_type(nvp
) == DATA_TYPE_UINT32
)) {
1094 (void) nvpair_value_uint32(nvp
, &val_uint32
);
1095 node
->hp_type
= val_uint32
;
1097 } else if ((strcmp(nvpair_name(nvp
), HP_INFO_NAME
) == 0) &&
1098 (nvpair_type(nvp
) == DATA_TYPE_STRING
)) {
1100 (void) nvpair_value_string(nvp
, &val_string
);
1101 if ((node
->hp_name
= strdup(val_string
)) == NULL
) {
1106 } else if ((strcmp(nvpair_name(nvp
), HP_INFO_STATE
) == 0) &&
1107 (nvpair_type(nvp
) == DATA_TYPE_UINT32
)) {
1109 (void) nvpair_value_uint32(nvp
, &val_uint32
);
1110 node
->hp_state
= val_uint32
;
1112 } else if ((strcmp(nvpair_name(nvp
), HP_INFO_USAGE
) == 0) &&
1113 (nvpair_type(nvp
) == DATA_TYPE_STRING
)) {
1115 (void) nvpair_value_string(nvp
, &val_string
);
1116 if ((node
->hp_usage
= strdup(val_string
)) == NULL
) {
1121 } else if ((strcmp(nvpair_name(nvp
), HP_INFO_DESC
) == 0) &&
1122 (nvpair_type(nvp
) == DATA_TYPE_STRING
)) {
1124 (void) nvpair_value_string(nvp
, &val_string
);
1125 if ((node
->hp_description
= strdup(val_string
))
1131 } else if ((strcmp(nvpair_name(nvp
), HP_INFO_TIME
) == 0) &&
1132 (nvpair_type(nvp
) == DATA_TYPE_UINT32
)) {
1134 (void) nvpair_value_uint32(nvp
, &val_uint32
);
1135 node
->hp_last_change
= (time_t)val_uint32
;
1138 i_hp_dprintf("i_hp_unpack_node: unrecognized: '%s'\n",
1143 /* Unpacked nvlist no longer needed */
1146 /* Check for errors */
1153 node
->hp_parent
= parent
;
1159 * i_hp_call_hotplugd()
1161 * Perform a door call to the hotplug daemon.
1164 i_hp_call_hotplugd(nvlist_t
*args
, nvlist_t
**resultsp
)
1166 door_arg_t door_arg
;
1167 nvlist_t
*results
= NULL
;
1174 /* Initialize results */
1178 if ((door_fd
= open(HOTPLUGD_DOOR
, O_RDONLY
)) < 0) {
1179 i_hp_dprintf("i_hp_call_hotplugd: cannot open door (%s)\n",
1184 /* Pack the nvlist of arguments */
1185 if ((rv
= nvlist_pack(args
, &buf
, &len
, NV_ENCODE_NATIVE
, 0)) != 0) {
1186 i_hp_dprintf("i_hp_call_hotplugd: cannot pack arguments (%s)\n",
1191 /* Set the door argument using the packed arguments */
1192 door_arg
.data_ptr
= buf
;
1193 door_arg
.data_size
= len
;
1194 door_arg
.desc_ptr
= NULL
;
1195 door_arg
.desc_num
= 0;
1196 door_arg
.rbuf
= (char *)(uintptr_t)&rv
;
1197 door_arg
.rsize
= sizeof (rv
);
1199 /* Attempt the door call */
1200 if (door_call(door_fd
, &door_arg
) != 0) {
1202 i_hp_dprintf("i_hp_call_hotplugd: door call failed (%s)\n",
1204 (void) close(door_fd
);
1209 /* The arguments are no longer needed */
1213 * If results are not in the original buffer provided,
1214 * then check and process the new results buffer.
1216 if (door_arg
.rbuf
!= (char *)(uintptr_t)&rv
) {
1219 * First check that the buffer is valid. Then check for
1220 * the simple case where a short result code was sent.
1221 * The last case is a packed nvlist was returned, which
1222 * needs to be unpacked.
1224 if ((door_arg
.rbuf
== NULL
) ||
1225 (door_arg
.data_size
< sizeof (rv
))) {
1226 i_hp_dprintf("i_hp_call_hotplugd: invalid results.\n");
1229 } else if (door_arg
.data_size
== sizeof (rv
)) {
1230 rv
= *(int *)(uintptr_t)door_arg
.rbuf
;
1232 } else if ((rv
= nvlist_unpack(door_arg
.rbuf
,
1233 door_arg
.data_size
, &results
, 0)) != 0) {
1234 i_hp_dprintf("i_hp_call_hotplugd: "
1235 "cannot unpack results (%s).\n", strerror(rv
));
1240 /* Unmap the results buffer */
1241 if (door_arg
.rbuf
!= NULL
)
1242 (void) munmap(door_arg
.rbuf
, door_arg
.rsize
);
1245 * In the case of a packed nvlist, notify the daemon
1246 * that it can free the result buffer from its heap.
1248 if ((results
!= NULL
) &&
1249 (nvlist_lookup_uint64(results
, HPD_SEQNUM
, &seqnum
) == 0)) {
1250 door_arg
.data_ptr
= (char *)(uintptr_t)&seqnum
;
1251 door_arg
.data_size
= sizeof (seqnum
);
1252 door_arg
.desc_ptr
= NULL
;
1253 door_arg
.desc_num
= 0;
1254 door_arg
.rbuf
= NULL
;
1256 (void) door_call(door_fd
, &door_arg
);
1257 if (door_arg
.rbuf
!= NULL
)
1258 (void) munmap(door_arg
.rbuf
, door_arg
.rsize
);
1261 *resultsp
= results
;
1264 (void) close(door_fd
);
1271 * Construct an nvlist of arguments for a hotplugd door call.
1274 i_hp_set_args(hp_cmd_t cmd
, const char *path
, const char *connection
,
1275 uint_t flags
, const char *options
, int state
)
1279 /* Allocate a new nvlist */
1280 if (nvlist_alloc(&args
, NV_UNIQUE_NAME_TYPE
, 0) != 0)
1283 /* Add common arguments */
1284 if ((nvlist_add_int32(args
, HPD_CMD
, cmd
) != 0) ||
1285 (nvlist_add_string(args
, HPD_PATH
, path
) != 0)) {
1290 /* Add connection, but only if defined */
1291 if ((connection
!= NULL
) && (connection
[0] != '\0') &&
1292 (nvlist_add_string(args
, HPD_CONNECTION
, connection
) != 0)) {
1297 /* Add flags, but only if defined */
1298 if ((flags
!= 0) && (nvlist_add_uint32(args
, HPD_FLAGS
, flags
) != 0)) {
1303 /* Add options, but only if defined */
1304 if ((options
!= NULL
) &&
1305 (nvlist_add_string(args
, HPD_OPTIONS
, options
) != 0)) {
1310 /* Add state, but only for CHANGESTATE command */
1311 if ((cmd
== HP_CMD_CHANGESTATE
) &&
1312 (nvlist_add_int32(args
, HPD_STATE
, state
) != 0)) {
1321 * i_hp_parse_results()
1323 * Parse out individual fields of an nvlist of results from
1324 * a hotplugd door call.
1327 i_hp_parse_results(nvlist_t
*results
, hp_node_t
*rootp
, char **optionsp
)
1331 /* Parse an information snapshot */
1337 if (nvlist_lookup_byte_array(results
, HPD_INFO
,
1338 (uchar_t
**)&buf
, (uint_t
*)&len
) == 0) {
1339 if ((rv
= hp_unpack(buf
, len
, rootp
)) != 0)
1344 /* Parse a bus private option string */
1349 if ((nvlist_lookup_string(results
, HPD_OPTIONS
, &str
) == 0) &&
1350 ((*optionsp
= strdup(str
)) == NULL
)) {
1355 /* Parse result code of the operation */
1356 if (nvlist_lookup_int32(results
, HPD_STATUS
, &rv
) != 0) {
1357 i_hp_dprintf("i_hp_call_hotplugd: missing status.\n");