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 2010 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 /*
28 * Some topology creation routines may need to defer completing enumeration
29 * until after the entire PRI graph has been visited. This file includes
30 * the interfaces necessary to permit these routines to do this in a general
31 * way.
32 */
33
34 #include <sys/types.h>
35 #include <sys/time.h>
36 #include <stddef.h>
37 #include <inttypes.h>
38 #include <strings.h>
39 #include <string.h>
40 #include <libuutil.h>
41 #include <libnvpair.h>
42 #include <sys/mdesc.h>
43 #include <fm/topo_mod.h>
44 #include <fm/topo_hc.h>
45 #include "pi_impl.h"
46
47 static uu_list_pool_t *defer_pool = NULL;
48 static uu_list_t *defer_list = NULL;
49
50 struct pi_defernode_s {
51 uu_list_node_t defer_node;
52
53 mde_cookie_t mde_node; /* MDE node index */
54 tnode_t *t_parent; /* Parent topology node */
55 tnode_t *t_node; /* Topo node associated with MDE node */
56 void *private; /* Private data for defer routine */
57
58 pi_deferenum_fn_t *func; /* Defered enumeration routine */
59 };
60 typedef struct pi_defernode_s pi_defernode_t;
61
62 /* Routines to handle the list of topology parents and mde_nodes */
63 static int pi_deferlist_create(topo_mod_t *);
64 static int pi_deferlist_compare(const void *, const void *, void *);
65
66
67 /*
68 * Add a new routine to the list of deferred enumeration routines
69 */
70 int
pi_defer_add(topo_mod_t * mod,mde_cookie_t mde_node,tnode_t * t_parent,tnode_t * t_node,pi_deferenum_fn_t func,void * private)71 pi_defer_add(topo_mod_t *mod, mde_cookie_t mde_node, tnode_t *t_parent,
72 tnode_t *t_node, pi_deferenum_fn_t func, void *private)
73 {
74 int result;
75 uu_list_index_t idx;
76 pi_defernode_t *dnp;
77
78 if (defer_list == NULL) {
79 result = pi_deferlist_create(mod);
80 if (result != 0) {
81 return (result);
82 }
83 }
84
85 /*
86 * Create a data structure to store information about the node for
87 * which to defer enumeration. The defer_pool is created by the
88 * list creation routine, above.
89 */
90 dnp = topo_mod_zalloc(mod, sizeof (pi_defernode_t));
91 if (dnp == NULL) {
92 (void) topo_mod_seterrno(mod, EMOD_NOMEM);
93 return (-1);
94 }
95 uu_list_node_init(dnp, &(dnp->defer_node), defer_pool);
96
97 dnp->mde_node = mde_node;
98 dnp->t_parent = t_parent;
99 dnp->t_node = t_node;
100 dnp->private = private;
101 dnp->func = func;
102
103 (void) uu_list_find(defer_list, dnp, NULL, &idx);
104 uu_list_insert(defer_list, dnp, idx);
105
106 return (0);
107 }
108
109
110 /*
111 * Execute the list of deferred enumeration routines, destroying the list as
112 * we go.
113 */
114 int
pi_defer_exec(topo_mod_t * mod,md_t * mdp)115 pi_defer_exec(topo_mod_t *mod, md_t *mdp)
116 {
117 int result;
118
119 void *dvp;
120 pi_defernode_t *dp;
121 topo_instance_t inst;
122 mde_cookie_t mde_node;
123 tnode_t *t_parent;
124 tnode_t *t_node;
125 void *private;
126 char *hc_name;
127
128 pi_deferenum_fn_t *func;
129
130 topo_mod_dprintf(mod, "beginning deferred enumerator execution\n");
131 if (defer_list == NULL) {
132 topo_mod_dprintf(mod, "no deferred enumerators. done.\n");
133 return (0);
134 }
135
136 while ((dvp = uu_list_first(defer_list)) != NULL) {
137 /* Extract the necessary information from the defernode_t */
138 dp = (pi_defernode_t *)dvp;
139 mde_node = dp->mde_node;
140 t_parent = dp->t_parent;
141 t_node = dp->t_node;
142 private = dp->private;
143 func = dp->func;
144
145 /*
146 * Remove the element from the list. Once we are done calling
147 * the routine we do not need it any more.
148 */
149 uu_list_remove(defer_list, dvp);
150 uu_list_node_fini(dp, &(dp->defer_node), defer_pool);
151 topo_mod_free(mod, dp, sizeof (pi_defernode_t));
152
153 /* Get the instance value from the mde node */
154 if (pi_get_instance(mod, mdp, mde_node, &inst) != 0) {
155 topo_mod_dprintf(mod, "deferred node_0x%llx invalid\n",
156 (uint64_t)mde_node);
157
158 /* Move on to the next node */
159 (void) topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM);
160 continue;
161 }
162
163 /* Get the hc name from the mde node */
164 hc_name = pi_get_topo_hc_name(mod, mdp, mde_node);
165 if (hc_name == NULL) {
166 topo_mod_dprintf(mod,
167 "deferred node_0x%llx has invalid NULL hc_name\n",
168 (uint64_t)mde_node);
169
170 /* Move on to the next node */
171 (void) topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM);
172 continue;
173 }
174 topo_mod_dprintf(mod,
175 "calling deferred enumerator for node_0x%llx\n",
176 (uint64_t)mde_node);
177
178 /* Call the deferred enumeration function */
179 result = (func)(mod, mdp, mde_node, inst, t_parent, hc_name,
180 t_node, private);
181 if (result != 0) {
182 topo_mod_dprintf(mod,
183 "deferred enumeration for node_0x%llx failed\n",
184 (uint64_t)mde_node);
185 (void) topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM);
186 }
187
188 /* Clean up from the deferred call */
189 topo_mod_strfree(mod, hc_name);
190 }
191 topo_mod_dprintf(mod, "deferred enumeration completed.\n");
192
193 uu_list_destroy(defer_list);
194 uu_list_pool_destroy(defer_pool);
195 defer_list = NULL;
196 defer_pool = NULL;
197
198 return (0);
199 }
200
201
202 static int
pi_deferlist_create(topo_mod_t * mod)203 pi_deferlist_create(topo_mod_t *mod)
204 {
205 /* Initialize the uutil list structure */
206 defer_pool = uu_list_pool_create("pi_defer_pool",
207 sizeof (pi_defernode_t), offsetof(pi_defernode_t, defer_node),
208 pi_deferlist_compare, 0);
209 if (defer_pool == NULL) {
210 (void) topo_mod_seterrno(mod, EMOD_NOMEM);
211 return (-1);
212 }
213 defer_list = uu_list_create(defer_pool, NULL, 0);
214 if (defer_list == NULL) {
215 uu_list_pool_destroy(defer_pool);
216 defer_pool = NULL;
217 (void) topo_mod_seterrno(mod, EMOD_NOMEM);
218 return (-1);
219 }
220
221 return (0);
222 }
223
224
225 /* ARGSUSED */
226 static int
pi_deferlist_compare(const void * l_arg,const void * r_arg,void * private)227 pi_deferlist_compare(const void *l_arg, const void *r_arg, void *private)
228 {
229 pi_defernode_t *lp = (pi_defernode_t *)l_arg;
230 pi_defernode_t *rp = (pi_defernode_t *)r_arg;
231
232 if (lp->func != rp->func) {
233 return (1);
234 }
235 if (lp->t_parent != rp->t_parent) {
236 return (-1);
237 }
238 return (0);
239 }
240