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