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
);
154 free(node
->hp_usage
);
155 if (node
->hp_description
)
156 free(node
->hp_description
);
165 * Walk a graph of hotplug nodes, executing a callback on each node.
168 hp_traverse(hp_node_t root
, void *arg
, int (*hp_callback
)(hp_node_t
, void *arg
))
173 i_hp_dprintf("hp_traverse: root=%p, arg=%p, hp_callback=%p\n",
174 (void *)root
, arg
, (void *)hp_callback
);
176 /* Check arguments */
177 if ((root
== NULL
) || (hp_callback
== NULL
)) {
178 i_hp_dprintf("hp_traverse: invalid arguments.\n");
183 for (node
= root
; node
; node
= node
->hp_sibling
) {
184 rv
= hp_callback(node
, arg
);
186 if (rv
== HP_WALK_TERMINATE
) {
187 i_hp_dprintf("hp_traverse: walk terminated.\n");
188 return (HP_WALK_TERMINATE
);
191 if (node
->hp_child
&& (rv
!= HP_WALK_PRUNECHILD
))
192 if (hp_traverse(node
->hp_child
, arg
, hp_callback
) ==
194 i_hp_dprintf("hp_traverse: walk terminated.\n");
195 return (HP_WALK_TERMINATE
);
198 if (rv
== HP_WALK_PRUNESIBLING
)
208 * Return a node's type.
211 hp_type(hp_node_t node
)
213 i_hp_dprintf("hp_type: node=%p\n", (void *)node
);
216 i_hp_dprintf("hp_type: invalid arguments.\n");
221 return (node
->hp_type
);
227 * Return a node's name.
230 hp_name(hp_node_t node
)
232 i_hp_dprintf("hp_name: node=%p\n", (void *)node
);
235 i_hp_dprintf("hp_name: invalid arguments.\n");
240 if (node
->hp_name
== NULL
) {
241 i_hp_dprintf("hp_name: missing name value.\n");
245 return (node
->hp_name
);
251 * Return a node's current state.
254 hp_state(hp_node_t node
)
256 i_hp_dprintf("hp_state: node=%p\n", (void *)node
);
259 i_hp_dprintf("hp_state: invalid arguments.\n");
264 if ((node
->hp_type
!= HP_NODE_CONNECTOR
) &&
265 (node
->hp_type
!= HP_NODE_PORT
)) {
266 i_hp_dprintf("hp_state: operation not supported.\n");
271 return (node
->hp_state
);
277 * Return a usage description for usage nodes.
280 hp_usage(hp_node_t node
)
282 i_hp_dprintf("hp_usage: node=%p\n", (void *)node
);
285 i_hp_dprintf("hp_usage: invalid arguments.\n");
290 if (node
->hp_type
!= HP_NODE_USAGE
) {
291 i_hp_dprintf("hp_usage: operation not supported.\n");
296 if (node
->hp_usage
== NULL
) {
297 i_hp_dprintf("hp_usage: missing usage value.\n");
301 return (node
->hp_usage
);
307 * Return a type description (e.g. "PCI slot") for connection nodes.
310 hp_description(hp_node_t node
)
312 i_hp_dprintf("hp_description: node=%p\n", (void *)node
);
315 i_hp_dprintf("hp_description: invalid arguments.\n");
320 if ((node
->hp_type
!= HP_NODE_CONNECTOR
) &&
321 (node
->hp_type
!= HP_NODE_PORT
)) {
322 i_hp_dprintf("hp_description: operation not supported.\n");
327 if (node
->hp_description
== NULL
) {
328 i_hp_dprintf("hp_description: missing description value.\n");
332 return (node
->hp_description
);
338 * Return when the state of a connection was last changed.
341 hp_last_change(hp_node_t node
)
343 i_hp_dprintf("hp_last_change: node=%p\n", (void *)node
);
346 i_hp_dprintf("hp_last_change: invalid arguments.\n");
351 if ((node
->hp_type
!= HP_NODE_CONNECTOR
) &&
352 (node
->hp_type
!= HP_NODE_PORT
)) {
353 i_hp_dprintf("hp_last_change: operation not supported.\n");
358 return (node
->hp_last_change
);
364 * Return a node's parent node.
367 hp_parent(hp_node_t node
)
369 i_hp_dprintf("hp_parent: node=%p\n", (void *)node
);
372 i_hp_dprintf("hp_parent: invalid arguments.\n");
377 if (node
->hp_parent
== NULL
) {
378 i_hp_dprintf("hp_parent: node has no parent.\n");
382 return (node
->hp_parent
);
388 * Return a node's first child node.
391 hp_child(hp_node_t node
)
393 i_hp_dprintf("hp_child: node=%p\n", (void *)node
);
396 i_hp_dprintf("hp_child: invalid arguments.\n");
401 if (node
->hp_child
== NULL
) {
402 i_hp_dprintf("hp_child: node has no child.\n");
406 return (node
->hp_child
);
412 * Return a node's next sibling node.
415 hp_sibling(hp_node_t node
)
417 i_hp_dprintf("hp_sibling: node=%p\n", (void *)node
);
420 i_hp_dprintf("hp_sibling: invalid arguments.\n");
425 if (node
->hp_sibling
== NULL
) {
426 i_hp_dprintf("hp_sibling: node has no sibling.\n");
430 return (node
->hp_sibling
);
436 * Return the path (and maybe connection name) of a node.
437 * The caller must supply two buffers, each MAXPATHLEN size.
440 hp_path(hp_node_t node
, char *path
, char *connection
)
442 hp_node_t root
= NULL
;
446 char components
[MAXPATHLEN
];
448 i_hp_dprintf("hp_path: node=%p, path=%p, connection=%p\n", (void *)node
,
449 (void *)path
, (void *)connection
);
451 if ((node
== NULL
) || (path
== NULL
) || (connection
== NULL
)) {
452 i_hp_dprintf("hp_path: invalid arguments.\n");
456 (void) memset(path
, 0, MAXPATHLEN
);
457 (void) memset(connection
, 0, MAXPATHLEN
);
458 (void) memset(components
, 0, MAXPATHLEN
);
460 /* Set 'connection' only for connectors and ports */
461 if ((node
->hp_type
== HP_NODE_CONNECTOR
) ||
462 (node
->hp_type
== HP_NODE_PORT
))
463 (void) strlcpy(connection
, node
->hp_name
, MAXPATHLEN
);
465 /* Trace back to the root node, accumulating components */
466 for (parent
= node
; parent
!= NULL
; parent
= parent
->hp_parent
) {
467 if (parent
->hp_type
== HP_NODE_DEVICE
) {
468 (void) strlcat(components
, "/", MAXPATHLEN
);
469 (void) strlcat(components
, parent
->hp_name
, MAXPATHLEN
);
471 if (parent
->hp_parent
== NULL
)
475 /* Ensure the snapshot actually contains a base path */
476 if (root
->hp_basepath
== NULL
) {
477 i_hp_dprintf("hp_path: missing base pathname.\n");
482 * Construct the path. Start with the base path from the root
483 * node, then append the accumulated components in reverse order.
485 if (strcmp(root
->hp_basepath
, "/") != 0) {
486 (void) strlcat(path
, root
->hp_basepath
, MAXPATHLEN
);
487 if ((root
->hp_type
== HP_NODE_DEVICE
) &&
488 ((s
= strrchr(path
, '/')) != NULL
))
491 for (i
= strlen(components
) - 1; i
>= 0; i
--) {
492 if (components
[i
] == '/') {
493 (void) strlcat(path
, &components
[i
], MAXPATHLEN
);
494 components
[i
] = '\0';
504 * Initiate a state change operation on a node.
507 hp_set_state(hp_node_t node
, uint_t flags
, int state
, hp_node_t
*resultsp
)
509 hp_node_t root
= NULL
;
513 char path
[MAXPATHLEN
];
514 char connection
[MAXPATHLEN
];
516 i_hp_dprintf("hp_set_state: node=%p, flags=0x%x, state=0x%x, "
517 "resultsp=%p\n", (void *)node
, flags
, state
, (void *)resultsp
);
519 /* Check arguments */
520 if ((node
== NULL
) || (resultsp
== NULL
) ||
521 !HP_SET_STATE_FLAGS_VALID(flags
)) {
522 i_hp_dprintf("hp_set_state: invalid arguments.\n");
526 /* Check node type */
527 if ((node
->hp_type
!= HP_NODE_CONNECTOR
) &&
528 (node
->hp_type
!= HP_NODE_PORT
)) {
529 i_hp_dprintf("hp_set_state: operation not supported.\n");
533 /* Check that target state is valid */
535 case DDI_HP_CN_STATE_PRESENT
:
536 case DDI_HP_CN_STATE_POWERED
:
537 case DDI_HP_CN_STATE_ENABLED
:
538 if (node
->hp_type
!= HP_NODE_CONNECTOR
) {
539 i_hp_dprintf("hp_set_state: mismatched target.\n");
543 case DDI_HP_CN_STATE_PORT_PRESENT
:
544 case DDI_HP_CN_STATE_OFFLINE
:
545 case DDI_HP_CN_STATE_ONLINE
:
546 if (node
->hp_type
!= HP_NODE_PORT
) {
547 i_hp_dprintf("hp_set_state: mismatched target.\n");
552 i_hp_dprintf("hp_set_state: invalid target state.\n");
556 /* Get path and connection of specified node */
557 if ((rv
= hp_path(node
, path
, connection
)) != 0)
560 /* Build arguments for door call */
561 if ((args
= i_hp_set_args(HP_CMD_CHANGESTATE
, path
, connection
, flags
,
562 NULL
, state
)) == NULL
)
565 /* Make the door call to hotplugd */
566 rv
= i_hp_call_hotplugd(args
, &results
);
568 /* Arguments no longer needed */
571 /* Parse additional results, if any */
572 if ((rv
== 0) && (results
!= NULL
)) {
573 rv
= i_hp_parse_results(results
, &root
, NULL
);
574 nvlist_free(results
);
585 * Set bus private options on the hotplug connection
586 * indicated by the given hotplug information node.
589 hp_set_private(hp_node_t node
, const char *options
, char **resultsp
)
595 char path
[MAXPATHLEN
];
596 char connection
[MAXPATHLEN
];
598 i_hp_dprintf("hp_set_private: node=%p, options=%p, resultsp=%p\n",
599 (void *)node
, (void *)options
, (void *)resultsp
);
601 /* Check arguments */
602 if ((node
== NULL
) || (options
== NULL
) || (resultsp
== NULL
)) {
603 i_hp_dprintf("hp_set_private: invalid arguments.\n");
607 /* Check node type */
608 if (node
->hp_type
!= HP_NODE_CONNECTOR
) {
609 i_hp_dprintf("hp_set_private: operation not supported.\n");
613 /* Initialize results */
616 /* Get path and connection of specified node */
617 if ((rv
= hp_path(node
, path
, connection
)) != 0)
620 /* Build arguments for door call */
621 if ((args
= i_hp_set_args(HP_CMD_SETPRIVATE
, path
, connection
, 0,
622 options
, 0)) == NULL
)
625 /* Make the door call to hotplugd */
626 rv
= i_hp_call_hotplugd(args
, &results
);
628 /* Arguments no longer needed */
631 /* Parse additional results, if any */
632 if ((rv
== 0) && (results
!= NULL
)) {
633 rv
= i_hp_parse_results(results
, NULL
, &values
);
634 nvlist_free(results
);
645 * Get bus private options on the hotplug connection
646 * indicated by the given hotplug information node.
649 hp_get_private(hp_node_t node
, const char *options
, char **resultsp
)
655 char path
[MAXPATHLEN
];
656 char connection
[MAXPATHLEN
];
658 i_hp_dprintf("hp_get_private: node=%p, options=%p, resultsp=%p\n",
659 (void *)node
, (void *)options
, (void *)resultsp
);
661 /* Check arguments */
662 if ((node
== NULL
) || (options
== NULL
) || (resultsp
== NULL
)) {
663 i_hp_dprintf("hp_get_private: invalid arguments.\n");
667 /* Check node type */
668 if (node
->hp_type
!= HP_NODE_CONNECTOR
) {
669 i_hp_dprintf("hp_get_private: operation not supported.\n");
673 /* Initialize results */
676 /* Get path and connection of specified node */
677 if ((rv
= hp_path(node
, path
, connection
)) != 0)
680 /* Build arguments for door call */
681 if ((args
= i_hp_set_args(HP_CMD_GETPRIVATE
, path
, connection
, 0,
682 options
, 0)) == NULL
)
685 /* Make the door call to hotplugd */
686 rv
= i_hp_call_hotplugd(args
, &results
);
688 /* Arguments no longer needed */
691 /* Parse additional results, if any */
692 if ((rv
== 0) && (results
!= NULL
)) {
693 rv
= i_hp_parse_results(results
, NULL
, &values
);
694 nvlist_free(results
);
705 * Given the root of a hotplug information snapshot, pack
706 * it into a contiguous byte array so that it is suitable
707 * for network transport.
710 hp_pack(hp_node_t root
, char **bufp
, size_t *lenp
)
718 i_hp_dprintf("hp_pack: root=%p, bufp=%p, lenp=%p\n", (void *)root
,
719 (void *)bufp
, (void *)lenp
);
721 if ((root
== NULL
) || (bufp
== NULL
) || (lenp
== NULL
)) {
722 i_hp_dprintf("hp_pack: invalid arguments.\n");
729 if (nvlist_alloc(&nvl
, 0, 0) != 0) {
730 i_hp_dprintf("hp_pack: nvlist_alloc() failed (%s).\n",
735 if (root
->hp_basepath
!= NULL
) {
736 rv
= nvlist_add_string(nvl
, HP_INFO_BASE
, root
->hp_basepath
);
743 for (node
= root
; node
!= NULL
; node
= node
->hp_sibling
) {
744 if ((rv
= i_hp_pack_branch(node
, &buf
, &len
)) == 0) {
745 rv
= nvlist_add_byte_array(nvl
, HP_INFO_BRANCH
,
746 (uchar_t
*)buf
, len
);
757 if ((rv
= nvlist_pack(nvl
, &buf
, &len
, NV_ENCODE_NATIVE
, 0)) == 0) {
770 * Unpack a hotplug information snapshot for normal usage.
773 hp_unpack(char *packed_buf
, size_t packed_len
, hp_node_t
*retp
)
776 hp_node_t root_list
= NULL
;
777 hp_node_t prev_root
= NULL
;
778 nvlist_t
*nvl
= NULL
;
780 char *basepath
= NULL
;
783 i_hp_dprintf("hp_unpack: packed_buf=%p, packed_len=%u, retp=%p\n",
784 (void *)packed_buf
, (uint32_t)packed_len
, (void *)retp
);
786 if ((packed_buf
== NULL
) || (packed_len
== 0) || (retp
== NULL
)) {
787 i_hp_dprintf("hp_unpack: invalid arguments.\n");
791 if ((rv
= nvlist_unpack(packed_buf
, packed_len
, &nvl
, 0)) != 0)
794 if (nvlist_next_nvpair(nvl
, NULL
) == NULL
) {
800 for (nvp
= NULL
; nvp
= nvlist_next_nvpair(nvl
, nvp
); ) {
804 if (strcmp(nvpair_name(nvp
), HP_INFO_BASE
) == 0) {
807 if ((rv
= nvpair_value_string(nvp
, &val_string
)) == 0) {
808 if ((basepath
= strdup(val_string
)) == NULL
)
812 } else if (strcmp(nvpair_name(nvp
), HP_INFO_BRANCH
) == 0) {
816 if ((rv
= nvpair_value_byte_array(nvp
,
817 (uchar_t
**)&buf
, (uint_t
*)&len
)) == 0) {
818 rv
= i_hp_unpack_branch(buf
, len
, NULL
, &root
);
823 prev_root
->hp_sibling
= root
;
841 /* Store the base path in each root node */
843 for (root
= root_list
; root
; root
= root
->hp_sibling
)
844 root
->hp_basepath
= basepath
;
855 * Print debug messages to stderr, but only when the debug flag
856 * (libhotplug_debug) is set.
860 i_hp_dprintf(const char *fmt
, ...)
864 if (libhotplug_debug
) {
866 (void) vfprintf(stderr
, fmt
, ap
);
874 * Pack an individual branch of a hotplug information snapshot.
877 i_hp_pack_branch(hp_node_t root
, char **bufp
, size_t *lenp
)
888 /* Allocate an nvlist for this branch */
889 if (nvlist_alloc(&nvl
, 0, 0) != 0)
892 /* Pack the root of the branch and add it to the nvlist */
893 if ((rv
= i_hp_pack_node(root
, &buf
, &len
)) == 0) {
894 rv
= nvlist_add_byte_array(nvl
, HP_INFO_NODE
,
895 (uchar_t
*)buf
, len
);
903 /* Pack each subordinate branch, and add it to the nvlist */
904 for (child
= root
->hp_child
; child
!= NULL
; child
= child
->hp_sibling
) {
905 if ((rv
= i_hp_pack_branch(child
, &buf
, &len
)) == 0) {
906 rv
= nvlist_add_byte_array(nvl
, HP_INFO_BRANCH
,
907 (uchar_t
*)buf
, len
);
916 /* Pack the resulting nvlist into a single buffer */
919 if ((rv
= nvlist_pack(nvl
, &buf
, &len
, NV_ENCODE_NATIVE
, 0)) == 0) {
924 /* Free the nvlist */
933 * Pack an individual node of a hotplug information snapshot.
936 i_hp_pack_node(hp_node_t node
, char **bufp
, size_t *lenp
)
943 if (nvlist_alloc(&nvl
, 0, 0) != 0)
946 if ((rv
= nvlist_add_uint32(nvl
, HP_INFO_TYPE
,
947 (uint32_t)node
->hp_type
)) != 0)
950 if ((node
->hp_name
) &&
951 ((rv
= nvlist_add_string(nvl
, HP_INFO_NAME
, node
->hp_name
)) != 0))
954 if ((node
->hp_usage
) &&
955 ((rv
= nvlist_add_string(nvl
, HP_INFO_USAGE
, node
->hp_usage
)) != 0))
958 if ((node
->hp_description
) &&
959 ((rv
= nvlist_add_string(nvl
, HP_INFO_DESC
,
960 node
->hp_description
)) != 0))
963 if ((rv
= nvlist_add_uint32(nvl
, HP_INFO_STATE
, node
->hp_state
)) != 0)
966 if ((node
->hp_last_change
!= 0) &&
967 ((rv
= nvlist_add_uint32(nvl
, HP_INFO_TIME
,
968 node
->hp_last_change
)) != 0))
971 if ((rv
= nvlist_pack(nvl
, &buf
, &len
, NV_ENCODE_NATIVE
, 0)) != 0)
987 * i_hp_unpack_branch()
989 * Unpack a branch of hotplug information nodes.
992 i_hp_unpack_branch(char *packed_buf
, size_t packed_len
, hp_node_t parent
,
995 hp_node_t node
= NULL
;
997 hp_node_t prev_child
= NULL
;
998 nvlist_t
*nvl
= NULL
;
1004 /* Initialize results */
1007 /* Unpack the nvlist for this branch */
1008 if ((rv
= nvlist_unpack(packed_buf
, packed_len
, &nvl
, 0)) != 0)
1012 * Unpack the branch. The first item in the nvlist is
1013 * always the root node. And zero or more subordinate
1014 * branches may be packed afterward.
1016 for (nvp
= NULL
; nvp
= nvlist_next_nvpair(nvl
, nvp
); ) {
1021 if (strcmp(nvpair_name(nvp
), HP_INFO_NODE
) == 0) {
1023 /* Check that there is only one root node */
1030 if ((rv
= nvpair_value_byte_array(nvp
, (uchar_t
**)&buf
,
1031 (uint_t
*)&len
)) == 0)
1032 rv
= i_hp_unpack_node(buf
, len
, parent
, &node
);
1039 } else if (strcmp(nvpair_name(nvp
), HP_INFO_BRANCH
) == 0) {
1041 if ((rv
= nvpair_value_byte_array(nvp
, (uchar_t
**)&buf
,
1042 (uint_t
*)&len
)) == 0)
1043 rv
= i_hp_unpack_branch(buf
, len
, node
, &child
);
1052 prev_child
->hp_sibling
= child
;
1054 node
->hp_child
= child
;
1066 * i_hp_unpack_node()
1068 * Unpack an individual hotplug information node.
1071 i_hp_unpack_node(char *buf
, size_t len
, hp_node_t parent
, hp_node_t
*retp
)
1076 uint32_t val_uint32
;
1080 /* Initialize results */
1083 /* Unpack node into an nvlist */
1084 if ((nvlist_unpack(buf
, len
, &nvl
, 0) != 0))
1087 /* Allocate the new node */
1088 if ((node
= (hp_node_t
)calloc(1, sizeof (struct hp_node
))) == NULL
) {
1093 /* Iterate through nvlist, unpacking each field */
1094 for (nvp
= NULL
; nvp
= nvlist_next_nvpair(nvl
, nvp
); ) {
1096 if ((strcmp(nvpair_name(nvp
), HP_INFO_TYPE
) == 0) &&
1097 (nvpair_type(nvp
) == DATA_TYPE_UINT32
)) {
1099 (void) nvpair_value_uint32(nvp
, &val_uint32
);
1100 node
->hp_type
= val_uint32
;
1102 } else if ((strcmp(nvpair_name(nvp
), HP_INFO_NAME
) == 0) &&
1103 (nvpair_type(nvp
) == DATA_TYPE_STRING
)) {
1105 (void) nvpair_value_string(nvp
, &val_string
);
1106 if ((node
->hp_name
= strdup(val_string
)) == NULL
) {
1111 } else if ((strcmp(nvpair_name(nvp
), HP_INFO_STATE
) == 0) &&
1112 (nvpair_type(nvp
) == DATA_TYPE_UINT32
)) {
1114 (void) nvpair_value_uint32(nvp
, &val_uint32
);
1115 node
->hp_state
= val_uint32
;
1117 } else if ((strcmp(nvpair_name(nvp
), HP_INFO_USAGE
) == 0) &&
1118 (nvpair_type(nvp
) == DATA_TYPE_STRING
)) {
1120 (void) nvpair_value_string(nvp
, &val_string
);
1121 if ((node
->hp_usage
= strdup(val_string
)) == NULL
) {
1126 } else if ((strcmp(nvpair_name(nvp
), HP_INFO_DESC
) == 0) &&
1127 (nvpair_type(nvp
) == DATA_TYPE_STRING
)) {
1129 (void) nvpair_value_string(nvp
, &val_string
);
1130 if ((node
->hp_description
= strdup(val_string
))
1136 } else if ((strcmp(nvpair_name(nvp
), HP_INFO_TIME
) == 0) &&
1137 (nvpair_type(nvp
) == DATA_TYPE_UINT32
)) {
1139 (void) nvpair_value_uint32(nvp
, &val_uint32
);
1140 node
->hp_last_change
= (time_t)val_uint32
;
1143 i_hp_dprintf("i_hp_unpack_node: unrecognized: '%s'\n",
1148 /* Unpacked nvlist no longer needed */
1151 /* Check for errors */
1158 node
->hp_parent
= parent
;
1164 * i_hp_call_hotplugd()
1166 * Perform a door call to the hotplug daemon.
1169 i_hp_call_hotplugd(nvlist_t
*args
, nvlist_t
**resultsp
)
1171 door_arg_t door_arg
;
1172 nvlist_t
*results
= NULL
;
1179 /* Initialize results */
1183 if ((door_fd
= open(HOTPLUGD_DOOR
, O_RDONLY
)) < 0) {
1184 i_hp_dprintf("i_hp_call_hotplugd: cannot open door (%s)\n",
1189 /* Pack the nvlist of arguments */
1190 if ((rv
= nvlist_pack(args
, &buf
, &len
, NV_ENCODE_NATIVE
, 0)) != 0) {
1191 i_hp_dprintf("i_hp_call_hotplugd: cannot pack arguments (%s)\n",
1196 /* Set the door argument using the packed arguments */
1197 door_arg
.data_ptr
= buf
;
1198 door_arg
.data_size
= len
;
1199 door_arg
.desc_ptr
= NULL
;
1200 door_arg
.desc_num
= 0;
1201 door_arg
.rbuf
= (char *)(uintptr_t)&rv
;
1202 door_arg
.rsize
= sizeof (rv
);
1204 /* Attempt the door call */
1205 if (door_call(door_fd
, &door_arg
) != 0) {
1207 i_hp_dprintf("i_hp_call_hotplugd: door call failed (%s)\n",
1209 (void) close(door_fd
);
1214 /* The arguments are no longer needed */
1218 * If results are not in the original buffer provided,
1219 * then check and process the new results buffer.
1221 if (door_arg
.rbuf
!= (char *)(uintptr_t)&rv
) {
1224 * First check that the buffer is valid. Then check for
1225 * the simple case where a short result code was sent.
1226 * The last case is a packed nvlist was returned, which
1227 * needs to be unpacked.
1229 if ((door_arg
.rbuf
== NULL
) ||
1230 (door_arg
.data_size
< sizeof (rv
))) {
1231 i_hp_dprintf("i_hp_call_hotplugd: invalid results.\n");
1234 } else if (door_arg
.data_size
== sizeof (rv
)) {
1235 rv
= *(int *)(uintptr_t)door_arg
.rbuf
;
1237 } else if ((rv
= nvlist_unpack(door_arg
.rbuf
,
1238 door_arg
.data_size
, &results
, 0)) != 0) {
1239 i_hp_dprintf("i_hp_call_hotplugd: "
1240 "cannot unpack results (%s).\n", strerror(rv
));
1245 /* Unmap the results buffer */
1246 if (door_arg
.rbuf
!= NULL
)
1247 (void) munmap(door_arg
.rbuf
, door_arg
.rsize
);
1250 * In the case of a packed nvlist, notify the daemon
1251 * that it can free the result buffer from its heap.
1253 if ((results
!= NULL
) &&
1254 (nvlist_lookup_uint64(results
, HPD_SEQNUM
, &seqnum
) == 0)) {
1255 door_arg
.data_ptr
= (char *)(uintptr_t)&seqnum
;
1256 door_arg
.data_size
= sizeof (seqnum
);
1257 door_arg
.desc_ptr
= NULL
;
1258 door_arg
.desc_num
= 0;
1259 door_arg
.rbuf
= NULL
;
1261 (void) door_call(door_fd
, &door_arg
);
1262 if (door_arg
.rbuf
!= NULL
)
1263 (void) munmap(door_arg
.rbuf
, door_arg
.rsize
);
1266 *resultsp
= results
;
1269 (void) close(door_fd
);
1276 * Construct an nvlist of arguments for a hotplugd door call.
1279 i_hp_set_args(hp_cmd_t cmd
, const char *path
, const char *connection
,
1280 uint_t flags
, const char *options
, int state
)
1284 /* Allocate a new nvlist */
1285 if (nvlist_alloc(&args
, NV_UNIQUE_NAME_TYPE
, 0) != 0)
1288 /* Add common arguments */
1289 if ((nvlist_add_int32(args
, HPD_CMD
, cmd
) != 0) ||
1290 (nvlist_add_string(args
, HPD_PATH
, path
) != 0)) {
1295 /* Add connection, but only if defined */
1296 if ((connection
!= NULL
) && (connection
[0] != '\0') &&
1297 (nvlist_add_string(args
, HPD_CONNECTION
, connection
) != 0)) {
1302 /* Add flags, but only if defined */
1303 if ((flags
!= 0) && (nvlist_add_uint32(args
, HPD_FLAGS
, flags
) != 0)) {
1308 /* Add options, but only if defined */
1309 if ((options
!= NULL
) &&
1310 (nvlist_add_string(args
, HPD_OPTIONS
, options
) != 0)) {
1315 /* Add state, but only for CHANGESTATE command */
1316 if ((cmd
== HP_CMD_CHANGESTATE
) &&
1317 (nvlist_add_int32(args
, HPD_STATE
, state
) != 0)) {
1326 * i_hp_parse_results()
1328 * Parse out individual fields of an nvlist of results from
1329 * a hotplugd door call.
1332 i_hp_parse_results(nvlist_t
*results
, hp_node_t
*rootp
, char **optionsp
)
1336 /* Parse an information snapshot */
1342 if (nvlist_lookup_byte_array(results
, HPD_INFO
,
1343 (uchar_t
**)&buf
, (uint_t
*)&len
) == 0) {
1344 if ((rv
= hp_unpack(buf
, len
, rootp
)) != 0)
1349 /* Parse a bus private option string */
1354 if ((nvlist_lookup_string(results
, HPD_OPTIONS
, &str
) == 0) &&
1355 ((*optionsp
= strdup(str
)) == NULL
)) {
1360 /* Parse result code of the operation */
1361 if (nvlist_lookup_int32(results
, HPD_STATUS
, &rv
) != 0) {
1362 i_hp_dprintf("i_hp_call_hotplugd: missing status.\n");