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