xref: /illumos-gate/usr/src/uts/common/io/pciex/hotplug/pciehpc.c (revision bd97c7ce2344fa3252d8785c35895490916bc79b)
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  * Copyright 2023 Oxide Computer Company
26  */
27 
28 /*
29  * This file contains Standard PCI Express HotPlug functionality that is
30  * compatible with the PCI Express ver 1.1 specification.
31  *
32  * NOTE: This file is compiled and delivered through misc/pcie module.
33  *
34  * The main purpose of this is to take the PCIe slot logic, which is found on a
35  * PCIe bridge that indicates it is hotplug capable, and map the DDI hotplug
36  * controller states to this. This is an imperfect mapping as the definition of
37  * the pciehpc_slot_power_t shows. This file assumes that a device can be
38  * removed at any time without notice. This is what the spec calls 'surprise
39  * removal'.
40  *
41  * Not all PCIe slots are the same. In particular this can handle the following
42  * features which may or may not exist on the slot:
43  *
44  *  o Power Controllers: With the rise of NVMe based hotplug and the Enterprise
45  *    SSD specification, you can have hotplug, but not specific power control
46  *    over the device.
47  *  o MRL sensor: Manually-operated Retention latches are an optional item and
48  *    less common with U.2, E.1, and E.3 based form factors, but there is the
49  *    ability to see their state.
50  *  o EMI: Electromechanical Interlock. This is used to lock the device in place
51  *    and is often paired with an MRL. This similarly isn't as common.
52  *  o Attention Button: A button which can be pressed to say please do
53  *    something. This is more of a holdover from the world of coordinated
54  *    removal from the PCI Standard Hot-Plug Controller (SHPC).
55  *  o Power Fault: The ability to tell whether or not a power fault has
56  *    occurred.
57  *  o Power and Attention Indicators: These are LEDs that are supposed to be
58  *    enabled in response to specific actions in the spec, but some of that is
59  *    ultimately policy. It's worth noting that not all controllers support both
60  *    LEDs and so platforms may want to munge the logical states here a bit
61  *    more.
62  *
63  * There are four primary states that a slot is considered to exist in that
64  * roughly have the following state transition diagram:
65  *
66  *      +-------+
67  *      | Empty |<---------------<------------+
68  *      +-------+                             |
69  *          |                                 |
70  * Device   |                                 |
71  * Inserted .                                 ^
72  *          |                                 |
73  *          |                                 |
74  *          v                                 |
75  *     +---------+                            . . . Device
76  *     | Present |<------+                    |     Removed
77  *     +---------+       |                    |
78  *          |            |                    |
79  * Slot     |            |                    |
80  * Power  . .            . . Slot Power       |
81  * Enabled  |            |   Disabled,        |
82  *          |            |   Power Fault,     |
83  *          v            |   or specific      |
84  *     +---------+       |   request          |
85  *     | Powered |-->----+                    |
86  *     +---------+       |                    |
87  *          |            |                    |
88  *          |            |                    |
89  * Request  |            ^                    ^
90  * or auto- |            |                    |
91  * online . *            |                    |
92  *          |            |                    |
93  *          v            |                    |
94  *     +---------+       |                    |
95  *     | Enabled |-->----+--------->----------+
96  *     +---------+
97  *
98  * These four states are all related to the DDI_HP_CN_STATE_* values. For
99  * example, the empty state above is DDI_HP_CN_STATE_EMPTY and enabled is
100  * DDI_HP_CN_STATE_ENABLED. These changes can happen initially because of
101  * outside action that is taken or because an explicit state change has been
102  * requested via cfgadm/libhotplug. Note that one cannot enter or leave empty
103  * without removing or inserting a device.
104  *
105  * A device node is created in the devinfo tree as a side effect of
106  * transitioning to the enabled state and removed when transitioning away from
107  * enabled. This is initiated by the DDI hotplug framework making a probe
108  * (DDI_HPOP_CN_PROBE) and unprobe (DDI_HPOP_CN_UNPROBE) request which will
109  * ultimately get us to pcicfg_configure() which dynamically sets up child
110  * nodes.
111  *
112  * State Initialization
113  * --------------------
114  *
115  * Initializing the state of the world is a bit tricky here. In particular,
116  * there are a few things that we need to understand and deal with:
117  *
118  * 1. A PCIe slot may or may not have been powered prior to us initializing this
119  * module. In particular, the PCIe firmware specification generally expects
120  * occupied slots to have both their MRL and power indicator match the slot
121  * occupancy state (3.5 Device State at Firmware/Operating System Handoff). Of
122  * course, we must not assume that firmware has done this or not.
123  *
124  * This is further complicated by the fact that while the PCIe default is that
125  * power is enabled at reset, some controllers require an explicit first write
126  * to enact the reset behavior. You cannot do things like enable or disable
127  * interrupts without doing a write to the PCIe Slot Control register and
128  * turning power on. Those are just the breaks from the spec. The spec also
129  * doesn't have a way to tell us if power is actually on or not, we just have to
130  * hope. All we can see is if we've commanded power on and if a power fault was
131  * detected at some point.
132  *
133  * 2. Because of (1), the normal platform-specific startup logic for PCIe may or
134  * may not have found any devices and initialized them depending on at what
135  * state in the initialization point it was at.
136  *
137  * 3. To actually enumerate a hotplug device, our DDI_HPOP_CN_PROBE entry point
138  * needs to be called, which is pciehpc_slot_probe(). This will ultimately call
139  * pcicfg_configure(). There is a wrinkle here. If we have done (2), we don't
140  * want to call the probe entry point. However, if we haven't, then at start up,
141  * the broader hotplug unfortunately, won't assume that there is anything to do
142  * here to make this happen. The kernel framework won't call this unless it sees
143  * a transition from a lesser state to DDI_HP_CN_STATE_ENABLED.
144  *
145  * The cases described above are not our only problem. In particular, there are
146  * some other complications that happen here. In particular, it's worth
147  * understanding how we actually keep all of our state in sync. The core idea is
148  * that changes are coming from one of two places: either a user has explicitly
149  * requested a state change or we have had external activity that has injected a
150  * hotplug interrupt. This is due to something such as a surprise insertion,
151  * removal, power fault, or similar activity.
152  *
153  * The general construction and assumption is that we know the valid state at
154  * the moment before an interrupt occurs, so then the slot status register will
155  * indicate to us what has changed. Once we know what we should transition to,
156  * then we will go ahead and ask the system to make a state change request to
157  * change our state to a given target. While this is similar in spirit to what a
158  * user could request, they could not imitate a state transition to EMPTY. The
159  * transition to EMPTY or to ENABLED is what kicks off the probe and unprobe
160  * operations.
161  *
162  * This system is all well and good, but it is dependent on the fact that we
163  * have an interrupt enabled for changes and that the various interrupt cause
164  * bits in the slot status register have been cleared as they are generally RW1C
165  * (read, write 1 to clear). This means that in addition to the issues with case
166  * (1) and what firmware has or hasn't done, it is also possible that additional
167  * changes may occur without us recording them or noticing them in an interrupt.
168  *
169  * This steady state is a great place to be, but because of the races we
170  * discussed above, we need to do a bit of additional work here to ensure that
171  * we can reliably enter it. As such, we're going to address the three
172  * complications above in reverse order. If we start with (3), while in the
173  * steady state, we basically treat the DDI states as the main states we can
174  * transition to and from (again see the pciehpc_slot_power_t comment for the
175  * fact that this is somewhat factious). This means that if we are ENABLED, a
176  * probe must have happened (or the semi-equivalent in (2)).
177  *
178  * Normally, we assume that if we got all the way up and have a powered device
179  * that the state we should return to the system is ENABLED. However, that only
180  * works if we can ensure that the state transition from less than ENABLED to
181  * ENABLED occurs so a probe can occur.
182  *
183  * This window is made larger because of (1) and (2). However, this is not
184  * unique to the ENABLED state and these cases can happen by having a device
185  * that was probed at initial time be removed prior to the interrupt being
186  * enabled. While this is honestly a very tight window and something that may
187  * not happen in practice, it highlights many of the things that can occur and
188  * that we need to handle.
189  *
190  * To deal with this we are a little more careful with our startup state. When
191  * we reach our module's main initialization entry point for a given controller,
192  * pciehpc_init(), we know that at that point (2) has completed. We also know
193  * that the interrupt shouldn't be initiated at that point, but that isn't
194  * guaranteed until we finish calling the pciehpc_hpc_init() entry point. We
195  * subsequently will enable the interrupt via the enable_phc_intr() function
196  * pointer, which is called from pcie_hpintr_enable(). This gap is to allow the
197  * overall driver (say pcieb) to ensure that it has allocated and attached
198  * interrupts prior to us enabling it.
199  *
200  * At the point that we are initialized, we can look and see if we have any
201  * children. If we do, then we know that (2) performed initialization and it's
202  * safe for us to set our initial state to ENABLED and allow that to be the
203  * first thing the kernel hotplug framework sees, assuming our state would
204  * otherwise suggest we'd be here. If we do not see a child device and we have
205  * enabled power, then we basically need to mimic the normal act of having
206  * transitioned to an ENABLED state. This needs to happen ahead of us first
207  * communicating our state to the DDI.
208  *
209  * The next set of things we need to do happen when we go to enable interrupts.
210  * It's worth keeping in mind that at this point the rest of the system is fully
211  * operational. One of three events can be injected at this point, a removal,
212  * insertion, or a power fault. We also need to consider that a removal or
213  * insertion happened in an intervening point. To make this all happen, let's
214  * discuss the different pieces that are involved in tracking what's going on:
215  *
216  * 1) During pciehpc_slotinfo_init() we check to see if we have a child devinfo
217  * node or not. We only mark a node as ENABLED if we have a child and it is
218  * already POWERED. This ensures that we aren't ahead of ourselves. The normal
219  * state determination logic will not put us at enabled prior to being there.
220  *
221  * 2) We have added a pair of flags to the pcie_hp_ctrl_t called
222  * PCIE_HP_SYNC_PENDING and PCIE_HP_SYNC_RUNNING. The former indicates that we
223  * have identified that we need to perform a state correction and have
224  * dispatched a task to the system taskq to deal with it. The
225  * PCIE_HP_SYNC_RUNNING flag is used to indicate that a state transition request
226  * is actually being made due to this right now. This is used to tweak a bit of
227  * the slot upgrade path, discussed below.
228  *
229  * 3) Immediately after enabling interrupts, while still holding the hotplug
230  * controller mutex, we investigate what our current state is and what we have
231  * previously set it to. Depending on the transition that needs to occur and if
232  * it has a side effect of needing to probe or unprobe a connection, then we'll
233  * end up scheduling a task in the system taskq to perform that transition.
234  * Otherwise, we will simply fix up the LED state as we have no reason to
235  * believe that it is currently correct for our state.
236  *
237  * Using the taskq has a major benefit for us in that it allows us to leverage
238  * the existing code paths for state transitions. This means that if things are
239  * already powered on and the data link layer is active, there won't be any
240  * extra delay and if not, it will honor the same 1s timeout, take advantage of
241  * the datalink layer active bit if supported, and on failure it will turn off
242  * the controller.
243  *
244  * 4) We are reliant on an important property of pciehpc_get_slot_state(): if it
245  * finds itself in the POWERED state, it will not change from that. This is half
246  * of the reason that we opt to go to the POWERED state when this occurs. The
247  * other half is that it is factually accurate and doing otherwise would get in
248  * the way of our logic which attempts to correct the state in
249  * pciehpc_change_slot_state() which corrects for the state being incorrect.
250  * While it is tempting to use the PRESENT state and try to avoid a special case
251  * in pciehpc_upgrade_slot_state(), that ends up breaking more invariants than
252  * the logic described below.
253  *
254  * 5) Finally, when the PCIE_HP_SYNC_RUNNING bit is set, that tells us when
255  * we're doing a power on exercise that we need to do so again regardless of
256  * what we think we've done. Because of our attempts to try to have things be
257  * idempotent, this ends up being a relatively safe operation to perform again
258  * and being able to reuse this helps a lot.
259  *
260  * It is our hope that after this point everything will be in line such that we
261  * can enter the steady state. If devices have come or gone, the use of the
262  * normal state machine transitions should allow us to get them to be attached
263  * or not.
264  */
265 
266 #include <sys/types.h>
267 #include <sys/note.h>
268 #include <sys/conf.h>
269 #include <sys/kmem.h>
270 #include <sys/debug.h>
271 #include <sys/vtrace.h>
272 #include <sys/autoconf.h>
273 #include <sys/varargs.h>
274 #include <sys/ddi_impldefs.h>
275 #include <sys/time.h>
276 #include <sys/callb.h>
277 #include <sys/ddi.h>
278 #include <sys/sunddi.h>
279 #include <sys/sunndi.h>
280 #include <sys/sysevent/dr.h>
281 #include <sys/pci_impl.h>
282 #include <sys/hotplug/pci/pcie_hp.h>
283 #include <sys/hotplug/pci/pciehpc.h>
284 
285 /* XXX /etc/system is NOT a policy interface */
286 int pcie_auto_online = 1;
287 
288 typedef struct pciehpc_prop {
289 	char	*prop_name;
290 	char	*prop_value;
291 } pciehpc_prop_t;
292 
293 static pciehpc_prop_t	pciehpc_props[] = {
294 	{ PCIEHPC_PROP_LED_FAULT,	PCIEHPC_PROP_VALUE_LED },
295 	{ PCIEHPC_PROP_LED_POWER,	PCIEHPC_PROP_VALUE_LED },
296 	{ PCIEHPC_PROP_LED_ATTN,	PCIEHPC_PROP_VALUE_LED },
297 	{ PCIEHPC_PROP_LED_ACTIVE,	PCIEHPC_PROP_VALUE_LED },
298 	{ PCIEHPC_PROP_CARD_TYPE,	PCIEHPC_PROP_VALUE_TYPE },
299 	{ PCIEHPC_PROP_BOARD_TYPE,	PCIEHPC_PROP_VALUE_TYPE },
300 	{ PCIEHPC_PROP_SLOT_CONDITION,	PCIEHPC_PROP_VALUE_TYPE }
301 };
302 
303 /*
304  * Ideally, it would be possible to represent the state of a slot with a single
305  * ddi_hp_cn_state_t; after all, that's the purpose of that data type.
306  * Unfortunately it wasn't designed very well and cannot even represent the
307  * range of possible power states of a PCIe slot.  It is possible for a slot to
308  * be powered on or off with or without a device present, and it is possible for
309  * a slot not to have a power controller at all.  Finally, it's possible for a
310  * power fault to be detected regardless of whether power is on or off or a
311  * device is present or not.  This state attempts to represent all possible
312  * power states that a slot can have, which is important for implementing our
313  * state machine that has to expose only the very limited DDI states.
314  *
315  * These are bits that may be ORed together.  Not all combinations comply with
316  * the standards, but these definitions were chosen to make it harder to
317  * construct invalid combinations.  In particular, if there is no controller,
318  * there is also no possibility of the slot being turned off, nor is it possible
319  * for there to be a fault.
320  */
321 typedef enum pciehpc_slot_power {
322 	PSP_NO_CONTROLLER = 0,
323 	PSP_HAS_CONTROLLER = (1U << 0),
324 	PSP_OFF = (1U << 1),
325 	PSP_FAULT = (1U << 2)
326 } pciehpc_slot_power_t;
327 
328 typedef struct {
329 	pcie_hp_ctrl_t *pst_ctrl;
330 	ddi_hp_cn_state_t pst_targ;
331 	ddi_hp_cn_state_t pst_cur;
332 } pciehpc_sync_task_t;
333 
334 /* Local functions prototype */
335 static int pciehpc_hpc_init(pcie_hp_ctrl_t *ctrl_p);
336 static int pciehpc_hpc_uninit(pcie_hp_ctrl_t *ctrl_p);
337 static int pciehpc_slotinfo_init(pcie_hp_ctrl_t *ctrl_p);
338 static int pciehpc_slotinfo_uninit(pcie_hp_ctrl_t *ctrl_p);
339 static int pciehpc_enable_intr(pcie_hp_ctrl_t *ctrl_p);
340 static int pciehpc_disable_intr(pcie_hp_ctrl_t *ctrl_p);
341 static pcie_hp_ctrl_t *pciehpc_create_controller(dev_info_t *dip);
342 static void pciehpc_destroy_controller(dev_info_t *dip);
343 static int pciehpc_register_slot(pcie_hp_ctrl_t *ctrl_p);
344 static int pciehpc_unregister_slot(pcie_hp_ctrl_t *ctrl_p);
345 static int pciehpc_slot_get_property(pcie_hp_slot_t *slot_p,
346     ddi_hp_property_t *arg, ddi_hp_property_t *rval);
347 static int pciehpc_slot_set_property(pcie_hp_slot_t *slot_p,
348     ddi_hp_property_t *arg, ddi_hp_property_t *rval);
349 static void pciehpc_issue_hpc_command(pcie_hp_ctrl_t *ctrl_p, uint16_t control);
350 static void pciehpc_attn_btn_handler(pcie_hp_ctrl_t *ctrl_p);
351 static pcie_hp_led_state_t pciehpc_led_state_to_hpc(uint16_t state);
352 static pcie_hp_led_state_t pciehpc_get_led_state(pcie_hp_ctrl_t *ctrl_p,
353     pcie_hp_led_t led);
354 static void pciehpc_set_led_state(pcie_hp_ctrl_t *ctrl_p, pcie_hp_led_t led,
355     pcie_hp_led_state_t state);
356 
357 static int pciehpc_upgrade_slot_state(pcie_hp_slot_t *slot_p,
358     ddi_hp_cn_state_t target_state);
359 static int pciehpc_downgrade_slot_state(pcie_hp_slot_t *slot_p,
360     ddi_hp_cn_state_t target_state);
361 static int pciehpc_change_slot_state(pcie_hp_slot_t *slot_p,
362     ddi_hp_cn_state_t target_state);
363 static int
364     pciehpc_slot_poweron(pcie_hp_slot_t *slot_p, ddi_hp_cn_state_t *result);
365 static int
366     pciehpc_slot_poweroff(pcie_hp_slot_t *slot_p, ddi_hp_cn_state_t *result);
367 static int pciehpc_slot_probe(pcie_hp_slot_t *slot_p);
368 static int pciehpc_slot_unprobe(pcie_hp_slot_t *slot_p);
369 static void pciehpc_handle_power_fault(dev_info_t *dip);
370 static void pciehpc_power_fault_handler(void *arg);
371 
372 #ifdef	DEBUG
373 static void pciehpc_dump_hpregs(pcie_hp_ctrl_t *ctrl_p);
374 #endif	/* DEBUG */
375 
376 /*
377  * Global functions (called by other drivers/modules)
378  */
379 
380 /*
381  * Initialize Hot Plug Controller if present. The arguments are:
382  *	dip	- Devinfo node pointer to the hot plug bus node
383  *	regops	- register ops to access HPC registers for non-standard
384  *		  HPC hw implementations (e.g: HPC in host PCI-E brdiges)
385  *		  This is NULL for standard HPC in PCIe bridges.
386  * Returns:
387  *	DDI_SUCCESS for successful HPC initialization
388  *	DDI_FAILURE for errors or if HPC hw not found
389  */
390 int
391 pciehpc_init(dev_info_t *dip, caddr_t arg)
392 {
393 	pcie_hp_regops_t	*regops = (pcie_hp_regops_t *)(void *)arg;
394 	pcie_hp_ctrl_t		*ctrl_p;
395 
396 	PCIE_DBG("pciehpc_init() called (dip=%p)\n", (void *)dip);
397 
398 	/* Make sure that it is not already initialized */
399 	if ((ctrl_p = PCIE_GET_HP_CTRL(dip)) != NULL) {
400 		PCIE_DBG("%s%d: pciehpc instance already initialized!\n",
401 		    ddi_driver_name(dip), ddi_get_instance(dip));
402 		return (DDI_SUCCESS);
403 	}
404 
405 	/* Allocate a new hotplug controller and slot structures */
406 	ctrl_p = pciehpc_create_controller(dip);
407 
408 	/* setup access handle for HPC regs */
409 	if (regops != NULL) {
410 		/* HPC access is non-standard; use the supplied reg ops */
411 		ctrl_p->hc_regops = *regops;
412 	}
413 
414 	/*
415 	 * Setup resource maps for this bus node.
416 	 */
417 	(void) pci_resource_setup(dip);
418 
419 	PCIE_DISABLE_ERRORS(dip);
420 
421 	/*
422 	 * Set the platform specific hot plug mode.
423 	 */
424 	ctrl_p->hc_ops.init_hpc_hw = pciehpc_hpc_init;
425 	ctrl_p->hc_ops.uninit_hpc_hw = pciehpc_hpc_uninit;
426 	ctrl_p->hc_ops.init_hpc_slotinfo = pciehpc_slotinfo_init;
427 	ctrl_p->hc_ops.uninit_hpc_slotinfo = pciehpc_slotinfo_uninit;
428 	ctrl_p->hc_ops.poweron_hpc_slot = pciehpc_slot_poweron;
429 	ctrl_p->hc_ops.poweroff_hpc_slot = pciehpc_slot_poweroff;
430 
431 	ctrl_p->hc_ops.enable_hpc_intr = pciehpc_enable_intr;
432 	ctrl_p->hc_ops.disable_hpc_intr = pciehpc_disable_intr;
433 
434 #if	defined(__x86)
435 	pciehpc_update_ops(ctrl_p);
436 #endif
437 
438 	/* initialize hot plug controller hw */
439 	if ((ctrl_p->hc_ops.init_hpc_hw)(ctrl_p) != DDI_SUCCESS)
440 		goto cleanup1;
441 
442 	/* initialize slot information soft state structure */
443 	if ((ctrl_p->hc_ops.init_hpc_slotinfo)(ctrl_p) != DDI_SUCCESS)
444 		goto cleanup2;
445 
446 	/* register the hot plug slot with DDI HP framework */
447 	if (pciehpc_register_slot(ctrl_p) != DDI_SUCCESS)
448 		goto cleanup3;
449 
450 	/* create minor node for this slot */
451 	if (pcie_create_minor_node(ctrl_p, 0) != DDI_SUCCESS)
452 		goto cleanup4;
453 
454 	/*
455 	 * While we disabled errors upon entry, if we were initialized and
456 	 * entered the ENABLED state that indicates we have children and
457 	 * therefore we should go back and enable errors.
458 	 */
459 	if (ctrl_p->hc_slots[0]->hs_info.cn_state == DDI_HP_CN_STATE_ENABLED) {
460 		PCIE_ENABLE_ERRORS(dip);
461 	}
462 
463 	/* HPC initialization is complete now */
464 	ctrl_p->hc_flags |= PCIE_HP_INITIALIZED_FLAG;
465 
466 #ifdef	DEBUG
467 	/* For debug, dump the HPC registers */
468 	pciehpc_dump_hpregs(ctrl_p);
469 #endif	/* DEBUG */
470 
471 	return (DDI_SUCCESS);
472 cleanup4:
473 	(void) pciehpc_unregister_slot(ctrl_p);
474 cleanup3:
475 	(void) (ctrl_p->hc_ops.uninit_hpc_slotinfo)(ctrl_p);
476 
477 cleanup2:
478 	(void) (ctrl_p->hc_ops.uninit_hpc_hw)(ctrl_p);
479 
480 cleanup1:
481 	PCIE_ENABLE_ERRORS(dip);
482 	(void) pci_resource_destroy(dip);
483 
484 	pciehpc_destroy_controller(dip);
485 	return (DDI_FAILURE);
486 }
487 
488 /*
489  * Uninitialize HPC soft state structure and free up any resources
490  * used for the HPC instance.
491  */
492 int
493 pciehpc_uninit(dev_info_t *dip)
494 {
495 	pcie_hp_ctrl_t *ctrl_p;
496 	taskqid_t id;
497 
498 	PCIE_DBG("pciehpc_uninit() called (dip=%p)\n", (void *)dip);
499 
500 	/* get the soft state structure for this dip */
501 	if ((ctrl_p = PCIE_GET_HP_CTRL(dip)) == NULL) {
502 		return (DDI_FAILURE);
503 	}
504 
505 	/*
506 	 * Prior to taking any action, we want to remove the initialized flag.
507 	 * Any interrupts should have already been quiesced prior to this. There
508 	 * may be an outstanding startup synchronization timeout(9F) call.
509 	 */
510 	mutex_enter(&ctrl_p->hc_mutex);
511 	ctrl_p->hc_flags &= ~PCIE_HP_INITIALIZED_FLAG;
512 	id = ctrl_p->hc_startup_sync;
513 	ctrl_p->hc_startup_sync = TASKQID_INVALID;
514 	mutex_exit(&ctrl_p->hc_mutex);
515 
516 	if (id != TASKQID_INVALID)
517 		taskq_wait_id(system_taskq, id);
518 
519 	pcie_remove_minor_node(ctrl_p, 0);
520 
521 	/* unregister the slot */
522 	(void) pciehpc_unregister_slot(ctrl_p);
523 
524 	/* uninit any slot info data structures */
525 	(void) (ctrl_p->hc_ops.uninit_hpc_slotinfo)(ctrl_p);
526 
527 	/* uninitialize hpc, remove interrupt handler, etc. */
528 	(void) (ctrl_p->hc_ops.uninit_hpc_hw)(ctrl_p);
529 
530 	PCIE_ENABLE_ERRORS(dip);
531 
532 	/*
533 	 * Destroy resource maps for this bus node.
534 	 */
535 	(void) pci_resource_destroy(dip);
536 
537 	/* destroy the soft state structure */
538 	pciehpc_destroy_controller(dip);
539 
540 	return (DDI_SUCCESS);
541 }
542 
543 /*
544  * pciehpc_intr()
545  *
546  * Interrupt handler for PCI-E Hot plug controller interrupts.
547  *
548  * Note: This is only for native mode hot plug. This is called
549  * by the nexus driver at interrupt context. Interrupt Service Routine
550  * registration is done by the nexus driver for both hot plug and
551  * non-hot plug interrupts. This function is called from the ISR
552  * of the nexus driver to handle hot-plug interrupts.
553  *
554  * We must check whether or not we have a pending synchronization event and if
555  * so, cancel it. In particular, there are several cases that may cause us to
556  * request an asynchronous state transition (e.g. a drive was removed or
557  * inserted). When that occurs, we effectively cancel the pending
558  * synchronization taskq activity. It will still execute, but do nothing. If it
559  * has already started executing, then its state change request will already
560  * have been dispatched and we let things shake out with the additional logic we
561  * have present in pciehpc_change_slot_state().
562  */
563 int
564 pciehpc_intr(dev_info_t *dip)
565 {
566 	pcie_hp_ctrl_t	*ctrl_p;
567 	pcie_hp_slot_t	*slot_p;
568 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(dip);
569 	uint16_t	status, control;
570 	boolean_t	clear_pend = B_FALSE;
571 
572 	/* get the soft state structure for this dip */
573 	if ((ctrl_p = PCIE_GET_HP_CTRL(dip)) == NULL)
574 		return (DDI_INTR_UNCLAIMED);
575 
576 	mutex_enter(&ctrl_p->hc_mutex);
577 
578 	/* make sure the controller soft state is initialized */
579 	if (!(ctrl_p->hc_flags & PCIE_HP_INITIALIZED_FLAG)) {
580 		mutex_exit(&ctrl_p->hc_mutex);
581 		return (DDI_INTR_UNCLAIMED);
582 	}
583 
584 	/* if it is not NATIVE hot plug mode then return */
585 	if (bus_p->bus_hp_curr_mode != PCIE_NATIVE_HP_MODE) {
586 		mutex_exit(&ctrl_p->hc_mutex);
587 		return (DDI_INTR_UNCLAIMED);
588 	}
589 
590 	slot_p = ctrl_p->hc_slots[0];
591 
592 	/* read the current slot status register */
593 	status = pciehpc_reg_get16(ctrl_p,
594 	    bus_p->bus_pcie_off + PCIE_SLOTSTS);
595 
596 	/* check if there are any hot plug interrupts occurred */
597 	if (!(status & PCIE_SLOTSTS_STATUS_EVENTS)) {
598 		/* no hot plug events occurred */
599 		mutex_exit(&ctrl_p->hc_mutex);
600 		return (DDI_INTR_UNCLAIMED);
601 	}
602 
603 	/* clear the interrupt status bits */
604 	pciehpc_reg_put16(ctrl_p,
605 	    bus_p->bus_pcie_off + PCIE_SLOTSTS, status);
606 
607 	/* check for CMD COMPLETE interrupt */
608 	if (status & PCIE_SLOTSTS_COMMAND_COMPLETED) {
609 		PCIE_DBG("pciehpc_intr(): CMD COMPLETED interrupt received\n");
610 		/* wake up any one waiting for Command Completion event */
611 		cv_signal(&ctrl_p->hc_cmd_comp_cv);
612 	}
613 
614 	/* check for ATTN button interrupt */
615 	if (status & PCIE_SLOTSTS_ATTN_BTN_PRESSED) {
616 		PCIE_DBG("pciehpc_intr(): ATTN BUTTON interrupt received\n");
617 
618 		/* if ATTN button event is still pending then cancel it */
619 		if (slot_p->hs_attn_btn_pending == B_TRUE)
620 			slot_p->hs_attn_btn_pending = B_FALSE;
621 		else
622 			slot_p->hs_attn_btn_pending = B_TRUE;
623 
624 		/* wake up the ATTN event handler */
625 		cv_signal(&slot_p->hs_attn_btn_cv);
626 	}
627 
628 	/* check for power fault interrupt */
629 	if (status & PCIE_SLOTSTS_PWR_FAULT_DETECTED) {
630 
631 		PCIE_DBG("pciehpc_intr(): POWER FAULT interrupt received"
632 		    " on slot %d\n", slot_p->hs_phy_slot_num);
633 		control =  pciehpc_reg_get16(ctrl_p,
634 		    bus_p->bus_pcie_off + PCIE_SLOTCTL);
635 
636 		if (control & PCIE_SLOTCTL_PWR_FAULT_EN) {
637 			slot_p->hs_condition = AP_COND_FAILED;
638 
639 			/* disable power fault detection interrupt */
640 			pciehpc_reg_put16(ctrl_p, bus_p->bus_pcie_off +
641 			    PCIE_SLOTCTL, control & ~PCIE_SLOTCTL_PWR_FAULT_EN);
642 
643 			pciehpc_handle_power_fault(dip);
644 			clear_pend = B_TRUE;
645 		}
646 	}
647 
648 	/* check for MRL SENSOR CHANGED interrupt */
649 	if (status & PCIE_SLOTSTS_MRL_SENSOR_CHANGED) {
650 		/* For now (phase-I), no action is taken on this event */
651 		PCIE_DBG("pciehpc_intr(): MRL SENSOR CHANGED interrupt received"
652 		    " on slot %d\n", slot_p->hs_phy_slot_num);
653 	}
654 
655 	/* check for PRESENCE CHANGED interrupt */
656 	if (status & PCIE_SLOTSTS_PRESENCE_CHANGED) {
657 
658 		PCIE_DBG("pciehpc_intr(): PRESENCE CHANGED interrupt received"
659 		    " on slot %d\n", slot_p->hs_phy_slot_num);
660 
661 		if (status & PCIE_SLOTSTS_PRESENCE_DETECTED) {
662 			ddi_hp_cn_state_t tgt_state = (pcie_auto_online != 0) ?
663 			    DDI_HP_CN_STATE_ENABLED : DDI_HP_CN_STATE_PRESENT;
664 			/*
665 			 * card is inserted into the slot, ask DDI Hotplug
666 			 * framework to change state to Present.
667 			 */
668 			cmn_err(CE_NOTE, "pciehpc (%s%d): card is inserted"
669 			    " in the slot %s",
670 			    ddi_driver_name(dip),
671 			    ddi_get_instance(dip),
672 			    slot_p->hs_info.cn_name);
673 
674 			(void) ndi_hp_state_change_req(dip,
675 			    slot_p->hs_info.cn_name,
676 			    tgt_state, DDI_HP_REQ_ASYNC);
677 		} else { /* card is removed from the slot */
678 			cmn_err(CE_NOTE, "pciehpc (%s%d): card is removed"
679 			    " from the slot %s",
680 			    ddi_driver_name(dip),
681 			    ddi_get_instance(dip),
682 			    slot_p->hs_info.cn_name);
683 
684 			if (slot_p->hs_info.cn_state ==
685 			    DDI_HP_CN_STATE_ENABLED) {
686 				/* Card is removed when slot is enabled */
687 				slot_p->hs_condition = AP_COND_FAILED;
688 			} else {
689 				slot_p->hs_condition = AP_COND_UNKNOWN;
690 			}
691 			/* make sure to disable power fault detction intr */
692 			control =  pciehpc_reg_get16(ctrl_p,
693 			    bus_p->bus_pcie_off + PCIE_SLOTCTL);
694 
695 			if (control & PCIE_SLOTCTL_PWR_FAULT_EN)
696 				pciehpc_reg_put16(ctrl_p, bus_p->bus_pcie_off +
697 				    PCIE_SLOTCTL,
698 				    control & ~PCIE_SLOTCTL_PWR_FAULT_EN);
699 
700 			/*
701 			 * If supported, notify the child device driver that the
702 			 * device is being removed.
703 			 */
704 			dev_info_t *cdip = ddi_get_child(dip);
705 			if (cdip != NULL) {
706 				ddi_eventcookie_t rm_cookie;
707 				if (ddi_get_eventcookie(cdip,
708 				    DDI_DEVI_REMOVE_EVENT,
709 				    &rm_cookie) == DDI_SUCCESS) {
710 					ndi_post_event(dip, cdip, rm_cookie,
711 					    NULL);
712 				}
713 			}
714 
715 			/*
716 			 * Ask DDI Hotplug framework to change state to Empty
717 			 */
718 			(void) ndi_hp_state_change_req(dip,
719 			    slot_p->hs_info.cn_name,
720 			    DDI_HP_CN_STATE_EMPTY,
721 			    DDI_HP_REQ_ASYNC);
722 		}
723 
724 		clear_pend = B_TRUE;
725 	}
726 
727 	/* check for DLL state changed interrupt */
728 	if (ctrl_p->hc_dll_active_rep &&
729 	    (status & PCIE_SLOTSTS_DLL_STATE_CHANGED)) {
730 		PCIE_DBG("pciehpc_intr(): DLL STATE CHANGED interrupt received"
731 		    " on slot %d\n", slot_p->hs_phy_slot_num);
732 
733 		cv_signal(&slot_p->hs_dll_active_cv);
734 	}
735 
736 	if (clear_pend) {
737 		ctrl_p->hc_flags &= ~PCIE_HP_SYNC_PENDING;
738 	}
739 	mutex_exit(&ctrl_p->hc_mutex);
740 
741 	return (DDI_INTR_CLAIMED);
742 }
743 
744 /*
745  * Handle hotplug commands
746  *
747  * Note: This function is called by DDI HP framework at kernel context only
748  */
749 /* ARGSUSED */
750 int
751 pciehpc_hp_ops(dev_info_t *dip, char *cn_name, ddi_hp_op_t op,
752     void *arg, void *result)
753 {
754 	pcie_hp_ctrl_t	*ctrl_p;
755 	pcie_hp_slot_t	*slot_p;
756 	int		ret = DDI_SUCCESS;
757 
758 	PCIE_DBG("pciehpc_hp_ops: dip=%p cn_name=%s op=%x arg=%p\n",
759 	    dip, cn_name, op, arg);
760 
761 	if ((ctrl_p = PCIE_GET_HP_CTRL(dip)) == NULL)
762 		return (DDI_FAILURE);
763 
764 	slot_p = ctrl_p->hc_slots[0];
765 
766 	if (strcmp(cn_name, slot_p->hs_info.cn_name) != 0)
767 		return (DDI_EINVAL);
768 
769 	switch (op) {
770 	case DDI_HPOP_CN_GET_STATE:
771 	{
772 		mutex_enter(&slot_p->hs_ctrl->hc_mutex);
773 
774 		/* get the current slot state */
775 		pciehpc_get_slot_state(slot_p);
776 
777 		*((ddi_hp_cn_state_t *)result) = slot_p->hs_info.cn_state;
778 
779 		mutex_exit(&slot_p->hs_ctrl->hc_mutex);
780 		break;
781 	}
782 	case DDI_HPOP_CN_CHANGE_STATE:
783 	{
784 		ddi_hp_cn_state_t target_state = *(ddi_hp_cn_state_t *)arg;
785 
786 		mutex_enter(&slot_p->hs_ctrl->hc_mutex);
787 
788 		ret = pciehpc_change_slot_state(slot_p, target_state);
789 		*(ddi_hp_cn_state_t *)result = slot_p->hs_info.cn_state;
790 
791 		mutex_exit(&slot_p->hs_ctrl->hc_mutex);
792 		break;
793 	}
794 	case DDI_HPOP_CN_PROBE:
795 
796 		ret = pciehpc_slot_probe(slot_p);
797 
798 		break;
799 	case DDI_HPOP_CN_UNPROBE:
800 		ret = pciehpc_slot_unprobe(slot_p);
801 
802 		break;
803 	case DDI_HPOP_CN_GET_PROPERTY:
804 		ret = pciehpc_slot_get_property(slot_p,
805 		    (ddi_hp_property_t *)arg, (ddi_hp_property_t *)result);
806 		break;
807 	case DDI_HPOP_CN_SET_PROPERTY:
808 		ret = pciehpc_slot_set_property(slot_p,
809 		    (ddi_hp_property_t *)arg, (ddi_hp_property_t *)result);
810 		break;
811 	default:
812 		ret = DDI_ENOTSUP;
813 		break;
814 	}
815 
816 	return (ret);
817 }
818 
819 /*
820  * Get the current state of the slot from the hw.
821  *
822  * The slot state should have been initialized before this function gets called.
823  */
824 void
825 pciehpc_get_slot_state(pcie_hp_slot_t *slot_p)
826 {
827 	pcie_hp_ctrl_t	*ctrl_p = slot_p->hs_ctrl;
828 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
829 	uint16_t	control, status;
830 	ddi_hp_cn_state_t curr_state = slot_p->hs_info.cn_state;
831 
832 	ASSERT(MUTEX_HELD(&ctrl_p->hc_mutex));
833 
834 	/* read the Slot Control Register */
835 	control = pciehpc_reg_get16(ctrl_p,
836 	    bus_p->bus_pcie_off + PCIE_SLOTCTL);
837 
838 	slot_p->hs_fault_led_state = PCIE_HP_LED_OFF; /* no fault led */
839 	slot_p->hs_active_led_state = PCIE_HP_LED_OFF; /* no active led */
840 
841 	/* read the current Slot Status Register */
842 	status = pciehpc_reg_get16(ctrl_p,
843 	    bus_p->bus_pcie_off + PCIE_SLOTSTS);
844 
845 	/* get POWER led state */
846 	slot_p->hs_power_led_state =
847 	    pciehpc_led_state_to_hpc(pcie_slotctl_pwr_indicator_get(control));
848 
849 	/* get ATTN led state */
850 	slot_p->hs_attn_led_state =
851 	    pciehpc_led_state_to_hpc(pcie_slotctl_attn_indicator_get(control));
852 
853 	if (!(status & PCIE_SLOTSTS_PRESENCE_DETECTED)) {
854 		/* no device present; slot is empty */
855 		slot_p->hs_info.cn_state = DDI_HP_CN_STATE_EMPTY;
856 		return;
857 	}
858 
859 	/* device is present */
860 	slot_p->hs_info.cn_state = DDI_HP_CN_STATE_PRESENT;
861 
862 	/*
863 	 * If we have power control and power control is disabled, then we are
864 	 * merely present. We cannot be POWERED or ENABLED without this being
865 	 * active.
866 	 */
867 	if (ctrl_p->hc_has_pwr && (control & PCIE_SLOTCTL_PWR_CONTROL) != 0) {
868 		return;
869 	}
870 
871 	/*
872 	 * To be in the ENABLED state that means that we have verified that the
873 	 * device is ready to be used. This happens at different points in time
874 	 * right now depending on whether or not we have a power controller and
875 	 * should be consolidated in the future. Our main constraint is that the
876 	 * kernel expects that when something is in the ENABLED state that probe
877 	 * should succeed.
878 	 *
879 	 * For devices with a power controller, this is guaranteed as part of
880 	 * the PRESENT->POWERED transition. For devices without a power
881 	 * controller, we must assume that power is always applied (the slot
882 	 * control register bit for power status is undefined). This means that
883 	 * the POWERED->ENABLED transition point is where this occurs.
884 	 *
885 	 * This is all a long way of justifying the logic below. If our current
886 	 * state is enabled then we will stay in enabled; however, if it is
887 	 * anything else we will go to powered and allow the normal state
888 	 * transition to take effect.
889 	 */
890 	if (curr_state == DDI_HP_CN_STATE_ENABLED) {
891 		slot_p->hs_info.cn_state = curr_state;
892 	} else {
893 		slot_p->hs_info.cn_state = DDI_HP_CN_STATE_POWERED;
894 	}
895 }
896 
897 /*
898  * setup slot name/slot-number info.
899  */
900 void
901 pciehpc_set_slot_name(pcie_hp_ctrl_t *ctrl_p)
902 {
903 	pcie_hp_slot_t	*slot_p = ctrl_p->hc_slots[0];
904 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
905 	uchar_t		*slotname_data;
906 	int		*slotnum;
907 	uint_t		count;
908 	int		len;
909 	int		invalid_slotnum = 0;
910 	uint32_t	slot_capabilities;
911 
912 	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, ctrl_p->hc_dip,
913 	    DDI_PROP_DONTPASS, "physical-slot#", &slotnum, &count) ==
914 	    DDI_PROP_SUCCESS) {
915 		slot_p->hs_phy_slot_num = slotnum[0];
916 		ddi_prop_free(slotnum);
917 	} else {
918 		slot_capabilities = pciehpc_reg_get32(ctrl_p,
919 		    bus_p->bus_pcie_off + PCIE_SLOTCAP);
920 		slot_p->hs_phy_slot_num =
921 		    PCIE_SLOTCAP_PHY_SLOT_NUM(slot_capabilities);
922 	}
923 
924 	/* platform may not have initialized it */
925 	if (!slot_p->hs_phy_slot_num) {
926 		PCIE_DBG("%s#%d: Invalid slot number!\n",
927 		    ddi_driver_name(ctrl_p->hc_dip),
928 		    ddi_get_instance(ctrl_p->hc_dip));
929 		slot_p->hs_phy_slot_num = pciehpc_reg_get8(ctrl_p,
930 		    PCI_BCNF_SECBUS);
931 		invalid_slotnum = 1;
932 	}
933 	slot_p->hs_info.cn_num = slot_p->hs_phy_slot_num;
934 	slot_p->hs_info.cn_num_dpd_on = DDI_HP_CN_NUM_NONE;
935 
936 	/*
937 	 * construct the slot_name:
938 	 *	if "slot-names" property exists then use that name
939 	 *	else if valid slot number exists then it is "pcie<slot-num>".
940 	 *	else it will be "pcie<sec-bus-number>dev0"
941 	 */
942 	if (ddi_getlongprop(DDI_DEV_T_ANY, ctrl_p->hc_dip, DDI_PROP_DONTPASS,
943 	    "slot-names", (caddr_t)&slotname_data, &len) == DDI_PROP_SUCCESS) {
944 		char tmp_name[256];
945 
946 		/*
947 		 * Note: for PCI-E slots, the device number is always 0 so the
948 		 * first (and only) string is the slot name for this slot.
949 		 */
950 		(void) snprintf(tmp_name, sizeof (tmp_name),
951 		    (char *)slotname_data + 4);
952 		slot_p->hs_info.cn_name = ddi_strdup(tmp_name, KM_SLEEP);
953 		kmem_free(slotname_data, len);
954 	} else {
955 		if (invalid_slotnum) {
956 			/* use device number ie. 0 */
957 			slot_p->hs_info.cn_name = ddi_strdup("pcie0",
958 			    KM_SLEEP);
959 		} else {
960 			char tmp_name[256];
961 
962 			(void) snprintf(tmp_name, sizeof (tmp_name), "pcie%d",
963 			    slot_p->hs_phy_slot_num);
964 			slot_p->hs_info.cn_name = ddi_strdup(tmp_name,
965 			    KM_SLEEP);
966 		}
967 	}
968 }
969 
970 /*
971  * Read/Write access to HPC registers. If platform nexus has non-standard
972  * HPC access mechanism then regops functions are used to do reads/writes.
973  */
974 uint8_t
975 pciehpc_reg_get8(pcie_hp_ctrl_t *ctrl_p, uint_t off)
976 {
977 	if (ctrl_p->hc_regops.get != NULL) {
978 		return ((uint8_t)ctrl_p->hc_regops.get(
979 		    ctrl_p->hc_regops.cookie, (off_t)off));
980 	} else {
981 		pcie_bus_t	*bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
982 
983 		return (pci_config_get8(bus_p->bus_cfg_hdl, off));
984 	}
985 }
986 
987 uint16_t
988 pciehpc_reg_get16(pcie_hp_ctrl_t *ctrl_p, uint_t off)
989 {
990 	if (ctrl_p->hc_regops.get != NULL) {
991 		return ((uint16_t)ctrl_p->hc_regops.get(
992 		    ctrl_p->hc_regops.cookie, (off_t)off));
993 	} else {
994 		pcie_bus_t	*bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
995 
996 		return (pci_config_get16(bus_p->bus_cfg_hdl, off));
997 	}
998 }
999 
1000 uint32_t
1001 pciehpc_reg_get32(pcie_hp_ctrl_t *ctrl_p, uint_t off)
1002 {
1003 	if (ctrl_p->hc_regops.get != NULL) {
1004 		return ((uint32_t)ctrl_p->hc_regops.get(
1005 		    ctrl_p->hc_regops.cookie, (off_t)off));
1006 	} else {
1007 		pcie_bus_t	*bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
1008 
1009 		return (pci_config_get32(bus_p->bus_cfg_hdl, off));
1010 	}
1011 }
1012 
1013 void
1014 pciehpc_reg_put8(pcie_hp_ctrl_t *ctrl_p, uint_t off, uint8_t val)
1015 {
1016 	if (ctrl_p->hc_regops.put != NULL) {
1017 		ctrl_p->hc_regops.put(ctrl_p->hc_regops.cookie,
1018 		    (off_t)off, (uint_t)val);
1019 	} else {
1020 		pcie_bus_t	*bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
1021 
1022 		pci_config_put8(bus_p->bus_cfg_hdl, off, val);
1023 	}
1024 }
1025 
1026 void
1027 pciehpc_reg_put16(pcie_hp_ctrl_t *ctrl_p, uint_t off, uint16_t val)
1028 {
1029 	if (ctrl_p->hc_regops.put != NULL) {
1030 		ctrl_p->hc_regops.put(ctrl_p->hc_regops.cookie,
1031 		    (off_t)off, (uint_t)val);
1032 	} else {
1033 		pcie_bus_t	*bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
1034 
1035 		pci_config_put16(bus_p->bus_cfg_hdl, off, val);
1036 	}
1037 }
1038 
1039 void
1040 pciehpc_reg_put32(pcie_hp_ctrl_t *ctrl_p, uint_t off, uint32_t val)
1041 {
1042 	if (ctrl_p->hc_regops.put != NULL) {
1043 		ctrl_p->hc_regops.put(ctrl_p->hc_regops.cookie,
1044 		    (off_t)off, (uint_t)val);
1045 	} else {
1046 		pcie_bus_t	*bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
1047 
1048 		pci_config_put32(bus_p->bus_cfg_hdl, off, val);
1049 	}
1050 }
1051 
1052 /*
1053  * ************************************************************************
1054  * ***	Local functions (called within this file)
1055  * ***	PCIe Native Hotplug mode specific functions
1056  * ************************************************************************
1057  */
1058 
1059 /*
1060  * Initialize HPC hardware, install interrupt handler, etc. It doesn't
1061  * enable hot plug interrupts.
1062  *
1063  * (Note: It is called only from pciehpc_init().)
1064  */
1065 static int
1066 pciehpc_hpc_init(pcie_hp_ctrl_t *ctrl_p)
1067 {
1068 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
1069 	uint16_t	reg;
1070 
1071 	/* read the Slot Control Register */
1072 	reg = pciehpc_reg_get16(ctrl_p,
1073 	    bus_p->bus_pcie_off + PCIE_SLOTCTL);
1074 
1075 	/* disable all interrupts */
1076 	reg &= ~(PCIE_SLOTCTL_INTR_MASK);
1077 	pciehpc_reg_put16(ctrl_p, bus_p->bus_pcie_off +
1078 	    PCIE_SLOTCTL, reg);
1079 
1080 	/* clear any interrupt status bits */
1081 	reg = pciehpc_reg_get16(ctrl_p,
1082 	    bus_p->bus_pcie_off + PCIE_SLOTSTS);
1083 	pciehpc_reg_put16(ctrl_p,
1084 	    bus_p->bus_pcie_off + PCIE_SLOTSTS, reg);
1085 
1086 	return (DDI_SUCCESS);
1087 }
1088 
1089 /*
1090  * Uninitialize HPC hardware, uninstall interrupt handler, etc.
1091  *
1092  * (Note: It is called only from pciehpc_uninit().)
1093  */
1094 static int
1095 pciehpc_hpc_uninit(pcie_hp_ctrl_t *ctrl_p)
1096 {
1097 	/* disable interrupts */
1098 	(void) pciehpc_disable_intr(ctrl_p);
1099 
1100 	return (DDI_SUCCESS);
1101 }
1102 
1103 /*
1104  * Setup slot information for use with DDI HP framework. Per the theory
1105  * statement, this is where we need to go through and look at whether or not we
1106  * have a child and whether or not we want the 1s later timeout to get things
1107  * into a reasonable state.
1108  */
1109 static int
1110 pciehpc_slotinfo_init(pcie_hp_ctrl_t *ctrl_p)
1111 {
1112 	uint32_t	slot_capabilities, link_capabilities;
1113 	pcie_hp_slot_t	*slot_p = ctrl_p->hc_slots[0];
1114 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
1115 	boolean_t	have_child;
1116 
1117 	/*
1118 	 * First we look to see if we have any children at all. If we do, then
1119 	 * we assume that things were initialized prior to our existence as
1120 	 * discussed by state initialization (2).
1121 	 */
1122 	ndi_devi_enter(ctrl_p->hc_dip);
1123 	have_child = ddi_get_child(ctrl_p->hc_dip) != NULL;
1124 	ndi_devi_exit(ctrl_p->hc_dip);
1125 
1126 	mutex_enter(&ctrl_p->hc_mutex);
1127 	/*
1128 	 * setup DDI HP framework slot information structure
1129 	 */
1130 	slot_p->hs_device_num = 0;
1131 
1132 	slot_p->hs_info.cn_type = DDI_HP_CN_TYPE_PCIE;
1133 	slot_p->hs_info.cn_type_str = (ctrl_p->hc_regops.get == NULL) ?
1134 	    PCIE_NATIVE_HP_TYPE : PCIE_PROP_HP_TYPE;
1135 	slot_p->hs_info.cn_child = NULL;
1136 
1137 	slot_p->hs_minor =
1138 	    PCI_MINOR_NUM(ddi_get_instance(ctrl_p->hc_dip),
1139 	    slot_p->hs_device_num);
1140 	slot_p->hs_condition = AP_COND_UNKNOWN;
1141 
1142 	/* read Slot Capabilities Register */
1143 	slot_capabilities = pciehpc_reg_get32(ctrl_p,
1144 	    bus_p->bus_pcie_off + PCIE_SLOTCAP);
1145 
1146 	/* set slot-name/slot-number info */
1147 	pciehpc_set_slot_name(ctrl_p);
1148 
1149 	/* check if Attn Button present */
1150 	ctrl_p->hc_has_attn = (slot_capabilities & PCIE_SLOTCAP_ATTN_BUTTON) ?
1151 	    B_TRUE : B_FALSE;
1152 
1153 	/* check if Manual Retention Latch sensor present */
1154 	ctrl_p->hc_has_mrl = (slot_capabilities & PCIE_SLOTCAP_MRL_SENSOR) ?
1155 	    B_TRUE : B_FALSE;
1156 
1157 	/*
1158 	 * Contrary to what one might expect, not all systems actually have
1159 	 * power control despite having hot-swap capabilities. This is most
1160 	 * commonly due to the Enterprise SSD specification which doesn't call
1161 	 * for power-control in the PCIe native hotplug implementation.
1162 	 */
1163 	ctrl_p->hc_has_pwr = (slot_capabilities &
1164 	    PCIE_SLOTCAP_POWER_CONTROLLER) ? B_TRUE: B_FALSE;
1165 
1166 	/*
1167 	 * PCI-E version 1.1 defines EMI Lock Present bit
1168 	 * in Slot Capabilities register. Check for it.
1169 	 */
1170 	ctrl_p->hc_has_emi_lock = (slot_capabilities &
1171 	    PCIE_SLOTCAP_EMI_LOCK_PRESENT) ? B_TRUE : B_FALSE;
1172 
1173 	link_capabilities = pciehpc_reg_get32(ctrl_p,
1174 	    bus_p->bus_pcie_off + PCIE_LINKCAP);
1175 	ctrl_p->hc_dll_active_rep = (link_capabilities &
1176 	    PCIE_LINKCAP_DLL_ACTIVE_REP_CAPABLE) ? B_TRUE : B_FALSE;
1177 	if (ctrl_p->hc_dll_active_rep)
1178 		cv_init(&slot_p->hs_dll_active_cv, NULL, CV_DRIVER, NULL);
1179 
1180 	/* setup thread for handling ATTN button events */
1181 	if (ctrl_p->hc_has_attn) {
1182 		PCIE_DBG("pciehpc_slotinfo_init: setting up ATTN button event "
1183 		    "handler thread for slot %d\n", slot_p->hs_phy_slot_num);
1184 
1185 		cv_init(&slot_p->hs_attn_btn_cv, NULL, CV_DRIVER, NULL);
1186 		slot_p->hs_attn_btn_pending = B_FALSE;
1187 		slot_p->hs_attn_btn_threadp = thread_create(NULL, 0,
1188 		    pciehpc_attn_btn_handler,
1189 		    (void *)ctrl_p, 0, &p0, TS_RUN, minclsyspri);
1190 		slot_p->hs_attn_btn_thread_exit = B_FALSE;
1191 	}
1192 
1193 	/* get current slot state from the hw */
1194 	slot_p->hs_info.cn_state = DDI_HP_CN_STATE_EMPTY;
1195 	pciehpc_get_slot_state(slot_p);
1196 
1197 	/*
1198 	 * If the kernel has enumerated a device, note that we have performed
1199 	 * the enabled transition.
1200 	 */
1201 	if (slot_p->hs_info.cn_state == DDI_HP_CN_STATE_POWERED &&
1202 	    have_child) {
1203 		slot_p->hs_info.cn_state = DDI_HP_CN_STATE_ENABLED;
1204 	}
1205 
1206 	if (slot_p->hs_info.cn_state >= DDI_HP_CN_STATE_ENABLED)
1207 		slot_p->hs_condition = AP_COND_OK;
1208 	mutex_exit(&ctrl_p->hc_mutex);
1209 
1210 	return (DDI_SUCCESS);
1211 }
1212 
1213 /*ARGSUSED*/
1214 static int
1215 pciehpc_slotinfo_uninit(pcie_hp_ctrl_t *ctrl_p)
1216 {
1217 	pcie_hp_slot_t *slot_p = ctrl_p->hc_slots[0];
1218 
1219 	if (slot_p->hs_attn_btn_threadp != NULL) {
1220 		mutex_enter(&ctrl_p->hc_mutex);
1221 		slot_p->hs_attn_btn_thread_exit = B_TRUE;
1222 		cv_signal(&slot_p->hs_attn_btn_cv);
1223 		PCIE_DBG("pciehpc_slotinfo_uninit: "
1224 		    "waiting for ATTN thread exit\n");
1225 		cv_wait(&slot_p->hs_attn_btn_cv, &ctrl_p->hc_mutex);
1226 		PCIE_DBG("pciehpc_slotinfo_uninit: ATTN thread exit\n");
1227 		cv_destroy(&slot_p->hs_attn_btn_cv);
1228 		slot_p->hs_attn_btn_threadp = NULL;
1229 		mutex_exit(&ctrl_p->hc_mutex);
1230 	}
1231 
1232 	if (ctrl_p->hc_dll_active_rep)
1233 		cv_destroy(&slot_p->hs_dll_active_cv);
1234 	if (slot_p->hs_info.cn_name)
1235 		kmem_free(slot_p->hs_info.cn_name,
1236 		    strlen(slot_p->hs_info.cn_name) + 1);
1237 
1238 	return (DDI_SUCCESS);
1239 }
1240 
1241 /*
1242  * This is the synchronization function that is discussed in the 'State
1243  * Initialization' portion of the theory statement in this file. It is
1244  * responsible for trying to make sure that devices are in a usable state during
1245  * a potentially turbulent start up sequence.
1246  */
1247 static void
1248 pciehpc_state_sync(void *arg)
1249 {
1250 	pciehpc_sync_task_t *sync = arg;
1251 	pcie_hp_ctrl_t *ctrl_p = sync->pst_ctrl;
1252 	dev_info_t *dip = ctrl_p->hc_dip;
1253 	pcie_hp_slot_t *slot_p = ctrl_p->hc_slots[0];
1254 
1255 	mutex_enter(&ctrl_p->hc_mutex);
1256 	if (ctrl_p->hc_startup_sync == TASKQID_INVALID) {
1257 		mutex_exit(&ctrl_p->hc_mutex);
1258 		kmem_free(sync, sizeof (pciehpc_sync_task_t));
1259 		return;
1260 	}
1261 
1262 	if ((ctrl_p->hc_flags & PCIE_HP_SYNC_PENDING) == 0) {
1263 		goto done;
1264 	}
1265 
1266 	cmn_err(CE_NOTE, "pciehpc (%s%d): synchronizing state in slot %s to "
1267 	    "0x%x", ddi_driver_name(dip), ddi_get_instance(dip),
1268 	    slot_p->hs_info.cn_name, sync->pst_targ);
1269 
1270 	ASSERT3U(slot_p->hs_info.cn_state, ==, sync->pst_cur);
1271 
1272 	ctrl_p->hc_flags &= ~PCIE_HP_SYNC_PENDING;
1273 	ctrl_p->hc_flags |= PCIE_HP_SYNC_RUNNING;
1274 	mutex_exit(&ctrl_p->hc_mutex);
1275 
1276 	(void) ndi_hp_state_change_req(dip, slot_p->hs_info.cn_name,
1277 	    sync->pst_targ, DDI_HP_REQ_SYNC);
1278 
1279 	/*
1280 	 * Now that we're done with operating this way, go ahead and clear
1281 	 * things up.
1282 	 */
1283 	mutex_enter(&ctrl_p->hc_mutex);
1284 done:
1285 	ctrl_p->hc_flags &= ~PCIE_HP_SYNC_RUNNING;
1286 	ctrl_p->hc_startup_sync = TASKQID_INVALID;
1287 	mutex_exit(&ctrl_p->hc_mutex);
1288 	kmem_free(sync, sizeof (pciehpc_sync_task_t));
1289 }
1290 
1291 static void
1292 pciehpc_dispatch_state_sync(pcie_hp_ctrl_t *ctrl_p, ddi_hp_cn_state_t targ)
1293 {
1294 	pciehpc_sync_task_t *sync;
1295 	pcie_hp_slot_t *slot_p = ctrl_p->hc_slots[0];
1296 
1297 	ASSERT(MUTEX_HELD(&ctrl_p->hc_mutex));
1298 	sync = kmem_alloc(sizeof (pciehpc_sync_task_t), KM_SLEEP);
1299 	sync->pst_ctrl = ctrl_p;
1300 	sync->pst_targ = targ;
1301 	sync->pst_cur = slot_p->hs_info.cn_state;
1302 
1303 	ctrl_p->hc_flags |= PCIE_HP_SYNC_PENDING;
1304 	ctrl_p->hc_startup_sync = taskq_dispatch(system_taskq,
1305 	    pciehpc_state_sync, sync, TQ_SLEEP);
1306 }
1307 
1308 static void
1309 pciehpc_enable_state_sync_leds(pcie_hp_ctrl_t *ctrl_p)
1310 {
1311 	pcie_hp_slot_t *slot_p = ctrl_p->hc_slots[0];
1312 
1313 	switch (slot_p->hs_info.cn_state) {
1314 	case DDI_HP_CN_STATE_ENABLED:
1315 	case DDI_HP_CN_STATE_POWERED:
1316 		pciehpc_set_led_state(ctrl_p, PCIE_HP_POWER_LED,
1317 		    PCIE_HP_LED_ON);
1318 		pciehpc_set_led_state(ctrl_p, PCIE_HP_ATTN_LED,
1319 		    PCIE_HP_LED_OFF);
1320 		break;
1321 	case DDI_HP_CN_STATE_PRESENT:
1322 	case DDI_HP_CN_STATE_EMPTY:
1323 		pciehpc_set_led_state(ctrl_p, PCIE_HP_POWER_LED,
1324 		    PCIE_HP_LED_OFF);
1325 		pciehpc_set_led_state(ctrl_p, PCIE_HP_ATTN_LED,
1326 		    PCIE_HP_LED_OFF);
1327 		break;
1328 	default:
1329 		dev_err(ctrl_p->hc_dip, CE_PANIC, "encountered invalid "
1330 		    "connector state: 0x%x", slot_p->hs_info.cn_state);
1331 		break;
1332 	}
1333 }
1334 
1335 /*
1336  * We have just enabled interrupts and cleared any changes that may or may not
1337  * have been valid from the hardware perspective. There are a few key
1338  * assumptions that we're making right now as discussed in the theory statement:
1339  *
1340  *  o If we are currently enabled, then we know that we have children and
1341  *    nothing has changed from our init.
1342  *  o Because we have just enabled interrupts, but have not relinquished our
1343  *    exclusion on the controller hardware, nothing else could have come in and
1344  *    started reacting to an actual change.
1345  *  o Even though someone could come and call DDI_HPOP_CN_GET_STATE, that could
1346  *    not transition us to enabled yet.
1347  *  o Because interrupt enable is still called in attach context, we cannot have
1348  *    a user accessing the node and requesting a state change.
1349  *
1350  * Finally there are a few things that we need to be mindful of. We must set any
1351  * updates to the state prior to calling into any request to update the LED
1352  * state as that may rely on getting an async callback.
1353  */
1354 static void
1355 pciehpc_enable_state_sync(pcie_hp_ctrl_t *ctrl_p)
1356 {
1357 	pcie_bus_t *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
1358 	pcie_hp_slot_t *slot_p = ctrl_p->hc_slots[0];
1359 	uint16_t control, status;
1360 	ddi_hp_cn_state_t curr_state, online_targ;
1361 
1362 	online_targ = (pcie_auto_online != 0) ?  DDI_HP_CN_STATE_ENABLED :
1363 	    DDI_HP_CN_STATE_PRESENT;
1364 	ASSERT(MUTEX_HELD(&ctrl_p->hc_mutex));
1365 
1366 	/*
1367 	 * We manually compute the status from a single read of things rather
1368 	 * than go through and use pciehpc_get_slot_state(). This is important
1369 	 * to make sure that we can get hardware in sync with the kernel.
1370 	 */
1371 	curr_state = slot_p->hs_info.cn_state;
1372 	control = pciehpc_reg_get16(ctrl_p, bus_p->bus_pcie_off + PCIE_SLOTCTL);
1373 	status = pciehpc_reg_get16(ctrl_p, bus_p->bus_pcie_off + PCIE_SLOTSTS);
1374 
1375 	if (!(status & PCIE_SLOTSTS_PRESENCE_DETECTED)) {
1376 		switch (curr_state) {
1377 		case DDI_HP_CN_STATE_ENABLED:
1378 			pciehpc_dispatch_state_sync(ctrl_p,
1379 			    DDI_HP_CN_STATE_EMPTY);
1380 			break;
1381 		case DDI_HP_CN_STATE_EMPTY:
1382 		case DDI_HP_CN_STATE_PRESENT:
1383 		case DDI_HP_CN_STATE_POWERED:
1384 			if (ctrl_p->hc_has_pwr &&
1385 			    (control & PCIE_SLOTCTL_PWR_CONTROL) == 0) {
1386 				slot_p->hs_info.cn_state =
1387 				    DDI_HP_CN_STATE_POWERED;
1388 				pciehpc_dispatch_state_sync(ctrl_p,
1389 				    DDI_HP_CN_STATE_EMPTY);
1390 			} else {
1391 				slot_p->hs_info.cn_state =
1392 				    DDI_HP_CN_STATE_EMPTY;
1393 				pciehpc_enable_state_sync_leds(ctrl_p);
1394 			}
1395 			break;
1396 		default:
1397 			dev_err(ctrl_p->hc_dip, CE_PANIC, "encountered invalid "
1398 			    "connector state: 0x%x", curr_state);
1399 			break;
1400 		}
1401 
1402 		return;
1403 	}
1404 
1405 	/*
1406 	 * If we don't have a power controller, don't bother looking at this.
1407 	 * There's nothing we can really do and we'll let the main case attempt
1408 	 * to online this.
1409 	 */
1410 	if (ctrl_p->hc_has_pwr && (control & PCIE_SLOTCTL_PWR_CONTROL) != 0) {
1411 		switch (curr_state) {
1412 		case DDI_HP_CN_STATE_EMPTY:
1413 			pciehpc_dispatch_state_sync(ctrl_p, online_targ);
1414 			break;
1415 		case DDI_HP_CN_STATE_PRESENT:
1416 			if (curr_state == online_targ) {
1417 				pciehpc_enable_state_sync_leds(ctrl_p);
1418 				break;
1419 			}
1420 			pciehpc_dispatch_state_sync(ctrl_p, online_targ);
1421 			break;
1422 		case DDI_HP_CN_STATE_POWERED:
1423 			dev_err(ctrl_p->hc_dip, CE_WARN, "device powered off "
1424 			    "somehow from prior powered state, attempting "
1425 			    "recovery");
1426 			slot_p->hs_info.cn_state = DDI_HP_CN_STATE_PRESENT;
1427 			if (online_targ > DDI_HP_CN_STATE_PRESENT) {
1428 				pciehpc_dispatch_state_sync(ctrl_p,
1429 				    online_targ);
1430 			} else {
1431 				pciehpc_enable_state_sync_leds(ctrl_p);
1432 			}
1433 			break;
1434 		case DDI_HP_CN_STATE_ENABLED:
1435 			/*
1436 			 * This case seems very strange. We had a device that we
1437 			 * enumerated and was online and something that wasn't
1438 			 * us powerd off the slot. This is possibly a
1439 			 * recoverable state, but it seems hard to understand
1440 			 * what the proper path to go here is. While we could
1441 			 * try to unprobe it, it's a real mystery how that
1442 			 * happened and even that path might not be safe. If
1443 			 * this kind of state is actually encountered in the
1444 			 * wild and during this startup window of the device,
1445 			 * then we'll need to figure out how to handle it there.
1446 			 * Odds are it's either a software bug in this driver or
1447 			 * something is going very wrong with hardware and as
1448 			 * such, it's hard to predict what the solution is.
1449 			 */
1450 			dev_err(ctrl_p->hc_dip, CE_PANIC, "device powered off "
1451 			    "somehow from prior enabled state unable to "
1452 			    "recover");
1453 			break;
1454 		default:
1455 			dev_err(ctrl_p->hc_dip, CE_PANIC, "encountered invalid "
1456 			    "connector state: 0x%x", curr_state);
1457 		}
1458 		return;
1459 	}
1460 
1461 	/*
1462 	 * While we should consider checking for a power fault here, if it was
1463 	 * injected just after we cleared everythign as part of interrupt
1464 	 * enable, then we'll get that injected normally and allow that to
1465 	 * happen naturally.
1466 	 */
1467 
1468 	switch (curr_state) {
1469 	case DDI_HP_CN_STATE_ENABLED:
1470 		pciehpc_enable_state_sync_leds(ctrl_p);
1471 		break;
1472 	case DDI_HP_CN_STATE_POWERED:
1473 	case DDI_HP_CN_STATE_EMPTY:
1474 	case DDI_HP_CN_STATE_PRESENT:
1475 		if (curr_state == online_targ) {
1476 			pciehpc_enable_state_sync_leds(ctrl_p);
1477 		} else {
1478 			pciehpc_dispatch_state_sync(ctrl_p, online_targ);
1479 		}
1480 		break;
1481 	default:
1482 		dev_err(ctrl_p->hc_dip, CE_PANIC, "encountered invalid "
1483 		    "connector state: 0x%x", curr_state);
1484 	}
1485 }
1486 
1487 /*
1488  * Enable hot plug interrupts.
1489  * Note: this is only for Native hot plug mode.
1490  */
1491 static int
1492 pciehpc_enable_intr(pcie_hp_ctrl_t *ctrl_p)
1493 {
1494 	pcie_hp_slot_t	*slot_p = ctrl_p->hc_slots[0];
1495 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
1496 	uint16_t	reg;
1497 	uint16_t	intr_mask = PCIE_SLOTCTL_INTR_MASK;
1498 
1499 	mutex_enter(&ctrl_p->hc_mutex);
1500 
1501 	/*
1502 	 * power fault detection interrupt is enabled only
1503 	 * when the slot is powered ON
1504 	 */
1505 	if (slot_p->hs_info.cn_state < DDI_HP_CN_STATE_POWERED)
1506 		intr_mask &= ~PCIE_SLOTCTL_PWR_FAULT_EN;
1507 
1508 	/*
1509 	 * enable interrupt sources but leave the top-level
1510 	 * interrupt disabled. some sources may generate a
1511 	 * spurrious event when they are first enabled.
1512 	 * by leaving the top-level interrupt disabled, those
1513 	 * can be cleared first.
1514 	 */
1515 	reg = pciehpc_reg_get16(ctrl_p,
1516 	    bus_p->bus_pcie_off + PCIE_SLOTCTL);
1517 	pciehpc_reg_put16(ctrl_p,
1518 	    bus_p->bus_pcie_off + PCIE_SLOTCTL,
1519 	    reg | (intr_mask & ~PCIE_SLOTCTL_HP_INTR_EN));
1520 
1521 	/* clear any interrupt status bits */
1522 	reg = pciehpc_reg_get16(ctrl_p,
1523 	    bus_p->bus_pcie_off + PCIE_SLOTSTS);
1524 	pciehpc_reg_put16(ctrl_p,
1525 	    bus_p->bus_pcie_off + PCIE_SLOTSTS, reg);
1526 
1527 	/* enable top-level interrupt */
1528 	reg = pciehpc_reg_get16(ctrl_p,
1529 	    bus_p->bus_pcie_off + PCIE_SLOTCTL);
1530 	pciehpc_reg_put16(ctrl_p,
1531 	    bus_p->bus_pcie_off + PCIE_SLOTCTL,
1532 	    reg | intr_mask);
1533 
1534 	/*
1535 	 * Now, and only now that interrupts are enabled can we go back and
1536 	 * perform state synchronization that is required of the system. This
1537 	 * happens in a few steps. We have previously checked to see if we
1538 	 * should be in the ENABLED or POWERED state. However, it is quite
1539 	 * possible that hardware was left at its PCIe default of power being
1540 	 * enabled, even if no device is present. Because we have interrupts
1541 	 * enabled, if there is a change after this point, then it will be
1542 	 * caught. See the theory statement for more information.
1543 	 */
1544 	pciehpc_enable_state_sync(ctrl_p);
1545 	mutex_exit(&ctrl_p->hc_mutex);
1546 
1547 	return (DDI_SUCCESS);
1548 }
1549 
1550 /*
1551  * Disable hot plug interrupts.
1552  * Note: this is only for Native hot plug mode.
1553  */
1554 static int
1555 pciehpc_disable_intr(pcie_hp_ctrl_t *ctrl_p)
1556 {
1557 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
1558 	uint16_t	reg;
1559 
1560 	/* read the Slot Control Register */
1561 	reg = pciehpc_reg_get16(ctrl_p,
1562 	    bus_p->bus_pcie_off + PCIE_SLOTCTL);
1563 
1564 	/* disable all interrupts */
1565 	reg &= ~(PCIE_SLOTCTL_INTR_MASK);
1566 	pciehpc_reg_put16(ctrl_p, bus_p->bus_pcie_off + PCIE_SLOTCTL, reg);
1567 
1568 	/* clear any interrupt status bits */
1569 	reg = pciehpc_reg_get16(ctrl_p,
1570 	    bus_p->bus_pcie_off + PCIE_SLOTSTS);
1571 	pciehpc_reg_put16(ctrl_p,
1572 	    bus_p->bus_pcie_off + PCIE_SLOTSTS, reg);
1573 
1574 	return (DDI_SUCCESS);
1575 }
1576 
1577 /*
1578  * Allocate a new hotplug controller and slot structures for HPC
1579  * associated with this dip.
1580  */
1581 static pcie_hp_ctrl_t *
1582 pciehpc_create_controller(dev_info_t *dip)
1583 {
1584 	pcie_hp_ctrl_t	*ctrl_p;
1585 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(dip);
1586 
1587 	ctrl_p = kmem_zalloc(sizeof (pcie_hp_ctrl_t), KM_SLEEP);
1588 	ctrl_p->hc_dip = dip;
1589 
1590 	/* Allocate a new slot structure. */
1591 	ctrl_p->hc_slots[0] = kmem_zalloc(sizeof (pcie_hp_slot_t), KM_SLEEP);
1592 	ctrl_p->hc_slots[0]->hs_num = 0;
1593 	ctrl_p->hc_slots[0]->hs_ctrl = ctrl_p;
1594 
1595 	/* Initialize the interrupt mutex */
1596 	mutex_init(&ctrl_p->hc_mutex, NULL, MUTEX_DRIVER,
1597 	    (void *)PCIE_INTR_PRI);
1598 
1599 	/* Initialize synchronization conditional variable */
1600 	cv_init(&ctrl_p->hc_cmd_comp_cv, NULL, CV_DRIVER, NULL);
1601 	ctrl_p->hc_cmd_pending = B_FALSE;
1602 
1603 	bus_p->bus_hp_curr_mode = PCIE_NATIVE_HP_MODE;
1604 	PCIE_SET_HP_CTRL(dip, ctrl_p);
1605 
1606 	return (ctrl_p);
1607 }
1608 
1609 /*
1610  * Remove the HPC controller and slot structures
1611  */
1612 static void
1613 pciehpc_destroy_controller(dev_info_t *dip)
1614 {
1615 	pcie_hp_ctrl_t	*ctrl_p;
1616 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(dip);
1617 
1618 	/* get the soft state structure for this dip */
1619 	if ((ctrl_p = PCIE_GET_HP_CTRL(dip)) == NULL)
1620 		return;
1621 
1622 	PCIE_SET_HP_CTRL(dip, NULL);
1623 	bus_p->bus_hp_curr_mode = PCIE_NONE_HP_MODE;
1624 
1625 	mutex_destroy(&ctrl_p->hc_mutex);
1626 	cv_destroy(&ctrl_p->hc_cmd_comp_cv);
1627 	kmem_free(ctrl_p->hc_slots[0], sizeof (pcie_hp_slot_t));
1628 	kmem_free(ctrl_p, sizeof (pcie_hp_ctrl_t));
1629 }
1630 
1631 /*
1632  * Register the PCI-E hot plug slot with DDI HP framework.
1633  */
1634 static int
1635 pciehpc_register_slot(pcie_hp_ctrl_t *ctrl_p)
1636 {
1637 	pcie_hp_slot_t	*slot_p = ctrl_p->hc_slots[0];
1638 	dev_info_t	*dip = ctrl_p->hc_dip;
1639 
1640 	/* register the slot with DDI HP framework */
1641 	if (ndi_hp_register(dip, &slot_p->hs_info) != NDI_SUCCESS) {
1642 		PCIE_DBG("pciehpc_register_slot() failed to register slot %d\n",
1643 		    slot_p->hs_phy_slot_num);
1644 		return (DDI_FAILURE);
1645 	}
1646 
1647 	pcie_hp_create_occupant_props(dip, makedevice(ddi_driver_major(dip),
1648 	    slot_p->hs_minor), slot_p->hs_device_num);
1649 
1650 	PCIE_DBG("pciehpc_register_slot(): registered slot %d\n",
1651 	    slot_p->hs_phy_slot_num);
1652 
1653 	return (DDI_SUCCESS);
1654 }
1655 
1656 /*
1657  * Unregister the PCI-E hot plug slot from DDI HP framework.
1658  */
1659 static int
1660 pciehpc_unregister_slot(pcie_hp_ctrl_t *ctrl_p)
1661 {
1662 	pcie_hp_slot_t *slot_p = ctrl_p->hc_slots[0];
1663 	dev_info_t	*dip = ctrl_p->hc_dip;
1664 
1665 	pcie_hp_delete_occupant_props(dip, makedevice(ddi_driver_major(dip),
1666 	    slot_p->hs_minor));
1667 
1668 	/* unregister the slot with DDI HP framework */
1669 	if (ndi_hp_unregister(dip, slot_p->hs_info.cn_name) != NDI_SUCCESS) {
1670 		PCIE_DBG("pciehpc_unregister_slot() "
1671 		    "failed to unregister slot %d\n", slot_p->hs_phy_slot_num);
1672 		return (DDI_FAILURE);
1673 	}
1674 
1675 	PCIE_DBG("pciehpc_unregister_slot(): unregistered slot %d\n",
1676 	    slot_p->hs_phy_slot_num);
1677 
1678 	return (DDI_SUCCESS);
1679 }
1680 
1681 static pciehpc_slot_power_t
1682 pciehpc_slot_power_state(pcie_hp_slot_t *slot_p)
1683 {
1684 	pcie_hp_ctrl_t	*ctrl_p = slot_p->hs_ctrl;
1685 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
1686 	uint16_t control, status;
1687 	pciehpc_slot_power_t state = 0;
1688 
1689 	ASSERT(MUTEX_HELD(&ctrl_p->hc_mutex));
1690 
1691 	if (!ctrl_p->hc_has_pwr) {
1692 		return (PSP_NO_CONTROLLER);
1693 	} else {
1694 		state |= PSP_HAS_CONTROLLER;
1695 	}
1696 
1697 	control = pciehpc_reg_get16(ctrl_p, bus_p->bus_pcie_off + PCIE_SLOTCTL);
1698 	status = pciehpc_reg_get16(ctrl_p, bus_p->bus_pcie_off + PCIE_SLOTSTS);
1699 
1700 	if ((control & PCIE_SLOTCTL_PWR_CONTROL) != 0)
1701 		state |= PSP_OFF;
1702 
1703 	if ((status & PCIE_SLOTSTS_PWR_FAULT_DETECTED) != 0)
1704 		state |= PSP_FAULT;
1705 
1706 	return (state);
1707 }
1708 
1709 /*
1710  * Wait for a PCIe slot to be considered active per the PCIe hotplug rules. If
1711  * there is no DLL active reporting capability then we wait up to 1 second and
1712  * just assume it was successful. Regardless of whether or not we have explicit
1713  * power control, the device is still powering on and may not be ready to work.
1714  */
1715 static boolean_t
1716 pciehpc_slot_wait_for_active(pcie_hp_slot_t *slot_p)
1717 {
1718 	pcie_hp_ctrl_t *ctrl_p = slot_p->hs_ctrl;
1719 	pcie_bus_t *bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
1720 
1721 	ASSERT(MUTEX_HELD(&ctrl_p->hc_mutex));
1722 
1723 	if (ctrl_p->hc_dll_active_rep) {
1724 		clock_t deadline;
1725 		uint16_t status;
1726 
1727 		/* wait 1 sec for the DLL State Changed event */
1728 		status = pciehpc_reg_get16(ctrl_p,
1729 		    bus_p->bus_pcie_off + PCIE_LINKSTS);
1730 
1731 		deadline = ddi_get_lbolt() +
1732 		    SEC_TO_TICK(PCIE_HP_DLL_STATE_CHANGE_TIMEOUT);
1733 
1734 		while ((status & PCIE_LINKSTS_DLL_LINK_ACTIVE) == 0 &&
1735 		    ddi_get_lbolt() < deadline) {
1736 			(void) cv_timedwait(&slot_p->hs_dll_active_cv,
1737 			    &ctrl_p->hc_mutex, deadline);
1738 
1739 			/* check Link status */
1740 			status =  pciehpc_reg_get16(ctrl_p,
1741 			    bus_p->bus_pcie_off +
1742 			    PCIE_LINKSTS);
1743 		}
1744 
1745 		if ((status & PCIE_LINKSTS_DLL_LINK_ACTIVE) == 0) {
1746 			return (B_FALSE);
1747 		}
1748 	} else {
1749 		/* wait 1 sec for link to come up */
1750 		delay(drv_usectohz(1000000));
1751 	}
1752 
1753 	return (B_TRUE);
1754 }
1755 
1756 /*
1757  * This takes care of all the logic for trying to verify a slot's state that
1758  * does not have an explicit power controller. If this is a surprise insertion,
1759  * we still need to wait for the data link layer to become active even if we
1760  * don't explicitly control power. We do this in three steps:
1761  *
1762  * 1) Verify the slot is powered at least.
1763  * 2) Wait for the slot to be active.
1764  * 3) Verify the slot is still powered after that.
1765  */
1766 static int
1767 pciehpc_slot_noctrl_active(pcie_hp_slot_t *slot_p, ddi_hp_cn_state_t *result)
1768 {
1769 	pcie_hp_ctrl_t *ctrl_p = slot_p->hs_ctrl;
1770 
1771 	VERIFY3U(ctrl_p->hc_has_pwr, ==, B_FALSE);
1772 	ASSERT(MUTEX_HELD(&ctrl_p->hc_mutex));
1773 
1774 	pciehpc_get_slot_state(slot_p);
1775 	if (slot_p->hs_info.cn_state < DDI_HP_CN_STATE_POWERED) {
1776 		return (DDI_FAILURE);
1777 	}
1778 
1779 	/*
1780 	 * Regardless of whether this worked or failed we must check the slot
1781 	 * state again.
1782 	 */
1783 	if (!pciehpc_slot_wait_for_active(slot_p)) {
1784 		cmn_err(CE_WARN, "pciehpc_slot_poweron_noctrl (slot %d): "
1785 		    "device failed to become active", slot_p->hs_phy_slot_num);
1786 		return (DDI_FAILURE);
1787 	}
1788 	pciehpc_get_slot_state(slot_p);
1789 	*result = slot_p->hs_info.cn_state;
1790 	if (slot_p->hs_info.cn_state >= DDI_HP_CN_STATE_POWERED) {
1791 		return (DDI_SUCCESS);
1792 	} else {
1793 		return (DDI_FAILURE);
1794 	}
1795 }
1796 
1797 /*
1798  * Poweron/Enable the slot.
1799  *
1800  * Note: This function is called by DDI HP framework at kernel context only
1801  *
1802  * We intend for this function to be idempotent.  That is, when we return, if
1803  * the slot we've been asked to turn on has a device present, and has a power
1804  * controller, then a successful return guarantees all of the following,
1805  * regardless of the hardware or software state that existed when called:
1806  *
1807  * 1. The power controller enable bit is clear (asserted).
1808  * 2. If DLL State Change is supported by the bridge, we waited until DLL Active
1809  *    was asserted; otherwise we waited at least one second after the first
1810  *    moment we knew for certain that the power controller was enabled.
1811  * 3. Any power fault that was previously asserted in the status register has
1812  *    been acknowledged and cleared, allowing detection of subsequent faults if
1813  *    supported by hardware.
1814  * 4. The power indicator is on (if it exists).
1815  * 5. The MRL, if it exists, is latched.
1816  *
1817  * If we fail, either this slot has no power control capability or the following
1818  * guarantees are made:
1819  *
1820  * 1. We have attempted to disable the power controller for this slot.
1821  * 2. We have attempted to disable the power indicator for this slot.
1822  *
1823  * In the failure case, *result has undefined contents.  This function does not
1824  * change the contents of slot_p->hs_info.cn_state.  This allows callers to act
1825  * upon the previous software state (preserved by this function), the new
1826  * software state (in *result if successful), and the current hardware state
1827  * which can be obtained via pciehpc_get_slot_state().
1828  */
1829 static int
1830 pciehpc_slot_poweron(pcie_hp_slot_t *slot_p, ddi_hp_cn_state_t *result)
1831 {
1832 	pcie_hp_ctrl_t	*ctrl_p = slot_p->hs_ctrl;
1833 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
1834 	uint16_t	status, control;
1835 
1836 	ASSERT(MUTEX_HELD(&ctrl_p->hc_mutex));
1837 
1838 	/*
1839 	 * If the hardware doesn't have support for a power controller, then
1840 	 * that generally means that power is already on or at the least there
1841 	 * isn't very much else we can do and the PCIe spec says it's the
1842 	 * responsibility of the controller to have turned it on if a device is
1843 	 * present.  We don't care whether a device is present in this case,
1844 	 * though, because we've been asked to turn on power and we know that we
1845 	 * cannot.  Either a device is present and power is already on, in which
1846 	 * case calling code can figure that out, or no device is present and
1847 	 * we'd fail even if we had a controller.  Either way, we still indicate
1848 	 * that is a failure since we can't change it and instead rely on code
1849 	 * executing the actual state machine to figure out how to handle this.
1850 	 */
1851 	if (!ctrl_p->hc_has_pwr) {
1852 		PCIE_DBG("pciehpc_slot_poweron (slot %d): no power control "
1853 		    "capability, but was asked to power on\n",
1854 		    slot_p->hs_phy_slot_num);
1855 		return (DDI_FAILURE);
1856 	}
1857 
1858 	/*
1859 	 * We need the current state of the slot control register to figure out
1860 	 * whether the power controller is enabled already.  Note that this is
1861 	 * not a status bit: it can't tell us whether power is actually on or
1862 	 * off, only what the last control input was.  We also grab the status
1863 	 * register here as we need several bits from it.
1864 	 */
1865 	control = pciehpc_reg_get16(ctrl_p, bus_p->bus_pcie_off + PCIE_SLOTCTL);
1866 	status = pciehpc_reg_get16(ctrl_p, bus_p->bus_pcie_off + PCIE_SLOTSTS);
1867 
1868 	/*
1869 	 * If there's no device present, we need to fail.
1870 	 */
1871 	if (!(status & PCIE_SLOTSTS_PRESENCE_DETECTED)) {
1872 		/* slot is empty */
1873 		PCIE_DBG("pciehpc_slot_poweron (slot %d): slot is empty\n",
1874 		    slot_p->hs_phy_slot_num);
1875 		goto cleanup;
1876 	}
1877 
1878 	/*
1879 	 * If there's an MRL and it's open, we need to fail.
1880 	 */
1881 	if ((ctrl_p->hc_has_mrl) && (status & PCIE_SLOTSTS_MRL_SENSOR_OPEN)) {
1882 		cmn_err(CE_WARN, "pciehpc_slot_poweron (slot %d): MRL switch "
1883 		    "is open", slot_p->hs_phy_slot_num);
1884 		goto cleanup;
1885 	}
1886 
1887 	/*
1888 	 * The power controller is already on, but we're in a state below
1889 	 * POWERED.  This shouldn't happen, but there are any number of ways
1890 	 * that it can; we simply note this if debugging and move on.
1891 	 */
1892 	if ((control & PCIE_SLOTCTL_PWR_CONTROL) == 0 &&
1893 	    slot_p->hs_info.cn_state < DDI_HP_CN_STATE_POWERED) {
1894 		PCIE_DBG("pciehpc_slot_poweron (slot %d): controller is "
1895 		    "already enabled in SW state %d; continuing\n",
1896 		    slot_p->hs_phy_slot_num, slot_p->hs_info.cn_state);
1897 		goto alreadyon;
1898 	}
1899 
1900 	/*
1901 	 * The power controller has been turned off (which doesn't mean it *is*
1902 	 * off), but software thinks it's on.  This is pretty bad, and we
1903 	 * probably need to consider doing something here to reset the state
1904 	 * machine because upper layers are likely to be confused.  We will
1905 	 * nevertheless turn on the controller and hope the right things happen
1906 	 * above us.
1907 	 */
1908 	if ((control & PCIE_SLOTCTL_PWR_CONTROL) != 0 &&
1909 	    slot_p->hs_info.cn_state >= DDI_HP_CN_STATE_POWERED) {
1910 		cmn_err(CE_WARN, "pciehpc_slot_poweron (slot %d): SW state is "
1911 		    "already %d but power controller is disabled; continuing",
1912 		    slot_p->hs_phy_slot_num, slot_p->hs_info.cn_state);
1913 	}
1914 
1915 	/*
1916 	 * Enable power to the slot involves:
1917 	 *	1. Set power LED to blink and ATTN led to OFF.
1918 	 *	2. Set power control ON in Slot Control Reigster and
1919 	 *	   wait for Command Completed Interrupt or 1 sec timeout.
1920 	 *	3. If Data Link Layer State Changed events are supported
1921 	 *	   then wait for the event to indicate Data Layer Link
1922 	 *	   is active. The time out value for this event is 1 second.
1923 	 *	   This is specified in PCI-E version 1.1.
1924 	 *	4. Set power LED to be ON.
1925 	 */
1926 
1927 	/* 1. set power LED to blink & ATTN led to OFF */
1928 	pciehpc_set_led_state(ctrl_p, PCIE_HP_POWER_LED, PCIE_HP_LED_BLINK);
1929 
1930 alreadyon:
1931 	pciehpc_set_led_state(ctrl_p, PCIE_HP_ATTN_LED, PCIE_HP_LED_OFF);
1932 
1933 	/* 2. set power control to ON */
1934 	control =  pciehpc_reg_get16(ctrl_p,
1935 	    bus_p->bus_pcie_off + PCIE_SLOTCTL);
1936 	control &= ~PCIE_SLOTCTL_PWR_CONTROL;
1937 	pciehpc_issue_hpc_command(ctrl_p, control);
1938 
1939 	/* 3. wait for DLL State Change event, if it's supported */
1940 	if (!pciehpc_slot_wait_for_active(slot_p))
1941 		goto cleanup;
1942 
1943 	/* check power is really turned ON */
1944 	control = pciehpc_reg_get16(ctrl_p,
1945 	    bus_p->bus_pcie_off + PCIE_SLOTCTL);
1946 
1947 	if (control & PCIE_SLOTCTL_PWR_CONTROL) {
1948 		PCIE_DBG("pciehpc_slot_poweron (slot %d): power controller "
1949 		    "enable was disabled autonomously after SW enable",
1950 		    slot_p->hs_phy_slot_num);
1951 
1952 		goto cleanup;
1953 	}
1954 
1955 	/* clear power fault status */
1956 	status = pciehpc_reg_get16(ctrl_p,
1957 	    bus_p->bus_pcie_off + PCIE_SLOTSTS);
1958 	status |= PCIE_SLOTSTS_PWR_FAULT_DETECTED;
1959 	pciehpc_reg_put16(ctrl_p, bus_p->bus_pcie_off + PCIE_SLOTSTS,
1960 	    status);
1961 
1962 	/* enable power fault detection interrupt */
1963 	control |= PCIE_SLOTCTL_PWR_FAULT_EN;
1964 	pciehpc_issue_hpc_command(ctrl_p, control);
1965 
1966 	/* 4. Set power LED to be ON */
1967 	pciehpc_set_led_state(ctrl_p, PCIE_HP_POWER_LED, PCIE_HP_LED_ON);
1968 
1969 	/* if EMI is present, turn it ON */
1970 	if (ctrl_p->hc_has_emi_lock) {
1971 		status = pciehpc_reg_get16(ctrl_p,
1972 		    bus_p->bus_pcie_off + PCIE_SLOTSTS);
1973 
1974 		if (!(status & PCIE_SLOTSTS_EMI_LOCK_SET)) {
1975 			control = pciehpc_reg_get16(ctrl_p,
1976 			    bus_p->bus_pcie_off + PCIE_SLOTCTL);
1977 			control |= PCIE_SLOTCTL_EMI_LOCK_CONTROL;
1978 			pciehpc_issue_hpc_command(ctrl_p, control);
1979 
1980 			/* wait 1 sec after toggling the state of EMI lock */
1981 			delay(drv_usectohz(1000000));
1982 		}
1983 	}
1984 
1985 	*result = slot_p->hs_info.cn_state = DDI_HP_CN_STATE_POWERED;
1986 
1987 	return (DDI_SUCCESS);
1988 
1989 cleanup:
1990 	control = pciehpc_reg_get16(ctrl_p,
1991 	    bus_p->bus_pcie_off + PCIE_SLOTCTL);
1992 
1993 	/* if power is ON, set power control to OFF */
1994 	if ((control & PCIE_SLOTCTL_PWR_CONTROL) == 0) {
1995 		control |= PCIE_SLOTCTL_PWR_CONTROL;
1996 		pciehpc_issue_hpc_command(ctrl_p, control);
1997 	}
1998 
1999 	/* set power led to OFF XXX what if HW/FW refused to turn off? */
2000 	pciehpc_set_led_state(ctrl_p, PCIE_HP_POWER_LED, PCIE_HP_LED_OFF);
2001 
2002 	return (DDI_FAILURE);
2003 }
2004 
2005 /*
2006  * All the same considerations apply to poweroff; see notes above.
2007  */
2008 static int
2009 pciehpc_slot_poweroff(pcie_hp_slot_t *slot_p, ddi_hp_cn_state_t *result)
2010 {
2011 	pcie_hp_ctrl_t	*ctrl_p = slot_p->hs_ctrl;
2012 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
2013 	uint16_t	status, control;
2014 
2015 	ASSERT(MUTEX_HELD(&ctrl_p->hc_mutex));
2016 
2017 	/*
2018 	 * Some devices do not have a power controller. In such cases we need to
2019 	 * fail any request to power it off. If a device is being pulled, the
2020 	 * state will generally have automatically been updated; however, if
2021 	 * someone is asking for us to do something via an explicit request,
2022 	 * then this will fail.
2023 	 */
2024 	if (!ctrl_p->hc_has_pwr) {
2025 		PCIE_DBG("pciehpc_slot_poweroff (slot %d): no power control "
2026 		    "capability, but was asked to power off\n",
2027 		    slot_p->hs_phy_slot_num);
2028 		return (DDI_ENOTSUP);
2029 	}
2030 
2031 	/*
2032 	 * SW thinks the slot is already powered off.  Note this unexpected
2033 	 * condition and continue.
2034 	 */
2035 	if (slot_p->hs_info.cn_state < DDI_HP_CN_STATE_POWERED) {
2036 		PCIE_DBG("pciehpc_slot_poweroff (slot %d): SW state is "
2037 		    "already %d; continuing\n",
2038 		    slot_p->hs_phy_slot_num, slot_p->hs_info.cn_state);
2039 	}
2040 
2041 	control = pciehpc_reg_get16(ctrl_p, bus_p->bus_pcie_off + PCIE_SLOTCTL);
2042 	status = pciehpc_reg_get16(ctrl_p, bus_p->bus_pcie_off + PCIE_SLOTSTS);
2043 
2044 	/*
2045 	 * The power controller has been turned off (which doesn't mean it *is*
2046 	 * off), but software thinks it's on.  Note this unexpected condition
2047 	 * for debugging and continue; we'll do what we can to get the state
2048 	 * machines back in sync.
2049 	 */
2050 	if ((control & PCIE_SLOTCTL_PWR_CONTROL) != 0 &&
2051 	    slot_p->hs_info.cn_state >= DDI_HP_CN_STATE_POWERED) {
2052 		cmn_err(CE_WARN, "pciehpc_slot_poweroff (slot %d): SW state is "
2053 		    "%d but power controller is already disabled; continuing",
2054 		    slot_p->hs_phy_slot_num, slot_p->hs_info.cn_state);
2055 		goto alreadyoff;
2056 	}
2057 
2058 	if (!(status & PCIE_SLOTSTS_PRESENCE_DETECTED)) {
2059 		PCIE_DBG("pciehpc_slot_poweroff (slot %d): powering off "
2060 		    "empty slot\n", slot_p->hs_phy_slot_num);
2061 	}
2062 
2063 	/*
2064 	 * Disable power to the slot involves:
2065 	 *	1. Set power LED to blink.
2066 	 *	2. Set power control OFF in Slot Control Reigster and
2067 	 *	   wait for Command Completed Interrupt or 1 sec timeout.
2068 	 *	3. Set POWER led and ATTN led to be OFF.
2069 	 */
2070 
2071 	/* 1. set power LED to blink */
2072 	pciehpc_set_led_state(ctrl_p, PCIE_HP_POWER_LED, PCIE_HP_LED_BLINK);
2073 
2074 alreadyoff:
2075 	/* disable power fault detection interrupt */
2076 	control = pciehpc_reg_get16(ctrl_p,
2077 	    bus_p->bus_pcie_off + PCIE_SLOTCTL);
2078 	control &= ~PCIE_SLOTCTL_PWR_FAULT_EN;
2079 	pciehpc_issue_hpc_command(ctrl_p, control);
2080 
2081 	/* 2. set power control to OFF */
2082 	control = pciehpc_reg_get16(ctrl_p,
2083 	    bus_p->bus_pcie_off + PCIE_SLOTCTL);
2084 	control |= PCIE_SLOTCTL_PWR_CONTROL;
2085 	pciehpc_issue_hpc_command(ctrl_p, control);
2086 
2087 	/*
2088 	 * Make sure our control input has been acknowledged.  Some
2089 	 * implementations may clear the control bit if the power controller
2090 	 * couldn't be disabled for some reasons, or if firmware decided to
2091 	 * disallow our command.
2092 	 */
2093 	control = pciehpc_reg_get16(ctrl_p,
2094 	    bus_p->bus_pcie_off + PCIE_SLOTCTL);
2095 	if ((control & PCIE_SLOTCTL_PWR_CONTROL) == 0) {
2096 		/*
2097 		 * Well, this is unfortunate: we couldn't turn power off.
2098 		 * XXX Should we turn on the ATTN indicator?  For now we just
2099 		 * log a warning and fail.
2100 		 */
2101 		cmn_err(CE_WARN, "pciehpc_slot_poweroff (slot %d): power "
2102 		    "controller completed our disable command but is still "
2103 		    "enabled", slot_p->hs_phy_slot_num);
2104 		pciehpc_set_led_state(ctrl_p, PCIE_HP_POWER_LED,
2105 		    PCIE_HP_LED_ON);
2106 
2107 		return (DDI_FAILURE);
2108 	}
2109 
2110 	/* 3. Set power LED to be OFF */
2111 	pciehpc_set_led_state(ctrl_p, PCIE_HP_POWER_LED, PCIE_HP_LED_OFF);
2112 	pciehpc_set_led_state(ctrl_p, PCIE_HP_ATTN_LED, PCIE_HP_LED_OFF);
2113 
2114 	/* if EMI is present, turn it OFF */
2115 	if (ctrl_p->hc_has_emi_lock) {
2116 		status =  pciehpc_reg_get16(ctrl_p,
2117 		    bus_p->bus_pcie_off + PCIE_SLOTSTS);
2118 
2119 		if (status & PCIE_SLOTSTS_EMI_LOCK_SET) {
2120 			control =  pciehpc_reg_get16(ctrl_p,
2121 			    bus_p->bus_pcie_off + PCIE_SLOTCTL);
2122 			control |= PCIE_SLOTCTL_EMI_LOCK_CONTROL;
2123 			pciehpc_issue_hpc_command(ctrl_p, control);
2124 
2125 			/* wait 1 sec after toggling the state of EMI lock */
2126 			delay(drv_usectohz(1000000));
2127 		}
2128 	}
2129 
2130 	/* get the current state of the slot */
2131 	pciehpc_get_slot_state(slot_p);
2132 
2133 	*result = slot_p->hs_info.cn_state;
2134 
2135 	return (DDI_SUCCESS);
2136 }
2137 
2138 /*
2139  * pciehpc_slot_probe()
2140  *
2141  * Probe the slot.
2142  *
2143  * Note: This function is called by DDI HP framework at kernel context only
2144  */
2145 /*ARGSUSED*/
2146 static int
2147 pciehpc_slot_probe(pcie_hp_slot_t *slot_p)
2148 {
2149 	pcie_hp_ctrl_t	*ctrl_p = slot_p->hs_ctrl;
2150 	int		ret = DDI_SUCCESS;
2151 
2152 	mutex_enter(&ctrl_p->hc_mutex);
2153 
2154 	/* get the current state of the slot */
2155 	pciehpc_get_slot_state(slot_p);
2156 
2157 	/*
2158 	 * Probe a given PCIe Hotplug Connection (CN).
2159 	 */
2160 	PCIE_DISABLE_ERRORS(ctrl_p->hc_dip);
2161 	ret = pcie_hp_probe(slot_p);
2162 
2163 	if (ret != DDI_SUCCESS) {
2164 		PCIE_DBG("pciehpc_slot_probe() failed\n");
2165 
2166 		/* turn the ATTN led ON for configure failure */
2167 		pciehpc_set_led_state(ctrl_p, PCIE_HP_ATTN_LED, PCIE_HP_LED_ON);
2168 
2169 		/* if power to the slot is still on then set Power led to ON */
2170 		if (slot_p->hs_info.cn_state >= DDI_HP_CN_STATE_POWERED)
2171 			pciehpc_set_led_state(ctrl_p, PCIE_HP_POWER_LED,
2172 			    PCIE_HP_LED_ON);
2173 
2174 		mutex_exit(&ctrl_p->hc_mutex);
2175 		return (DDI_FAILURE);
2176 	}
2177 
2178 	PCIE_ENABLE_ERRORS(ctrl_p->hc_dip);
2179 
2180 	/* get the current state of the slot */
2181 	pciehpc_get_slot_state(slot_p);
2182 
2183 	mutex_exit(&ctrl_p->hc_mutex);
2184 	return (DDI_SUCCESS);
2185 }
2186 
2187 /*
2188  * pciehpc_slot_unprobe()
2189  *
2190  * Unprobe the slot.
2191  *
2192  * Note: This function is called by DDI HP framework at kernel context only
2193  */
2194 /*ARGSUSED*/
2195 static int
2196 pciehpc_slot_unprobe(pcie_hp_slot_t *slot_p)
2197 {
2198 	pcie_hp_ctrl_t	*ctrl_p = slot_p->hs_ctrl;
2199 	int		ret;
2200 
2201 	mutex_enter(&ctrl_p->hc_mutex);
2202 
2203 	/* get the current state of the slot */
2204 	pciehpc_get_slot_state(slot_p);
2205 
2206 	/*
2207 	 * Unprobe a given PCIe Hotplug Connection (CN).
2208 	 */
2209 	PCIE_DISABLE_ERRORS(ctrl_p->hc_dip);
2210 	ret = pcie_hp_unprobe(slot_p);
2211 
2212 	if (ret != DDI_SUCCESS) {
2213 		PCIE_DBG("pciehpc_slot_unprobe() failed\n");
2214 
2215 		/* if power to the slot is still on then set Power led to ON */
2216 		if (slot_p->hs_info.cn_state >= DDI_HP_CN_STATE_POWERED)
2217 			pciehpc_set_led_state(ctrl_p, PCIE_HP_POWER_LED,
2218 			    PCIE_HP_LED_ON);
2219 
2220 		PCIE_ENABLE_ERRORS(ctrl_p->hc_dip);
2221 
2222 		mutex_exit(&ctrl_p->hc_mutex);
2223 		return (DDI_FAILURE);
2224 	}
2225 
2226 	/* get the current state of the slot */
2227 	pciehpc_get_slot_state(slot_p);
2228 
2229 	mutex_exit(&ctrl_p->hc_mutex);
2230 	return (DDI_SUCCESS);
2231 }
2232 
2233 static int
2234 pciehpc_upgrade_slot_state(pcie_hp_slot_t *slot_p,
2235     ddi_hp_cn_state_t target_state)
2236 {
2237 	ddi_hp_cn_state_t curr_state;
2238 	int rv = DDI_SUCCESS;
2239 	pcie_hp_ctrl_t *ctrl_p = slot_p->hs_ctrl;
2240 
2241 	if (target_state > DDI_HP_CN_STATE_ENABLED) {
2242 		return (DDI_EINVAL);
2243 	}
2244 
2245 	curr_state = slot_p->hs_info.cn_state;
2246 	while ((curr_state < target_state) && (rv == DDI_SUCCESS)) {
2247 
2248 		switch (curr_state) {
2249 		case DDI_HP_CN_STATE_EMPTY:
2250 			/*
2251 			 * From EMPTY to PRESENT, just check the hardware
2252 			 * slot state.
2253 			 */
2254 			pciehpc_get_slot_state(slot_p);
2255 			curr_state = slot_p->hs_info.cn_state;
2256 			if (curr_state < DDI_HP_CN_STATE_PRESENT)
2257 				rv = DDI_FAILURE;
2258 			break;
2259 		case DDI_HP_CN_STATE_PRESENT:
2260 			if (!ctrl_p->hc_has_pwr) {
2261 				pciehpc_get_slot_state(slot_p);
2262 				curr_state = slot_p->hs_info.cn_state;
2263 				if (curr_state < DDI_HP_CN_STATE_POWERED)
2264 					rv = DDI_FAILURE;
2265 				break;
2266 			}
2267 
2268 			rv = (ctrl_p->hc_ops.poweron_hpc_slot)(slot_p,
2269 			    &curr_state);
2270 
2271 			break;
2272 		case DDI_HP_CN_STATE_POWERED:
2273 			/*
2274 			 * If we're performing a synchronization, then the
2275 			 * POWERED state isn't quite accurate. Power is enabled,
2276 			 * but we haven't really done all the actual steps that
2277 			 * are expected. As such, we will do another call to
2278 			 * power on and if successful, then do the change to
2279 			 * ENABLED. If the call to power on did not work, then
2280 			 * we must transition back to PRESENT. If there is no
2281 			 * power controller, then this is a no-op.
2282 			 */
2283 			if ((ctrl_p->hc_flags & PCIE_HP_SYNC_RUNNING) != 0 &&
2284 			    ctrl_p->hc_has_pwr) {
2285 				rv = (ctrl_p->hc_ops.poweron_hpc_slot)(slot_p,
2286 				    &curr_state);
2287 				if (rv != DDI_SUCCESS) {
2288 					slot_p->hs_info.cn_state =
2289 					    DDI_HP_CN_STATE_PRESENT;
2290 					break;
2291 				}
2292 			} else if (!ctrl_p->hc_has_pwr) {
2293 				rv = pciehpc_slot_noctrl_active(slot_p,
2294 				    &curr_state);
2295 				if (rv != DDI_SUCCESS)
2296 					break;
2297 			}
2298 
2299 			curr_state = slot_p->hs_info.cn_state =
2300 			    DDI_HP_CN_STATE_ENABLED;
2301 			break;
2302 		default:
2303 			/* should never reach here */
2304 			ASSERT("unknown devinfo state");
2305 		}
2306 	}
2307 
2308 	return (rv);
2309 }
2310 
2311 static int
2312 pciehpc_downgrade_slot_state(pcie_hp_slot_t *slot_p,
2313     ddi_hp_cn_state_t target_state)
2314 {
2315 	ddi_hp_cn_state_t curr_state;
2316 	int rv = DDI_SUCCESS;
2317 
2318 
2319 	curr_state = slot_p->hs_info.cn_state;
2320 	while ((curr_state > target_state) && (rv == DDI_SUCCESS)) {
2321 
2322 		switch (curr_state) {
2323 		case DDI_HP_CN_STATE_PRESENT:
2324 			/*
2325 			 * From PRESENT to EMPTY, just check hardware slot
2326 			 * state.
2327 			 */
2328 			pciehpc_get_slot_state(slot_p);
2329 			curr_state = slot_p->hs_info.cn_state;
2330 			if (curr_state >= DDI_HP_CN_STATE_PRESENT)
2331 				rv = DDI_FAILURE;
2332 			break;
2333 		case DDI_HP_CN_STATE_POWERED:
2334 			/*
2335 			 * If the device doesn't have power control then we
2336 			 * cannot ask it to power off the slot. However, a
2337 			 * device may have been removed and therefore we need to
2338 			 * manually check if the device was removed by getting
2339 			 * the state. Otherwise we let power control do
2340 			 * everything.
2341 			 */
2342 			if (!slot_p->hs_ctrl->hc_has_pwr) {
2343 				pciehpc_get_slot_state(slot_p);
2344 				curr_state = slot_p->hs_info.cn_state;
2345 				if (curr_state >= DDI_HP_CN_STATE_POWERED)
2346 					rv = DDI_FAILURE;
2347 				break;
2348 			}
2349 
2350 			rv = (slot_p->hs_ctrl->hc_ops.poweroff_hpc_slot)(
2351 			    slot_p, &curr_state);
2352 
2353 			break;
2354 		case DDI_HP_CN_STATE_ENABLED:
2355 			curr_state = slot_p->hs_info.cn_state =
2356 			    DDI_HP_CN_STATE_POWERED;
2357 
2358 			break;
2359 		default:
2360 			/* should never reach here */
2361 			ASSERT("unknown devinfo state");
2362 		}
2363 	}
2364 
2365 	return (rv);
2366 }
2367 
2368 /* Change slot state to a target state */
2369 static int
2370 pciehpc_change_slot_state(pcie_hp_slot_t *slot_p,
2371     ddi_hp_cn_state_t target_state)
2372 {
2373 	ddi_hp_cn_state_t curr_state;
2374 	pciehpc_slot_power_t pwr_state;
2375 	boolean_t sync = B_FALSE;
2376 	int rv = 0;
2377 
2378 	ASSERT(MUTEX_HELD(&slot_p->hs_ctrl->hc_mutex));
2379 
2380 	pciehpc_get_slot_state(slot_p);
2381 	curr_state = slot_p->hs_info.cn_state;
2382 	pwr_state = pciehpc_slot_power_state(slot_p);
2383 
2384 	/*
2385 	 * We've been asked to change the slot state. If we still had an
2386 	 * outstanding synchronization task, then we should remove that because
2387 	 * we've had an explicit state change. In essence we take over that sync
2388 	 * and note that it's running.
2389 	 */
2390 	if ((slot_p->hs_ctrl->hc_flags & PCIE_HP_SYNC_PENDING) != 0 &&
2391 	    slot_p->hs_info.cn_state == DDI_HP_CN_STATE_POWERED) {
2392 		sync = B_TRUE;
2393 		slot_p->hs_ctrl->hc_flags |= PCIE_HP_SYNC_RUNNING;
2394 	}
2395 	slot_p->hs_ctrl->hc_flags &= ~PCIE_HP_SYNC_PENDING;
2396 
2397 	/*
2398 	 * We need to see whether the power controller state (if there is one)
2399 	 * matches the DDI slot state.  If not, it may be necessary to perform
2400 	 * the upgrade or downgrade procedure even if the DDI slot state matches
2401 	 * the target already.  We'll make sure that curr_state reflects the
2402 	 * state of the power controller with respect to our desired target
2403 	 * state, even if the slot is empty.
2404 	 */
2405 	if (pwr_state == PSP_NO_CONTROLLER)
2406 		goto skip_sync;
2407 
2408 	switch (target_state) {
2409 	case DDI_HP_CN_STATE_EMPTY:
2410 	case DDI_HP_CN_STATE_PRESENT:
2411 		/*
2412 		 * Power controller is on but software doesn't know that, and
2413 		 * wants to enter a state in which power should be off.
2414 		 */
2415 		if ((pwr_state & PSP_OFF) == 0 &&
2416 		    curr_state < DDI_HP_CN_STATE_POWERED) {
2417 			curr_state = DDI_HP_CN_STATE_POWERED;
2418 		}
2419 		break;
2420 	case DDI_HP_CN_STATE_POWERED:
2421 	case DDI_HP_CN_STATE_ENABLED:
2422 		/*
2423 		 * Power controller is off but software doesn't know that, and
2424 		 * wants to enter a state in which power should be on.
2425 		 */
2426 		if ((pwr_state & PSP_OFF) != 0 &&
2427 		    curr_state >= DDI_HP_CN_STATE_POWERED) {
2428 			curr_state = DDI_HP_CN_STATE_PRESENT;
2429 		}
2430 		break;
2431 	default:
2432 		break;
2433 	}
2434 
2435 	slot_p->hs_info.cn_state = curr_state;
2436 
2437 skip_sync:
2438 	if (curr_state == target_state) {
2439 		return (DDI_SUCCESS);
2440 	}
2441 
2442 	if (curr_state < target_state) {
2443 		rv = pciehpc_upgrade_slot_state(slot_p, target_state);
2444 	} else {
2445 		rv = pciehpc_downgrade_slot_state(slot_p, target_state);
2446 	}
2447 
2448 	if (sync) {
2449 		slot_p->hs_ctrl->hc_flags &= ~PCIE_HP_SYNC_RUNNING;
2450 	}
2451 
2452 	return (rv);
2453 }
2454 
2455 int
2456 pciehpc_slot_get_property(pcie_hp_slot_t *slot_p, ddi_hp_property_t *arg,
2457     ddi_hp_property_t *rval)
2458 {
2459 	ddi_hp_property_t request, result;
2460 #ifdef _SYSCALL32_IMPL
2461 	ddi_hp_property32_t request32, result32;
2462 #endif
2463 	pcie_hp_ctrl_t	*ctrl_p = slot_p->hs_ctrl;
2464 	nvlist_t	*prop_list;
2465 	nvlist_t	*prop_rlist; /* nvlist for return values */
2466 	nvpair_t	*prop_pair;
2467 	char		*name, *value;
2468 	int		ret = DDI_SUCCESS;
2469 	int		i, n;
2470 	boolean_t	get_all_prop = B_FALSE;
2471 
2472 	if (get_udatamodel() == DATAMODEL_NATIVE) {
2473 		if (copyin(arg, &request, sizeof (ddi_hp_property_t)) ||
2474 		    copyin(rval, &result, sizeof (ddi_hp_property_t)))
2475 			return (DDI_FAILURE);
2476 	}
2477 #ifdef _SYSCALL32_IMPL
2478 	else {
2479 		bzero(&request, sizeof (request));
2480 		bzero(&result, sizeof (result));
2481 		if (copyin(arg, &request32, sizeof (ddi_hp_property32_t)) ||
2482 		    copyin(rval, &result32, sizeof (ddi_hp_property32_t)))
2483 			return (DDI_FAILURE);
2484 		request.nvlist_buf = (char *)(uintptr_t)request32.nvlist_buf;
2485 		request.buf_size = request32.buf_size;
2486 		result.nvlist_buf = (char *)(uintptr_t)result32.nvlist_buf;
2487 		result.buf_size = result32.buf_size;
2488 	}
2489 #endif
2490 
2491 	if ((ret = pcie_copyin_nvlist(request.nvlist_buf, request.buf_size,
2492 	    &prop_list)) != DDI_SUCCESS)
2493 		return (ret);
2494 
2495 	if (nvlist_alloc(&prop_rlist, NV_UNIQUE_NAME, 0)) {
2496 		ret = DDI_ENOMEM;
2497 		goto get_prop_cleanup;
2498 	}
2499 
2500 	/* check whether the requested property is "all" or "help" */
2501 	prop_pair = nvlist_next_nvpair(prop_list, NULL);
2502 	if (prop_pair && !nvlist_next_nvpair(prop_list, prop_pair)) {
2503 		name = nvpair_name(prop_pair);
2504 		n = sizeof (pciehpc_props) / sizeof (pciehpc_prop_t);
2505 
2506 		if (strcmp(name, PCIEHPC_PROP_ALL) == 0) {
2507 			(void) nvlist_remove_all(prop_list, PCIEHPC_PROP_ALL);
2508 
2509 			/*
2510 			 * Add all properties into the request list, so that we
2511 			 * will get the values in the following for loop.
2512 			 */
2513 			for (i = 0; i < n; i++) {
2514 				if (nvlist_add_string(prop_list,
2515 				    pciehpc_props[i].prop_name, "") != 0) {
2516 					ret = DDI_FAILURE;
2517 					goto get_prop_cleanup1;
2518 				}
2519 			}
2520 			get_all_prop = B_TRUE;
2521 		} else if (strcmp(name, PCIEHPC_PROP_HELP) == 0) {
2522 			/*
2523 			 * Empty the request list, and add help strings into the
2524 			 * return list. We will pass the following for loop.
2525 			 */
2526 			(void) nvlist_remove_all(prop_list, PCIEHPC_PROP_HELP);
2527 
2528 			for (i = 0; i < n; i++) {
2529 				if (nvlist_add_string(prop_rlist,
2530 				    pciehpc_props[i].prop_name,
2531 				    pciehpc_props[i].prop_value) != 0) {
2532 					ret = DDI_FAILURE;
2533 					goto get_prop_cleanup1;
2534 				}
2535 			}
2536 		}
2537 	}
2538 
2539 	mutex_enter(&ctrl_p->hc_mutex);
2540 
2541 	/* get the current slot state */
2542 	pciehpc_get_slot_state(slot_p);
2543 
2544 	/* for each requested property, get the value and add it to nvlist */
2545 	prop_pair = NULL;
2546 	while ((prop_pair = nvlist_next_nvpair(prop_list, prop_pair)) != NULL) {
2547 		name = nvpair_name(prop_pair);
2548 		value = NULL;
2549 
2550 		if (strcmp(name, PCIEHPC_PROP_LED_FAULT) == 0) {
2551 			value = pcie_led_state_text(
2552 			    slot_p->hs_fault_led_state);
2553 		} else if (strcmp(name, PCIEHPC_PROP_LED_POWER) == 0) {
2554 			value = pcie_led_state_text(
2555 			    slot_p->hs_power_led_state);
2556 		} else if (strcmp(name, PCIEHPC_PROP_LED_ATTN) == 0) {
2557 			value = pcie_led_state_text(
2558 			    slot_p->hs_attn_led_state);
2559 		} else if (strcmp(name, PCIEHPC_PROP_LED_ACTIVE) == 0) {
2560 			value = pcie_led_state_text(
2561 			    slot_p->hs_active_led_state);
2562 		} else if (strcmp(name, PCIEHPC_PROP_CARD_TYPE) == 0) {
2563 			ddi_acc_handle_t handle;
2564 			dev_info_t	*cdip;
2565 			uint8_t		prog_class, base_class, sub_class;
2566 			size_t		i;
2567 
2568 			mutex_exit(&ctrl_p->hc_mutex);
2569 			cdip = pcie_hp_devi_find(
2570 			    ctrl_p->hc_dip, slot_p->hs_device_num, 0);
2571 			mutex_enter(&ctrl_p->hc_mutex);
2572 
2573 			if ((slot_p->hs_info.cn_state
2574 			    != DDI_HP_CN_STATE_ENABLED) || (cdip == NULL)) {
2575 				/*
2576 				 * When getting all properties, just ignore the
2577 				 * one that's not available under certain state.
2578 				 */
2579 				if (get_all_prop)
2580 					continue;
2581 
2582 				ret = DDI_ENOTSUP;
2583 				goto get_prop_cleanup2;
2584 			}
2585 
2586 			if (pci_config_setup(cdip, &handle) != DDI_SUCCESS) {
2587 				ret = DDI_FAILURE;
2588 				goto get_prop_cleanup2;
2589 			}
2590 
2591 			prog_class = pci_config_get8(handle,
2592 			    PCI_CONF_PROGCLASS);
2593 			base_class = pci_config_get8(handle, PCI_CONF_BASCLASS);
2594 			sub_class = pci_config_get8(handle, PCI_CONF_SUBCLASS);
2595 			pci_config_teardown(&handle);
2596 
2597 			for (i = 0; i < class_pci_items; i++) {
2598 				if ((base_class == class_pci[i].base_class) &&
2599 				    (sub_class == class_pci[i].sub_class) &&
2600 				    (prog_class == class_pci[i].prog_class)) {
2601 					value = class_pci[i].short_desc;
2602 					break;
2603 				}
2604 			}
2605 			if (i == class_pci_items)
2606 				value = PCIEHPC_PROP_VALUE_UNKNOWN;
2607 		} else if (strcmp(name, PCIEHPC_PROP_BOARD_TYPE) == 0) {
2608 			if (slot_p->hs_info.cn_state <= DDI_HP_CN_STATE_EMPTY)
2609 				value = PCIEHPC_PROP_VALUE_UNKNOWN;
2610 			else
2611 				value = PCIEHPC_PROP_VALUE_PCIHOTPLUG;
2612 		} else if (strcmp(name, PCIEHPC_PROP_SLOT_CONDITION) == 0) {
2613 			value = pcie_slot_condition_text(slot_p->hs_condition);
2614 		} else {
2615 			/* unsupported property */
2616 			PCIE_DBG("Unsupported property: %s\n", name);
2617 
2618 			ret = DDI_ENOTSUP;
2619 			goto get_prop_cleanup2;
2620 		}
2621 		if (nvlist_add_string(prop_rlist, name, value) != 0) {
2622 			ret = DDI_FAILURE;
2623 			goto get_prop_cleanup2;
2624 		}
2625 	}
2626 
2627 	/* pack nvlist and copyout */
2628 	if ((ret = pcie_copyout_nvlist(prop_rlist, result.nvlist_buf,
2629 	    &result.buf_size)) != DDI_SUCCESS) {
2630 		goto get_prop_cleanup2;
2631 	}
2632 	if (get_udatamodel() == DATAMODEL_NATIVE) {
2633 		if (copyout(&result, rval, sizeof (ddi_hp_property_t)))
2634 			ret = DDI_FAILURE;
2635 	}
2636 #ifdef _SYSCALL32_IMPL
2637 	else {
2638 		if (result.buf_size > UINT32_MAX) {
2639 			ret = DDI_FAILURE;
2640 		} else {
2641 			result32.buf_size = (uint32_t)result.buf_size;
2642 			if (copyout(&result32, rval,
2643 			    sizeof (ddi_hp_property32_t)))
2644 				ret = DDI_FAILURE;
2645 		}
2646 	}
2647 #endif
2648 
2649 get_prop_cleanup2:
2650 	mutex_exit(&ctrl_p->hc_mutex);
2651 get_prop_cleanup1:
2652 	nvlist_free(prop_rlist);
2653 get_prop_cleanup:
2654 	nvlist_free(prop_list);
2655 	return (ret);
2656 }
2657 
2658 int
2659 pciehpc_slot_set_property(pcie_hp_slot_t *slot_p, ddi_hp_property_t *arg,
2660     ddi_hp_property_t *rval)
2661 {
2662 	ddi_hp_property_t	request, result;
2663 #ifdef _SYSCALL32_IMPL
2664 	ddi_hp_property32_t	request32, result32;
2665 #endif
2666 	pcie_hp_ctrl_t		*ctrl_p = slot_p->hs_ctrl;
2667 	nvlist_t		*prop_list;
2668 	nvlist_t		*prop_rlist;
2669 	nvpair_t		*prop_pair;
2670 	char			*name, *value;
2671 	pcie_hp_led_state_t	led_state;
2672 	int			ret = DDI_SUCCESS;
2673 
2674 	if (get_udatamodel() == DATAMODEL_NATIVE) {
2675 		if (copyin(arg, &request, sizeof (ddi_hp_property_t)))
2676 			return (DDI_FAILURE);
2677 		if (rval &&
2678 		    copyin(rval, &result, sizeof (ddi_hp_property_t)))
2679 			return (DDI_FAILURE);
2680 	}
2681 #ifdef _SYSCALL32_IMPL
2682 	else {
2683 		bzero(&request, sizeof (request));
2684 		bzero(&result, sizeof (result));
2685 		if (copyin(arg, &request32, sizeof (ddi_hp_property32_t)))
2686 			return (DDI_FAILURE);
2687 		if (rval &&
2688 		    copyin(rval, &result32, sizeof (ddi_hp_property32_t)))
2689 			return (DDI_FAILURE);
2690 		request.nvlist_buf = (char *)(uintptr_t)request32.nvlist_buf;
2691 		request.buf_size = request32.buf_size;
2692 		if (rval) {
2693 			result.nvlist_buf =
2694 			    (char *)(uintptr_t)result32.nvlist_buf;
2695 			result.buf_size = result32.buf_size;
2696 		}
2697 	}
2698 #endif
2699 
2700 	if ((ret = pcie_copyin_nvlist(request.nvlist_buf, request.buf_size,
2701 	    &prop_list)) != DDI_SUCCESS)
2702 		return (ret);
2703 
2704 	/* check whether the requested property is "help" */
2705 	prop_pair = nvlist_next_nvpair(prop_list, NULL);
2706 	if (prop_pair && !nvlist_next_nvpair(prop_list, prop_pair) &&
2707 	    (strcmp(nvpair_name(prop_pair), PCIEHPC_PROP_HELP) == 0)) {
2708 		if (!rval) {
2709 			ret = DDI_ENOTSUP;
2710 			goto set_prop_cleanup;
2711 		}
2712 
2713 		if (nvlist_alloc(&prop_rlist, NV_UNIQUE_NAME, 0)) {
2714 			ret = DDI_ENOMEM;
2715 			goto set_prop_cleanup;
2716 		}
2717 		if (nvlist_add_string(prop_rlist, PCIEHPC_PROP_LED_ATTN,
2718 		    PCIEHPC_PROP_VALUE_LED) != 0) {
2719 			ret = DDI_FAILURE;
2720 			goto set_prop_cleanup1;
2721 		}
2722 
2723 		if ((ret = pcie_copyout_nvlist(prop_rlist, result.nvlist_buf,
2724 		    &result.buf_size)) != DDI_SUCCESS) {
2725 			goto set_prop_cleanup1;
2726 		}
2727 		if (get_udatamodel() == DATAMODEL_NATIVE) {
2728 			if (copyout(&result, rval,
2729 			    sizeof (ddi_hp_property_t))) {
2730 				ret =  DDI_FAILURE;
2731 				goto set_prop_cleanup1;
2732 			}
2733 		}
2734 #ifdef _SYSCALL32_IMPL
2735 		else {
2736 			if (result.buf_size > UINT32_MAX) {
2737 				ret =  DDI_FAILURE;
2738 				goto set_prop_cleanup1;
2739 			} else {
2740 				result32.buf_size = (uint32_t)result.buf_size;
2741 				if (copyout(&result32, rval,
2742 				    sizeof (ddi_hp_property32_t))) {
2743 					ret =  DDI_FAILURE;
2744 					goto set_prop_cleanup1;
2745 				}
2746 			}
2747 		}
2748 #endif
2749 set_prop_cleanup1:
2750 		nvlist_free(prop_rlist);
2751 		nvlist_free(prop_list);
2752 		return (ret);
2753 	}
2754 
2755 	/* Validate the request */
2756 	prop_pair = NULL;
2757 	while ((prop_pair = nvlist_next_nvpair(prop_list, prop_pair)) != NULL) {
2758 		name = nvpair_name(prop_pair);
2759 		if (nvpair_type(prop_pair) != DATA_TYPE_STRING) {
2760 			PCIE_DBG("Unexpected data type of setting "
2761 			    "property %s.\n", name);
2762 			ret = DDI_EINVAL;
2763 			goto set_prop_cleanup;
2764 		}
2765 		if (nvpair_value_string(prop_pair, &value)) {
2766 			PCIE_DBG("Get string value failed for property %s.\n",
2767 			    name);
2768 			ret = DDI_FAILURE;
2769 			goto set_prop_cleanup;
2770 		}
2771 
2772 		if (strcmp(name, PCIEHPC_PROP_LED_ATTN) == 0) {
2773 			if ((strcmp(value, PCIEHPC_PROP_VALUE_ON) != 0) &&
2774 			    (strcmp(value, PCIEHPC_PROP_VALUE_OFF) != 0) &&
2775 			    (strcmp(value, PCIEHPC_PROP_VALUE_BLINK) != 0)) {
2776 				PCIE_DBG("Unsupported value of setting "
2777 				    "property %s\n", name);
2778 				ret = DDI_ENOTSUP;
2779 				goto set_prop_cleanup;
2780 			}
2781 		} else {
2782 			PCIE_DBG("Unsupported property: %s\n", name);
2783 			ret = DDI_ENOTSUP;
2784 			goto set_prop_cleanup;
2785 		}
2786 	}
2787 	mutex_enter(&ctrl_p->hc_mutex);
2788 
2789 	/* get the current slot state */
2790 	pciehpc_get_slot_state(slot_p);
2791 
2792 	/* set each property */
2793 	prop_pair = NULL;
2794 	while ((prop_pair = nvlist_next_nvpair(prop_list, prop_pair)) != NULL) {
2795 		name = nvpair_name(prop_pair);
2796 
2797 		/*
2798 		 * The validity of the property was checked above.
2799 		 */
2800 		if (strcmp(name, PCIEHPC_PROP_LED_ATTN) == 0) {
2801 			if (strcmp(value, PCIEHPC_PROP_VALUE_ON) == 0)
2802 				led_state = PCIE_HP_LED_ON;
2803 			else if (strcmp(value, PCIEHPC_PROP_VALUE_OFF) == 0)
2804 				led_state = PCIE_HP_LED_OFF;
2805 			else if (strcmp(value, PCIEHPC_PROP_VALUE_BLINK) == 0)
2806 				led_state = PCIE_HP_LED_BLINK;
2807 			else
2808 				continue;
2809 
2810 			pciehpc_set_led_state(ctrl_p, PCIE_HP_ATTN_LED,
2811 			    led_state);
2812 		}
2813 	}
2814 	if (rval) {
2815 		if (get_udatamodel() == DATAMODEL_NATIVE) {
2816 			result.buf_size = 0;
2817 			if (copyout(&result, rval, sizeof (ddi_hp_property_t)))
2818 				ret =  DDI_FAILURE;
2819 		}
2820 #ifdef _SYSCALL32_IMPL
2821 		else {
2822 			result32.buf_size = 0;
2823 			if (copyout(&result32, rval,
2824 			    sizeof (ddi_hp_property32_t)))
2825 				ret =  DDI_FAILURE;
2826 		}
2827 #endif
2828 	}
2829 
2830 	mutex_exit(&ctrl_p->hc_mutex);
2831 set_prop_cleanup:
2832 	nvlist_free(prop_list);
2833 	return (ret);
2834 }
2835 
2836 /*
2837  * Send a command to the PCI-E Hot Plug Controller.
2838  *
2839  * NOTES: The PCI-E spec defines the following semantics for issuing hot plug
2840  * commands.
2841  * 1) If Command Complete events/interrupts are supported then software
2842  *    waits for Command Complete event after issuing a command (i.e writing
2843  *    to the Slot Control register). The command completion could take as
2844  *    long as 1 second so software should be prepared to wait for 1 second
2845  *    before issuing another command.
2846  *
2847  * 2) If Command Complete events/interrupts are not supported then
2848  *    software could issue multiple Slot Control writes without any delay
2849  *    between writes.
2850  */
2851 static void
2852 pciehpc_issue_hpc_command(pcie_hp_ctrl_t *ctrl_p, uint16_t control)
2853 {
2854 	pcie_hp_slot_t	*slot_p = ctrl_p->hc_slots[0];
2855 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
2856 	uint16_t	status;
2857 	uint32_t	slot_cap;
2858 
2859 	/*
2860 	 * PCI-E version 1.1 spec defines No Command Completed
2861 	 * Support bit (bit#18) in Slot Capabilities register. If this
2862 	 * bit is set then slot doesn't support notification of command
2863 	 * completion events.
2864 	 */
2865 	slot_cap =  pciehpc_reg_get32(ctrl_p,
2866 	    bus_p->bus_pcie_off + PCIE_SLOTCAP);
2867 
2868 	/*
2869 	 * If no Command Completion event is supported or it is ACPI
2870 	 * hot plug mode then just issue the command and return.
2871 	 */
2872 	if ((slot_cap & PCIE_SLOTCAP_NO_CMD_COMP_SUPP) ||
2873 	    (bus_p->bus_hp_curr_mode == PCIE_ACPI_HP_MODE)) {
2874 		pciehpc_reg_put16(ctrl_p,
2875 		    bus_p->bus_pcie_off + PCIE_SLOTCTL, control);
2876 		return;
2877 	}
2878 
2879 	/*
2880 	 * **************************************
2881 	 * Command Complete events are supported.
2882 	 * **************************************
2883 	 */
2884 
2885 	/*
2886 	 * If HPC is not yet initialized then just poll for the Command
2887 	 * Completion interrupt.
2888 	 */
2889 	if (!(ctrl_p->hc_flags & PCIE_HP_INITIALIZED_FLAG)) {
2890 		int retry = PCIE_HP_CMD_WAIT_RETRY;
2891 
2892 		/* write the command to the HPC */
2893 		pciehpc_reg_put16(ctrl_p,
2894 		    bus_p->bus_pcie_off + PCIE_SLOTCTL, control);
2895 
2896 		/* poll for status completion */
2897 		while (retry--) {
2898 			/* wait for 10 msec before checking the status */
2899 			delay(drv_usectohz(PCIE_HP_CMD_WAIT_TIME));
2900 
2901 			status = pciehpc_reg_get16(ctrl_p,
2902 			    bus_p->bus_pcie_off + PCIE_SLOTSTS);
2903 
2904 			if (status & PCIE_SLOTSTS_COMMAND_COMPLETED) {
2905 				/* clear the status bits */
2906 				pciehpc_reg_put16(ctrl_p,
2907 				    bus_p->bus_pcie_off + PCIE_SLOTSTS, status);
2908 				break;
2909 			}
2910 		}
2911 		return;
2912 	}
2913 
2914 	/* HPC is already initialized */
2915 
2916 	ASSERT(MUTEX_HELD(&ctrl_p->hc_mutex));
2917 
2918 	/*
2919 	 * If previous command is still pending then wait for its
2920 	 * completion. i.e cv_wait()
2921 	 */
2922 
2923 	while (ctrl_p->hc_cmd_pending == B_TRUE)
2924 		cv_wait(&ctrl_p->hc_cmd_comp_cv, &ctrl_p->hc_mutex);
2925 
2926 	/*
2927 	 * Issue the command and wait for Command Completion or
2928 	 * the 1 sec timeout.
2929 	 */
2930 	pciehpc_reg_put16(ctrl_p,
2931 	    bus_p->bus_pcie_off + PCIE_SLOTCTL, control);
2932 
2933 	ctrl_p->hc_cmd_pending = B_TRUE;
2934 
2935 	if (cv_timedwait(&ctrl_p->hc_cmd_comp_cv, &ctrl_p->hc_mutex,
2936 	    ddi_get_lbolt() + SEC_TO_TICK(1)) == -1) {
2937 
2938 		/* it is a timeout */
2939 		PCIE_DBG("pciehpc_issue_hpc_command: Command Complete"
2940 		    " interrupt is not received for slot %d\n",
2941 		    slot_p->hs_phy_slot_num);
2942 
2943 		/* clear the status info in case interrupts are disabled? */
2944 		status = pciehpc_reg_get16(ctrl_p,
2945 		    bus_p->bus_pcie_off + PCIE_SLOTSTS);
2946 
2947 		if (status & PCIE_SLOTSTS_COMMAND_COMPLETED) {
2948 			/* clear the status bits */
2949 			pciehpc_reg_put16(ctrl_p,
2950 			    bus_p->bus_pcie_off + PCIE_SLOTSTS, status);
2951 		}
2952 	}
2953 
2954 	ctrl_p->hc_cmd_pending = B_FALSE;
2955 
2956 	/* wake up any one waiting for issuing another command to HPC */
2957 	cv_signal(&ctrl_p->hc_cmd_comp_cv);
2958 }
2959 
2960 /*
2961  * pciehcp_attn_btn_handler()
2962  *
2963  * This handles ATTN button pressed event as per the PCI-E 1.1 spec.
2964  */
2965 static void
2966 pciehpc_attn_btn_handler(pcie_hp_ctrl_t *ctrl_p)
2967 {
2968 	pcie_hp_slot_t		*slot_p = ctrl_p->hc_slots[0];
2969 	pcie_hp_led_state_t	power_led_state;
2970 	callb_cpr_t		cprinfo;
2971 
2972 	PCIE_DBG("pciehpc_attn_btn_handler: thread started\n");
2973 
2974 	CALLB_CPR_INIT(&cprinfo, &ctrl_p->hc_mutex, callb_generic_cpr,
2975 	    "pciehpc_attn_btn_handler");
2976 
2977 	mutex_enter(&ctrl_p->hc_mutex);
2978 
2979 	/* wait for ATTN button event */
2980 	cv_wait(&slot_p->hs_attn_btn_cv, &ctrl_p->hc_mutex);
2981 
2982 	while (slot_p->hs_attn_btn_thread_exit == B_FALSE) {
2983 		if (slot_p->hs_attn_btn_pending == B_TRUE) {
2984 			/* get the current state of power LED */
2985 			power_led_state = pciehpc_get_led_state(ctrl_p,
2986 			    PCIE_HP_POWER_LED);
2987 
2988 			/* Blink the Power LED while we wait for 5 seconds */
2989 			pciehpc_set_led_state(ctrl_p, PCIE_HP_POWER_LED,
2990 			    PCIE_HP_LED_BLINK);
2991 
2992 			/* wait for 5 seconds before taking any action */
2993 			if (cv_timedwait(&slot_p->hs_attn_btn_cv,
2994 			    &ctrl_p->hc_mutex,
2995 			    ddi_get_lbolt() + SEC_TO_TICK(5)) == -1) {
2996 				/*
2997 				 * It is a time out; make sure the ATTN pending
2998 				 * flag is still ON before sending the event to
2999 				 * DDI HP framework.
3000 				 */
3001 				if (slot_p->hs_attn_btn_pending == B_TRUE) {
3002 					int hint;
3003 
3004 					slot_p->hs_attn_btn_pending = B_FALSE;
3005 					pciehpc_get_slot_state(slot_p);
3006 
3007 					if (slot_p->hs_info.cn_state <=
3008 					    DDI_HP_CN_STATE_PRESENT) {
3009 						/*
3010 						 * Insertion.
3011 						 */
3012 						hint = SE_INCOMING_RES;
3013 					} else {
3014 						/*
3015 						 * Want to remove;
3016 						 */
3017 						hint = SE_OUTGOING_RES;
3018 					}
3019 
3020 					/*
3021 					 * We can't call ddihp_cn_gen_sysevent
3022 					 * here since it's not a DDI interface.
3023 					 */
3024 					pcie_hp_gen_sysevent_req(
3025 					    slot_p->hs_info.cn_name,
3026 					    hint,
3027 					    ctrl_p->hc_dip,
3028 					    KM_SLEEP);
3029 				}
3030 			}
3031 
3032 			/* restore the power LED state */
3033 			pciehpc_set_led_state(ctrl_p, PCIE_HP_POWER_LED,
3034 			    power_led_state);
3035 			continue;
3036 		}
3037 
3038 		/* wait for another ATTN button event */
3039 		cv_wait(&slot_p->hs_attn_btn_cv, &ctrl_p->hc_mutex);
3040 	}
3041 
3042 	PCIE_DBG("pciehpc_attn_btn_handler: thread exit\n");
3043 	cv_signal(&slot_p->hs_attn_btn_cv);
3044 	CALLB_CPR_EXIT(&cprinfo);
3045 	thread_exit();
3046 }
3047 
3048 /*
3049  * convert LED state from PCIE HPC definition to pcie_hp_led_state_t
3050  * definition.
3051  */
3052 static pcie_hp_led_state_t
3053 pciehpc_led_state_to_hpc(uint16_t state)
3054 {
3055 	switch (state) {
3056 	case PCIE_SLOTCTL_INDICATOR_STATE_ON:
3057 		return (PCIE_HP_LED_ON);
3058 	case PCIE_SLOTCTL_INDICATOR_STATE_BLINK:
3059 		return (PCIE_HP_LED_BLINK);
3060 	case PCIE_SLOTCTL_INDICATOR_STATE_OFF:
3061 	default:
3062 		return (PCIE_HP_LED_OFF);
3063 	}
3064 }
3065 
3066 /*
3067  * Get the state of an LED.
3068  */
3069 static pcie_hp_led_state_t
3070 pciehpc_get_led_state(pcie_hp_ctrl_t *ctrl_p, pcie_hp_led_t led)
3071 {
3072 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
3073 	uint16_t	control, state;
3074 
3075 	/* get the current state of Slot Control register */
3076 	control =  pciehpc_reg_get16(ctrl_p,
3077 	    bus_p->bus_pcie_off + PCIE_SLOTCTL);
3078 
3079 	switch (led) {
3080 	case PCIE_HP_POWER_LED:
3081 		state = pcie_slotctl_pwr_indicator_get(control);
3082 		break;
3083 	case PCIE_HP_ATTN_LED:
3084 		state = pcie_slotctl_attn_indicator_get(control);
3085 		break;
3086 	default:
3087 		PCIE_DBG("pciehpc_get_led_state() invalid LED %d\n", led);
3088 		return (PCIE_HP_LED_OFF);
3089 	}
3090 
3091 	switch (state) {
3092 	case PCIE_SLOTCTL_INDICATOR_STATE_ON:
3093 		return (PCIE_HP_LED_ON);
3094 
3095 	case PCIE_SLOTCTL_INDICATOR_STATE_BLINK:
3096 		return (PCIE_HP_LED_BLINK);
3097 
3098 	case PCIE_SLOTCTL_INDICATOR_STATE_OFF:
3099 	default:
3100 		return (PCIE_HP_LED_OFF);
3101 	}
3102 }
3103 
3104 /*
3105  * Set the state of an LED. It updates both hw and sw state.
3106  */
3107 static void
3108 pciehpc_set_led_state(pcie_hp_ctrl_t *ctrl_p, pcie_hp_led_t led,
3109     pcie_hp_led_state_t state)
3110 {
3111 	pcie_hp_slot_t	*slot_p = ctrl_p->hc_slots[0];
3112 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
3113 	uint16_t	control, orig_control;
3114 
3115 	/* get the current state of Slot Control register */
3116 	orig_control = control =  pciehpc_reg_get16(ctrl_p,
3117 	    bus_p->bus_pcie_off + PCIE_SLOTCTL);
3118 
3119 	switch (led) {
3120 	case PCIE_HP_POWER_LED:
3121 		/* clear led mask */
3122 		control &= ~PCIE_SLOTCTL_PWR_INDICATOR_MASK;
3123 		slot_p->hs_power_led_state = state;
3124 		break;
3125 	case PCIE_HP_ATTN_LED:
3126 		/* clear led mask */
3127 		control &= ~PCIE_SLOTCTL_ATTN_INDICATOR_MASK;
3128 		slot_p->hs_attn_led_state = state;
3129 		break;
3130 	default:
3131 		PCIE_DBG("pciehpc_set_led_state() invalid LED %d\n", led);
3132 		return;
3133 	}
3134 
3135 	switch (state) {
3136 	case PCIE_HP_LED_ON:
3137 		if (led == PCIE_HP_POWER_LED)
3138 			control = pcie_slotctl_pwr_indicator_set(control,
3139 			    PCIE_SLOTCTL_INDICATOR_STATE_ON);
3140 		else if (led == PCIE_HP_ATTN_LED)
3141 			control = pcie_slotctl_attn_indicator_set(control,
3142 			    PCIE_SLOTCTL_INDICATOR_STATE_ON);
3143 		break;
3144 	case PCIE_HP_LED_OFF:
3145 		if (led == PCIE_HP_POWER_LED)
3146 			control = pcie_slotctl_pwr_indicator_set(control,
3147 			    PCIE_SLOTCTL_INDICATOR_STATE_OFF);
3148 		else if (led == PCIE_HP_ATTN_LED)
3149 			control = pcie_slotctl_attn_indicator_set(control,
3150 			    PCIE_SLOTCTL_INDICATOR_STATE_OFF);
3151 		break;
3152 	case PCIE_HP_LED_BLINK:
3153 		if (led == PCIE_HP_POWER_LED)
3154 			control = pcie_slotctl_pwr_indicator_set(control,
3155 			    PCIE_SLOTCTL_INDICATOR_STATE_BLINK);
3156 		else if (led == PCIE_HP_ATTN_LED)
3157 			control = pcie_slotctl_attn_indicator_set(control,
3158 			    PCIE_SLOTCTL_INDICATOR_STATE_BLINK);
3159 		break;
3160 
3161 	default:
3162 		PCIE_DBG("pciehpc_set_led_state() invalid LED state %d\n",
3163 		    state);
3164 		return;
3165 	}
3166 
3167 	/*
3168 	 * Update hardware if we're actually changing anything here. If things
3169 	 * are instead saying the same (because a user asked us to update state
3170 	 * or we're already in the state we think we should be), then we just
3171 	 * leave it as is.
3172 	 */
3173 	if (control != orig_control) {
3174 		pciehpc_issue_hpc_command(ctrl_p, control);
3175 	}
3176 
3177 #ifdef DEBUG
3178 	/* get the current state of Slot Control register */
3179 	control =  pciehpc_reg_get16(ctrl_p,
3180 	    bus_p->bus_pcie_off + PCIE_SLOTCTL);
3181 
3182 	PCIE_DBG("pciehpc_set_led_state: slot %d power-led %s attn-led %s\n",
3183 	    slot_p->hs_phy_slot_num, pcie_led_state_text(
3184 	    pciehpc_led_state_to_hpc(pcie_slotctl_pwr_indicator_get(control))),
3185 	    pcie_led_state_text(pciehpc_led_state_to_hpc(
3186 	    pcie_slotctl_attn_indicator_get(control))));
3187 #endif
3188 }
3189 
3190 static void
3191 pciehpc_handle_power_fault(dev_info_t *dip)
3192 {
3193 	/*
3194 	 * Hold the parent's ref so that it won't disappear when the taskq is
3195 	 * scheduled to run.
3196 	 */
3197 	ndi_hold_devi(dip);
3198 
3199 	if (taskq_dispatch(system_taskq, pciehpc_power_fault_handler, dip,
3200 	    TQ_NOSLEEP) == TASKQID_INVALID) {
3201 		ndi_rele_devi(dip);
3202 		PCIE_DBG("pciehpc_intr(): "
3203 		    "Failed to dispatch power fault handler, dip %p\n", dip);
3204 	}
3205 }
3206 
3207 static void
3208 pciehpc_power_fault_handler(void *arg)
3209 {
3210 	dev_info_t *dip = (dev_info_t *)arg;
3211 	pcie_hp_ctrl_t  *ctrl_p;
3212 	pcie_hp_slot_t  *slot_p;
3213 
3214 	/* get the soft state structure for this dip */
3215 	if ((ctrl_p = PCIE_GET_HP_CTRL(dip)) == NULL) {
3216 		ndi_rele_devi(dip);
3217 		return;
3218 	}
3219 	slot_p = ctrl_p->hc_slots[0];
3220 
3221 	/*
3222 	 * Send the event to DDI Hotplug framework, power off
3223 	 * the slot
3224 	 */
3225 	(void) ndi_hp_state_change_req(dip,
3226 	    slot_p->hs_info.cn_name,
3227 	    DDI_HP_CN_STATE_PRESENT, DDI_HP_REQ_SYNC);
3228 
3229 	mutex_enter(&ctrl_p->hc_mutex);
3230 	pciehpc_set_led_state(ctrl_p, PCIE_HP_ATTN_LED,
3231 	    PCIE_HP_LED_ON);
3232 	mutex_exit(&ctrl_p->hc_mutex);
3233 	ndi_rele_devi(dip);
3234 }
3235 
3236 #ifdef DEBUG
3237 /*
3238  * Dump PCI-E Hot Plug registers.
3239  */
3240 static void
3241 pciehpc_dump_hpregs(pcie_hp_ctrl_t *ctrl_p)
3242 {
3243 	pcie_hp_slot_t	*slot_p = ctrl_p->hc_slots[0];
3244 	pcie_bus_t	*bus_p = PCIE_DIP2BUS(ctrl_p->hc_dip);
3245 	uint16_t	control;
3246 	uint32_t	capabilities;
3247 
3248 	if (!pcie_debug_flags)
3249 		return;
3250 
3251 	capabilities = pciehpc_reg_get32(ctrl_p,
3252 	    bus_p->bus_pcie_off + PCIE_SLOTCAP);
3253 
3254 	control =  pciehpc_reg_get16(ctrl_p,
3255 	    bus_p->bus_pcie_off + PCIE_SLOTCTL);
3256 
3257 	PCIE_DBG("pciehpc_dump_hpregs: Found PCI-E hot plug slot %d\n",
3258 	    slot_p->hs_phy_slot_num);
3259 
3260 	PCIE_DBG("Attention Button Present = %s\n",
3261 	    capabilities & PCIE_SLOTCAP_ATTN_BUTTON ? "Yes":"No");
3262 
3263 	PCIE_DBG("Power controller Present = %s\n",
3264 	    capabilities & PCIE_SLOTCAP_POWER_CONTROLLER ? "Yes":"No");
3265 
3266 	PCIE_DBG("MRL Sensor Present	   = %s\n",
3267 	    capabilities & PCIE_SLOTCAP_MRL_SENSOR ? "Yes":"No");
3268 
3269 	PCIE_DBG("Attn Indicator Present   = %s\n",
3270 	    capabilities & PCIE_SLOTCAP_ATTN_INDICATOR ? "Yes":"No");
3271 
3272 	PCIE_DBG("Power Indicator Present  = %s\n",
3273 	    capabilities & PCIE_SLOTCAP_PWR_INDICATOR ? "Yes":"No");
3274 
3275 	PCIE_DBG("HotPlug Surprise	   = %s\n",
3276 	    capabilities & PCIE_SLOTCAP_HP_SURPRISE ? "Yes":"No");
3277 
3278 	PCIE_DBG("HotPlug Capable	   = %s\n",
3279 	    capabilities & PCIE_SLOTCAP_HP_CAPABLE ? "Yes":"No");
3280 
3281 	PCIE_DBG("Physical Slot Number	   = %d\n",
3282 	    PCIE_SLOTCAP_PHY_SLOT_NUM(capabilities));
3283 
3284 	PCIE_DBG("Attn Button interrupt Enabled  = %s\n",
3285 	    control & PCIE_SLOTCTL_ATTN_BTN_EN ? "Yes":"No");
3286 
3287 	PCIE_DBG("Power Fault interrupt Enabled  = %s\n",
3288 	    control & PCIE_SLOTCTL_PWR_FAULT_EN ? "Yes":"No");
3289 
3290 	PCIE_DBG("MRL Sensor INTR Enabled   = %s\n",
3291 	    control & PCIE_SLOTCTL_MRL_SENSOR_EN ? "Yes":"No");
3292 
3293 	PCIE_DBG("Presence interrupt Enabled	 = %s\n",
3294 	    control & PCIE_SLOTCTL_PRESENCE_CHANGE_EN ? "Yes":"No");
3295 
3296 	PCIE_DBG("Cmd Complete interrupt Enabled = %s\n",
3297 	    control & PCIE_SLOTCTL_CMD_INTR_EN ? "Yes":"No");
3298 
3299 	PCIE_DBG("HotPlug interrupt Enabled	 = %s\n",
3300 	    control & PCIE_SLOTCTL_HP_INTR_EN ? "Yes":"No");
3301 
3302 	PCIE_DBG("Power Indicator LED = %s", pcie_led_state_text(
3303 	    pciehpc_led_state_to_hpc(pcie_slotctl_pwr_indicator_get(control))));
3304 
3305 	PCIE_DBG("Attn Indicator LED = %s\n",
3306 	    pcie_led_state_text(pciehpc_led_state_to_hpc(
3307 	    pcie_slotctl_attn_indicator_get(control))));
3308 }
3309 #endif	/* DEBUG */
3310