1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  *  Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24  *  Use is subject to license terms.
25  */
26 
27 /*
28  * This file contains Standard PCI Express HotPlug functionality that is
29  * compatible with the PCI Express ver 1.1 specification.
30  *
31  * NOTE: This file is compiled and delivered through misc/pcie module.
32  */
33 
34 #include <sys/types.h>
35 #include <sys/note.h>
36 #include <sys/conf.h>
37 #include <sys/kmem.h>
38 #include <sys/debug.h>
39 #include <sys/vtrace.h>
40 #include <sys/autoconf.h>
41 #include <sys/varargs.h>
42 #include <sys/ddi_impldefs.h>
43 #include <sys/time.h>
44 #include <sys/callb.h>
45 #include <sys/ddi.h>
46 #include <sys/sunddi.h>
47 #include <sys/sunndi.h>
48 #include <sys/sysevent/dr.h>
49 #include <sys/pci_impl.h>
50 #include <sys/hotplug/pci/pcie_hp.h>
51 #include <sys/hotplug/pci/pciehpc.h>
52 
53 typedef struct pciehpc_prop {
54 	char	*prop_name;
55 	char	*prop_value;
56 } pciehpc_prop_t;
57 
58 static pciehpc_prop_t	pciehpc_props[] = {
59 	{ PCIEHPC_PROP_LED_FAULT,	PCIEHPC_PROP_VALUE_LED },
60 	{ PCIEHPC_PROP_LED_POWER,	PCIEHPC_PROP_VALUE_LED },
61 	{ PCIEHPC_PROP_LED_ATTN,	PCIEHPC_PROP_VALUE_LED },
62 	{ PCIEHPC_PROP_LED_ACTIVE,	PCIEHPC_PROP_VALUE_LED },
63 	{ PCIEHPC_PROP_CARD_TYPE,	PCIEHPC_PROP_VALUE_TYPE },
64 	{ PCIEHPC_PROP_BOARD_TYPE,	PCIEHPC_PROP_VALUE_TYPE },
65 	{ PCIEHPC_PROP_SLOT_CONDITION,	PCIEHPC_PROP_VALUE_TYPE }
66 };
67 
68 /* Local functions prototype */
69 static int pciehpc_hpc_init(pcie_hp_ctrl_t *ctrl_p);
70 static int pciehpc_hpc_uninit(pcie_hp_ctrl_t *ctrl_p);
71 static int pciehpc_slotinfo_init(pcie_hp_ctrl_t *ctrl_p);
72 static int pciehpc_slotinfo_uninit(pcie_hp_ctrl_t *ctrl_p);
73 static int pciehpc_enable_intr(pcie_hp_ctrl_t *ctrl_p);
74 static int pciehpc_disable_intr(pcie_hp_ctrl_t *ctrl_p);
75 static pcie_hp_ctrl_t *pciehpc_create_controller(dev_info_t *dip);
76 static void pciehpc_destroy_controller(dev_info_t *dip);
77 static int pciehpc_register_slot(pcie_hp_ctrl_t *ctrl_p);
78 static int pciehpc_unregister_slot(pcie_hp_ctrl_t *ctrl_p);
79 static int pciehpc_slot_get_property(pcie_hp_slot_t *slot_p,
80     ddi_hp_property_t *arg, ddi_hp_property_t *rval);
81 static int pciehpc_slot_set_property(pcie_hp_slot_t *slot_p,
82     ddi_hp_property_t *arg, ddi_hp_property_t *rval);
83 static void pciehpc_issue_hpc_command(pcie_hp_ctrl_t *ctrl_p, uint16_t control);
84 static void pciehpc_attn_btn_handler(pcie_hp_ctrl_t *ctrl_p);
85 static pcie_hp_led_state_t pciehpc_led_state_to_hpc(uint16_t state);
86 static pcie_hp_led_state_t pciehpc_get_led_state(pcie_hp_ctrl_t *ctrl_p,
87     pcie_hp_led_t led);
88 static void pciehpc_set_led_state(pcie_hp_ctrl_t *ctrl_p, pcie_hp_led_t led,
89     pcie_hp_led_state_t state);
90 
91 static int pciehpc_upgrade_slot_state(pcie_hp_slot_t *slot_p,
92     ddi_hp_cn_state_t target_state);
93 static int pciehpc_downgrade_slot_state(pcie_hp_slot_t *slot_p,
94     ddi_hp_cn_state_t target_state);
95 static int pciehpc_change_slot_state(pcie_hp_slot_t *slot_p,
96     ddi_hp_cn_state_t target_state);
97 static int
98     pciehpc_slot_poweron(pcie_hp_slot_t *slot_p, ddi_hp_cn_state_t *result);
99 static int
100     pciehpc_slot_poweroff(pcie_hp_slot_t *slot_p, ddi_hp_cn_state_t *result);
101 static int pciehpc_slot_probe(pcie_hp_slot_t *slot_p);
102 static int pciehpc_slot_unprobe(pcie_hp_slot_t *slot_p);
103 
104 #ifdef	DEBUG
105 static void pciehpc_dump_hpregs(pcie_hp_ctrl_t *ctrl_p);
106 #endif	/* DEBUG */
107 
108 /*
109  * Global functions (called by other drivers/modules)
110  */
111 
112 /*
113  * Initialize Hot Plug Controller if present. The arguments are:
114  *	dip	- Devinfo node pointer to the hot plug bus node
115  *	regops	- register ops to access HPC registers for non-standard
116  *		  HPC hw implementations (e.g: HPC in host PCI-E brdiges)
117  *		  This is NULL for standard HPC in PCIe bridges.
118  * Returns:
119  *	DDI_SUCCESS for successful HPC initialization
120  *	DDI_FAILURE for errors or if HPC hw not found
121  */
122 int
123 pciehpc_init(dev_info_t *dip, caddr_t arg)
124 {
125 	pcie_hp_regops_t	*regops = (pcie_hp_regops_t *)(void *)arg;
126 	pcie_hp_ctrl_t		*ctrl_p;
127 
128 	PCIE_DBG("pciehpc_init() called (dip=%p)\n", (void *)dip);
129 
130 	/* Make sure that it is not already initialized */
131 	if ((ctrl_p = PCIE_GET_HP_CTRL(dip)) != NULL) {
132 		PCIE_DBG("%s%d: pciehpc instance already initialized!\n",
133 		    ddi_driver_name(dip), ddi_get_instance(dip));
134 		return (DDI_SUCCESS);
135 	}
136 
137 	/* Allocate a new hotplug controller and slot structures */
138 	ctrl_p = pciehpc_create_controller(dip);
139 
140 	/* setup access handle for HPC regs */
141 	if (regops != NULL) {
142 		/* HPC access is non-standard; use the supplied reg ops */
143 		ctrl_p->hc_regops = *regops;
144 	}
145 
146 	/*
147 	 * Setup resource maps for this bus node.
148 	 */
149 	(void) pci_resource_setup(dip);
150 
151 	PCIE_DISABLE_ERRORS(dip);
152 
153 	/*
154 	 * Set the platform specific hot plug mode.
155 	 */
156 	ctrl_p->hc_ops.init_hpc_hw = pciehpc_hpc_init;
157 	ctrl_p->hc_ops.uninit_hpc_hw = pciehpc_hpc_uninit;
158 	ctrl_p->hc_ops.init_hpc_slotinfo = pciehpc_slotinfo_init;
159 	ctrl_p->hc_ops.uninit_hpc_slotinfo = pciehpc_slotinfo_uninit;
160 	ctrl_p->hc_ops.poweron_hpc_slot = pciehpc_slot_poweron;
161 	ctrl_p->hc_ops.poweroff_hpc_slot = pciehpc_slot_poweroff;
162 
163 	ctrl_p->hc_ops.enable_hpc_intr = pciehpc_enable_intr;
164 	ctrl_p->hc_ops.disable_hpc_intr = pciehpc_disable_intr;
165 
166 #if	defined(__i386) || defined(__amd64)
167 	pciehpc_update_ops(ctrl_p);
168 #endif
169 
170 	/* initialize hot plug controller hw */
171 	if ((ctrl_p->hc_ops.init_hpc_hw)(ctrl_p) != DDI_SUCCESS)
172 		goto cleanup1;
173 
174 	/* initialize slot information soft state structure */
175 	if ((ctrl_p->hc_ops.init_hpc_slotinfo)(ctrl_p) != DDI_SUCCESS)
176 		goto cleanup2;
177 
178 	/* register the hot plug slot with DDI HP framework */
179 	if (pciehpc_register_slot(ctrl_p) != DDI_SUCCESS)
180 		goto cleanup3;
181 
182 	/* create minor node for this slot */
183 	if (pcie_create_minor_node(ctrl_p, 0) != DDI_SUCCESS)
184 		goto cleanup4;
185 
186 	/* HPC initialization is complete now */
187 	ctrl_p->hc_flags = PCIE_HP_INITIALIZED_FLAG;
188 
189 #ifdef	DEBUG
190 	/* For debug, dump the HPC registers */
191 	pciehpc_dump_hpregs(ctrl_p);
192 #endif	/* DEBUG */
193 
194 	/* enable hot plug interrupts/event */
195 	(void) (ctrl_p->hc_ops.enable_hpc_intr)(ctrl_p);
196 
197 	return (DDI_SUCCESS);
198 cleanup4:
199 	(void) pciehpc_unregister_slot(ctrl_p);
200 cleanup3:
201 	(void) (ctrl_p->hc_ops.uninit_hpc_slotinfo)(ctrl_p);
202 
203 cleanup2:
204 	(void) (ctrl_p->hc_ops.uninit_hpc_hw)(ctrl_p);
205 
206 cleanup1:
207 	PCIE_ENABLE_ERRORS(dip);
208 	(void) pci_resource_destroy(dip);
209 
210 	pciehpc_destroy_controller(dip);
211 	return (DDI_FAILURE);
212 }
213 
214 /*
215  * Uninitialize HPC soft state structure and free up any resources
216  * used for the HPC instance.
217  */
218 int
219 pciehpc_uninit(dev_info_t *dip)
220 {
221 	pcie_hp_ctrl_t *ctrl_p;
222 
223 	PCIE_DBG("pciehpc_uninit() called (dip=%p)\n", (void *)dip);
224 
225 	/* get the soft state structure for this dip */
226 	if ((ctrl_p = PCIE_GET_HP_CTRL(dip)) == NULL) {
227 		return (DDI_FAILURE);
228 	}
229 
230 	pcie_remove_minor_node(ctrl_p, 0);
231 
232 	/* disable interrupts */
233 	(void) (ctrl_p->hc_ops.disable_hpc_intr)(ctrl_p);
234 
235 	/* unregister the slot */
236 	(void) pciehpc_unregister_slot(ctrl_p);
237 
238 	/* uninit any slot info data structures */
239 	(void) (ctrl_p->hc_ops.uninit_hpc_slotinfo)(ctrl_p);
240 
241 	/* uninitialize hpc, remove interrupt handler, etc. */
242 	(void) (ctrl_p->hc_ops.uninit_hpc_hw)(ctrl_p);
243 
244 	PCIE_ENABLE_ERRORS(dip);
245 
246 	/*
247 	 * Destroy resource maps for this bus node.
248 	 */
249 	(void) pci_resource_destroy(dip);
250 
251 	/* destroy the soft state structure */
252 	pciehpc_destroy_controller(dip);
253 
254 	return (DDI_SUCCESS);
255 }
256 
257 /*
258  * pciehpc_intr()
259  *
260  * Interrupt handler for PCI-E Hot plug controller interrupts.
261  *
262  * Note: This is only for native mode hot plug. This is called
263  * by the nexus driver at interrupt context. Interrupt Service Routine
264  * registration is done by the nexus driver for both hot plug and
265  * non-hot plug interrupts. This function is called from the ISR
266  * of the nexus driver to handle hot-plug interrupts.
267  */
268 int
269 pciehpc_intr(dev_info_t *dip)
270 {
271 	pcie_hp_ctrl_t	*ctrl_p;
272 	pcie_hp_slot_t	*slot_p;
273 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(dip);
274 	uint16_t	status, control;
275 
276 	/* get the soft state structure for this dip */
277 	if ((ctrl_p = PCIE_GET_HP_CTRL(dip)) == NULL)
278 		return (DDI_INTR_UNCLAIMED);
279 
280 	mutex_enter(&ctrl_p->hc_mutex);
281 
282 	/* make sure the controller soft state is initialized */
283 	if (!(ctrl_p->hc_flags & PCIE_HP_INITIALIZED_FLAG)) {
284 		mutex_exit(&ctrl_p->hc_mutex);
285 		return (DDI_INTR_UNCLAIMED);
286 	}
287 
288 	/* if it is not NATIVE hot plug mode then return */
289 	if (bus_p->bus_hp_curr_mode != PCIE_NATIVE_HP_MODE) {
290 		mutex_exit(&ctrl_p->hc_mutex);
291 		return (DDI_INTR_UNCLAIMED);
292 	}
293 
294 	slot_p = ctrl_p->hc_slots[0];
295 
296 	/* read the current slot status register */
297 	status = pciehpc_reg_get16(ctrl_p,
298 	    bus_p->bus_pcie_off + PCIE_SLOTSTS);
299 
300 	/* check if there are any hot plug interrupts occurred */
301 	if (!(status & PCIE_SLOTSTS_STATUS_EVENTS)) {
302 		/* no hot plug events occurred */
303 		mutex_exit(&ctrl_p->hc_mutex);
304 		return (DDI_INTR_UNCLAIMED);
305 	}
306 
307 	/* clear the interrupt status bits */
308 	pciehpc_reg_put16(ctrl_p,
309 	    bus_p->bus_pcie_off + PCIE_SLOTSTS, status);
310 
311 	/* check for CMD COMPLETE interrupt */
312 	if (status & PCIE_SLOTSTS_COMMAND_COMPLETED) {
313 		PCIE_DBG("pciehpc_intr(): CMD COMPLETED interrupt received\n");
314 		/* wake up any one waiting for Command Completion event */
315 		cv_signal(&ctrl_p->hc_cmd_comp_cv);
316 	}
317 
318 	/* check for ATTN button interrupt */
319 	if (status & PCIE_SLOTSTS_ATTN_BTN_PRESSED) {
320 		PCIE_DBG("pciehpc_intr(): ATTN BUTTON interrupt received\n");
321 
322 		/* if ATTN button event is still pending then cancel it */
323 		if (slot_p->hs_attn_btn_pending == B_TRUE)
324 			slot_p->hs_attn_btn_pending = B_FALSE;
325 		else
326 			slot_p->hs_attn_btn_pending = B_TRUE;
327 
328 		/* wake up the ATTN event handler */
329 		cv_signal(&slot_p->hs_attn_btn_cv);
330 	}
331 
332 	/* check for power fault interrupt */
333 	if (status & PCIE_SLOTSTS_PWR_FAULT_DETECTED) {
334 
335 		PCIE_DBG("pciehpc_intr(): POWER FAULT interrupt received"
336 		    " on slot %d\n", slot_p->hs_phy_slot_num);
337 		control =  pciehpc_reg_get16(ctrl_p,
338 		    bus_p->bus_pcie_off + PCIE_SLOTCTL);
339 
340 		if (control & PCIE_SLOTCTL_PWR_FAULT_EN) {
341 			slot_p->hs_condition = AP_COND_FAILED;
342 
343 			/* disable power fault detction interrupt */
344 			pciehpc_reg_put16(ctrl_p, bus_p->bus_pcie_off +
345 			    PCIE_SLOTCTL, control & ~PCIE_SLOTCTL_PWR_FAULT_EN);
346 
347 			/*
348 			 * Send the event to DDI Hotplug framework, power off
349 			 * the slot
350 			 */
351 			(void) ndi_hp_state_change_req(dip,
352 			    slot_p->hs_info.cn_name,
353 			    DDI_HP_CN_STATE_EMPTY, DDI_HP_REQ_ASYNC);
354 
355 			pciehpc_set_led_state(ctrl_p, PCIE_HP_ATTN_LED,
356 			    PCIE_HP_LED_ON);
357 		}
358 	}
359 
360 	/* check for MRL SENSOR CHANGED interrupt */
361 	if (status & PCIE_SLOTSTS_MRL_SENSOR_CHANGED) {
362 		/* For now (phase-I), no action is taken on this event */
363 		PCIE_DBG("pciehpc_intr(): MRL SENSOR CHANGED interrupt received"
364 		    " on slot %d\n", slot_p->hs_phy_slot_num);
365 	}
366 
367 	/* check for PRESENCE CHANGED interrupt */
368 	if (status & PCIE_SLOTSTS_PRESENCE_CHANGED) {
369 
370 		PCIE_DBG("pciehpc_intr(): PRESENCE CHANGED interrupt received"
371 		    " on slot %d\n", slot_p->hs_phy_slot_num);
372 
373 		if (status & PCIE_SLOTSTS_PRESENCE_DETECTED) {
374 			/*
375 			 * card is inserted into the slot, ask DDI Hotplug
376 			 * framework to change state to Present.
377 			 */
378 			(void) ndi_hp_state_change_req(dip,
379 			    slot_p->hs_info.cn_name,
380 			    DDI_HP_CN_STATE_PRESENT,
381 			    DDI_HP_REQ_ASYNC);
382 		} else { /* card is removed from the slot */
383 			cmn_err(CE_NOTE, "pciehpc (%s%d): card is removed"
384 			    " from the slot %s",
385 			    ddi_driver_name(dip),
386 			    ddi_get_instance(dip),
387 			    slot_p->hs_info.cn_name);
388 
389 			if (slot_p->hs_info.cn_state ==
390 			    DDI_HP_CN_STATE_ENABLED) {
391 				/* Card is removed when slot is enabled */
392 				slot_p->hs_condition = AP_COND_FAILED;
393 			} else {
394 				slot_p->hs_condition = AP_COND_UNKNOWN;
395 			}
396 			/* make sure to disable power fault detction intr */
397 			control =  pciehpc_reg_get16(ctrl_p,
398 			    bus_p->bus_pcie_off + PCIE_SLOTCTL);
399 
400 			if (control & PCIE_SLOTCTL_PWR_FAULT_EN)
401 				pciehpc_reg_put16(ctrl_p, bus_p->bus_pcie_off +
402 				    PCIE_SLOTCTL,
403 				    control & ~PCIE_SLOTCTL_PWR_FAULT_EN);
404 
405 			/*
406 			 * Ask DDI Hotplug framework to change state to Empty
407 			 */
408 			(void) ndi_hp_state_change_req(dip,
409 			    slot_p->hs_info.cn_name,
410 			    DDI_HP_CN_STATE_EMPTY,
411 			    DDI_HP_REQ_ASYNC);
412 		}
413 	}
414 
415 	/* check for DLL state changed interrupt */
416 	if (ctrl_p->hc_dll_active_rep &&
417 	    (status & PCIE_SLOTSTS_DLL_STATE_CHANGED)) {
418 		PCIE_DBG("pciehpc_intr(): DLL STATE CHANGED interrupt received"
419 		    " on slot %d\n", slot_p->hs_phy_slot_num);
420 
421 		cv_signal(&slot_p->hs_dll_active_cv);
422 	}
423 
424 	mutex_exit(&ctrl_p->hc_mutex);
425 
426 	return (DDI_INTR_CLAIMED);
427 }
428 
429 /*
430  * Handle hotplug commands
431  *
432  * Note: This function is called by DDI HP framework at kernel context only
433  */
434 /* ARGSUSED */
435 int
436 pciehpc_hp_ops(dev_info_t *dip, char *cn_name, ddi_hp_op_t op,
437     void *arg, void *result)
438 {
439 	pcie_hp_ctrl_t	*ctrl_p;
440 	pcie_hp_slot_t	*slot_p;
441 	int		ret = DDI_SUCCESS;
442 
443 	PCIE_DBG("pciehpc_hp_ops: dip=%p cn_name=%s op=%x arg=%p\n",
444 	    dip, cn_name, op, arg);
445 
446 	if ((ctrl_p = PCIE_GET_HP_CTRL(dip)) == NULL)
447 		return (DDI_FAILURE);
448 
449 	slot_p = ctrl_p->hc_slots[0];
450 
451 	if (strcmp(cn_name, slot_p->hs_info.cn_name) != 0)
452 		return (DDI_EINVAL);
453 
454 	switch (op) {
455 	case DDI_HPOP_CN_GET_STATE:
456 	{
457 		mutex_enter(&slot_p->hs_ctrl->hc_mutex);
458 
459 		/* get the current slot state */
460 		pciehpc_get_slot_state(slot_p);
461 
462 		*((ddi_hp_cn_state_t *)result) = slot_p->hs_info.cn_state;
463 
464 		mutex_exit(&slot_p->hs_ctrl->hc_mutex);
465 		break;
466 	}
467 	case DDI_HPOP_CN_CHANGE_STATE:
468 	{
469 		ddi_hp_cn_state_t target_state = *(ddi_hp_cn_state_t *)arg;
470 
471 		mutex_enter(&slot_p->hs_ctrl->hc_mutex);
472 
473 		ret = pciehpc_change_slot_state(slot_p, target_state);
474 		*(ddi_hp_cn_state_t *)result = slot_p->hs_info.cn_state;
475 
476 		mutex_exit(&slot_p->hs_ctrl->hc_mutex);
477 		break;
478 	}
479 	case DDI_HPOP_CN_PROBE:
480 
481 		ret = pciehpc_slot_probe(slot_p);
482 
483 		break;
484 	case DDI_HPOP_CN_UNPROBE:
485 		ret = pciehpc_slot_unprobe(slot_p);
486 
487 		break;
488 	case DDI_HPOP_CN_GET_PROPERTY:
489 		ret = pciehpc_slot_get_property(slot_p,
490 		    (ddi_hp_property_t *)arg, (ddi_hp_property_t *)result);
491 		break;
492 	case DDI_HPOP_CN_SET_PROPERTY:
493 		ret = pciehpc_slot_set_property(slot_p,
494 		    (ddi_hp_property_t *)arg, (ddi_hp_property_t *)result);
495 		break;
496 	default:
497 		ret = DDI_ENOTSUP;
498 		break;
499 	}
500 
501 	return (ret);
502 }
503 
504 /*
505  * Get the current state of the slot from the hw.
506  *
507  * The slot state should have been initialized before this function gets called.
508  */
509 void
510 pciehpc_get_slot_state(pcie_hp_slot_t *slot_p)
511 {
512 	pcie_hp_ctrl_t	*ctrl_p = slot_p->hs_ctrl;
513 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
514 	uint16_t	control, status;
515 	ddi_hp_cn_state_t curr_state = slot_p->hs_info.cn_state;
516 
517 	/* read the Slot Control Register */
518 	control = pciehpc_reg_get16(ctrl_p,
519 	    bus_p->bus_pcie_off + PCIE_SLOTCTL);
520 
521 	slot_p->hs_fault_led_state = PCIE_HP_LED_OFF; /* no fault led */
522 	slot_p->hs_active_led_state = PCIE_HP_LED_OFF; /* no active led */
523 
524 	/* read the current Slot Status Register */
525 	status = pciehpc_reg_get16(ctrl_p,
526 	    bus_p->bus_pcie_off + PCIE_SLOTSTS);
527 
528 	/* get POWER led state */
529 	slot_p->hs_power_led_state =
530 	    pciehpc_led_state_to_hpc(pcie_slotctl_pwr_indicator_get(control));
531 
532 	/* get ATTN led state */
533 	slot_p->hs_attn_led_state =
534 	    pciehpc_led_state_to_hpc(pcie_slotctl_attn_indicator_get(control));
535 
536 	if (!(status & PCIE_SLOTSTS_PRESENCE_DETECTED)) {
537 		/* no device present; slot is empty */
538 		slot_p->hs_info.cn_state = DDI_HP_CN_STATE_EMPTY;
539 
540 		return;
541 	}
542 
543 	/* device is present */
544 	slot_p->hs_info.cn_state = DDI_HP_CN_STATE_PRESENT;
545 
546 	if (!(control & PCIE_SLOTCTL_PWR_CONTROL)) {
547 		/*
548 		 * Device is powered on. Set to "ENABLED" state (skip
549 		 * POWERED state) because there is not a explicit "enable"
550 		 * action exists for PCIe.
551 		 * If it is already in "POWERED" state, then keep it until
552 		 * user explicitly change it to other states.
553 		 */
554 		if (curr_state == DDI_HP_CN_STATE_POWERED) {
555 			slot_p->hs_info.cn_state = curr_state;
556 		} else {
557 			slot_p->hs_info.cn_state = DDI_HP_CN_STATE_ENABLED;
558 		}
559 	}
560 }
561 
562 /*
563  * setup slot name/slot-number info.
564  */
565 void
566 pciehpc_set_slot_name(pcie_hp_ctrl_t *ctrl_p)
567 {
568 	pcie_hp_slot_t	*slot_p = ctrl_p->hc_slots[0];
569 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
570 	uchar_t		*slotname_data;
571 	int		*slotnum;
572 	uint_t		count;
573 	int		len;
574 	int		invalid_slotnum = 0;
575 	uint32_t	slot_capabilities;
576 
577 	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, ctrl_p->hc_dip,
578 	    DDI_PROP_DONTPASS, "physical-slot#", &slotnum, &count) ==
579 	    DDI_PROP_SUCCESS) {
580 		slot_p->hs_phy_slot_num = slotnum[0];
581 		ddi_prop_free(slotnum);
582 	} else {
583 		slot_capabilities = pciehpc_reg_get32(ctrl_p,
584 		    bus_p->bus_pcie_off + PCIE_SLOTCAP);
585 		slot_p->hs_phy_slot_num =
586 		    PCIE_SLOTCAP_PHY_SLOT_NUM(slot_capabilities);
587 	}
588 
589 	/* platform may not have initialized it */
590 	if (!slot_p->hs_phy_slot_num) {
591 		PCIE_DBG("%s#%d: Invalid slot number!\n",
592 		    ddi_driver_name(ctrl_p->hc_dip),
593 		    ddi_get_instance(ctrl_p->hc_dip));
594 		slot_p->hs_phy_slot_num = pciehpc_reg_get8(ctrl_p,
595 		    PCI_BCNF_SECBUS);
596 		invalid_slotnum = 1;
597 	}
598 	slot_p->hs_info.cn_num = slot_p->hs_phy_slot_num;
599 	slot_p->hs_info.cn_num_dpd_on = DDI_HP_CN_NUM_NONE;
600 
601 	/*
602 	 * construct the slot_name:
603 	 *	if "slot-names" property exists then use that name
604 	 *	else if valid slot number exists then it is "pcie<slot-num>".
605 	 *	else it will be "pcie<sec-bus-number>dev0"
606 	 */
607 	if (ddi_getlongprop(DDI_DEV_T_ANY, ctrl_p->hc_dip, DDI_PROP_DONTPASS,
608 	    "slot-names", (caddr_t)&slotname_data, &len) == DDI_PROP_SUCCESS) {
609 		char tmp_name[256];
610 
611 		/*
612 		 * Note: for PCI-E slots, the device number is always 0 so the
613 		 * first (and only) string is the slot name for this slot.
614 		 */
615 		(void) snprintf(tmp_name, sizeof (tmp_name),
616 		    (char *)slotname_data + 4);
617 		slot_p->hs_info.cn_name = ddi_strdup(tmp_name, KM_SLEEP);
618 		kmem_free(slotname_data, len);
619 	} else {
620 		if (invalid_slotnum) {
621 			/* use device number ie. 0 */
622 			slot_p->hs_info.cn_name = ddi_strdup("pcie0",
623 			    KM_SLEEP);
624 		} else {
625 			char tmp_name[256];
626 
627 			(void) snprintf(tmp_name, sizeof (tmp_name), "pcie%d",
628 			    slot_p->hs_phy_slot_num);
629 			slot_p->hs_info.cn_name = ddi_strdup(tmp_name,
630 			    KM_SLEEP);
631 		}
632 	}
633 }
634 
635 /*
636  * Read/Write access to HPC registers. If platform nexus has non-standard
637  * HPC access mechanism then regops functions are used to do reads/writes.
638  */
639 uint8_t
640 pciehpc_reg_get8(pcie_hp_ctrl_t *ctrl_p, uint_t off)
641 {
642 	if (ctrl_p->hc_regops.get != NULL) {
643 		return ((uint8_t)ctrl_p->hc_regops.get(
644 		    ctrl_p->hc_regops.cookie, (off_t)off));
645 	} else {
646 		pcie_bus_t	*bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
647 
648 		return (pci_config_get8(bus_p->bus_cfg_hdl, off));
649 	}
650 }
651 
652 uint16_t
653 pciehpc_reg_get16(pcie_hp_ctrl_t *ctrl_p, uint_t off)
654 {
655 	if (ctrl_p->hc_regops.get != NULL) {
656 		return ((uint16_t)ctrl_p->hc_regops.get(
657 		    ctrl_p->hc_regops.cookie, (off_t)off));
658 	} else {
659 		pcie_bus_t	*bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
660 
661 		return (pci_config_get16(bus_p->bus_cfg_hdl, off));
662 	}
663 }
664 
665 uint32_t
666 pciehpc_reg_get32(pcie_hp_ctrl_t *ctrl_p, uint_t off)
667 {
668 	if (ctrl_p->hc_regops.get != NULL) {
669 		return ((uint32_t)ctrl_p->hc_regops.get(
670 		    ctrl_p->hc_regops.cookie, (off_t)off));
671 	} else {
672 		pcie_bus_t	*bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
673 
674 		return (pci_config_get32(bus_p->bus_cfg_hdl, off));
675 	}
676 }
677 
678 void
679 pciehpc_reg_put8(pcie_hp_ctrl_t *ctrl_p, uint_t off, uint8_t val)
680 {
681 	if (ctrl_p->hc_regops.put != NULL) {
682 		ctrl_p->hc_regops.put(ctrl_p->hc_regops.cookie,
683 		    (off_t)off, (uint_t)val);
684 	} else {
685 		pcie_bus_t	*bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
686 
687 		pci_config_put8(bus_p->bus_cfg_hdl, off, val);
688 	}
689 }
690 
691 void
692 pciehpc_reg_put16(pcie_hp_ctrl_t *ctrl_p, uint_t off, uint16_t val)
693 {
694 	if (ctrl_p->hc_regops.put != NULL) {
695 		ctrl_p->hc_regops.put(ctrl_p->hc_regops.cookie,
696 		    (off_t)off, (uint_t)val);
697 	} else {
698 		pcie_bus_t	*bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
699 
700 		pci_config_put16(bus_p->bus_cfg_hdl, off, val);
701 	}
702 }
703 
704 void
705 pciehpc_reg_put32(pcie_hp_ctrl_t *ctrl_p, uint_t off, uint32_t val)
706 {
707 	if (ctrl_p->hc_regops.put != NULL) {
708 		ctrl_p->hc_regops.put(ctrl_p->hc_regops.cookie,
709 		    (off_t)off, (uint_t)val);
710 	} else {
711 		pcie_bus_t	*bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
712 
713 		pci_config_put32(bus_p->bus_cfg_hdl, off, val);
714 	}
715 }
716 
717 /*
718  * ************************************************************************
719  * ***	Local functions (called within this file)
720  * ***	PCIe Native Hotplug mode specific functions
721  * ************************************************************************
722  */
723 
724 /*
725  * Initialize HPC hardware, install interrupt handler, etc. It doesn't
726  * enable hot plug interrupts.
727  *
728  * (Note: It is called only from pciehpc_init().)
729  */
730 static int
731 pciehpc_hpc_init(pcie_hp_ctrl_t *ctrl_p)
732 {
733 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
734 	uint16_t	reg;
735 
736 	/* read the Slot Control Register */
737 	reg = pciehpc_reg_get16(ctrl_p,
738 	    bus_p->bus_pcie_off + PCIE_SLOTCTL);
739 
740 	/* disable all interrupts */
741 	reg &= ~(PCIE_SLOTCTL_INTR_MASK);
742 	pciehpc_reg_put16(ctrl_p, bus_p->bus_pcie_off +
743 	    PCIE_SLOTCTL, reg);
744 
745 	/* clear any interrupt status bits */
746 	reg = pciehpc_reg_get16(ctrl_p,
747 	    bus_p->bus_pcie_off + PCIE_SLOTSTS);
748 	pciehpc_reg_put16(ctrl_p,
749 	    bus_p->bus_pcie_off + PCIE_SLOTSTS, reg);
750 
751 	return (DDI_SUCCESS);
752 }
753 
754 /*
755  * Uninitialize HPC hardware, uninstall interrupt handler, etc.
756  *
757  * (Note: It is called only from pciehpc_uninit().)
758  */
759 static int
760 pciehpc_hpc_uninit(pcie_hp_ctrl_t *ctrl_p)
761 {
762 	/* disable interrupts */
763 	(void) pciehpc_disable_intr(ctrl_p);
764 
765 	return (DDI_SUCCESS);
766 }
767 
768 /*
769  * Setup slot information for use with DDI HP framework.
770  */
771 static int
772 pciehpc_slotinfo_init(pcie_hp_ctrl_t *ctrl_p)
773 {
774 	uint32_t	slot_capabilities, link_capabilities;
775 	pcie_hp_slot_t	*slot_p = ctrl_p->hc_slots[0];
776 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
777 
778 	mutex_enter(&ctrl_p->hc_mutex);
779 	/*
780 	 * setup DDI HP framework slot information structure
781 	 */
782 	slot_p->hs_device_num = 0;
783 
784 	slot_p->hs_info.cn_type = DDI_HP_CN_TYPE_PCIE;
785 	slot_p->hs_info.cn_type_str = (ctrl_p->hc_regops.get == NULL) ?
786 	    PCIE_NATIVE_HP_TYPE : PCIE_PROP_HP_TYPE;
787 	slot_p->hs_info.cn_child = NULL;
788 
789 	slot_p->hs_minor =
790 	    PCI_MINOR_NUM(ddi_get_instance(ctrl_p->hc_dip),
791 	    slot_p->hs_device_num);
792 	slot_p->hs_condition = AP_COND_UNKNOWN;
793 
794 	/* read Slot Capabilities Register */
795 	slot_capabilities = pciehpc_reg_get32(ctrl_p,
796 	    bus_p->bus_pcie_off + PCIE_SLOTCAP);
797 
798 	/* set slot-name/slot-number info */
799 	pciehpc_set_slot_name(ctrl_p);
800 
801 	/* check if Attn Button present */
802 	ctrl_p->hc_has_attn = (slot_capabilities & PCIE_SLOTCAP_ATTN_BUTTON) ?
803 	    B_TRUE : B_FALSE;
804 
805 	/* check if Manual Retention Latch sensor present */
806 	ctrl_p->hc_has_mrl = (slot_capabilities & PCIE_SLOTCAP_MRL_SENSOR) ?
807 	    B_TRUE : B_FALSE;
808 
809 	/*
810 	 * PCI-E version 1.1 defines EMI Lock Present bit
811 	 * in Slot Capabilities register. Check for it.
812 	 */
813 	ctrl_p->hc_has_emi_lock = (slot_capabilities &
814 	    PCIE_SLOTCAP_EMI_LOCK_PRESENT) ? B_TRUE : B_FALSE;
815 
816 	link_capabilities = pciehpc_reg_get32(ctrl_p,
817 	    bus_p->bus_pcie_off + PCIE_LINKCAP);
818 	ctrl_p->hc_dll_active_rep = (link_capabilities &
819 	    PCIE_LINKCAP_DLL_ACTIVE_REP_CAPABLE) ? B_TRUE : B_FALSE;
820 	if (ctrl_p->hc_dll_active_rep)
821 		cv_init(&slot_p->hs_dll_active_cv, NULL, CV_DRIVER, NULL);
822 
823 	/* setup thread for handling ATTN button events */
824 	if (ctrl_p->hc_has_attn) {
825 		PCIE_DBG("pciehpc_slotinfo_init: setting up ATTN button event "
826 		    "handler thread for slot %d\n", slot_p->hs_phy_slot_num);
827 
828 		cv_init(&slot_p->hs_attn_btn_cv, NULL, CV_DRIVER, NULL);
829 		slot_p->hs_attn_btn_pending = B_FALSE;
830 		slot_p->hs_attn_btn_threadp = thread_create(NULL, 0,
831 		    pciehpc_attn_btn_handler,
832 		    (void *)ctrl_p, 0, &p0, TS_RUN, minclsyspri);
833 		slot_p->hs_attn_btn_thread_exit = B_FALSE;
834 	}
835 
836 	/* get current slot state from the hw */
837 	slot_p->hs_info.cn_state = DDI_HP_CN_STATE_EMPTY;
838 	pciehpc_get_slot_state(slot_p);
839 	if (slot_p->hs_info.cn_state >= DDI_HP_CN_STATE_ENABLED)
840 		slot_p->hs_condition = AP_COND_OK;
841 
842 	mutex_exit(&ctrl_p->hc_mutex);
843 
844 	return (DDI_SUCCESS);
845 }
846 
847 /*ARGSUSED*/
848 static int
849 pciehpc_slotinfo_uninit(pcie_hp_ctrl_t *ctrl_p)
850 {
851 	pcie_hp_slot_t *slot_p = ctrl_p->hc_slots[0];
852 
853 	if (slot_p->hs_attn_btn_threadp != NULL) {
854 		mutex_enter(&ctrl_p->hc_mutex);
855 		slot_p->hs_attn_btn_thread_exit = B_TRUE;
856 		cv_signal(&slot_p->hs_attn_btn_cv);
857 		PCIE_DBG("pciehpc_slotinfo_uninit: "
858 		    "waiting for ATTN thread exit\n");
859 		cv_wait(&slot_p->hs_attn_btn_cv, &ctrl_p->hc_mutex);
860 		PCIE_DBG("pciehpc_slotinfo_uninit: ATTN thread exit\n");
861 		cv_destroy(&slot_p->hs_attn_btn_cv);
862 		slot_p->hs_attn_btn_threadp = NULL;
863 		mutex_exit(&ctrl_p->hc_mutex);
864 	}
865 
866 	if (ctrl_p->hc_dll_active_rep)
867 		cv_destroy(&slot_p->hs_dll_active_cv);
868 	if (slot_p->hs_info.cn_name)
869 		kmem_free(slot_p->hs_info.cn_name,
870 		    strlen(slot_p->hs_info.cn_name) + 1);
871 
872 	return (DDI_SUCCESS);
873 }
874 
875 /*
876  * Enable hot plug interrupts.
877  * Note: this is only for Native hot plug mode.
878  */
879 static int
880 pciehpc_enable_intr(pcie_hp_ctrl_t *ctrl_p)
881 {
882 	pcie_hp_slot_t	*slot_p = ctrl_p->hc_slots[0];
883 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
884 	uint16_t	reg;
885 
886 	/* clear any interrupt status bits */
887 	reg = pciehpc_reg_get16(ctrl_p,
888 	    bus_p->bus_pcie_off + PCIE_SLOTSTS);
889 	pciehpc_reg_put16(ctrl_p,
890 	    bus_p->bus_pcie_off + PCIE_SLOTSTS, reg);
891 
892 	/* read the Slot Control Register */
893 	reg = pciehpc_reg_get16(ctrl_p,
894 	    bus_p->bus_pcie_off + PCIE_SLOTCTL);
895 
896 	/*
897 	 * enable interrupts: power fault detection interrupt is enabled
898 	 * only when the slot is powered ON
899 	 */
900 	if (slot_p->hs_info.cn_state >= DDI_HP_CN_STATE_POWERED)
901 		pciehpc_reg_put16(ctrl_p, bus_p->bus_pcie_off +
902 		    PCIE_SLOTCTL, reg | PCIE_SLOTCTL_INTR_MASK);
903 	else
904 		pciehpc_reg_put16(ctrl_p, bus_p->bus_pcie_off +
905 		    PCIE_SLOTCTL, reg | (PCIE_SLOTCTL_INTR_MASK &
906 		    ~PCIE_SLOTCTL_PWR_FAULT_EN));
907 
908 	return (DDI_SUCCESS);
909 }
910 
911 /*
912  * Disable hot plug interrupts.
913  * Note: this is only for Native hot plug mode.
914  */
915 static int
916 pciehpc_disable_intr(pcie_hp_ctrl_t *ctrl_p)
917 {
918 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
919 	uint16_t	reg;
920 
921 	/* read the Slot Control Register */
922 	reg = pciehpc_reg_get16(ctrl_p,
923 	    bus_p->bus_pcie_off + PCIE_SLOTCTL);
924 
925 	/* disable all interrupts */
926 	reg &= ~(PCIE_SLOTCTL_INTR_MASK);
927 	pciehpc_reg_put16(ctrl_p, bus_p->bus_pcie_off + PCIE_SLOTCTL, reg);
928 
929 	/* clear any interrupt status bits */
930 	reg = pciehpc_reg_get16(ctrl_p,
931 	    bus_p->bus_pcie_off + PCIE_SLOTSTS);
932 	pciehpc_reg_put16(ctrl_p,
933 	    bus_p->bus_pcie_off + PCIE_SLOTSTS, reg);
934 
935 	return (DDI_SUCCESS);
936 }
937 
938 /*
939  * Allocate a new hotplug controller and slot structures for HPC
940  * associated with this dip.
941  */
942 static pcie_hp_ctrl_t *
943 pciehpc_create_controller(dev_info_t *dip)
944 {
945 	pcie_hp_ctrl_t	*ctrl_p;
946 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(dip);
947 
948 	ctrl_p = kmem_zalloc(sizeof (pcie_hp_ctrl_t), KM_SLEEP);
949 	ctrl_p->hc_dip = dip;
950 
951 	/* Allocate a new slot structure. */
952 	ctrl_p->hc_slots[0] = kmem_zalloc(sizeof (pcie_hp_slot_t), KM_SLEEP);
953 	ctrl_p->hc_slots[0]->hs_num = 0;
954 	ctrl_p->hc_slots[0]->hs_ctrl = ctrl_p;
955 
956 	/* Initialize the interrupt mutex */
957 	mutex_init(&ctrl_p->hc_mutex, NULL, MUTEX_DRIVER,
958 	    (void *)PCIE_INTR_PRI);
959 
960 	/* Initialize synchronization conditional variable */
961 	cv_init(&ctrl_p->hc_cmd_comp_cv, NULL, CV_DRIVER, NULL);
962 	ctrl_p->hc_cmd_pending = B_FALSE;
963 
964 	bus_p->bus_hp_curr_mode = PCIE_NATIVE_HP_MODE;
965 	PCIE_SET_HP_CTRL(dip, ctrl_p);
966 
967 	return (ctrl_p);
968 }
969 
970 /*
971  * Remove the HPC controller and slot structures
972  */
973 static void
974 pciehpc_destroy_controller(dev_info_t *dip)
975 {
976 	pcie_hp_ctrl_t	*ctrl_p;
977 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(dip);
978 
979 	/* get the soft state structure for this dip */
980 	if ((ctrl_p = PCIE_GET_HP_CTRL(dip)) == NULL)
981 		return;
982 
983 	PCIE_SET_HP_CTRL(dip, NULL);
984 	bus_p->bus_hp_curr_mode = PCIE_NONE_HP_MODE;
985 
986 	mutex_destroy(&ctrl_p->hc_mutex);
987 	cv_destroy(&ctrl_p->hc_cmd_comp_cv);
988 	kmem_free(ctrl_p->hc_slots[0], sizeof (pcie_hp_slot_t));
989 	kmem_free(ctrl_p, sizeof (pcie_hp_ctrl_t));
990 }
991 
992 /*
993  * Register the PCI-E hot plug slot with DDI HP framework.
994  */
995 static int
996 pciehpc_register_slot(pcie_hp_ctrl_t *ctrl_p)
997 {
998 	pcie_hp_slot_t	*slot_p = ctrl_p->hc_slots[0];
999 	dev_info_t	*dip = ctrl_p->hc_dip;
1000 
1001 	/* register the slot with DDI HP framework */
1002 	if (ndi_hp_register(dip, &slot_p->hs_info) != NDI_SUCCESS) {
1003 		PCIE_DBG("pciehpc_register_slot() failed to register slot %d\n",
1004 		    slot_p->hs_phy_slot_num);
1005 		return (DDI_FAILURE);
1006 	}
1007 
1008 	pcie_hp_create_occupant_props(dip, makedevice(ddi_driver_major(dip),
1009 	    slot_p->hs_minor), slot_p->hs_device_num);
1010 
1011 	PCIE_DBG("pciehpc_register_slot(): registered slot %d\n",
1012 	    slot_p->hs_phy_slot_num);
1013 
1014 	return (DDI_SUCCESS);
1015 }
1016 
1017 /*
1018  * Unregister the PCI-E hot plug slot from DDI HP framework.
1019  */
1020 static int
1021 pciehpc_unregister_slot(pcie_hp_ctrl_t *ctrl_p)
1022 {
1023 	pcie_hp_slot_t *slot_p = ctrl_p->hc_slots[0];
1024 	dev_info_t	*dip = ctrl_p->hc_dip;
1025 
1026 	pcie_hp_delete_occupant_props(dip, makedevice(ddi_driver_major(dip),
1027 	    slot_p->hs_minor));
1028 
1029 	/* unregister the slot with DDI HP framework */
1030 	if (ndi_hp_unregister(dip, slot_p->hs_info.cn_name) != NDI_SUCCESS) {
1031 		PCIE_DBG("pciehpc_unregister_slot() "
1032 		    "failed to unregister slot %d\n", slot_p->hs_phy_slot_num);
1033 		return (DDI_FAILURE);
1034 	}
1035 
1036 	PCIE_DBG("pciehpc_unregister_slot(): unregistered slot %d\n",
1037 	    slot_p->hs_phy_slot_num);
1038 
1039 	return (DDI_SUCCESS);
1040 }
1041 
1042 /*
1043  * pciehpc_slot_poweron()
1044  *
1045  * Poweron/Enable the slot.
1046  *
1047  * Note: This function is called by DDI HP framework at kernel context only
1048  */
1049 /*ARGSUSED*/
1050 static int
1051 pciehpc_slot_poweron(pcie_hp_slot_t *slot_p, ddi_hp_cn_state_t *result)
1052 {
1053 	pcie_hp_ctrl_t	*ctrl_p = slot_p->hs_ctrl;
1054 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
1055 	uint16_t	status, control;
1056 
1057 	ASSERT(MUTEX_HELD(&ctrl_p->hc_mutex));
1058 
1059 	/* get the current state of the slot */
1060 	pciehpc_get_slot_state(slot_p);
1061 
1062 	/* check if the slot is already in the 'enabled' state */
1063 	if (slot_p->hs_info.cn_state >= DDI_HP_CN_STATE_POWERED) {
1064 		/* slot is already in the 'enabled' state */
1065 		PCIE_DBG("pciehpc_slot_poweron() slot %d already enabled\n",
1066 		    slot_p->hs_phy_slot_num);
1067 
1068 		*result = slot_p->hs_info.cn_state;
1069 		return (DDI_SUCCESS);
1070 	}
1071 
1072 	/* read the Slot Status Register */
1073 	status =  pciehpc_reg_get16(ctrl_p,
1074 	    bus_p->bus_pcie_off + PCIE_SLOTSTS);
1075 
1076 	/* make sure the MRL switch is closed if present */
1077 	if ((ctrl_p->hc_has_mrl) && (status & PCIE_SLOTSTS_MRL_SENSOR_OPEN)) {
1078 		/* MRL switch is open */
1079 		cmn_err(CE_WARN, "MRL switch is open on slot %d\n",
1080 		    slot_p->hs_phy_slot_num);
1081 		goto cleanup;
1082 	}
1083 
1084 	/* make sure the slot has a device present */
1085 	if (!(status & PCIE_SLOTSTS_PRESENCE_DETECTED)) {
1086 		/* slot is empty */
1087 		PCIE_DBG("slot %d is empty\n", slot_p->hs_phy_slot_num);
1088 		goto cleanup;
1089 	}
1090 
1091 	/* get the current state of Slot Control Register */
1092 	control =  pciehpc_reg_get16(ctrl_p,
1093 	    bus_p->bus_pcie_off + PCIE_SLOTCTL);
1094 
1095 	/*
1096 	 * Enable power to the slot involves:
1097 	 *	1. Set power LED to blink and ATTN led to OFF.
1098 	 *	2. Set power control ON in Slot Control Reigster and
1099 	 *	   wait for Command Completed Interrupt or 1 sec timeout.
1100 	 *	3. If Data Link Layer State Changed events are supported
1101 	 *	   then wait for the event to indicate Data Layer Link
1102 	 *	   is active. The time out value for this event is 1 second.
1103 	 *	   This is specified in PCI-E version 1.1.
1104 	 *	4. Set power LED to be ON.
1105 	 */
1106 
1107 	/* 1. set power LED to blink & ATTN led to OFF */
1108 	pciehpc_set_led_state(ctrl_p, PCIE_HP_POWER_LED, PCIE_HP_LED_BLINK);
1109 	pciehpc_set_led_state(ctrl_p, PCIE_HP_ATTN_LED, PCIE_HP_LED_OFF);
1110 
1111 	/* 2. set power control to ON */
1112 	control =  pciehpc_reg_get16(ctrl_p,
1113 	    bus_p->bus_pcie_off + PCIE_SLOTCTL);
1114 	control &= ~PCIE_SLOTCTL_PWR_CONTROL;
1115 	pciehpc_issue_hpc_command(ctrl_p, control);
1116 
1117 	/* 3. wait for DLL State Change event, if it's supported */
1118 	if (ctrl_p->hc_dll_active_rep) {
1119 		status =  pciehpc_reg_get16(ctrl_p,
1120 		    bus_p->bus_pcie_off + PCIE_LINKSTS);
1121 
1122 		if (!(status & PCIE_LINKSTS_DLL_LINK_ACTIVE)) {
1123 			/* wait 1 sec for the DLL State Changed event */
1124 			(void) cv_timedwait(&slot_p->hs_dll_active_cv,
1125 			    &ctrl_p->hc_mutex,
1126 			    ddi_get_lbolt() +
1127 			    SEC_TO_TICK(PCIE_HP_DLL_STATE_CHANGE_TIMEOUT));
1128 
1129 			/* check Link status */
1130 			status =  pciehpc_reg_get16(ctrl_p,
1131 			    bus_p->bus_pcie_off +
1132 			    PCIE_LINKSTS);
1133 			if (!(status & PCIE_LINKSTS_DLL_LINK_ACTIVE))
1134 				goto cleanup2;
1135 		}
1136 	}
1137 
1138 	/* wait 1 sec for link to come up */
1139 	delay(drv_usectohz(1000000));
1140 
1141 	/* check power is really turned ON */
1142 	control =  pciehpc_reg_get16(ctrl_p,
1143 	    bus_p->bus_pcie_off + PCIE_SLOTCTL);
1144 
1145 	if (control & PCIE_SLOTCTL_PWR_CONTROL) {
1146 		PCIE_DBG("slot %d fails to turn on power on connect\n",
1147 		    slot_p->hs_phy_slot_num);
1148 
1149 		goto cleanup1;
1150 	}
1151 
1152 	/* clear power fault status */
1153 	status =  pciehpc_reg_get16(ctrl_p,
1154 	    bus_p->bus_pcie_off + PCIE_SLOTSTS);
1155 	status |= PCIE_SLOTSTS_PWR_FAULT_DETECTED;
1156 	pciehpc_reg_put16(ctrl_p, bus_p->bus_pcie_off + PCIE_SLOTSTS,
1157 	    status);
1158 
1159 	/* enable power fault detection interrupt */
1160 	control |= PCIE_SLOTCTL_PWR_FAULT_EN;
1161 	pciehpc_issue_hpc_command(ctrl_p, control);
1162 
1163 	/* 4. Set power LED to be ON */
1164 	pciehpc_set_led_state(ctrl_p, PCIE_HP_POWER_LED, PCIE_HP_LED_ON);
1165 
1166 	/* if EMI is present, turn it ON */
1167 	if (ctrl_p->hc_has_emi_lock) {
1168 		status =  pciehpc_reg_get16(ctrl_p,
1169 		    bus_p->bus_pcie_off + PCIE_SLOTSTS);
1170 
1171 		if (!(status & PCIE_SLOTSTS_EMI_LOCK_SET)) {
1172 			control =  pciehpc_reg_get16(ctrl_p,
1173 			    bus_p->bus_pcie_off + PCIE_SLOTCTL);
1174 			control |= PCIE_SLOTCTL_EMI_LOCK_CONTROL;
1175 			pciehpc_issue_hpc_command(ctrl_p, control);
1176 
1177 			/* wait 1 sec after toggling the state of EMI lock */
1178 			delay(drv_usectohz(1000000));
1179 		}
1180 	}
1181 
1182 	*result = slot_p->hs_info.cn_state =
1183 	    DDI_HP_CN_STATE_POWERED;
1184 
1185 	return (DDI_SUCCESS);
1186 
1187 cleanup2:
1188 	control =  pciehpc_reg_get16(ctrl_p,
1189 	    bus_p->bus_pcie_off + PCIE_SLOTCTL);
1190 
1191 	/* if power is ON, set power control to OFF */
1192 	if (!(control & PCIE_SLOTCTL_PWR_CONTROL)) {
1193 		control |= PCIE_SLOTCTL_PWR_CONTROL;
1194 		pciehpc_issue_hpc_command(ctrl_p, control);
1195 	}
1196 
1197 cleanup1:
1198 	/* set power led to OFF */
1199 	pciehpc_set_led_state(ctrl_p, PCIE_HP_POWER_LED, PCIE_HP_LED_OFF);
1200 
1201 cleanup:
1202 	return (DDI_FAILURE);
1203 }
1204 
1205 /*ARGSUSED*/
1206 static int
1207 pciehpc_slot_poweroff(pcie_hp_slot_t *slot_p, ddi_hp_cn_state_t *result)
1208 {
1209 	pcie_hp_ctrl_t	*ctrl_p = slot_p->hs_ctrl;
1210 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
1211 	uint16_t	status, control;
1212 
1213 	ASSERT(MUTEX_HELD(&ctrl_p->hc_mutex));
1214 
1215 	/* get the current state of the slot */
1216 	pciehpc_get_slot_state(slot_p);
1217 
1218 	/* check if the slot is not in the "enabled' state */
1219 	if (slot_p->hs_info.cn_state < DDI_HP_CN_STATE_POWERED) {
1220 		/* slot is in the 'disabled' state */
1221 		PCIE_DBG("pciehpc_slot_poweroff(): "
1222 		    "slot %d already disabled\n", slot_p->hs_phy_slot_num);
1223 		ASSERT(slot_p->hs_power_led_state == PCIE_HP_LED_OFF);
1224 
1225 		*result = slot_p->hs_info.cn_state;
1226 		return (DDI_SUCCESS);
1227 	}
1228 
1229 	/* read the Slot Status Register */
1230 	status =  pciehpc_reg_get16(ctrl_p,
1231 	    bus_p->bus_pcie_off + PCIE_SLOTSTS);
1232 
1233 	/* make sure the slot has a device present */
1234 	if (!(status & PCIE_SLOTSTS_PRESENCE_DETECTED)) {
1235 		/* slot is empty */
1236 		PCIE_DBG("pciehpc_slot_poweroff(): slot %d is empty\n",
1237 		    slot_p->hs_phy_slot_num);
1238 		goto cleanup;
1239 	}
1240 
1241 	/*
1242 	 * Disable power to the slot involves:
1243 	 *	1. Set power LED to blink.
1244 	 *	2. Set power control OFF in Slot Control Reigster and
1245 	 *	   wait for Command Completed Interrupt or 1 sec timeout.
1246 	 *	3. Set POWER led and ATTN led to be OFF.
1247 	 */
1248 
1249 	/* 1. set power LED to blink */
1250 	pciehpc_set_led_state(ctrl_p, PCIE_HP_POWER_LED, PCIE_HP_LED_BLINK);
1251 
1252 	/* disable power fault detection interrupt */
1253 	control = pciehpc_reg_get16(ctrl_p,
1254 	    bus_p->bus_pcie_off + PCIE_SLOTCTL);
1255 	control &= ~PCIE_SLOTCTL_PWR_FAULT_EN;
1256 	pciehpc_issue_hpc_command(ctrl_p, control);
1257 
1258 	/* 2. set power control to OFF */
1259 	control =  pciehpc_reg_get16(ctrl_p,
1260 	    bus_p->bus_pcie_off + PCIE_SLOTCTL);
1261 	control |= PCIE_SLOTCTL_PWR_CONTROL;
1262 	pciehpc_issue_hpc_command(ctrl_p, control);
1263 
1264 #ifdef DEBUG
1265 	/* check for power control bit to be OFF */
1266 	control =  pciehpc_reg_get16(ctrl_p,
1267 	    bus_p->bus_pcie_off + PCIE_SLOTCTL);
1268 	ASSERT(control & PCIE_SLOTCTL_PWR_CONTROL);
1269 #endif
1270 
1271 	/* 3. Set power LED to be OFF */
1272 	pciehpc_set_led_state(ctrl_p, PCIE_HP_POWER_LED, PCIE_HP_LED_OFF);
1273 	pciehpc_set_led_state(ctrl_p, PCIE_HP_ATTN_LED, PCIE_HP_LED_OFF);
1274 
1275 	/* if EMI is present, turn it OFF */
1276 	if (ctrl_p->hc_has_emi_lock) {
1277 		status =  pciehpc_reg_get16(ctrl_p,
1278 		    bus_p->bus_pcie_off + PCIE_SLOTSTS);
1279 
1280 		if (status & PCIE_SLOTSTS_EMI_LOCK_SET) {
1281 			control =  pciehpc_reg_get16(ctrl_p,
1282 			    bus_p->bus_pcie_off + PCIE_SLOTCTL);
1283 			control |= PCIE_SLOTCTL_EMI_LOCK_CONTROL;
1284 			pciehpc_issue_hpc_command(ctrl_p, control);
1285 
1286 			/* wait 1 sec after toggling the state of EMI lock */
1287 			delay(drv_usectohz(1000000));
1288 		}
1289 	}
1290 
1291 	/* get the current state of the slot */
1292 	pciehpc_get_slot_state(slot_p);
1293 
1294 	*result = slot_p->hs_info.cn_state;
1295 
1296 	return (DDI_SUCCESS);
1297 
1298 cleanup:
1299 	return (DDI_FAILURE);
1300 }
1301 
1302 /*
1303  * pciehpc_slot_probe()
1304  *
1305  * Probe the slot.
1306  *
1307  * Note: This function is called by DDI HP framework at kernel context only
1308  */
1309 /*ARGSUSED*/
1310 static int
1311 pciehpc_slot_probe(pcie_hp_slot_t *slot_p)
1312 {
1313 	pcie_hp_ctrl_t	*ctrl_p = slot_p->hs_ctrl;
1314 	int		ret = DDI_SUCCESS;
1315 
1316 	mutex_enter(&ctrl_p->hc_mutex);
1317 
1318 	/* get the current state of the slot */
1319 	pciehpc_get_slot_state(slot_p);
1320 
1321 	/*
1322 	 * Probe a given PCIe Hotplug Connection (CN).
1323 	 */
1324 	PCIE_DISABLE_ERRORS(ctrl_p->hc_dip);
1325 	ret = pcie_hp_probe(slot_p);
1326 
1327 	if (ret != DDI_SUCCESS) {
1328 		PCIE_DBG("pciehpc_slot_probe() failed\n");
1329 
1330 		/* turn the ATTN led ON for configure failure */
1331 		pciehpc_set_led_state(ctrl_p, PCIE_HP_ATTN_LED, PCIE_HP_LED_ON);
1332 
1333 		/* if power to the slot is still on then set Power led to ON */
1334 		if (slot_p->hs_info.cn_state >= DDI_HP_CN_STATE_POWERED)
1335 			pciehpc_set_led_state(ctrl_p, PCIE_HP_POWER_LED,
1336 			    PCIE_HP_LED_ON);
1337 
1338 		mutex_exit(&ctrl_p->hc_mutex);
1339 		return (DDI_FAILURE);
1340 	}
1341 
1342 	PCIE_ENABLE_ERRORS(ctrl_p->hc_dip);
1343 
1344 	/* get the current state of the slot */
1345 	pciehpc_get_slot_state(slot_p);
1346 
1347 	mutex_exit(&ctrl_p->hc_mutex);
1348 	return (DDI_SUCCESS);
1349 }
1350 
1351 /*
1352  * pciehpc_slot_unprobe()
1353  *
1354  * Unprobe the slot.
1355  *
1356  * Note: This function is called by DDI HP framework at kernel context only
1357  */
1358 /*ARGSUSED*/
1359 static int
1360 pciehpc_slot_unprobe(pcie_hp_slot_t *slot_p)
1361 {
1362 	pcie_hp_ctrl_t	*ctrl_p = slot_p->hs_ctrl;
1363 	int		ret;
1364 
1365 	mutex_enter(&ctrl_p->hc_mutex);
1366 
1367 	/* get the current state of the slot */
1368 	pciehpc_get_slot_state(slot_p);
1369 
1370 	/*
1371 	 * Unprobe a given PCIe Hotplug Connection (CN).
1372 	 */
1373 	PCIE_DISABLE_ERRORS(ctrl_p->hc_dip);
1374 	ret = pcie_hp_unprobe(slot_p);
1375 
1376 	if (ret != DDI_SUCCESS) {
1377 		PCIE_DBG("pciehpc_slot_unprobe() failed\n");
1378 
1379 		/* if power to the slot is still on then set Power led to ON */
1380 		if (slot_p->hs_info.cn_state >= DDI_HP_CN_STATE_POWERED)
1381 			pciehpc_set_led_state(ctrl_p, PCIE_HP_POWER_LED,
1382 			    PCIE_HP_LED_ON);
1383 
1384 		PCIE_ENABLE_ERRORS(ctrl_p->hc_dip);
1385 
1386 		mutex_exit(&ctrl_p->hc_mutex);
1387 		return (DDI_FAILURE);
1388 	}
1389 
1390 	/* get the current state of the slot */
1391 	pciehpc_get_slot_state(slot_p);
1392 
1393 	mutex_exit(&ctrl_p->hc_mutex);
1394 	return (DDI_SUCCESS);
1395 }
1396 
1397 static int
1398 pciehpc_upgrade_slot_state(pcie_hp_slot_t *slot_p,
1399     ddi_hp_cn_state_t target_state)
1400 {
1401 	ddi_hp_cn_state_t curr_state;
1402 	int rv = DDI_SUCCESS;
1403 
1404 	if (target_state > DDI_HP_CN_STATE_ENABLED) {
1405 		return (DDI_EINVAL);
1406 	}
1407 
1408 	curr_state = slot_p->hs_info.cn_state;
1409 	while ((curr_state < target_state) && (rv == DDI_SUCCESS)) {
1410 
1411 		switch (curr_state) {
1412 		case DDI_HP_CN_STATE_EMPTY:
1413 			/*
1414 			 * From EMPTY to PRESENT, just check the hardware
1415 			 * slot state.
1416 			 */
1417 			pciehpc_get_slot_state(slot_p);
1418 			curr_state = slot_p->hs_info.cn_state;
1419 			if (curr_state < DDI_HP_CN_STATE_PRESENT)
1420 				rv = DDI_FAILURE;
1421 			break;
1422 		case DDI_HP_CN_STATE_PRESENT:
1423 			rv = (slot_p->hs_ctrl->hc_ops.poweron_hpc_slot)(slot_p,
1424 			    &curr_state);
1425 
1426 			break;
1427 		case DDI_HP_CN_STATE_POWERED:
1428 			curr_state = slot_p->hs_info.cn_state =
1429 			    DDI_HP_CN_STATE_ENABLED;
1430 			break;
1431 		default:
1432 			/* should never reach here */
1433 			ASSERT("unknown devinfo state");
1434 		}
1435 	}
1436 
1437 	return (rv);
1438 }
1439 
1440 static int
1441 pciehpc_downgrade_slot_state(pcie_hp_slot_t *slot_p,
1442     ddi_hp_cn_state_t target_state)
1443 {
1444 	ddi_hp_cn_state_t curr_state;
1445 	int rv = DDI_SUCCESS;
1446 
1447 
1448 	curr_state = slot_p->hs_info.cn_state;
1449 	while ((curr_state > target_state) && (rv == DDI_SUCCESS)) {
1450 
1451 		switch (curr_state) {
1452 		case DDI_HP_CN_STATE_PRESENT:
1453 			/*
1454 			 * From PRESENT to EMPTY, just check hardware slot
1455 			 * state.
1456 			 */
1457 			pciehpc_get_slot_state(slot_p);
1458 			curr_state = slot_p->hs_info.cn_state;
1459 			if (curr_state >= DDI_HP_CN_STATE_PRESENT)
1460 				rv = DDI_FAILURE;
1461 			break;
1462 		case DDI_HP_CN_STATE_POWERED:
1463 			rv = (slot_p->hs_ctrl->hc_ops.poweroff_hpc_slot)(
1464 			    slot_p, &curr_state);
1465 
1466 			break;
1467 		case DDI_HP_CN_STATE_ENABLED:
1468 			curr_state = slot_p->hs_info.cn_state =
1469 			    DDI_HP_CN_STATE_POWERED;
1470 
1471 			break;
1472 		default:
1473 			/* should never reach here */
1474 			ASSERT("unknown devinfo state");
1475 		}
1476 	}
1477 
1478 	return (rv);
1479 }
1480 
1481 /* Change slot state to a target state */
1482 static int
1483 pciehpc_change_slot_state(pcie_hp_slot_t *slot_p,
1484     ddi_hp_cn_state_t target_state)
1485 {
1486 	ddi_hp_cn_state_t curr_state;
1487 	int rv;
1488 
1489 	pciehpc_get_slot_state(slot_p);
1490 	curr_state = slot_p->hs_info.cn_state;
1491 
1492 	if (curr_state == target_state) {
1493 		return (DDI_SUCCESS);
1494 	}
1495 	if (curr_state < target_state) {
1496 
1497 		rv = pciehpc_upgrade_slot_state(slot_p, target_state);
1498 	} else {
1499 		rv = pciehpc_downgrade_slot_state(slot_p, target_state);
1500 	}
1501 
1502 	return (rv);
1503 }
1504 
1505 int
1506 pciehpc_slot_get_property(pcie_hp_slot_t *slot_p, ddi_hp_property_t *arg,
1507     ddi_hp_property_t *rval)
1508 {
1509 	ddi_hp_property_t request, result;
1510 #ifdef _SYSCALL32_IMPL
1511 	ddi_hp_property32_t request32, result32;
1512 #endif
1513 	pcie_hp_ctrl_t	*ctrl_p = slot_p->hs_ctrl;
1514 	nvlist_t	*prop_list;
1515 	nvlist_t	*prop_rlist; /* nvlist for return values */
1516 	nvpair_t	*prop_pair;
1517 	char		*name, *value;
1518 	int		ret = DDI_SUCCESS;
1519 	int		i, n;
1520 	boolean_t	get_all_prop = B_FALSE;
1521 
1522 	if (get_udatamodel() == DATAMODEL_NATIVE) {
1523 		if (copyin(arg, &request, sizeof (ddi_hp_property_t)) ||
1524 		    copyin(rval, &result, sizeof (ddi_hp_property_t)))
1525 			return (DDI_FAILURE);
1526 	}
1527 #ifdef _SYSCALL32_IMPL
1528 	else {
1529 		bzero(&request, sizeof (request));
1530 		bzero(&result, sizeof (result));
1531 		if (copyin(arg, &request32, sizeof (ddi_hp_property32_t)) ||
1532 		    copyin(rval, &result32, sizeof (ddi_hp_property32_t)))
1533 			return (DDI_FAILURE);
1534 		request.nvlist_buf = (char *)(uintptr_t)request32.nvlist_buf;
1535 		request.buf_size = request32.buf_size;
1536 		result.nvlist_buf = (char *)(uintptr_t)result32.nvlist_buf;
1537 		result.buf_size = result32.buf_size;
1538 	}
1539 #endif
1540 
1541 	if ((ret = pcie_copyin_nvlist(request.nvlist_buf, request.buf_size,
1542 	    &prop_list)) != DDI_SUCCESS)
1543 		return (ret);
1544 
1545 	if (nvlist_alloc(&prop_rlist, NV_UNIQUE_NAME, 0)) {
1546 		ret = DDI_ENOMEM;
1547 		goto get_prop_cleanup;
1548 	}
1549 
1550 	/* check whether the requested property is "all" or "help" */
1551 	prop_pair = nvlist_next_nvpair(prop_list, NULL);
1552 	if (prop_pair && !nvlist_next_nvpair(prop_list, prop_pair)) {
1553 		name = nvpair_name(prop_pair);
1554 		n = sizeof (pciehpc_props) / sizeof (pciehpc_prop_t);
1555 
1556 		if (strcmp(name, PCIEHPC_PROP_ALL) == 0) {
1557 			(void) nvlist_remove_all(prop_list, PCIEHPC_PROP_ALL);
1558 
1559 			/*
1560 			 * Add all properties into the request list, so that we
1561 			 * will get the values in the following for loop.
1562 			 */
1563 			for (i = 0; i < n; i++) {
1564 				if (nvlist_add_string(prop_list,
1565 				    pciehpc_props[i].prop_name, "") != 0) {
1566 					ret = DDI_FAILURE;
1567 					goto get_prop_cleanup1;
1568 				}
1569 			}
1570 			get_all_prop = B_TRUE;
1571 		} else if (strcmp(name, PCIEHPC_PROP_HELP) == 0) {
1572 			/*
1573 			 * Empty the request list, and add help strings into the
1574 			 * return list. We will pass the following for loop.
1575 			 */
1576 			(void) nvlist_remove_all(prop_list, PCIEHPC_PROP_HELP);
1577 
1578 			for (i = 0; i < n; i++) {
1579 				if (nvlist_add_string(prop_rlist,
1580 				    pciehpc_props[i].prop_name,
1581 				    pciehpc_props[i].prop_value) != 0) {
1582 					ret = DDI_FAILURE;
1583 					goto get_prop_cleanup1;
1584 				}
1585 			}
1586 		}
1587 	}
1588 
1589 	mutex_enter(&ctrl_p->hc_mutex);
1590 
1591 	/* get the current slot state */
1592 	pciehpc_get_slot_state(slot_p);
1593 
1594 	/* for each requested property, get the value and add it to nvlist */
1595 	prop_pair = NULL;
1596 	while (prop_pair = nvlist_next_nvpair(prop_list, prop_pair)) {
1597 		name = nvpair_name(prop_pair);
1598 
1599 		if (strcmp(name, PCIEHPC_PROP_LED_FAULT) == 0) {
1600 			value = pcie_led_state_text(
1601 			    slot_p->hs_fault_led_state);
1602 		} else if (strcmp(name, PCIEHPC_PROP_LED_POWER) == 0) {
1603 			value = pcie_led_state_text(
1604 			    slot_p->hs_power_led_state);
1605 		} else if (strcmp(name, PCIEHPC_PROP_LED_ATTN) == 0) {
1606 			value = pcie_led_state_text(
1607 			    slot_p->hs_attn_led_state);
1608 		} else if (strcmp(name, PCIEHPC_PROP_LED_ACTIVE) == 0) {
1609 			value = pcie_led_state_text(
1610 			    slot_p->hs_active_led_state);
1611 		} else if (strcmp(name, PCIEHPC_PROP_CARD_TYPE) == 0) {
1612 			ddi_acc_handle_t handle;
1613 			dev_info_t	*cdip;
1614 			uint8_t		prog_class, base_class, sub_class;
1615 			int		i;
1616 
1617 			mutex_exit(&ctrl_p->hc_mutex);
1618 			cdip = pcie_hp_devi_find(
1619 			    ctrl_p->hc_dip, slot_p->hs_device_num, 0);
1620 			mutex_enter(&ctrl_p->hc_mutex);
1621 
1622 			if ((slot_p->hs_info.cn_state
1623 			    != DDI_HP_CN_STATE_ENABLED) || (cdip == NULL)) {
1624 				/*
1625 				 * When getting all properties, just ignore the
1626 				 * one that's not available under certain state.
1627 				 */
1628 				if (get_all_prop)
1629 					continue;
1630 
1631 				ret = DDI_ENOTSUP;
1632 				goto get_prop_cleanup2;
1633 			}
1634 
1635 			if (pci_config_setup(cdip, &handle) != DDI_SUCCESS) {
1636 				ret = DDI_FAILURE;
1637 				goto get_prop_cleanup2;
1638 			}
1639 
1640 			prog_class = pci_config_get8(handle,
1641 			    PCI_CONF_PROGCLASS);
1642 			base_class = pci_config_get8(handle, PCI_CONF_BASCLASS);
1643 			sub_class = pci_config_get8(handle, PCI_CONF_SUBCLASS);
1644 			pci_config_teardown(&handle);
1645 
1646 			for (i = 0; i < class_pci_items; i++) {
1647 				if ((base_class == class_pci[i].base_class) &&
1648 				    (sub_class == class_pci[i].sub_class) &&
1649 				    (prog_class == class_pci[i].prog_class)) {
1650 					value = class_pci[i].short_desc;
1651 					break;
1652 				}
1653 			}
1654 			if (i == class_pci_items)
1655 				value = PCIEHPC_PROP_VALUE_UNKNOWN;
1656 		} else if (strcmp(name, PCIEHPC_PROP_BOARD_TYPE) == 0) {
1657 			if (slot_p->hs_info.cn_state <= DDI_HP_CN_STATE_EMPTY)
1658 				value = PCIEHPC_PROP_VALUE_UNKNOWN;
1659 			else
1660 				value = PCIEHPC_PROP_VALUE_PCIHOTPLUG;
1661 		} else if (strcmp(name, PCIEHPC_PROP_SLOT_CONDITION) == 0) {
1662 			value = pcie_slot_condition_text(slot_p->hs_condition);
1663 		} else {
1664 			/* unsupported property */
1665 			PCIE_DBG("Unsupported property: %s\n", name);
1666 
1667 			ret = DDI_ENOTSUP;
1668 			goto get_prop_cleanup2;
1669 		}
1670 		if (nvlist_add_string(prop_rlist, name, value) != 0) {
1671 			ret = DDI_FAILURE;
1672 			goto get_prop_cleanup2;
1673 		}
1674 	}
1675 
1676 	/* pack nvlist and copyout */
1677 	if ((ret = pcie_copyout_nvlist(prop_rlist, result.nvlist_buf,
1678 	    &result.buf_size)) != DDI_SUCCESS) {
1679 		goto get_prop_cleanup2;
1680 	}
1681 	if (get_udatamodel() == DATAMODEL_NATIVE) {
1682 		if (copyout(&result, rval, sizeof (ddi_hp_property_t)))
1683 			ret = DDI_FAILURE;
1684 	}
1685 #ifdef _SYSCALL32_IMPL
1686 	else {
1687 		if (result.buf_size > UINT32_MAX) {
1688 			ret = DDI_FAILURE;
1689 		} else {
1690 			result32.buf_size = (uint32_t)result.buf_size;
1691 			if (copyout(&result32, rval,
1692 			    sizeof (ddi_hp_property32_t)))
1693 				ret = DDI_FAILURE;
1694 		}
1695 	}
1696 #endif
1697 
1698 get_prop_cleanup2:
1699 	mutex_exit(&ctrl_p->hc_mutex);
1700 get_prop_cleanup1:
1701 	nvlist_free(prop_rlist);
1702 get_prop_cleanup:
1703 	nvlist_free(prop_list);
1704 	return (ret);
1705 }
1706 
1707 int
1708 pciehpc_slot_set_property(pcie_hp_slot_t *slot_p, ddi_hp_property_t *arg,
1709     ddi_hp_property_t *rval)
1710 {
1711 	ddi_hp_property_t	request, result;
1712 #ifdef _SYSCALL32_IMPL
1713 	ddi_hp_property32_t	request32, result32;
1714 #endif
1715 	pcie_hp_ctrl_t		*ctrl_p = slot_p->hs_ctrl;
1716 	nvlist_t		*prop_list;
1717 	nvlist_t		*prop_rlist;
1718 	nvpair_t		*prop_pair;
1719 	char			*name, *value;
1720 	pcie_hp_led_state_t	led_state;
1721 	int			ret = DDI_SUCCESS;
1722 
1723 	if (get_udatamodel() == DATAMODEL_NATIVE) {
1724 		if (copyin(arg, &request, sizeof (ddi_hp_property_t)))
1725 			return (DDI_FAILURE);
1726 		if (rval &&
1727 		    copyin(rval, &result, sizeof (ddi_hp_property_t)))
1728 			return (DDI_FAILURE);
1729 	}
1730 #ifdef _SYSCALL32_IMPL
1731 	else {
1732 		bzero(&request, sizeof (request));
1733 		bzero(&result, sizeof (result));
1734 		if (copyin(arg, &request32, sizeof (ddi_hp_property32_t)))
1735 			return (DDI_FAILURE);
1736 		if (rval &&
1737 		    copyin(rval, &result32, sizeof (ddi_hp_property32_t)))
1738 			return (DDI_FAILURE);
1739 		request.nvlist_buf = (char *)(uintptr_t)request32.nvlist_buf;
1740 		request.buf_size = request32.buf_size;
1741 		if (rval) {
1742 			result.nvlist_buf =
1743 			    (char *)(uintptr_t)result32.nvlist_buf;
1744 			result.buf_size = result32.buf_size;
1745 		}
1746 	}
1747 #endif
1748 
1749 	if ((ret = pcie_copyin_nvlist(request.nvlist_buf, request.buf_size,
1750 	    &prop_list)) != DDI_SUCCESS)
1751 		return (ret);
1752 
1753 	/* check whether the requested property is "help" */
1754 	prop_pair = nvlist_next_nvpair(prop_list, NULL);
1755 	if (prop_pair && !nvlist_next_nvpair(prop_list, prop_pair) &&
1756 	    (strcmp(nvpair_name(prop_pair), PCIEHPC_PROP_HELP) == 0)) {
1757 		if (!rval) {
1758 			ret = DDI_ENOTSUP;
1759 			goto set_prop_cleanup;
1760 		}
1761 
1762 		if (nvlist_alloc(&prop_rlist, NV_UNIQUE_NAME, 0)) {
1763 			ret = DDI_ENOMEM;
1764 			goto set_prop_cleanup;
1765 		}
1766 		if (nvlist_add_string(prop_rlist, PCIEHPC_PROP_LED_ATTN,
1767 		    PCIEHPC_PROP_VALUE_LED) != 0) {
1768 			ret = DDI_FAILURE;
1769 			goto set_prop_cleanup1;
1770 		}
1771 
1772 		if ((ret = pcie_copyout_nvlist(prop_rlist, result.nvlist_buf,
1773 		    &result.buf_size)) != DDI_SUCCESS) {
1774 			goto set_prop_cleanup1;
1775 		}
1776 		if (get_udatamodel() == DATAMODEL_NATIVE) {
1777 			if (copyout(&result, rval,
1778 			    sizeof (ddi_hp_property_t))) {
1779 				ret =  DDI_FAILURE;
1780 				goto set_prop_cleanup1;
1781 			}
1782 		}
1783 #ifdef _SYSCALL32_IMPL
1784 		else {
1785 			if (result.buf_size > UINT32_MAX) {
1786 				ret =  DDI_FAILURE;
1787 				goto set_prop_cleanup1;
1788 			} else {
1789 				result32.buf_size = (uint32_t)result.buf_size;
1790 				if (copyout(&result32, rval,
1791 				    sizeof (ddi_hp_property32_t))) {
1792 					ret =  DDI_FAILURE;
1793 					goto set_prop_cleanup1;
1794 				}
1795 			}
1796 		}
1797 #endif
1798 set_prop_cleanup1:
1799 		nvlist_free(prop_rlist);
1800 		nvlist_free(prop_list);
1801 		return (ret);
1802 	}
1803 
1804 	/* Validate the request */
1805 	prop_pair = NULL;
1806 	while (prop_pair = nvlist_next_nvpair(prop_list, prop_pair)) {
1807 		name = nvpair_name(prop_pair);
1808 		if (nvpair_type(prop_pair) != DATA_TYPE_STRING) {
1809 			PCIE_DBG("Unexpected data type of setting "
1810 			    "property %s.\n", name);
1811 			ret = DDI_EINVAL;
1812 			goto set_prop_cleanup;
1813 		}
1814 		if (nvpair_value_string(prop_pair, &value)) {
1815 			PCIE_DBG("Get string value failed for property %s.\n",
1816 			    name);
1817 			ret = DDI_FAILURE;
1818 			goto set_prop_cleanup;
1819 		}
1820 
1821 		if (strcmp(name, PCIEHPC_PROP_LED_ATTN) == 0) {
1822 			if ((strcmp(value, PCIEHPC_PROP_VALUE_ON) != 0) &&
1823 			    (strcmp(value, PCIEHPC_PROP_VALUE_OFF) != 0) &&
1824 			    (strcmp(value, PCIEHPC_PROP_VALUE_BLINK) != 0)) {
1825 				PCIE_DBG("Unsupported value of setting "
1826 				    "property %s\n", name);
1827 				ret = DDI_ENOTSUP;
1828 				goto set_prop_cleanup;
1829 			}
1830 		} else {
1831 			PCIE_DBG("Unsupported property: %s\n", name);
1832 			ret = DDI_ENOTSUP;
1833 			goto set_prop_cleanup;
1834 		}
1835 	}
1836 	mutex_enter(&ctrl_p->hc_mutex);
1837 
1838 	/* get the current slot state */
1839 	pciehpc_get_slot_state(slot_p);
1840 
1841 	/* set each property */
1842 	prop_pair = NULL;
1843 	while (prop_pair = nvlist_next_nvpair(prop_list, prop_pair)) {
1844 		name = nvpair_name(prop_pair);
1845 
1846 		if (strcmp(name, PCIEHPC_PROP_LED_ATTN) == 0) {
1847 			if (strcmp(value, PCIEHPC_PROP_VALUE_ON) == 0)
1848 				led_state = PCIE_HP_LED_ON;
1849 			else if (strcmp(value, PCIEHPC_PROP_VALUE_OFF) == 0)
1850 				led_state = PCIE_HP_LED_OFF;
1851 			else if (strcmp(value, PCIEHPC_PROP_VALUE_BLINK) == 0)
1852 				led_state = PCIE_HP_LED_BLINK;
1853 
1854 			pciehpc_set_led_state(ctrl_p, PCIE_HP_ATTN_LED,
1855 			    led_state);
1856 		}
1857 	}
1858 	if (rval) {
1859 		if (get_udatamodel() == DATAMODEL_NATIVE) {
1860 			result.buf_size = 0;
1861 			if (copyout(&result, rval, sizeof (ddi_hp_property_t)))
1862 				ret =  DDI_FAILURE;
1863 		}
1864 #ifdef _SYSCALL32_IMPL
1865 		else {
1866 			result32.buf_size = 0;
1867 			if (copyout(&result32, rval,
1868 			    sizeof (ddi_hp_property32_t)))
1869 				ret =  DDI_FAILURE;
1870 		}
1871 #endif
1872 	}
1873 
1874 	mutex_exit(&ctrl_p->hc_mutex);
1875 set_prop_cleanup:
1876 	nvlist_free(prop_list);
1877 	return (ret);
1878 }
1879 
1880 /*
1881  * Send a command to the PCI-E Hot Plug Controller.
1882  *
1883  * NOTES: The PCI-E spec defines the following semantics for issuing hot plug
1884  * commands.
1885  * 1) If Command Complete events/interrupts are supported then software
1886  *    waits for Command Complete event after issuing a command (i.e writing
1887  *    to the Slot Control register). The command completion could take as
1888  *    long as 1 second so software should be prepared to wait for 1 second
1889  *    before issuing another command.
1890  *
1891  * 2) If Command Complete events/interrupts are not supported then
1892  *    software could issue multiple Slot Control writes without any delay
1893  *    between writes.
1894  */
1895 static void
1896 pciehpc_issue_hpc_command(pcie_hp_ctrl_t *ctrl_p, uint16_t control)
1897 {
1898 	pcie_hp_slot_t	*slot_p = ctrl_p->hc_slots[0];
1899 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
1900 	uint16_t	status;
1901 	uint32_t	slot_cap;
1902 
1903 	/*
1904 	 * PCI-E version 1.1 spec defines No Command Completed
1905 	 * Support bit (bit#18) in Slot Capabilities register. If this
1906 	 * bit is set then slot doesn't support notification of command
1907 	 * completion events.
1908 	 */
1909 	slot_cap =  pciehpc_reg_get32(ctrl_p,
1910 	    bus_p->bus_pcie_off + PCIE_SLOTCAP);
1911 
1912 	/*
1913 	 * If no Command Completion event is supported or it is ACPI
1914 	 * hot plug mode then just issue the command and return.
1915 	 */
1916 	if ((slot_cap & PCIE_SLOTCAP_NO_CMD_COMP_SUPP) ||
1917 	    (bus_p->bus_hp_curr_mode == PCIE_ACPI_HP_MODE)) {
1918 		pciehpc_reg_put16(ctrl_p,
1919 		    bus_p->bus_pcie_off + PCIE_SLOTCTL, control);
1920 		return;
1921 	}
1922 
1923 	/*
1924 	 * **************************************
1925 	 * Command Complete events are supported.
1926 	 * **************************************
1927 	 */
1928 
1929 	/*
1930 	 * If HPC is not yet initialized then just poll for the Command
1931 	 * Completion interrupt.
1932 	 */
1933 	if (!(ctrl_p->hc_flags & PCIE_HP_INITIALIZED_FLAG)) {
1934 		int retry = PCIE_HP_CMD_WAIT_RETRY;
1935 
1936 		/* write the command to the HPC */
1937 		pciehpc_reg_put16(ctrl_p,
1938 		    bus_p->bus_pcie_off + PCIE_SLOTCTL, control);
1939 
1940 		/* poll for status completion */
1941 		while (retry--) {
1942 			/* wait for 10 msec before checking the status */
1943 			delay(drv_usectohz(PCIE_HP_CMD_WAIT_TIME));
1944 
1945 			status = pciehpc_reg_get16(ctrl_p,
1946 			    bus_p->bus_pcie_off + PCIE_SLOTSTS);
1947 
1948 			if (status & PCIE_SLOTSTS_COMMAND_COMPLETED) {
1949 				/* clear the status bits */
1950 				pciehpc_reg_put16(ctrl_p,
1951 				    bus_p->bus_pcie_off + PCIE_SLOTSTS, status);
1952 				break;
1953 			}
1954 		}
1955 		return;
1956 	}
1957 
1958 	/* HPC is already initialized */
1959 
1960 	ASSERT(MUTEX_HELD(&ctrl_p->hc_mutex));
1961 
1962 	/*
1963 	 * If previous command is still pending then wait for its
1964 	 * completion. i.e cv_wait()
1965 	 */
1966 
1967 	while (ctrl_p->hc_cmd_pending == B_TRUE)
1968 		cv_wait(&ctrl_p->hc_cmd_comp_cv, &ctrl_p->hc_mutex);
1969 
1970 	/*
1971 	 * Issue the command and wait for Command Completion or
1972 	 * the 1 sec timeout.
1973 	 */
1974 	pciehpc_reg_put16(ctrl_p,
1975 	    bus_p->bus_pcie_off + PCIE_SLOTCTL, control);
1976 
1977 	ctrl_p->hc_cmd_pending = B_TRUE;
1978 
1979 	if (cv_timedwait(&ctrl_p->hc_cmd_comp_cv, &ctrl_p->hc_mutex,
1980 	    ddi_get_lbolt() + SEC_TO_TICK(1)) == -1) {
1981 
1982 		/* it is a timeout */
1983 		PCIE_DBG("pciehpc_issue_hpc_command: Command Complete"
1984 		    " interrupt is not received for slot %d\n",
1985 		    slot_p->hs_phy_slot_num);
1986 
1987 		/* clear the status info in case interrupts are disabled? */
1988 		status = pciehpc_reg_get16(ctrl_p,
1989 		    bus_p->bus_pcie_off + PCIE_SLOTSTS);
1990 
1991 		if (status & PCIE_SLOTSTS_COMMAND_COMPLETED) {
1992 			/* clear the status bits */
1993 			pciehpc_reg_put16(ctrl_p,
1994 			    bus_p->bus_pcie_off + PCIE_SLOTSTS, status);
1995 		}
1996 	}
1997 
1998 	ctrl_p->hc_cmd_pending = B_FALSE;
1999 
2000 	/* wake up any one waiting for issuing another command to HPC */
2001 	cv_signal(&ctrl_p->hc_cmd_comp_cv);
2002 }
2003 
2004 /*
2005  * pciehcp_attn_btn_handler()
2006  *
2007  * This handles ATTN button pressed event as per the PCI-E 1.1 spec.
2008  */
2009 static void
2010 pciehpc_attn_btn_handler(pcie_hp_ctrl_t *ctrl_p)
2011 {
2012 	pcie_hp_slot_t		*slot_p = ctrl_p->hc_slots[0];
2013 	pcie_hp_led_state_t	power_led_state;
2014 	callb_cpr_t		cprinfo;
2015 
2016 	PCIE_DBG("pciehpc_attn_btn_handler: thread started\n");
2017 
2018 	CALLB_CPR_INIT(&cprinfo, &ctrl_p->hc_mutex, callb_generic_cpr,
2019 	    "pciehpc_attn_btn_handler");
2020 
2021 	mutex_enter(&ctrl_p->hc_mutex);
2022 
2023 	/* wait for ATTN button event */
2024 	cv_wait(&slot_p->hs_attn_btn_cv, &ctrl_p->hc_mutex);
2025 
2026 	while (slot_p->hs_attn_btn_thread_exit == B_FALSE) {
2027 		if (slot_p->hs_attn_btn_pending == B_TRUE) {
2028 			/* get the current state of power LED */
2029 			power_led_state = pciehpc_get_led_state(ctrl_p,
2030 			    PCIE_HP_POWER_LED);
2031 
2032 			/* Blink the Power LED while we wait for 5 seconds */
2033 			pciehpc_set_led_state(ctrl_p, PCIE_HP_POWER_LED,
2034 			    PCIE_HP_LED_BLINK);
2035 
2036 			/* wait for 5 seconds before taking any action */
2037 			if (cv_timedwait(&slot_p->hs_attn_btn_cv,
2038 			    &ctrl_p->hc_mutex,
2039 			    ddi_get_lbolt() + SEC_TO_TICK(5)) == -1) {
2040 				/*
2041 				 * It is a time out; make sure the ATTN pending
2042 				 * flag is still ON before sending the event to
2043 				 * DDI HP framework.
2044 				 */
2045 				if (slot_p->hs_attn_btn_pending == B_TRUE) {
2046 					int hint;
2047 
2048 					slot_p->hs_attn_btn_pending = B_FALSE;
2049 					pciehpc_get_slot_state(slot_p);
2050 
2051 					if (slot_p->hs_info.cn_state <=
2052 					    DDI_HP_CN_STATE_PRESENT) {
2053 						/*
2054 						 * Insertion.
2055 						 */
2056 						hint = SE_INCOMING_RES;
2057 					} else {
2058 						/*
2059 						 * Want to remove;
2060 						 */
2061 						hint = SE_OUTGOING_RES;
2062 					}
2063 
2064 					/*
2065 					 * We can't call ddihp_cn_gen_sysevent
2066 					 * here since it's not a DDI interface.
2067 					 */
2068 					pcie_hp_gen_sysevent_req(
2069 					    slot_p->hs_info.cn_name,
2070 					    hint,
2071 					    ctrl_p->hc_dip,
2072 					    KM_SLEEP);
2073 				}
2074 			}
2075 
2076 			/* restore the power LED state */
2077 			pciehpc_set_led_state(ctrl_p, PCIE_HP_POWER_LED,
2078 			    power_led_state);
2079 			continue;
2080 		}
2081 
2082 		/* wait for another ATTN button event */
2083 		cv_wait(&slot_p->hs_attn_btn_cv, &ctrl_p->hc_mutex);
2084 	}
2085 
2086 	PCIE_DBG("pciehpc_attn_btn_handler: thread exit\n");
2087 	cv_signal(&slot_p->hs_attn_btn_cv);
2088 	CALLB_CPR_EXIT(&cprinfo);
2089 	thread_exit();
2090 }
2091 
2092 /*
2093  * convert LED state from PCIE HPC definition to pcie_hp_led_state_t
2094  * definition.
2095  */
2096 static pcie_hp_led_state_t
2097 pciehpc_led_state_to_hpc(uint16_t state)
2098 {
2099 	switch (state) {
2100 	case PCIE_SLOTCTL_INDICATOR_STATE_ON:
2101 		return (PCIE_HP_LED_ON);
2102 	case PCIE_SLOTCTL_INDICATOR_STATE_BLINK:
2103 		return (PCIE_HP_LED_BLINK);
2104 	case PCIE_SLOTCTL_INDICATOR_STATE_OFF:
2105 	default:
2106 		return (PCIE_HP_LED_OFF);
2107 	}
2108 }
2109 
2110 /*
2111  * Get the state of an LED.
2112  */
2113 static pcie_hp_led_state_t
2114 pciehpc_get_led_state(pcie_hp_ctrl_t *ctrl_p, pcie_hp_led_t led)
2115 {
2116 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
2117 	uint16_t	control, state;
2118 
2119 	/* get the current state of Slot Control register */
2120 	control =  pciehpc_reg_get16(ctrl_p,
2121 	    bus_p->bus_pcie_off + PCIE_SLOTCTL);
2122 
2123 	switch (led) {
2124 	case PCIE_HP_POWER_LED:
2125 		state = pcie_slotctl_pwr_indicator_get(control);
2126 		break;
2127 	case PCIE_HP_ATTN_LED:
2128 		state = pcie_slotctl_attn_indicator_get(control);
2129 		break;
2130 	default:
2131 		PCIE_DBG("pciehpc_get_led_state() invalid LED %d\n", led);
2132 		return (PCIE_HP_LED_OFF);
2133 	}
2134 
2135 	switch (state) {
2136 	case PCIE_SLOTCTL_INDICATOR_STATE_ON:
2137 		return (PCIE_HP_LED_ON);
2138 
2139 	case PCIE_SLOTCTL_INDICATOR_STATE_BLINK:
2140 		return (PCIE_HP_LED_BLINK);
2141 
2142 	case PCIE_SLOTCTL_INDICATOR_STATE_OFF:
2143 	default:
2144 		return (PCIE_HP_LED_OFF);
2145 	}
2146 }
2147 
2148 /*
2149  * Set the state of an LED. It updates both hw and sw state.
2150  */
2151 static void
2152 pciehpc_set_led_state(pcie_hp_ctrl_t *ctrl_p, pcie_hp_led_t led,
2153     pcie_hp_led_state_t state)
2154 {
2155 	pcie_hp_slot_t	*slot_p = ctrl_p->hc_slots[0];
2156 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
2157 	uint16_t	control;
2158 
2159 	/* get the current state of Slot Control register */
2160 	control =  pciehpc_reg_get16(ctrl_p,
2161 	    bus_p->bus_pcie_off + PCIE_SLOTCTL);
2162 
2163 	switch (led) {
2164 	case PCIE_HP_POWER_LED:
2165 		/* clear led mask */
2166 		control &= ~PCIE_SLOTCTL_PWR_INDICATOR_MASK;
2167 		slot_p->hs_power_led_state = state;
2168 		break;
2169 	case PCIE_HP_ATTN_LED:
2170 		/* clear led mask */
2171 		control &= ~PCIE_SLOTCTL_ATTN_INDICATOR_MASK;
2172 		slot_p->hs_attn_led_state = state;
2173 		break;
2174 	default:
2175 		PCIE_DBG("pciehpc_set_led_state() invalid LED %d\n", led);
2176 		return;
2177 	}
2178 
2179 	switch (state) {
2180 	case PCIE_HP_LED_ON:
2181 		if (led == PCIE_HP_POWER_LED)
2182 			control = pcie_slotctl_pwr_indicator_set(control,
2183 			    PCIE_SLOTCTL_INDICATOR_STATE_ON);
2184 		else if (led == PCIE_HP_ATTN_LED)
2185 			control = pcie_slotctl_attn_indicator_set(control,
2186 			    PCIE_SLOTCTL_INDICATOR_STATE_ON);
2187 		break;
2188 	case PCIE_HP_LED_OFF:
2189 		if (led == PCIE_HP_POWER_LED)
2190 			control = pcie_slotctl_pwr_indicator_set(control,
2191 			    PCIE_SLOTCTL_INDICATOR_STATE_OFF);
2192 		else if (led == PCIE_HP_ATTN_LED)
2193 			control = pcie_slotctl_attn_indicator_set(control,
2194 			    PCIE_SLOTCTL_INDICATOR_STATE_OFF);
2195 		break;
2196 	case PCIE_HP_LED_BLINK:
2197 		if (led == PCIE_HP_POWER_LED)
2198 			control = pcie_slotctl_pwr_indicator_set(control,
2199 			    PCIE_SLOTCTL_INDICATOR_STATE_BLINK);
2200 		else if (led == PCIE_HP_ATTN_LED)
2201 			control = pcie_slotctl_attn_indicator_set(control,
2202 			    PCIE_SLOTCTL_INDICATOR_STATE_BLINK);
2203 		break;
2204 
2205 	default:
2206 		PCIE_DBG("pciehpc_set_led_state() invalid LED state %d\n",
2207 		    state);
2208 		return;
2209 	}
2210 
2211 	/* update the Slot Control Register */
2212 	pciehpc_issue_hpc_command(ctrl_p, control);
2213 
2214 #ifdef DEBUG
2215 	/* get the current state of Slot Control register */
2216 	control =  pciehpc_reg_get16(ctrl_p,
2217 	    bus_p->bus_pcie_off + PCIE_SLOTCTL);
2218 
2219 	PCIE_DBG("pciehpc_set_led_state: slot %d power-led %s attn-led %s\n",
2220 	    slot_p->hs_phy_slot_num, pcie_led_state_text(
2221 	    pciehpc_led_state_to_hpc(pcie_slotctl_pwr_indicator_get(control))),
2222 	    pcie_led_state_text(pciehpc_led_state_to_hpc(
2223 	    pcie_slotctl_attn_indicator_get(control))));
2224 #endif
2225 }
2226 
2227 #ifdef DEBUG
2228 /*
2229  * Dump PCI-E Hot Plug registers.
2230  */
2231 static void
2232 pciehpc_dump_hpregs(pcie_hp_ctrl_t *ctrl_p)
2233 {
2234 	pcie_hp_slot_t	*slot_p = ctrl_p->hc_slots[0];
2235 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
2236 	uint16_t	control;
2237 	uint32_t	capabilities;
2238 
2239 	if (!pcie_debug_flags)
2240 		return;
2241 
2242 	capabilities = pciehpc_reg_get32(ctrl_p,
2243 	    bus_p->bus_pcie_off + PCIE_SLOTCAP);
2244 
2245 	control =  pciehpc_reg_get16(ctrl_p,
2246 	    bus_p->bus_pcie_off + PCIE_SLOTCTL);
2247 
2248 	PCIE_DBG("pciehpc_dump_hpregs: Found PCI-E hot plug slot %d\n",
2249 	    slot_p->hs_phy_slot_num);
2250 
2251 	PCIE_DBG("Attention Button Present = %s\n",
2252 	    capabilities & PCIE_SLOTCAP_ATTN_BUTTON ? "Yes":"No");
2253 
2254 	PCIE_DBG("Power controller Present = %s\n",
2255 	    capabilities & PCIE_SLOTCAP_POWER_CONTROLLER ? "Yes":"No");
2256 
2257 	PCIE_DBG("MRL Sensor Present	   = %s\n",
2258 	    capabilities & PCIE_SLOTCAP_MRL_SENSOR ? "Yes":"No");
2259 
2260 	PCIE_DBG("Attn Indicator Present   = %s\n",
2261 	    capabilities & PCIE_SLOTCAP_ATTN_INDICATOR ? "Yes":"No");
2262 
2263 	PCIE_DBG("Power Indicator Present  = %s\n",
2264 	    capabilities & PCIE_SLOTCAP_PWR_INDICATOR ? "Yes":"No");
2265 
2266 	PCIE_DBG("HotPlug Surprise	   = %s\n",
2267 	    capabilities & PCIE_SLOTCAP_HP_SURPRISE ? "Yes":"No");
2268 
2269 	PCIE_DBG("HotPlug Capable	   = %s\n",
2270 	    capabilities & PCIE_SLOTCAP_HP_CAPABLE ? "Yes":"No");
2271 
2272 	PCIE_DBG("Physical Slot Number	   = %d\n",
2273 	    PCIE_SLOTCAP_PHY_SLOT_NUM(capabilities));
2274 
2275 	PCIE_DBG("Attn Button interrupt Enabled  = %s\n",
2276 	    control & PCIE_SLOTCTL_ATTN_BTN_EN ? "Yes":"No");
2277 
2278 	PCIE_DBG("Power Fault interrupt Enabled  = %s\n",
2279 	    control & PCIE_SLOTCTL_PWR_FAULT_EN ? "Yes":"No");
2280 
2281 	PCIE_DBG("MRL Sensor INTR Enabled   = %s\n",
2282 	    control & PCIE_SLOTCTL_MRL_SENSOR_EN ? "Yes":"No");
2283 
2284 	PCIE_DBG("Presence interrupt Enabled	 = %s\n",
2285 	    control & PCIE_SLOTCTL_PRESENCE_CHANGE_EN ? "Yes":"No");
2286 
2287 	PCIE_DBG("Cmd Complete interrupt Enabled = %s\n",
2288 	    control & PCIE_SLOTCTL_CMD_INTR_EN ? "Yes":"No");
2289 
2290 	PCIE_DBG("HotPlug interrupt Enabled	 = %s\n",
2291 	    control & PCIE_SLOTCTL_HP_INTR_EN ? "Yes":"No");
2292 
2293 	PCIE_DBG("Power Indicator LED = %s", pcie_led_state_text(
2294 	    pciehpc_led_state_to_hpc(pcie_slotctl_pwr_indicator_get(control))));
2295 
2296 	PCIE_DBG("Attn Indicator LED = %s\n",
2297 	    pcie_led_state_text(pciehpc_led_state_to_hpc(
2298 	    pcie_slotctl_attn_indicator_get(control))));
2299 }
2300 #endif	/* DEBUG */
2301