xref: /onnv-gate/usr/src/uts/i86pc/io/acpi/drmach_acpi/drmach_acpi.c (revision 12004:93f274d4a367)
1*12004Sjiang.liu@intel.com /*
2*12004Sjiang.liu@intel.com  * CDDL HEADER START
3*12004Sjiang.liu@intel.com  *
4*12004Sjiang.liu@intel.com  * The contents of this file are subject to the terms of the
5*12004Sjiang.liu@intel.com  * Common Development and Distribution License (the "License").
6*12004Sjiang.liu@intel.com  * You may not use this file except in compliance with the License.
7*12004Sjiang.liu@intel.com  *
8*12004Sjiang.liu@intel.com  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*12004Sjiang.liu@intel.com  * or http://www.opensolaris.org/os/licensing.
10*12004Sjiang.liu@intel.com  * See the License for the specific language governing permissions
11*12004Sjiang.liu@intel.com  * and limitations under the License.
12*12004Sjiang.liu@intel.com  *
13*12004Sjiang.liu@intel.com  * When distributing Covered Code, include this CDDL HEADER in each
14*12004Sjiang.liu@intel.com  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*12004Sjiang.liu@intel.com  * If applicable, add the following below this CDDL HEADER, with the
16*12004Sjiang.liu@intel.com  * fields enclosed by brackets "[]" replaced with your own identifying
17*12004Sjiang.liu@intel.com  * information: Portions Copyright [yyyy] [name of copyright owner]
18*12004Sjiang.liu@intel.com  *
19*12004Sjiang.liu@intel.com  * CDDL HEADER END
20*12004Sjiang.liu@intel.com  */
21*12004Sjiang.liu@intel.com /*
22*12004Sjiang.liu@intel.com  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23*12004Sjiang.liu@intel.com  * Use is subject to license terms.
24*12004Sjiang.liu@intel.com  */
25*12004Sjiang.liu@intel.com /*
26*12004Sjiang.liu@intel.com  * Copyright (c) 2010, Intel Corporation.
27*12004Sjiang.liu@intel.com  * All rights reserved.
28*12004Sjiang.liu@intel.com  */
29*12004Sjiang.liu@intel.com 
30*12004Sjiang.liu@intel.com #include <sys/types.h>
31*12004Sjiang.liu@intel.com #include <sys/cmn_err.h>
32*12004Sjiang.liu@intel.com #include <sys/conf.h>
33*12004Sjiang.liu@intel.com #include <sys/debug.h>
34*12004Sjiang.liu@intel.com #include <sys/errno.h>
35*12004Sjiang.liu@intel.com #include <sys/note.h>
36*12004Sjiang.liu@intel.com #include <sys/dditypes.h>
37*12004Sjiang.liu@intel.com #include <sys/ddi.h>
38*12004Sjiang.liu@intel.com #include <sys/sunddi.h>
39*12004Sjiang.liu@intel.com #include <sys/sunndi.h>
40*12004Sjiang.liu@intel.com #include <sys/ddi_impldefs.h>
41*12004Sjiang.liu@intel.com #include <sys/ndi_impldefs.h>
42*12004Sjiang.liu@intel.com #include <sys/varargs.h>
43*12004Sjiang.liu@intel.com #include <sys/modctl.h>
44*12004Sjiang.liu@intel.com #include <sys/kmem.h>
45*12004Sjiang.liu@intel.com #include <sys/cpuvar.h>
46*12004Sjiang.liu@intel.com #include <sys/cpupart.h>
47*12004Sjiang.liu@intel.com #include <sys/mem_config.h>
48*12004Sjiang.liu@intel.com #include <sys/mem_cage.h>
49*12004Sjiang.liu@intel.com #include <sys/memnode.h>
50*12004Sjiang.liu@intel.com #include <sys/callb.h>
51*12004Sjiang.liu@intel.com #include <sys/ontrap.h>
52*12004Sjiang.liu@intel.com #include <sys/obpdefs.h>
53*12004Sjiang.liu@intel.com #include <sys/promif.h>
54*12004Sjiang.liu@intel.com #include <sys/synch.h>
55*12004Sjiang.liu@intel.com #include <sys/systm.h>
56*12004Sjiang.liu@intel.com #include <sys/sysmacros.h>
57*12004Sjiang.liu@intel.com #include <sys/archsystm.h>
58*12004Sjiang.liu@intel.com #include <sys/machsystm.h>
59*12004Sjiang.liu@intel.com #include <sys/x_call.h>
60*12004Sjiang.liu@intel.com #include <sys/x86_archext.h>
61*12004Sjiang.liu@intel.com #include <sys/fastboot_impl.h>
62*12004Sjiang.liu@intel.com #include <sys/sysevent.h>
63*12004Sjiang.liu@intel.com #include <sys/sysevent/dr.h>
64*12004Sjiang.liu@intel.com #include <sys/sysevent/eventdefs.h>
65*12004Sjiang.liu@intel.com #include <sys/acpi/acpi.h>
66*12004Sjiang.liu@intel.com #include <sys/acpica.h>
67*12004Sjiang.liu@intel.com #include <sys/acpidev.h>
68*12004Sjiang.liu@intel.com #include <sys/acpidev_rsc.h>
69*12004Sjiang.liu@intel.com #include <sys/acpidev_dr.h>
70*12004Sjiang.liu@intel.com #include <sys/dr.h>
71*12004Sjiang.liu@intel.com #include <sys/dr_util.h>
72*12004Sjiang.liu@intel.com #include <sys/drmach.h>
73*12004Sjiang.liu@intel.com #include "drmach_acpi.h"
74*12004Sjiang.liu@intel.com 
75*12004Sjiang.liu@intel.com /* utility */
76*12004Sjiang.liu@intel.com #define	MBYTE		(1048576ull)
77*12004Sjiang.liu@intel.com #define	_ptob64(p)	((uint64_t)(p) << PAGESHIFT)
78*12004Sjiang.liu@intel.com #define	_b64top(b)	((pgcnt_t)((b) >> PAGESHIFT))
79*12004Sjiang.liu@intel.com 
80*12004Sjiang.liu@intel.com static int 		drmach_init(void);
81*12004Sjiang.liu@intel.com static void 		drmach_fini(void);
82*12004Sjiang.liu@intel.com static int		drmach_name2type_idx(char *);
83*12004Sjiang.liu@intel.com static sbd_error_t	*drmach_mem_update_lgrp(drmachid_t);
84*12004Sjiang.liu@intel.com 
85*12004Sjiang.liu@intel.com #ifdef DEBUG
86*12004Sjiang.liu@intel.com int drmach_debug = 1;		 /* set to non-zero to enable debug messages */
87*12004Sjiang.liu@intel.com #endif /* DEBUG */
88*12004Sjiang.liu@intel.com 
89*12004Sjiang.liu@intel.com drmach_domain_info_t	 drmach_domain;
90*12004Sjiang.liu@intel.com 
91*12004Sjiang.liu@intel.com static char		*drmach_ie_fmt = "drmach_acpi.c %d";
92*12004Sjiang.liu@intel.com static drmach_array_t	*drmach_boards;
93*12004Sjiang.liu@intel.com 
94*12004Sjiang.liu@intel.com /* rwlock to protect drmach_boards. */
95*12004Sjiang.liu@intel.com static krwlock_t	 drmach_boards_rwlock;
96*12004Sjiang.liu@intel.com 
97*12004Sjiang.liu@intel.com /* rwlock to block out CPR thread. */
98*12004Sjiang.liu@intel.com static krwlock_t	 drmach_cpr_rwlock;
99*12004Sjiang.liu@intel.com 
100*12004Sjiang.liu@intel.com /* CPR callb id. */
101*12004Sjiang.liu@intel.com static callb_id_t	 drmach_cpr_cid;
102*12004Sjiang.liu@intel.com 
103*12004Sjiang.liu@intel.com static struct {
104*12004Sjiang.liu@intel.com 	const char	*name;
105*12004Sjiang.liu@intel.com 	const char	*type;
106*12004Sjiang.liu@intel.com 	sbd_error_t	*(*new)(drmach_device_t *, drmachid_t *);
107*12004Sjiang.liu@intel.com } drmach_name2type[] = {
108*12004Sjiang.liu@intel.com 	{ ACPIDEV_NODE_NAME_CPU,	DRMACH_DEVTYPE_CPU, drmach_cpu_new },
109*12004Sjiang.liu@intel.com 	{ ACPIDEV_NODE_NAME_MEMORY,	DRMACH_DEVTYPE_MEM, drmach_mem_new },
110*12004Sjiang.liu@intel.com 	{ ACPIDEV_NODE_NAME_PCI,	DRMACH_DEVTYPE_PCI, drmach_io_new  },
111*12004Sjiang.liu@intel.com };
112*12004Sjiang.liu@intel.com 
113*12004Sjiang.liu@intel.com /*
114*12004Sjiang.liu@intel.com  * drmach autoconfiguration data structures and interfaces
115*12004Sjiang.liu@intel.com  */
116*12004Sjiang.liu@intel.com static struct modlmisc modlmisc = {
117*12004Sjiang.liu@intel.com 	&mod_miscops,
118*12004Sjiang.liu@intel.com 	"ACPI based DR v1.0"
119*12004Sjiang.liu@intel.com };
120*12004Sjiang.liu@intel.com 
121*12004Sjiang.liu@intel.com static struct modlinkage modlinkage = {
122*12004Sjiang.liu@intel.com 	MODREV_1,
123*12004Sjiang.liu@intel.com 	(void *)&modlmisc,
124*12004Sjiang.liu@intel.com 	NULL
125*12004Sjiang.liu@intel.com };
126*12004Sjiang.liu@intel.com 
127*12004Sjiang.liu@intel.com int
_init(void)128*12004Sjiang.liu@intel.com _init(void)
129*12004Sjiang.liu@intel.com {
130*12004Sjiang.liu@intel.com 	int err;
131*12004Sjiang.liu@intel.com 
132*12004Sjiang.liu@intel.com 	if ((err = drmach_init()) != 0) {
133*12004Sjiang.liu@intel.com 		return (err);
134*12004Sjiang.liu@intel.com 	}
135*12004Sjiang.liu@intel.com 
136*12004Sjiang.liu@intel.com 	if ((err = mod_install(&modlinkage)) != 0) {
137*12004Sjiang.liu@intel.com 		drmach_fini();
138*12004Sjiang.liu@intel.com 	}
139*12004Sjiang.liu@intel.com 
140*12004Sjiang.liu@intel.com 	return (err);
141*12004Sjiang.liu@intel.com }
142*12004Sjiang.liu@intel.com 
143*12004Sjiang.liu@intel.com int
_fini(void)144*12004Sjiang.liu@intel.com _fini(void)
145*12004Sjiang.liu@intel.com {
146*12004Sjiang.liu@intel.com 	int	err;
147*12004Sjiang.liu@intel.com 
148*12004Sjiang.liu@intel.com 	if ((err = mod_remove(&modlinkage)) == 0) {
149*12004Sjiang.liu@intel.com 		drmach_fini();
150*12004Sjiang.liu@intel.com 	}
151*12004Sjiang.liu@intel.com 
152*12004Sjiang.liu@intel.com 	return (err);
153*12004Sjiang.liu@intel.com }
154*12004Sjiang.liu@intel.com 
155*12004Sjiang.liu@intel.com int
_info(struct modinfo * modinfop)156*12004Sjiang.liu@intel.com _info(struct modinfo *modinfop)
157*12004Sjiang.liu@intel.com {
158*12004Sjiang.liu@intel.com 	return (mod_info(&modlinkage, modinfop));
159*12004Sjiang.liu@intel.com }
160*12004Sjiang.liu@intel.com 
161*12004Sjiang.liu@intel.com /*
162*12004Sjiang.liu@intel.com  * Internal support functions.
163*12004Sjiang.liu@intel.com  */
164*12004Sjiang.liu@intel.com static DRMACH_HANDLE
drmach_node_acpi_get_dnode(drmach_node_t * np)165*12004Sjiang.liu@intel.com drmach_node_acpi_get_dnode(drmach_node_t *np)
166*12004Sjiang.liu@intel.com {
167*12004Sjiang.liu@intel.com 	return ((DRMACH_HANDLE)(uintptr_t)np->here);
168*12004Sjiang.liu@intel.com }
169*12004Sjiang.liu@intel.com 
170*12004Sjiang.liu@intel.com static dev_info_t *
drmach_node_acpi_get_dip(drmach_node_t * np)171*12004Sjiang.liu@intel.com drmach_node_acpi_get_dip(drmach_node_t *np)
172*12004Sjiang.liu@intel.com {
173*12004Sjiang.liu@intel.com 	dev_info_t *dip = NULL;
174*12004Sjiang.liu@intel.com 
175*12004Sjiang.liu@intel.com 	if (ACPI_FAILURE(acpica_get_devinfo((DRMACH_HANDLE)(np->here), &dip))) {
176*12004Sjiang.liu@intel.com 		return (NULL);
177*12004Sjiang.liu@intel.com 	}
178*12004Sjiang.liu@intel.com 
179*12004Sjiang.liu@intel.com 	return (dip);
180*12004Sjiang.liu@intel.com }
181*12004Sjiang.liu@intel.com 
182*12004Sjiang.liu@intel.com static int
drmach_node_acpi_get_prop(drmach_node_t * np,char * name,void * buf,int len)183*12004Sjiang.liu@intel.com drmach_node_acpi_get_prop(drmach_node_t *np, char *name, void *buf, int len)
184*12004Sjiang.liu@intel.com {
185*12004Sjiang.liu@intel.com 	int		rv = 0;
186*12004Sjiang.liu@intel.com 	DRMACH_HANDLE	hdl;
187*12004Sjiang.liu@intel.com 
188*12004Sjiang.liu@intel.com 	hdl = np->get_dnode(np);
189*12004Sjiang.liu@intel.com 	if (hdl == NULL) {
190*12004Sjiang.liu@intel.com 		DRMACH_PR("!drmach_node_acpi_get_prop: NULL handle");
191*12004Sjiang.liu@intel.com 		rv = -1;
192*12004Sjiang.liu@intel.com 	} else {
193*12004Sjiang.liu@intel.com 		rv = acpidev_dr_device_getprop(hdl, name, buf, len);
194*12004Sjiang.liu@intel.com 		if (rv >= 0) {
195*12004Sjiang.liu@intel.com 			ASSERT(rv <= len);
196*12004Sjiang.liu@intel.com 			rv = 0;
197*12004Sjiang.liu@intel.com 		}
198*12004Sjiang.liu@intel.com 	}
199*12004Sjiang.liu@intel.com 
200*12004Sjiang.liu@intel.com 	return (rv);
201*12004Sjiang.liu@intel.com }
202*12004Sjiang.liu@intel.com 
203*12004Sjiang.liu@intel.com static int
drmach_node_acpi_get_proplen(drmach_node_t * np,char * name,int * len)204*12004Sjiang.liu@intel.com drmach_node_acpi_get_proplen(drmach_node_t *np, char *name, int *len)
205*12004Sjiang.liu@intel.com {
206*12004Sjiang.liu@intel.com 	int		rv = 0;
207*12004Sjiang.liu@intel.com 	DRMACH_HANDLE	hdl;
208*12004Sjiang.liu@intel.com 
209*12004Sjiang.liu@intel.com 	hdl = np->get_dnode(np);
210*12004Sjiang.liu@intel.com 	if (hdl == NULL) {
211*12004Sjiang.liu@intel.com 		DRMACH_PR("!drmach_node_acpi_get_proplen: NULL handle");
212*12004Sjiang.liu@intel.com 		rv = -1;
213*12004Sjiang.liu@intel.com 	} else {
214*12004Sjiang.liu@intel.com 		rv = acpidev_dr_device_getprop(hdl, name, NULL, 0);
215*12004Sjiang.liu@intel.com 		if (rv >= 0) {
216*12004Sjiang.liu@intel.com 			*len = rv;
217*12004Sjiang.liu@intel.com 			return (0);
218*12004Sjiang.liu@intel.com 		}
219*12004Sjiang.liu@intel.com 	}
220*12004Sjiang.liu@intel.com 
221*12004Sjiang.liu@intel.com 	return (-1);
222*12004Sjiang.liu@intel.com }
223*12004Sjiang.liu@intel.com 
224*12004Sjiang.liu@intel.com static ACPI_STATUS
drmach_node_acpi_callback(ACPI_HANDLE hdl,uint_t lvl,void * ctx,void ** retval)225*12004Sjiang.liu@intel.com drmach_node_acpi_callback(ACPI_HANDLE hdl, uint_t lvl, void *ctx, void **retval)
226*12004Sjiang.liu@intel.com {
227*12004Sjiang.liu@intel.com 	_NOTE(ARGUNUSED(lvl));
228*12004Sjiang.liu@intel.com 
229*12004Sjiang.liu@intel.com 	int rv;
230*12004Sjiang.liu@intel.com 	dev_info_t *dip;
231*12004Sjiang.liu@intel.com 	drmach_node_walk_args_t *argp = ctx;
232*12004Sjiang.liu@intel.com 	int (*cb)(drmach_node_walk_args_t *args);
233*12004Sjiang.liu@intel.com 	acpidev_class_id_t clsid;
234*12004Sjiang.liu@intel.com 
235*12004Sjiang.liu@intel.com 	ASSERT(hdl != NULL);
236*12004Sjiang.liu@intel.com 	ASSERT(ctx != NULL);
237*12004Sjiang.liu@intel.com 	ASSERT(retval != NULL);
238*12004Sjiang.liu@intel.com 
239*12004Sjiang.liu@intel.com 	/* Skip subtree if the device is not powered. */
240*12004Sjiang.liu@intel.com 	if (!acpidev_dr_device_is_powered(hdl)) {
241*12004Sjiang.liu@intel.com 		return (AE_CTRL_DEPTH);
242*12004Sjiang.liu@intel.com 	}
243*12004Sjiang.liu@intel.com 
244*12004Sjiang.liu@intel.com 	/*
245*12004Sjiang.liu@intel.com 	 * Keep scanning subtree if it fails to lookup device node.
246*12004Sjiang.liu@intel.com 	 * There may be some ACPI objects without device nodes created.
247*12004Sjiang.liu@intel.com 	 */
248*12004Sjiang.liu@intel.com 	if (ACPI_FAILURE(acpica_get_devinfo(hdl, &dip))) {
249*12004Sjiang.liu@intel.com 		return (AE_OK);
250*12004Sjiang.liu@intel.com 	}
251*12004Sjiang.liu@intel.com 
252*12004Sjiang.liu@intel.com 	argp->node->here = hdl;
253*12004Sjiang.liu@intel.com 	cb = (int (*)(drmach_node_walk_args_t *args))argp->func;
254*12004Sjiang.liu@intel.com 	rv = (*cb)(argp);
255*12004Sjiang.liu@intel.com 	argp->node->here = NULL;
256*12004Sjiang.liu@intel.com 	if (rv) {
257*12004Sjiang.liu@intel.com 		*(int *)retval = rv;
258*12004Sjiang.liu@intel.com 		return (AE_CTRL_TERMINATE);
259*12004Sjiang.liu@intel.com 	}
260*12004Sjiang.liu@intel.com 
261*12004Sjiang.liu@intel.com 	/*
262*12004Sjiang.liu@intel.com 	 * Skip descendants of PCI/PCIex host bridges.
263*12004Sjiang.liu@intel.com 	 * PCI/PCIex devices will be handled by pcihp.
264*12004Sjiang.liu@intel.com 	 */
265*12004Sjiang.liu@intel.com 	clsid = acpidev_dr_device_get_class(hdl);
266*12004Sjiang.liu@intel.com 	if (clsid == ACPIDEV_CLASS_ID_PCI || clsid == ACPIDEV_CLASS_ID_PCIEX) {
267*12004Sjiang.liu@intel.com 		return (AE_CTRL_DEPTH);
268*12004Sjiang.liu@intel.com 	}
269*12004Sjiang.liu@intel.com 
270*12004Sjiang.liu@intel.com 	return (AE_OK);
271*12004Sjiang.liu@intel.com }
272*12004Sjiang.liu@intel.com 
273*12004Sjiang.liu@intel.com static int
drmach_node_acpi_walk(drmach_node_t * np,void * data,int (* cb)(drmach_node_walk_args_t * args))274*12004Sjiang.liu@intel.com drmach_node_acpi_walk(drmach_node_t *np, void *data,
275*12004Sjiang.liu@intel.com     int (*cb)(drmach_node_walk_args_t *args))
276*12004Sjiang.liu@intel.com {
277*12004Sjiang.liu@intel.com 	DRMACH_HANDLE		hdl;
278*12004Sjiang.liu@intel.com 	int			rv = 0;
279*12004Sjiang.liu@intel.com 	drmach_node_walk_args_t	args;
280*12004Sjiang.liu@intel.com 
281*12004Sjiang.liu@intel.com 	/* initialize the args structure for callback */
282*12004Sjiang.liu@intel.com 	args.node = np;
283*12004Sjiang.liu@intel.com 	args.data = data;
284*12004Sjiang.liu@intel.com 	args.func = (void *)cb;
285*12004Sjiang.liu@intel.com 
286*12004Sjiang.liu@intel.com 	/* save the handle, it will be modified when walking the tree. */
287*12004Sjiang.liu@intel.com 	hdl = np->get_dnode(np);
288*12004Sjiang.liu@intel.com 	if (hdl == NULL) {
289*12004Sjiang.liu@intel.com 		DRMACH_PR("!drmach_node_acpi_walk: failed to get device node.");
290*12004Sjiang.liu@intel.com 		return (EX86_INAPPROP);
291*12004Sjiang.liu@intel.com 	}
292*12004Sjiang.liu@intel.com 
293*12004Sjiang.liu@intel.com 	if (ACPI_FAILURE(acpidev_dr_device_walk_device(hdl,
294*12004Sjiang.liu@intel.com 	    ACPIDEV_MAX_ENUM_LEVELS, drmach_node_acpi_callback,
295*12004Sjiang.liu@intel.com 	    &args, (void *)&rv))) {
296*12004Sjiang.liu@intel.com 		/*
297*12004Sjiang.liu@intel.com 		 * If acpidev_dr_device_walk_device() itself fails, rv won't
298*12004Sjiang.liu@intel.com 		 * be set to suitable error code. Set it here.
299*12004Sjiang.liu@intel.com 		 */
300*12004Sjiang.liu@intel.com 		if (rv == 0) {
301*12004Sjiang.liu@intel.com 			cmn_err(CE_WARN, "!drmach_node_acpi_walk: failed to "
302*12004Sjiang.liu@intel.com 			    "walk ACPI namespace.");
303*12004Sjiang.liu@intel.com 			rv = EX86_ACPIWALK;
304*12004Sjiang.liu@intel.com 		}
305*12004Sjiang.liu@intel.com 	}
306*12004Sjiang.liu@intel.com 
307*12004Sjiang.liu@intel.com 	/* restore the handle to original value after walking the tree. */
308*12004Sjiang.liu@intel.com 	np->here = (void *)hdl;
309*12004Sjiang.liu@intel.com 
310*12004Sjiang.liu@intel.com 	return ((int)rv);
311*12004Sjiang.liu@intel.com }
312*12004Sjiang.liu@intel.com 
313*12004Sjiang.liu@intel.com static drmach_node_t *
drmach_node_new(void)314*12004Sjiang.liu@intel.com drmach_node_new(void)
315*12004Sjiang.liu@intel.com {
316*12004Sjiang.liu@intel.com 	drmach_node_t *np;
317*12004Sjiang.liu@intel.com 
318*12004Sjiang.liu@intel.com 	np = kmem_zalloc(sizeof (drmach_node_t), KM_SLEEP);
319*12004Sjiang.liu@intel.com 
320*12004Sjiang.liu@intel.com 	np->get_dnode = drmach_node_acpi_get_dnode;
321*12004Sjiang.liu@intel.com 	np->getdip = drmach_node_acpi_get_dip;
322*12004Sjiang.liu@intel.com 	np->getproplen = drmach_node_acpi_get_proplen;
323*12004Sjiang.liu@intel.com 	np->getprop = drmach_node_acpi_get_prop;
324*12004Sjiang.liu@intel.com 	np->walk = drmach_node_acpi_walk;
325*12004Sjiang.liu@intel.com 
326*12004Sjiang.liu@intel.com 	return (np);
327*12004Sjiang.liu@intel.com }
328*12004Sjiang.liu@intel.com 
329*12004Sjiang.liu@intel.com static drmachid_t
drmach_node_dup(drmach_node_t * np)330*12004Sjiang.liu@intel.com drmach_node_dup(drmach_node_t *np)
331*12004Sjiang.liu@intel.com {
332*12004Sjiang.liu@intel.com 	drmach_node_t *dup;
333*12004Sjiang.liu@intel.com 
334*12004Sjiang.liu@intel.com 	dup = drmach_node_new();
335*12004Sjiang.liu@intel.com 	dup->here = np->here;
336*12004Sjiang.liu@intel.com 	dup->get_dnode = np->get_dnode;
337*12004Sjiang.liu@intel.com 	dup->getdip = np->getdip;
338*12004Sjiang.liu@intel.com 	dup->getproplen = np->getproplen;
339*12004Sjiang.liu@intel.com 	dup->getprop = np->getprop;
340*12004Sjiang.liu@intel.com 	dup->walk = np->walk;
341*12004Sjiang.liu@intel.com 
342*12004Sjiang.liu@intel.com 	return (dup);
343*12004Sjiang.liu@intel.com }
344*12004Sjiang.liu@intel.com 
345*12004Sjiang.liu@intel.com static void
drmach_node_dispose(drmach_node_t * np)346*12004Sjiang.liu@intel.com drmach_node_dispose(drmach_node_t *np)
347*12004Sjiang.liu@intel.com {
348*12004Sjiang.liu@intel.com 	kmem_free(np, sizeof (*np));
349*12004Sjiang.liu@intel.com }
350*12004Sjiang.liu@intel.com 
351*12004Sjiang.liu@intel.com static int
drmach_node_walk(drmach_node_t * np,void * param,int (* cb)(drmach_node_walk_args_t * args))352*12004Sjiang.liu@intel.com drmach_node_walk(drmach_node_t *np, void *param,
353*12004Sjiang.liu@intel.com 	int (*cb)(drmach_node_walk_args_t *args))
354*12004Sjiang.liu@intel.com {
355*12004Sjiang.liu@intel.com 	return (np->walk(np, param, cb));
356*12004Sjiang.liu@intel.com }
357*12004Sjiang.liu@intel.com 
358*12004Sjiang.liu@intel.com static DRMACH_HANDLE
drmach_node_get_dnode(drmach_node_t * np)359*12004Sjiang.liu@intel.com drmach_node_get_dnode(drmach_node_t *np)
360*12004Sjiang.liu@intel.com {
361*12004Sjiang.liu@intel.com 	return (np->get_dnode(np));
362*12004Sjiang.liu@intel.com }
363*12004Sjiang.liu@intel.com 
364*12004Sjiang.liu@intel.com /*
365*12004Sjiang.liu@intel.com  * drmach_array provides convenient array construction, access,
366*12004Sjiang.liu@intel.com  * bounds checking and array destruction logic.
367*12004Sjiang.liu@intel.com  */
368*12004Sjiang.liu@intel.com static drmach_array_t *
drmach_array_new(uint_t min_index,uint_t max_index)369*12004Sjiang.liu@intel.com drmach_array_new(uint_t min_index, uint_t max_index)
370*12004Sjiang.liu@intel.com {
371*12004Sjiang.liu@intel.com 	drmach_array_t *arr;
372*12004Sjiang.liu@intel.com 
373*12004Sjiang.liu@intel.com 	arr = kmem_zalloc(sizeof (drmach_array_t), KM_SLEEP);
374*12004Sjiang.liu@intel.com 
375*12004Sjiang.liu@intel.com 	arr->arr_sz = (max_index - min_index + 1) * sizeof (void *);
376*12004Sjiang.liu@intel.com 	if (arr->arr_sz > 0) {
377*12004Sjiang.liu@intel.com 		arr->min_index = min_index;
378*12004Sjiang.liu@intel.com 		arr->max_index = max_index;
379*12004Sjiang.liu@intel.com 
380*12004Sjiang.liu@intel.com 		arr->arr = kmem_zalloc(arr->arr_sz, KM_SLEEP);
381*12004Sjiang.liu@intel.com 		return (arr);
382*12004Sjiang.liu@intel.com 	} else {
383*12004Sjiang.liu@intel.com 		kmem_free(arr, sizeof (*arr));
384*12004Sjiang.liu@intel.com 		return (0);
385*12004Sjiang.liu@intel.com 	}
386*12004Sjiang.liu@intel.com }
387*12004Sjiang.liu@intel.com 
388*12004Sjiang.liu@intel.com static int
drmach_array_set(drmach_array_t * arr,uint_t idx,drmachid_t val)389*12004Sjiang.liu@intel.com drmach_array_set(drmach_array_t *arr, uint_t idx, drmachid_t val)
390*12004Sjiang.liu@intel.com {
391*12004Sjiang.liu@intel.com 	if (idx < arr->min_index || idx > arr->max_index)
392*12004Sjiang.liu@intel.com 		return (-1);
393*12004Sjiang.liu@intel.com 	arr->arr[idx - arr->min_index] = val;
394*12004Sjiang.liu@intel.com 	return (0);
395*12004Sjiang.liu@intel.com }
396*12004Sjiang.liu@intel.com 
397*12004Sjiang.liu@intel.com /*
398*12004Sjiang.liu@intel.com  * Get the item with index idx.
399*12004Sjiang.liu@intel.com  * Return 0 with the value stored in val if succeeds, otherwise return -1.
400*12004Sjiang.liu@intel.com  */
401*12004Sjiang.liu@intel.com static int
drmach_array_get(drmach_array_t * arr,uint_t idx,drmachid_t * val)402*12004Sjiang.liu@intel.com drmach_array_get(drmach_array_t *arr, uint_t idx, drmachid_t *val)
403*12004Sjiang.liu@intel.com {
404*12004Sjiang.liu@intel.com 	if (idx < arr->min_index || idx > arr->max_index)
405*12004Sjiang.liu@intel.com 		return (-1);
406*12004Sjiang.liu@intel.com 	*val = arr->arr[idx - arr->min_index];
407*12004Sjiang.liu@intel.com 	return (0);
408*12004Sjiang.liu@intel.com }
409*12004Sjiang.liu@intel.com 
410*12004Sjiang.liu@intel.com static int
drmach_array_first(drmach_array_t * arr,uint_t * idx,drmachid_t * val)411*12004Sjiang.liu@intel.com drmach_array_first(drmach_array_t *arr, uint_t *idx, drmachid_t *val)
412*12004Sjiang.liu@intel.com {
413*12004Sjiang.liu@intel.com 	int rv;
414*12004Sjiang.liu@intel.com 
415*12004Sjiang.liu@intel.com 	*idx = arr->min_index;
416*12004Sjiang.liu@intel.com 	while ((rv = drmach_array_get(arr, *idx, val)) == 0 && *val == NULL)
417*12004Sjiang.liu@intel.com 		*idx += 1;
418*12004Sjiang.liu@intel.com 
419*12004Sjiang.liu@intel.com 	return (rv);
420*12004Sjiang.liu@intel.com }
421*12004Sjiang.liu@intel.com 
422*12004Sjiang.liu@intel.com static int
drmach_array_next(drmach_array_t * arr,uint_t * idx,drmachid_t * val)423*12004Sjiang.liu@intel.com drmach_array_next(drmach_array_t *arr, uint_t *idx, drmachid_t *val)
424*12004Sjiang.liu@intel.com {
425*12004Sjiang.liu@intel.com 	int rv;
426*12004Sjiang.liu@intel.com 
427*12004Sjiang.liu@intel.com 	*idx += 1;
428*12004Sjiang.liu@intel.com 	while ((rv = drmach_array_get(arr, *idx, val)) == 0 && *val == NULL)
429*12004Sjiang.liu@intel.com 		*idx += 1;
430*12004Sjiang.liu@intel.com 
431*12004Sjiang.liu@intel.com 	return (rv);
432*12004Sjiang.liu@intel.com }
433*12004Sjiang.liu@intel.com 
434*12004Sjiang.liu@intel.com static void
drmach_array_dispose(drmach_array_t * arr,void (* disposer)(drmachid_t))435*12004Sjiang.liu@intel.com drmach_array_dispose(drmach_array_t *arr, void (*disposer)(drmachid_t))
436*12004Sjiang.liu@intel.com {
437*12004Sjiang.liu@intel.com 	drmachid_t	val;
438*12004Sjiang.liu@intel.com 	uint_t		idx;
439*12004Sjiang.liu@intel.com 	int		rv;
440*12004Sjiang.liu@intel.com 
441*12004Sjiang.liu@intel.com 	rv = drmach_array_first(arr, &idx, &val);
442*12004Sjiang.liu@intel.com 	while (rv == 0) {
443*12004Sjiang.liu@intel.com 		(*disposer)(val);
444*12004Sjiang.liu@intel.com 		rv = drmach_array_next(arr, &idx, &val);
445*12004Sjiang.liu@intel.com 	}
446*12004Sjiang.liu@intel.com 
447*12004Sjiang.liu@intel.com 	kmem_free(arr->arr, arr->arr_sz);
448*12004Sjiang.liu@intel.com 	kmem_free(arr, sizeof (*arr));
449*12004Sjiang.liu@intel.com }
450*12004Sjiang.liu@intel.com 
451*12004Sjiang.liu@intel.com static drmach_board_t *
drmach_get_board_by_bnum(uint_t bnum)452*12004Sjiang.liu@intel.com drmach_get_board_by_bnum(uint_t bnum)
453*12004Sjiang.liu@intel.com {
454*12004Sjiang.liu@intel.com 	drmachid_t id;
455*12004Sjiang.liu@intel.com 
456*12004Sjiang.liu@intel.com 	if (drmach_array_get(drmach_boards, bnum, &id) == 0)
457*12004Sjiang.liu@intel.com 		return ((drmach_board_t *)id);
458*12004Sjiang.liu@intel.com 	else
459*12004Sjiang.liu@intel.com 		return (NULL);
460*12004Sjiang.liu@intel.com }
461*12004Sjiang.liu@intel.com 
462*12004Sjiang.liu@intel.com sbd_error_t *
drmach_device_new(drmach_node_t * node,drmach_board_t * bp,int portid,drmachid_t * idp)463*12004Sjiang.liu@intel.com drmach_device_new(drmach_node_t *node,
464*12004Sjiang.liu@intel.com 	drmach_board_t *bp, int portid, drmachid_t *idp)
465*12004Sjiang.liu@intel.com {
466*12004Sjiang.liu@intel.com 	int		 i;
467*12004Sjiang.liu@intel.com 	int		 rv;
468*12004Sjiang.liu@intel.com 	drmach_device_t	 proto;
469*12004Sjiang.liu@intel.com 	sbd_error_t	*err;
470*12004Sjiang.liu@intel.com 	char		 name[OBP_MAXDRVNAME];
471*12004Sjiang.liu@intel.com 
472*12004Sjiang.liu@intel.com 	rv = node->getprop(node, ACPIDEV_DR_PROP_DEVNAME, name, OBP_MAXDRVNAME);
473*12004Sjiang.liu@intel.com 	if (rv) {
474*12004Sjiang.liu@intel.com 		/* every node is expected to have a name */
475*12004Sjiang.liu@intel.com 		err = drerr_new(1, EX86_GETPROP, "device node %s: property %s",
476*12004Sjiang.liu@intel.com 		    ddi_node_name(node->getdip(node)),
477*12004Sjiang.liu@intel.com 		    ACPIDEV_DR_PROP_DEVNAME);
478*12004Sjiang.liu@intel.com 		return (err);
479*12004Sjiang.liu@intel.com 	}
480*12004Sjiang.liu@intel.com 
481*12004Sjiang.liu@intel.com 	/*
482*12004Sjiang.liu@intel.com 	 * The node currently being examined is not listed in the name2type[]
483*12004Sjiang.liu@intel.com 	 * array.  In this case, the node is no interest to drmach.  Both
484*12004Sjiang.liu@intel.com 	 * dp and err are initialized here to yield nothing (no device or
485*12004Sjiang.liu@intel.com 	 * error structure) for this case.
486*12004Sjiang.liu@intel.com 	 */
487*12004Sjiang.liu@intel.com 	i = drmach_name2type_idx(name);
488*12004Sjiang.liu@intel.com 	if (i < 0) {
489*12004Sjiang.liu@intel.com 		*idp = (drmachid_t)0;
490*12004Sjiang.liu@intel.com 		return (NULL);
491*12004Sjiang.liu@intel.com 	}
492*12004Sjiang.liu@intel.com 
493*12004Sjiang.liu@intel.com 	/* device specific new function will set unum */
494*12004Sjiang.liu@intel.com 	bzero(&proto, sizeof (proto));
495*12004Sjiang.liu@intel.com 	proto.type = drmach_name2type[i].type;
496*12004Sjiang.liu@intel.com 	proto.bp = bp;
497*12004Sjiang.liu@intel.com 	proto.node = node;
498*12004Sjiang.liu@intel.com 	proto.portid = portid;
499*12004Sjiang.liu@intel.com 
500*12004Sjiang.liu@intel.com 	return (drmach_name2type[i].new(&proto, idp));
501*12004Sjiang.liu@intel.com }
502*12004Sjiang.liu@intel.com 
503*12004Sjiang.liu@intel.com static void
drmach_device_dispose(drmachid_t id)504*12004Sjiang.liu@intel.com drmach_device_dispose(drmachid_t id)
505*12004Sjiang.liu@intel.com {
506*12004Sjiang.liu@intel.com 	drmach_device_t *self = id;
507*12004Sjiang.liu@intel.com 
508*12004Sjiang.liu@intel.com 	self->cm.dispose(id);
509*12004Sjiang.liu@intel.com }
510*12004Sjiang.liu@intel.com 
511*12004Sjiang.liu@intel.com static sbd_error_t *
drmach_device_status(drmachid_t id,drmach_status_t * stat)512*12004Sjiang.liu@intel.com drmach_device_status(drmachid_t id, drmach_status_t *stat)
513*12004Sjiang.liu@intel.com {
514*12004Sjiang.liu@intel.com 	drmach_common_t *cp;
515*12004Sjiang.liu@intel.com 
516*12004Sjiang.liu@intel.com 	if (!DRMACH_IS_ID(id))
517*12004Sjiang.liu@intel.com 		return (drerr_new(0, EX86_NOTID, NULL));
518*12004Sjiang.liu@intel.com 	cp = id;
519*12004Sjiang.liu@intel.com 
520*12004Sjiang.liu@intel.com 	return (cp->status(id, stat));
521*12004Sjiang.liu@intel.com }
522*12004Sjiang.liu@intel.com 
523*12004Sjiang.liu@intel.com drmach_board_t *
drmach_board_new(uint_t bnum,int boot_board)524*12004Sjiang.liu@intel.com drmach_board_new(uint_t bnum, int boot_board)
525*12004Sjiang.liu@intel.com {
526*12004Sjiang.liu@intel.com 	static void drmach_board_dispose(drmachid_t id);
527*12004Sjiang.liu@intel.com 	static sbd_error_t *drmach_board_release(drmachid_t);
528*12004Sjiang.liu@intel.com 	static sbd_error_t *drmach_board_status(drmachid_t, drmach_status_t *);
529*12004Sjiang.liu@intel.com 
530*12004Sjiang.liu@intel.com 	sbd_error_t *err;
531*12004Sjiang.liu@intel.com 	drmach_board_t	*bp;
532*12004Sjiang.liu@intel.com 	dev_info_t *dip = NULL;
533*12004Sjiang.liu@intel.com 
534*12004Sjiang.liu@intel.com 	bp = kmem_zalloc(sizeof (drmach_board_t), KM_SLEEP);
535*12004Sjiang.liu@intel.com 	bp->cm.isa = (void *)drmach_board_new;
536*12004Sjiang.liu@intel.com 	bp->cm.release = drmach_board_release;
537*12004Sjiang.liu@intel.com 	bp->cm.status = drmach_board_status;
538*12004Sjiang.liu@intel.com 
539*12004Sjiang.liu@intel.com 	bp->bnum = bnum;
540*12004Sjiang.liu@intel.com 	bp->devices = NULL;
541*12004Sjiang.liu@intel.com 	bp->tree = drmach_node_new();
542*12004Sjiang.liu@intel.com 
543*12004Sjiang.liu@intel.com 	acpidev_dr_lock_all();
544*12004Sjiang.liu@intel.com 	if (ACPI_FAILURE(acpidev_dr_get_board_handle(bnum, &bp->tree->here))) {
545*12004Sjiang.liu@intel.com 		acpidev_dr_unlock_all();
546*12004Sjiang.liu@intel.com 		drmach_board_dispose(bp);
547*12004Sjiang.liu@intel.com 		return (NULL);
548*12004Sjiang.liu@intel.com 	}
549*12004Sjiang.liu@intel.com 	acpidev_dr_unlock_all();
550*12004Sjiang.liu@intel.com 	ASSERT(bp->tree->here != NULL);
551*12004Sjiang.liu@intel.com 
552*12004Sjiang.liu@intel.com 	err = drmach_board_name(bnum, bp->cm.name, sizeof (bp->cm.name));
553*12004Sjiang.liu@intel.com 	if (err != NULL) {
554*12004Sjiang.liu@intel.com 		sbd_err_clear(&err);
555*12004Sjiang.liu@intel.com 		drmach_board_dispose(bp);
556*12004Sjiang.liu@intel.com 		return (NULL);
557*12004Sjiang.liu@intel.com 	}
558*12004Sjiang.liu@intel.com 
559*12004Sjiang.liu@intel.com 	if (acpidev_dr_device_is_powered(bp->tree->here)) {
560*12004Sjiang.liu@intel.com 		bp->boot_board = boot_board;
561*12004Sjiang.liu@intel.com 		bp->powered = 1;
562*12004Sjiang.liu@intel.com 	} else {
563*12004Sjiang.liu@intel.com 		bp->boot_board = 0;
564*12004Sjiang.liu@intel.com 		bp->powered = 0;
565*12004Sjiang.liu@intel.com 	}
566*12004Sjiang.liu@intel.com 	bp->assigned = boot_board;
567*12004Sjiang.liu@intel.com 	if (ACPI_SUCCESS(acpica_get_devinfo(bp->tree->here, &dip))) {
568*12004Sjiang.liu@intel.com 		bp->connected = 1;
569*12004Sjiang.liu@intel.com 	} else {
570*12004Sjiang.liu@intel.com 		bp->connected = 0;
571*12004Sjiang.liu@intel.com 	}
572*12004Sjiang.liu@intel.com 
573*12004Sjiang.liu@intel.com 	(void) drmach_array_set(drmach_boards, bnum, bp);
574*12004Sjiang.liu@intel.com 
575*12004Sjiang.liu@intel.com 	return (bp);
576*12004Sjiang.liu@intel.com }
577*12004Sjiang.liu@intel.com 
578*12004Sjiang.liu@intel.com static void
drmach_board_dispose(drmachid_t id)579*12004Sjiang.liu@intel.com drmach_board_dispose(drmachid_t id)
580*12004Sjiang.liu@intel.com {
581*12004Sjiang.liu@intel.com 	drmach_board_t *bp;
582*12004Sjiang.liu@intel.com 
583*12004Sjiang.liu@intel.com 	ASSERT(DRMACH_IS_BOARD_ID(id));
584*12004Sjiang.liu@intel.com 	bp = id;
585*12004Sjiang.liu@intel.com 
586*12004Sjiang.liu@intel.com 	if (bp->tree)
587*12004Sjiang.liu@intel.com 		drmach_node_dispose(bp->tree);
588*12004Sjiang.liu@intel.com 
589*12004Sjiang.liu@intel.com 	if (bp->devices)
590*12004Sjiang.liu@intel.com 		drmach_array_dispose(bp->devices, drmach_device_dispose);
591*12004Sjiang.liu@intel.com 
592*12004Sjiang.liu@intel.com 	kmem_free(bp, sizeof (drmach_board_t));
593*12004Sjiang.liu@intel.com }
594*12004Sjiang.liu@intel.com 
595*12004Sjiang.liu@intel.com static sbd_error_t *
drmach_board_release(drmachid_t id)596*12004Sjiang.liu@intel.com drmach_board_release(drmachid_t id)
597*12004Sjiang.liu@intel.com {
598*12004Sjiang.liu@intel.com 	if (!DRMACH_IS_BOARD_ID(id))
599*12004Sjiang.liu@intel.com 		return (drerr_new(0, EX86_INAPPROP, NULL));
600*12004Sjiang.liu@intel.com 
601*12004Sjiang.liu@intel.com 	return (NULL);
602*12004Sjiang.liu@intel.com }
603*12004Sjiang.liu@intel.com 
604*12004Sjiang.liu@intel.com static int
drmach_board_check_power(drmach_board_t * bp)605*12004Sjiang.liu@intel.com drmach_board_check_power(drmach_board_t *bp)
606*12004Sjiang.liu@intel.com {
607*12004Sjiang.liu@intel.com 	DRMACH_HANDLE	hdl;
608*12004Sjiang.liu@intel.com 
609*12004Sjiang.liu@intel.com 	hdl = drmach_node_get_dnode(bp->tree);
610*12004Sjiang.liu@intel.com 
611*12004Sjiang.liu@intel.com 	return (acpidev_dr_device_is_powered(hdl));
612*12004Sjiang.liu@intel.com }
613*12004Sjiang.liu@intel.com 
614*12004Sjiang.liu@intel.com struct drmach_board_list_dep_arg {
615*12004Sjiang.liu@intel.com 	int	count;
616*12004Sjiang.liu@intel.com 	size_t	len;
617*12004Sjiang.liu@intel.com 	ssize_t	off;
618*12004Sjiang.liu@intel.com 	char	*buf;
619*12004Sjiang.liu@intel.com 	char	temp[MAXPATHLEN];
620*12004Sjiang.liu@intel.com };
621*12004Sjiang.liu@intel.com 
622*12004Sjiang.liu@intel.com static ACPI_STATUS
drmach_board_generate_name(ACPI_HANDLE hdl,UINT32 lvl,void * ctx,void ** retval)623*12004Sjiang.liu@intel.com drmach_board_generate_name(ACPI_HANDLE hdl, UINT32 lvl, void *ctx,
624*12004Sjiang.liu@intel.com     void **retval)
625*12004Sjiang.liu@intel.com {
626*12004Sjiang.liu@intel.com 	_NOTE(ARGUNUSED(retval));
627*12004Sjiang.liu@intel.com 
628*12004Sjiang.liu@intel.com 	struct drmach_board_list_dep_arg *argp = ctx;
629*12004Sjiang.liu@intel.com 
630*12004Sjiang.liu@intel.com 	ASSERT(hdl != NULL);
631*12004Sjiang.liu@intel.com 	ASSERT(lvl == UINT32_MAX);
632*12004Sjiang.liu@intel.com 	ASSERT(ctx != NULL);
633*12004Sjiang.liu@intel.com 
634*12004Sjiang.liu@intel.com 	/* Skip non-board devices. */
635*12004Sjiang.liu@intel.com 	if (!acpidev_dr_device_is_board(hdl)) {
636*12004Sjiang.liu@intel.com 		return (AE_OK);
637*12004Sjiang.liu@intel.com 	}
638*12004Sjiang.liu@intel.com 
639*12004Sjiang.liu@intel.com 	if (ACPI_FAILURE(acpidev_dr_get_board_name(hdl, argp->temp,
640*12004Sjiang.liu@intel.com 	    sizeof (argp->temp)))) {
641*12004Sjiang.liu@intel.com 		DRMACH_PR("!drmach_board_generate_name: failed to "
642*12004Sjiang.liu@intel.com 		    "generate board name for handle %p.", hdl);
643*12004Sjiang.liu@intel.com 		/* Keep on walking. */
644*12004Sjiang.liu@intel.com 		return (AE_OK);
645*12004Sjiang.liu@intel.com 	}
646*12004Sjiang.liu@intel.com 	argp->count++;
647*12004Sjiang.liu@intel.com 	argp->off += snprintf(argp->buf + argp->off, argp->len - argp->off,
648*12004Sjiang.liu@intel.com 	    " %s", argp->temp);
649*12004Sjiang.liu@intel.com 	if (argp->off >= argp->len) {
650*12004Sjiang.liu@intel.com 		return (AE_CTRL_TERMINATE);
651*12004Sjiang.liu@intel.com 	}
652*12004Sjiang.liu@intel.com 
653*12004Sjiang.liu@intel.com 	return (AE_OK);
654*12004Sjiang.liu@intel.com }
655*12004Sjiang.liu@intel.com 
656*12004Sjiang.liu@intel.com static ssize_t
drmach_board_list_dependency(ACPI_HANDLE hdl,boolean_t edl,char * prefix,char * buf,size_t len)657*12004Sjiang.liu@intel.com drmach_board_list_dependency(ACPI_HANDLE hdl, boolean_t edl, char *prefix,
658*12004Sjiang.liu@intel.com     char *buf, size_t len)
659*12004Sjiang.liu@intel.com {
660*12004Sjiang.liu@intel.com 	ACPI_STATUS rc;
661*12004Sjiang.liu@intel.com 	ssize_t off;
662*12004Sjiang.liu@intel.com 	struct drmach_board_list_dep_arg *ap;
663*12004Sjiang.liu@intel.com 
664*12004Sjiang.liu@intel.com 	ASSERT(buf != NULL && len != 0);
665*12004Sjiang.liu@intel.com 	if (buf == NULL || len == 0) {
666*12004Sjiang.liu@intel.com 		return (-1);
667*12004Sjiang.liu@intel.com 	}
668*12004Sjiang.liu@intel.com 
669*12004Sjiang.liu@intel.com 	ap = kmem_zalloc(sizeof (*ap), KM_SLEEP);
670*12004Sjiang.liu@intel.com 	ap->buf = buf;
671*12004Sjiang.liu@intel.com 	ap->len = len;
672*12004Sjiang.liu@intel.com 	ap->off = snprintf(buf, len, "%s", prefix);
673*12004Sjiang.liu@intel.com 	if (ap->off >= len) {
674*12004Sjiang.liu@intel.com 		*buf = '\0';
675*12004Sjiang.liu@intel.com 		kmem_free(ap, sizeof (*ap));
676*12004Sjiang.liu@intel.com 		return (-1);
677*12004Sjiang.liu@intel.com 	}
678*12004Sjiang.liu@intel.com 
679*12004Sjiang.liu@intel.com 	/* Generate the device dependency list. */
680*12004Sjiang.liu@intel.com 	if (edl) {
681*12004Sjiang.liu@intel.com 		rc = acpidev_dr_device_walk_edl(hdl,
682*12004Sjiang.liu@intel.com 		    drmach_board_generate_name, ap, NULL);
683*12004Sjiang.liu@intel.com 	} else {
684*12004Sjiang.liu@intel.com 		rc = acpidev_dr_device_walk_ejd(hdl,
685*12004Sjiang.liu@intel.com 		    drmach_board_generate_name, ap, NULL);
686*12004Sjiang.liu@intel.com 	}
687*12004Sjiang.liu@intel.com 	if (ACPI_FAILURE(rc)) {
688*12004Sjiang.liu@intel.com 		*buf = '\0';
689*12004Sjiang.liu@intel.com 		ap->off = -1;
690*12004Sjiang.liu@intel.com 	/* No device has dependency on this board. */
691*12004Sjiang.liu@intel.com 	} else if (ap->count == 0) {
692*12004Sjiang.liu@intel.com 		*buf = '\0';
693*12004Sjiang.liu@intel.com 		ap->off = 0;
694*12004Sjiang.liu@intel.com 	}
695*12004Sjiang.liu@intel.com 
696*12004Sjiang.liu@intel.com 	off = ap->off;
697*12004Sjiang.liu@intel.com 	kmem_free(ap, sizeof (*ap));
698*12004Sjiang.liu@intel.com 
699*12004Sjiang.liu@intel.com 	return (off);
700*12004Sjiang.liu@intel.com }
701*12004Sjiang.liu@intel.com 
702*12004Sjiang.liu@intel.com static sbd_error_t *
drmach_board_status(drmachid_t id,drmach_status_t * stat)703*12004Sjiang.liu@intel.com drmach_board_status(drmachid_t id, drmach_status_t *stat)
704*12004Sjiang.liu@intel.com {
705*12004Sjiang.liu@intel.com 	sbd_error_t	*err = NULL;
706*12004Sjiang.liu@intel.com 	drmach_board_t	*bp;
707*12004Sjiang.liu@intel.com 	DRMACH_HANDLE	hdl;
708*12004Sjiang.liu@intel.com 	size_t		off;
709*12004Sjiang.liu@intel.com 
710*12004Sjiang.liu@intel.com 	if (!DRMACH_IS_BOARD_ID(id))
711*12004Sjiang.liu@intel.com 		return (drerr_new(0, EX86_INAPPROP, NULL));
712*12004Sjiang.liu@intel.com 	bp = id;
713*12004Sjiang.liu@intel.com 
714*12004Sjiang.liu@intel.com 	if (bp->tree == NULL)
715*12004Sjiang.liu@intel.com 		return (drerr_new(0, EX86_INAPPROP, NULL));
716*12004Sjiang.liu@intel.com 	hdl = drmach_node_get_dnode(bp->tree);
717*12004Sjiang.liu@intel.com 	if (hdl == NULL)
718*12004Sjiang.liu@intel.com 		return (drerr_new(0, EX86_INAPPROP, NULL));
719*12004Sjiang.liu@intel.com 
720*12004Sjiang.liu@intel.com 	stat->busy = 0;			/* assume not busy */
721*12004Sjiang.liu@intel.com 	stat->configured = 0;		/* assume not configured */
722*12004Sjiang.liu@intel.com 	stat->assigned = bp->assigned;
723*12004Sjiang.liu@intel.com 	stat->powered = bp->powered = acpidev_dr_device_is_powered(hdl);
724*12004Sjiang.liu@intel.com 	stat->empty = !acpidev_dr_device_is_present(hdl);
725*12004Sjiang.liu@intel.com 	if (ACPI_SUCCESS(acpidev_dr_device_check_status(hdl))) {
726*12004Sjiang.liu@intel.com 		stat->cond = bp->cond = SBD_COND_OK;
727*12004Sjiang.liu@intel.com 	} else {
728*12004Sjiang.liu@intel.com 		stat->cond = bp->cond = SBD_COND_FAILED;
729*12004Sjiang.liu@intel.com 	}
730*12004Sjiang.liu@intel.com 	stat->info[0] = '\0';
731*12004Sjiang.liu@intel.com 
732*12004Sjiang.liu@intel.com 	/* Generate the eject device list. */
733*12004Sjiang.liu@intel.com 	if (drmach_board_list_dependency(hdl, B_TRUE, "EDL:",
734*12004Sjiang.liu@intel.com 	    stat->info, sizeof (stat->info)) < 0) {
735*12004Sjiang.liu@intel.com 		DRMACH_PR("!drmach_board_status: failed to generate "
736*12004Sjiang.liu@intel.com 		    "eject device list for board %d.", bp->bnum);
737*12004Sjiang.liu@intel.com 		stat->info[0] = '\0';
738*12004Sjiang.liu@intel.com 	}
739*12004Sjiang.liu@intel.com 	off = strlen(stat->info);
740*12004Sjiang.liu@intel.com 	if (off < sizeof (stat->info)) {
741*12004Sjiang.liu@intel.com 		if (drmach_board_list_dependency(hdl, B_FALSE,
742*12004Sjiang.liu@intel.com 		    off ? ", EJD:" : "EJD:",
743*12004Sjiang.liu@intel.com 		    stat->info + off, sizeof (stat->info) - off) < 0) {
744*12004Sjiang.liu@intel.com 			DRMACH_PR("!drmach_board_status: failed to generate "
745*12004Sjiang.liu@intel.com 			    "eject dependent device for board %d.", bp->bnum);
746*12004Sjiang.liu@intel.com 			stat->info[off] = '\0';
747*12004Sjiang.liu@intel.com 		}
748*12004Sjiang.liu@intel.com 	}
749*12004Sjiang.liu@intel.com 
750*12004Sjiang.liu@intel.com 	switch (acpidev_dr_get_board_type(bp->tree->get_dnode(bp->tree))) {
751*12004Sjiang.liu@intel.com 	case ACPIDEV_CPU_BOARD:
752*12004Sjiang.liu@intel.com 		(void) strlcpy(stat->type, "CPU Board", sizeof (stat->type));
753*12004Sjiang.liu@intel.com 		break;
754*12004Sjiang.liu@intel.com 	case ACPIDEV_MEMORY_BOARD:
755*12004Sjiang.liu@intel.com 		(void) strlcpy(stat->type, "MemoryBoard", sizeof (stat->type));
756*12004Sjiang.liu@intel.com 		break;
757*12004Sjiang.liu@intel.com 	case ACPIDEV_IO_BOARD:
758*12004Sjiang.liu@intel.com 		(void) strlcpy(stat->type, "IO Board", sizeof (stat->type));
759*12004Sjiang.liu@intel.com 		break;
760*12004Sjiang.liu@intel.com 	case ACPIDEV_SYSTEM_BOARD:
761*12004Sjiang.liu@intel.com 		/*FALLTHROUGH*/
762*12004Sjiang.liu@intel.com 	default:
763*12004Sjiang.liu@intel.com 		(void) strlcpy(stat->type, "SystemBoard", sizeof (stat->type));
764*12004Sjiang.liu@intel.com 		break;
765*12004Sjiang.liu@intel.com 	}
766*12004Sjiang.liu@intel.com 
767*12004Sjiang.liu@intel.com 	if (bp->devices) {
768*12004Sjiang.liu@intel.com 		int		 rv;
769*12004Sjiang.liu@intel.com 		uint_t		 d_idx;
770*12004Sjiang.liu@intel.com 		drmachid_t	 d_id;
771*12004Sjiang.liu@intel.com 
772*12004Sjiang.liu@intel.com 		rv = drmach_array_first(bp->devices, &d_idx, &d_id);
773*12004Sjiang.liu@intel.com 		while (rv == 0) {
774*12004Sjiang.liu@intel.com 			drmach_status_t	d_stat;
775*12004Sjiang.liu@intel.com 
776*12004Sjiang.liu@intel.com 			err = drmach_device_status(d_id, &d_stat);
777*12004Sjiang.liu@intel.com 			if (err)
778*12004Sjiang.liu@intel.com 				break;
779*12004Sjiang.liu@intel.com 
780*12004Sjiang.liu@intel.com 			stat->busy |= d_stat.busy;
781*12004Sjiang.liu@intel.com 			stat->configured |= d_stat.configured;
782*12004Sjiang.liu@intel.com 
783*12004Sjiang.liu@intel.com 			rv = drmach_array_next(bp->devices, &d_idx, &d_id);
784*12004Sjiang.liu@intel.com 		}
785*12004Sjiang.liu@intel.com 	}
786*12004Sjiang.liu@intel.com 
787*12004Sjiang.liu@intel.com 	return (err);
788*12004Sjiang.liu@intel.com }
789*12004Sjiang.liu@intel.com 
790*12004Sjiang.liu@intel.com /*
791*12004Sjiang.liu@intel.com  * When DR is initialized, we walk the device tree and acquire a hold on
792*12004Sjiang.liu@intel.com  * all the nodes that are interesting to DR. This is so that the corresponding
793*12004Sjiang.liu@intel.com  * branches cannot be deleted.
794*12004Sjiang.liu@intel.com  */
795*12004Sjiang.liu@intel.com static int
drmach_hold_rele_devtree(dev_info_t * rdip,void * arg)796*12004Sjiang.liu@intel.com drmach_hold_rele_devtree(dev_info_t *rdip, void *arg)
797*12004Sjiang.liu@intel.com {
798*12004Sjiang.liu@intel.com 	int *holdp = (int *)arg;
799*12004Sjiang.liu@intel.com 	ACPI_HANDLE hdl = NULL;
800*12004Sjiang.liu@intel.com 	acpidev_data_handle_t dhdl;
801*12004Sjiang.liu@intel.com 
802*12004Sjiang.liu@intel.com 	/* Skip nodes and subtrees which are not created by acpidev. */
803*12004Sjiang.liu@intel.com 	if (ACPI_FAILURE(acpica_get_handle(rdip, &hdl))) {
804*12004Sjiang.liu@intel.com 		return (DDI_WALK_PRUNECHILD);
805*12004Sjiang.liu@intel.com 	}
806*12004Sjiang.liu@intel.com 	ASSERT(hdl != NULL);
807*12004Sjiang.liu@intel.com 	dhdl = acpidev_data_get_handle(hdl);
808*12004Sjiang.liu@intel.com 	if (dhdl == NULL) {
809*12004Sjiang.liu@intel.com 		return (DDI_WALK_PRUNECHILD);
810*12004Sjiang.liu@intel.com 	}
811*12004Sjiang.liu@intel.com 
812*12004Sjiang.liu@intel.com 	/* Hold/release devices which are interesting to DR operations. */
813*12004Sjiang.liu@intel.com 	if (acpidev_data_dr_ready(dhdl)) {
814*12004Sjiang.liu@intel.com 		if (*holdp) {
815*12004Sjiang.liu@intel.com 			ASSERT(!e_ddi_branch_held(rdip));
816*12004Sjiang.liu@intel.com 			e_ddi_branch_hold(rdip);
817*12004Sjiang.liu@intel.com 		} else {
818*12004Sjiang.liu@intel.com 			ASSERT(e_ddi_branch_held(rdip));
819*12004Sjiang.liu@intel.com 			e_ddi_branch_rele(rdip);
820*12004Sjiang.liu@intel.com 		}
821*12004Sjiang.liu@intel.com 	}
822*12004Sjiang.liu@intel.com 
823*12004Sjiang.liu@intel.com 	return (DDI_WALK_CONTINUE);
824*12004Sjiang.liu@intel.com }
825*12004Sjiang.liu@intel.com 
826*12004Sjiang.liu@intel.com static void
drmach_hold_devtree(void)827*12004Sjiang.liu@intel.com drmach_hold_devtree(void)
828*12004Sjiang.liu@intel.com {
829*12004Sjiang.liu@intel.com 	dev_info_t *dip;
830*12004Sjiang.liu@intel.com 	int circ;
831*12004Sjiang.liu@intel.com 	int hold = 1;
832*12004Sjiang.liu@intel.com 
833*12004Sjiang.liu@intel.com 	dip = ddi_root_node();
834*12004Sjiang.liu@intel.com 	ndi_devi_enter(dip, &circ);
835*12004Sjiang.liu@intel.com 	ddi_walk_devs(ddi_get_child(dip), drmach_hold_rele_devtree, &hold);
836*12004Sjiang.liu@intel.com 	ndi_devi_exit(dip, circ);
837*12004Sjiang.liu@intel.com }
838*12004Sjiang.liu@intel.com 
839*12004Sjiang.liu@intel.com static void
drmach_release_devtree(void)840*12004Sjiang.liu@intel.com drmach_release_devtree(void)
841*12004Sjiang.liu@intel.com {
842*12004Sjiang.liu@intel.com 	dev_info_t *dip;
843*12004Sjiang.liu@intel.com 	int circ;
844*12004Sjiang.liu@intel.com 	int hold = 0;
845*12004Sjiang.liu@intel.com 
846*12004Sjiang.liu@intel.com 	dip = ddi_root_node();
847*12004Sjiang.liu@intel.com 	ndi_devi_enter(dip, &circ);
848*12004Sjiang.liu@intel.com 	ddi_walk_devs(ddi_get_child(dip), drmach_hold_rele_devtree, &hold);
849*12004Sjiang.liu@intel.com 	ndi_devi_exit(dip, circ);
850*12004Sjiang.liu@intel.com }
851*12004Sjiang.liu@intel.com 
852*12004Sjiang.liu@intel.com static boolean_t
drmach_cpr_callb(void * arg,int code)853*12004Sjiang.liu@intel.com drmach_cpr_callb(void *arg, int code)
854*12004Sjiang.liu@intel.com {
855*12004Sjiang.liu@intel.com 	_NOTE(ARGUNUSED(arg));
856*12004Sjiang.liu@intel.com 
857*12004Sjiang.liu@intel.com 	if (code == CB_CODE_CPR_CHKPT) {
858*12004Sjiang.liu@intel.com 		/*
859*12004Sjiang.liu@intel.com 		 * Temporarily block CPR operations if there are DR operations
860*12004Sjiang.liu@intel.com 		 * ongoing.
861*12004Sjiang.liu@intel.com 		 */
862*12004Sjiang.liu@intel.com 		rw_enter(&drmach_cpr_rwlock, RW_WRITER);
863*12004Sjiang.liu@intel.com 	} else {
864*12004Sjiang.liu@intel.com 		rw_exit(&drmach_cpr_rwlock);
865*12004Sjiang.liu@intel.com 	}
866*12004Sjiang.liu@intel.com 
867*12004Sjiang.liu@intel.com 	return (B_TRUE);
868*12004Sjiang.liu@intel.com }
869*12004Sjiang.liu@intel.com 
870*12004Sjiang.liu@intel.com static int
drmach_init(void)871*12004Sjiang.liu@intel.com drmach_init(void)
872*12004Sjiang.liu@intel.com {
873*12004Sjiang.liu@intel.com 	DRMACH_HANDLE	hdl;
874*12004Sjiang.liu@intel.com 	drmachid_t	id;
875*12004Sjiang.liu@intel.com 	uint_t		bnum;
876*12004Sjiang.liu@intel.com 
877*12004Sjiang.liu@intel.com 	if (MAX_BOARDS > SHRT_MAX) {
878*12004Sjiang.liu@intel.com 		cmn_err(CE_WARN, "!drmach_init: system has too many (%d) "
879*12004Sjiang.liu@intel.com 		    "hotplug capable boards.", MAX_BOARDS);
880*12004Sjiang.liu@intel.com 		return (ENXIO);
881*12004Sjiang.liu@intel.com 	} else if (MAX_CMP_UNITS_PER_BOARD > 1) {
882*12004Sjiang.liu@intel.com 		cmn_err(CE_WARN, "!drmach_init: DR doesn't support multiple "
883*12004Sjiang.liu@intel.com 		    "(%d) physical processors on one board.",
884*12004Sjiang.liu@intel.com 		    MAX_CMP_UNITS_PER_BOARD);
885*12004Sjiang.liu@intel.com 		return (ENXIO);
886*12004Sjiang.liu@intel.com 	} else if (MAX_CORES_PER_CMP & (MAX_CORES_PER_CMP - 1)) {
887*12004Sjiang.liu@intel.com 		cmn_err(CE_WARN, "!drmach_init: number of logical CPUs (%d) in "
888*12004Sjiang.liu@intel.com 		    "physical processor is not power of 2.",
889*12004Sjiang.liu@intel.com 		    MAX_CORES_PER_CMP);
890*12004Sjiang.liu@intel.com 		return (ENXIO);
891*12004Sjiang.liu@intel.com 	} else if (MAX_CPU_UNITS_PER_BOARD > DEVSET_CPU_NUMBER ||
892*12004Sjiang.liu@intel.com 	    MAX_MEM_UNITS_PER_BOARD > DEVSET_MEM_NUMBER ||
893*12004Sjiang.liu@intel.com 	    MAX_IO_UNITS_PER_BOARD > DEVSET_IO_NUMBER) {
894*12004Sjiang.liu@intel.com 		cmn_err(CE_WARN, "!drmach_init: system has more CPU/memory/IO "
895*12004Sjiang.liu@intel.com 		    "units than the DR driver can handle.");
896*12004Sjiang.liu@intel.com 		return (ENXIO);
897*12004Sjiang.liu@intel.com 	}
898*12004Sjiang.liu@intel.com 
899*12004Sjiang.liu@intel.com 	rw_init(&drmach_cpr_rwlock, NULL, RW_DEFAULT, NULL);
900*12004Sjiang.liu@intel.com 	drmach_cpr_cid = callb_add(drmach_cpr_callb, NULL,
901*12004Sjiang.liu@intel.com 	    CB_CL_CPR_PM, "drmach");
902*12004Sjiang.liu@intel.com 
903*12004Sjiang.liu@intel.com 	rw_init(&drmach_boards_rwlock, NULL, RW_DEFAULT, NULL);
904*12004Sjiang.liu@intel.com 	drmach_boards = drmach_array_new(0, MAX_BOARDS - 1);
905*12004Sjiang.liu@intel.com 	drmach_domain.allow_dr = acpidev_dr_capable();
906*12004Sjiang.liu@intel.com 
907*12004Sjiang.liu@intel.com 	for (bnum = 0; bnum < MAX_BOARDS; bnum++) {
908*12004Sjiang.liu@intel.com 		hdl = NULL;
909*12004Sjiang.liu@intel.com 		if (ACPI_FAILURE(acpidev_dr_get_board_handle(bnum, &hdl)) ||
910*12004Sjiang.liu@intel.com 		    hdl == NULL) {
911*12004Sjiang.liu@intel.com 			cmn_err(CE_WARN, "!drmach_init: failed to lookup ACPI "
912*12004Sjiang.liu@intel.com 			    "handle for board %d.", bnum);
913*12004Sjiang.liu@intel.com 			continue;
914*12004Sjiang.liu@intel.com 		}
915*12004Sjiang.liu@intel.com 		if (drmach_array_get(drmach_boards, bnum, &id) == -1) {
916*12004Sjiang.liu@intel.com 			DRMACH_PR("!drmach_init: failed to get handle "
917*12004Sjiang.liu@intel.com 			    "for board %d.", bnum);
918*12004Sjiang.liu@intel.com 			ASSERT(0);
919*12004Sjiang.liu@intel.com 			goto error;
920*12004Sjiang.liu@intel.com 		} else if (id == NULL) {
921*12004Sjiang.liu@intel.com 			(void) drmach_board_new(bnum, 1);
922*12004Sjiang.liu@intel.com 		}
923*12004Sjiang.liu@intel.com 	}
924*12004Sjiang.liu@intel.com 
925*12004Sjiang.liu@intel.com 	/*
926*12004Sjiang.liu@intel.com 	 * Walk descendants of the devinfo root node and hold
927*12004Sjiang.liu@intel.com 	 * all devinfo branches of interest.
928*12004Sjiang.liu@intel.com 	 */
929*12004Sjiang.liu@intel.com 	drmach_hold_devtree();
930*12004Sjiang.liu@intel.com 
931*12004Sjiang.liu@intel.com 	return (0);
932*12004Sjiang.liu@intel.com 
933*12004Sjiang.liu@intel.com error:
934*12004Sjiang.liu@intel.com 	drmach_array_dispose(drmach_boards, drmach_board_dispose);
935*12004Sjiang.liu@intel.com 	rw_destroy(&drmach_boards_rwlock);
936*12004Sjiang.liu@intel.com 	rw_destroy(&drmach_cpr_rwlock);
937*12004Sjiang.liu@intel.com 	return (ENXIO);
938*12004Sjiang.liu@intel.com }
939*12004Sjiang.liu@intel.com 
940*12004Sjiang.liu@intel.com static void
drmach_fini(void)941*12004Sjiang.liu@intel.com drmach_fini(void)
942*12004Sjiang.liu@intel.com {
943*12004Sjiang.liu@intel.com 	rw_enter(&drmach_boards_rwlock, RW_WRITER);
944*12004Sjiang.liu@intel.com 	if (drmach_boards != NULL) {
945*12004Sjiang.liu@intel.com 		drmach_array_dispose(drmach_boards, drmach_board_dispose);
946*12004Sjiang.liu@intel.com 		drmach_boards = NULL;
947*12004Sjiang.liu@intel.com 	}
948*12004Sjiang.liu@intel.com 	rw_exit(&drmach_boards_rwlock);
949*12004Sjiang.liu@intel.com 
950*12004Sjiang.liu@intel.com 	/*
951*12004Sjiang.liu@intel.com 	 * Walk descendants of the root devinfo node
952*12004Sjiang.liu@intel.com 	 * release holds acquired on branches in drmach_init()
953*12004Sjiang.liu@intel.com 	 */
954*12004Sjiang.liu@intel.com 	drmach_release_devtree();
955*12004Sjiang.liu@intel.com 
956*12004Sjiang.liu@intel.com 	(void) callb_delete(drmach_cpr_cid);
957*12004Sjiang.liu@intel.com 	rw_destroy(&drmach_cpr_rwlock);
958*12004Sjiang.liu@intel.com 	rw_destroy(&drmach_boards_rwlock);
959*12004Sjiang.liu@intel.com }
960*12004Sjiang.liu@intel.com 
961*12004Sjiang.liu@intel.com sbd_error_t *
drmach_io_new(drmach_device_t * proto,drmachid_t * idp)962*12004Sjiang.liu@intel.com drmach_io_new(drmach_device_t *proto, drmachid_t *idp)
963*12004Sjiang.liu@intel.com {
964*12004Sjiang.liu@intel.com 	static void drmach_io_dispose(drmachid_t);
965*12004Sjiang.liu@intel.com 	static sbd_error_t *drmach_io_release(drmachid_t);
966*12004Sjiang.liu@intel.com 	static sbd_error_t *drmach_io_status(drmachid_t, drmach_status_t *);
967*12004Sjiang.liu@intel.com 
968*12004Sjiang.liu@intel.com 	drmach_io_t	*ip;
969*12004Sjiang.liu@intel.com 	int		portid;
970*12004Sjiang.liu@intel.com 
971*12004Sjiang.liu@intel.com 	portid = proto->portid;
972*12004Sjiang.liu@intel.com 	ASSERT(portid != -1);
973*12004Sjiang.liu@intel.com 	proto->unum = portid;
974*12004Sjiang.liu@intel.com 
975*12004Sjiang.liu@intel.com 	ip = kmem_zalloc(sizeof (drmach_io_t), KM_SLEEP);
976*12004Sjiang.liu@intel.com 	bcopy(proto, &ip->dev, sizeof (ip->dev));
977*12004Sjiang.liu@intel.com 	ip->dev.node = drmach_node_dup(proto->node);
978*12004Sjiang.liu@intel.com 	ip->dev.cm.isa = (void *)drmach_io_new;
979*12004Sjiang.liu@intel.com 	ip->dev.cm.dispose = drmach_io_dispose;
980*12004Sjiang.liu@intel.com 	ip->dev.cm.release = drmach_io_release;
981*12004Sjiang.liu@intel.com 	ip->dev.cm.status = drmach_io_status;
982*12004Sjiang.liu@intel.com 	(void) snprintf(ip->dev.cm.name, sizeof (ip->dev.cm.name), "%s%d",
983*12004Sjiang.liu@intel.com 	    ip->dev.type, ip->dev.unum);
984*12004Sjiang.liu@intel.com 
985*12004Sjiang.liu@intel.com 	*idp = (drmachid_t)ip;
986*12004Sjiang.liu@intel.com 
987*12004Sjiang.liu@intel.com 	return (NULL);
988*12004Sjiang.liu@intel.com }
989*12004Sjiang.liu@intel.com 
990*12004Sjiang.liu@intel.com static void
drmach_io_dispose(drmachid_t id)991*12004Sjiang.liu@intel.com drmach_io_dispose(drmachid_t id)
992*12004Sjiang.liu@intel.com {
993*12004Sjiang.liu@intel.com 	drmach_io_t *self;
994*12004Sjiang.liu@intel.com 
995*12004Sjiang.liu@intel.com 	ASSERT(DRMACH_IS_IO_ID(id));
996*12004Sjiang.liu@intel.com 
997*12004Sjiang.liu@intel.com 	self = id;
998*12004Sjiang.liu@intel.com 	if (self->dev.node)
999*12004Sjiang.liu@intel.com 		drmach_node_dispose(self->dev.node);
1000*12004Sjiang.liu@intel.com 
1001*12004Sjiang.liu@intel.com 	kmem_free(self, sizeof (*self));
1002*12004Sjiang.liu@intel.com }
1003*12004Sjiang.liu@intel.com 
1004*12004Sjiang.liu@intel.com static sbd_error_t *
drmach_io_release(drmachid_t id)1005*12004Sjiang.liu@intel.com drmach_io_release(drmachid_t id)
1006*12004Sjiang.liu@intel.com {
1007*12004Sjiang.liu@intel.com 	if (!DRMACH_IS_IO_ID(id))
1008*12004Sjiang.liu@intel.com 		return (drerr_new(0, EX86_INAPPROP, NULL));
1009*12004Sjiang.liu@intel.com 
1010*12004Sjiang.liu@intel.com 	return (NULL);
1011*12004Sjiang.liu@intel.com }
1012*12004Sjiang.liu@intel.com 
1013*12004Sjiang.liu@intel.com static sbd_error_t *
drmach_io_status(drmachid_t id,drmach_status_t * stat)1014*12004Sjiang.liu@intel.com drmach_io_status(drmachid_t id, drmach_status_t *stat)
1015*12004Sjiang.liu@intel.com {
1016*12004Sjiang.liu@intel.com 	drmach_device_t *dp;
1017*12004Sjiang.liu@intel.com 	sbd_error_t	*err;
1018*12004Sjiang.liu@intel.com 	int		 configured;
1019*12004Sjiang.liu@intel.com 
1020*12004Sjiang.liu@intel.com 	ASSERT(DRMACH_IS_IO_ID(id));
1021*12004Sjiang.liu@intel.com 	dp = id;
1022*12004Sjiang.liu@intel.com 
1023*12004Sjiang.liu@intel.com 	err = drmach_io_is_attached(id, &configured);
1024*12004Sjiang.liu@intel.com 	if (err)
1025*12004Sjiang.liu@intel.com 		return (err);
1026*12004Sjiang.liu@intel.com 
1027*12004Sjiang.liu@intel.com 	stat->assigned = dp->bp->assigned;
1028*12004Sjiang.liu@intel.com 	stat->powered = dp->bp->powered;
1029*12004Sjiang.liu@intel.com 	stat->configured = (configured != 0);
1030*12004Sjiang.liu@intel.com 	stat->busy = dp->busy;
1031*12004Sjiang.liu@intel.com 	(void) strlcpy(stat->type, dp->type, sizeof (stat->type));
1032*12004Sjiang.liu@intel.com 	stat->info[0] = '\0';
1033*12004Sjiang.liu@intel.com 
1034*12004Sjiang.liu@intel.com 	return (NULL);
1035*12004Sjiang.liu@intel.com }
1036*12004Sjiang.liu@intel.com 
1037*12004Sjiang.liu@intel.com sbd_error_t *
drmach_cpu_new(drmach_device_t * proto,drmachid_t * idp)1038*12004Sjiang.liu@intel.com drmach_cpu_new(drmach_device_t *proto, drmachid_t *idp)
1039*12004Sjiang.liu@intel.com {
1040*12004Sjiang.liu@intel.com 	static void drmach_cpu_dispose(drmachid_t);
1041*12004Sjiang.liu@intel.com 	static sbd_error_t *drmach_cpu_release(drmachid_t);
1042*12004Sjiang.liu@intel.com 	static sbd_error_t *drmach_cpu_status(drmachid_t, drmach_status_t *);
1043*12004Sjiang.liu@intel.com 
1044*12004Sjiang.liu@intel.com 	int		 portid;
1045*12004Sjiang.liu@intel.com 	processorid_t	 cpuid;
1046*12004Sjiang.liu@intel.com 	drmach_cpu_t	*cp = NULL;
1047*12004Sjiang.liu@intel.com 
1048*12004Sjiang.liu@intel.com 	/* the portid is APIC ID of the node */
1049*12004Sjiang.liu@intel.com 	portid = proto->portid;
1050*12004Sjiang.liu@intel.com 	ASSERT(portid != -1);
1051*12004Sjiang.liu@intel.com 
1052*12004Sjiang.liu@intel.com 	/*
1053*12004Sjiang.liu@intel.com 	 * Assume all CPUs are homogeneous and have the same number of
1054*12004Sjiang.liu@intel.com 	 * cores/threads.
1055*12004Sjiang.liu@intel.com 	 */
1056*12004Sjiang.liu@intel.com 	proto->unum = portid % MAX_CPU_UNITS_PER_BOARD;
1057*12004Sjiang.liu@intel.com 
1058*12004Sjiang.liu@intel.com 	cp = kmem_zalloc(sizeof (drmach_cpu_t), KM_SLEEP);
1059*12004Sjiang.liu@intel.com 	bcopy(proto, &cp->dev, sizeof (cp->dev));
1060*12004Sjiang.liu@intel.com 	cp->dev.node = drmach_node_dup(proto->node);
1061*12004Sjiang.liu@intel.com 	cp->dev.cm.isa = (void *)drmach_cpu_new;
1062*12004Sjiang.liu@intel.com 	cp->dev.cm.dispose = drmach_cpu_dispose;
1063*12004Sjiang.liu@intel.com 	cp->dev.cm.release = drmach_cpu_release;
1064*12004Sjiang.liu@intel.com 	cp->dev.cm.status = drmach_cpu_status;
1065*12004Sjiang.liu@intel.com 	(void) snprintf(cp->dev.cm.name, sizeof (cp->dev.cm.name), "%s%d",
1066*12004Sjiang.liu@intel.com 	    cp->dev.type, cp->dev.unum);
1067*12004Sjiang.liu@intel.com 
1068*12004Sjiang.liu@intel.com 	cp->apicid = portid;
1069*12004Sjiang.liu@intel.com 	if (ACPI_SUCCESS(acpica_get_cpu_id_by_object(
1070*12004Sjiang.liu@intel.com 	    drmach_node_get_dnode(proto->node), &cpuid))) {
1071*12004Sjiang.liu@intel.com 		cp->cpuid = cpuid;
1072*12004Sjiang.liu@intel.com 	} else {
1073*12004Sjiang.liu@intel.com 		cp->cpuid = -1;
1074*12004Sjiang.liu@intel.com 	}
1075*12004Sjiang.liu@intel.com 
1076*12004Sjiang.liu@intel.com 	/* Mark CPU0 as busy, many other components have dependency on it. */
1077*12004Sjiang.liu@intel.com 	if (cp->cpuid == 0) {
1078*12004Sjiang.liu@intel.com 		cp->dev.busy = 1;
1079*12004Sjiang.liu@intel.com 	}
1080*12004Sjiang.liu@intel.com 
1081*12004Sjiang.liu@intel.com 	*idp = (drmachid_t)cp;
1082*12004Sjiang.liu@intel.com 
1083*12004Sjiang.liu@intel.com 	return (NULL);
1084*12004Sjiang.liu@intel.com }
1085*12004Sjiang.liu@intel.com 
1086*12004Sjiang.liu@intel.com static void
drmach_cpu_dispose(drmachid_t id)1087*12004Sjiang.liu@intel.com drmach_cpu_dispose(drmachid_t id)
1088*12004Sjiang.liu@intel.com {
1089*12004Sjiang.liu@intel.com 	drmach_cpu_t	*self;
1090*12004Sjiang.liu@intel.com 
1091*12004Sjiang.liu@intel.com 	ASSERT(DRMACH_IS_CPU_ID(id));
1092*12004Sjiang.liu@intel.com 
1093*12004Sjiang.liu@intel.com 	self = id;
1094*12004Sjiang.liu@intel.com 	if (self->dev.node)
1095*12004Sjiang.liu@intel.com 		drmach_node_dispose(self->dev.node);
1096*12004Sjiang.liu@intel.com 
1097*12004Sjiang.liu@intel.com 	kmem_free(self, sizeof (*self));
1098*12004Sjiang.liu@intel.com }
1099*12004Sjiang.liu@intel.com 
1100*12004Sjiang.liu@intel.com static sbd_error_t *
drmach_cpu_release(drmachid_t id)1101*12004Sjiang.liu@intel.com drmach_cpu_release(drmachid_t id)
1102*12004Sjiang.liu@intel.com {
1103*12004Sjiang.liu@intel.com 	if (!DRMACH_IS_CPU_ID(id))
1104*12004Sjiang.liu@intel.com 		return (drerr_new(0, EX86_INAPPROP, NULL));
1105*12004Sjiang.liu@intel.com 
1106*12004Sjiang.liu@intel.com 	return (NULL);
1107*12004Sjiang.liu@intel.com }
1108*12004Sjiang.liu@intel.com 
1109*12004Sjiang.liu@intel.com static sbd_error_t *
drmach_cpu_status(drmachid_t id,drmach_status_t * stat)1110*12004Sjiang.liu@intel.com drmach_cpu_status(drmachid_t id, drmach_status_t *stat)
1111*12004Sjiang.liu@intel.com {
1112*12004Sjiang.liu@intel.com 	drmach_cpu_t *cp;
1113*12004Sjiang.liu@intel.com 	drmach_device_t *dp;
1114*12004Sjiang.liu@intel.com 
1115*12004Sjiang.liu@intel.com 	ASSERT(DRMACH_IS_CPU_ID(id));
1116*12004Sjiang.liu@intel.com 	cp = (drmach_cpu_t *)id;
1117*12004Sjiang.liu@intel.com 	dp = &cp->dev;
1118*12004Sjiang.liu@intel.com 
1119*12004Sjiang.liu@intel.com 	stat->assigned = dp->bp->assigned;
1120*12004Sjiang.liu@intel.com 	stat->powered = dp->bp->powered;
1121*12004Sjiang.liu@intel.com 	mutex_enter(&cpu_lock);
1122*12004Sjiang.liu@intel.com 	stat->configured = (cpu_get(cp->cpuid) != NULL);
1123*12004Sjiang.liu@intel.com 	mutex_exit(&cpu_lock);
1124*12004Sjiang.liu@intel.com 	stat->busy = dp->busy;
1125*12004Sjiang.liu@intel.com 	(void) strlcpy(stat->type, dp->type, sizeof (stat->type));
1126*12004Sjiang.liu@intel.com 	stat->info[0] = '\0';
1127*12004Sjiang.liu@intel.com 
1128*12004Sjiang.liu@intel.com 	return (NULL);
1129*12004Sjiang.liu@intel.com }
1130*12004Sjiang.liu@intel.com 
1131*12004Sjiang.liu@intel.com static int
drmach_setup_mc_info(DRMACH_HANDLE hdl,drmach_mem_t * mp)1132*12004Sjiang.liu@intel.com drmach_setup_mc_info(DRMACH_HANDLE hdl, drmach_mem_t *mp)
1133*12004Sjiang.liu@intel.com {
1134*12004Sjiang.liu@intel.com 	uint_t i, j, count;
1135*12004Sjiang.liu@intel.com 	struct memlist	*ml = NULL, *ml2 = NULL;
1136*12004Sjiang.liu@intel.com 	acpidev_regspec_t *regp;
1137*12004Sjiang.liu@intel.com 	uint64_t align, addr_min, addr_max, total_size, skipped_size;
1138*12004Sjiang.liu@intel.com 
1139*12004Sjiang.liu@intel.com 	if (hdl == NULL) {
1140*12004Sjiang.liu@intel.com 		return (-1);
1141*12004Sjiang.liu@intel.com 	} else if (ACPI_FAILURE(acpidev_dr_get_mem_alignment(hdl, &align))) {
1142*12004Sjiang.liu@intel.com 		return (-1);
1143*12004Sjiang.liu@intel.com 	} else {
1144*12004Sjiang.liu@intel.com 		ASSERT((align & (align - 1)) == 0);
1145*12004Sjiang.liu@intel.com 		mp->mem_alignment = align;
1146*12004Sjiang.liu@intel.com 	}
1147*12004Sjiang.liu@intel.com 
1148*12004Sjiang.liu@intel.com 	addr_min = UINT64_MAX;
1149*12004Sjiang.liu@intel.com 	addr_max = 0;
1150*12004Sjiang.liu@intel.com 	total_size = 0;
1151*12004Sjiang.liu@intel.com 	skipped_size = 0;
1152*12004Sjiang.liu@intel.com 	/*
1153*12004Sjiang.liu@intel.com 	 * There's a memory hole just below 4G on x86, which needs special
1154*12004Sjiang.liu@intel.com 	 * handling. All other addresses assigned to a specific memory device
1155*12004Sjiang.liu@intel.com 	 * should be contiguous.
1156*12004Sjiang.liu@intel.com 	 */
1157*12004Sjiang.liu@intel.com 	if (ACPI_FAILURE(acpidev_dr_device_get_regspec(hdl, TRUE, &regp,
1158*12004Sjiang.liu@intel.com 	    &count))) {
1159*12004Sjiang.liu@intel.com 		return (-1);
1160*12004Sjiang.liu@intel.com 	}
1161*12004Sjiang.liu@intel.com 	for (i = 0, j = 0; i < count; i++) {
1162*12004Sjiang.liu@intel.com 		uint64_t	addr, size;
1163*12004Sjiang.liu@intel.com 
1164*12004Sjiang.liu@intel.com 		addr  = (uint64_t)regp[i].phys_mid << 32;
1165*12004Sjiang.liu@intel.com 		addr |= (uint64_t)regp[i].phys_low;
1166*12004Sjiang.liu@intel.com 		size  = (uint64_t)regp[i].size_hi << 32;
1167*12004Sjiang.liu@intel.com 		size |= (uint64_t)regp[i].size_low;
1168*12004Sjiang.liu@intel.com 		if (size == 0)
1169*12004Sjiang.liu@intel.com 			continue;
1170*12004Sjiang.liu@intel.com 		else
1171*12004Sjiang.liu@intel.com 			j++;
1172*12004Sjiang.liu@intel.com 
1173*12004Sjiang.liu@intel.com 		total_size += size;
1174*12004Sjiang.liu@intel.com 		if (addr < addr_min)
1175*12004Sjiang.liu@intel.com 			addr_min = addr;
1176*12004Sjiang.liu@intel.com 		if (addr + size > addr_max)
1177*12004Sjiang.liu@intel.com 			addr_max = addr + size;
1178*12004Sjiang.liu@intel.com 		if (mp->dev.bp->boot_board ||
1179*12004Sjiang.liu@intel.com 		    j <= acpidev_dr_max_segments_per_mem_device()) {
1180*12004Sjiang.liu@intel.com 			ml = memlist_add_span(ml, addr, size);
1181*12004Sjiang.liu@intel.com 		} else {
1182*12004Sjiang.liu@intel.com 			skipped_size += size;
1183*12004Sjiang.liu@intel.com 		}
1184*12004Sjiang.liu@intel.com 	}
1185*12004Sjiang.liu@intel.com 	acpidev_dr_device_free_regspec(regp, count);
1186*12004Sjiang.liu@intel.com 
1187*12004Sjiang.liu@intel.com 	if (skipped_size != 0) {
1188*12004Sjiang.liu@intel.com 		cmn_err(CE_WARN, "!drmach: too many (%d) segments on memory "
1189*12004Sjiang.liu@intel.com 		    "device, max (%d) segments supported, 0x%" PRIx64 " bytes "
1190*12004Sjiang.liu@intel.com 		    "of memory skipped.",
1191*12004Sjiang.liu@intel.com 		    j, acpidev_dr_max_segments_per_mem_device(), skipped_size);
1192*12004Sjiang.liu@intel.com 	}
1193*12004Sjiang.liu@intel.com 
1194*12004Sjiang.liu@intel.com 	mp->slice_base = addr_min;
1195*12004Sjiang.liu@intel.com 	mp->slice_top = addr_max;
1196*12004Sjiang.liu@intel.com 	mp->slice_size = total_size;
1197*12004Sjiang.liu@intel.com 
1198*12004Sjiang.liu@intel.com 	if (mp->dev.bp->boot_board) {
1199*12004Sjiang.liu@intel.com 		uint64_t endpa = _ptob64(physmax + 1);
1200*12004Sjiang.liu@intel.com 
1201*12004Sjiang.liu@intel.com 		/*
1202*12004Sjiang.liu@intel.com 		 * we intersect phys_install to get base_pa.
1203*12004Sjiang.liu@intel.com 		 * This only works at boot-up time.
1204*12004Sjiang.liu@intel.com 		 */
1205*12004Sjiang.liu@intel.com 		memlist_read_lock();
1206*12004Sjiang.liu@intel.com 		ml2 = memlist_dup(phys_install);
1207*12004Sjiang.liu@intel.com 		memlist_read_unlock();
1208*12004Sjiang.liu@intel.com 
1209*12004Sjiang.liu@intel.com 		ml2 = memlist_del_span(ml2, 0ull, mp->slice_base);
1210*12004Sjiang.liu@intel.com 		if (ml2 && endpa > addr_max) {
1211*12004Sjiang.liu@intel.com 			ml2 = memlist_del_span(ml2, addr_max, endpa - addr_max);
1212*12004Sjiang.liu@intel.com 		}
1213*12004Sjiang.liu@intel.com 	}
1214*12004Sjiang.liu@intel.com 
1215*12004Sjiang.liu@intel.com 	/*
1216*12004Sjiang.liu@intel.com 	 * Create a memlist for the memory board.
1217*12004Sjiang.liu@intel.com 	 * The created memlist only contains configured memory if there's
1218*12004Sjiang.liu@intel.com 	 * configured memory on the board, otherwise it contains all memory
1219*12004Sjiang.liu@intel.com 	 * on the board.
1220*12004Sjiang.liu@intel.com 	 */
1221*12004Sjiang.liu@intel.com 	if (ml2) {
1222*12004Sjiang.liu@intel.com 		uint64_t nbytes = 0;
1223*12004Sjiang.liu@intel.com 		struct memlist *p;
1224*12004Sjiang.liu@intel.com 
1225*12004Sjiang.liu@intel.com 		for (p = ml2; p; p = p->ml_next) {
1226*12004Sjiang.liu@intel.com 			nbytes += p->ml_size;
1227*12004Sjiang.liu@intel.com 		}
1228*12004Sjiang.liu@intel.com 		if (nbytes == 0) {
1229*12004Sjiang.liu@intel.com 			memlist_delete(ml2);
1230*12004Sjiang.liu@intel.com 			ml2 = NULL;
1231*12004Sjiang.liu@intel.com 		} else {
1232*12004Sjiang.liu@intel.com 			/* Node has configured memory at boot time. */
1233*12004Sjiang.liu@intel.com 			mp->base_pa = ml2->ml_address;
1234*12004Sjiang.liu@intel.com 			mp->nbytes = nbytes;
1235*12004Sjiang.liu@intel.com 			mp->memlist = ml2;
1236*12004Sjiang.liu@intel.com 			if (ml)
1237*12004Sjiang.liu@intel.com 				memlist_delete(ml);
1238*12004Sjiang.liu@intel.com 		}
1239*12004Sjiang.liu@intel.com 	}
1240*12004Sjiang.liu@intel.com 	if (ml2 == NULL) {
1241*12004Sjiang.liu@intel.com 		/* Not configured at boot time. */
1242*12004Sjiang.liu@intel.com 		mp->base_pa = UINT64_MAX;
1243*12004Sjiang.liu@intel.com 		mp->nbytes = 0;
1244*12004Sjiang.liu@intel.com 		mp->memlist = ml;
1245*12004Sjiang.liu@intel.com 	}
1246*12004Sjiang.liu@intel.com 
1247*12004Sjiang.liu@intel.com 	return (0);
1248*12004Sjiang.liu@intel.com }
1249*12004Sjiang.liu@intel.com 
1250*12004Sjiang.liu@intel.com sbd_error_t *
drmach_mem_new(drmach_device_t * proto,drmachid_t * idp)1251*12004Sjiang.liu@intel.com drmach_mem_new(drmach_device_t *proto, drmachid_t *idp)
1252*12004Sjiang.liu@intel.com {
1253*12004Sjiang.liu@intel.com 	static void drmach_mem_dispose(drmachid_t);
1254*12004Sjiang.liu@intel.com 	static sbd_error_t *drmach_mem_release(drmachid_t);
1255*12004Sjiang.liu@intel.com 	static sbd_error_t *drmach_mem_status(drmachid_t, drmach_status_t *);
1256*12004Sjiang.liu@intel.com 
1257*12004Sjiang.liu@intel.com 	DRMACH_HANDLE	hdl;
1258*12004Sjiang.liu@intel.com 	drmach_mem_t	*mp;
1259*12004Sjiang.liu@intel.com 	int		portid;
1260*12004Sjiang.liu@intel.com 
1261*12004Sjiang.liu@intel.com 	mp = kmem_zalloc(sizeof (drmach_mem_t), KM_SLEEP);
1262*12004Sjiang.liu@intel.com 	portid = proto->portid;
1263*12004Sjiang.liu@intel.com 	ASSERT(portid != -1);
1264*12004Sjiang.liu@intel.com 	proto->unum = portid;
1265*12004Sjiang.liu@intel.com 
1266*12004Sjiang.liu@intel.com 	bcopy(proto, &mp->dev, sizeof (mp->dev));
1267*12004Sjiang.liu@intel.com 	mp->dev.node = drmach_node_dup(proto->node);
1268*12004Sjiang.liu@intel.com 	mp->dev.cm.isa = (void *)drmach_mem_new;
1269*12004Sjiang.liu@intel.com 	mp->dev.cm.dispose = drmach_mem_dispose;
1270*12004Sjiang.liu@intel.com 	mp->dev.cm.release = drmach_mem_release;
1271*12004Sjiang.liu@intel.com 	mp->dev.cm.status = drmach_mem_status;
1272*12004Sjiang.liu@intel.com 
1273*12004Sjiang.liu@intel.com 	(void) snprintf(mp->dev.cm.name, sizeof (mp->dev.cm.name), "%s%d",
1274*12004Sjiang.liu@intel.com 	    mp->dev.type, proto->unum);
1275*12004Sjiang.liu@intel.com 	hdl = mp->dev.node->get_dnode(mp->dev.node);
1276*12004Sjiang.liu@intel.com 	ASSERT(hdl != NULL);
1277*12004Sjiang.liu@intel.com 	if (drmach_setup_mc_info(hdl, mp) != 0) {
1278*12004Sjiang.liu@intel.com 		kmem_free(mp, sizeof (drmach_mem_t));
1279*12004Sjiang.liu@intel.com 		*idp = (drmachid_t)NULL;
1280*12004Sjiang.liu@intel.com 		return (drerr_new(1, EX86_MC_SETUP, NULL));
1281*12004Sjiang.liu@intel.com 	}
1282*12004Sjiang.liu@intel.com 
1283*12004Sjiang.liu@intel.com 	/* make sure we do not create memoryless nodes */
1284*12004Sjiang.liu@intel.com 	if (mp->nbytes == 0 && mp->slice_size == 0) {
1285*12004Sjiang.liu@intel.com 		kmem_free(mp, sizeof (drmach_mem_t));
1286*12004Sjiang.liu@intel.com 		*idp = (drmachid_t)NULL;
1287*12004Sjiang.liu@intel.com 	} else
1288*12004Sjiang.liu@intel.com 		*idp = (drmachid_t)mp;
1289*12004Sjiang.liu@intel.com 
1290*12004Sjiang.liu@intel.com 	return (NULL);
1291*12004Sjiang.liu@intel.com }
1292*12004Sjiang.liu@intel.com 
1293*12004Sjiang.liu@intel.com static void
drmach_mem_dispose(drmachid_t id)1294*12004Sjiang.liu@intel.com drmach_mem_dispose(drmachid_t id)
1295*12004Sjiang.liu@intel.com {
1296*12004Sjiang.liu@intel.com 	drmach_mem_t *mp;
1297*12004Sjiang.liu@intel.com 
1298*12004Sjiang.liu@intel.com 	ASSERT(DRMACH_IS_MEM_ID(id));
1299*12004Sjiang.liu@intel.com 
1300*12004Sjiang.liu@intel.com 	mp = id;
1301*12004Sjiang.liu@intel.com 
1302*12004Sjiang.liu@intel.com 	if (mp->dev.node)
1303*12004Sjiang.liu@intel.com 		drmach_node_dispose(mp->dev.node);
1304*12004Sjiang.liu@intel.com 
1305*12004Sjiang.liu@intel.com 	if (mp->memlist) {
1306*12004Sjiang.liu@intel.com 		memlist_delete(mp->memlist);
1307*12004Sjiang.liu@intel.com 		mp->memlist = NULL;
1308*12004Sjiang.liu@intel.com 	}
1309*12004Sjiang.liu@intel.com 
1310*12004Sjiang.liu@intel.com 	kmem_free(mp, sizeof (*mp));
1311*12004Sjiang.liu@intel.com }
1312*12004Sjiang.liu@intel.com 
1313*12004Sjiang.liu@intel.com static sbd_error_t *
drmach_mem_release(drmachid_t id)1314*12004Sjiang.liu@intel.com drmach_mem_release(drmachid_t id)
1315*12004Sjiang.liu@intel.com {
1316*12004Sjiang.liu@intel.com 	if (!DRMACH_IS_MEM_ID(id))
1317*12004Sjiang.liu@intel.com 		return (drerr_new(0, EX86_INAPPROP, NULL));
1318*12004Sjiang.liu@intel.com 
1319*12004Sjiang.liu@intel.com 	return (NULL);
1320*12004Sjiang.liu@intel.com }
1321*12004Sjiang.liu@intel.com 
1322*12004Sjiang.liu@intel.com static sbd_error_t *
drmach_mem_status(drmachid_t id,drmach_status_t * stat)1323*12004Sjiang.liu@intel.com drmach_mem_status(drmachid_t id, drmach_status_t *stat)
1324*12004Sjiang.liu@intel.com {
1325*12004Sjiang.liu@intel.com 	uint64_t	 pa;
1326*12004Sjiang.liu@intel.com 	drmach_mem_t	*dp;
1327*12004Sjiang.liu@intel.com 	struct memlist	*ml = NULL;
1328*12004Sjiang.liu@intel.com 
1329*12004Sjiang.liu@intel.com 	ASSERT(DRMACH_IS_MEM_ID(id));
1330*12004Sjiang.liu@intel.com 	dp = id;
1331*12004Sjiang.liu@intel.com 
1332*12004Sjiang.liu@intel.com 	/* get starting physical address of target memory */
1333*12004Sjiang.liu@intel.com 	pa = dp->base_pa;
1334*12004Sjiang.liu@intel.com 	/* round down to slice boundary */
1335*12004Sjiang.liu@intel.com 	pa &= ~(dp->mem_alignment - 1);
1336*12004Sjiang.liu@intel.com 
1337*12004Sjiang.liu@intel.com 	/* stop at first span that is in slice */
1338*12004Sjiang.liu@intel.com 	memlist_read_lock();
1339*12004Sjiang.liu@intel.com 	for (ml = phys_install; ml; ml = ml->ml_next)
1340*12004Sjiang.liu@intel.com 		if (ml->ml_address >= pa && ml->ml_address < dp->slice_top)
1341*12004Sjiang.liu@intel.com 			break;
1342*12004Sjiang.liu@intel.com 	memlist_read_unlock();
1343*12004Sjiang.liu@intel.com 
1344*12004Sjiang.liu@intel.com 	stat->assigned = dp->dev.bp->assigned;
1345*12004Sjiang.liu@intel.com 	stat->powered = dp->dev.bp->powered;
1346*12004Sjiang.liu@intel.com 	stat->configured = (ml != NULL);
1347*12004Sjiang.liu@intel.com 	stat->busy = dp->dev.busy;
1348*12004Sjiang.liu@intel.com 	(void) strlcpy(stat->type, dp->dev.type, sizeof (stat->type));
1349*12004Sjiang.liu@intel.com 	stat->info[0] = '\0';
1350*12004Sjiang.liu@intel.com 
1351*12004Sjiang.liu@intel.com 	return (NULL);
1352*12004Sjiang.liu@intel.com }
1353*12004Sjiang.liu@intel.com 
1354*12004Sjiang.liu@intel.com /*
1355*12004Sjiang.liu@intel.com  * Public interfaces exported to support platform independent dr driver.
1356*12004Sjiang.liu@intel.com  */
1357*12004Sjiang.liu@intel.com uint_t
drmach_max_boards(void)1358*12004Sjiang.liu@intel.com drmach_max_boards(void)
1359*12004Sjiang.liu@intel.com {
1360*12004Sjiang.liu@intel.com 	return (acpidev_dr_max_boards());
1361*12004Sjiang.liu@intel.com }
1362*12004Sjiang.liu@intel.com 
1363*12004Sjiang.liu@intel.com uint_t
drmach_max_io_units_per_board(void)1364*12004Sjiang.liu@intel.com drmach_max_io_units_per_board(void)
1365*12004Sjiang.liu@intel.com {
1366*12004Sjiang.liu@intel.com 	return (acpidev_dr_max_io_units_per_board());
1367*12004Sjiang.liu@intel.com }
1368*12004Sjiang.liu@intel.com 
1369*12004Sjiang.liu@intel.com uint_t
drmach_max_cmp_units_per_board(void)1370*12004Sjiang.liu@intel.com drmach_max_cmp_units_per_board(void)
1371*12004Sjiang.liu@intel.com {
1372*12004Sjiang.liu@intel.com 	return (acpidev_dr_max_cmp_units_per_board());
1373*12004Sjiang.liu@intel.com }
1374*12004Sjiang.liu@intel.com 
1375*12004Sjiang.liu@intel.com uint_t
drmach_max_mem_units_per_board(void)1376*12004Sjiang.liu@intel.com drmach_max_mem_units_per_board(void)
1377*12004Sjiang.liu@intel.com {
1378*12004Sjiang.liu@intel.com 	return (acpidev_dr_max_mem_units_per_board());
1379*12004Sjiang.liu@intel.com }
1380*12004Sjiang.liu@intel.com 
1381*12004Sjiang.liu@intel.com uint_t
drmach_max_core_per_cmp(void)1382*12004Sjiang.liu@intel.com drmach_max_core_per_cmp(void)
1383*12004Sjiang.liu@intel.com {
1384*12004Sjiang.liu@intel.com 	return (acpidev_dr_max_cpu_units_per_cmp());
1385*12004Sjiang.liu@intel.com }
1386*12004Sjiang.liu@intel.com 
1387*12004Sjiang.liu@intel.com sbd_error_t *
drmach_pre_op(int cmd,drmachid_t id,drmach_opts_t * opts,void * argp)1388*12004Sjiang.liu@intel.com drmach_pre_op(int cmd, drmachid_t id, drmach_opts_t *opts, void *argp)
1389*12004Sjiang.liu@intel.com {
1390*12004Sjiang.liu@intel.com 	drmach_board_t	*bp = (drmach_board_t *)id;
1391*12004Sjiang.liu@intel.com 	sbd_error_t	*err = NULL;
1392*12004Sjiang.liu@intel.com 
1393*12004Sjiang.liu@intel.com 	/* allow status and ncm operations to always succeed */
1394*12004Sjiang.liu@intel.com 	if ((cmd == SBD_CMD_STATUS) || (cmd == SBD_CMD_GETNCM)) {
1395*12004Sjiang.liu@intel.com 		return (NULL);
1396*12004Sjiang.liu@intel.com 	}
1397*12004Sjiang.liu@intel.com 
1398*12004Sjiang.liu@intel.com 	switch (cmd) {
1399*12004Sjiang.liu@intel.com 	case SBD_CMD_POWERON:
1400*12004Sjiang.liu@intel.com 	case SBD_CMD_POWEROFF:
1401*12004Sjiang.liu@intel.com 		/*
1402*12004Sjiang.liu@intel.com 		 * Disable fast reboot if CPU/MEM/IOH hotplug event happens.
1403*12004Sjiang.liu@intel.com 		 * Note: this is a temporary solution and will be revised when
1404*12004Sjiang.liu@intel.com 		 * fast reboot can support CPU/MEM/IOH DR operations in future.
1405*12004Sjiang.liu@intel.com 		 *
1406*12004Sjiang.liu@intel.com 		 * ACPI BIOS generates some static ACPI tables, such as MADT,
1407*12004Sjiang.liu@intel.com 		 * SRAT and SLIT, to describe system hardware configuration on
1408*12004Sjiang.liu@intel.com 		 * power-on. When CPU/MEM/IOH hotplug event happens, those
1409*12004Sjiang.liu@intel.com 		 * static tables won't be updated and will become stale.
1410*12004Sjiang.liu@intel.com 		 *
1411*12004Sjiang.liu@intel.com 		 * If we reset system by fast reboot, BIOS will have no chance
1412*12004Sjiang.liu@intel.com 		 * to regenerate those staled static tables. Fast reboot can't
1413*12004Sjiang.liu@intel.com 		 * tolerate such inconsistency between staled ACPI tables and
1414*12004Sjiang.liu@intel.com 		 * real hardware configuration yet.
1415*12004Sjiang.liu@intel.com 		 *
1416*12004Sjiang.liu@intel.com 		 * A temporary solution is introduced to disable fast reboot if
1417*12004Sjiang.liu@intel.com 		 * CPU/MEM/IOH hotplug event happens. This solution should be
1418*12004Sjiang.liu@intel.com 		 * revised when fast reboot is enhanced to support CPU/MEM/IOH
1419*12004Sjiang.liu@intel.com 		 * DR operations.
1420*12004Sjiang.liu@intel.com 		 */
1421*12004Sjiang.liu@intel.com 		fastreboot_disable(FBNS_HOTPLUG);
1422*12004Sjiang.liu@intel.com 		/*FALLTHROUGH*/
1423*12004Sjiang.liu@intel.com 
1424*12004Sjiang.liu@intel.com 	default:
1425*12004Sjiang.liu@intel.com 		/* Block out the CPR thread. */
1426*12004Sjiang.liu@intel.com 		rw_enter(&drmach_cpr_rwlock, RW_READER);
1427*12004Sjiang.liu@intel.com 		break;
1428*12004Sjiang.liu@intel.com 	}
1429*12004Sjiang.liu@intel.com 
1430*12004Sjiang.liu@intel.com 	/* check all other commands for the required option string */
1431*12004Sjiang.liu@intel.com 	if ((opts->size > 0) && (opts->copts != NULL)) {
1432*12004Sjiang.liu@intel.com 		if (strstr(opts->copts, ACPIDEV_CMD_OST_PREFIX) == NULL) {
1433*12004Sjiang.liu@intel.com 			err = drerr_new(1, EX86_SUPPORT, NULL);
1434*12004Sjiang.liu@intel.com 		}
1435*12004Sjiang.liu@intel.com 	} else {
1436*12004Sjiang.liu@intel.com 		err = drerr_new(1, EX86_SUPPORT, NULL);
1437*12004Sjiang.liu@intel.com 	}
1438*12004Sjiang.liu@intel.com 
1439*12004Sjiang.liu@intel.com 	if (!err && id && DRMACH_IS_BOARD_ID(id)) {
1440*12004Sjiang.liu@intel.com 		switch (cmd) {
1441*12004Sjiang.liu@intel.com 		case SBD_CMD_TEST:
1442*12004Sjiang.liu@intel.com 			break;
1443*12004Sjiang.liu@intel.com 		case SBD_CMD_CONNECT:
1444*12004Sjiang.liu@intel.com 			if (bp->connected)
1445*12004Sjiang.liu@intel.com 				err = drerr_new(0, ESBD_STATE, NULL);
1446*12004Sjiang.liu@intel.com 			else if (!drmach_domain.allow_dr)
1447*12004Sjiang.liu@intel.com 				err = drerr_new(1, EX86_SUPPORT, NULL);
1448*12004Sjiang.liu@intel.com 			break;
1449*12004Sjiang.liu@intel.com 		case SBD_CMD_DISCONNECT:
1450*12004Sjiang.liu@intel.com 			if (!bp->connected)
1451*12004Sjiang.liu@intel.com 				err = drerr_new(0, ESBD_STATE, NULL);
1452*12004Sjiang.liu@intel.com 			else if (!drmach_domain.allow_dr)
1453*12004Sjiang.liu@intel.com 				err = drerr_new(1, EX86_SUPPORT, NULL);
1454*12004Sjiang.liu@intel.com 			break;
1455*12004Sjiang.liu@intel.com 		default:
1456*12004Sjiang.liu@intel.com 			if (!drmach_domain.allow_dr)
1457*12004Sjiang.liu@intel.com 				err = drerr_new(1, EX86_SUPPORT, NULL);
1458*12004Sjiang.liu@intel.com 			break;
1459*12004Sjiang.liu@intel.com 
1460*12004Sjiang.liu@intel.com 		}
1461*12004Sjiang.liu@intel.com 	}
1462*12004Sjiang.liu@intel.com 
1463*12004Sjiang.liu@intel.com 	/*
1464*12004Sjiang.liu@intel.com 	 * CPU/memory/IO DR operations will be supported in stages on x86.
1465*12004Sjiang.liu@intel.com 	 * With early versions, some operations should be blocked here.
1466*12004Sjiang.liu@intel.com 	 * This temporary hook will be removed when all CPU/memory/IO DR
1467*12004Sjiang.liu@intel.com 	 * operations are supported on x86 systems.
1468*12004Sjiang.liu@intel.com 	 *
1469*12004Sjiang.liu@intel.com 	 * We only need to filter unsupported device types for
1470*12004Sjiang.liu@intel.com 	 * SBD_CMD_CONFIGURE/SBD_CMD_UNCONFIGURE commands, all other
1471*12004Sjiang.liu@intel.com 	 * commands are supported by all device types.
1472*12004Sjiang.liu@intel.com 	 */
1473*12004Sjiang.liu@intel.com 	if (!err && (cmd == SBD_CMD_CONFIGURE || cmd == SBD_CMD_UNCONFIGURE)) {
1474*12004Sjiang.liu@intel.com 		int		i;
1475*12004Sjiang.liu@intel.com 		dr_devset_t	*devsetp = (dr_devset_t *)argp;
1476*12004Sjiang.liu@intel.com 		dr_devset_t	devset = *devsetp;
1477*12004Sjiang.liu@intel.com 
1478*12004Sjiang.liu@intel.com 		switch (cmd) {
1479*12004Sjiang.liu@intel.com 		case SBD_CMD_CONFIGURE:
1480*12004Sjiang.liu@intel.com 			if (!plat_dr_support_cpu()) {
1481*12004Sjiang.liu@intel.com 				DEVSET_DEL(devset, SBD_COMP_CPU,
1482*12004Sjiang.liu@intel.com 				    DEVSET_ANYUNIT);
1483*12004Sjiang.liu@intel.com 			} else {
1484*12004Sjiang.liu@intel.com 				for (i = MAX_CPU_UNITS_PER_BOARD;
1485*12004Sjiang.liu@intel.com 				    i < DEVSET_CPU_NUMBER; i++) {
1486*12004Sjiang.liu@intel.com 					DEVSET_DEL(devset, SBD_COMP_CPU, i);
1487*12004Sjiang.liu@intel.com 				}
1488*12004Sjiang.liu@intel.com 			}
1489*12004Sjiang.liu@intel.com 
1490*12004Sjiang.liu@intel.com 			if (!plat_dr_support_memory()) {
1491*12004Sjiang.liu@intel.com 				DEVSET_DEL(devset, SBD_COMP_MEM,
1492*12004Sjiang.liu@intel.com 				    DEVSET_ANYUNIT);
1493*12004Sjiang.liu@intel.com 			} else {
1494*12004Sjiang.liu@intel.com 				for (i = MAX_MEM_UNITS_PER_BOARD;
1495*12004Sjiang.liu@intel.com 				    i < DEVSET_MEM_NUMBER; i++) {
1496*12004Sjiang.liu@intel.com 					DEVSET_DEL(devset, SBD_COMP_MEM, i);
1497*12004Sjiang.liu@intel.com 				}
1498*12004Sjiang.liu@intel.com 			}
1499*12004Sjiang.liu@intel.com 
1500*12004Sjiang.liu@intel.com 			/* No support of configuring IOH devices yet. */
1501*12004Sjiang.liu@intel.com 			DEVSET_DEL(devset, SBD_COMP_IO, DEVSET_ANYUNIT);
1502*12004Sjiang.liu@intel.com 			break;
1503*12004Sjiang.liu@intel.com 
1504*12004Sjiang.liu@intel.com 		case SBD_CMD_UNCONFIGURE:
1505*12004Sjiang.liu@intel.com 			if (!plat_dr_support_cpu()) {
1506*12004Sjiang.liu@intel.com 				DEVSET_DEL(devset, SBD_COMP_CPU,
1507*12004Sjiang.liu@intel.com 				    DEVSET_ANYUNIT);
1508*12004Sjiang.liu@intel.com 			} else {
1509*12004Sjiang.liu@intel.com 				for (i = MAX_CPU_UNITS_PER_BOARD;
1510*12004Sjiang.liu@intel.com 				    i < DEVSET_CPU_NUMBER; i++) {
1511*12004Sjiang.liu@intel.com 					DEVSET_DEL(devset, SBD_COMP_CPU, i);
1512*12004Sjiang.liu@intel.com 				}
1513*12004Sjiang.liu@intel.com 			}
1514*12004Sjiang.liu@intel.com 
1515*12004Sjiang.liu@intel.com 			/* No support of unconfiguring MEM/IOH devices yet. */
1516*12004Sjiang.liu@intel.com 			DEVSET_DEL(devset, SBD_COMP_MEM, DEVSET_ANYUNIT);
1517*12004Sjiang.liu@intel.com 			DEVSET_DEL(devset, SBD_COMP_IO, DEVSET_ANYUNIT);
1518*12004Sjiang.liu@intel.com 			break;
1519*12004Sjiang.liu@intel.com 		}
1520*12004Sjiang.liu@intel.com 
1521*12004Sjiang.liu@intel.com 		*devsetp = devset;
1522*12004Sjiang.liu@intel.com 		if (DEVSET_IS_NULL(devset)) {
1523*12004Sjiang.liu@intel.com 			err = drerr_new(1, EX86_SUPPORT, NULL);
1524*12004Sjiang.liu@intel.com 		}
1525*12004Sjiang.liu@intel.com 	}
1526*12004Sjiang.liu@intel.com 
1527*12004Sjiang.liu@intel.com 	return (err);
1528*12004Sjiang.liu@intel.com }
1529*12004Sjiang.liu@intel.com 
1530*12004Sjiang.liu@intel.com sbd_error_t *
drmach_post_op(int cmd,drmachid_t id,drmach_opts_t * opts,int rv)1531*12004Sjiang.liu@intel.com drmach_post_op(int cmd, drmachid_t id, drmach_opts_t *opts, int rv)
1532*12004Sjiang.liu@intel.com {
1533*12004Sjiang.liu@intel.com 	_NOTE(ARGUNUSED(id, opts, rv));
1534*12004Sjiang.liu@intel.com 
1535*12004Sjiang.liu@intel.com 	switch (cmd) {
1536*12004Sjiang.liu@intel.com 	case SBD_CMD_STATUS:
1537*12004Sjiang.liu@intel.com 	case SBD_CMD_GETNCM:
1538*12004Sjiang.liu@intel.com 		break;
1539*12004Sjiang.liu@intel.com 
1540*12004Sjiang.liu@intel.com 	default:
1541*12004Sjiang.liu@intel.com 		rw_exit(&drmach_cpr_rwlock);
1542*12004Sjiang.liu@intel.com 		break;
1543*12004Sjiang.liu@intel.com 	}
1544*12004Sjiang.liu@intel.com 
1545*12004Sjiang.liu@intel.com 	return (NULL);
1546*12004Sjiang.liu@intel.com }
1547*12004Sjiang.liu@intel.com 
1548*12004Sjiang.liu@intel.com sbd_error_t *
drmach_configure(drmachid_t id,int flags)1549*12004Sjiang.liu@intel.com drmach_configure(drmachid_t id, int flags)
1550*12004Sjiang.liu@intel.com {
1551*12004Sjiang.liu@intel.com 	_NOTE(ARGUNUSED(flags));
1552*12004Sjiang.liu@intel.com 
1553*12004Sjiang.liu@intel.com 	drmach_device_t		*dp;
1554*12004Sjiang.liu@intel.com 	sbd_error_t		*err = NULL;
1555*12004Sjiang.liu@intel.com 	dev_info_t		*rdip;
1556*12004Sjiang.liu@intel.com 	dev_info_t		*fdip = NULL;
1557*12004Sjiang.liu@intel.com 
1558*12004Sjiang.liu@intel.com 	if (!DRMACH_IS_DEVICE_ID(id))
1559*12004Sjiang.liu@intel.com 		return (drerr_new(0, EX86_INAPPROP, NULL));
1560*12004Sjiang.liu@intel.com 	dp = id;
1561*12004Sjiang.liu@intel.com 
1562*12004Sjiang.liu@intel.com 	rdip = dp->node->getdip(dp->node);
1563*12004Sjiang.liu@intel.com 	ASSERT(rdip);
1564*12004Sjiang.liu@intel.com 	ASSERT(e_ddi_branch_held(rdip));
1565*12004Sjiang.liu@intel.com 
1566*12004Sjiang.liu@intel.com 	/* allocate cpu id for the CPU device. */
1567*12004Sjiang.liu@intel.com 	if (DRMACH_IS_CPU_ID(id)) {
1568*12004Sjiang.liu@intel.com 		DRMACH_HANDLE hdl = drmach_node_get_dnode(dp->node);
1569*12004Sjiang.liu@intel.com 		ASSERT(hdl != NULL);
1570*12004Sjiang.liu@intel.com 		if (ACPI_FAILURE(acpidev_dr_allocate_cpuid(hdl, NULL))) {
1571*12004Sjiang.liu@intel.com 			err = drerr_new(1, EX86_ALLOC_CPUID, NULL);
1572*12004Sjiang.liu@intel.com 		}
1573*12004Sjiang.liu@intel.com 		return (err);
1574*12004Sjiang.liu@intel.com 	}
1575*12004Sjiang.liu@intel.com 
1576*12004Sjiang.liu@intel.com 	if (DRMACH_IS_MEM_ID(id)) {
1577*12004Sjiang.liu@intel.com 		err = drmach_mem_update_lgrp(id);
1578*12004Sjiang.liu@intel.com 		if (err)
1579*12004Sjiang.liu@intel.com 			return (err);
1580*12004Sjiang.liu@intel.com 	}
1581*12004Sjiang.liu@intel.com 
1582*12004Sjiang.liu@intel.com 	if (e_ddi_branch_configure(rdip, &fdip, 0) != 0) {
1583*12004Sjiang.liu@intel.com 		char *path = kmem_alloc(MAXPATHLEN, KM_SLEEP);
1584*12004Sjiang.liu@intel.com 		dev_info_t *dip = (fdip != NULL) ? fdip : rdip;
1585*12004Sjiang.liu@intel.com 
1586*12004Sjiang.liu@intel.com 		(void) ddi_pathname(dip, path);
1587*12004Sjiang.liu@intel.com 		err = drerr_new(1, EX86_DRVFAIL, path);
1588*12004Sjiang.liu@intel.com 		kmem_free(path, MAXPATHLEN);
1589*12004Sjiang.liu@intel.com 
1590*12004Sjiang.liu@intel.com 		/* If non-NULL, fdip is returned held and must be released */
1591*12004Sjiang.liu@intel.com 		if (fdip != NULL)
1592*12004Sjiang.liu@intel.com 			ddi_release_devi(fdip);
1593*12004Sjiang.liu@intel.com 	}
1594*12004Sjiang.liu@intel.com 
1595*12004Sjiang.liu@intel.com 	return (err);
1596*12004Sjiang.liu@intel.com }
1597*12004Sjiang.liu@intel.com 
1598*12004Sjiang.liu@intel.com sbd_error_t *
drmach_unconfigure(drmachid_t id,int flags)1599*12004Sjiang.liu@intel.com drmach_unconfigure(drmachid_t id, int flags)
1600*12004Sjiang.liu@intel.com {
1601*12004Sjiang.liu@intel.com 	_NOTE(ARGUNUSED(flags));
1602*12004Sjiang.liu@intel.com 
1603*12004Sjiang.liu@intel.com 	drmach_device_t *dp;
1604*12004Sjiang.liu@intel.com 	sbd_error_t	*err = NULL;
1605*12004Sjiang.liu@intel.com 	dev_info_t	*rdip, *fdip = NULL;
1606*12004Sjiang.liu@intel.com 
1607*12004Sjiang.liu@intel.com 	if (!DRMACH_IS_DEVICE_ID(id))
1608*12004Sjiang.liu@intel.com 		return (drerr_new(0, EX86_INAPPROP, NULL));
1609*12004Sjiang.liu@intel.com 	dp = id;
1610*12004Sjiang.liu@intel.com 
1611*12004Sjiang.liu@intel.com 	rdip = dp->node->getdip(dp->node);
1612*12004Sjiang.liu@intel.com 	ASSERT(rdip);
1613*12004Sjiang.liu@intel.com 	ASSERT(e_ddi_branch_held(rdip));
1614*12004Sjiang.liu@intel.com 
1615*12004Sjiang.liu@intel.com 	if (DRMACH_IS_CPU_ID(id)) {
1616*12004Sjiang.liu@intel.com 		DRMACH_HANDLE hdl = drmach_node_get_dnode(dp->node);
1617*12004Sjiang.liu@intel.com 		ASSERT(hdl != NULL);
1618*12004Sjiang.liu@intel.com 		if (ACPI_FAILURE(acpidev_dr_free_cpuid(hdl))) {
1619*12004Sjiang.liu@intel.com 			err = drerr_new(1, EX86_FREE_CPUID, NULL);
1620*12004Sjiang.liu@intel.com 		}
1621*12004Sjiang.liu@intel.com 		return (err);
1622*12004Sjiang.liu@intel.com 	}
1623*12004Sjiang.liu@intel.com 
1624*12004Sjiang.liu@intel.com 	/*
1625*12004Sjiang.liu@intel.com 	 * Note: FORCE flag is no longer necessary under devfs
1626*12004Sjiang.liu@intel.com 	 */
1627*12004Sjiang.liu@intel.com 	if (e_ddi_branch_unconfigure(rdip, &fdip, 0)) {
1628*12004Sjiang.liu@intel.com 		char		*path = kmem_alloc(MAXPATHLEN, KM_SLEEP);
1629*12004Sjiang.liu@intel.com 
1630*12004Sjiang.liu@intel.com 		/*
1631*12004Sjiang.liu@intel.com 		 * If non-NULL, fdip is returned held and must be released.
1632*12004Sjiang.liu@intel.com 		 */
1633*12004Sjiang.liu@intel.com 		if (fdip != NULL) {
1634*12004Sjiang.liu@intel.com 			(void) ddi_pathname(fdip, path);
1635*12004Sjiang.liu@intel.com 			ndi_rele_devi(fdip);
1636*12004Sjiang.liu@intel.com 		} else {
1637*12004Sjiang.liu@intel.com 			(void) ddi_pathname(rdip, path);
1638*12004Sjiang.liu@intel.com 		}
1639*12004Sjiang.liu@intel.com 
1640*12004Sjiang.liu@intel.com 		err = drerr_new(1, EX86_DRVFAIL, path);
1641*12004Sjiang.liu@intel.com 
1642*12004Sjiang.liu@intel.com 		kmem_free(path, MAXPATHLEN);
1643*12004Sjiang.liu@intel.com 	}
1644*12004Sjiang.liu@intel.com 
1645*12004Sjiang.liu@intel.com 	return (err);
1646*12004Sjiang.liu@intel.com }
1647*12004Sjiang.liu@intel.com 
1648*12004Sjiang.liu@intel.com sbd_error_t *
drmach_get_dip(drmachid_t id,dev_info_t ** dip)1649*12004Sjiang.liu@intel.com drmach_get_dip(drmachid_t id, dev_info_t **dip)
1650*12004Sjiang.liu@intel.com {
1651*12004Sjiang.liu@intel.com 	drmach_device_t	*dp;
1652*12004Sjiang.liu@intel.com 
1653*12004Sjiang.liu@intel.com 	if (!DRMACH_IS_DEVICE_ID(id))
1654*12004Sjiang.liu@intel.com 		return (drerr_new(0, EX86_INAPPROP, NULL));
1655*12004Sjiang.liu@intel.com 	dp = id;
1656*12004Sjiang.liu@intel.com 
1657*12004Sjiang.liu@intel.com 	*dip = dp->node->getdip(dp->node);
1658*12004Sjiang.liu@intel.com 
1659*12004Sjiang.liu@intel.com 	return (NULL);
1660*12004Sjiang.liu@intel.com }
1661*12004Sjiang.liu@intel.com 
1662*12004Sjiang.liu@intel.com sbd_error_t *
drmach_release(drmachid_t id)1663*12004Sjiang.liu@intel.com drmach_release(drmachid_t id)
1664*12004Sjiang.liu@intel.com {
1665*12004Sjiang.liu@intel.com 	drmach_common_t *cp;
1666*12004Sjiang.liu@intel.com 
1667*12004Sjiang.liu@intel.com 	if (!DRMACH_IS_DEVICE_ID(id))
1668*12004Sjiang.liu@intel.com 		return (drerr_new(0, EX86_INAPPROP, NULL));
1669*12004Sjiang.liu@intel.com 	cp = id;
1670*12004Sjiang.liu@intel.com 
1671*12004Sjiang.liu@intel.com 	return (cp->release(id));
1672*12004Sjiang.liu@intel.com }
1673*12004Sjiang.liu@intel.com 
1674*12004Sjiang.liu@intel.com sbd_error_t *
drmach_status(drmachid_t id,drmach_status_t * stat)1675*12004Sjiang.liu@intel.com drmach_status(drmachid_t id, drmach_status_t *stat)
1676*12004Sjiang.liu@intel.com {
1677*12004Sjiang.liu@intel.com 	drmach_common_t *cp;
1678*12004Sjiang.liu@intel.com 	sbd_error_t	*err;
1679*12004Sjiang.liu@intel.com 
1680*12004Sjiang.liu@intel.com 	rw_enter(&drmach_boards_rwlock, RW_READER);
1681*12004Sjiang.liu@intel.com 	if (!DRMACH_IS_ID(id)) {
1682*12004Sjiang.liu@intel.com 		rw_exit(&drmach_boards_rwlock);
1683*12004Sjiang.liu@intel.com 		return (drerr_new(0, EX86_NOTID, NULL));
1684*12004Sjiang.liu@intel.com 	}
1685*12004Sjiang.liu@intel.com 	cp = (drmach_common_t *)id;
1686*12004Sjiang.liu@intel.com 	err = cp->status(id, stat);
1687*12004Sjiang.liu@intel.com 	rw_exit(&drmach_boards_rwlock);
1688*12004Sjiang.liu@intel.com 
1689*12004Sjiang.liu@intel.com 	return (err);
1690*12004Sjiang.liu@intel.com }
1691*12004Sjiang.liu@intel.com 
1692*12004Sjiang.liu@intel.com static sbd_error_t *
drmach_update_acpi_status(drmachid_t id,drmach_opts_t * opts)1693*12004Sjiang.liu@intel.com drmach_update_acpi_status(drmachid_t id, drmach_opts_t *opts)
1694*12004Sjiang.liu@intel.com {
1695*12004Sjiang.liu@intel.com 	char		*copts;
1696*12004Sjiang.liu@intel.com 	drmach_board_t	*bp;
1697*12004Sjiang.liu@intel.com 	DRMACH_HANDLE	hdl;
1698*12004Sjiang.liu@intel.com 	int		event, code;
1699*12004Sjiang.liu@intel.com 	boolean_t	inprogress = B_FALSE;
1700*12004Sjiang.liu@intel.com 
1701*12004Sjiang.liu@intel.com 	if (DRMACH_NULL_ID(id) || !DRMACH_IS_BOARD_ID(id))
1702*12004Sjiang.liu@intel.com 		return (drerr_new(0, EX86_INAPPROP, NULL));
1703*12004Sjiang.liu@intel.com 	bp = (drmach_board_t *)id;
1704*12004Sjiang.liu@intel.com 	hdl = drmach_node_get_dnode(bp->tree);
1705*12004Sjiang.liu@intel.com 	ASSERT(hdl != NULL);
1706*12004Sjiang.liu@intel.com 	if (hdl == NULL)
1707*12004Sjiang.liu@intel.com 		return (drerr_new(0, EX86_INAPPROP, NULL));
1708*12004Sjiang.liu@intel.com 
1709*12004Sjiang.liu@intel.com 	/* Get the status code. */
1710*12004Sjiang.liu@intel.com 	copts = opts->copts;
1711*12004Sjiang.liu@intel.com 	if (strncmp(copts, ACPIDEV_CMD_OST_INPROGRESS,
1712*12004Sjiang.liu@intel.com 	    strlen(ACPIDEV_CMD_OST_INPROGRESS)) == 0) {
1713*12004Sjiang.liu@intel.com 		inprogress = B_TRUE;
1714*12004Sjiang.liu@intel.com 		code = ACPI_OST_STA_INSERT_IN_PROGRESS;
1715*12004Sjiang.liu@intel.com 		copts += strlen(ACPIDEV_CMD_OST_INPROGRESS);
1716*12004Sjiang.liu@intel.com 	} else if (strncmp(copts, ACPIDEV_CMD_OST_SUCCESS,
1717*12004Sjiang.liu@intel.com 	    strlen(ACPIDEV_CMD_OST_SUCCESS)) == 0) {
1718*12004Sjiang.liu@intel.com 		code = ACPI_OST_STA_SUCCESS;
1719*12004Sjiang.liu@intel.com 		copts += strlen(ACPIDEV_CMD_OST_SUCCESS);
1720*12004Sjiang.liu@intel.com 	} else if (strncmp(copts, ACPIDEV_CMD_OST_FAILURE,
1721*12004Sjiang.liu@intel.com 	    strlen(ACPIDEV_CMD_OST_FAILURE)) == 0) {
1722*12004Sjiang.liu@intel.com 		code = ACPI_OST_STA_FAILURE;
1723*12004Sjiang.liu@intel.com 		copts += strlen(ACPIDEV_CMD_OST_FAILURE);
1724*12004Sjiang.liu@intel.com 	} else if (strncmp(copts, ACPIDEV_CMD_OST_NOOP,
1725*12004Sjiang.liu@intel.com 	    strlen(ACPIDEV_CMD_OST_NOOP)) == 0) {
1726*12004Sjiang.liu@intel.com 		return (NULL);
1727*12004Sjiang.liu@intel.com 	} else {
1728*12004Sjiang.liu@intel.com 		return (drerr_new(0, EX86_UNKPTCMD, opts->copts));
1729*12004Sjiang.liu@intel.com 	}
1730*12004Sjiang.liu@intel.com 
1731*12004Sjiang.liu@intel.com 	/* Get the event type. */
1732*12004Sjiang.liu@intel.com 	copts = strstr(copts, ACPIDEV_EVENT_TYPE_ATTR_NAME);
1733*12004Sjiang.liu@intel.com 	if (copts == NULL) {
1734*12004Sjiang.liu@intel.com 		return (drerr_new(0, EX86_UNKPTCMD, opts->copts));
1735*12004Sjiang.liu@intel.com 	}
1736*12004Sjiang.liu@intel.com 	copts += strlen(ACPIDEV_EVENT_TYPE_ATTR_NAME);
1737*12004Sjiang.liu@intel.com 	if (copts[0] != '=') {
1738*12004Sjiang.liu@intel.com 		return (drerr_new(0, EX86_UNKPTCMD, opts->copts));
1739*12004Sjiang.liu@intel.com 	}
1740*12004Sjiang.liu@intel.com 	copts += strlen("=");
1741*12004Sjiang.liu@intel.com 	if (strncmp(copts, ACPIDEV_EVENT_TYPE_BUS_CHECK,
1742*12004Sjiang.liu@intel.com 	    strlen(ACPIDEV_EVENT_TYPE_BUS_CHECK)) == 0) {
1743*12004Sjiang.liu@intel.com 		event = ACPI_NOTIFY_BUS_CHECK;
1744*12004Sjiang.liu@intel.com 	} else if (strncmp(copts, ACPIDEV_EVENT_TYPE_DEVICE_CHECK,
1745*12004Sjiang.liu@intel.com 	    strlen(ACPIDEV_EVENT_TYPE_DEVICE_CHECK)) == 0) {
1746*12004Sjiang.liu@intel.com 		event = ACPI_NOTIFY_DEVICE_CHECK;
1747*12004Sjiang.liu@intel.com 	} else if (strncmp(copts, ACPIDEV_EVENT_TYPE_DEVICE_CHECK_LIGHT,
1748*12004Sjiang.liu@intel.com 	    strlen(ACPIDEV_EVENT_TYPE_DEVICE_CHECK_LIGHT)) == 0) {
1749*12004Sjiang.liu@intel.com 		event = ACPI_NOTIFY_DEVICE_CHECK_LIGHT;
1750*12004Sjiang.liu@intel.com 	} else if (strncmp(copts, ACPIDEV_EVENT_TYPE_EJECT_REQUEST,
1751*12004Sjiang.liu@intel.com 	    strlen(ACPIDEV_EVENT_TYPE_EJECT_REQUEST)) == 0) {
1752*12004Sjiang.liu@intel.com 		event = ACPI_NOTIFY_EJECT_REQUEST;
1753*12004Sjiang.liu@intel.com 		if (inprogress) {
1754*12004Sjiang.liu@intel.com 			code = ACPI_OST_STA_EJECT_IN_PROGRESS;
1755*12004Sjiang.liu@intel.com 		}
1756*12004Sjiang.liu@intel.com 	} else {
1757*12004Sjiang.liu@intel.com 		return (drerr_new(0, EX86_UNKPTCMD, opts->copts));
1758*12004Sjiang.liu@intel.com 	}
1759*12004Sjiang.liu@intel.com 
1760*12004Sjiang.liu@intel.com 	(void) acpidev_eval_ost(hdl, event, code, NULL, 0);
1761*12004Sjiang.liu@intel.com 
1762*12004Sjiang.liu@intel.com 	return (NULL);
1763*12004Sjiang.liu@intel.com }
1764*12004Sjiang.liu@intel.com 
1765*12004Sjiang.liu@intel.com static struct {
1766*12004Sjiang.liu@intel.com 	const char	*name;
1767*12004Sjiang.liu@intel.com 	sbd_error_t	*(*handler)(drmachid_t id, drmach_opts_t *opts);
1768*12004Sjiang.liu@intel.com } drmach_pt_arr[] = {
1769*12004Sjiang.liu@intel.com 	{ ACPIDEV_CMD_OST_PREFIX,	&drmach_update_acpi_status	},
1770*12004Sjiang.liu@intel.com 	/* the following line must always be last */
1771*12004Sjiang.liu@intel.com 	{ NULL,				NULL				}
1772*12004Sjiang.liu@intel.com };
1773*12004Sjiang.liu@intel.com 
1774*12004Sjiang.liu@intel.com sbd_error_t *
drmach_passthru(drmachid_t id,drmach_opts_t * opts)1775*12004Sjiang.liu@intel.com drmach_passthru(drmachid_t id, drmach_opts_t *opts)
1776*12004Sjiang.liu@intel.com {
1777*12004Sjiang.liu@intel.com 	int		i;
1778*12004Sjiang.liu@intel.com 	sbd_error_t	*err;
1779*12004Sjiang.liu@intel.com 
1780*12004Sjiang.liu@intel.com 	i = 0;
1781*12004Sjiang.liu@intel.com 	while (drmach_pt_arr[i].name != NULL) {
1782*12004Sjiang.liu@intel.com 		int len = strlen(drmach_pt_arr[i].name);
1783*12004Sjiang.liu@intel.com 
1784*12004Sjiang.liu@intel.com 		if (strncmp(drmach_pt_arr[i].name, opts->copts, len) == 0)
1785*12004Sjiang.liu@intel.com 			break;
1786*12004Sjiang.liu@intel.com 
1787*12004Sjiang.liu@intel.com 		i += 1;
1788*12004Sjiang.liu@intel.com 	}
1789*12004Sjiang.liu@intel.com 
1790*12004Sjiang.liu@intel.com 	if (drmach_pt_arr[i].name == NULL)
1791*12004Sjiang.liu@intel.com 		err = drerr_new(0, EX86_UNKPTCMD, opts->copts);
1792*12004Sjiang.liu@intel.com 	else
1793*12004Sjiang.liu@intel.com 		err = (*drmach_pt_arr[i].handler)(id, opts);
1794*12004Sjiang.liu@intel.com 
1795*12004Sjiang.liu@intel.com 	return (err);
1796*12004Sjiang.liu@intel.com }
1797*12004Sjiang.liu@intel.com 
1798*12004Sjiang.liu@intel.com /*
1799*12004Sjiang.liu@intel.com  * Board specific interfaces to support dr driver
1800*12004Sjiang.liu@intel.com  */
1801*12004Sjiang.liu@intel.com static int
drmach_get_portid(drmach_node_t * np)1802*12004Sjiang.liu@intel.com drmach_get_portid(drmach_node_t *np)
1803*12004Sjiang.liu@intel.com {
1804*12004Sjiang.liu@intel.com 	uint32_t	portid;
1805*12004Sjiang.liu@intel.com 
1806*12004Sjiang.liu@intel.com 	if (np->getprop(np, ACPIDEV_DR_PROP_PORTID,
1807*12004Sjiang.liu@intel.com 	    &portid, sizeof (portid)) == 0) {
1808*12004Sjiang.liu@intel.com 		/*
1809*12004Sjiang.liu@intel.com 		 * acpidev returns portid as uint32_t, validates it.
1810*12004Sjiang.liu@intel.com 		 */
1811*12004Sjiang.liu@intel.com 		if (portid > INT_MAX) {
1812*12004Sjiang.liu@intel.com 			return (-1);
1813*12004Sjiang.liu@intel.com 		} else {
1814*12004Sjiang.liu@intel.com 			return (portid);
1815*12004Sjiang.liu@intel.com 		}
1816*12004Sjiang.liu@intel.com 	}
1817*12004Sjiang.liu@intel.com 
1818*12004Sjiang.liu@intel.com 	return (-1);
1819*12004Sjiang.liu@intel.com }
1820*12004Sjiang.liu@intel.com 
1821*12004Sjiang.liu@intel.com /*
1822*12004Sjiang.liu@intel.com  * This is a helper function to determine if a given
1823*12004Sjiang.liu@intel.com  * node should be considered for a dr operation according
1824*12004Sjiang.liu@intel.com  * to predefined dr type nodes and the node's name.
1825*12004Sjiang.liu@intel.com  * Formal Parameter : The name of a device node.
1826*12004Sjiang.liu@intel.com  * Return Value: -1, name does not map to a valid dr type.
1827*12004Sjiang.liu@intel.com  *		 A value greater or equal to 0, name is a valid dr type.
1828*12004Sjiang.liu@intel.com  */
1829*12004Sjiang.liu@intel.com static int
drmach_name2type_idx(char * name)1830*12004Sjiang.liu@intel.com drmach_name2type_idx(char *name)
1831*12004Sjiang.liu@intel.com {
1832*12004Sjiang.liu@intel.com 	int 	index, ntypes;
1833*12004Sjiang.liu@intel.com 
1834*12004Sjiang.liu@intel.com 	if (name == NULL)
1835*12004Sjiang.liu@intel.com 		return (-1);
1836*12004Sjiang.liu@intel.com 
1837*12004Sjiang.liu@intel.com 	/*
1838*12004Sjiang.liu@intel.com 	 * Determine how many possible types are currently supported
1839*12004Sjiang.liu@intel.com 	 * for dr.
1840*12004Sjiang.liu@intel.com 	 */
1841*12004Sjiang.liu@intel.com 	ntypes = sizeof (drmach_name2type) / sizeof (drmach_name2type[0]);
1842*12004Sjiang.liu@intel.com 
1843*12004Sjiang.liu@intel.com 	/* Determine if the node's name correspond to a predefined type. */
1844*12004Sjiang.liu@intel.com 	for (index = 0; index < ntypes; index++) {
1845*12004Sjiang.liu@intel.com 		if (strcmp(drmach_name2type[index].name, name) == 0)
1846*12004Sjiang.liu@intel.com 			/* The node is an allowed type for dr. */
1847*12004Sjiang.liu@intel.com 			return (index);
1848*12004Sjiang.liu@intel.com 	}
1849*12004Sjiang.liu@intel.com 
1850*12004Sjiang.liu@intel.com 	/*
1851*12004Sjiang.liu@intel.com 	 * If the name of the node does not map to any of the
1852*12004Sjiang.liu@intel.com 	 * types in the array drmach_name2type then the node is not of
1853*12004Sjiang.liu@intel.com 	 * interest to dr.
1854*12004Sjiang.liu@intel.com 	 */
1855*12004Sjiang.liu@intel.com 	return (-1);
1856*12004Sjiang.liu@intel.com }
1857*12004Sjiang.liu@intel.com 
1858*12004Sjiang.liu@intel.com static int
drmach_board_find_devices_cb(drmach_node_walk_args_t * args)1859*12004Sjiang.liu@intel.com drmach_board_find_devices_cb(drmach_node_walk_args_t *args)
1860*12004Sjiang.liu@intel.com {
1861*12004Sjiang.liu@intel.com 	drmach_node_t			*node = args->node;
1862*12004Sjiang.liu@intel.com 	drmach_board_cb_data_t		*data = args->data;
1863*12004Sjiang.liu@intel.com 	drmach_board_t			*obj = data->obj;
1864*12004Sjiang.liu@intel.com 
1865*12004Sjiang.liu@intel.com 	int		rv, portid;
1866*12004Sjiang.liu@intel.com 	uint32_t	bnum;
1867*12004Sjiang.liu@intel.com 	drmachid_t	id;
1868*12004Sjiang.liu@intel.com 	drmach_device_t	*device;
1869*12004Sjiang.liu@intel.com 	char		name[OBP_MAXDRVNAME];
1870*12004Sjiang.liu@intel.com 
1871*12004Sjiang.liu@intel.com 	portid = drmach_get_portid(node);
1872*12004Sjiang.liu@intel.com 	rv = node->getprop(node, ACPIDEV_DR_PROP_DEVNAME,
1873*12004Sjiang.liu@intel.com 	    name, OBP_MAXDRVNAME);
1874*12004Sjiang.liu@intel.com 	if (rv)
1875*12004Sjiang.liu@intel.com 		return (0);
1876*12004Sjiang.liu@intel.com 
1877*12004Sjiang.liu@intel.com 	rv = node->getprop(node, ACPIDEV_DR_PROP_BOARDNUM,
1878*12004Sjiang.liu@intel.com 	    &bnum, sizeof (bnum));
1879*12004Sjiang.liu@intel.com 	if (rv) {
1880*12004Sjiang.liu@intel.com 		return (0);
1881*12004Sjiang.liu@intel.com 	}
1882*12004Sjiang.liu@intel.com 	if (bnum > INT_MAX) {
1883*12004Sjiang.liu@intel.com 		return (0);
1884*12004Sjiang.liu@intel.com 	}
1885*12004Sjiang.liu@intel.com 
1886*12004Sjiang.liu@intel.com 	if (bnum != obj->bnum)
1887*12004Sjiang.liu@intel.com 		return (0);
1888*12004Sjiang.liu@intel.com 
1889*12004Sjiang.liu@intel.com 	if (drmach_name2type_idx(name) < 0) {
1890*12004Sjiang.liu@intel.com 		return (0);
1891*12004Sjiang.liu@intel.com 	}
1892*12004Sjiang.liu@intel.com 
1893*12004Sjiang.liu@intel.com 	/*
1894*12004Sjiang.liu@intel.com 	 * Create a device data structure from this node data.
1895*12004Sjiang.liu@intel.com 	 * The call may yield nothing if the node is not of interest
1896*12004Sjiang.liu@intel.com 	 * to drmach.
1897*12004Sjiang.liu@intel.com 	 */
1898*12004Sjiang.liu@intel.com 	data->err = drmach_device_new(node, obj, portid, &id);
1899*12004Sjiang.liu@intel.com 	if (data->err)
1900*12004Sjiang.liu@intel.com 		return (-1);
1901*12004Sjiang.liu@intel.com 	else if (!id) {
1902*12004Sjiang.liu@intel.com 		/*
1903*12004Sjiang.liu@intel.com 		 * drmach_device_new examined the node we passed in
1904*12004Sjiang.liu@intel.com 		 * and determined that it was one not of interest to
1905*12004Sjiang.liu@intel.com 		 * drmach.  So, it is skipped.
1906*12004Sjiang.liu@intel.com 		 */
1907*12004Sjiang.liu@intel.com 		return (0);
1908*12004Sjiang.liu@intel.com 	}
1909*12004Sjiang.liu@intel.com 
1910*12004Sjiang.liu@intel.com 	rv = drmach_array_set(obj->devices, data->ndevs++, id);
1911*12004Sjiang.liu@intel.com 	if (rv) {
1912*12004Sjiang.liu@intel.com 		data->err = DRMACH_INTERNAL_ERROR();
1913*12004Sjiang.liu@intel.com 		return (-1);
1914*12004Sjiang.liu@intel.com 	}
1915*12004Sjiang.liu@intel.com 	device = id;
1916*12004Sjiang.liu@intel.com 
1917*12004Sjiang.liu@intel.com 	data->err = (*data->found)(data->a, device->type, device->unum, id);
1918*12004Sjiang.liu@intel.com 
1919*12004Sjiang.liu@intel.com 	return (data->err == NULL ? 0 : -1);
1920*12004Sjiang.liu@intel.com }
1921*12004Sjiang.liu@intel.com 
1922*12004Sjiang.liu@intel.com sbd_error_t *
drmach_board_find_devices(drmachid_t id,void * a,sbd_error_t * (* found)(void * a,const char *,int,drmachid_t))1923*12004Sjiang.liu@intel.com drmach_board_find_devices(drmachid_t id, void *a,
1924*12004Sjiang.liu@intel.com 	sbd_error_t *(*found)(void *a, const char *, int, drmachid_t))
1925*12004Sjiang.liu@intel.com {
1926*12004Sjiang.liu@intel.com 	drmach_board_t		*bp = (drmach_board_t *)id;
1927*12004Sjiang.liu@intel.com 	sbd_error_t		*err;
1928*12004Sjiang.liu@intel.com 	int			 max_devices;
1929*12004Sjiang.liu@intel.com 	int			 rv;
1930*12004Sjiang.liu@intel.com 	drmach_board_cb_data_t	data;
1931*12004Sjiang.liu@intel.com 
1932*12004Sjiang.liu@intel.com 	if (!DRMACH_IS_BOARD_ID(id))
1933*12004Sjiang.liu@intel.com 		return (drerr_new(0, EX86_INAPPROP, NULL));
1934*12004Sjiang.liu@intel.com 
1935*12004Sjiang.liu@intel.com 	max_devices  = MAX_CPU_UNITS_PER_BOARD;
1936*12004Sjiang.liu@intel.com 	max_devices += MAX_MEM_UNITS_PER_BOARD;
1937*12004Sjiang.liu@intel.com 	max_devices += MAX_IO_UNITS_PER_BOARD;
1938*12004Sjiang.liu@intel.com 
1939*12004Sjiang.liu@intel.com 	if (bp->devices == NULL)
1940*12004Sjiang.liu@intel.com 		bp->devices = drmach_array_new(0, max_devices);
1941*12004Sjiang.liu@intel.com 	ASSERT(bp->tree != NULL);
1942*12004Sjiang.liu@intel.com 
1943*12004Sjiang.liu@intel.com 	data.obj = bp;
1944*12004Sjiang.liu@intel.com 	data.ndevs = 0;
1945*12004Sjiang.liu@intel.com 	data.found = found;
1946*12004Sjiang.liu@intel.com 	data.a = a;
1947*12004Sjiang.liu@intel.com 	data.err = NULL;
1948*12004Sjiang.liu@intel.com 
1949*12004Sjiang.liu@intel.com 	acpidev_dr_lock_all();
1950*12004Sjiang.liu@intel.com 	rv = drmach_node_walk(bp->tree, &data, drmach_board_find_devices_cb);
1951*12004Sjiang.liu@intel.com 	acpidev_dr_unlock_all();
1952*12004Sjiang.liu@intel.com 	if (rv == 0) {
1953*12004Sjiang.liu@intel.com 		err = NULL;
1954*12004Sjiang.liu@intel.com 	} else {
1955*12004Sjiang.liu@intel.com 		drmach_array_dispose(bp->devices, drmach_device_dispose);
1956*12004Sjiang.liu@intel.com 		bp->devices = NULL;
1957*12004Sjiang.liu@intel.com 
1958*12004Sjiang.liu@intel.com 		if (data.err)
1959*12004Sjiang.liu@intel.com 			err = data.err;
1960*12004Sjiang.liu@intel.com 		else
1961*12004Sjiang.liu@intel.com 			err = DRMACH_INTERNAL_ERROR();
1962*12004Sjiang.liu@intel.com 	}
1963*12004Sjiang.liu@intel.com 
1964*12004Sjiang.liu@intel.com 	return (err);
1965*12004Sjiang.liu@intel.com }
1966*12004Sjiang.liu@intel.com 
1967*12004Sjiang.liu@intel.com int
drmach_board_lookup(int bnum,drmachid_t * id)1968*12004Sjiang.liu@intel.com drmach_board_lookup(int bnum, drmachid_t *id)
1969*12004Sjiang.liu@intel.com {
1970*12004Sjiang.liu@intel.com 	int	rv = 0;
1971*12004Sjiang.liu@intel.com 
1972*12004Sjiang.liu@intel.com 	if (bnum < 0) {
1973*12004Sjiang.liu@intel.com 		*id = 0;
1974*12004Sjiang.liu@intel.com 		return (-1);
1975*12004Sjiang.liu@intel.com 	}
1976*12004Sjiang.liu@intel.com 
1977*12004Sjiang.liu@intel.com 	rw_enter(&drmach_boards_rwlock, RW_READER);
1978*12004Sjiang.liu@intel.com 	if (drmach_array_get(drmach_boards, (uint_t)bnum, id)) {
1979*12004Sjiang.liu@intel.com 		*id = 0;
1980*12004Sjiang.liu@intel.com 		rv = -1;
1981*12004Sjiang.liu@intel.com 	}
1982*12004Sjiang.liu@intel.com 	rw_exit(&drmach_boards_rwlock);
1983*12004Sjiang.liu@intel.com 
1984*12004Sjiang.liu@intel.com 	return (rv);
1985*12004Sjiang.liu@intel.com }
1986*12004Sjiang.liu@intel.com 
1987*12004Sjiang.liu@intel.com sbd_error_t *
drmach_board_name(int bnum,char * buf,int buflen)1988*12004Sjiang.liu@intel.com drmach_board_name(int bnum, char *buf, int buflen)
1989*12004Sjiang.liu@intel.com {
1990*12004Sjiang.liu@intel.com 	ACPI_HANDLE hdl;
1991*12004Sjiang.liu@intel.com 	sbd_error_t *err = NULL;
1992*12004Sjiang.liu@intel.com 
1993*12004Sjiang.liu@intel.com 	if (bnum < 0) {
1994*12004Sjiang.liu@intel.com 		return (drerr_new(1, EX86_BNUM, "%d", bnum));
1995*12004Sjiang.liu@intel.com 	}
1996*12004Sjiang.liu@intel.com 
1997*12004Sjiang.liu@intel.com 	acpidev_dr_lock_all();
1998*12004Sjiang.liu@intel.com 	if (ACPI_FAILURE(acpidev_dr_get_board_handle(bnum, &hdl))) {
1999*12004Sjiang.liu@intel.com 		DRMACH_PR("!drmach_board_name: failed to lookup ACPI handle "
2000*12004Sjiang.liu@intel.com 		    "for board %d.", bnum);
2001*12004Sjiang.liu@intel.com 		err = drerr_new(1, EX86_BNUM, "%d", bnum);
2002*12004Sjiang.liu@intel.com 	} else if (ACPI_FAILURE(acpidev_dr_get_board_name(hdl, buf, buflen))) {
2003*12004Sjiang.liu@intel.com 		DRMACH_PR("!drmach_board_name: failed to generate board name "
2004*12004Sjiang.liu@intel.com 		    "for board %d.", bnum);
2005*12004Sjiang.liu@intel.com 		err = drerr_new(0, EX86_INVALID_ARG,
2006*12004Sjiang.liu@intel.com 		    ": buffer is too small for board name.");
2007*12004Sjiang.liu@intel.com 	}
2008*12004Sjiang.liu@intel.com 	acpidev_dr_unlock_all();
2009*12004Sjiang.liu@intel.com 
2010*12004Sjiang.liu@intel.com 	return (err);
2011*12004Sjiang.liu@intel.com }
2012*12004Sjiang.liu@intel.com 
2013*12004Sjiang.liu@intel.com int
drmach_board_is_floating(drmachid_t id)2014*12004Sjiang.liu@intel.com drmach_board_is_floating(drmachid_t id)
2015*12004Sjiang.liu@intel.com {
2016*12004Sjiang.liu@intel.com 	drmach_board_t *bp;
2017*12004Sjiang.liu@intel.com 
2018*12004Sjiang.liu@intel.com 	if (!DRMACH_IS_BOARD_ID(id))
2019*12004Sjiang.liu@intel.com 		return (0);
2020*12004Sjiang.liu@intel.com 
2021*12004Sjiang.liu@intel.com 	bp = (drmach_board_t *)id;
2022*12004Sjiang.liu@intel.com 
2023*12004Sjiang.liu@intel.com 	return ((drmach_domain.floating & (1ULL << bp->bnum)) ? 1 : 0);
2024*12004Sjiang.liu@intel.com }
2025*12004Sjiang.liu@intel.com 
2026*12004Sjiang.liu@intel.com static ACPI_STATUS
drmach_board_check_dependent_cb(ACPI_HANDLE hdl,UINT32 lvl,void * ctx,void ** retval)2027*12004Sjiang.liu@intel.com drmach_board_check_dependent_cb(ACPI_HANDLE hdl, UINT32 lvl, void *ctx,
2028*12004Sjiang.liu@intel.com     void **retval)
2029*12004Sjiang.liu@intel.com {
2030*12004Sjiang.liu@intel.com 	uint32_t bdnum;
2031*12004Sjiang.liu@intel.com 	drmach_board_t *bp;
2032*12004Sjiang.liu@intel.com 	ACPI_STATUS rc = AE_OK;
2033*12004Sjiang.liu@intel.com 	int cmd = (int)(intptr_t)ctx;
2034*12004Sjiang.liu@intel.com 
2035*12004Sjiang.liu@intel.com 	ASSERT(hdl != NULL);
2036*12004Sjiang.liu@intel.com 	ASSERT(lvl == UINT32_MAX);
2037*12004Sjiang.liu@intel.com 	ASSERT(retval != NULL);
2038*12004Sjiang.liu@intel.com 
2039*12004Sjiang.liu@intel.com 	/* Skip non-board devices. */
2040*12004Sjiang.liu@intel.com 	if (!acpidev_dr_device_is_board(hdl)) {
2041*12004Sjiang.liu@intel.com 		return (AE_OK);
2042*12004Sjiang.liu@intel.com 	} else if (ACPI_FAILURE(acpidev_dr_get_board_number(hdl, &bdnum))) {
2043*12004Sjiang.liu@intel.com 		DRMACH_PR("!drmach_board_check_dependent_cb: failed to get "
2044*12004Sjiang.liu@intel.com 		    "board number for object %p.\n", hdl);
2045*12004Sjiang.liu@intel.com 		return (AE_ERROR);
2046*12004Sjiang.liu@intel.com 	} else if (bdnum > MAX_BOARDS) {
2047*12004Sjiang.liu@intel.com 		DRMACH_PR("!drmach_board_check_dependent_cb: board number %u "
2048*12004Sjiang.liu@intel.com 		    "is too big, max %u.", bdnum, MAX_BOARDS);
2049*12004Sjiang.liu@intel.com 		return (AE_ERROR);
2050*12004Sjiang.liu@intel.com 	}
2051*12004Sjiang.liu@intel.com 
2052*12004Sjiang.liu@intel.com 	bp = drmach_get_board_by_bnum(bdnum);
2053*12004Sjiang.liu@intel.com 	switch (cmd) {
2054*12004Sjiang.liu@intel.com 	case SBD_CMD_CONNECT:
2055*12004Sjiang.liu@intel.com 		/*
2056*12004Sjiang.liu@intel.com 		 * Its parent board should be present, assigned, powered and
2057*12004Sjiang.liu@intel.com 		 * connected when connecting the child board.
2058*12004Sjiang.liu@intel.com 		 */
2059*12004Sjiang.liu@intel.com 		if (bp == NULL) {
2060*12004Sjiang.liu@intel.com 			*retval = hdl;
2061*12004Sjiang.liu@intel.com 			rc = AE_ERROR;
2062*12004Sjiang.liu@intel.com 		} else {
2063*12004Sjiang.liu@intel.com 			bp->powered = acpidev_dr_device_is_powered(hdl);
2064*12004Sjiang.liu@intel.com 			if (!bp->connected || !bp->powered || !bp->assigned) {
2065*12004Sjiang.liu@intel.com 				*retval = hdl;
2066*12004Sjiang.liu@intel.com 				rc = AE_ERROR;
2067*12004Sjiang.liu@intel.com 			}
2068*12004Sjiang.liu@intel.com 		}
2069*12004Sjiang.liu@intel.com 		break;
2070*12004Sjiang.liu@intel.com 
2071*12004Sjiang.liu@intel.com 	case SBD_CMD_POWERON:
2072*12004Sjiang.liu@intel.com 		/*
2073*12004Sjiang.liu@intel.com 		 * Its parent board should be present, assigned and powered when
2074*12004Sjiang.liu@intel.com 		 * powering on the child board.
2075*12004Sjiang.liu@intel.com 		 */
2076*12004Sjiang.liu@intel.com 		if (bp == NULL) {
2077*12004Sjiang.liu@intel.com 			*retval = hdl;
2078*12004Sjiang.liu@intel.com 			rc = AE_ERROR;
2079*12004Sjiang.liu@intel.com 		} else {
2080*12004Sjiang.liu@intel.com 			bp->powered = acpidev_dr_device_is_powered(hdl);
2081*12004Sjiang.liu@intel.com 			if (!bp->powered || !bp->assigned) {
2082*12004Sjiang.liu@intel.com 				*retval = hdl;
2083*12004Sjiang.liu@intel.com 				rc = AE_ERROR;
2084*12004Sjiang.liu@intel.com 			}
2085*12004Sjiang.liu@intel.com 		}
2086*12004Sjiang.liu@intel.com 		break;
2087*12004Sjiang.liu@intel.com 
2088*12004Sjiang.liu@intel.com 	case SBD_CMD_ASSIGN:
2089*12004Sjiang.liu@intel.com 		/*
2090*12004Sjiang.liu@intel.com 		 * Its parent board should be present and assigned when
2091*12004Sjiang.liu@intel.com 		 * assigning the child board.
2092*12004Sjiang.liu@intel.com 		 */
2093*12004Sjiang.liu@intel.com 		if (bp == NULL) {
2094*12004Sjiang.liu@intel.com 			*retval = hdl;
2095*12004Sjiang.liu@intel.com 			rc = AE_ERROR;
2096*12004Sjiang.liu@intel.com 		} else if (!bp->assigned) {
2097*12004Sjiang.liu@intel.com 			*retval = hdl;
2098*12004Sjiang.liu@intel.com 			rc = AE_ERROR;
2099*12004Sjiang.liu@intel.com 		}
2100*12004Sjiang.liu@intel.com 		break;
2101*12004Sjiang.liu@intel.com 
2102*12004Sjiang.liu@intel.com 	case SBD_CMD_DISCONNECT:
2103*12004Sjiang.liu@intel.com 		/*
2104*12004Sjiang.liu@intel.com 		 * The child board should be disconnected if present when
2105*12004Sjiang.liu@intel.com 		 * disconnecting its parent board.
2106*12004Sjiang.liu@intel.com 		 */
2107*12004Sjiang.liu@intel.com 		if (bp != NULL && bp->connected) {
2108*12004Sjiang.liu@intel.com 			*retval = hdl;
2109*12004Sjiang.liu@intel.com 			rc = AE_ERROR;
2110*12004Sjiang.liu@intel.com 		}
2111*12004Sjiang.liu@intel.com 		break;
2112*12004Sjiang.liu@intel.com 
2113*12004Sjiang.liu@intel.com 	case SBD_CMD_POWEROFF:
2114*12004Sjiang.liu@intel.com 		/*
2115*12004Sjiang.liu@intel.com 		 * The child board should be disconnected and powered off if
2116*12004Sjiang.liu@intel.com 		 * present when powering off its parent board.
2117*12004Sjiang.liu@intel.com 		 */
2118*12004Sjiang.liu@intel.com 		if (bp != NULL) {
2119*12004Sjiang.liu@intel.com 			bp->powered = acpidev_dr_device_is_powered(hdl);
2120*12004Sjiang.liu@intel.com 			if (bp->connected || bp->powered) {
2121*12004Sjiang.liu@intel.com 				*retval = hdl;
2122*12004Sjiang.liu@intel.com 				rc = AE_ERROR;
2123*12004Sjiang.liu@intel.com 			}
2124*12004Sjiang.liu@intel.com 		}
2125*12004Sjiang.liu@intel.com 		break;
2126*12004Sjiang.liu@intel.com 
2127*12004Sjiang.liu@intel.com 	case SBD_CMD_UNASSIGN:
2128*12004Sjiang.liu@intel.com 		/*
2129*12004Sjiang.liu@intel.com 		 * The child board should be disconnected, powered off and
2130*12004Sjiang.liu@intel.com 		 * unassigned if present when unassigning its parent board.
2131*12004Sjiang.liu@intel.com 		 */
2132*12004Sjiang.liu@intel.com 		if (bp != NULL) {
2133*12004Sjiang.liu@intel.com 			bp->powered = acpidev_dr_device_is_powered(hdl);
2134*12004Sjiang.liu@intel.com 			if (bp->connected || bp->powered || bp->assigned) {
2135*12004Sjiang.liu@intel.com 				*retval = hdl;
2136*12004Sjiang.liu@intel.com 				rc = AE_ERROR;
2137*12004Sjiang.liu@intel.com 			}
2138*12004Sjiang.liu@intel.com 		}
2139*12004Sjiang.liu@intel.com 		break;
2140*12004Sjiang.liu@intel.com 
2141*12004Sjiang.liu@intel.com 	default:
2142*12004Sjiang.liu@intel.com 		/* Return success for all other commands. */
2143*12004Sjiang.liu@intel.com 		break;
2144*12004Sjiang.liu@intel.com 	}
2145*12004Sjiang.liu@intel.com 
2146*12004Sjiang.liu@intel.com 	return (rc);
2147*12004Sjiang.liu@intel.com }
2148*12004Sjiang.liu@intel.com 
2149*12004Sjiang.liu@intel.com sbd_error_t *
drmach_board_check_dependent(int cmd,drmach_board_t * bp)2150*12004Sjiang.liu@intel.com drmach_board_check_dependent(int cmd, drmach_board_t *bp)
2151*12004Sjiang.liu@intel.com {
2152*12004Sjiang.liu@intel.com 	int reverse;
2153*12004Sjiang.liu@intel.com 	char *name;
2154*12004Sjiang.liu@intel.com 	sbd_error_t *err = NULL;
2155*12004Sjiang.liu@intel.com 	DRMACH_HANDLE hdl;
2156*12004Sjiang.liu@intel.com 	DRMACH_HANDLE dp = NULL;
2157*12004Sjiang.liu@intel.com 
2158*12004Sjiang.liu@intel.com 	ASSERT(bp != NULL);
2159*12004Sjiang.liu@intel.com 	ASSERT(DRMACH_IS_BOARD_ID(bp));
2160*12004Sjiang.liu@intel.com 	ASSERT(RW_LOCK_HELD(&drmach_boards_rwlock));
2161*12004Sjiang.liu@intel.com 
2162*12004Sjiang.liu@intel.com 	hdl = drmach_node_get_dnode(bp->tree);
2163*12004Sjiang.liu@intel.com 	if (hdl == NULL)
2164*12004Sjiang.liu@intel.com 		return (drerr_new(0, EX86_INAPPROP, NULL));
2165*12004Sjiang.liu@intel.com 
2166*12004Sjiang.liu@intel.com 	switch (cmd) {
2167*12004Sjiang.liu@intel.com 	case SBD_CMD_ASSIGN:
2168*12004Sjiang.liu@intel.com 	case SBD_CMD_POWERON:
2169*12004Sjiang.liu@intel.com 	case SBD_CMD_CONNECT:
2170*12004Sjiang.liu@intel.com 		if (ACPI_SUCCESS(acpidev_dr_device_walk_ejd(hdl,
2171*12004Sjiang.liu@intel.com 		    &drmach_board_check_dependent_cb,
2172*12004Sjiang.liu@intel.com 		    (void *)(intptr_t)cmd, &dp))) {
2173*12004Sjiang.liu@intel.com 			return (NULL);
2174*12004Sjiang.liu@intel.com 		}
2175*12004Sjiang.liu@intel.com 		reverse = 0;
2176*12004Sjiang.liu@intel.com 		break;
2177*12004Sjiang.liu@intel.com 
2178*12004Sjiang.liu@intel.com 	case SBD_CMD_UNASSIGN:
2179*12004Sjiang.liu@intel.com 	case SBD_CMD_POWEROFF:
2180*12004Sjiang.liu@intel.com 	case SBD_CMD_DISCONNECT:
2181*12004Sjiang.liu@intel.com 		if (ACPI_SUCCESS(acpidev_dr_device_walk_edl(hdl,
2182*12004Sjiang.liu@intel.com 		    &drmach_board_check_dependent_cb,
2183*12004Sjiang.liu@intel.com 		    (void *)(intptr_t)cmd, &dp))) {
2184*12004Sjiang.liu@intel.com 			return (NULL);
2185*12004Sjiang.liu@intel.com 		}
2186*12004Sjiang.liu@intel.com 		reverse = 1;
2187*12004Sjiang.liu@intel.com 		break;
2188*12004Sjiang.liu@intel.com 
2189*12004Sjiang.liu@intel.com 	default:
2190*12004Sjiang.liu@intel.com 		return (drerr_new(0, EX86_INAPPROP, NULL));
2191*12004Sjiang.liu@intel.com 	}
2192*12004Sjiang.liu@intel.com 
2193*12004Sjiang.liu@intel.com 	if (dp == NULL) {
2194*12004Sjiang.liu@intel.com 		return (drerr_new(1, EX86_WALK_DEPENDENCY, "%s", bp->cm.name));
2195*12004Sjiang.liu@intel.com 	}
2196*12004Sjiang.liu@intel.com 	name = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
2197*12004Sjiang.liu@intel.com 	if (ACPI_FAILURE(acpidev_dr_get_board_name(dp, name, MAXPATHLEN))) {
2198*12004Sjiang.liu@intel.com 		err = drerr_new(1, EX86_WALK_DEPENDENCY, "%s", bp->cm.name);
2199*12004Sjiang.liu@intel.com 	} else if (reverse == 0) {
2200*12004Sjiang.liu@intel.com 		err = drerr_new(1, EX86_WALK_DEPENDENCY,
2201*12004Sjiang.liu@intel.com 		    "%s, depends on board %s", bp->cm.name, name);
2202*12004Sjiang.liu@intel.com 	} else {
2203*12004Sjiang.liu@intel.com 		err = drerr_new(1, EX86_WALK_DEPENDENCY,
2204*12004Sjiang.liu@intel.com 		    "board %s depends on %s", name, bp->cm.name);
2205*12004Sjiang.liu@intel.com 	}
2206*12004Sjiang.liu@intel.com 	kmem_free(name, MAXPATHLEN);
2207*12004Sjiang.liu@intel.com 
2208*12004Sjiang.liu@intel.com 	return (err);
2209*12004Sjiang.liu@intel.com }
2210*12004Sjiang.liu@intel.com 
2211*12004Sjiang.liu@intel.com sbd_error_t *
drmach_board_assign(int bnum,drmachid_t * id)2212*12004Sjiang.liu@intel.com drmach_board_assign(int bnum, drmachid_t *id)
2213*12004Sjiang.liu@intel.com {
2214*12004Sjiang.liu@intel.com 	sbd_error_t	*err = NULL;
2215*12004Sjiang.liu@intel.com 
2216*12004Sjiang.liu@intel.com 	if (bnum < 0) {
2217*12004Sjiang.liu@intel.com 		return (drerr_new(1, EX86_BNUM, "%d", bnum));
2218*12004Sjiang.liu@intel.com 	}
2219*12004Sjiang.liu@intel.com 
2220*12004Sjiang.liu@intel.com 	rw_enter(&drmach_boards_rwlock, RW_WRITER);
2221*12004Sjiang.liu@intel.com 
2222*12004Sjiang.liu@intel.com 	if (drmach_array_get(drmach_boards, bnum, id) == -1) {
2223*12004Sjiang.liu@intel.com 		err = drerr_new(1, EX86_BNUM, "%d", bnum);
2224*12004Sjiang.liu@intel.com 	} else {
2225*12004Sjiang.liu@intel.com 		drmach_board_t	*bp;
2226*12004Sjiang.liu@intel.com 
2227*12004Sjiang.liu@intel.com 		/*
2228*12004Sjiang.liu@intel.com 		 * Board has already been created, downgrade to reader.
2229*12004Sjiang.liu@intel.com 		 */
2230*12004Sjiang.liu@intel.com 		if (*id)
2231*12004Sjiang.liu@intel.com 			rw_downgrade(&drmach_boards_rwlock);
2232*12004Sjiang.liu@intel.com 
2233*12004Sjiang.liu@intel.com 		bp = *id;
2234*12004Sjiang.liu@intel.com 		if (!(*id))
2235*12004Sjiang.liu@intel.com 			bp = *id  =
2236*12004Sjiang.liu@intel.com 			    (drmachid_t)drmach_board_new(bnum, 0);
2237*12004Sjiang.liu@intel.com 
2238*12004Sjiang.liu@intel.com 		if (bp == NULL) {
2239*12004Sjiang.liu@intel.com 			DRMACH_PR("!drmach_board_assign: failed to create "
2240*12004Sjiang.liu@intel.com 			    "object for board %d.", bnum);
2241*12004Sjiang.liu@intel.com 			err = drerr_new(1, EX86_BNUM, "%d", bnum);
2242*12004Sjiang.liu@intel.com 		} else {
2243*12004Sjiang.liu@intel.com 			err = drmach_board_check_dependent(SBD_CMD_ASSIGN, bp);
2244*12004Sjiang.liu@intel.com 			if (err == NULL)
2245*12004Sjiang.liu@intel.com 				bp->assigned = 1;
2246*12004Sjiang.liu@intel.com 		}
2247*12004Sjiang.liu@intel.com 	}
2248*12004Sjiang.liu@intel.com 
2249*12004Sjiang.liu@intel.com 	rw_exit(&drmach_boards_rwlock);
2250*12004Sjiang.liu@intel.com 
2251*12004Sjiang.liu@intel.com 	return (err);
2252*12004Sjiang.liu@intel.com }
2253*12004Sjiang.liu@intel.com 
2254*12004Sjiang.liu@intel.com sbd_error_t *
drmach_board_unassign(drmachid_t id)2255*12004Sjiang.liu@intel.com drmach_board_unassign(drmachid_t id)
2256*12004Sjiang.liu@intel.com {
2257*12004Sjiang.liu@intel.com 	drmach_board_t	*bp;
2258*12004Sjiang.liu@intel.com 	sbd_error_t	*err;
2259*12004Sjiang.liu@intel.com 	drmach_status_t	 stat;
2260*12004Sjiang.liu@intel.com 
2261*12004Sjiang.liu@intel.com 	if (DRMACH_NULL_ID(id))
2262*12004Sjiang.liu@intel.com 		return (NULL);
2263*12004Sjiang.liu@intel.com 
2264*12004Sjiang.liu@intel.com 	if (!DRMACH_IS_BOARD_ID(id)) {
2265*12004Sjiang.liu@intel.com 		return (drerr_new(0, EX86_INAPPROP, NULL));
2266*12004Sjiang.liu@intel.com 	}
2267*12004Sjiang.liu@intel.com 	bp = id;
2268*12004Sjiang.liu@intel.com 
2269*12004Sjiang.liu@intel.com 	rw_enter(&drmach_boards_rwlock, RW_WRITER);
2270*12004Sjiang.liu@intel.com 
2271*12004Sjiang.liu@intel.com 	err = drmach_board_status(id, &stat);
2272*12004Sjiang.liu@intel.com 	if (err) {
2273*12004Sjiang.liu@intel.com 		rw_exit(&drmach_boards_rwlock);
2274*12004Sjiang.liu@intel.com 		return (err);
2275*12004Sjiang.liu@intel.com 	}
2276*12004Sjiang.liu@intel.com 
2277*12004Sjiang.liu@intel.com 	if (stat.configured || stat.busy) {
2278*12004Sjiang.liu@intel.com 		err = drerr_new(0, EX86_CONFIGBUSY, bp->cm.name);
2279*12004Sjiang.liu@intel.com 	} else if (bp->connected) {
2280*12004Sjiang.liu@intel.com 		err = drerr_new(0, EX86_CONNECTBUSY, bp->cm.name);
2281*12004Sjiang.liu@intel.com 	} else if (stat.powered) {
2282*12004Sjiang.liu@intel.com 		err = drerr_new(0, EX86_POWERBUSY, bp->cm.name);
2283*12004Sjiang.liu@intel.com 	} else {
2284*12004Sjiang.liu@intel.com 		err = drmach_board_check_dependent(SBD_CMD_UNASSIGN, bp);
2285*12004Sjiang.liu@intel.com 		if (err == NULL) {
2286*12004Sjiang.liu@intel.com 			if (drmach_array_set(drmach_boards, bp->bnum, 0) != 0)
2287*12004Sjiang.liu@intel.com 				err = DRMACH_INTERNAL_ERROR();
2288*12004Sjiang.liu@intel.com 			else
2289*12004Sjiang.liu@intel.com 				drmach_board_dispose(bp);
2290*12004Sjiang.liu@intel.com 		}
2291*12004Sjiang.liu@intel.com 	}
2292*12004Sjiang.liu@intel.com 
2293*12004Sjiang.liu@intel.com 	rw_exit(&drmach_boards_rwlock);
2294*12004Sjiang.liu@intel.com 
2295*12004Sjiang.liu@intel.com 	return (err);
2296*12004Sjiang.liu@intel.com }
2297*12004Sjiang.liu@intel.com 
2298*12004Sjiang.liu@intel.com sbd_error_t *
drmach_board_poweron(drmachid_t id)2299*12004Sjiang.liu@intel.com drmach_board_poweron(drmachid_t id)
2300*12004Sjiang.liu@intel.com {
2301*12004Sjiang.liu@intel.com 	drmach_board_t	*bp;
2302*12004Sjiang.liu@intel.com 	sbd_error_t *err = NULL;
2303*12004Sjiang.liu@intel.com 	DRMACH_HANDLE hdl;
2304*12004Sjiang.liu@intel.com 
2305*12004Sjiang.liu@intel.com 	if (!DRMACH_IS_BOARD_ID(id))
2306*12004Sjiang.liu@intel.com 		return (drerr_new(0, EX86_INAPPROP, NULL));
2307*12004Sjiang.liu@intel.com 	bp = id;
2308*12004Sjiang.liu@intel.com 
2309*12004Sjiang.liu@intel.com 	hdl = drmach_node_get_dnode(bp->tree);
2310*12004Sjiang.liu@intel.com 	if (hdl == NULL)
2311*12004Sjiang.liu@intel.com 		return (drerr_new(0, EX86_INAPPROP, NULL));
2312*12004Sjiang.liu@intel.com 
2313*12004Sjiang.liu@intel.com 	bp->powered = drmach_board_check_power(bp);
2314*12004Sjiang.liu@intel.com 	if (bp->powered) {
2315*12004Sjiang.liu@intel.com 		return (NULL);
2316*12004Sjiang.liu@intel.com 	}
2317*12004Sjiang.liu@intel.com 
2318*12004Sjiang.liu@intel.com 	rw_enter(&drmach_boards_rwlock, RW_WRITER);
2319*12004Sjiang.liu@intel.com 	err = drmach_board_check_dependent(SBD_CMD_POWERON, bp);
2320*12004Sjiang.liu@intel.com 	if (err == NULL) {
2321*12004Sjiang.liu@intel.com 		acpidev_dr_lock_all();
2322*12004Sjiang.liu@intel.com 		if (ACPI_FAILURE(acpidev_dr_device_poweron(hdl)))
2323*12004Sjiang.liu@intel.com 			err = drerr_new(0, EX86_POWERON, NULL);
2324*12004Sjiang.liu@intel.com 		acpidev_dr_unlock_all();
2325*12004Sjiang.liu@intel.com 
2326*12004Sjiang.liu@intel.com 		/* Check whether the board is powered on. */
2327*12004Sjiang.liu@intel.com 		bp->powered = drmach_board_check_power(bp);
2328*12004Sjiang.liu@intel.com 		if (err == NULL && bp->powered == 0)
2329*12004Sjiang.liu@intel.com 			err = drerr_new(0, EX86_POWERON, NULL);
2330*12004Sjiang.liu@intel.com 	}
2331*12004Sjiang.liu@intel.com 	rw_exit(&drmach_boards_rwlock);
2332*12004Sjiang.liu@intel.com 
2333*12004Sjiang.liu@intel.com 	return (err);
2334*12004Sjiang.liu@intel.com }
2335*12004Sjiang.liu@intel.com 
2336*12004Sjiang.liu@intel.com sbd_error_t *
drmach_board_poweroff(drmachid_t id)2337*12004Sjiang.liu@intel.com drmach_board_poweroff(drmachid_t id)
2338*12004Sjiang.liu@intel.com {
2339*12004Sjiang.liu@intel.com 	sbd_error_t	*err = NULL;
2340*12004Sjiang.liu@intel.com 	drmach_board_t	*bp;
2341*12004Sjiang.liu@intel.com 	drmach_status_t	 stat;
2342*12004Sjiang.liu@intel.com 	DRMACH_HANDLE	 hdl;
2343*12004Sjiang.liu@intel.com 
2344*12004Sjiang.liu@intel.com 	if (DRMACH_NULL_ID(id))
2345*12004Sjiang.liu@intel.com 		return (NULL);
2346*12004Sjiang.liu@intel.com 
2347*12004Sjiang.liu@intel.com 	if (!DRMACH_IS_BOARD_ID(id))
2348*12004Sjiang.liu@intel.com 		return (drerr_new(0, EX86_INAPPROP, NULL));
2349*12004Sjiang.liu@intel.com 	bp = id;
2350*12004Sjiang.liu@intel.com 
2351*12004Sjiang.liu@intel.com 	hdl = drmach_node_get_dnode(bp->tree);
2352*12004Sjiang.liu@intel.com 	if (hdl == NULL)
2353*12004Sjiang.liu@intel.com 		return (drerr_new(0, EX86_INAPPROP, NULL));
2354*12004Sjiang.liu@intel.com 
2355*12004Sjiang.liu@intel.com 	/* Check whether the board is busy, configured or connected. */
2356*12004Sjiang.liu@intel.com 	err = drmach_board_status(id, &stat);
2357*12004Sjiang.liu@intel.com 	if (err != NULL)
2358*12004Sjiang.liu@intel.com 		return (err);
2359*12004Sjiang.liu@intel.com 	if (stat.configured || stat.busy) {
2360*12004Sjiang.liu@intel.com 		return (drerr_new(0, EX86_CONFIGBUSY, bp->cm.name));
2361*12004Sjiang.liu@intel.com 	} else if (bp->connected) {
2362*12004Sjiang.liu@intel.com 		return (drerr_new(0, EX86_CONNECTBUSY, bp->cm.name));
2363*12004Sjiang.liu@intel.com 	}
2364*12004Sjiang.liu@intel.com 
2365*12004Sjiang.liu@intel.com 	bp->powered = drmach_board_check_power(bp);
2366*12004Sjiang.liu@intel.com 	if (bp->powered == 0) {
2367*12004Sjiang.liu@intel.com 		return (NULL);
2368*12004Sjiang.liu@intel.com 	}
2369*12004Sjiang.liu@intel.com 
2370*12004Sjiang.liu@intel.com 	rw_enter(&drmach_boards_rwlock, RW_WRITER);
2371*12004Sjiang.liu@intel.com 	err = drmach_board_check_dependent(SBD_CMD_POWEROFF, bp);
2372*12004Sjiang.liu@intel.com 	if (err == NULL) {
2373*12004Sjiang.liu@intel.com 		acpidev_dr_lock_all();
2374*12004Sjiang.liu@intel.com 		if (ACPI_FAILURE(acpidev_dr_device_poweroff(hdl)))
2375*12004Sjiang.liu@intel.com 			err = drerr_new(0, EX86_POWEROFF, NULL);
2376*12004Sjiang.liu@intel.com 		acpidev_dr_unlock_all();
2377*12004Sjiang.liu@intel.com 
2378*12004Sjiang.liu@intel.com 		bp->powered = drmach_board_check_power(bp);
2379*12004Sjiang.liu@intel.com 		if (err == NULL && bp->powered != 0)
2380*12004Sjiang.liu@intel.com 			err = drerr_new(0, EX86_POWEROFF, NULL);
2381*12004Sjiang.liu@intel.com 	}
2382*12004Sjiang.liu@intel.com 	rw_exit(&drmach_boards_rwlock);
2383*12004Sjiang.liu@intel.com 
2384*12004Sjiang.liu@intel.com 	return (err);
2385*12004Sjiang.liu@intel.com }
2386*12004Sjiang.liu@intel.com 
2387*12004Sjiang.liu@intel.com sbd_error_t *
drmach_board_test(drmachid_t id,drmach_opts_t * opts,int force)2388*12004Sjiang.liu@intel.com drmach_board_test(drmachid_t id, drmach_opts_t *opts, int force)
2389*12004Sjiang.liu@intel.com {
2390*12004Sjiang.liu@intel.com 	_NOTE(ARGUNUSED(opts, force));
2391*12004Sjiang.liu@intel.com 
2392*12004Sjiang.liu@intel.com 	drmach_board_t	*bp;
2393*12004Sjiang.liu@intel.com 	DRMACH_HANDLE	 hdl;
2394*12004Sjiang.liu@intel.com 
2395*12004Sjiang.liu@intel.com 	if (DRMACH_NULL_ID(id))
2396*12004Sjiang.liu@intel.com 		return (NULL);
2397*12004Sjiang.liu@intel.com 
2398*12004Sjiang.liu@intel.com 	if (!DRMACH_IS_BOARD_ID(id))
2399*12004Sjiang.liu@intel.com 		return (drerr_new(0, EX86_INAPPROP, NULL));
2400*12004Sjiang.liu@intel.com 	bp = id;
2401*12004Sjiang.liu@intel.com 
2402*12004Sjiang.liu@intel.com 	hdl = drmach_node_get_dnode(bp->tree);
2403*12004Sjiang.liu@intel.com 	if (hdl == NULL)
2404*12004Sjiang.liu@intel.com 		return (drerr_new(0, EX86_INAPPROP, NULL));
2405*12004Sjiang.liu@intel.com 
2406*12004Sjiang.liu@intel.com 	if (ACPI_FAILURE(acpidev_dr_device_check_status(hdl)))
2407*12004Sjiang.liu@intel.com 		return (drerr_new(0, EX86_IN_FAILURE, NULL));
2408*12004Sjiang.liu@intel.com 
2409*12004Sjiang.liu@intel.com 	return (NULL);
2410*12004Sjiang.liu@intel.com }
2411*12004Sjiang.liu@intel.com 
2412*12004Sjiang.liu@intel.com sbd_error_t *
drmach_board_connect(drmachid_t id,drmach_opts_t * opts)2413*12004Sjiang.liu@intel.com drmach_board_connect(drmachid_t id, drmach_opts_t *opts)
2414*12004Sjiang.liu@intel.com {
2415*12004Sjiang.liu@intel.com 	_NOTE(ARGUNUSED(opts));
2416*12004Sjiang.liu@intel.com 
2417*12004Sjiang.liu@intel.com 	sbd_error_t	*err = NULL;
2418*12004Sjiang.liu@intel.com 	drmach_board_t	*bp = (drmach_board_t *)id;
2419*12004Sjiang.liu@intel.com 	DRMACH_HANDLE	hdl;
2420*12004Sjiang.liu@intel.com 
2421*12004Sjiang.liu@intel.com 	if (!DRMACH_IS_BOARD_ID(id))
2422*12004Sjiang.liu@intel.com 		return (drerr_new(0, EX86_INAPPROP, NULL));
2423*12004Sjiang.liu@intel.com 	bp = (drmach_board_t *)id;
2424*12004Sjiang.liu@intel.com 
2425*12004Sjiang.liu@intel.com 	hdl = drmach_node_get_dnode(bp->tree);
2426*12004Sjiang.liu@intel.com 	if (hdl == NULL)
2427*12004Sjiang.liu@intel.com 		return (drerr_new(0, EX86_INAPPROP, NULL));
2428*12004Sjiang.liu@intel.com 
2429*12004Sjiang.liu@intel.com 	rw_enter(&drmach_boards_rwlock, RW_WRITER);
2430*12004Sjiang.liu@intel.com 	err = drmach_board_check_dependent(SBD_CMD_CONNECT, bp);
2431*12004Sjiang.liu@intel.com 	if (err == NULL) {
2432*12004Sjiang.liu@intel.com 		acpidev_dr_lock_all();
2433*12004Sjiang.liu@intel.com 		if (ACPI_FAILURE(acpidev_dr_device_insert(hdl))) {
2434*12004Sjiang.liu@intel.com 			(void) acpidev_dr_device_remove(hdl);
2435*12004Sjiang.liu@intel.com 			err = drerr_new(1, EX86_PROBE, NULL);
2436*12004Sjiang.liu@intel.com 		} else {
2437*12004Sjiang.liu@intel.com 			bp->connected = 1;
2438*12004Sjiang.liu@intel.com 		}
2439*12004Sjiang.liu@intel.com 		acpidev_dr_unlock_all();
2440*12004Sjiang.liu@intel.com 	}
2441*12004Sjiang.liu@intel.com 	rw_exit(&drmach_boards_rwlock);
2442*12004Sjiang.liu@intel.com 
2443*12004Sjiang.liu@intel.com 	return (err);
2444*12004Sjiang.liu@intel.com }
2445*12004Sjiang.liu@intel.com 
2446*12004Sjiang.liu@intel.com sbd_error_t *
drmach_board_disconnect(drmachid_t id,drmach_opts_t * opts)2447*12004Sjiang.liu@intel.com drmach_board_disconnect(drmachid_t id, drmach_opts_t *opts)
2448*12004Sjiang.liu@intel.com {
2449*12004Sjiang.liu@intel.com 	_NOTE(ARGUNUSED(opts));
2450*12004Sjiang.liu@intel.com 
2451*12004Sjiang.liu@intel.com 	DRMACH_HANDLE hdl;
2452*12004Sjiang.liu@intel.com 	drmach_board_t *bp;
2453*12004Sjiang.liu@intel.com 	drmach_status_t	stat;
2454*12004Sjiang.liu@intel.com 	sbd_error_t *err = NULL;
2455*12004Sjiang.liu@intel.com 
2456*12004Sjiang.liu@intel.com 	if (DRMACH_NULL_ID(id))
2457*12004Sjiang.liu@intel.com 		return (NULL);
2458*12004Sjiang.liu@intel.com 	if (!DRMACH_IS_BOARD_ID(id))
2459*12004Sjiang.liu@intel.com 		return (drerr_new(0, EX86_INAPPROP, NULL));
2460*12004Sjiang.liu@intel.com 	bp = (drmach_board_t *)id;
2461*12004Sjiang.liu@intel.com 
2462*12004Sjiang.liu@intel.com 	hdl = drmach_node_get_dnode(bp->tree);
2463*12004Sjiang.liu@intel.com 	if (hdl == NULL)
2464*12004Sjiang.liu@intel.com 		return (drerr_new(0, EX86_INAPPROP, NULL));
2465*12004Sjiang.liu@intel.com 
2466*12004Sjiang.liu@intel.com 	/* Check whether the board is busy or configured. */
2467*12004Sjiang.liu@intel.com 	err = drmach_board_status(id, &stat);
2468*12004Sjiang.liu@intel.com 	if (err != NULL)
2469*12004Sjiang.liu@intel.com 		return (err);
2470*12004Sjiang.liu@intel.com 	if (stat.configured || stat.busy)
2471*12004Sjiang.liu@intel.com 		return (drerr_new(0, EX86_CONFIGBUSY, bp->cm.name));
2472*12004Sjiang.liu@intel.com 
2473*12004Sjiang.liu@intel.com 	rw_enter(&drmach_boards_rwlock, RW_WRITER);
2474*12004Sjiang.liu@intel.com 	err = drmach_board_check_dependent(SBD_CMD_DISCONNECT, bp);
2475*12004Sjiang.liu@intel.com 	if (err == NULL) {
2476*12004Sjiang.liu@intel.com 		acpidev_dr_lock_all();
2477*12004Sjiang.liu@intel.com 		if (ACPI_SUCCESS(acpidev_dr_device_remove(hdl))) {
2478*12004Sjiang.liu@intel.com 			bp->connected = 0;
2479*12004Sjiang.liu@intel.com 		} else {
2480*12004Sjiang.liu@intel.com 			err = drerr_new(1, EX86_DEPROBE, bp->cm.name);
2481*12004Sjiang.liu@intel.com 		}
2482*12004Sjiang.liu@intel.com 		acpidev_dr_unlock_all();
2483*12004Sjiang.liu@intel.com 	}
2484*12004Sjiang.liu@intel.com 	rw_exit(&drmach_boards_rwlock);
2485*12004Sjiang.liu@intel.com 
2486*12004Sjiang.liu@intel.com 	return (err);
2487*12004Sjiang.liu@intel.com }
2488*12004Sjiang.liu@intel.com 
2489*12004Sjiang.liu@intel.com sbd_error_t *
drmach_board_deprobe(drmachid_t id)2490*12004Sjiang.liu@intel.com drmach_board_deprobe(drmachid_t id)
2491*12004Sjiang.liu@intel.com {
2492*12004Sjiang.liu@intel.com 	drmach_board_t	*bp;
2493*12004Sjiang.liu@intel.com 
2494*12004Sjiang.liu@intel.com 	if (!DRMACH_IS_BOARD_ID(id))
2495*12004Sjiang.liu@intel.com 		return (drerr_new(0, EX86_INAPPROP, NULL));
2496*12004Sjiang.liu@intel.com 	bp = id;
2497*12004Sjiang.liu@intel.com 
2498*12004Sjiang.liu@intel.com 	cmn_err(CE_CONT, "DR: detach board %d\n", bp->bnum);
2499*12004Sjiang.liu@intel.com 
2500*12004Sjiang.liu@intel.com 	if (bp->devices) {
2501*12004Sjiang.liu@intel.com 		drmach_array_dispose(bp->devices, drmach_device_dispose);
2502*12004Sjiang.liu@intel.com 		bp->devices = NULL;
2503*12004Sjiang.liu@intel.com 	}
2504*12004Sjiang.liu@intel.com 
2505*12004Sjiang.liu@intel.com 	bp->boot_board = 0;
2506*12004Sjiang.liu@intel.com 
2507*12004Sjiang.liu@intel.com 	return (NULL);
2508*12004Sjiang.liu@intel.com }
2509*12004Sjiang.liu@intel.com 
2510*12004Sjiang.liu@intel.com /*
2511*12004Sjiang.liu@intel.com  * CPU specific interfaces to support dr driver
2512*12004Sjiang.liu@intel.com  */
2513*12004Sjiang.liu@intel.com sbd_error_t *
drmach_cpu_disconnect(drmachid_t id)2514*12004Sjiang.liu@intel.com drmach_cpu_disconnect(drmachid_t id)
2515*12004Sjiang.liu@intel.com {
2516*12004Sjiang.liu@intel.com 	if (!DRMACH_IS_CPU_ID(id))
2517*12004Sjiang.liu@intel.com 		return (drerr_new(0, EX86_INAPPROP, NULL));
2518*12004Sjiang.liu@intel.com 
2519*12004Sjiang.liu@intel.com 	return (NULL);
2520*12004Sjiang.liu@intel.com }
2521*12004Sjiang.liu@intel.com 
2522*12004Sjiang.liu@intel.com sbd_error_t *
drmach_cpu_get_id(drmachid_t id,processorid_t * cpuid)2523*12004Sjiang.liu@intel.com drmach_cpu_get_id(drmachid_t id, processorid_t *cpuid)
2524*12004Sjiang.liu@intel.com {
2525*12004Sjiang.liu@intel.com 	drmach_cpu_t *cpu;
2526*12004Sjiang.liu@intel.com 
2527*12004Sjiang.liu@intel.com 	if (!DRMACH_IS_CPU_ID(id))
2528*12004Sjiang.liu@intel.com 		return (drerr_new(0, EX86_INAPPROP, NULL));
2529*12004Sjiang.liu@intel.com 	cpu = (drmach_cpu_t *)id;
2530*12004Sjiang.liu@intel.com 
2531*12004Sjiang.liu@intel.com 	if (cpu->cpuid == -1) {
2532*12004Sjiang.liu@intel.com 		if (ACPI_SUCCESS(acpica_get_cpu_id_by_object(
2533*12004Sjiang.liu@intel.com 		    drmach_node_get_dnode(cpu->dev.node), cpuid))) {
2534*12004Sjiang.liu@intel.com 			cpu->cpuid = *cpuid;
2535*12004Sjiang.liu@intel.com 		} else {
2536*12004Sjiang.liu@intel.com 			*cpuid = -1;
2537*12004Sjiang.liu@intel.com 		}
2538*12004Sjiang.liu@intel.com 	} else {
2539*12004Sjiang.liu@intel.com 		*cpuid = cpu->cpuid;
2540*12004Sjiang.liu@intel.com 	}
2541*12004Sjiang.liu@intel.com 
2542*12004Sjiang.liu@intel.com 	return (NULL);
2543*12004Sjiang.liu@intel.com }
2544*12004Sjiang.liu@intel.com 
2545*12004Sjiang.liu@intel.com sbd_error_t *
drmach_cpu_get_impl(drmachid_t id,int * ip)2546*12004Sjiang.liu@intel.com drmach_cpu_get_impl(drmachid_t id, int *ip)
2547*12004Sjiang.liu@intel.com {
2548*12004Sjiang.liu@intel.com 	if (!DRMACH_IS_CPU_ID(id))
2549*12004Sjiang.liu@intel.com 		return (drerr_new(0, EX86_INAPPROP, NULL));
2550*12004Sjiang.liu@intel.com 
2551*12004Sjiang.liu@intel.com 	/* Assume all CPUs in system are homogeneous. */
2552*12004Sjiang.liu@intel.com 	*ip = X86_CPU_IMPL_UNKNOWN;
2553*12004Sjiang.liu@intel.com 
2554*12004Sjiang.liu@intel.com 	kpreempt_disable();
2555*12004Sjiang.liu@intel.com 	if (cpuid_getvendor(CPU) == X86_VENDOR_Intel) {
2556*12004Sjiang.liu@intel.com 		/* NHM-EX CPU */
2557*12004Sjiang.liu@intel.com 		if (cpuid_getfamily(CPU) == 0x6 &&
2558*12004Sjiang.liu@intel.com 		    cpuid_getmodel(CPU) == 0x2e) {
2559*12004Sjiang.liu@intel.com 			*ip = X86_CPU_IMPL_NEHALEM_EX;
2560*12004Sjiang.liu@intel.com 		}
2561*12004Sjiang.liu@intel.com 	}
2562*12004Sjiang.liu@intel.com 	kpreempt_enable();
2563*12004Sjiang.liu@intel.com 
2564*12004Sjiang.liu@intel.com 	return (NULL);
2565*12004Sjiang.liu@intel.com }
2566*12004Sjiang.liu@intel.com 
2567*12004Sjiang.liu@intel.com /*
2568*12004Sjiang.liu@intel.com  * Memory specific interfaces to support dr driver
2569*12004Sjiang.liu@intel.com  */
2570*12004Sjiang.liu@intel.com 
2571*12004Sjiang.liu@intel.com /*
2572*12004Sjiang.liu@intel.com  * When drmach_mem_new() is called, the mp->base_pa field is set to the base
2573*12004Sjiang.liu@intel.com  * address of configured memory if there's configured memory on the board,
2574*12004Sjiang.liu@intel.com  * otherwise set to UINT64_MAX. For hot-added memory board, there's no
2575*12004Sjiang.liu@intel.com  * configured memory when drmach_mem_new() is called, so mp->base_pa is set
2576*12004Sjiang.liu@intel.com  * to UINT64_MAX and we need to set a correct value for it after memory
2577*12004Sjiang.liu@intel.com  * hot-add  operations.
2578*12004Sjiang.liu@intel.com  * A hot-added memory board may contain multiple memory segments,
2579*12004Sjiang.liu@intel.com  * drmach_mem_add_span() will be called once for each segment, so we can't
2580*12004Sjiang.liu@intel.com  * rely on the basepa argument. And it's possible that only part of a memory
2581*12004Sjiang.liu@intel.com  * segment is added into OS, so need to intersect with phys_installed list
2582*12004Sjiang.liu@intel.com  * to get the real base address of configured memory on the board.
2583*12004Sjiang.liu@intel.com  */
2584*12004Sjiang.liu@intel.com sbd_error_t *
drmach_mem_add_span(drmachid_t id,uint64_t basepa,uint64_t size)2585*12004Sjiang.liu@intel.com drmach_mem_add_span(drmachid_t id, uint64_t basepa, uint64_t size)
2586*12004Sjiang.liu@intel.com {
2587*12004Sjiang.liu@intel.com 	_NOTE(ARGUNUSED(basepa));
2588*12004Sjiang.liu@intel.com 
2589*12004Sjiang.liu@intel.com 	uint64_t	nbytes = 0;
2590*12004Sjiang.liu@intel.com 	uint64_t	endpa;
2591*12004Sjiang.liu@intel.com 	drmach_mem_t	*mp;
2592*12004Sjiang.liu@intel.com 	struct memlist	*ml2;
2593*12004Sjiang.liu@intel.com 	struct memlist	*p;
2594*12004Sjiang.liu@intel.com 
2595*12004Sjiang.liu@intel.com 	ASSERT(size != 0);
2596*12004Sjiang.liu@intel.com 
2597*12004Sjiang.liu@intel.com 	if (!DRMACH_IS_MEM_ID(id))
2598*12004Sjiang.liu@intel.com 		return (drerr_new(0, EX86_INAPPROP, NULL));
2599*12004Sjiang.liu@intel.com 	mp = (drmach_mem_t *)id;
2600*12004Sjiang.liu@intel.com 
2601*12004Sjiang.liu@intel.com 	/* Compute basepa and size of installed memory. */
2602*12004Sjiang.liu@intel.com 	endpa = _ptob64(physmax + 1);
2603*12004Sjiang.liu@intel.com 	memlist_read_lock();
2604*12004Sjiang.liu@intel.com 	ml2 = memlist_dup(phys_install);
2605*12004Sjiang.liu@intel.com 	memlist_read_unlock();
2606*12004Sjiang.liu@intel.com 	ml2 = memlist_del_span(ml2, 0ull, mp->slice_base);
2607*12004Sjiang.liu@intel.com 	if (ml2 && endpa > mp->slice_top) {
2608*12004Sjiang.liu@intel.com 		ml2 = memlist_del_span(ml2, mp->slice_top,
2609*12004Sjiang.liu@intel.com 		    endpa - mp->slice_top);
2610*12004Sjiang.liu@intel.com 	}
2611*12004Sjiang.liu@intel.com 
2612*12004Sjiang.liu@intel.com 	ASSERT(ml2);
2613*12004Sjiang.liu@intel.com 	if (ml2) {
2614*12004Sjiang.liu@intel.com 		for (p = ml2; p; p = p->ml_next) {
2615*12004Sjiang.liu@intel.com 			nbytes += p->ml_size;
2616*12004Sjiang.liu@intel.com 			if (mp->base_pa > p->ml_address)
2617*12004Sjiang.liu@intel.com 				mp->base_pa = p->ml_address;
2618*12004Sjiang.liu@intel.com 		}
2619*12004Sjiang.liu@intel.com 		ASSERT(nbytes > 0);
2620*12004Sjiang.liu@intel.com 		mp->nbytes += nbytes;
2621*12004Sjiang.liu@intel.com 		memlist_delete(ml2);
2622*12004Sjiang.liu@intel.com 	}
2623*12004Sjiang.liu@intel.com 
2624*12004Sjiang.liu@intel.com 	return (NULL);
2625*12004Sjiang.liu@intel.com }
2626*12004Sjiang.liu@intel.com 
2627*12004Sjiang.liu@intel.com static sbd_error_t *
drmach_mem_update_lgrp(drmachid_t id)2628*12004Sjiang.liu@intel.com drmach_mem_update_lgrp(drmachid_t id)
2629*12004Sjiang.liu@intel.com {
2630*12004Sjiang.liu@intel.com 	ACPI_STATUS	rc;
2631*12004Sjiang.liu@intel.com 	DRMACH_HANDLE	hdl;
2632*12004Sjiang.liu@intel.com 	void		*hdlp;
2633*12004Sjiang.liu@intel.com 	drmach_mem_t	*mp;
2634*12004Sjiang.liu@intel.com 	update_membounds_t umb;
2635*12004Sjiang.liu@intel.com 
2636*12004Sjiang.liu@intel.com 	if (!DRMACH_IS_MEM_ID(id))
2637*12004Sjiang.liu@intel.com 		return (drerr_new(0, EX86_INAPPROP, NULL));
2638*12004Sjiang.liu@intel.com 	mp = (drmach_mem_t *)id;
2639*12004Sjiang.liu@intel.com 	/* No need to update lgrp if memory is already installed. */
2640*12004Sjiang.liu@intel.com 	if (mp->nbytes != 0)
2641*12004Sjiang.liu@intel.com 		return (NULL);
2642*12004Sjiang.liu@intel.com 	/* No need to update lgrp if lgrp is disabled. */
2643*12004Sjiang.liu@intel.com 	if (max_mem_nodes == 1)
2644*12004Sjiang.liu@intel.com 		return (NULL);
2645*12004Sjiang.liu@intel.com 
2646*12004Sjiang.liu@intel.com 	/* Add memory to lgroup */
2647*12004Sjiang.liu@intel.com 	hdl = mp->dev.node->get_dnode(mp->dev.node);
2648*12004Sjiang.liu@intel.com 	rc = acpidev_dr_device_get_memory_index(hdl, &umb.u_device_id);
2649*12004Sjiang.liu@intel.com 	ASSERT(ACPI_SUCCESS(rc));
2650*12004Sjiang.liu@intel.com 	if (ACPI_FAILURE(rc)) {
2651*12004Sjiang.liu@intel.com 		cmn_err(CE_WARN, "drmach: failed to get device id of memory, "
2652*12004Sjiang.liu@intel.com 		    "can't update lgrp information.");
2653*12004Sjiang.liu@intel.com 		return (drerr_new(0, EX86_INTERNAL, NULL));
2654*12004Sjiang.liu@intel.com 	}
2655*12004Sjiang.liu@intel.com 	rc = acpidev_dr_get_mem_numa_info(hdl, mp->memlist, &hdlp,
2656*12004Sjiang.liu@intel.com 	    &umb.u_domain, &umb.u_sli_cnt, &umb.u_sli_ptr);
2657*12004Sjiang.liu@intel.com 	ASSERT(ACPI_SUCCESS(rc));
2658*12004Sjiang.liu@intel.com 	if (ACPI_FAILURE(rc)) {
2659*12004Sjiang.liu@intel.com 		cmn_err(CE_WARN, "drmach: failed to get lgrp info of memory, "
2660*12004Sjiang.liu@intel.com 		    "can't update lgrp information.");
2661*12004Sjiang.liu@intel.com 		return (drerr_new(0, EX86_INTERNAL, NULL));
2662*12004Sjiang.liu@intel.com 	}
2663*12004Sjiang.liu@intel.com 	umb.u_base = (uint64_t)mp->slice_base;
2664*12004Sjiang.liu@intel.com 	umb.u_length = (uint64_t)(mp->slice_top - mp->slice_base);
2665*12004Sjiang.liu@intel.com 	lgrp_plat_config(LGRP_CONFIG_MEM_ADD, (uintptr_t)&umb);
2666*12004Sjiang.liu@intel.com 	acpidev_dr_free_mem_numa_info(hdlp);
2667*12004Sjiang.liu@intel.com 
2668*12004Sjiang.liu@intel.com 	return (NULL);
2669*12004Sjiang.liu@intel.com }
2670*12004Sjiang.liu@intel.com 
2671*12004Sjiang.liu@intel.com sbd_error_t *
drmach_mem_enable(drmachid_t id)2672*12004Sjiang.liu@intel.com drmach_mem_enable(drmachid_t id)
2673*12004Sjiang.liu@intel.com {
2674*12004Sjiang.liu@intel.com 	if (!DRMACH_IS_MEM_ID(id))
2675*12004Sjiang.liu@intel.com 		return (drerr_new(0, EX86_INAPPROP, NULL));
2676*12004Sjiang.liu@intel.com 	else
2677*12004Sjiang.liu@intel.com 		return (NULL);
2678*12004Sjiang.liu@intel.com }
2679*12004Sjiang.liu@intel.com 
2680*12004Sjiang.liu@intel.com sbd_error_t *
drmach_mem_get_info(drmachid_t id,drmach_mem_info_t * mem)2681*12004Sjiang.liu@intel.com drmach_mem_get_info(drmachid_t id, drmach_mem_info_t *mem)
2682*12004Sjiang.liu@intel.com {
2683*12004Sjiang.liu@intel.com 	drmach_mem_t *mp;
2684*12004Sjiang.liu@intel.com 
2685*12004Sjiang.liu@intel.com 	if (!DRMACH_IS_MEM_ID(id))
2686*12004Sjiang.liu@intel.com 		return (drerr_new(0, EX86_INAPPROP, NULL));
2687*12004Sjiang.liu@intel.com 	mp = (drmach_mem_t *)id;
2688*12004Sjiang.liu@intel.com 
2689*12004Sjiang.liu@intel.com 	/*
2690*12004Sjiang.liu@intel.com 	 * This is only used by dr to round up/down the memory
2691*12004Sjiang.liu@intel.com 	 * for copying.
2692*12004Sjiang.liu@intel.com 	 */
2693*12004Sjiang.liu@intel.com 	mem->mi_alignment_mask = mp->mem_alignment - 1;
2694*12004Sjiang.liu@intel.com 	mem->mi_basepa = mp->base_pa;
2695*12004Sjiang.liu@intel.com 	mem->mi_size = mp->nbytes;
2696*12004Sjiang.liu@intel.com 	mem->mi_slice_base = mp->slice_base;
2697*12004Sjiang.liu@intel.com 	mem->mi_slice_top = mp->slice_top;
2698*12004Sjiang.liu@intel.com 	mem->mi_slice_size = mp->slice_size;
2699*12004Sjiang.liu@intel.com 
2700*12004Sjiang.liu@intel.com 	return (NULL);
2701*12004Sjiang.liu@intel.com }
2702*12004Sjiang.liu@intel.com 
2703*12004Sjiang.liu@intel.com sbd_error_t *
drmach_mem_get_slice_info(drmachid_t id,uint64_t * bp,uint64_t * ep,uint64_t * sp)2704*12004Sjiang.liu@intel.com drmach_mem_get_slice_info(drmachid_t id,
2705*12004Sjiang.liu@intel.com     uint64_t *bp, uint64_t *ep, uint64_t *sp)
2706*12004Sjiang.liu@intel.com {
2707*12004Sjiang.liu@intel.com 	drmach_mem_t *mp;
2708*12004Sjiang.liu@intel.com 
2709*12004Sjiang.liu@intel.com 	if (!DRMACH_IS_MEM_ID(id))
2710*12004Sjiang.liu@intel.com 		return (drerr_new(0, EX86_INAPPROP, NULL));
2711*12004Sjiang.liu@intel.com 	mp = (drmach_mem_t *)id;
2712*12004Sjiang.liu@intel.com 
2713*12004Sjiang.liu@intel.com 	if (bp)
2714*12004Sjiang.liu@intel.com 		*bp = mp->slice_base;
2715*12004Sjiang.liu@intel.com 	if (ep)
2716*12004Sjiang.liu@intel.com 		*ep = mp->slice_top;
2717*12004Sjiang.liu@intel.com 	if (sp)
2718*12004Sjiang.liu@intel.com 		*sp = mp->slice_size;
2719*12004Sjiang.liu@intel.com 
2720*12004Sjiang.liu@intel.com 	return (NULL);
2721*12004Sjiang.liu@intel.com }
2722*12004Sjiang.liu@intel.com 
2723*12004Sjiang.liu@intel.com sbd_error_t *
drmach_mem_get_memlist(drmachid_t id,struct memlist ** ml)2724*12004Sjiang.liu@intel.com drmach_mem_get_memlist(drmachid_t id, struct memlist **ml)
2725*12004Sjiang.liu@intel.com {
2726*12004Sjiang.liu@intel.com #ifdef	DEBUG
2727*12004Sjiang.liu@intel.com 	int		rv;
2728*12004Sjiang.liu@intel.com #endif
2729*12004Sjiang.liu@intel.com 	drmach_mem_t	*mem;
2730*12004Sjiang.liu@intel.com 	struct memlist	*mlist;
2731*12004Sjiang.liu@intel.com 
2732*12004Sjiang.liu@intel.com 	if (!DRMACH_IS_MEM_ID(id))
2733*12004Sjiang.liu@intel.com 		return (drerr_new(0, EX86_INAPPROP, NULL));
2734*12004Sjiang.liu@intel.com 	mem = (drmach_mem_t *)id;
2735*12004Sjiang.liu@intel.com 
2736*12004Sjiang.liu@intel.com 	mlist = memlist_dup(mem->memlist);
2737*12004Sjiang.liu@intel.com 	*ml = mlist;
2738*12004Sjiang.liu@intel.com 
2739*12004Sjiang.liu@intel.com #ifdef DEBUG
2740*12004Sjiang.liu@intel.com 	/*
2741*12004Sjiang.liu@intel.com 	 * Make sure the incoming memlist doesn't already
2742*12004Sjiang.liu@intel.com 	 * intersect with what's present in the system (phys_install).
2743*12004Sjiang.liu@intel.com 	 */
2744*12004Sjiang.liu@intel.com 	memlist_read_lock();
2745*12004Sjiang.liu@intel.com 	rv = memlist_intersect(phys_install, mlist);
2746*12004Sjiang.liu@intel.com 	memlist_read_unlock();
2747*12004Sjiang.liu@intel.com 	if (rv) {
2748*12004Sjiang.liu@intel.com 		DRMACH_PR("Derived memlist intersects with phys_install\n");
2749*12004Sjiang.liu@intel.com 		memlist_dump(mlist);
2750*12004Sjiang.liu@intel.com 
2751*12004Sjiang.liu@intel.com 		DRMACH_PR("phys_install memlist:\n");
2752*12004Sjiang.liu@intel.com 		memlist_dump(phys_install);
2753*12004Sjiang.liu@intel.com 
2754*12004Sjiang.liu@intel.com 		memlist_delete(mlist);
2755*12004Sjiang.liu@intel.com 		return (DRMACH_INTERNAL_ERROR());
2756*12004Sjiang.liu@intel.com 	}
2757*12004Sjiang.liu@intel.com 
2758*12004Sjiang.liu@intel.com 	DRMACH_PR("Derived memlist:");
2759*12004Sjiang.liu@intel.com 	memlist_dump(mlist);
2760*12004Sjiang.liu@intel.com #endif
2761*12004Sjiang.liu@intel.com 
2762*12004Sjiang.liu@intel.com 	return (NULL);
2763*12004Sjiang.liu@intel.com }
2764*12004Sjiang.liu@intel.com 
2765*12004Sjiang.liu@intel.com processorid_t
drmach_mem_cpu_affinity(drmachid_t id)2766*12004Sjiang.liu@intel.com drmach_mem_cpu_affinity(drmachid_t id)
2767*12004Sjiang.liu@intel.com {
2768*12004Sjiang.liu@intel.com 	_NOTE(ARGUNUSED(id));
2769*12004Sjiang.liu@intel.com 
2770*12004Sjiang.liu@intel.com 	return (CPU_CURRENT);
2771*12004Sjiang.liu@intel.com }
2772*12004Sjiang.liu@intel.com 
2773*12004Sjiang.liu@intel.com int
drmach_copy_rename_need_suspend(drmachid_t id)2774*12004Sjiang.liu@intel.com drmach_copy_rename_need_suspend(drmachid_t id)
2775*12004Sjiang.liu@intel.com {
2776*12004Sjiang.liu@intel.com 	_NOTE(ARGUNUSED(id));
2777*12004Sjiang.liu@intel.com 
2778*12004Sjiang.liu@intel.com 	return (0);
2779*12004Sjiang.liu@intel.com }
2780*12004Sjiang.liu@intel.com 
2781*12004Sjiang.liu@intel.com /*
2782*12004Sjiang.liu@intel.com  * IO specific interfaces to support dr driver
2783*12004Sjiang.liu@intel.com  */
2784*12004Sjiang.liu@intel.com sbd_error_t *
drmach_io_pre_release(drmachid_t id)2785*12004Sjiang.liu@intel.com drmach_io_pre_release(drmachid_t id)
2786*12004Sjiang.liu@intel.com {
2787*12004Sjiang.liu@intel.com 	if (!DRMACH_IS_IO_ID(id))
2788*12004Sjiang.liu@intel.com 		return (drerr_new(0, EX86_INAPPROP, NULL));
2789*12004Sjiang.liu@intel.com 
2790*12004Sjiang.liu@intel.com 	return (NULL);
2791*12004Sjiang.liu@intel.com }
2792*12004Sjiang.liu@intel.com 
2793*12004Sjiang.liu@intel.com sbd_error_t *
drmach_io_unrelease(drmachid_t id)2794*12004Sjiang.liu@intel.com drmach_io_unrelease(drmachid_t id)
2795*12004Sjiang.liu@intel.com {
2796*12004Sjiang.liu@intel.com 	if (!DRMACH_IS_IO_ID(id))
2797*12004Sjiang.liu@intel.com 		return (drerr_new(0, EX86_INAPPROP, NULL));
2798*12004Sjiang.liu@intel.com 
2799*12004Sjiang.liu@intel.com 	return (NULL);
2800*12004Sjiang.liu@intel.com }
2801*12004Sjiang.liu@intel.com 
2802*12004Sjiang.liu@intel.com sbd_error_t *
drmach_io_post_release(drmachid_t id)2803*12004Sjiang.liu@intel.com drmach_io_post_release(drmachid_t id)
2804*12004Sjiang.liu@intel.com {
2805*12004Sjiang.liu@intel.com 	_NOTE(ARGUNUSED(id));
2806*12004Sjiang.liu@intel.com 
2807*12004Sjiang.liu@intel.com 	return (NULL);
2808*12004Sjiang.liu@intel.com }
2809*12004Sjiang.liu@intel.com 
2810*12004Sjiang.liu@intel.com sbd_error_t *
drmach_io_post_attach(drmachid_t id)2811*12004Sjiang.liu@intel.com drmach_io_post_attach(drmachid_t id)
2812*12004Sjiang.liu@intel.com {
2813*12004Sjiang.liu@intel.com 	if (!DRMACH_IS_IO_ID(id))
2814*12004Sjiang.liu@intel.com 		return (drerr_new(0, EX86_INAPPROP, NULL));
2815*12004Sjiang.liu@intel.com 
2816*12004Sjiang.liu@intel.com 	return (NULL);
2817*12004Sjiang.liu@intel.com }
2818*12004Sjiang.liu@intel.com 
2819*12004Sjiang.liu@intel.com sbd_error_t *
drmach_io_is_attached(drmachid_t id,int * yes)2820*12004Sjiang.liu@intel.com drmach_io_is_attached(drmachid_t id, int *yes)
2821*12004Sjiang.liu@intel.com {
2822*12004Sjiang.liu@intel.com 	drmach_device_t *dp;
2823*12004Sjiang.liu@intel.com 	dev_info_t	*dip;
2824*12004Sjiang.liu@intel.com 	int		state;
2825*12004Sjiang.liu@intel.com 
2826*12004Sjiang.liu@intel.com 	if (!DRMACH_IS_IO_ID(id))
2827*12004Sjiang.liu@intel.com 		return (drerr_new(0, EX86_INAPPROP, NULL));
2828*12004Sjiang.liu@intel.com 	dp = id;
2829*12004Sjiang.liu@intel.com 
2830*12004Sjiang.liu@intel.com 	dip = dp->node->getdip(dp->node);
2831*12004Sjiang.liu@intel.com 	if (dip == NULL) {
2832*12004Sjiang.liu@intel.com 		*yes = 0;
2833*12004Sjiang.liu@intel.com 		return (NULL);
2834*12004Sjiang.liu@intel.com 	}
2835*12004Sjiang.liu@intel.com 
2836*12004Sjiang.liu@intel.com 	state = ddi_get_devstate(dip);
2837*12004Sjiang.liu@intel.com 	*yes = ((i_ddi_node_state(dip) >= DS_ATTACHED) ||
2838*12004Sjiang.liu@intel.com 	    (state == DDI_DEVSTATE_UP));
2839*12004Sjiang.liu@intel.com 
2840*12004Sjiang.liu@intel.com 	return (NULL);
2841*12004Sjiang.liu@intel.com }
2842*12004Sjiang.liu@intel.com 
2843*12004Sjiang.liu@intel.com /*
2844*12004Sjiang.liu@intel.com  * Miscellaneous interfaces to support dr driver
2845*12004Sjiang.liu@intel.com  */
2846*12004Sjiang.liu@intel.com int
drmach_verify_sr(dev_info_t * dip,int sflag)2847*12004Sjiang.liu@intel.com drmach_verify_sr(dev_info_t *dip, int sflag)
2848*12004Sjiang.liu@intel.com {
2849*12004Sjiang.liu@intel.com 	_NOTE(ARGUNUSED(dip, sflag));
2850*12004Sjiang.liu@intel.com 
2851*12004Sjiang.liu@intel.com 	return (0);
2852*12004Sjiang.liu@intel.com }
2853*12004Sjiang.liu@intel.com 
2854*12004Sjiang.liu@intel.com void
drmach_suspend_last(void)2855*12004Sjiang.liu@intel.com drmach_suspend_last(void)
2856*12004Sjiang.liu@intel.com {
2857*12004Sjiang.liu@intel.com }
2858*12004Sjiang.liu@intel.com 
2859*12004Sjiang.liu@intel.com void
drmach_resume_first(void)2860*12004Sjiang.liu@intel.com drmach_resume_first(void)
2861*12004Sjiang.liu@intel.com {
2862*12004Sjiang.liu@intel.com }
2863*12004Sjiang.liu@intel.com 
2864*12004Sjiang.liu@intel.com /*
2865*12004Sjiang.liu@intel.com  * Log a DR sysevent.
2866*12004Sjiang.liu@intel.com  * Return value: 0 success, non-zero failure.
2867*12004Sjiang.liu@intel.com  */
2868*12004Sjiang.liu@intel.com int
drmach_log_sysevent(int board,char * hint,int flag,int verbose)2869*12004Sjiang.liu@intel.com drmach_log_sysevent(int board, char *hint, int flag, int verbose)
2870*12004Sjiang.liu@intel.com {
2871*12004Sjiang.liu@intel.com 	sysevent_t			*ev = NULL;
2872*12004Sjiang.liu@intel.com 	sysevent_id_t			eid;
2873*12004Sjiang.liu@intel.com 	int				rv, km_flag;
2874*12004Sjiang.liu@intel.com 	sysevent_value_t		evnt_val;
2875*12004Sjiang.liu@intel.com 	sysevent_attr_list_t		*evnt_attr_list = NULL;
2876*12004Sjiang.liu@intel.com 	sbd_error_t			*err;
2877*12004Sjiang.liu@intel.com 	char				attach_pnt[MAXNAMELEN];
2878*12004Sjiang.liu@intel.com 
2879*12004Sjiang.liu@intel.com 	km_flag = (flag == SE_SLEEP) ? KM_SLEEP : KM_NOSLEEP;
2880*12004Sjiang.liu@intel.com 	attach_pnt[0] = '\0';
2881*12004Sjiang.liu@intel.com 	err = drmach_board_name(board, attach_pnt, MAXNAMELEN);
2882*12004Sjiang.liu@intel.com 	if (err != NULL) {
2883*12004Sjiang.liu@intel.com 		sbd_err_clear(&err);
2884*12004Sjiang.liu@intel.com 		rv = -1;
2885*12004Sjiang.liu@intel.com 		goto logexit;
2886*12004Sjiang.liu@intel.com 	}
2887*12004Sjiang.liu@intel.com 	if (verbose) {
2888*12004Sjiang.liu@intel.com 		DRMACH_PR("drmach_log_sysevent: %s %s, flag: %d, verbose: %d\n",
2889*12004Sjiang.liu@intel.com 		    attach_pnt, hint, flag, verbose);
2890*12004Sjiang.liu@intel.com 	}
2891*12004Sjiang.liu@intel.com 
2892*12004Sjiang.liu@intel.com 	if ((ev = sysevent_alloc(EC_DR, ESC_DR_AP_STATE_CHANGE,
2893*12004Sjiang.liu@intel.com 	    SUNW_KERN_PUB"dr", km_flag)) == NULL) {
2894*12004Sjiang.liu@intel.com 		rv = -2;
2895*12004Sjiang.liu@intel.com 		goto logexit;
2896*12004Sjiang.liu@intel.com 	}
2897*12004Sjiang.liu@intel.com 	evnt_val.value_type = SE_DATA_TYPE_STRING;
2898*12004Sjiang.liu@intel.com 	evnt_val.value.sv_string = attach_pnt;
2899*12004Sjiang.liu@intel.com 	if ((rv = sysevent_add_attr(&evnt_attr_list, DR_AP_ID, &evnt_val,
2900*12004Sjiang.liu@intel.com 	    km_flag)) != 0)
2901*12004Sjiang.liu@intel.com 		goto logexit;
2902*12004Sjiang.liu@intel.com 
2903*12004Sjiang.liu@intel.com 	evnt_val.value_type = SE_DATA_TYPE_STRING;
2904*12004Sjiang.liu@intel.com 	evnt_val.value.sv_string = hint;
2905*12004Sjiang.liu@intel.com 	if ((rv = sysevent_add_attr(&evnt_attr_list, DR_HINT, &evnt_val,
2906*12004Sjiang.liu@intel.com 	    km_flag)) != 0) {
2907*12004Sjiang.liu@intel.com 		sysevent_free_attr(evnt_attr_list);
2908*12004Sjiang.liu@intel.com 		goto logexit;
2909*12004Sjiang.liu@intel.com 	}
2910*12004Sjiang.liu@intel.com 
2911*12004Sjiang.liu@intel.com 	(void) sysevent_attach_attributes(ev, evnt_attr_list);
2912*12004Sjiang.liu@intel.com 
2913*12004Sjiang.liu@intel.com 	/*
2914*12004Sjiang.liu@intel.com 	 * Log the event but do not sleep waiting for its
2915*12004Sjiang.liu@intel.com 	 * delivery. This provides insulation from syseventd.
2916*12004Sjiang.liu@intel.com 	 */
2917*12004Sjiang.liu@intel.com 	rv = log_sysevent(ev, SE_NOSLEEP, &eid);
2918*12004Sjiang.liu@intel.com 
2919*12004Sjiang.liu@intel.com logexit:
2920*12004Sjiang.liu@intel.com 	if (ev)
2921*12004Sjiang.liu@intel.com 		sysevent_free(ev);
2922*12004Sjiang.liu@intel.com 	if ((rv != 0) && verbose)
2923*12004Sjiang.liu@intel.com 		cmn_err(CE_WARN, "!drmach_log_sysevent failed (rv %d) for %s "
2924*12004Sjiang.liu@intel.com 		    " %s\n", rv, attach_pnt, hint);
2925*12004Sjiang.liu@intel.com 
2926*12004Sjiang.liu@intel.com 	return (rv);
2927*12004Sjiang.liu@intel.com }
2928