1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 /*
27  * Copyright (c)  * Copyright (c) 2001 Tadpole Technology plc
28  * All rights reserved.
29  * From "@(#)pcicfg.c   1.31    99/06/18 SMI"
30  */
31 
32 #pragma ident	"%Z%%M%	%I%	%E% SMI"
33 
34 /*
35  * Cardbus hotplug module
36  */
37 
38 #include <sys/open.h>
39 #include <sys/file.h>
40 #include <sys/stat.h>
41 #include <sys/ddi.h>
42 #include <sys/sunndi.h>
43 
44 #include <sys/note.h>
45 
46 #include <sys/pci.h>
47 
48 #include <sys/hotplug/hpcsvc.h>
49 #include <sys/hotplug/pci/pcicfg.h>
50 #include <sys/pcic_reg.h>
51 
52 #include "cardbus.h"
53 #include "cardbus_hp.h"
54 #include "cardbus_cfg.h"
55 
56 /*
57  * ************************************************************************
58  * *** Implementation specific data structures/definitions.             ***
59  * ************************************************************************
60  */
61 
62 #ifndef HPC_MAX_OCCUPANTS
63 #define	HPC_MAX_OCCUPANTS 8
64 typedef struct hpc_occupant_info {
65 	int	i;
66 	char 	*id[HPC_MAX_OCCUPANTS];
67 } hpc_occupant_info_t;
68 #endif
69 
70 #define	PCICFG_FLAGS_CONTINUE   0x1
71 
72 #define	PCICFG_OP_ONLINE	0x1
73 #define	PCICFG_OP_OFFLINE	0x0
74 
75 #define	CBHP_DEVCTL_MINOR	255
76 
77 #define	AP_MINOR_NUM_TO_CB_INSTANCE(x)	((x) & 0xFF)
78 #define	AP_MINOR_NUM(x)		(((uint_t)(3) << 8) | ((x) & 0xFF))
79 #define	AP_IS_CB_MINOR(x)	(((x)>>8) == (3))
80 
81 extern int cardbus_debug;
82 
83 static int cardbus_autocfg_enabled = 1;	/* auto config is enabled by default */
84 
85 /* static functions */
86 static int cardbus_event_handler(caddr_t slot_arg, uint_t event_mask);
87 static int cardbus_pci_control(caddr_t ops_arg, hpc_slot_t slot_hdl,
88 				int request, caddr_t arg);
89 static int cardbus_new_slot_state(dev_info_t *dip, hpc_slot_t hdl,
90 				hpc_slot_info_t *slot_info, int slot_state);
91 static int cardbus_list_occupants(dev_info_t *dip, void *hdl);
92 static void create_occupant_props(dev_info_t *self, dev_t dev);
93 static void delete_occupant_props(dev_info_t *dip, dev_t dev);
94 static int cardbus_configure_ap(cbus_t *cbp);
95 static int cardbus_unconfigure_ap(cbus_t *cbp);
96 static int cbus_unconfigure(dev_info_t *devi, int prim_bus);
97 void cardbus_dump_pci_config(dev_info_t *dip);
98 void cardbus_dump_pci_node(dev_info_t *dip);
99 
100 int
101 cardbus_init_hotplug(cbus_t *cbp)
102 {
103 	char tbuf[MAXNAMELEN];
104 	hpc_slot_info_t	slot_info;
105 	hpc_slot_ops_t	*slot_ops;
106 	hpc_slot_t	slhandle;	/* HPS slot handle */
107 
108 	/*
109 	 *  register the bus instance with the HPS framework.
110 	 */
111 	if (hpc_nexus_register_bus(cbp->cb_dip,
112 	    cardbus_new_slot_state, 0) != 0) {
113 		cmn_err(CE_WARN, "%s%d: failed to register the bus with HPS\n",
114 		    ddi_driver_name(cbp->cb_dip), cbp->cb_instance);
115 		return (DDI_FAILURE);
116 	}
117 
118 	(void) sprintf(cbp->ap_id, "slot%d", cbp->cb_instance);
119 	(void) ddi_pathname(cbp->cb_dip, tbuf);
120 	cbp->nexus_path = kmem_alloc(strlen(tbuf) + 1, KM_SLEEP);
121 	(void) strcpy(cbp->nexus_path, tbuf);
122 	cardbus_err(cbp->cb_dip, 8,
123 	    "cardbus_init_hotplug: nexus_path set to %s", cbp->nexus_path);
124 
125 	slot_ops = hpc_alloc_slot_ops(KM_SLEEP);
126 	cbp->slot_ops = slot_ops;
127 
128 	/*
129 	 * Fill in the slot information structure that
130 	 * describes the slot.
131 	 */
132 	slot_info.version = HPC_SLOT_INFO_VERSION;
133 	slot_info.slot_type = HPC_SLOT_TYPE_PCI;
134 	slot_info.slot.pci.device_number = 0;
135 	slot_info.slot.pci.slot_capabilities = 0;
136 
137 	(void) strcpy(slot_info.slot.pci.slot_logical_name, cbp->ap_id);
138 
139 	slot_ops->hpc_version = HPC_SLOT_OPS_VERSION;
140 	slot_ops->hpc_op_connect = NULL;
141 	slot_ops->hpc_op_disconnect = NULL;
142 	slot_ops->hpc_op_insert = NULL;
143 	slot_ops->hpc_op_remove = NULL;
144 	slot_ops->hpc_op_control = cardbus_pci_control;
145 
146 	if (hpc_slot_register(cbp->cb_dip, cbp->nexus_path, &slot_info,
147 	    &slhandle, slot_ops, (caddr_t)cbp, 0) != 0) {
148 		/*
149 		 * If the slot can not be registered,
150 		 * then the slot_ops need to be freed.
151 		 */
152 		cmn_err(CE_WARN,
153 		    "cbp%d Unable to Register Slot %s", cbp->cb_instance,
154 		    slot_info.slot.pci.slot_logical_name);
155 
156 		(void) hpc_nexus_unregister_bus(cbp->cb_dip);
157 		hpc_free_slot_ops(slot_ops);
158 		cbp->slot_ops = NULL;
159 		return (DDI_FAILURE);
160 	}
161 
162 	ASSERT(slhandle == cbp->slot_handle);
163 
164 	cardbus_err(cbp->cb_dip, 8,
165 	    "cardbus_init_hotplug: slot_handle 0x%p", cbp->slot_handle);
166 	return (DDI_SUCCESS);
167 }
168 
169 static int
170 cardbus_event_handler(caddr_t slot_arg, uint_t event_mask)
171 {
172 	int ap_minor = (int)((uintptr_t)slot_arg);
173 	cbus_t *cbp;
174 	int cb_instance;
175 	int rv = HPC_EVENT_CLAIMED;
176 
177 	cb_instance = AP_MINOR_NUM_TO_CB_INSTANCE(ap_minor);
178 
179 	ASSERT(cb_instance >= 0);
180 	cbp = (cbus_t *)ddi_get_soft_state(cardbus_state, cb_instance);
181 	mutex_enter(&cbp->cb_mutex);
182 
183 	switch (event_mask) {
184 
185 	case HPC_EVENT_SLOT_INSERTION:
186 		/*
187 		 * A card is inserted in the slot. Just report this
188 		 * event and return.
189 		 */
190 		cardbus_err(cbp->cb_dip, 7,
191 		    "cardbus_event_handler(%s%d): card is inserted",
192 		    ddi_driver_name(cbp->cb_dip), cbp->cb_instance);
193 
194 		break;
195 
196 	case HPC_EVENT_SLOT_CONFIGURE:
197 		/*
198 		 * Configure the occupant that is just inserted in the slot.
199 		 * The receptacle may or may not be in the connected state. If
200 		 * the receptacle is not connected and the auto configuration
201 		 * is enabled on this slot then connect the slot. If auto
202 		 * configuration is enabled then configure the card.
203 		 */
204 		if (!(cbp->auto_config)) {
205 			/*
206 			 * auto configuration is disabled.
207 			 */
208 			cardbus_err(cbp->cb_dip, 7,
209 			    "cardbus_event_handler(%s%d): "
210 			    "SLOT_CONFIGURE event occured (slot %s)",
211 			    ddi_driver_name(cbp->cb_dip), cbp->cb_instance,
212 			    cbp->name);
213 
214 			break;
215 		}
216 
217 		cardbus_err(cbp->cb_dip, 7,
218 		    "cardbus_event_handler(%s%d): configure event",
219 		    ddi_driver_name(cbp->cb_dip), cbp->cb_instance);
220 
221 		if (cbp->ostate != AP_OSTATE_UNCONFIGURED) {
222 			cmn_err(CE_WARN, "!slot%d already configured\n",
223 				cbp->cb_instance);
224 			break;
225 		}
226 
227 		/*
228 		 * Auto configuration is enabled. First, make sure the
229 		 * receptacle is in the CONNECTED state.
230 		 */
231 		if ((rv = hpc_nexus_connect(cbp->slot_handle,
232 		    NULL, 0)) == HPC_SUCCESS) {
233 			cbp->rstate = AP_RSTATE_CONNECTED; /* record rstate */
234 		}
235 
236 		if (cardbus_configure_ap(cbp) == HPC_SUCCESS)
237 			create_occupant_props(cbp->cb_dip,
238 			    makedevice(ddi_name_to_major(ddi_get_name
239 			    (cbp->cb_dip)),
240 			    ap_minor));
241 		else
242 			rv = HPC_ERR_FAILED;
243 
244 		break;
245 
246 	case HPC_EVENT_SLOT_UNCONFIGURE:
247 		/*
248 		 * Unconfigure the occupant in this slot.
249 		 */
250 		if (!(cbp->auto_config)) {
251 			/*
252 			 * auto configuration is disabled.
253 			 */
254 			cardbus_err(cbp->cb_dip, 7,
255 			    "cardbus_event_handler(%s%d): "
256 			    "SLOT_UNCONFIGURE event"
257 			    " occured - auto-conf disabled (slot %s)",
258 			    ddi_driver_name(cbp->cb_dip), cbp->cb_instance,
259 			    cbp->name);
260 
261 			break;
262 		}
263 
264 		cardbus_err(cbp->cb_dip, 7,
265 		    "cardbus_event_handler(%s%d): SLOT_UNCONFIGURE event"
266 		    " occured (slot %s)",
267 		    ddi_driver_name(cbp->cb_dip), cbp->cb_instance,
268 		    cbp->name);
269 
270 		if (cardbus_unconfigure_ap(cbp) != HPC_SUCCESS)
271 			rv = HPC_ERR_FAILED;
272 
273 		break;
274 
275 	case HPC_EVENT_SLOT_REMOVAL:
276 		/*
277 		 * Card is removed from the slot. The card must have been
278 		 * unconfigured before this event.
279 		 */
280 		if (cbp->ostate != AP_OSTATE_UNCONFIGURED) {
281 			cardbus_err(cbp->cb_dip, 1,
282 			    "cardbus_event_handler(%s%d): "
283 			    "card is removed from"
284 			    " the slot %s before doing unconfigure!!",
285 			    ddi_driver_name(cbp->cb_dip), cbp->cb_instance,
286 			    cbp->name);
287 
288 			break;
289 		}
290 
291 		cardbus_err(cbp->cb_dip, 7,
292 		    "cardbus_event_handler(%s%d): "
293 		    "card is removed from the slot %s",
294 		    ddi_driver_name(cbp->cb_dip), cbp->cb_instance,
295 		    cbp->name);
296 
297 		break;
298 
299 	case HPC_EVENT_SLOT_POWER_ON:
300 		/*
301 		 * Slot is connected to the bus. i.e the card is powered
302 		 * on.
303 		 */
304 		cardbus_err(cbp->cb_dip, 7,
305 		    "cardbus_event_handler(%s%d): "
306 		    "card is powered on in the slot %s",
307 		    ddi_driver_name(cbp->cb_dip), cbp->cb_instance,
308 		    cbp->name);
309 
310 		cbp->rstate = AP_RSTATE_CONNECTED; /* record rstate */
311 
312 		break;
313 
314 	case HPC_EVENT_SLOT_POWER_OFF:
315 		/*
316 		 * Slot is disconnected from the bus. i.e the card is powered
317 		 * off.
318 		 */
319 		cardbus_err(cbp->cb_dip, 7,
320 		    "cardbus_event_handler(%s%d): "
321 		    "card is powered off in the slot %s",
322 		    ddi_driver_name(cbp->cb_dip), cbp->cb_instance,
323 		    cbp->name);
324 
325 		cbp->rstate = AP_RSTATE_DISCONNECTED; /* record rstate */
326 
327 		break;
328 
329 	default:
330 		cardbus_err(cbp->cb_dip, 4,
331 		    "cardbus_event_handler(%s%d): "
332 		    "unknown event %x for this slot %s",
333 		    ddi_driver_name(cbp->cb_dip), cbp->cb_instance,
334 		    event_mask, cbp->name);
335 
336 		break;
337 	}
338 
339 	mutex_exit(&cbp->cb_mutex);
340 
341 	return (rv);
342 }
343 
344 static int
345 cardbus_pci_control(caddr_t ops_arg, hpc_slot_t slot_hdl, int request,
346 			caddr_t arg)
347 {
348 	cbus_t *cbp;
349 	int rval = HPC_SUCCESS;
350 	hpc_led_info_t *hpc_led_info;
351 
352 	_NOTE(ARGUNUSED(slot_hdl))
353 
354 	cbp = (cbus_t *)ops_arg;
355 	ASSERT(mutex_owned(&cbp->cb_mutex));
356 
357 	switch (request) {
358 
359 	case HPC_CTRL_GET_SLOT_STATE:
360 	    {
361 		hpc_slot_state_t	*hpc_slot_state;
362 
363 		hpc_slot_state = (hpc_slot_state_t *)arg;
364 
365 		cardbus_err(cbp->cb_dip, 7,
366 		    "cardbus_pci_control() - "
367 		    "HPC_CTRL_GET_SLOT_STATE hpc_slot_state=0x%p",
368 		    (void *) hpc_slot_state);
369 
370 		if (cbp->card_present)
371 			*hpc_slot_state = HPC_SLOT_CONNECTED;
372 		else
373 			*hpc_slot_state = HPC_SLOT_EMPTY;
374 
375 		break;
376 	    }
377 
378 	case HPC_CTRL_GET_BOARD_TYPE:
379 	    {
380 		hpc_board_type_t	*hpc_board_type;
381 
382 		hpc_board_type = (hpc_board_type_t *)arg;
383 
384 		cardbus_err(cbp->cb_dip, 7,
385 		    "cardbus_pci_control() - HPC_CTRL_GET_BOARD_TYPE");
386 
387 		/*
388 		 * The HPC driver does not know what board type
389 		 * is plugged in.
390 		 */
391 		*hpc_board_type = HPC_BOARD_PCI_HOTPLUG;
392 
393 		break;
394 	    }
395 
396 	case HPC_CTRL_DEV_CONFIGURED:
397 	case HPC_CTRL_DEV_UNCONFIGURED:
398 		cardbus_err(cbp->cb_dip, 5,
399 		    "cardbus_pci_control() - HPC_CTRL_DEV_%sCONFIGURED",
400 		    request == HPC_CTRL_DEV_UNCONFIGURED ? "UN" : "");
401 		break;
402 
403 	case HPC_CTRL_GET_LED_STATE:
404 		hpc_led_info = (hpc_led_info_t *)arg;
405 		cardbus_err(cbp->cb_dip, 5,
406 		    "cardbus_pci_control() - HPC_CTRL_GET_LED_STATE "
407 		    "led %d is %d",
408 		    hpc_led_info->led, cbp->leds[hpc_led_info->led]);
409 
410 		hpc_led_info->state = cbp->leds[hpc_led_info->led];
411 		break;
412 
413 	case HPC_CTRL_SET_LED_STATE:
414 		hpc_led_info = (hpc_led_info_t *)arg;
415 
416 		cardbus_err(cbp->cb_dip, 4,
417 		    "cardbus_pci_control() - HPC_CTRL_SET_LED_STATE "
418 		    "led %d to %d",
419 		    hpc_led_info->led, hpc_led_info->state);
420 
421 		cbp->leds[hpc_led_info->led] = hpc_led_info->state;
422 		break;
423 
424 	case HPC_CTRL_ENABLE_AUTOCFG:
425 		cardbus_err(cbp->cb_dip, 5,
426 		    "cardbus_pci_control() - HPC_CTRL_ENABLE_AUTOCFG");
427 
428 		/*
429 		 * Cardbus ALWAYS does auto config, from the slots point of
430 		 * view this is turning on the card and making sure it's ok.
431 		 * This is all done by the bridge driver before we see any
432 		 * indication.
433 		 */
434 		break;
435 
436 	case HPC_CTRL_DISABLE_AUTOCFG:
437 		cardbus_err(cbp->cb_dip, 5,
438 		    "cardbus_pci_control() - HPC_CTRL_DISABLE_AUTOCFG");
439 		break;
440 
441 	case HPC_CTRL_DISABLE_ENUM:
442 	case HPC_CTRL_ENABLE_ENUM:
443 	default:
444 		rval = HPC_ERR_NOTSUPPORTED;
445 		break;
446 	}
447 
448 	return (rval);
449 }
450 
451 /*
452  * cardbus_new_slot_state()
453  *
454  * This function is called by the HPS when it finds a hot plug
455  * slot is added or being removed from the hot plug framework.
456  * It returns 0 for success and HPC_ERR_FAILED for errors.
457  */
458 static int
459 cardbus_new_slot_state(dev_info_t *dip, hpc_slot_t hdl,
460 			hpc_slot_info_t *slot_info, int slot_state)
461 {
462 	int cb_instance;
463 	cbus_t *cbp;
464 	int ap_minor;
465 	int rv = 0;
466 
467 	cardbus_err(dip, 8,
468 	    "cardbus_new_slot_state: slot_handle 0x%p", hdl);
469 
470 	/*
471 	 * get the soft state structure for the bus instance.
472 	 */
473 	cb_instance = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
474 	    DDI_PROP_DONTPASS, "cbus-instance", -1);
475 	    ASSERT(cb_instance >= 0);
476 	cbp = (cbus_t *)ddi_get_soft_state(cardbus_state, cb_instance);
477 
478 	mutex_enter(&cbp->cb_mutex);
479 
480 	switch (slot_state) {
481 
482 	case HPC_SLOT_ONLINE:
483 		/*
484 		 * Make sure the slot is not already ONLINE
485 		 */
486 		if (cbp->slot_handle != NULL) {
487 			cardbus_err(dip, 4,
488 			    "cardbus_new_slot_state: "
489 			    "cardbus already ONLINE!!");
490 			rv = HPC_ERR_FAILED;
491 			break;
492 		}
493 
494 		/*
495 		 * Add the hot plug slot to the bus.
496 		 */
497 
498 		/* create the AP minor node */
499 		ap_minor = AP_MINOR_NUM(cb_instance);
500 		if (ddi_create_minor_node(dip, slot_info->pci_slot_name,
501 		    S_IFCHR, ap_minor,
502 		    DDI_NT_PCI_ATTACHMENT_POINT,
503 		    0) == DDI_FAILURE) {
504 			cardbus_err(dip, 4,
505 			    "cardbus_new_slot_state: "
506 			    "ddi_create_minor_node failed");
507 			rv = HPC_ERR_FAILED;
508 			break;
509 		}
510 
511 		/* save the slot handle */
512 		cbp->slot_handle = hdl;
513 
514 		/* setup event handler for all hardware events on the slot */
515 		if (hpc_install_event_handler(hdl, -1, cardbus_event_handler,
516 		    (caddr_t)((long)ap_minor)) != 0) {
517 			cardbus_err(dip, 4,
518 			    "cardbus_new_slot_state: "
519 			    "install event handler failed");
520 			rv = HPC_ERR_FAILED;
521 			break;
522 		}
523 		cbp->event_mask = (uint32_t)0xFFFFFFFF;
524 		create_occupant_props(dip,
525 		    makedevice(ddi_name_to_major(ddi_get_name(dip)),
526 		    ap_minor));
527 
528 		/* set default auto configuration enabled flag for this slot */
529 		cbp->auto_config = cardbus_autocfg_enabled;
530 
531 		/* copy the slot information */
532 		cbp->name = (char *)kmem_alloc(strlen(slot_info->pci_slot_name)
533 		    + 1, KM_SLEEP);
534 		(void) strcpy(cbp->name, slot_info->pci_slot_name);
535 		cardbus_err(cbp->cb_dip, 10,
536 		    "cardbus_new_slot_state: cbp->name set to %s", cbp->name);
537 
538 		cardbus_err(dip, 4,
539 		    "Cardbus slot \"%s\" ONLINE\n", slot_info->pci_slot_name);
540 
541 		cbp->ostate = AP_OSTATE_UNCONFIGURED;
542 		cbp->rstate = AP_RSTATE_EMPTY;
543 
544 		break;
545 
546 	case HPC_SLOT_OFFLINE:
547 		/*
548 		 * A hot plug slot is being removed from the bus.
549 		 * Make sure there is no occupant configured on the
550 		 * slot before removing the AP minor node.
551 		 */
552 		if (cbp->ostate != AP_OSTATE_UNCONFIGURED) {
553 			cmn_err(CE_WARN,
554 			    "cardbus: Card is still in configured state");
555 			rv = HPC_ERR_FAILED;
556 			break;
557 		}
558 
559 		/*
560 		 * If the AP device is in open state then return
561 		 * error.
562 		 */
563 		if (cbp->soft_state != PCIHP_SOFT_STATE_CLOSED) {
564 			rv = HPC_ERR_FAILED;
565 			break;
566 		}
567 
568 		/* remove the minor node */
569 		ddi_remove_minor_node(dip, cbp->name);
570 		/* free up the memory for the name string */
571 		kmem_free(cbp->name, strlen(cbp->name) + 1);
572 
573 		/* update the slot info data */
574 		cbp->name = NULL;
575 		cbp->slot_handle = NULL;
576 
577 		cardbus_err(dip, 6,
578 		    "cardbus_new_slot_state: Cardbus slot OFFLINE");
579 		break;
580 
581 	default:
582 		cmn_err(CE_WARN,
583 		    "cardbus_new_slot_state: unknown slot_state %d\n",
584 		    slot_state);
585 		rv = HPC_ERR_FAILED;
586 	}
587 
588 	mutex_exit(&cbp->cb_mutex);
589 
590 	return (rv);
591 }
592 
593 static int
594 cardbus_list_occupants(dev_info_t *dip, void *hdl)
595 {
596 	hpc_occupant_info_t *occupant = (hpc_occupant_info_t *)hdl;
597 	char pn[MAXPATHLEN];
598 
599 	/*
600 	 * Ignore the attachment point and pcs.
601 	 */
602 	if (strcmp(ddi_binding_name(dip), "pcs") == 0) {
603 		return (DDI_WALK_CONTINUE);
604 	}
605 
606 	(void) ddi_pathname(dip, pn);
607 
608 	occupant->id[occupant->i] = kmem_alloc(strlen(pn) + 1, KM_SLEEP);
609 	(void) strcpy(occupant->id[occupant->i], pn);
610 
611 	occupant->i++;
612 
613 	/*
614 	 * continue the walk to the next sibling to look for a match
615 	 * or to find other nodes if this card is a multi-function card.
616 	 */
617 	return (DDI_WALK_PRUNECHILD);
618 }
619 
620 static void
621 create_occupant_props(dev_info_t *self, dev_t dev)
622 {
623 	hpc_occupant_info_t occupant;
624 	int i;
625 	int circular;
626 
627 	occupant.i = 0;
628 
629 	ndi_devi_enter(self, &circular);
630 	ddi_walk_devs(ddi_get_child(self), cardbus_list_occupants,
631 	    (void *)&occupant);
632 	ndi_devi_exit(self, circular);
633 
634 	if (occupant.i == 0) {
635 		char *c[] = { "" };
636 		cardbus_err(self, 1, "create_occupant_props: no occupant\n");
637 		(void) ddi_prop_update_string_array(dev, self, "pci-occupant",
638 		    c, 1);
639 	} else {
640 		cardbus_err(self, 1,
641 		    "create_occupant_props: %d occupant\n", occupant.i);
642 		(void) ddi_prop_update_string_array(dev, self, "pci-occupant",
643 		    occupant.id, occupant.i);
644 	}
645 
646 	for (i = 0; i < occupant.i; i++) {
647 		kmem_free(occupant.id[i], strlen(occupant.id[i]) + 1);
648 	}
649 }
650 
651 static void
652 delete_occupant_props(dev_info_t *dip, dev_t dev)
653 {
654 	if (ddi_prop_remove(dev, dip, "pci-occupant")
655 	    != DDI_PROP_SUCCESS)
656 		return; /* add error handling */
657 
658 }
659 
660 /*
661  * **************************************
662  * CONFIGURE the occupant in the slot.
663  * **************************************
664  */
665 static int
666 cardbus_configure_ap(cbus_t *cbp)
667 {
668 	dev_info_t *self = cbp->cb_dip;
669 	int rv = HPC_SUCCESS;
670 	hpc_slot_state_t rstate;
671 	struct cardbus_config_ctrl ctrl;
672 	int circular_count;
673 
674 	/*
675 	 * check for valid request:
676 	 *  1. It is a hotplug slot.
677 	 *  2. The receptacle is in the CONNECTED state.
678 	 */
679 	if (cbp->slot_handle == NULL || cbp->disabled) {
680 		return (ENXIO);
681 	}
682 
683 	/*
684 	 * If the occupant is already in (partially) configured
685 	 * state then call the ndi_devi_online() on the device
686 	 * subtree(s) for this attachment point.
687 	 */
688 
689 	if (cbp->ostate == AP_OSTATE_CONFIGURED) {
690 		ctrl.flags = PCICFG_FLAGS_CONTINUE;
691 		ctrl.busno = cardbus_primary_busno(self);
692 		ctrl.rv = NDI_SUCCESS;
693 		ctrl.dip = NULL;
694 		ctrl.op = PCICFG_OP_ONLINE;
695 
696 		ndi_devi_enter(self, &circular_count);
697 		ddi_walk_devs(ddi_get_child(self),
698 			cbus_configure, (void *)&ctrl);
699 		ndi_devi_exit(self, circular_count);
700 
701 		if (cardbus_debug) {
702 			cardbus_dump_pci_config(self);
703 			cardbus_dump_pci_node(self);
704 		}
705 
706 		if (ctrl.rv != NDI_SUCCESS) {
707 			/*
708 			 * one or more of the devices are not
709 			 * onlined.
710 			 */
711 			cmn_err(CE_WARN, "cardbus(%s%d): failed to attach "
712 			    "one or more drivers for the card in the slot %s",
713 			    ddi_driver_name(self), cbp->cb_instance,
714 			    cbp->name);
715 		}
716 
717 		/* tell HPC driver that the occupant is configured */
718 		(void) hpc_nexus_control(cbp->slot_handle,
719 		    HPC_CTRL_DEV_CONFIGURED, NULL);
720 		return (rv);
721 	}
722 
723 	/*
724 	 * Occupant is in the UNCONFIGURED state.
725 	 */
726 
727 	/* Check if the receptacle is in the CONNECTED state. */
728 	if (hpc_nexus_control(cbp->slot_handle,
729 	    HPC_CTRL_GET_SLOT_STATE, (caddr_t)&rstate) != 0) {
730 		return (ENXIO);
731 	}
732 
733 	if (rstate != HPC_SLOT_CONNECTED) {
734 		/* error. either the slot is empty or connect failed */
735 		return (ENXIO);
736 	}
737 
738 	cbp->rstate = AP_RSTATE_CONNECTED; /* record rstate */
739 
740 	/*
741 	 * Call the configurator to configure the card.
742 	 */
743 	if (cardbus_configure(cbp) != PCICFG_SUCCESS) {
744 		return (EIO);
745 	}
746 
747 	/* record the occupant state as CONFIGURED */
748 	cbp->ostate = AP_OSTATE_CONFIGURED;
749 	cbp->condition = AP_COND_OK;
750 
751 	/* now, online all the devices in the AP */
752 	ctrl.flags = PCICFG_FLAGS_CONTINUE;
753 	ctrl.busno = cardbus_primary_busno(self);
754 	ctrl.rv = NDI_SUCCESS;
755 	ctrl.dip = NULL;
756 	ctrl.op = PCICFG_OP_ONLINE;
757 
758 	ndi_devi_enter(self, &circular_count);
759 	ddi_walk_devs(ddi_get_child(self), cbus_configure, (void *)&ctrl);
760 	ndi_devi_exit(self, circular_count);
761 
762 	if (cardbus_debug) {
763 		cardbus_dump_pci_config(self);
764 		cardbus_dump_pci_node(self);
765 	}
766 	if (ctrl.rv != NDI_SUCCESS) {
767 		/*
768 		 * one or more of the devices are not
769 		 * ONLINE'd.
770 		 */
771 		cmn_err(CE_WARN, "cbhp (%s%d): failed to attach one or"
772 		    " more drivers for the card in the slot %s",
773 		    ddi_driver_name(cbp->cb_dip),
774 		    cbp->cb_instance, cbp->name);
775 		/* rv = EFAULT; */
776 	}
777 
778 	/* tell HPC driver that the occupant is configured */
779 	(void) hpc_nexus_control(cbp->slot_handle,
780 		HPC_CTRL_DEV_CONFIGURED, NULL);
781 
782 	return (rv);
783 }
784 
785 /*
786  * **************************************
787  * UNCONFIGURE the occupant in the slot.
788  * **************************************
789  */
790 static int
791 cardbus_unconfigure_ap(cbus_t *cbp)
792 {
793 	dev_info_t *self = cbp->cb_dip;
794 	int rv = HPC_SUCCESS, nrv;
795 
796 	/*
797 	 * check for valid request:
798 	 *  1. It is a hotplug slot.
799 	 *  2. The occupant is in the CONFIGURED state.
800 	 */
801 
802 	if (cbp->slot_handle == NULL || cbp->disabled) {
803 		return (ENXIO);
804 	}
805 
806 	/*
807 	 * If the occupant is in the CONFIGURED state then
808 	 * call the configurator to unconfigure the slot.
809 	 */
810 	if (cbp->ostate == AP_OSTATE_CONFIGURED) {
811 		/*
812 		 * Detach all the drivers for the devices in the
813 		 * slot.
814 		 */
815 		nrv = cardbus_unconfigure_node(self,
816 		    cardbus_primary_busno(self),
817 		    B_TRUE);
818 
819 		if (nrv != NDI_SUCCESS) {
820 			/*
821 			 * Failed to detach one or more drivers.
822 			 * Restore the status for the drivers
823 			 * which are offlined during this step.
824 			 */
825 			cmn_err(CE_WARN,
826 			    "cbhp (%s%d): Failed to offline all devices"
827 			    " (slot %s)", ddi_driver_name(cbp->cb_dip),
828 			    cbp->cb_instance, cbp->name);
829 			rv = EBUSY;
830 		} else {
831 
832 			if (cardbus_unconfigure(cbp) == PCICFG_SUCCESS) {
833 				/*
834 				 * Now that resources are freed,
835 				 * clear EXT and Turn LED ON.
836 				 */
837 				cbp->ostate = AP_OSTATE_UNCONFIGURED;
838 				cbp->condition = AP_COND_UNKNOWN;
839 				/*
840 				 * send the notification of state change
841 				 * to the HPC driver.
842 				 */
843 				(void) hpc_nexus_control(cbp->slot_handle,
844 				    HPC_CTRL_DEV_UNCONFIGURED, NULL);
845 			} else {
846 				rv = EIO;
847 			}
848 		}
849 	}
850 
851 	return (rv);
852 }
853 
854 int
855 cbus_configure(dev_info_t *dip, void *hdl)
856 {
857 	pci_regspec_t *pci_rp;
858 	int length, rc;
859 	struct cardbus_config_ctrl *ctrl = (struct cardbus_config_ctrl *)hdl;
860 	uint8_t bus, device, function;
861 
862 	/*
863 	 * Ignore the attachment point and pcs.
864 	 */
865 	if (strcmp(ddi_binding_name(dip), "hp_attachment") == 0 ||
866 	    strcmp(ddi_binding_name(dip), "pcs") == 0) {
867 		cardbus_err(dip, 8, "cbus_configure: Ignoring\n");
868 		return (DDI_WALK_CONTINUE);
869 	}
870 
871 	cardbus_err(dip, 6, "cbus_configure\n");
872 
873 	ASSERT(ctrl->op == PCICFG_OP_ONLINE);
874 
875 	/*
876 	 * Get the PCI device number information from the devinfo
877 	 * node. Since the node may not have the address field
878 	 * setup (this is done in the DDI_INITCHILD of the parent)
879 	 * we look up the 'reg' property to decode that information.
880 	 */
881 	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip,
882 	    DDI_PROP_DONTPASS, "reg", (int **)&pci_rp,
883 	    (uint_t *)&length) != DDI_PROP_SUCCESS) {
884 		/* Porbably not a real device, like PCS for example */
885 		if (ddi_get_child(dip) == NULL)
886 			return (DDI_WALK_PRUNECHILD);
887 
888 		cardbus_err(dip, 1, "cubs_configure: Don't configure device\n");
889 		ctrl->rv = DDI_FAILURE;
890 		ctrl->dip = dip;
891 		return (DDI_WALK_TERMINATE);
892 	}
893 
894 	if (pci_rp->pci_phys_hi == 0)
895 		return (DDI_WALK_CONTINUE);
896 
897 	/* get the pci device id information */
898 	bus = PCI_REG_BUS_G(pci_rp->pci_phys_hi);
899 	device = PCI_REG_DEV_G(pci_rp->pci_phys_hi);
900 	function = PCI_REG_FUNC_G(pci_rp->pci_phys_hi);
901 
902 	/*
903 	 * free the memory allocated by ddi_prop_lookup_int_array
904 	 */
905 	ddi_prop_free(pci_rp);
906 
907 	if (bus <= ctrl->busno)
908 		return (DDI_WALK_CONTINUE);
909 
910 	cardbus_err(dip, 8,
911 	    "cbus_configure on-line device at: "
912 	    "[0x%x][0x%x][0x%x]\n", bus, device, function);
913 
914 	rc = ndi_devi_online(dip, NDI_ONLINE_ATTACH|NDI_CONFIG);
915 
916 	cardbus_err(dip, 7,
917 	    "cbus_configure %s\n",
918 	    rc == NDI_SUCCESS ? "Success": "Failure");
919 
920 	if (rc != NDI_SUCCESS)
921 		return (DDI_WALK_PRUNECHILD);
922 
923 	return (DDI_WALK_CONTINUE);
924 }
925 
926 int
927 cardbus_unconfigure_node(dev_info_t *dip, int prim_bus, boolean_t top_bridge)
928 {
929 	dev_info_t *child, *next;
930 
931 	cardbus_err(dip, 6, "cardbus_unconfigure_node\n");
932 
933 	/*
934 	 * Ignore pcs.
935 	 */
936 	if (strcmp(ddi_binding_name(dip), "pcs") == 0) {
937 		cardbus_err(dip, 8, "cardbus_unconfigure_node: Ignoring\n");
938 		return (NDI_SUCCESS);
939 	}
940 
941 	/*
942 	 * bottom up off-line
943 	 */
944 	for (child = ddi_get_child(dip); child; child = next) {
945 		int rc;
946 		next = ddi_get_next_sibling(child);
947 		rc = cardbus_unconfigure_node(child, prim_bus, B_FALSE);
948 		if (rc != NDI_SUCCESS)
949 			return (rc);
950 	}
951 
952 	/*
953 	 * Don't unconfigure the bridge itself.
954 	 */
955 	if (top_bridge)
956 		return (NDI_SUCCESS);
957 
958 	if (cbus_unconfigure(dip, prim_bus) != NDI_SUCCESS) {
959 		cardbus_err(dip, 1,
960 		    "cardbus_unconfigure_node: cardbus_unconfigure failed\n");
961 		return (NDI_FAILURE);
962 	}
963 	return (NDI_SUCCESS);
964 }
965 
966 /*
967  * This will turn  resources allocated by cbus_configure()
968  * and remove the device tree from the attachment point
969  * and below.  The routine assumes the devices have their
970  * drivers detached.
971  */
972 static int
973 cbus_unconfigure(dev_info_t *devi, int prim_bus)
974 {
975 	pci_regspec_t *pci_rp;
976 	uint_t bus, device, func, length;
977 	int ndi_flags = NDI_UNCONFIG;
978 
979 	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, devi,
980 	    DDI_PROP_DONTPASS, "reg", (int **)&pci_rp,
981 	    &length) != DDI_PROP_SUCCESS) {
982 		/*
983 		 * This cannot be one of our devices. If it's something like a
984 		 * SCSI device then the attempt to offline the HBA
985 		 * (which probably is one of our devices)
986 		 * will also do bottom up offlining. That
987 		 * will fail if this device is busy. So always
988 		 * return success here
989 		 * so that the walk will continue.
990 		 */
991 		return (NDI_SUCCESS);
992 	}
993 
994 	if (pci_rp->pci_phys_hi == 0)
995 		return (NDI_FAILURE);
996 
997 	bus = PCI_REG_BUS_G(pci_rp->pci_phys_hi);
998 
999 	if (bus <= prim_bus)
1000 		return (NDI_SUCCESS);
1001 
1002 	device = PCI_REG_DEV_G(pci_rp->pci_phys_hi);
1003 	func = PCI_REG_FUNC_G(pci_rp->pci_phys_hi);
1004 	ddi_prop_free(pci_rp);
1005 
1006 	cardbus_err(devi, 8,
1007 	    "cbus_unconfigure: "
1008 	    "offline bus [0x%x] device [0x%x] function [%x]\n",
1009 	    bus, device, func);
1010 	if (ndi_devi_offline(devi, ndi_flags) != NDI_SUCCESS) {
1011 		cardbus_err(devi, 1,
1012 		    "Device [0x%x] function [%x] is busy\n", device, func);
1013 		return (NDI_FAILURE);
1014 	}
1015 
1016 	cardbus_err(devi, 9,
1017 	    "Tearing down device [0x%x] function [0x%x]\n", device, func);
1018 
1019 	if (cardbus_teardown_device(devi) != PCICFG_SUCCESS) {
1020 		cardbus_err(devi, 1,
1021 		    "Failed to tear down "
1022 		    "device [0x%x] function [0x%x]\n", device, func);
1023 		return (NDI_FAILURE);
1024 	}
1025 
1026 	return (NDI_SUCCESS);
1027 }
1028 
1029 boolean_t
1030 cardbus_is_cb_minor(dev_t dev)
1031 {
1032 	return (AP_IS_CB_MINOR(getminor(dev)) ? B_TRUE : B_FALSE);
1033 }
1034 
1035 int
1036 cardbus_open(dev_t *devp, int flags, int otyp, cred_t *credp)
1037 {
1038 	cbus_t *cbp;
1039 	int minor;
1040 
1041 	_NOTE(ARGUNUSED(credp))
1042 
1043 	minor = getminor(*devp);
1044 
1045 	/*
1046 	 * Make sure the open is for the right file type.
1047 	 */
1048 	if (otyp != OTYP_CHR)
1049 	return (EINVAL);
1050 
1051 	/*
1052 	 * Get the soft state structure for the 'devctl' device.
1053 	 */
1054 	cbp = (cbus_t *)ddi_get_soft_state(cardbus_state,
1055 		AP_MINOR_NUM_TO_CB_INSTANCE(minor));
1056 	if (cbp == NULL)
1057 		return (ENXIO);
1058 
1059 	mutex_enter(&cbp->cb_mutex);
1060 
1061 	/*
1062 	 * Handle the open by tracking the device state.
1063 	 *
1064 	 * Note: Needs review w.r.t exclusive access to AP or the bus.
1065 	 * Currently in the pci plug-in we don't use EXCL open at all
1066 	 * so the code below implements EXCL access on the bus.
1067 	 */
1068 
1069 	/* enforce exclusive access to the bus */
1070 	if ((cbp->soft_state == PCIHP_SOFT_STATE_OPEN_EXCL) ||
1071 	    ((flags & FEXCL) &&
1072 	    (cbp->soft_state != PCIHP_SOFT_STATE_CLOSED))) {
1073 		mutex_exit(&cbp->cb_mutex);
1074 		return (EBUSY);
1075 	}
1076 
1077 	if (flags & FEXCL)
1078 		cbp->soft_state = PCIHP_SOFT_STATE_OPEN_EXCL;
1079 	else
1080 		cbp->soft_state = PCIHP_SOFT_STATE_OPEN;
1081 
1082 	mutex_exit(&cbp->cb_mutex);
1083 	return (0);
1084 }
1085 
1086 /*ARGSUSED*/
1087 int
1088 cardbus_close(dev_t dev, int flags, int otyp, cred_t *credp)
1089 {
1090 	cbus_t *cbp;
1091 	int minor;
1092 
1093 	_NOTE(ARGUNUSED(credp))
1094 
1095 	minor = getminor(dev);
1096 
1097 	if (otyp != OTYP_CHR)
1098 		return (EINVAL);
1099 
1100 	cbp = (cbus_t *)ddi_get_soft_state(cardbus_state,
1101 	    AP_MINOR_NUM_TO_CB_INSTANCE(minor));
1102 	if (cbp == NULL)
1103 		return (ENXIO);
1104 
1105 	mutex_enter(&cbp->cb_mutex);
1106 	cbp->soft_state = PCIHP_SOFT_STATE_CLOSED;
1107 	mutex_exit(&cbp->cb_mutex);
1108 	return (0);
1109 }
1110 
1111 /*
1112  * cardbus_ioctl: devctl hotplug controls
1113  */
1114 /*ARGSUSED*/
1115 int
1116 cardbus_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
1117 		int *rvalp)
1118 {
1119 	cbus_t *cbp;
1120 	dev_info_t *self;
1121 	dev_info_t *child_dip = NULL;
1122 	struct devctl_iocdata *dcp;
1123 	uint_t bus_state;
1124 	int rv = 0;
1125 	int nrv = 0;
1126 	int ap_minor;
1127 	hpc_slot_state_t rstate;
1128 	devctl_ap_state_t ap_state;
1129 	struct hpc_control_data hpc_ctrldata;
1130 	struct hpc_led_info led_info;
1131 
1132 	_NOTE(ARGUNUSED(credp))
1133 
1134 	ap_minor = getminor(dev);
1135 	cbp = (cbus_t *)ddi_get_soft_state(cardbus_state,
1136 	    AP_MINOR_NUM_TO_CB_INSTANCE(ap_minor));
1137 	if (cbp == NULL)
1138 		return (ENXIO);
1139 
1140 	self = cbp->cb_dip;
1141 	/*
1142 	 * read devctl ioctl data
1143 	 */
1144 	if ((cmd != DEVCTL_AP_CONTROL) && ndi_dc_allochdl((void *)arg,
1145 	    &dcp) != NDI_SUCCESS)
1146 		return (EFAULT);
1147 
1148 #ifdef CARDBUS_DEBUG
1149 {
1150 	char *cmd_name;
1151 
1152 	switch (cmd) {
1153 	case DEVCTL_DEVICE_GETSTATE: cmd_name = "DEVCTL_DEVICE_GETSTATE"; break;
1154 	case DEVCTL_DEVICE_ONLINE: cmd_name = "DEVCTL_DEVICE_ONLINE"; break;
1155 	case DEVCTL_DEVICE_OFFLINE: cmd_name = "DEVCTL_DEVICE_OFFLINE"; break;
1156 	case DEVCTL_DEVICE_RESET: cmd_name = "DEVCTL_DEVICE_RESET"; break;
1157 	case DEVCTL_BUS_QUIESCE: cmd_name = "DEVCTL_BUS_QUIESCE"; break;
1158 	case DEVCTL_BUS_UNQUIESCE: cmd_name = "DEVCTL_BUS_UNQUIESCE"; break;
1159 	case DEVCTL_BUS_RESET: cmd_name = "DEVCTL_BUS_RESET"; break;
1160 	case DEVCTL_BUS_RESETALL: cmd_name = "DEVCTL_BUS_RESETALL"; break;
1161 	case DEVCTL_BUS_GETSTATE: cmd_name = "DEVCTL_BUS_GETSTATE"; break;
1162 	case DEVCTL_AP_CONNECT: cmd_name = "DEVCTL_AP_CONNECT"; break;
1163 	case DEVCTL_AP_DISCONNECT: cmd_name = "DEVCTL_AP_DISCONNECT"; break;
1164 	case DEVCTL_AP_INSERT: cmd_name = "DEVCTL_AP_INSERT"; break;
1165 	case DEVCTL_AP_REMOVE: cmd_name = "DEVCTL_AP_REMOVE"; break;
1166 	case DEVCTL_AP_CONFIGURE: cmd_name = "DEVCTL_AP_CONFIGURE"; break;
1167 	case DEVCTL_AP_UNCONFIGURE: cmd_name = "DEVCTL_AP_UNCONFIGURE"; break;
1168 	case DEVCTL_AP_GETSTATE: cmd_name = "DEVCTL_AP_GETSTATE"; break;
1169 	case DEVCTL_AP_CONTROL: cmd_name = "DEVCTL_AP_CONTROL"; break;
1170 	default: cmd_name = "Unknown"; break;
1171 	}
1172 	cardbus_err(cbp->cb_dip, 7,
1173 	    "cardbus_ioctl: cmd = 0x%x, \"%s\"", cmd, cmd_name);
1174 }
1175 #endif
1176 
1177 	switch (cmd) {
1178 	case DEVCTL_DEVICE_GETSTATE:
1179 	case DEVCTL_DEVICE_ONLINE:
1180 	case DEVCTL_DEVICE_OFFLINE:
1181 	case DEVCTL_BUS_GETSTATE:
1182 		rv = ndi_devctl_ioctl(self, cmd, arg, mode, 0);
1183 		ndi_dc_freehdl(dcp);
1184 		return (rv);
1185 	default:
1186 		break;
1187 	}
1188 
1189 	switch (cmd) {
1190 	case DEVCTL_DEVICE_RESET:
1191 		rv = ENOTSUP;
1192 		break;
1193 
1194 	case DEVCTL_BUS_QUIESCE:
1195 		if (ndi_get_bus_state(self, &bus_state) == NDI_SUCCESS)
1196 			if (bus_state == BUS_QUIESCED)
1197 				break;
1198 		(void) ndi_set_bus_state(self, BUS_QUIESCED);
1199 		break;
1200 
1201 	case DEVCTL_BUS_UNQUIESCE:
1202 		if (ndi_get_bus_state(self, &bus_state) == NDI_SUCCESS)
1203 			if (bus_state == BUS_ACTIVE)
1204 				break;
1205 		(void) ndi_set_bus_state(self, BUS_ACTIVE);
1206 		break;
1207 
1208 	case DEVCTL_BUS_RESET:
1209 		rv = ENOTSUP;
1210 		break;
1211 
1212 	case DEVCTL_BUS_RESETALL:
1213 		rv = ENOTSUP;
1214 		break;
1215 
1216 	case DEVCTL_AP_CONNECT:
1217 	case DEVCTL_AP_DISCONNECT:
1218 		/*
1219 		 * CONNECT(DISCONNECT) the hot plug slot to(from) the bus.
1220 		 */
1221 	case DEVCTL_AP_INSERT:
1222 	case DEVCTL_AP_REMOVE:
1223 		/*
1224 		 * Prepare the slot for INSERT/REMOVE operation.
1225 		 */
1226 
1227 		/*
1228 		 * check for valid request:
1229 		 * 	1. It is a hotplug slot.
1230 		 * 	2. The slot has no occupant that is in
1231 		 * 	the 'configured' state.
1232 		 *
1233 		 * The lower 8 bits of the minor number is the PCI
1234 		 * device number for the slot.
1235 		 */
1236 		if ((cbp->slot_handle == NULL) || cbp->disabled) {
1237 			rv = ENXIO;
1238 			break;
1239 		}
1240 
1241 		/* the slot occupant must be in the UNCONFIGURED state */
1242 		if (cbp->ostate != AP_OSTATE_UNCONFIGURED) {
1243 			rv = EINVAL;
1244 			break;
1245 		}
1246 
1247 		/*
1248 		 * Call the HPC driver to perform the operation on the slot.
1249 		 */
1250 		mutex_enter(&cbp->cb_mutex);
1251 		switch (cmd) {
1252 		case DEVCTL_AP_INSERT:
1253 			rv = hpc_nexus_insert(cbp->slot_handle, NULL, 0);
1254 			break;
1255 		case DEVCTL_AP_REMOVE:
1256 			rv = hpc_nexus_remove(cbp->slot_handle, NULL, 0);
1257 			break;
1258 		case DEVCTL_AP_CONNECT:
1259 			if ((rv = hpc_nexus_connect(cbp->slot_handle,
1260 			    NULL, 0)) == 0)
1261 				cbp->rstate = AP_RSTATE_CONNECTED;
1262 			break;
1263 		case DEVCTL_AP_DISCONNECT:
1264 			if ((rv = hpc_nexus_disconnect(cbp->slot_handle,
1265 			    NULL, 0)) == 0)
1266 				cbp->rstate = AP_RSTATE_DISCONNECTED;
1267 			break;
1268 		}
1269 		mutex_exit(&cbp->cb_mutex);
1270 
1271 		switch (rv) {
1272 		case HPC_ERR_INVALID:
1273 			rv = ENXIO;
1274 			break;
1275 		case HPC_ERR_NOTSUPPORTED:
1276 			rv = ENOTSUP;
1277 			break;
1278 		case HPC_ERR_FAILED:
1279 			rv = EIO;
1280 			break;
1281 		}
1282 
1283 		break;
1284 
1285 	case DEVCTL_AP_CONFIGURE:
1286 		/*
1287 		 * **************************************
1288 		 * CONFIGURE the occupant in the slot.
1289 		 * **************************************
1290 		 */
1291 
1292 		mutex_enter(&cbp->cb_mutex);
1293 		if ((nrv = cardbus_configure_ap(cbp)) == HPC_SUCCESS) {
1294 			create_occupant_props(cbp->cb_dip, dev);
1295 		} else
1296 			rv = nrv;
1297 		mutex_exit(&cbp->cb_mutex);
1298 		break;
1299 
1300 	case DEVCTL_AP_UNCONFIGURE:
1301 		/*
1302 		 * **************************************
1303 		 * UNCONFIGURE the occupant in the slot.
1304 		 * **************************************
1305 		 */
1306 
1307 		mutex_enter(&cbp->cb_mutex);
1308 		if ((nrv = cardbus_unconfigure_ap(cbp)) == HPC_SUCCESS) {
1309 			delete_occupant_props(cbp->cb_dip, dev);
1310 		} else
1311 			rv = nrv;
1312 		mutex_exit(&cbp->cb_mutex);
1313 		break;
1314 
1315 	case DEVCTL_AP_GETSTATE:
1316 	    {
1317 		int mutex_held;
1318 
1319 		/*
1320 		 * return the state of Attachment Point.
1321 		 *
1322 		 * If the occupant is in UNCONFIGURED state then
1323 		 * we should get the receptacle state from the
1324 		 * HPC driver because the receptacle state
1325 		 * maintained in the nexus may not be accurate.
1326 		 */
1327 
1328 		/*
1329 		 * check for valid request:
1330 		 * 	1. It is a hotplug slot.
1331 		 */
1332 		if (cbp->slot_handle == NULL) {
1333 			rv = ENXIO;
1334 			break;
1335 		}
1336 
1337 		/* try to acquire the slot mutex */
1338 		mutex_held = mutex_tryenter(&cbp->cb_mutex);
1339 
1340 		if (cbp->ostate == AP_OSTATE_UNCONFIGURED) {
1341 			if (hpc_nexus_control(cbp->slot_handle,
1342 			    HPC_CTRL_GET_SLOT_STATE,
1343 			    (caddr_t)&rstate) != 0) {
1344 				rv = ENXIO;
1345 				if (mutex_held)
1346 					mutex_exit(&cbp->cb_mutex);
1347 				break;
1348 			}
1349 			cbp->rstate = (ap_rstate_t)rstate;
1350 		}
1351 
1352 		ap_state.ap_rstate = cbp->rstate;
1353 		ap_state.ap_ostate = cbp->ostate;
1354 		ap_state.ap_condition = cbp->condition;
1355 		ap_state.ap_last_change = 0;
1356 		ap_state.ap_error_code = 0;
1357 		if (mutex_held)
1358 			ap_state.ap_in_transition = 0; /* AP is not busy */
1359 		else
1360 			ap_state.ap_in_transition = 1; /* AP is busy */
1361 
1362 		if (mutex_held)
1363 			mutex_exit(&cbp->cb_mutex);
1364 
1365 		/* copy the return-AP-state information to the user space */
1366 		if (ndi_dc_return_ap_state(&ap_state, dcp) != NDI_SUCCESS)
1367 			rv = ENXIO;
1368 
1369 		break;
1370 
1371 	    }
1372 
1373 	case DEVCTL_AP_CONTROL:
1374 		/*
1375 		 * HPC control functions:
1376 		 * 	HPC_CTRL_ENABLE_SLOT/HPC_CTRL_DISABLE_SLOT
1377 		 * 		Changes the state of the slot and preserves
1378 		 * 		the state across the reboot.
1379 		 * 	HPC_CTRL_ENABLE_AUTOCFG/HPC_CTRL_DISABLE_AUTOCFG
1380 		 * 		Enables or disables the auto configuration
1381 		 * 		of hot plugged occupant if the hardware
1382 		 * 		supports notification of the hot plug
1383 		 * 		events.
1384 		 * 	HPC_CTRL_GET_LED_STATE/HPC_CTRL_SET_LED_STATE
1385 		 * 		Controls the state of an LED.
1386 		 * 	HPC_CTRL_GET_SLOT_INFO
1387 		 * 		Get slot information data structure
1388 		 * 		(hpc_slot_info_t).
1389 		 * 	HPC_CTRL_GET_BOARD_TYPE
1390 		 * 		Get board type information (hpc_board_type_t).
1391 		 * 	HPC_CTRL_GET_CARD_INFO
1392 		 * 		Get card information (hpc_card_info_t).
1393 		 *
1394 		 * These control functions are used by the cfgadm plug-in
1395 		 * to implement "-x" and "-v" options.
1396 		 */
1397 
1398 		/* copy user ioctl data first */
1399 #ifdef _MULTI_DATAMODEL
1400 		if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
1401 			struct hpc_control32_data hpc_ctrldata32;
1402 
1403 			if (copyin((void *)arg, (void *)&hpc_ctrldata32,
1404 			    sizeof (struct hpc_control32_data)) != 0) {
1405 				rv = EFAULT;
1406 				break;
1407 			}
1408 			hpc_ctrldata.cmd = hpc_ctrldata32.cmd;
1409 			hpc_ctrldata.data =
1410 			    (void *)(intptr_t)hpc_ctrldata32.data;
1411 		}
1412 #else
1413 		if (copyin((void *)arg, (void *)&hpc_ctrldata,
1414 		    sizeof (struct hpc_control_data)) != 0) {
1415 			rv = EFAULT;
1416 			break;
1417 		}
1418 #endif
1419 
1420 #ifdef CARDBUS_DEBUG
1421 {
1422 		char *hpc_name;
1423 		switch (hpc_ctrldata.cmd) {
1424 		case HPC_CTRL_GET_LED_STATE:
1425 			hpc_name = "HPC_CTRL_GET_LED_STATE";
1426 			break;
1427 		case HPC_CTRL_SET_LED_STATE:
1428 			hpc_name = "HPC_CTRL_SET_LED_STATE";
1429 			break;
1430 		case HPC_CTRL_ENABLE_SLOT:
1431 			hpc_name = "HPC_CTRL_ENABLE_SLOT";
1432 			break;
1433 		case HPC_CTRL_DISABLE_SLOT:
1434 			hpc_name = "HPC_CTRL_DISABLE_SLOT";
1435 			break;
1436 		case HPC_CTRL_ENABLE_AUTOCFG:
1437 			hpc_name = "HPC_CTRL_ENABLE_AUTOCFG";
1438 			break;
1439 		case HPC_CTRL_DISABLE_AUTOCFG:
1440 			hpc_name = "HPC_CTRL_DISABLE_AUTOCFG";
1441 			break;
1442 		case HPC_CTRL_GET_BOARD_TYPE:
1443 			hpc_name = "HPC_CTRL_GET_BOARD_TYPE";
1444 			break;
1445 		case HPC_CTRL_GET_SLOT_INFO:
1446 			hpc_name = "HPC_CTRL_GET_SLOT_INFO";
1447 			break;
1448 		case HPC_CTRL_GET_CARD_INFO:
1449 			hpc_name = "HPC_CTRL_GET_CARD_INFO";
1450 			break;
1451 		default: hpc_name = "Unknown"; break;
1452 		}
1453 		cardbus_err(cbp->cb_dip, 7,
1454 		    "cardbus_ioctl: HP Control cmd 0x%x - \"%s\"",
1455 		    hpc_ctrldata.cmd, hpc_name);
1456 }
1457 #endif
1458 		/*
1459 		 * check for valid request:
1460 		 * 	1. It is a hotplug slot.
1461 		 */
1462 		if (cbp->slot_handle == NULL) {
1463 			rv = ENXIO;
1464 			break;
1465 		}
1466 
1467 		mutex_enter(&cbp->cb_mutex);
1468 		switch (hpc_ctrldata.cmd) {
1469 		case HPC_CTRL_GET_LED_STATE:
1470 			/* copy the led info from the user space */
1471 			if (copyin(hpc_ctrldata.data, (void *)&led_info,
1472 			    sizeof (hpc_led_info_t)) != 0) {
1473 				rv = ENXIO;
1474 				break;
1475 			}
1476 
1477 			/* get the state of LED information */
1478 			if (hpc_nexus_control(cbp->slot_handle,
1479 			    HPC_CTRL_GET_LED_STATE,
1480 			    (caddr_t)&led_info) != 0) {
1481 				rv = ENXIO;
1482 				break;
1483 			}
1484 
1485 			/* copy the led info to the user space */
1486 			if (copyout((void *)&led_info, hpc_ctrldata.data,
1487 			    sizeof (hpc_led_info_t)) != 0) {
1488 				rv = ENXIO;
1489 				break;
1490 			}
1491 			break;
1492 
1493 		case HPC_CTRL_SET_LED_STATE:
1494 			/* copy the led info from the user space */
1495 			if (copyin(hpc_ctrldata.data, (void *)&led_info,
1496 			    sizeof (hpc_led_info_t)) != 0) {
1497 				rv = ENXIO;
1498 				break;
1499 			}
1500 
1501 			/* set the state of an LED */
1502 			if (hpc_nexus_control(cbp->slot_handle,
1503 			    HPC_CTRL_SET_LED_STATE,
1504 			    (caddr_t)&led_info) != 0) {
1505 				rv = ENXIO;
1506 				break;
1507 			}
1508 
1509 			break;
1510 
1511 		case HPC_CTRL_ENABLE_SLOT:
1512 			/*
1513 			 * Enable the slot for hotplug operations.
1514 			 */
1515 			cbp->disabled = B_FALSE;
1516 
1517 			/* tell the HPC driver also */
1518 			(void) hpc_nexus_control(cbp->slot_handle,
1519 				HPC_CTRL_ENABLE_SLOT, NULL);
1520 
1521 			break;
1522 
1523 		case HPC_CTRL_DISABLE_SLOT:
1524 			/*
1525 			 * Disable the slot for hotplug operations.
1526 			 */
1527 			cbp->disabled = B_TRUE;
1528 
1529 			/* tell the HPC driver also */
1530 			(void) hpc_nexus_control(cbp->slot_handle,
1531 				HPC_CTRL_DISABLE_SLOT, NULL);
1532 
1533 			break;
1534 
1535 		case HPC_CTRL_ENABLE_AUTOCFG:
1536 			/*
1537 			 * Enable auto configuration on this slot.
1538 			 */
1539 			cbp->auto_config = B_TRUE;
1540 
1541 			/* tell the HPC driver also */
1542 			(void) hpc_nexus_control(cbp->slot_handle,
1543 				HPC_CTRL_ENABLE_AUTOCFG, NULL);
1544 			break;
1545 
1546 		case HPC_CTRL_DISABLE_AUTOCFG:
1547 			/*
1548 			 * Disable auto configuration on this slot.
1549 			 */
1550 			cbp->auto_config = B_FALSE;
1551 
1552 			/* tell the HPC driver also */
1553 			(void) hpc_nexus_control(cbp->slot_handle,
1554 				HPC_CTRL_DISABLE_AUTOCFG, NULL);
1555 
1556 			break;
1557 
1558 		case HPC_CTRL_GET_BOARD_TYPE:
1559 		    {
1560 			hpc_board_type_t board_type;
1561 
1562 			/*
1563 			 * Get board type data structure, hpc_board_type_t.
1564 			 */
1565 			if (hpc_nexus_control(cbp->slot_handle,
1566 			    HPC_CTRL_GET_BOARD_TYPE,
1567 			    (caddr_t)&board_type) != 0) {
1568 				rv = ENXIO;
1569 				break;
1570 			}
1571 
1572 			/* copy the board type info to the user space */
1573 			if (copyout((void *)&board_type, hpc_ctrldata.data,
1574 			    sizeof (hpc_board_type_t)) != 0) {
1575 				rv = ENXIO;
1576 				break;
1577 			}
1578 
1579 			break;
1580 		    }
1581 
1582 		case HPC_CTRL_GET_SLOT_INFO:
1583 		    {
1584 			hpc_slot_info_t slot_info;
1585 
1586 			/*
1587 			 * Get slot information structure, hpc_slot_info_t.
1588 			 */
1589 			slot_info.version = HPC_SLOT_INFO_VERSION;
1590 			slot_info.slot_type = 0;
1591 			slot_info.pci_slot_capabilities = 0;
1592 			slot_info.pci_dev_num =
1593 				(uint16_t)AP_MINOR_NUM_TO_CB_INSTANCE(ap_minor);
1594 			(void) strcpy(slot_info.pci_slot_name, cbp->name);
1595 
1596 			/* copy the slot info structure to the user space */
1597 			if (copyout((void *)&slot_info, hpc_ctrldata.data,
1598 			    sizeof (hpc_slot_info_t)) != 0) {
1599 				rv = ENXIO;
1600 				break;
1601 			}
1602 
1603 			break;
1604 		    }
1605 
1606 		case HPC_CTRL_GET_CARD_INFO:
1607 		    {
1608 			hpc_card_info_t card_info;
1609 			ddi_acc_handle_t handle;
1610 
1611 			/*
1612 			 * Get card information structure, hpc_card_info_t.
1613 			 */
1614 
1615 			/* verify that the card is configured */
1616 			if (cbp->ostate != AP_OSTATE_CONFIGURED) {
1617 				/* either the card is not present or */
1618 				/* it is not configured. */
1619 				rv = ENXIO;
1620 				break;
1621 			}
1622 
1623 			/* get the information from the PCI config header */
1624 			/* for the function 0. */
1625 			for (child_dip = ddi_get_child(cbp->cb_dip); child_dip;
1626 			    child_dip = ddi_get_next_sibling(child_dip))
1627 				if (strcmp("pcs", ddi_get_name(child_dip)))
1628 					break;
1629 
1630 			if (!child_dip) {
1631 				rv = ENXIO;
1632 				break;
1633 			}
1634 
1635 			if (pci_config_setup(child_dip, &handle)
1636 			    != DDI_SUCCESS) {
1637 				rv = EIO;
1638 				break;
1639 			}
1640 			card_info.prog_class = pci_config_get8(handle,
1641 							PCI_CONF_PROGCLASS);
1642 			card_info.base_class = pci_config_get8(handle,
1643 							PCI_CONF_BASCLASS);
1644 			card_info.sub_class = pci_config_get8(handle,
1645 							PCI_CONF_SUBCLASS);
1646 			card_info.header_type = pci_config_get8(handle,
1647 							PCI_CONF_HEADER);
1648 			pci_config_teardown(&handle);
1649 
1650 			/* copy the card info structure to the user space */
1651 			if (copyout((void *)&card_info, hpc_ctrldata.data,
1652 			    sizeof (hpc_card_info_t)) != 0) {
1653 				rv = ENXIO;
1654 				break;
1655 			}
1656 
1657 			break;
1658 		    }
1659 
1660 		default:
1661 			rv = EINVAL;
1662 			break;
1663 		}
1664 
1665 		mutex_exit(&cbp->cb_mutex);
1666 		break;
1667 
1668 	default:
1669 		rv = ENOTTY;
1670 	}
1671 
1672 	if (cmd != DEVCTL_AP_CONTROL)
1673 		ndi_dc_freehdl(dcp);
1674 
1675 	cardbus_err(cbp->cb_dip, 7,
1676 	    "cardbus_ioctl: rv = 0x%x", rv);
1677 
1678 	return (rv);
1679 }
1680 
1681 struct cardbus_pci_desc {
1682 	char	*name;
1683 	ushort_t	offset;
1684 	int	(*cfg_get_func)();
1685 	char	*fmt;
1686 };
1687 
1688 static struct cardbus_pci_desc generic_pci_cfg[] = {
1689 	    { "VendorId    =", 0, (int(*)())pci_config_get16, "%s 0x%04x" },
1690 	    { "DeviceId    =", 2, (int(*)())pci_config_get16, "%s 0x%04x" },
1691 	    { "Command     =", 4, (int(*)())pci_config_get16, "%s 0x%04x" },
1692 	    { "Status      =", 6, (int(*)())pci_config_get16, "%s 0x%04x" },
1693 	    { "Latency     =", 0xd, (int(*)())pci_config_get8, "%s 0x%02x" },
1694 	    { "BASE0       =", 0x10, (int(*)())pci_config_get32, "%s 0x%08x" },
1695 	    { "BASE1       =", 0x14, (int(*)())pci_config_get32, "%s 0x%08x" },
1696 	    { "BASE2       =", 0x18, (int(*)())pci_config_get32, "%s 0x%08x" },
1697 	    { "BASE3       =", 0x1c, (int(*)())pci_config_get32, "%s 0x%08x" },
1698 	    { "BASE4       =", 0x20, (int(*)())pci_config_get32, "%s 0x%08x" },
1699 	    { "CIS Pointer =", 0x28, (int(*)())pci_config_get32, "%s 0x%08x" },
1700 	    { "ILINE       =", 0x3c, (int(*)())pci_config_get8, "%s 0x%02x" },
1701 	    { "IPIN        =", 0x3d, (int(*)())pci_config_get8, "%s 0x%02x" },
1702 	    { NULL, 0, NULL, NULL }
1703 };
1704 
1705 static struct cardbus_pci_desc cardbus_pci_cfg[] = {
1706 	    { "VendorId    =", 0, (int(*)())pci_config_get16, "%s 0x%04x" },
1707 	    { "DeviceId    =", 2, (int(*)())pci_config_get16, "%s 0x%04x" },
1708 	    { "Command     =", 4, (int(*)())pci_config_get16, "%s 0x%04x" },
1709 	    { "Status      =", 6, (int(*)())pci_config_get16, "%s 0x%04x" },
1710 	    { "CacheLineSz =", 0xc, (int(*)())pci_config_get8, "%s 0x%02x" },
1711 	    { "Latency     =", 0xd, (int(*)())pci_config_get8, "%s 0x%02x" },
1712 	    { "MemBase Addr=", 0x10, (int(*)())pci_config_get32, "%s 0x%08x" },
1713 	    { "Pri Bus     =", 0x18, (int(*)())pci_config_get8, "%s 0x%02x" },
1714 	    { "Sec Bus     =", 0x19, (int(*)())pci_config_get8, "%s 0x%02x" },
1715 	    { "Sub Bus     =", 0x1a, (int(*)())pci_config_get8, "%s 0x%02x" },
1716 	    { "CBus Latency=", 0x1b, (int(*)())pci_config_get8, "%s 0x%02x" },
1717 	    { "Mem0 Base   =", 0x1c, (int(*)())pci_config_get32, "%s 0x%08x" },
1718 	    { "Mem0 Limit  =", 0x20, (int(*)())pci_config_get32, "%s 0x%08x" },
1719 	    { "Mem1 Base   =", 0x24, (int(*)())pci_config_get32, "%s 0x%08x" },
1720 	    { "Mem1 Limit  =", 0x28, (int(*)())pci_config_get32, "%s 0x%08x" },
1721 	    { "I/O0 Base   =", 0x2c, (int(*)())pci_config_get32, "%s 0x%08x" },
1722 	    { "I/O0 Limit  =", 0x30, (int(*)())pci_config_get32, "%s 0x%08x" },
1723 	    { "I/O1 Base   =", 0x34, (int(*)())pci_config_get32, "%s 0x%08x" },
1724 	    { "I/O1 Limit  =", 0x38, (int(*)())pci_config_get32, "%s 0x%08x" },
1725 	    { "ILINE       =", 0x3c, (int(*)())pci_config_get8, "%s 0x%02x" },
1726 	    { "IPIN        =", 0x3d, (int(*)())pci_config_get8, "%s 0x%02x" },
1727 	    { "Bridge Ctrl =", 0x3e, (int(*)())pci_config_get16, "%s 0x%04x" },
1728 	    { "Legacy Addr =", 0x44, (int(*)())pci_config_get32, "%s 0x%08x" },
1729 	    { NULL, 0, NULL, NULL }
1730 };
1731 
1732 static void
1733 cardbus_dump(struct cardbus_pci_desc *spcfg, ddi_acc_handle_t handle)
1734 {
1735 	int	i;
1736 	for (i = 0; spcfg[i].name; i++) {
1737 
1738 		cmn_err(CE_NOTE, spcfg[i].fmt, spcfg[i].name,
1739 			spcfg[i].cfg_get_func(handle, spcfg[i].offset));
1740 	}
1741 
1742 }
1743 
1744 void
1745 cardbus_dump_pci_node(dev_info_t *dip)
1746 {
1747 	dev_info_t *next;
1748 	struct cardbus_pci_desc *spcfg;
1749 	ddi_acc_handle_t config_handle;
1750 	uint32_t VendorId;
1751 
1752 	cmn_err(CE_NOTE, "\nPCI leaf node of dip 0x%p:\n", (void *)dip);
1753 	for (next = ddi_get_child(dip); next;
1754 		next = ddi_get_next_sibling(next)) {
1755 
1756 		VendorId = ddi_getprop(DDI_DEV_T_ANY, next,
1757 				DDI_PROP_CANSLEEP|DDI_PROP_DONTPASS,
1758 				"vendor-id", -1);
1759 		if (VendorId == -1) {
1760 			/* not a pci device */
1761 			continue;
1762 		}
1763 
1764 		if (pci_config_setup(next, &config_handle) != DDI_SUCCESS) {
1765 			cmn_err(CE_WARN, "!pcic child: non pci device\n");
1766 			continue;
1767 		}
1768 
1769 		spcfg = generic_pci_cfg;
1770 		cardbus_dump(spcfg, config_handle);
1771 		pci_config_teardown(&config_handle);
1772 
1773 	}
1774 
1775 }
1776 
1777 void
1778 cardbus_dump_pci_config(dev_info_t *dip)
1779 {
1780 	struct cardbus_pci_desc *spcfg;
1781 	ddi_acc_handle_t config_handle;
1782 
1783 	if (pci_config_setup(dip, &config_handle) != DDI_SUCCESS) {
1784 	    cmn_err(CE_WARN, "!pci_config_setup() failed on 0x%p", (void *)dip);
1785 	    return;
1786 	}
1787 
1788 	spcfg = cardbus_pci_cfg;
1789 	cardbus_dump(spcfg, config_handle);
1790 
1791 	pci_config_teardown(&config_handle);
1792 }
1793 
1794 void
1795 cardbus_dump_socket(dev_info_t *dip)
1796 {
1797 	ddi_acc_handle_t 	iohandle;
1798 	caddr_t		ioaddr;
1799 	ddi_device_acc_attr_t attr;
1800 	attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
1801 	attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
1802 	attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
1803 	if (ddi_regs_map_setup(dip, 1,
1804 				(caddr_t *)&ioaddr,
1805 				0,
1806 				4096,
1807 				&attr, &iohandle) != DDI_SUCCESS) {
1808 	    cmn_err(CE_WARN, "Failed to map address for 0x%p", (void *)dip);
1809 	    return;
1810 	}
1811 
1812 	cmn_err(CE_NOTE, "////////////////////////////////////////");
1813 	cmn_err(CE_NOTE, "SOCKET_EVENT  = [0x%x]",
1814 		ddi_get32(iohandle, (uint32_t *)(ioaddr+CB_STATUS_EVENT)));
1815 	cmn_err(CE_NOTE, "SOCKET_MASK   = [0x%x]",
1816 		ddi_get32(iohandle, (uint32_t *)(ioaddr+CB_STATUS_MASK)));
1817 	cmn_err(CE_NOTE, "SOCKET_STATE  = [0x%x]",
1818 		ddi_get32(iohandle, (uint32_t *)(ioaddr+CB_PRESENT_STATE)));
1819 	cmn_err(CE_NOTE, "////////////////////////////////////////");
1820 
1821 	ddi_regs_map_free(&iohandle);
1822 
1823 }
1824