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