1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21/*
22 * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23 * Use is subject to license terms.
24 */
25
26/*
27 * **********************************************************************
28 * Extension module for PCI nexus drivers to support PCI Hot Plug feature.
29 *
30 * DESCRIPTION:
31 *    This module basically implements "devctl" and Attachment Point device
32 *    nodes for hot plug operations. The cb_ops functions needed for access
33 *    to these device nodes are also implemented. For hotplug operations
34 *    on Attachment Points it interacts with the hotplug services (HPS)
35 *    framework. A pci nexus driver would simply call pcihp_init() in its
36 *    attach() function and pcihp_uninit() call in its detach() function.
37 * **********************************************************************
38 */
39
40#include <sys/conf.h>
41#include <sys/kmem.h>
42#include <sys/debug.h>
43#include <sys/modctl.h>
44#include <sys/autoconf.h>
45#include <sys/ddi.h>
46#include <sys/sunddi.h>
47#include <sys/sunndi.h>
48#include <sys/ddi_impldefs.h>
49#include <sys/ndi_impldefs.h>
50#include <sys/ddipropdefs.h>
51#include <sys/open.h>
52#include <sys/file.h>
53#include <sys/stat.h>
54#include <sys/pci.h>
55#include <sys/pci_impl.h>
56#include <sys/devctl.h>
57#include <sys/hotplug/hpcsvc.h>
58#include <sys/hotplug/pci/pcicfg.h>
59#include <sys/hotplug/pci/pcihp.h>
60#include <sys/sysevent.h>
61#include <sys/sysevent/eventdefs.h>
62#include <sys/sysevent/dr.h>
63#include <sys/fs/dv_node.h>
64
65/*
66 * NOTE:
67 * This module depends on PCI Configurator module (misc/pcicfg),
68 * Hot Plug Services framework module (misc/hpcsvc) and Bus Resource
69 * Allocator module (misc/busra).
70 */
71
72/*
73 * ************************************************************************
74 * *** Implementation specific data structures/definitions.		***
75 * ************************************************************************
76 */
77
78/* soft state */
79typedef enum { PCIHP_SOFT_STATE_CLOSED, PCIHP_SOFT_STATE_OPEN,
80		PCIHP_SOFT_STATE_OPEN_EXCL } pcihp_soft_state_t;
81
82#define	PCI_MAX_DEVS	32	/* max. number of devices on a pci bus */
83
84/* the following correspond to sysevent defined subclasses */
85#define	PCIHP_DR_AP_STATE_CHANGE	0
86#define	PCIHP_DR_REQ			1
87
88/*  pcihp_get_soft_state() command argument */
89#define	PCIHP_DR_NOOP			0
90#define	PCIHP_DR_BUS_CONFIGURE		1
91#define	PCIHP_DR_BUS_UNCONFIGURE	2
92#define	PCIHP_DR_SLOT_ENTER		4
93#define	PCIHP_DR_SLOT_EXIT		8
94
95/*  hot plug bus state */
96enum { PCIHP_BUS_INITIALIZING, PCIHP_BUS_UNCONFIGURED,
97		PCIHP_BUS_CONFIGURED };
98
99/*
100 * Soft state structure associated with each hot plug pci bus instance.
101 */
102typedef struct pcihp {
103	struct pcihp		*nextp;
104
105	/* devinfo pointer to the pci bus node */
106	dev_info_t		*dip;
107
108	/* soft state flags: PCIHP_SOFT_STATE_* */
109	pcihp_soft_state_t	soft_state;
110
111	/* global mutex to serialize exclusive access to the bus */
112	kmutex_t		mutex;
113
114	/* slot information structure */
115	struct pcihp_slotinfo {
116		hpc_slot_t	slot_hdl;	/* HPS slot handle */
117		ap_rstate_t	rstate;		/* state of Receptacle */
118		ap_ostate_t	ostate;		/* state of the Occupant */
119		ap_condition_t	condition;	/* condition of the occupant */
120		time32_t	last_change;	/* XXX needed? */
121		uint32_t	event_mask;	/* last event mask registered */
122		char		*name;		/* slot logical name */
123		uint_t		slot_flags;
124		uint16_t	slot_type;	/* slot type: pci or cpci */
125		uint16_t	slot_capabilities; /* 64bit, etc. */
126		int		hs_csr_location; /* Location of HS_CSR */
127		kmutex_t	slot_mutex;	/* mutex to serialize hotplug */
128						/* operations on the slot */
129	} slotinfo[PCI_MAX_DEVS];
130
131	/* misc. bus attributes */
132	uint_t			bus_flags;
133	uint_t			bus_state;
134	uint_t			slots_active;
135} pcihp_t;
136
137/*
138 * Bit definitions for slot_flags field:
139 *
140 *	PCIHP_SLOT_AUTO_CFG_EN	This flags is set if nexus can do auto
141 *				configuration of hot plugged card on this slot
142 *				if the hardware reports the hot plug events.
143 *
144 *	PCIHP_SLOT_DISABLED	Slot is disabled for hotplug operations.
145 *
146 *	PCIHP_SLOT_NOT_HEALTHY	HEALTHY# signal is not OK on this slot.
147 */
148#define	PCIHP_SLOT_AUTO_CFG_EN		0x1
149#define	PCIHP_SLOT_DISABLED		0x2
150#define	PCIHP_SLOT_NOT_HEALTHY		0x4
151#define	PCIHP_SLOT_DEV_NON_HOTPLUG	0x8
152#define	PCIHP_SLOT_ENUM_INS_PENDING	0x10
153#define	PCIHP_SLOT_ENUM_EXT_PENDING	0x20
154
155/*
156 * Bit definitions for bus_flags field:
157 *
158 *	PCIHP_BUS_66MHZ	Bus is running at 66Mhz.
159 */
160#define	PCIHP_BUS_66MHZ		0x1
161#define	PCIHP_BUS_ENUM_RADIAL	0x2
162
163#define	PCIHP_DEVICES_STR		"/devices"
164
165/*
166 * control structure for tree walk during configure/unconfigure operation.
167 */
168struct pcihp_config_ctrl {
169	int	pci_dev;	/* PCI device number for the slot */
170	uint_t	flags;		/* control flags (see below) */
171	int	op;		/* operation: PCIHP_ONLINE or PCIHP_OFFLINE */
172	int	rv;		/* return error code */
173	dev_info_t *dip;	/* dip at which the (first) error occurred */
174	hpc_occupant_info_t *occupant;
175};
176
177/*
178 * control flags for configure/unconfigure operations on the tree.
179 *
180 * PCIHP_CFG_CONTINUE	continue the operation ignoring errors
181 */
182#define	PCIHP_CFG_CONTINUE	0x1
183
184#define	PCIHP_ONLINE	1
185#define	PCIHP_OFFLINE	0
186
187
188/* Leaf ops (hotplug controls for target devices) */
189static int pcihp_open(dev_t *, int, int, cred_t *);
190static int pcihp_close(dev_t, int, int, cred_t *);
191static int pcihp_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
192
193#ifdef DEBUG
194static int pcihp_debug = 0;
195#define	PCIHP_DEBUG(args)	if (pcihp_debug >= 1) cmn_err args
196#define	PCIHP_DEBUG2(args)	if (pcihp_debug >= 2) cmn_err args
197#else
198#define	PCIHP_DEBUG(args)
199#define	PCIHP_DEBUG2(args)
200#endif
201
202/*
203 * We process ENUM# event one device at a time ie. as soon as we detect
204 * that a device has the right ENUM# conditions, we return. If the following
205 * variable is set to non-zero, we scan all the devices on the bus
206 * for ENUM# conditions.
207 */
208static int pcihp_enum_scan_all = 0;
209/*
210 * If HSC driver cannot determine the board type (for example: it may not
211 * be possible to differentiate between a Basic Hotswap, Non Hotswap or
212 * Non-friendly Full hotswap board), the default board type is assigned
213 * to be as defined by the following variable.
214 */
215static int pcihp_cpci_board_type = HPC_BOARD_CPCI_NON_HS;
216static int pcihp_cpci_led_blink = 30;
217/*
218 * It was noted that the blue LED when written on/off would cause INS/EXT
219 * bit to be set causing an extra interrupt. Although the cPCI specifications
220 * does not imply this, this behavior is seen with some FHS silicons.
221 * Also, handling the INS/EXT bit would control the LED being On/Off.
222 * Until the behavior is confirmed, this flag could be used to enable or
223 * disable handling the LED.
224 * 0 means the silicons handles the LED behavior via the INS/EXT bit.
225 * 1 means the software must explicitly do the LED behavior.
226 */
227static int pcihp_cpci_blue_led = 1;
228
229/* static functions */
230static pcihp_t *pcihp_create_soft_state(dev_info_t *dip);
231static void pcihp_destroy_soft_state(dev_info_t *dip);
232static pcihp_t *pcihp_get_soft_state(dev_info_t *dip, int cmd, int *rv);
233static int pcihp_configure_ap(pcihp_t *pcihp_p, int pci_dev);
234static int pcihp_unconfigure_ap(pcihp_t *pcihp_p, int pci_dev);
235static int pcihp_new_slot_state(dev_info_t *, hpc_slot_t,
236	hpc_slot_info_t *, int);
237static int pcihp_configure(dev_info_t *, void *);
238static bool_t pcihp_check_status(dev_info_t *);
239static int pcihp_event_handler(caddr_t, uint_t);
240static dev_info_t *pcihp_devi_find(dev_info_t *dip, uint_t dev, uint_t func);
241static int pcihp_match_dev(dev_info_t *dip, void *hdl);
242static int pcihp_get_hs_csr(struct pcihp_slotinfo *, ddi_acc_handle_t,
243	uint8_t *);
244static void pcihp_set_hs_csr(struct pcihp_slotinfo *, ddi_acc_handle_t,
245	uint8_t *);
246static int pcihp_get_hs_csr_location(ddi_acc_handle_t);
247static int pcihp_handle_enum(pcihp_t *, int, int, int);
248static void pcihp_hs_csr_op(pcihp_t *, int, int);
249static int pcihp_enum_slot(pcihp_t *, struct pcihp_slotinfo *, int, int, int);
250static int pcihp_handle_enum_extraction(pcihp_t *, int, int, int);
251static int pcihp_handle_enum_insertion(pcihp_t *, int, int, int);
252static int pcihp_add_dummy_reg_property(dev_info_t *, uint_t, uint_t, uint_t);
253static int pcihp_config_setup(dev_info_t **, ddi_acc_handle_t *,
254			dev_info_t **, int, pcihp_t *);
255static void pcihp_config_teardown(ddi_acc_handle_t *,
256			dev_info_t **, int, pcihp_t *);
257static int pcihp_get_board_type(struct pcihp_slotinfo *);
258/* sysevent function */
259static void pcihp_gen_sysevent(char *, int, int, dev_info_t *, int);
260
261static int pcihp_list_occupants(dev_info_t *, void *);
262static int pcihp_indirect_map(dev_info_t *dip);
263
264#if 0
265static void pcihp_probe_slot_state(dev_info_t *, int, hpc_slot_state_t *);
266#endif
267
268int pcihp_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op,
269    int flags, char *name, caddr_t valuep, int *lengthp);
270
271struct cb_ops pcihp_cb_ops = {
272	pcihp_open,			/* open */
273	pcihp_close,			/* close */
274	nodev,				/* strategy */
275	nodev,				/* print */
276	nodev,				/* dump */
277	nodev,				/* read */
278	nodev,				/* write */
279	pcihp_ioctl,			/* ioctl */
280	nodev,				/* devmap */
281	nodev,				/* mmap */
282	nodev,				/* segmap */
283	nochpoll,			/* poll */
284	pcihp_prop_op,			/* cb_prop_op */
285	NULL,				/* streamtab */
286	D_NEW | D_MP | D_HOTPLUG,	/* Driver compatibility flag */
287	CB_REV,				/* rev */
288	nodev,				/* int (*cb_aread)() */
289	nodev				/* int (*cb_awrite)() */
290};
291
292/*
293 * local data
294 */
295
296int pcihp_autocfg_enabled = 1; /* auto config is enabled by default */
297
298static kmutex_t pcihp_mutex; /* mutex to protect the following data */
299static pcihp_t *pcihp_head = NULL;
300
301static kmutex_t pcihp_open_mutex; /* mutex to protect open/close/uninit */
302static int	pci_devlink_flags = 0;
303
304/*
305 * Module linkage information for the kernel.
306 */
307extern struct mod_ops mod_miscops;
308static struct modlmisc modlmisc = {
309	&mod_miscops,
310	"PCI nexus hotplug support",
311};
312
313static struct modlinkage modlinkage = {
314	MODREV_1,
315	&modlmisc,
316	NULL
317};
318
319int
320_init(void)
321{
322	int error;
323
324	mutex_init(&pcihp_mutex, NULL, MUTEX_DRIVER, NULL);
325	mutex_init(&pcihp_open_mutex, NULL, MUTEX_DRIVER, NULL);
326	if ((error = mod_install(&modlinkage)) != 0) {
327		mutex_destroy(&pcihp_open_mutex);
328		mutex_destroy(&pcihp_mutex);
329	}
330
331	return (error);
332}
333
334int
335_fini(void)
336{
337	return (EBUSY);
338}
339
340int
341_info(struct modinfo *modinfop)
342{
343	return (mod_info(&modlinkage, modinfop));
344}
345
346static	pcihp_t *
347pcihp_create_soft_state(
348	dev_info_t *dip)
349{
350	pcihp_t	*pcihp_p;
351
352	pcihp_p = kmem_zalloc(sizeof (struct pcihp), KM_SLEEP);
353
354	pcihp_p->dip = dip;
355	mutex_init(&pcihp_p->mutex, NULL, MUTEX_DRIVER, NULL);
356
357	mutex_enter(&pcihp_mutex);
358	pcihp_p->nextp = pcihp_head;
359	pcihp_head = pcihp_p;
360	pcihp_p->bus_state = PCIHP_BUS_INITIALIZING;
361	pcihp_p->slots_active = 0;
362	mutex_exit(&pcihp_mutex);
363
364	return (pcihp_p);
365}
366
367static	void
368pcihp_destroy_soft_state(
369	dev_info_t *dip)
370{
371	pcihp_t	*p;
372	pcihp_t	**pp;
373
374	mutex_enter(&pcihp_mutex);
375	pp = &pcihp_head;
376	while ((p = *pp) != NULL) {
377		if (p->dip == dip) {
378			*pp = p->nextp;
379			kmem_free(p, sizeof (struct pcihp));
380			break;
381		}
382		pp = &(p->nextp);
383	}
384	mutex_exit(&pcihp_mutex);
385}
386
387/*
388 * This function should be imported by client nexus drivers as their
389 * devo_getinfo() entry point.
390 */
391
392/* ARGSUSED */
393int
394pcihp_info(
395	dev_info_t	*dip,
396	ddi_info_cmd_t	cmd,
397	void		*arg,
398	void		**result)
399{
400	pcihp_t		*pcihp_p;
401	major_t		major;
402	minor_t		minor;
403	int		instance;
404
405	major = getmajor((dev_t)arg);
406	minor = getminor((dev_t)arg);
407	instance = PCIHP_AP_MINOR_NUM_TO_INSTANCE(minor);
408
409	switch (cmd) {
410	default:
411		return (DDI_FAILURE);
412
413	case DDI_INFO_DEVT2INSTANCE:
414		*result = (void *)(intptr_t)instance;
415		return (DDI_SUCCESS);
416
417	case DDI_INFO_DEVT2DEVINFO:
418		mutex_enter(&pcihp_mutex);
419		pcihp_p = pcihp_head;
420		while (pcihp_p != NULL) {
421			if (ddi_driver_major(pcihp_p->dip) ==
422			    major && ddi_get_instance(pcihp_p->dip) ==
423			    instance) {
424				*result = (void *)pcihp_p->dip;
425				mutex_exit(&pcihp_mutex);
426				return (DDI_SUCCESS);
427			}
428			pcihp_p = pcihp_p->nextp;
429		}
430		mutex_exit(&pcihp_mutex);
431		return (DDI_FAILURE);
432	}
433}
434
435/*
436 * This function retrieves the hot plug soft state and performs the
437 * following primitive commands while the soft state is locked:
438 * mark the bus unconfigured, increment slot activity, decrement
439 * slot activity and noop.
440 */
441
442/* ARGSUSED */
443static	pcihp_t *
444pcihp_get_soft_state(
445	dev_info_t	*dip, int cmd, int *rv)
446{
447	pcihp_t		*pcihp_p;
448
449	*rv = PCIHP_SUCCESS;
450	mutex_enter(&pcihp_mutex);
451	pcihp_p = pcihp_head;
452	while (pcihp_p != NULL) {
453		if (pcihp_p->dip == dip) {
454			switch (cmd) {
455			case PCIHP_DR_BUS_UNCONFIGURE:
456				if (pcihp_p->slots_active == 0)
457					pcihp_p->bus_state =
458					    PCIHP_BUS_UNCONFIGURED;
459				else
460					*rv = PCIHP_FAILURE;
461				break;
462			case PCIHP_DR_SLOT_ENTER:
463				if (pcihp_p->bus_state ==
464				    PCIHP_BUS_UNCONFIGURED)
465					*rv = PCIHP_FAILURE;
466				else
467					pcihp_p->slots_active++;
468				break;
469			case PCIHP_DR_SLOT_EXIT:
470				ASSERT(pcihp_p->slots_active > 0);
471				if (pcihp_p->slots_active == 0)
472					cmn_err(CE_PANIC,
473					    "pcihp (%s%d): mismatched slot"
474					    " activity",
475					    ddi_driver_name(dip),
476					    ddi_get_instance(dip));
477				else
478					pcihp_p->slots_active--;
479				break;
480			case PCIHP_DR_NOOP:
481				break;
482			default:
483				*rv = PCIHP_FAILURE;
484				break;
485			}
486			mutex_exit(&pcihp_mutex);
487			return (pcihp_p);
488		}
489		pcihp_p = pcihp_p->nextp;
490	}
491	mutex_exit(&pcihp_mutex);
492
493	return (NULL);
494}
495
496/* ARGSUSED3 */
497static int
498pcihp_open(dev_t *devp, int flags, int otyp, cred_t *credp)
499{
500	dev_info_t *self;
501	pcihp_t *pcihp_p;
502	minor_t	minor;
503	int pci_dev;
504	int rv;
505
506	/*
507	 * Make sure the open is for the right file type.
508	 */
509	if (otyp != OTYP_CHR)
510		return (EINVAL);
511
512	mutex_enter(&pcihp_open_mutex);
513	/*
514	 * Get the soft state structure.
515	 */
516	if (pcihp_info(NULL, DDI_INFO_DEVT2DEVINFO, (void *)*devp,
517	    (void **)&self) != DDI_SUCCESS) {
518		mutex_exit(&pcihp_open_mutex);
519		return (ENXIO);
520	}
521
522	pcihp_p = pcihp_get_soft_state(self, PCIHP_DR_NOOP, &rv);
523	ASSERT(pcihp_p != NULL);
524
525	mutex_enter(&pcihp_p->mutex);
526
527	/*
528	 * If the pci_dev is valid then the minor device is an
529	 * AP. Otherwise it is ":devctl" minor device.
530	 */
531	minor = getminor(*devp);
532	pci_dev = PCIHP_AP_MINOR_NUM_TO_PCI_DEVNUM(minor);
533	if (pci_dev < PCI_MAX_DEVS) {
534		struct pcihp_slotinfo *slotinfop;
535
536		slotinfop = &pcihp_p->slotinfo[pci_dev];
537		if (slotinfop->slot_hdl == NULL) {
538			mutex_exit(&pcihp_p->mutex);
539			mutex_exit(&pcihp_open_mutex);
540			return (ENXIO);
541		}
542	}
543
544	/*
545	 * Handle the open by tracking the device state.
546	 *
547	 * Note: Needs review w.r.t exclusive access to AP or the bus.
548	 * Currently in the pci plug-in we don't use EXCL open at all
549	 * so the code below implements EXCL access on the bus.
550	 */
551
552	/* enforce exclusive access to the bus */
553	if ((pcihp_p->soft_state == PCIHP_SOFT_STATE_OPEN_EXCL) ||
554	    ((flags & FEXCL) &&
555	    (pcihp_p->soft_state != PCIHP_SOFT_STATE_CLOSED))) {
556		mutex_exit(&pcihp_p->mutex);
557		mutex_exit(&pcihp_open_mutex);
558		return (EBUSY);
559	}
560
561	if (flags & FEXCL)
562		pcihp_p->soft_state = PCIHP_SOFT_STATE_OPEN_EXCL;
563	else
564		pcihp_p->soft_state = PCIHP_SOFT_STATE_OPEN;
565
566	mutex_exit(&pcihp_p->mutex);
567	mutex_exit(&pcihp_open_mutex);
568
569	return (0);
570}
571
572/* ARGSUSED */
573static int
574pcihp_close(dev_t dev, int flags, int otyp, cred_t *credp)
575{
576	dev_info_t *self;
577	pcihp_t *pcihp_p;
578	int rv;
579
580	if (otyp != OTYP_CHR)
581		return (EINVAL);
582
583	mutex_enter(&pcihp_open_mutex);
584
585	if (pcihp_info(NULL, DDI_INFO_DEVT2DEVINFO, (void *)dev,
586	    (void **)&self) != DDI_SUCCESS) {
587		mutex_exit(&pcihp_open_mutex);
588		return (ENXIO);
589	}
590
591	pcihp_p = pcihp_get_soft_state(self, PCIHP_DR_NOOP, &rv);
592	ASSERT(pcihp_p != NULL);
593
594	mutex_enter(&pcihp_p->mutex);
595	pcihp_p->soft_state = PCIHP_SOFT_STATE_CLOSED;
596	mutex_exit(&pcihp_p->mutex);
597
598	mutex_exit(&pcihp_open_mutex);
599
600	return (0);
601}
602
603static int
604pcihp_list_occupants(dev_info_t *dip, void *hdl)
605{
606	int pci_dev;
607	struct pcihp_config_ctrl *ctrl = (struct pcihp_config_ctrl *)hdl;
608	pci_regspec_t *pci_rp;
609	int length;
610	major_t major;
611
612	/*
613	 * Get the PCI device number information from the devinfo
614	 * node. Since the node may not have the address field
615	 * setup (this is done in the DDI_INITCHILD of the parent)
616	 * we look up the 'reg' property to decode that information.
617	 */
618	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip,
619	    DDI_PROP_DONTPASS, "reg", (int **)&pci_rp,
620	    (uint_t *)&length) != DDI_PROP_SUCCESS) {
621		ctrl->rv = DDI_FAILURE;
622		ctrl->dip = dip;
623		return (DDI_WALK_TERMINATE);
624	}
625
626	/* get the pci device id information */
627	pci_dev = PCI_REG_DEV_G(pci_rp->pci_phys_hi);
628
629	/*
630	 * free the memory allocated by ddi_prop_lookup_int_array
631	 */
632	ddi_prop_free(pci_rp);
633
634	/*
635	 * Match the node for the device number of the slot.
636	 */
637	if (pci_dev == ctrl->pci_dev) { /* node is a match */
638
639		major = ddi_driver_major(dip);
640
641		/*
642		 * If the node is not yet attached, then don't list it
643		 * as an occupant. This is valid, since nothing can be
644		 * consuming it until it is attached, and cfgadm will
645		 * ask for the property explicitly which will cause it
646		 * to be re-freshed right before checking with rcm.
647		 */
648		if ((major == -1) || !i_ddi_devi_attached(dip))
649			return (DDI_WALK_PRUNECHILD);
650
651		/*
652		 * If we have used all our occupants then print mesage
653		 * and terminate walk.
654		 */
655		if (ctrl->occupant->i >= HPC_MAX_OCCUPANTS) {
656			cmn_err(CE_WARN,
657			    "pcihp (%s%d): unable to list all occupants",
658			    ddi_driver_name(ddi_get_parent(dip)),
659			    ddi_get_instance(ddi_get_parent(dip)));
660			return (DDI_WALK_TERMINATE);
661		}
662
663		/*
664		 * No need to hold the dip as ddi_walk_devs
665		 * has already arranged that for us.
666		 */
667		ctrl->occupant->id[ctrl->occupant->i] =
668		    kmem_alloc(sizeof (char[MAXPATHLEN]), KM_SLEEP);
669		(void) ddi_pathname(dip,
670		    (char *)ctrl->occupant->id[ctrl->occupant->i]);
671		ctrl->occupant->i++;
672	}
673
674	/*
675	 * continue the walk to the next sibling to look for a match
676	 * or to find other nodes if this card is a multi-function card.
677	 */
678	return (DDI_WALK_PRUNECHILD);
679}
680
681static void
682pcihp_create_occupant_props_nolock(dev_info_t *self, dev_t dev, int pci_dev)
683{
684	struct pcihp_config_ctrl ctrl;
685	hpc_occupant_info_t *occupant;
686	int i;
687
688	occupant = kmem_alloc(sizeof (hpc_occupant_info_t), KM_SLEEP);
689	occupant->i = 0;
690
691	ctrl.flags = 0;
692	ctrl.dip = NULL;
693	ctrl.rv = NDI_SUCCESS;
694	ctrl.pci_dev = pci_dev;
695	ctrl.op = 55; /* should define DRYRUN */
696	ctrl.occupant = occupant;
697
698	ddi_walk_devs(ddi_get_child(self), pcihp_list_occupants,
699	    (void *)&ctrl);
700
701	if (occupant->i == 0) {
702		/* no occupants right now, need to create stub property */
703		char *c[] = { "" };
704		(void) ddi_prop_update_string_array(dev, self, "pci-occupant",
705		    c, 1);
706	} else {
707		(void) ddi_prop_update_string_array(dev, self, "pci-occupant",
708		    occupant->id, occupant->i);
709	}
710	for (i = 0; i < occupant->i; i++) {
711		kmem_free(occupant->id[i], sizeof (char[MAXPATHLEN]));
712	}
713
714	kmem_free(occupant, sizeof (hpc_occupant_info_t));
715}
716
717static void
718pcihp_create_occupant_props(dev_info_t *self, dev_t dev, int pci_dev)
719{
720	int circular;
721
722	ndi_devi_enter(self, &circular);
723	pcihp_create_occupant_props_nolock(self, dev, pci_dev);
724	ndi_devi_exit(self, circular);
725}
726
727static void
728pcihp_delete_occupant_props(dev_info_t *dip, dev_t dev)
729{
730	if (ddi_prop_remove(dev, dip, "pci-occupant")
731	    != DDI_PROP_SUCCESS)
732		return; /* add error handling */
733
734}
735
736/*
737 * pcihp_ioctl: devctl hotplug controls
738 */
739/* ARGSUSED */
740static int
741pcihp_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
742	int *rvalp)
743{
744	pcihp_t *pcihp_p;
745	dev_info_t *self;
746	struct devctl_iocdata *dcp;
747	uint_t bus_state;
748	int rv = 0;
749	int pci_dev;
750	struct pcihp_slotinfo *slotinfop;
751	hpc_slot_state_t rstate;
752	devctl_ap_state_t ap_state;
753	struct hpc_control_data hpc_ctrldata;
754	struct hpc_led_info led_info;
755	time_t time;
756	int state_locking;
757	int state_unlocking;
758	int rval;
759	char *pathname = NULL;
760
761	/*
762	 * read devctl ioctl data before soft state retrieval
763	 */
764	if ((cmd != DEVCTL_AP_CONTROL) &&
765	    ndi_dc_allochdl((void *)arg, &dcp) != NDI_SUCCESS)
766		return (EFAULT);
767
768	if (pcihp_info(NULL, DDI_INFO_DEVT2DEVINFO, (void *)dev,
769	    (void **)&self) != DDI_SUCCESS) {
770		if (cmd != DEVCTL_AP_CONTROL)
771			ndi_dc_freehdl(dcp);
772		return (ENXIO);
773	}
774
775	switch (cmd) {
776	case DEVCTL_AP_INSERT:
777	case DEVCTL_AP_REMOVE:
778	case DEVCTL_AP_CONNECT:
779	case DEVCTL_AP_DISCONNECT:
780	case DEVCTL_AP_CONFIGURE:
781	case DEVCTL_AP_UNCONFIGURE:
782	case DEVCTL_AP_GETSTATE:
783	case DEVCTL_AP_CONTROL:
784		state_locking = PCIHP_DR_SLOT_ENTER;
785		state_unlocking = PCIHP_DR_SLOT_EXIT;
786		break;
787	default:
788		state_locking = PCIHP_DR_NOOP;
789		state_unlocking = PCIHP_DR_NOOP;
790		break;
791	}
792
793	pcihp_p = pcihp_get_soft_state(self, state_locking, &rval);
794	ASSERT(pcihp_p != NULL);
795
796	if (rval == PCIHP_FAILURE) {
797		(void) ddi_pathname(pcihp_p->dip, pathname);
798		PCIHP_DEBUG((CE_WARN, "Hot Plug bus %s instance is unconfigured"
799		    " while slot activity is requested\n", pathname));
800		if (cmd != DEVCTL_AP_CONTROL)
801			ndi_dc_freehdl(dcp);
802		return (EBUSY);
803	}
804
805	/*
806	 * For attachment points the lower 8 bits of the minor number is the
807	 * PCI device number.
808	 */
809	pci_dev = PCIHP_AP_MINOR_NUM_TO_PCI_DEVNUM(getminor(dev));
810
811	/*
812	 * We can use the generic implementation for these ioctls
813	 */
814	switch (cmd) {
815	case DEVCTL_DEVICE_GETSTATE:
816	case DEVCTL_DEVICE_ONLINE:
817	case DEVCTL_DEVICE_OFFLINE:
818	case DEVCTL_BUS_GETSTATE:
819		rv = ndi_devctl_ioctl(self, cmd, arg, mode, 0);
820		ndi_dc_freehdl(dcp);
821		return (rv);
822	default:
823		break;
824	}
825
826	switch (cmd) {
827
828	case DEVCTL_DEVICE_RESET:
829		rv = ENOTSUP;
830		break;
831
832	case DEVCTL_BUS_QUIESCE:
833		if (ndi_get_bus_state(self, &bus_state) == NDI_SUCCESS)
834			if (bus_state == BUS_QUIESCED)
835				break;
836		(void) ndi_set_bus_state(self, BUS_QUIESCED);
837		break;
838
839	case DEVCTL_BUS_UNQUIESCE:
840		if (ndi_get_bus_state(self, &bus_state) == NDI_SUCCESS)
841			if (bus_state == BUS_ACTIVE)
842				break;
843		(void) ndi_set_bus_state(self, BUS_ACTIVE);
844		break;
845
846	case DEVCTL_BUS_RESET:
847		rv = ENOTSUP;
848		break;
849
850	case DEVCTL_BUS_RESETALL:
851		rv = ENOTSUP;
852		break;
853
854	case DEVCTL_AP_CONNECT:
855	case DEVCTL_AP_DISCONNECT:
856		/*
857		 * CONNECT(DISCONNECT) the hot plug slot to(from) the bus.
858		 *
859		 * For cPCI slots this operation is a nop so the HPC
860		 * driver may return success if it is a valid operation.
861		 */
862	case DEVCTL_AP_INSERT:
863	case DEVCTL_AP_REMOVE:
864		/*
865		 * Prepare the slot for INSERT/REMOVE operation.
866		 */
867
868		/*
869		 * check for valid request:
870		 *	1. It is a hotplug slot.
871		 *	2. The slot has no occupant that is in
872		 *	   the 'configured' state.
873		 */
874		if (pci_dev >= PCI_MAX_DEVS) {
875			rv = ENXIO;
876			break;
877		}
878		slotinfop = &pcihp_p->slotinfo[pci_dev];
879
880		mutex_enter(&slotinfop->slot_mutex);
881
882		if ((slotinfop->slot_hdl == NULL) ||
883		    (slotinfop->slot_flags & PCIHP_SLOT_DISABLED)) {
884			rv = ENXIO;
885			mutex_exit(&slotinfop->slot_mutex);
886			break;
887		}
888
889		/* the slot occupant must be in the UNCONFIGURED state */
890		if (slotinfop->ostate != AP_OSTATE_UNCONFIGURED) {
891			rv = EINVAL;
892			mutex_exit(&slotinfop->slot_mutex);
893			break;
894		}
895		/*
896		 * Call the HPC driver to perform the operation on the slot.
897		 */
898
899		switch (cmd) {
900		case DEVCTL_AP_INSERT:
901			rv = hpc_nexus_insert(slotinfop->slot_hdl, NULL, 0);
902			break;
903		case DEVCTL_AP_REMOVE:
904			rv = hpc_nexus_remove(slotinfop->slot_hdl, NULL, 0);
905			break;
906		case DEVCTL_AP_CONNECT:
907			rv = hpc_nexus_connect(slotinfop->slot_hdl, NULL, 0);
908			if (rv == HPC_SUCCESS) {
909				slotinfop->rstate = AP_RSTATE_CONNECTED;
910
911				if (drv_getparm(TIME, (void *)&time) !=
912				    DDI_SUCCESS)
913					slotinfop->last_change = (time_t)-1;
914				else
915					slotinfop->last_change = (time32_t)time;
916
917				slotinfop = &pcihp_p->slotinfo[pci_dev];
918				pcihp_gen_sysevent(slotinfop->name,
919				    PCIHP_DR_AP_STATE_CHANGE,
920				    SE_NO_HINT, pcihp_p->dip,
921				    KM_SLEEP);
922			}
923			break;
924		case DEVCTL_AP_DISCONNECT:
925			rv = hpc_nexus_disconnect(slotinfop->slot_hdl, NULL, 0);
926			if (rv == HPC_SUCCESS) {
927				slotinfop->rstate = AP_RSTATE_DISCONNECTED;
928
929				if (drv_getparm(TIME, (void *)&time) !=
930				    DDI_SUCCESS)
931					slotinfop->last_change = (time_t)-1;
932				else
933					slotinfop->last_change = (time32_t)time;
934
935				slotinfop = &pcihp_p->slotinfo[pci_dev];
936				pcihp_gen_sysevent(slotinfop->name,
937				    PCIHP_DR_AP_STATE_CHANGE,
938				    SE_NO_HINT, pcihp_p->dip,
939				    KM_SLEEP);
940			}
941			break;
942		}
943		mutex_exit(&slotinfop->slot_mutex);
944
945		switch (rv) {
946		case HPC_ERR_INVALID:
947			rv = ENXIO;
948			break;
949		case HPC_ERR_NOTSUPPORTED:
950			rv = ENOTSUP;
951			break;
952		case HPC_ERR_FAILED:
953			rv = EIO;
954			break;
955		}
956
957		break;
958
959	case DEVCTL_AP_CONFIGURE:
960		/*
961		 * **************************************
962		 * CONFIGURE the occupant in the slot.
963		 * **************************************
964		 */
965		slotinfop = &pcihp_p->slotinfo[pci_dev];
966
967		mutex_enter(&slotinfop->slot_mutex);
968
969		rv = pcihp_configure_ap(pcihp_p, pci_dev);
970		if (rv == HPC_SUCCESS) {
971			pcihp_gen_sysevent(slotinfop->name,
972			    PCIHP_DR_AP_STATE_CHANGE,
973			    SE_NO_HINT, pcihp_p->dip, KM_SLEEP);
974			pcihp_create_occupant_props(self, dev, pci_dev);
975		}
976		mutex_exit(&slotinfop->slot_mutex);
977
978		break;
979
980	case DEVCTL_AP_UNCONFIGURE:
981		/*
982		 * **************************************
983		 * UNCONFIGURE the occupant in the slot.
984		 * **************************************
985		 */
986		slotinfop = &pcihp_p->slotinfo[pci_dev];
987
988		mutex_enter(&slotinfop->slot_mutex);
989
990		rv = pcihp_unconfigure_ap(pcihp_p, pci_dev);
991
992		if (rv == HPC_SUCCESS) {
993			pcihp_gen_sysevent(slotinfop->name,
994			    PCIHP_DR_AP_STATE_CHANGE,
995			    SE_NO_HINT, pcihp_p->dip, KM_SLEEP);
996			pcihp_delete_occupant_props(pcihp_p->dip, dev);
997		}
998		mutex_exit(&slotinfop->slot_mutex);
999
1000		break;
1001
1002	case DEVCTL_AP_GETSTATE:
1003	{
1004		int mutex_held;
1005
1006		/*
1007		 * return the state of Attachment Point.
1008		 *
1009		 * If the occupant is in UNCONFIGURED state then
1010		 * we should get the receptacle state from the
1011		 * HPC driver because the receptacle state
1012		 * maintained in the nexus may not be accurate.
1013		 */
1014
1015		/*
1016		 * check for valid request:
1017		 *	1. It is a hotplug slot.
1018		 */
1019		slotinfop = &pcihp_p->slotinfo[pci_dev];
1020
1021		/* try to acquire the slot mutex */
1022		mutex_held = mutex_tryenter(&slotinfop->slot_mutex);
1023
1024		if (pci_dev >= PCI_MAX_DEVS || slotinfop->slot_hdl == NULL) {
1025			rv = ENXIO;
1026			if (mutex_held) {
1027				mutex_exit(&slotinfop->slot_mutex);
1028			}
1029			break;
1030		}
1031
1032		if (slotinfop->ostate == AP_OSTATE_UNCONFIGURED) {
1033			if (hpc_nexus_control(slotinfop->slot_hdl,
1034			    HPC_CTRL_GET_SLOT_STATE, (caddr_t)&rstate) != 0) {
1035				rv = EIO;
1036				if (mutex_held)
1037					mutex_exit(&slotinfop->slot_mutex);
1038				break;
1039			}
1040			slotinfop->rstate = (ap_rstate_t)rstate;
1041		}
1042
1043		ap_state.ap_rstate = slotinfop->rstate;
1044		ap_state.ap_ostate = slotinfop->ostate;
1045		ap_state.ap_condition = slotinfop->condition;
1046		ap_state.ap_last_change = slotinfop->last_change;
1047		ap_state.ap_error_code = 0; /* XXX */
1048		if (mutex_held)
1049			ap_state.ap_in_transition = 0; /* AP is not busy */
1050		else
1051			ap_state.ap_in_transition = 1; /* AP is busy */
1052
1053		if (mutex_held)
1054			mutex_exit(&slotinfop->slot_mutex);
1055
1056		/* copy the return-AP-state information to the user space */
1057		if (ndi_dc_return_ap_state(&ap_state, dcp) != NDI_SUCCESS)
1058			rv = EFAULT;
1059
1060		break;
1061
1062	}
1063	case DEVCTL_AP_CONTROL:
1064		/*
1065		 * HPC control functions:
1066		 *	HPC_CTRL_ENABLE_SLOT/HPC_CTRL_DISABLE_SLOT
1067		 *		Changes the state of the slot and preserves
1068		 *		the state across the reboot.
1069		 *	HPC_CTRL_ENABLE_AUTOCFG/HPC_CTRL_DISABLE_AUTOCFG
1070		 *		Enables or disables the auto configuration
1071		 *		of hot plugged occupant if the hardware
1072		 *		supports notification of the hot plug
1073		 *		events.
1074		 *	HPC_CTRL_GET_LED_STATE/HPC_CTRL_SET_LED_STATE
1075		 *		Controls the state of an LED.
1076		 *	HPC_CTRL_GET_SLOT_INFO
1077		 *		Get slot information data structure
1078		 *		(hpc_slot_info_t).
1079		 *	HPC_CTRL_GET_BOARD_TYPE
1080		 *		Get board type information (hpc_board_type_t).
1081		 *	HPC_CTRL_GET_CARD_INFO
1082		 *		Get card information (hpc_card_info_t).
1083		 *
1084		 * These control functions are used by the cfgadm plug-in
1085		 * to implement "-x" and "-v" options.
1086		 */
1087
1088		/* copy user ioctl data first */
1089		switch (ddi_model_convert_from(mode & FMODELS)) {
1090		case DDI_MODEL_ILP32: {
1091			struct hpc_control32_data hpc_ctrldata32;
1092
1093			if (copyin((void *)arg, (void *)&hpc_ctrldata32,
1094				sizeof (struct hpc_control32_data)) != 0) {
1095				rv = EFAULT;
1096				break;
1097			}
1098			hpc_ctrldata.cmd = hpc_ctrldata32.cmd;
1099			hpc_ctrldata.data =
1100			    (void *)(intptr_t)hpc_ctrldata32.data;
1101			break;
1102		}
1103		case DDI_MODEL_NONE:
1104			if (copyin((void *)arg, (void *)&hpc_ctrldata,
1105			    sizeof (struct hpc_control_data)) != 0) {
1106				rv = EFAULT;
1107			}
1108			break;
1109		default:
1110			rv = EFAULT;
1111			break;
1112		}
1113		if (rv == EFAULT)
1114			break;
1115		/*
1116		 * check for valid request:
1117		 *	1. It is a hotplug slot.
1118		 */
1119		slotinfop = &pcihp_p->slotinfo[pci_dev];
1120
1121		mutex_enter(&slotinfop->slot_mutex);
1122
1123		if (pci_dev >= PCI_MAX_DEVS || slotinfop->slot_hdl == NULL) {
1124			rv = ENXIO;
1125			mutex_exit(&slotinfop->slot_mutex);
1126			break;
1127		}
1128
1129		switch (hpc_ctrldata.cmd) {
1130
1131		case HPC_CTRL_GET_LED_STATE:
1132			/* copy the led info from the user space */
1133			if (copyin(hpc_ctrldata.data, (void *)&led_info,
1134			    sizeof (hpc_led_info_t)) != 0) {
1135				rv = EFAULT;
1136				break;
1137			}
1138
1139			/* get the state of LED information */
1140			if (hpc_nexus_control(slotinfop->slot_hdl,
1141			    HPC_CTRL_GET_LED_STATE, (caddr_t)&led_info) != 0) {
1142
1143				if (rv != ENOTSUP)
1144					rv = EIO;
1145
1146				break;
1147			}
1148
1149			/* copy the led info to the user space */
1150			if (copyout((void *)&led_info, hpc_ctrldata.data,
1151			    sizeof (hpc_led_info_t)) != 0) {
1152				rv = EFAULT;
1153				break;
1154			}
1155
1156			break;
1157
1158		case HPC_CTRL_SET_LED_STATE:
1159			/* copy the led info from the user space */
1160			if (copyin(hpc_ctrldata.data, (void *)&led_info,
1161			    sizeof (hpc_led_info_t)) != 0) {
1162				rv = EFAULT;
1163				break;
1164			}
1165
1166			/* set the state of an LED */
1167			rv = hpc_nexus_control(slotinfop->slot_hdl,
1168			    HPC_CTRL_SET_LED_STATE, (caddr_t)&led_info);
1169
1170			/*
1171			 * If the Hotswap Controller does not support
1172			 * LED management (as you would find typically
1173			 * in the cPCI industry), then we handle the
1174			 * blue LED on/off/blink operations, just in
1175			 * case it helps slot identification.
1176			 */
1177			if ((rv == HPC_ERR_NOTSUPPORTED) &&
1178			    (slotinfop->slot_type & HPC_SLOT_TYPE_CPCI)) {
1179				if (led_info.led != HPC_ATTN_LED)
1180					break;
1181
1182				switch (led_info.state) {
1183				case HPC_LED_OFF:
1184					pcihp_hs_csr_op(pcihp_p,
1185					    pci_dev,
1186					    HPC_EVENT_SLOT_BLUE_LED_OFF);
1187					rv = 0;
1188					break;
1189				case HPC_LED_ON:
1190					/*
1191					 * Please note that leaving
1192					 * LED ON could be dangerous
1193					 * as it means it is Ok to
1194					 * remove the board, which
1195					 * is not what we want to
1196					 * convey. So it is upto the
1197					 * user to take care of this
1198					 * situation and usage.
1199					 *
1200					 * Normally, a Blink command
1201					 * is more appropriate for
1202					 * identifying a board.
1203					 */
1204					pcihp_hs_csr_op(pcihp_p,
1205					    pci_dev,
1206					    HPC_EVENT_SLOT_BLUE_LED_ON);
1207					rv = 0;
1208					break;
1209				case HPC_LED_BLINK:
1210				{
1211					int bl;
1212
1213					for (bl = 0; bl < 2; bl++) {
1214						pcihp_hs_csr_op(pcihp_p,
1215						    pci_dev,
1216						    HPC_EVENT_SLOT_BLUE_LED_ON);
1217						delay(pcihp_cpci_led_blink);
1218					pcihp_hs_csr_op(pcihp_p,
1219					    pci_dev,
1220					    HPC_EVENT_SLOT_BLUE_LED_OFF);
1221						delay(pcihp_cpci_led_blink);
1222					}
1223					rv = 0;
1224					break;
1225				}
1226				default:
1227					break;
1228				}
1229			}
1230
1231			if (rv == HPC_ERR_FAILED)
1232				rv = EIO;
1233			break;
1234
1235		case HPC_CTRL_ENABLE_SLOT:
1236
1237			/*
1238			 * If slot already enabled, do not send a duplicate
1239			 * control message to the HPC driver.
1240			 */
1241			if ((slotinfop->slot_flags & PCIHP_SLOT_DISABLED) == 0)
1242				break;
1243
1244			/* tell the HPC driver also */
1245			if (hpc_nexus_control(slotinfop->slot_hdl,
1246			    HPC_CTRL_ENABLE_SLOT, NULL) != HPC_SUCCESS) {
1247				rv = EIO;
1248				break;
1249			}
1250
1251			/*
1252			 * Enable the slot for hotplug operations.
1253			 */
1254			slotinfop->slot_flags &= ~PCIHP_SLOT_DISABLED;
1255
1256			slotinfop->condition = AP_COND_UNKNOWN;
1257
1258			/* XXX need to preserve this state across reboot? */
1259
1260			break;
1261
1262		case HPC_CTRL_DISABLE_SLOT:
1263
1264			/* Do not disable if occupant configured */
1265			if (slotinfop->ostate == AP_OSTATE_CONFIGURED) {
1266				rv = EAGAIN;
1267				break;
1268			}
1269
1270			/* tell the HPC driver also */
1271			if (hpc_nexus_control(slotinfop->slot_hdl,
1272			    HPC_CTRL_DISABLE_SLOT, NULL) != HPC_SUCCESS) {
1273				rv = EIO;
1274				break;
1275			}
1276
1277			/*
1278			 * Disable the slot for hotplug operations.
1279			 */
1280			slotinfop->slot_flags |= PCIHP_SLOT_DISABLED;
1281
1282			slotinfop->condition = AP_COND_UNUSABLE;
1283
1284			/* XXX need to preserve this state across reboot? */
1285
1286			break;
1287
1288		case HPC_CTRL_ENABLE_AUTOCFG:
1289			/*
1290			 * Enable auto configuration on this slot.
1291			 */
1292			slotinfop->slot_flags |= PCIHP_SLOT_AUTO_CFG_EN;
1293
1294			/* tell the HPC driver also */
1295			(void) hpc_nexus_control(slotinfop->slot_hdl,
1296			    HPC_CTRL_ENABLE_AUTOCFG, NULL);
1297
1298			if (slotinfop->slot_type & HPC_SLOT_TYPE_CPCI)
1299				pcihp_hs_csr_op(pcihp_p, pci_dev,
1300				    HPC_EVENT_ENABLE_ENUM);
1301			break;
1302
1303		case HPC_CTRL_DISABLE_AUTOCFG:
1304			/*
1305			 * Disable auto configuration on this slot.
1306			 */
1307			slotinfop->slot_flags &= ~PCIHP_SLOT_AUTO_CFG_EN;
1308
1309			/* tell the HPC driver also */
1310			(void) hpc_nexus_control(slotinfop->slot_hdl,
1311			    HPC_CTRL_DISABLE_AUTOCFG, NULL);
1312
1313			if (slotinfop->slot_type & HPC_SLOT_TYPE_CPCI)
1314				pcihp_hs_csr_op(pcihp_p, pci_dev,
1315				    HPC_EVENT_DISABLE_ENUM);
1316			break;
1317
1318		case HPC_CTRL_GET_BOARD_TYPE:
1319		{
1320			hpc_board_type_t board_type;
1321
1322			/*
1323			 * Get board type data structure, hpc_board_type_t.
1324			 */
1325			board_type = pcihp_get_board_type(slotinfop);
1326			if (board_type == -1) {
1327				rv = ENXIO;
1328				break;
1329			}
1330
1331			/* copy the board type info to the user space */
1332			if (copyout((void *)&board_type, hpc_ctrldata.data,
1333			    sizeof (hpc_board_type_t)) != 0) {
1334				rv = ENXIO;
1335				break;
1336			}
1337
1338			break;
1339		}
1340
1341		case HPC_CTRL_GET_SLOT_INFO:
1342		{
1343			hpc_slot_info_t slot_info;
1344
1345			/*
1346			 * Get slot information structure, hpc_slot_info_t.
1347			 */
1348			slot_info.version = HPC_SLOT_INFO_VERSION;
1349			slot_info.slot_type = slotinfop->slot_type;
1350			slot_info.pci_slot_capabilities =
1351			    slotinfop->slot_capabilities;
1352			slot_info.pci_dev_num = (uint16_t)pci_dev;
1353			(void) strcpy(slot_info.pci_slot_name, slotinfop->name);
1354
1355			/* copy the slot info structure to the user space */
1356			if (copyout((void *)&slot_info, hpc_ctrldata.data,
1357			    sizeof (hpc_slot_info_t)) != 0) {
1358				rv = EFAULT;
1359				break;
1360			}
1361
1362			break;
1363		}
1364
1365		case HPC_CTRL_GET_CARD_INFO:
1366		{
1367			hpc_card_info_t card_info;
1368			ddi_acc_handle_t handle;
1369			dev_info_t *cdip;
1370
1371			/*
1372			 * Get card information structure, hpc_card_info_t.
1373			 */
1374
1375			/* verify that the card is configured */
1376			if ((slotinfop->ostate != AP_OSTATE_CONFIGURED) ||
1377			    ((cdip = pcihp_devi_find(self,
1378			    pci_dev, 0)) == NULL)) {
1379				/*
1380				 * either the card is not present or
1381				 * it is not configured.
1382				 */
1383				rv = ENXIO;
1384				break;
1385			}
1386
1387			/*
1388			 * If declared failed, don't allow Config operations.
1389			 * Otherwise, if good or failing, it is assumed Ok
1390			 * to get config data.
1391			 */
1392			if (slotinfop->condition == AP_COND_FAILED) {
1393				rv = EIO;
1394				break;
1395			}
1396
1397			/* get the information from the PCI config header */
1398			/* for the function 0.				  */
1399			if (pci_config_setup(cdip, &handle) != DDI_SUCCESS) {
1400				rv = EIO;
1401				break;
1402			}
1403			card_info.prog_class = pci_config_get8(handle,
1404			    PCI_CONF_PROGCLASS);
1405			card_info.base_class = pci_config_get8(handle,
1406			    PCI_CONF_BASCLASS);
1407			card_info.sub_class = pci_config_get8(handle,
1408			    PCI_CONF_SUBCLASS);
1409			card_info.header_type = pci_config_get8(handle,
1410			    PCI_CONF_HEADER);
1411			pci_config_teardown(&handle);
1412
1413			/* copy the card info structure to the user space */
1414			if (copyout((void *)&card_info, hpc_ctrldata.data,
1415			    sizeof (hpc_card_info_t)) != 0) {
1416				rv = EFAULT;
1417				break;
1418			}
1419
1420			break;
1421		}
1422
1423		default:
1424			rv = EINVAL;
1425			break;
1426		}
1427
1428		mutex_exit(&slotinfop->slot_mutex);
1429
1430		break;
1431
1432	default:
1433		rv = ENOTTY;
1434	}
1435
1436	if (cmd != DEVCTL_AP_CONTROL)
1437		ndi_dc_freehdl(dcp);
1438
1439	(void) pcihp_get_soft_state(self, state_unlocking, &rval);
1440
1441	return (rv);
1442}
1443
1444/*
1445 * **************************************
1446 * CONFIGURE the occupant in the slot.
1447 * **************************************
1448 */
1449static int
1450pcihp_configure_ap(pcihp_t *pcihp_p, int pci_dev)
1451{
1452	dev_info_t *self = pcihp_p->dip;
1453	int rv = HPC_SUCCESS;
1454	struct pcihp_slotinfo *slotinfop;
1455	hpc_slot_state_t rstate;
1456	struct pcihp_config_ctrl ctrl;
1457	int circular_count;
1458	time_t time;
1459
1460	/*
1461	 * check for valid request:
1462	 *	1. It is a hotplug slot.
1463	 *	2. The receptacle is in the CONNECTED state.
1464	 */
1465	slotinfop = &pcihp_p->slotinfo[pci_dev];
1466
1467
1468
1469	if ((pci_dev >= PCI_MAX_DEVS) || (slotinfop->slot_hdl == NULL) ||
1470	    (slotinfop->slot_flags & PCIHP_SLOT_DISABLED)) {
1471
1472		return (ENXIO);
1473	}
1474
1475	/*
1476	 * If the occupant is already in (partially?) configured
1477	 * state then call the ndi_devi_online() on the device
1478	 * subtree(s) for this attachment point.
1479	 */
1480
1481	if (slotinfop->ostate == AP_OSTATE_CONFIGURED) {
1482		ctrl.flags = PCIHP_CFG_CONTINUE;
1483		ctrl.rv = NDI_SUCCESS;
1484		ctrl.dip = NULL;
1485		ctrl.pci_dev = pci_dev;
1486		ctrl.op = PCIHP_ONLINE;
1487
1488		ndi_devi_enter(self, &circular_count);
1489		ddi_walk_devs(ddi_get_child(self), pcihp_configure,
1490		    (void *)&ctrl);
1491		ndi_devi_exit(self, circular_count);
1492
1493		if (ctrl.rv != NDI_SUCCESS) {
1494			/*
1495			 * one or more of the devices are not
1496			 * onlined. How is this to be reported?
1497			 */
1498			cmn_err(CE_WARN,
1499			    "pcihp (%s%d): failed to attach one or"
1500			    " more drivers for the card in the slot %s",
1501			    ddi_driver_name(self), ddi_get_instance(self),
1502			    slotinfop->name);
1503			/* rv = EFAULT; */
1504		}
1505		/* tell HPC driver that the occupant is configured */
1506		(void) hpc_nexus_control(slotinfop->slot_hdl,
1507		    HPC_CTRL_DEV_CONFIGURED, NULL);
1508
1509		if (drv_getparm(TIME, (void *)&time) != DDI_SUCCESS)
1510			slotinfop->last_change = (time_t)-1;
1511		else
1512			slotinfop->last_change = (time32_t)time;
1513
1514
1515		return (rv);
1516	}
1517
1518	/*
1519	 * Occupant is in the UNCONFIGURED state.
1520	 */
1521
1522	/* Check if the receptacle is in the CONNECTED state. */
1523	if (hpc_nexus_control(slotinfop->slot_hdl,
1524	    HPC_CTRL_GET_SLOT_STATE, (caddr_t)&rstate) != 0) {
1525
1526		return (ENXIO);
1527	}
1528
1529	if (rstate == HPC_SLOT_EMPTY) {
1530		/* error. slot is empty */
1531
1532		return (ENXIO);
1533	}
1534
1535	if (rstate != HPC_SLOT_CONNECTED) {
1536		/* error. either the slot is empty or connect failed */
1537
1538		return (ENXIO);
1539	}
1540
1541	slotinfop->rstate = AP_RSTATE_CONNECTED; /* record rstate */
1542
1543	/* Turn INS and LED off, and start configuration. */
1544	if (slotinfop->slot_type & HPC_SLOT_TYPE_CPCI) {
1545		pcihp_hs_csr_op(pcihp_p, pci_dev, HPC_EVENT_SLOT_CONFIGURE);
1546		if (pcihp_cpci_blue_led)
1547			pcihp_hs_csr_op(pcihp_p, pci_dev,
1548			    HPC_EVENT_SLOT_BLUE_LED_OFF);
1549		slotinfop->slot_flags &= ~PCIHP_SLOT_ENUM_INS_PENDING;
1550	}
1551
1552	(void) hpc_nexus_control(slotinfop->slot_hdl,
1553	    HPC_CTRL_DEV_CONFIG_START, NULL);
1554
1555	/*
1556	 * Call the configurator to configure the card.
1557	 */
1558	if (pcicfg_configure(self, pci_dev, PCICFG_ALL_FUNC, 0)
1559	    != PCICFG_SUCCESS) {
1560		if (slotinfop->slot_type & HPC_SLOT_TYPE_CPCI) {
1561			if (pcihp_cpci_blue_led)
1562				pcihp_hs_csr_op(pcihp_p, pci_dev,
1563				    HPC_EVENT_SLOT_BLUE_LED_ON);
1564			pcihp_hs_csr_op(pcihp_p, pci_dev,
1565			    HPC_EVENT_SLOT_UNCONFIGURE);
1566		}
1567		/* tell HPC driver occupant configure Error */
1568		(void) hpc_nexus_control(slotinfop->slot_hdl,
1569		    HPC_CTRL_DEV_CONFIG_FAILURE, NULL);
1570
1571		return (EIO);
1572	}
1573
1574	/* record the occupant state as CONFIGURED */
1575	slotinfop->ostate = AP_OSTATE_CONFIGURED;
1576	slotinfop->condition = AP_COND_OK;
1577
1578	/* now, online all the devices in the AP */
1579	ctrl.flags = PCIHP_CFG_CONTINUE;
1580	ctrl.rv = NDI_SUCCESS;
1581	ctrl.dip = NULL;
1582	ctrl.pci_dev = pci_dev;
1583	ctrl.op = PCIHP_ONLINE;
1584
1585	ndi_devi_enter(self, &circular_count);
1586	ddi_walk_devs(ddi_get_child(self), pcihp_configure, (void *)&ctrl);
1587	ndi_devi_exit(self, circular_count);
1588
1589	if (ctrl.rv != NDI_SUCCESS) {
1590		/*
1591		 * one or more of the devices are not
1592		 * ONLINE'd. How is this to be
1593		 * reported?
1594		 */
1595		cmn_err(CE_WARN,
1596		    "pcihp (%s%d): failed to attach one or"
1597		    " more drivers for the card in the slot %s",
1598		    ddi_driver_name(pcihp_p->dip),
1599		    ddi_get_instance(pcihp_p->dip),
1600		    slotinfop->name);
1601		/* rv = EFAULT; */
1602	}
1603	/* store HS_CSR location.  No events, jut a read operation. */
1604	if (slotinfop->slot_type & HPC_SLOT_TYPE_CPCI)
1605		pcihp_hs_csr_op(pcihp_p, pci_dev, -1);
1606
1607	/* tell HPC driver that the occupant is configured */
1608	(void) hpc_nexus_control(slotinfop->slot_hdl,
1609	    HPC_CTRL_DEV_CONFIGURED, NULL);
1610
1611
1612	return (rv);
1613}
1614
1615/*
1616 * **************************************
1617 * UNCONFIGURE the occupant in the slot.
1618 * **************************************
1619 */
1620static int
1621pcihp_unconfigure_ap(pcihp_t *pcihp_p, int pci_dev)
1622{
1623	dev_info_t *self = pcihp_p->dip;
1624	int rv = HPC_SUCCESS;
1625	struct pcihp_slotinfo *slotinfop;
1626	struct pcihp_config_ctrl ctrl;
1627	int circular_count;
1628	time_t time;
1629
1630	/*
1631	 * check for valid request:
1632	 *	1. It is a hotplug slot.
1633	 *	2. The occupant is in the CONFIGURED state.
1634	 */
1635	slotinfop = &pcihp_p->slotinfo[pci_dev];
1636
1637
1638
1639	if ((pci_dev >= PCI_MAX_DEVS) || (slotinfop->slot_hdl == NULL) ||
1640	    (slotinfop->slot_flags & PCIHP_SLOT_DISABLED)) {
1641
1642		return (ENXIO);
1643	}
1644	/*
1645	 * The following may not need to be there, as we should
1646	 * support unconfiguring of boards and free resources
1647	 * even when the board is not hotswappable. But this is
1648	 * the only way, we may be able to tell the system
1649	 * administrator that it is not a hotswap board since
1650	 * disconnect operation is never called.
1651	 * This way we help the system administrator from not
1652	 * accidentally removing a non hotswap board and
1653	 * possibly destroying it. May be this behavior can
1654	 * be a default, and can be enabled or disabled via
1655	 * a global flag.
1656	 */
1657	if (slotinfop->slot_type & HPC_SLOT_TYPE_CPCI) {
1658		if (slotinfop->slot_flags & PCIHP_SLOT_DEV_NON_HOTPLUG) {
1659			/* Operation unsupported if no HS board/slot */
1660			return (ENOTSUP);
1661		}
1662	}
1663
1664	/*
1665	 * If the occupant is in the CONFIGURED state then
1666	 * call the configurator to unconfigure the slot.
1667	 */
1668	if (slotinfop->ostate == AP_OSTATE_CONFIGURED) {
1669
1670		/*
1671		 * since potential state change is imminent mask
1672		 * enum events to prevent the slot from being re-configured
1673		 */
1674		pcihp_hs_csr_op(pcihp_p, pci_dev, HPC_EVENT_DISABLE_ENUM);
1675
1676		/*
1677		 * Detach all the drivers for the devices in the
1678		 * slot. Call pcihp_configure() to do this.
1679		 */
1680		ctrl.flags = 0;
1681		ctrl.rv = NDI_SUCCESS;
1682		ctrl.dip = NULL;
1683		ctrl.pci_dev = pci_dev;
1684		ctrl.op = PCIHP_OFFLINE;
1685
1686		(void) devfs_clean(self, NULL, DV_CLEAN_FORCE);
1687		ndi_devi_enter(self, &circular_count);
1688		ddi_walk_devs(ddi_get_child(self), pcihp_configure,
1689		    (void *)&ctrl);
1690		ndi_devi_exit(self, circular_count);
1691
1692		if (ctrl.rv != NDI_SUCCESS) {
1693			/*
1694			 * Failed to detach one or more drivers
1695			 * Restore the state of drivers which
1696			 * are offlined during this operation.
1697			 */
1698			ctrl.flags = 0;
1699			ctrl.rv = NDI_SUCCESS;
1700			ctrl.dip = NULL;
1701			ctrl.pci_dev = pci_dev;
1702			ctrl.op = PCIHP_ONLINE;
1703
1704			ndi_devi_enter(self, &circular_count);
1705			ddi_walk_devs(ddi_get_child(self),
1706			    pcihp_configure, (void *)&ctrl);
1707			ndi_devi_exit(self, circular_count);
1708
1709			/* tell HPC driver that the occupant is Busy */
1710			(void) hpc_nexus_control(slotinfop->slot_hdl,
1711			    HPC_CTRL_DEV_UNCONFIG_FAILURE, NULL);
1712
1713			rv = EBUSY;
1714		} else {
1715			(void) hpc_nexus_control(slotinfop->slot_hdl,
1716			    HPC_CTRL_DEV_UNCONFIG_START, NULL);
1717
1718			if (pcicfg_unconfigure(self, pci_dev,
1719			    PCICFG_ALL_FUNC, 0) == PCICFG_SUCCESS) {
1720				/*
1721				 * Now that resources are freed,
1722				 * clear EXT and Turn LED ON.
1723				 */
1724				if (slotinfop->slot_type & HPC_SLOT_TYPE_CPCI) {
1725					pcihp_hs_csr_op(pcihp_p, pci_dev,
1726					    HPC_EVENT_SLOT_UNCONFIGURE);
1727					if (pcihp_cpci_blue_led)
1728						pcihp_hs_csr_op(pcihp_p,
1729						    pci_dev,
1730						    HPC_EVENT_SLOT_BLUE_LED_ON);
1731					slotinfop->hs_csr_location = 0;
1732					slotinfop->slot_flags &=
1733					    ~(PCIHP_SLOT_DEV_NON_HOTPLUG|
1734					    PCIHP_SLOT_ENUM_EXT_PENDING);
1735				}
1736				slotinfop->ostate = AP_OSTATE_UNCONFIGURED;
1737				slotinfop->condition = AP_COND_UNKNOWN;
1738				/*
1739				 * send the notification of state change
1740				 * to the HPC driver.
1741				 */
1742				(void) hpc_nexus_control(slotinfop->slot_hdl,
1743				    HPC_CTRL_DEV_UNCONFIGURED,
1744				    NULL);
1745			} else {
1746				/* tell HPC driver occupant unconfigure Error */
1747				(void) hpc_nexus_control(slotinfop->slot_hdl,
1748				    HPC_CTRL_DEV_UNCONFIG_FAILURE, NULL);
1749
1750				rv = EIO;
1751			}
1752		}
1753	}
1754
1755	if (drv_getparm(TIME, (void *)&time) != DDI_SUCCESS)
1756		slotinfop->last_change = (time_t)-1;
1757	else
1758		slotinfop->last_change = (time32_t)time;
1759
1760
1761
1762	/* unmask enum events again */
1763	if ((slotinfop->slot_flags & PCIHP_SLOT_AUTO_CFG_EN) == 0) {
1764		pcihp_hs_csr_op(pcihp_p, pci_dev, HPC_EVENT_ENABLE_ENUM);
1765	}
1766
1767	return (rv);
1768}
1769
1770/*
1771 * Accessor function to return pointer to the pci hotplug
1772 * cb_ops structure.
1773 */
1774struct cb_ops *
1775pcihp_get_cb_ops()
1776{
1777	return (&pcihp_cb_ops);
1778}
1779
1780/*
1781 * Setup function to initialize hot plug feature. Returns DDI_SUCCESS
1782 * for successful initialization, otherwise it returns DDI_FAILURE.
1783 *
1784 * It is assumed that this this function is called from the attach()
1785 * entry point of the PCI nexus driver.
1786 */
1787
1788int
1789pcihp_init(dev_info_t *dip)
1790{
1791	pcihp_t *pcihp_p;
1792	int i;
1793	caddr_t enum_data;
1794	int enum_size;
1795	int rv;
1796
1797	mutex_enter(&pcihp_open_mutex);
1798
1799	/*
1800	 * Make sure that it is not already initialized.
1801	 */
1802	if (pcihp_get_soft_state(dip, PCIHP_DR_NOOP, &rv) != NULL) {
1803		cmn_err(CE_WARN, "%s%d: pcihp instance already initialized!",
1804		    ddi_driver_name(dip), ddi_get_instance(dip));
1805		goto cleanup;
1806	}
1807
1808	/*
1809	 * Initialize soft state structure for the bus instance.
1810	 */
1811	if ((pcihp_p = pcihp_create_soft_state(dip)) == NULL) {
1812		cmn_err(CE_WARN, "%s%d: can't allocate pcihp structure",
1813		    ddi_driver_name(dip), ddi_get_instance(dip));
1814		goto cleanup;
1815	}
1816
1817	pcihp_p->soft_state = PCIHP_SOFT_STATE_CLOSED;
1818	/* XXX if bus is running at 66Mhz then set PCI_BUS_66MHZ bit */
1819	pcihp_p->bus_flags = 0;	/* XXX FIX IT */
1820
1821	/*
1822	 * If a platform wishes to implement Radial ENUM# routing
1823	 * a property "enum-impl" must be presented to us with a
1824	 * string value "radial".
1825	 * This helps us not go for polling operation (default)
1826	 * during a ENUM# event.
1827	 */
1828	if (ddi_getlongprop(DDI_DEV_T_ANY, dip, 0, "enum-impl",
1829	    (caddr_t)&enum_data, &enum_size) == DDI_PROP_SUCCESS) {
1830		if (strcmp(enum_data, "radial") == 0) {
1831			pcihp_p->bus_flags |= PCIHP_BUS_ENUM_RADIAL;
1832		}
1833		kmem_free(enum_data, enum_size);
1834	}
1835
1836	for (i = 0; i < PCI_MAX_DEVS; i++) {
1837		/* initialize slot mutex */
1838		mutex_init(&pcihp_p->slotinfo[i].slot_mutex, NULL,
1839		    MUTEX_DRIVER, NULL);
1840	}
1841
1842	/*
1843	 *  register the bus instance with the HPS framework.
1844	 */
1845	if (hpc_nexus_register_bus(dip, pcihp_new_slot_state, 0) != 0) {
1846		cmn_err(CE_WARN, "%s%d: failed to register the bus with HPS",
1847		    ddi_driver_name(dip), ddi_get_instance(dip));
1848		goto cleanup1;
1849	}
1850
1851	/*
1852	 * Create the "devctl" minor for hot plug support. The minor
1853	 * number for "devctl" node is in the same format as the AP
1854	 * minor nodes.
1855	 */
1856	if (ddi_create_minor_node(dip, "devctl", S_IFCHR,
1857	    PCIHP_AP_MINOR_NUM(ddi_get_instance(dip), PCIHP_DEVCTL_MINOR),
1858	    DDI_NT_NEXUS, 0) != DDI_SUCCESS)
1859		goto cleanup2;
1860
1861	/*
1862	 * Setup resource maps for this bus node. (Note: This can
1863	 * be done from the attach(9E) of the nexus itself.)
1864	 */
1865	(void) pci_resource_setup(dip);
1866
1867	pcihp_p->bus_state = PCIHP_BUS_CONFIGURED;
1868
1869	mutex_exit(&pcihp_open_mutex);
1870
1871	return (DDI_SUCCESS);
1872
1873cleanup2:
1874	(void) hpc_nexus_unregister_bus(dip);
1875cleanup1:
1876	for (i = 0; i < PCI_MAX_DEVS; i++)
1877		mutex_destroy(&pcihp_p->slotinfo[i].slot_mutex);
1878	pcihp_destroy_soft_state(dip);
1879cleanup:
1880	mutex_exit(&pcihp_open_mutex);
1881	return (DDI_FAILURE);
1882}
1883
1884/*
1885 * pcihp_uninit()
1886 *
1887 * The bus instance is going away, cleanup any data associated with
1888 * the management of hot plug slots. It is assumed that this function
1889 * is called from detach() routine of the PCI nexus driver. Also,
1890 * it is assumed that no devices on the bus are in the configured state.
1891 */
1892int
1893pcihp_uninit(dev_info_t *dip)
1894{
1895	pcihp_t *pcihp_p;
1896	int i, j;
1897	int rv;
1898
1899	mutex_enter(&pcihp_open_mutex);
1900	/* get a pointer to the soft state structure */
1901	pcihp_p = pcihp_get_soft_state(dip, PCIHP_DR_BUS_UNCONFIGURE, &rv);
1902	ASSERT(pcihp_p != NULL);
1903
1904	/* slot mutexes should prevent any configure/unconfigure access */
1905	for (i = 0; i < PCI_MAX_DEVS; i++) {
1906		if (!mutex_tryenter(&pcihp_p->slotinfo[i].slot_mutex)) {
1907			for (j = 0; j < i; j++) {
1908				mutex_exit(&pcihp_p->slotinfo[j].slot_mutex);
1909			}
1910			mutex_exit(&pcihp_open_mutex);
1911			return (DDI_FAILURE);
1912		}
1913	}
1914
1915	if ((pcihp_p->soft_state != PCIHP_SOFT_STATE_CLOSED) ||
1916	    (rv == PCIHP_FAILURE)) {
1917		cmn_err(CE_WARN, "%s%d: pcihp instance is busy",
1918		    ddi_driver_name(dip), ddi_get_instance(dip));
1919		for (i = 0; i < PCI_MAX_DEVS; i++) {
1920			mutex_exit(&pcihp_p->slotinfo[i].slot_mutex);
1921		}
1922		mutex_exit(&pcihp_open_mutex);
1923		return (DDI_FAILURE);
1924	}
1925
1926	/*
1927	 * Unregister the bus with the HPS.
1928	 *
1929	 * (Note: It is assumed that the HPS framework uninstalls
1930	 *  event handlers for all the hot plug slots on this bus.)
1931	 */
1932	(void) hpc_nexus_unregister_bus(dip);
1933
1934	/* Free up any kmem_alloc'd memory for slot info table. */
1935	for (i = 0; i < PCI_MAX_DEVS; i++) {
1936		/* free up slot name strings */
1937		if (pcihp_p->slotinfo[i].name != NULL)
1938			kmem_free(pcihp_p->slotinfo[i].name,
1939			    strlen(pcihp_p->slotinfo[i].name) + 1);
1940	}
1941
1942	/* destroy slot mutexes */
1943	for (i = 0; i < PCI_MAX_DEVS; i++)
1944		mutex_destroy(&pcihp_p->slotinfo[i].slot_mutex);
1945
1946	ddi_remove_minor_node(dip, NULL);
1947
1948	/* free up the soft state structure */
1949	pcihp_destroy_soft_state(dip);
1950
1951	/*
1952	 * Destroy resource maps for this bus node. (Note: This can
1953	 * be done from the detach(9E) of the nexus itself.)
1954	 */
1955	(void) pci_resource_destroy(dip);
1956
1957	mutex_exit(&pcihp_open_mutex);
1958
1959	return (DDI_SUCCESS);
1960}
1961
1962/*
1963 * pcihp_new_slot_state()
1964 *
1965 * This function is called by the HPS when it finds a hot plug
1966 * slot is added or being removed from the hot plug framework.
1967 * It returns 0 for success and HPC_ERR_FAILED for errors.
1968 */
1969static int
1970pcihp_new_slot_state(dev_info_t *dip, hpc_slot_t hdl,
1971	hpc_slot_info_t *slot_info, int slot_state)
1972{
1973	pcihp_t *pcihp_p;
1974	struct pcihp_slotinfo *slotinfop;
1975	int pci_dev;
1976	minor_t ap_minor;
1977	major_t ap_major;
1978	int rv = 0;
1979	time_t time;
1980	int auto_enable = 1;
1981	int rval;
1982
1983	/* get a pointer to the soft state structure */
1984	pcihp_p = pcihp_get_soft_state(dip, PCIHP_DR_SLOT_ENTER, &rval);
1985	ASSERT(pcihp_p != NULL);
1986
1987	if (rval == PCIHP_FAILURE) {
1988		PCIHP_DEBUG((CE_WARN, "pcihp instance is unconfigured"
1989		    " while slot activity is requested\n"));
1990		return (HPC_ERR_FAILED);
1991	}
1992
1993	pci_dev = slot_info->pci_dev_num;
1994	slotinfop = &pcihp_p->slotinfo[pci_dev];
1995
1996	mutex_enter(&slotinfop->slot_mutex);
1997
1998	switch (slot_state) {
1999
2000	case HPC_SLOT_ONLINE:
2001
2002		/*
2003		 * Make sure the slot is not already ONLINE (paranoia?).
2004		 * (Note: Should this be simply an ASSERTION?)
2005		 */
2006		if (slotinfop->slot_hdl != NULL) {
2007			PCIHP_DEBUG((CE_WARN,
2008			    "pcihp (%s%d): pci slot (dev %x) already ONLINE!!",
2009			    ddi_driver_name(dip), ddi_get_instance(dip),
2010			    pci_dev));
2011			rv = HPC_ERR_FAILED;
2012			break;
2013		}
2014
2015		/*
2016		 * Add the hot plug slot to the bus.
2017		 */
2018
2019		/* create the AP minor node */
2020		ap_minor = PCIHP_AP_MINOR_NUM(ddi_get_instance(dip), pci_dev);
2021		if (ddi_create_minor_node(dip, slot_info->pci_slot_name,
2022		    S_IFCHR, ap_minor,
2023		    DDI_NT_PCI_ATTACHMENT_POINT, 0) == DDI_FAILURE) {
2024			cmn_err(CE_WARN,
2025			    "pcihp (%s%d): ddi_create_minor_node failed"
2026			    " for pci dev %x", ddi_driver_name(dip),
2027			    ddi_get_instance(dip), pci_dev);
2028			rv = HPC_ERR_FAILED;
2029			break;
2030		}
2031
2032		/* save the slot handle */
2033		slotinfop->slot_hdl = hdl;
2034
2035		/* setup event handler for all hardware events on the slot */
2036		ap_major = ddi_driver_major(dip);
2037		if (hpc_install_event_handler(hdl, -1, pcihp_event_handler,
2038		    (caddr_t)makedevice(ap_major, ap_minor)) != 0) {
2039			cmn_err(CE_WARN,
2040			    "pcihp (%s%d): install event handler failed"
2041			    " for pci dev %x", ddi_driver_name(dip),
2042			    ddi_get_instance(dip), pci_dev);
2043			rv = HPC_ERR_FAILED;
2044			break;
2045		}
2046		slotinfop->event_mask = (uint32_t)0xFFFFFFFF;
2047
2048		pcihp_create_occupant_props(dip, makedevice(ap_major,
2049		    ap_minor), pci_dev);
2050
2051		/* set default auto configuration enabled flag for this slot */
2052		slotinfop->slot_flags = pcihp_autocfg_enabled;
2053
2054		/* copy the slot information */
2055		slotinfop->name =
2056		    kmem_alloc(strlen(slot_info->pci_slot_name) + 1, KM_SLEEP);
2057		(void) strcpy(slotinfop->name, slot_info->pci_slot_name);
2058		slotinfop->slot_type = slot_info->slot_type;
2059		slotinfop->hs_csr_location = 0;
2060		slotinfop->slot_capabilities = slot_info->pci_slot_capabilities;
2061		if (slot_info->slot_flags & HPC_SLOT_NO_AUTO_ENABLE)
2062			auto_enable = 0;
2063
2064		if (slot_info->slot_flags & HPC_SLOT_CREATE_DEVLINK) {
2065			pci_devlink_flags |= (1 << pci_dev);
2066			(void) ddi_prop_update_int(DDI_DEV_T_NONE,
2067			    dip, "ap-names", pci_devlink_flags);
2068		}
2069
2070		PCIHP_DEBUG((CE_NOTE,
2071		    "pcihp (%s%d): pci slot (dev %x) ONLINE\n",
2072		    ddi_driver_name(dip), ddi_get_instance(dip), pci_dev));
2073
2074		/*
2075		 * The slot may have an occupant that was configured
2076		 * at boot time. If we find a devinfo node in the tree
2077		 * for this slot (i.e pci device number) then we
2078		 * record the occupant state as CONFIGURED.
2079		 */
2080		if (pcihp_devi_find(dip, pci_dev, 0) != NULL) {
2081			/* we have a configured occupant */
2082			slotinfop->ostate = AP_OSTATE_CONFIGURED;
2083			slotinfop->rstate = AP_RSTATE_CONNECTED;
2084			slotinfop->condition = AP_COND_OK;
2085
2086			if (slotinfop->slot_type & HPC_SLOT_TYPE_CPCI) {
2087				/* this will set slot flags too. */
2088				(void) pcihp_get_board_type(slotinfop);
2089				pcihp_hs_csr_op(pcihp_p, pci_dev,
2090				    HPC_EVENT_SLOT_CONFIGURE);
2091				if (pcihp_cpci_blue_led)
2092					pcihp_hs_csr_op(pcihp_p, pci_dev,
2093					    HPC_EVENT_SLOT_BLUE_LED_OFF);
2094				/* ENUM# enabled by default for cPCI devices */
2095				slotinfop->slot_flags |= PCIHP_SLOT_AUTO_CFG_EN;
2096				slotinfop->slot_flags &=
2097				    ~PCIHP_SLOT_ENUM_INS_PENDING;
2098			}
2099
2100			/* tell HPC driver that the occupant is configured */
2101			(void) hpc_nexus_control(slotinfop->slot_hdl,
2102			    HPC_CTRL_DEV_CONFIGURED, NULL);
2103
2104			/*
2105			 * Tell sysevent listeners that slot has
2106			 * changed state.  At minimum, this is useful
2107			 * when a PCI-E Chassis (containing Occupants) is
2108			 * hotplugged.  In this case, the following will
2109			 * announce that the Occupant in the Receptacle
2110			 * in the Chassis had a state-change.
2111			 */
2112			pcihp_gen_sysevent(slotinfop->name,
2113			    PCIHP_DR_AP_STATE_CHANGE, SE_NO_HINT,
2114			    pcihp_p->dip, KM_SLEEP);
2115		} else {
2116			struct pcihp_config_ctrl ctrl;
2117			int circular_count;
2118
2119			slotinfop->ostate = AP_OSTATE_UNCONFIGURED;
2120			slotinfop->rstate = AP_RSTATE_EMPTY;
2121			slotinfop->condition = AP_COND_UNKNOWN;
2122
2123			if (!auto_enable) {	/* no further action */
2124				break;
2125			}
2126
2127			/*
2128			 * We enable power to the slot and try to
2129			 * configure if there is any card present.
2130			 *
2131			 * Note: This case is possible if the BIOS or
2132			 * firmware doesn't enable the slots during
2133			 * soft reboot.
2134			 */
2135			if (hpc_nexus_connect(slotinfop->slot_hdl,
2136			    NULL, 0) != HPC_SUCCESS)
2137				break;
2138
2139			if (slotinfop->slot_type & HPC_SLOT_TYPE_CPCI) {
2140				pcihp_hs_csr_op(pcihp_p, pci_dev,
2141				    HPC_EVENT_SLOT_CONFIGURE);
2142				if (pcihp_cpci_blue_led)
2143					pcihp_hs_csr_op(pcihp_p, pci_dev,
2144					    HPC_EVENT_SLOT_BLUE_LED_OFF);
2145				slotinfop->slot_flags |= PCIHP_SLOT_AUTO_CFG_EN;
2146				slotinfop->slot_flags &=
2147				    ~PCIHP_SLOT_ENUM_INS_PENDING;
2148			}
2149
2150			(void) hpc_nexus_control(slotinfop->slot_hdl,
2151			    HPC_CTRL_DEV_CONFIG_START, NULL);
2152
2153			/*
2154			 * Call the configurator to configure the card.
2155			 */
2156			if (pcicfg_configure(dip, pci_dev, PCICFG_ALL_FUNC, 0)
2157			    != PCICFG_SUCCESS) {
2158				if (slotinfop->slot_type & HPC_SLOT_TYPE_CPCI) {
2159					if (pcihp_cpci_blue_led)
2160						pcihp_hs_csr_op(pcihp_p,
2161						    pci_dev,
2162						    HPC_EVENT_SLOT_BLUE_LED_ON);
2163					pcihp_hs_csr_op(pcihp_p, pci_dev,
2164					    HPC_EVENT_SLOT_UNCONFIGURE);
2165				}
2166
2167				/* tell HPC driver occupant configure Error */
2168				(void) hpc_nexus_control(slotinfop->slot_hdl,
2169				    HPC_CTRL_DEV_CONFIG_FAILURE, NULL);
2170
2171				/*
2172				 * call HPC driver to turn off the power for
2173				 * the slot.
2174				 */
2175				(void) hpc_nexus_disconnect(slotinfop->slot_hdl,
2176				    NULL, 0);
2177			} else {
2178				/* record the occupant state as CONFIGURED */
2179				slotinfop->ostate = AP_OSTATE_CONFIGURED;
2180				slotinfop->rstate = AP_RSTATE_CONNECTED;
2181				slotinfop->condition = AP_COND_OK;
2182
2183				/* now, online all the devices in the AP */
2184				ctrl.flags = PCIHP_CFG_CONTINUE;
2185				ctrl.rv = NDI_SUCCESS;
2186				ctrl.dip = NULL;
2187				ctrl.pci_dev = pci_dev;
2188				ctrl.op = PCIHP_ONLINE;
2189				/*
2190				 * the following sets slot_flags and
2191				 * hs_csr_location too.
2192				 */
2193				(void) pcihp_get_board_type(slotinfop);
2194
2195				ndi_devi_enter(dip, &circular_count);
2196				ddi_walk_devs(ddi_get_child(dip),
2197				    pcihp_configure, (void *)&ctrl);
2198				ndi_devi_exit(dip, circular_count);
2199
2200				if (ctrl.rv != NDI_SUCCESS) {
2201					/*
2202					 * one or more of the devices are not
2203					 * ONLINE'd. How is this to be
2204					 * reported?
2205					 */
2206					cmn_err(CE_WARN,
2207					    "pcihp (%s%d): failed to attach"
2208					    " one or more drivers for the"
2209					    " card in the slot %s",
2210					    ddi_driver_name(dip),
2211					    ddi_get_instance(dip),
2212					    slotinfop->name);
2213				}
2214
2215				/* tell HPC driver the Occupant is Configured */
2216				(void) hpc_nexus_control(slotinfop->slot_hdl,
2217				    HPC_CTRL_DEV_CONFIGURED, NULL);
2218
2219				/*
2220				 * Tell sysevent listeners that slot has
2221				 * changed state.  At minimum, this is useful
2222				 * when a PCI-E Chassis (containing Occupants)
2223				 * is hotplugged.  In this case, the following
2224				 * will announce that the Occupant in the
2225				 * Receptacle in the Chassis had a state-change.
2226				 */
2227				pcihp_gen_sysevent(slotinfop->name,
2228				    PCIHP_DR_AP_STATE_CHANGE, SE_NO_HINT,
2229				    pcihp_p->dip, KM_SLEEP);
2230			}
2231		}
2232
2233		break;
2234
2235	case HPC_SLOT_OFFLINE:
2236		/*
2237		 * A hot plug slot is being removed from the bus.
2238		 * Make sure there is no occupant configured on the
2239		 * slot before removing the AP minor node.
2240		 */
2241		if (slotinfop->ostate != AP_OSTATE_UNCONFIGURED) {
2242			cmn_err(CE_WARN, "pcihp (%s%d): Card is still in "
2243			    "configured state for pci dev %x",
2244			    ddi_driver_name(dip), ddi_get_instance(dip),
2245			    pci_dev);
2246			rv = HPC_ERR_FAILED;
2247			break;
2248		}
2249
2250		/*
2251		 * If the AP device is in open state then return
2252		 * error.
2253		 */
2254		if (pcihp_p->soft_state != PCIHP_SOFT_STATE_CLOSED) {
2255			rv = HPC_ERR_FAILED;
2256			break;
2257		}
2258		if (slot_info->slot_flags & HPC_SLOT_CREATE_DEVLINK) {
2259			pci_devlink_flags &= ~(1 << pci_dev);
2260			(void) ddi_prop_update_int(DDI_DEV_T_NONE, dip,
2261			    "ap-names", pci_devlink_flags);
2262		}
2263
2264		/* remove the minor node */
2265		ddi_remove_minor_node(dip, slotinfop->name);
2266
2267		/* free up the memory for the name string */
2268		kmem_free(slotinfop->name, strlen(slotinfop->name) + 1);
2269
2270		/* update the slot info data */
2271		slotinfop->name = NULL;
2272		slotinfop->slot_hdl = NULL;
2273
2274		PCIHP_DEBUG((CE_NOTE,
2275		    "pcihp (%s%d): pci slot (dev %x) OFFLINE\n",
2276		    ddi_driver_name(dip), ddi_get_instance(dip),
2277		    slot_info->pci_dev_num));
2278
2279		break;
2280	default:
2281		cmn_err(CE_WARN,
2282		    "pcihp_new_slot_state: unknown slot_state %d", slot_state);
2283		rv = HPC_ERR_FAILED;
2284	}
2285
2286	if (rv == 0) {
2287		if (drv_getparm(TIME, (void *)&time) != DDI_SUCCESS)
2288			slotinfop->last_change = (time_t)-1;
2289		else
2290			slotinfop->last_change = (time32_t)time;
2291	}
2292
2293	mutex_exit(&slotinfop->slot_mutex);
2294
2295	(void) pcihp_get_soft_state(dip, PCIHP_DR_SLOT_EXIT, &rval);
2296
2297	return (rv);
2298}
2299
2300/*
2301 * Event handler. It is assumed that this function is called from
2302 * a kernel context only.
2303 *
2304 * Parameters:
2305 *	slot_arg	AP minor number.
2306 *	event_mask	Event that occurred.
2307 */
2308
2309static int
2310pcihp_event_handler(caddr_t slot_arg, uint_t event_mask)
2311{
2312	dev_t ap_dev = (dev_t)slot_arg;
2313	dev_info_t *self;
2314	pcihp_t *pcihp_p;
2315	int pci_dev;
2316	int rv = HPC_EVENT_CLAIMED;
2317	struct pcihp_slotinfo *slotinfop;
2318	struct pcihp_config_ctrl ctrl;
2319	int circular_count;
2320	int rval;
2321	int hint;
2322	hpc_slot_state_t rstate;
2323	struct hpc_led_info led_info;
2324
2325	/*
2326	 * Get the soft state structure.
2327	 */
2328	if (pcihp_info(NULL, DDI_INFO_DEVT2DEVINFO, (void *)ap_dev,
2329	    (void **)&self) != DDI_SUCCESS)
2330		return (ENXIO);
2331
2332	pcihp_p = pcihp_get_soft_state(self, PCIHP_DR_SLOT_ENTER, &rval);
2333	ASSERT(pcihp_p != NULL);
2334
2335	if (rval == PCIHP_FAILURE) {
2336		PCIHP_DEBUG((CE_WARN, "pcihp instance is unconfigured"
2337		    " while slot activity is requested\n"));
2338		return (-1);
2339	}
2340
2341	/* get the PCI device number for the slot */
2342	pci_dev = PCIHP_AP_MINOR_NUM_TO_PCI_DEVNUM(getminor(ap_dev));
2343
2344	slotinfop = &pcihp_p->slotinfo[pci_dev];
2345
2346	/*
2347	 * All the events that may be handled in interrupt context should be
2348	 * free of any mutex usage.
2349	 */
2350	switch (event_mask) {
2351
2352	case HPC_EVENT_CLEAR_ENUM:
2353		/*
2354		 * Check and clear ENUM# interrupt status. This may be
2355		 * called by the Hotswap controller driver when it is
2356		 * operating in a full hotswap system where the
2357		 * platform may not have control on globally disabling ENUM#.
2358		 * In such cases, the intent is to clear interrupt and
2359		 * process the interrupt in non-interrupt context.
2360		 * This is the first part of the ENUM# event processing.
2361		 */
2362		PCIHP_DEBUG((CE_NOTE, "pcihp (%s%d): ENUM# is generated"
2363		    " on the bus (for slot %s ?)",
2364		    ddi_driver_name(pcihp_p->dip),
2365		    ddi_get_instance(pcihp_p->dip), slotinfop->name));
2366
2367		/* this is the only event coming through in interrupt context */
2368		rv = pcihp_handle_enum(pcihp_p, pci_dev, PCIHP_CLEAR_ENUM,
2369		    KM_NOSLEEP);
2370
2371		(void) pcihp_get_soft_state(self, PCIHP_DR_SLOT_EXIT, &rval);
2372
2373		return (rv);
2374	default:
2375		break;
2376	}
2377
2378	mutex_enter(&slotinfop->slot_mutex);
2379
2380	if (hpc_nexus_control(slotinfop->slot_hdl,
2381	    HPC_CTRL_GET_SLOT_STATE, (caddr_t)&rstate) != 0)
2382		rv = HPC_ERR_FAILED;
2383
2384	slotinfop->rstate = (ap_rstate_t)rstate;
2385
2386	switch (event_mask) {
2387
2388	case HPC_EVENT_SLOT_INSERTION:
2389		/*
2390		 * A card is inserted in the slot. Just report this
2391		 * event and return.
2392		 */
2393		cmn_err(CE_NOTE, "pcihp (%s%d): card is inserted"
2394		    " in the slot %s (pci dev %x)",
2395		    ddi_driver_name(pcihp_p->dip),
2396		    ddi_get_instance(pcihp_p->dip),
2397		    slotinfop->name, pci_dev);
2398
2399		/* +++ HOOK for RCM to report this hotplug event? +++ */
2400
2401		break;
2402
2403	case HPC_EVENT_SLOT_CONFIGURE:
2404		/*
2405		 * Configure the occupant that is just inserted in the slot.
2406		 * The receptacle may or may not be in the connected state. If
2407		 * the receptacle is not connected and the auto configuration
2408		 * is enabled on this slot then connect the slot. If auto
2409		 * configuration is enabled then configure the card.
2410		 */
2411		if ((slotinfop->slot_flags & PCIHP_SLOT_AUTO_CFG_EN) == 0) {
2412			/*
2413			 * auto configuration is disabled. Tell someone
2414			 * like RCM about this hotplug event?
2415			 */
2416			cmn_err(CE_NOTE, "pcihp (%s%d): SLOT_CONFIGURE event"
2417			    " occurred for pci dev %x (slot %s),"
2418			    " Slot disabled for auto-configuration.",
2419			    ddi_driver_name(pcihp_p->dip),
2420			    ddi_get_instance(pcihp_p->dip), pci_dev,
2421			    slotinfop->name);
2422
2423			/* +++ HOOK for RCM to report this hotplug event? +++ */
2424
2425			break;
2426		}
2427
2428		if (slotinfop->ostate == AP_OSTATE_CONFIGURED) {
2429			cmn_err(CE_WARN, "pcihp (%s%d): SLOT_CONFIGURE event"
2430			    " re-occurred for pci dev %x (slot %s),",
2431			    ddi_driver_name(pcihp_p->dip),
2432			    ddi_get_instance(pcihp_p->dip), pci_dev,
2433			    slotinfop->name);
2434			mutex_exit(&slotinfop->slot_mutex);
2435
2436			(void) pcihp_get_soft_state(self, PCIHP_DR_SLOT_EXIT,
2437			    &rval);
2438
2439			return (EAGAIN);
2440		}
2441
2442		/*
2443		 * Auto configuration is enabled. First, make sure the
2444		 * receptacle is in the CONNECTED state.
2445		 */
2446		if ((rv = hpc_nexus_connect(slotinfop->slot_hdl,
2447		    NULL, 0)) == HPC_SUCCESS) {
2448			/* record rstate */
2449			slotinfop->rstate = AP_RSTATE_CONNECTED;
2450		}
2451
2452		/* Clear INS and Turn LED Off and start configuring. */
2453		if (slotinfop->slot_type & HPC_SLOT_TYPE_CPCI) {
2454			pcihp_hs_csr_op(pcihp_p, pci_dev,
2455			    HPC_EVENT_SLOT_CONFIGURE);
2456			if (pcihp_cpci_blue_led)
2457				pcihp_hs_csr_op(pcihp_p, pci_dev,
2458				    HPC_EVENT_SLOT_BLUE_LED_OFF);
2459		}
2460
2461		(void) hpc_nexus_control(slotinfop->slot_hdl,
2462		    HPC_CTRL_DEV_CONFIG_START, NULL);
2463
2464		/*
2465		 * Call the configurator to configure the card.
2466		 */
2467		if (pcicfg_configure(pcihp_p->dip, pci_dev, PCICFG_ALL_FUNC, 0)
2468		    != PCICFG_SUCCESS) {
2469			if (slotinfop->slot_type & HPC_SLOT_TYPE_CPCI) {
2470				if (pcihp_cpci_blue_led)
2471					pcihp_hs_csr_op(pcihp_p, pci_dev,
2472					    HPC_EVENT_SLOT_BLUE_LED_ON);
2473				pcihp_hs_csr_op(pcihp_p, pci_dev,
2474				    HPC_EVENT_SLOT_UNCONFIGURE);
2475			}
2476			/* failed to configure the card */
2477			cmn_err(CE_WARN, "pcihp (%s%d): failed to configure"
2478			    " the card in the slot %s",
2479			    ddi_driver_name(pcihp_p->dip),
2480			    ddi_get_instance(pcihp_p->dip),
2481			    slotinfop->name);
2482			/* failed to configure; disconnect the slot */
2483			if (hpc_nexus_disconnect(slotinfop->slot_hdl,
2484			    NULL, 0) == HPC_SUCCESS) {
2485				slotinfop->rstate = AP_RSTATE_DISCONNECTED;
2486			}
2487
2488			/* tell HPC driver occupant configure Error */
2489			(void) hpc_nexus_control(slotinfop->slot_hdl,
2490			    HPC_CTRL_DEV_CONFIG_FAILURE, NULL);
2491		} else {
2492			/* record the occupant state as CONFIGURED */
2493			slotinfop->ostate = AP_OSTATE_CONFIGURED;
2494			slotinfop->condition = AP_COND_OK;
2495
2496			/* now, online all the devices in the AP */
2497			ctrl.flags = PCIHP_CFG_CONTINUE;
2498			ctrl.rv = NDI_SUCCESS;
2499			ctrl.dip = NULL;
2500			ctrl.pci_dev = pci_dev;
2501			ctrl.op = PCIHP_ONLINE;
2502				(void) pcihp_get_board_type(slotinfop);
2503
2504			ndi_devi_enter(pcihp_p->dip, &circular_count);
2505			ddi_walk_devs(ddi_get_child(pcihp_p->dip),
2506			    pcihp_configure, (void *)&ctrl);
2507			ndi_devi_exit(pcihp_p->dip, circular_count);
2508
2509			if (ctrl.rv != NDI_SUCCESS) {
2510				/*
2511				 * one or more of the devices are not
2512				 * ONLINE'd. How is this to be
2513				 * reported?
2514				 */
2515				cmn_err(CE_WARN,
2516				    "pcihp (%s%d): failed to attach one or"
2517				    " more drivers for the card in"
2518				    " the slot %s",
2519				    ddi_driver_name(pcihp_p->dip),
2520				    ddi_get_instance(pcihp_p->dip),
2521				    slotinfop->name);
2522			}
2523
2524			/* tell HPC driver that the occupant is configured */
2525			(void) hpc_nexus_control(slotinfop->slot_hdl,
2526			    HPC_CTRL_DEV_CONFIGURED, NULL);
2527
2528			cmn_err(CE_NOTE, "pcihp (%s%d): card is CONFIGURED"
2529			    " in the slot %s (pci dev %x)",
2530			    ddi_driver_name(pcihp_p->dip),
2531			    ddi_get_instance(pcihp_p->dip),
2532			    slotinfop->name, pci_dev);
2533		}
2534
2535		break;
2536
2537	case HPC_EVENT_SLOT_UNCONFIGURE:
2538		/*
2539		 * Unconfigure the occupant in this slot.
2540		 */
2541		if ((slotinfop->slot_flags & PCIHP_SLOT_AUTO_CFG_EN) == 0) {
2542			/*
2543			 * auto configuration is disabled. Tell someone
2544			 * like RCM about this hotplug event?
2545			 */
2546			cmn_err(CE_NOTE, "pcihp (%s%d): SLOT_UNCONFIGURE event"
2547			    " for pci dev %x (slot %s) ignored,"
2548			    " Slot disabled for auto-configuration.",
2549			    ddi_driver_name(pcihp_p->dip),
2550			    ddi_get_instance(pcihp_p->dip), pci_dev,
2551			    slotinfop->name);
2552
2553			/* +++ HOOK for RCM to report this hotplug event? +++ */
2554
2555			break;
2556		}
2557
2558		if (slotinfop->ostate == AP_OSTATE_UNCONFIGURED) {
2559			cmn_err(CE_WARN, "pcihp (%s%d): SLOT_UNCONFIGURE "
2560			    "event re-occurred for pci dev %x (slot %s),",
2561			    ddi_driver_name(pcihp_p->dip),
2562			    ddi_get_instance(pcihp_p->dip), pci_dev,
2563			    slotinfop->name);
2564			mutex_exit(&slotinfop->slot_mutex);
2565
2566			(void) pcihp_get_soft_state(self, PCIHP_DR_SLOT_EXIT,
2567			    &rval);
2568
2569			return (EAGAIN);
2570		}
2571		/*
2572		 * If the occupant is in the CONFIGURED state then
2573		 * call the configurator to unconfigure the slot.
2574		 */
2575		if (slotinfop->ostate == AP_OSTATE_CONFIGURED) {
2576			/*
2577			 * Detach all the drivers for the devices in the
2578			 * slot. Call pcihp_configure() to offline the
2579			 * devices.
2580			 */
2581			ctrl.flags = 0;
2582			ctrl.rv = NDI_SUCCESS;
2583			ctrl.dip = NULL;
2584			ctrl.pci_dev = pci_dev;
2585			ctrl.op = PCIHP_OFFLINE;
2586
2587			(void) devfs_clean(pcihp_p->dip, NULL, DV_CLEAN_FORCE);
2588			ndi_devi_enter(pcihp_p->dip, &circular_count);
2589			ddi_walk_devs(ddi_get_child(pcihp_p->dip),
2590			    pcihp_configure, (void *)&ctrl);
2591			ndi_devi_exit(pcihp_p->dip, circular_count);
2592
2593			if (ctrl.rv != NDI_SUCCESS) {
2594				/*
2595				 * Failed to detach one or more drivers.
2596				 * Restore the status for the drivers
2597				 * which are offlined during this step.
2598				 */
2599				ctrl.flags = PCIHP_CFG_CONTINUE;
2600				ctrl.rv = NDI_SUCCESS;
2601				ctrl.dip = NULL;
2602				ctrl.pci_dev = pci_dev;
2603				ctrl.op = PCIHP_ONLINE;
2604
2605				ndi_devi_enter(pcihp_p->dip, &circular_count);
2606				ddi_walk_devs(ddi_get_child(pcihp_p->dip),
2607				    pcihp_configure, (void *)&ctrl);
2608				ndi_devi_exit(pcihp_p->dip, circular_count);
2609				rv = HPC_ERR_FAILED;
2610			} else {
2611				(void) hpc_nexus_control(slotinfop->slot_hdl,
2612				    HPC_CTRL_DEV_UNCONFIG_START, NULL);
2613
2614				if (pcicfg_unconfigure(pcihp_p->dip, pci_dev,
2615				    PCICFG_ALL_FUNC, 0) == PCICFG_SUCCESS) {
2616
2617				/* Resources freed. Turn LED on. Clear EXT. */
2618				if (slotinfop->slot_type & HPC_SLOT_TYPE_CPCI) {
2619					if (pcihp_cpci_blue_led)
2620						pcihp_hs_csr_op(pcihp_p,
2621						    pci_dev,
2622						    HPC_EVENT_SLOT_BLUE_LED_ON);
2623					pcihp_hs_csr_op(pcihp_p, pci_dev,
2624					    HPC_EVENT_SLOT_UNCONFIGURE);
2625					slotinfop->hs_csr_location = 0;
2626					slotinfop->slot_flags &=
2627					    ~PCIHP_SLOT_DEV_NON_HOTPLUG;
2628				}
2629					slotinfop->ostate =
2630					    AP_OSTATE_UNCONFIGURED;
2631					slotinfop->condition = AP_COND_UNKNOWN;
2632					/*
2633					 * send the notification of state change
2634					 * to the HPC driver.
2635					 */
2636					(void) hpc_nexus_control(
2637					    slotinfop->slot_hdl,
2638					    HPC_CTRL_DEV_UNCONFIGURED, NULL);
2639					/* disconnect the slot */
2640					if (hpc_nexus_disconnect(
2641					    slotinfop->slot_hdl,
2642					    NULL, 0) == HPC_SUCCESS) {
2643						slotinfop->rstate =
2644						    AP_RSTATE_DISCONNECTED;
2645					}
2646
2647					cmn_err(CE_NOTE,
2648					    "pcihp (%s%d): card is UNCONFIGURED"
2649					    " in the slot %s (pci dev %x)",
2650					    ddi_driver_name(pcihp_p->dip),
2651					    ddi_get_instance(pcihp_p->dip),
2652					    slotinfop->name, pci_dev);
2653				} else {
2654					/* tell HPC driver occupant is Busy */
2655					(void) hpc_nexus_control(
2656					    slotinfop->slot_hdl,
2657					    HPC_CTRL_DEV_UNCONFIG_FAILURE,
2658					    NULL);
2659
2660					rv = HPC_ERR_FAILED;
2661				}
2662			}
2663		}
2664
2665		/* +++ HOOK for RCM to report this hotplug event? +++ */
2666
2667		break;
2668
2669	case HPC_EVENT_SLOT_REMOVAL:
2670		/*
2671		 * Card is removed from the slot. The card must have been
2672		 * unconfigured before this event.
2673		 */
2674		if (slotinfop->ostate != AP_OSTATE_UNCONFIGURED) {
2675			slotinfop->condition = AP_COND_FAILED;
2676			cmn_err(CE_WARN, "pcihp (%s%d): card is removed"
2677			    " from the slot %s",
2678			    ddi_driver_name(pcihp_p->dip),
2679			    ddi_get_instance(pcihp_p->dip),
2680			    slotinfop->name);
2681		} else {
2682			slotinfop->condition = AP_COND_UNKNOWN;
2683			cmn_err(CE_NOTE, "pcihp (%s%d): card is removed"
2684			    " from the slot %s",
2685			    ddi_driver_name(pcihp_p->dip),
2686			    ddi_get_instance(pcihp_p->dip),
2687			    slotinfop->name);
2688		}
2689
2690		slotinfop->rstate = AP_RSTATE_EMPTY;
2691
2692		/* +++ HOOK for RCM to report this hotplug event? +++ */
2693
2694		break;
2695
2696	case HPC_EVENT_SLOT_POWER_ON:
2697		/*
2698		 * Slot is connected to the bus. i.e the card is powered
2699		 * on. Are there any error conditions to be checked?
2700		 */
2701		PCIHP_DEBUG((CE_NOTE, "pcihp (%s%d): card is powered"
2702		    " on in the slot %s",
2703		    ddi_driver_name(pcihp_p->dip),
2704		    ddi_get_instance(pcihp_p->dip),
2705		    slotinfop->name));
2706
2707		slotinfop->rstate = AP_RSTATE_CONNECTED; /* record rstate */
2708
2709		/* +++ HOOK for RCM to report this hotplug event? +++ */
2710
2711		break;
2712
2713	case HPC_EVENT_SLOT_POWER_OFF:
2714		/*
2715		 * Slot is disconnected from the bus. i.e the card is powered
2716		 * off. Are there any error conditions to be checked?
2717		 */
2718		PCIHP_DEBUG((CE_NOTE, "pcihp (%s%d): card is powered"
2719		    " off in the slot %s",
2720		    ddi_driver_name(pcihp_p->dip),
2721		    ddi_get_instance(pcihp_p->dip),
2722		    slotinfop->name));
2723
2724		slotinfop->rstate = AP_RSTATE_DISCONNECTED; /* record rstate */
2725
2726		/* +++ HOOK for RCM to report this hotplug event? +++ */
2727
2728		break;
2729
2730	case HPC_EVENT_SLOT_LATCH_SHUT:
2731		/*
2732		 * Latch on the slot is closed.
2733		 */
2734		cmn_err(CE_NOTE, "pcihp (%s%d): latch is shut for the slot %s",
2735		    ddi_driver_name(pcihp_p->dip),
2736		    ddi_get_instance(pcihp_p->dip),
2737		    slotinfop->name);
2738
2739		/* +++ HOOK for RCM to report this hotplug event? +++ */
2740
2741		break;
2742
2743	case HPC_EVENT_SLOT_LATCH_OPEN:
2744		/*
2745		 * Latch on the slot is open.
2746		 */
2747		cmn_err(CE_NOTE, "pcihp (%s%d): latch is open for the slot %s",
2748		    ddi_driver_name(pcihp_p->dip),
2749		    ddi_get_instance(pcihp_p->dip),
2750		    slotinfop->name);
2751
2752		/* +++ HOOK for RCM to report this hotplug event? +++ */
2753
2754		break;
2755
2756	case HPC_EVENT_PROCESS_ENUM:
2757		/*
2758		 * HSC knows the device number of the slot where the
2759		 * ENUM# was triggered.
2760		 * Now finish the necessary actions to be taken on that
2761		 * slot. Please note that the interrupt is already cleared.
2762		 * This is the second(last) part of the ENUM# event processing.
2763		 */
2764		PCIHP_DEBUG((CE_NOTE, "pcihp (%s%d): processing ENUM#"
2765		    " for slot %s",
2766		    ddi_driver_name(pcihp_p->dip),
2767		    ddi_get_instance(pcihp_p->dip),
2768		    slotinfop->name));
2769
2770		mutex_exit(&slotinfop->slot_mutex);
2771		rv = pcihp_enum_slot(pcihp_p, slotinfop, pci_dev,
2772		    PCIHP_HANDLE_ENUM, KM_SLEEP);
2773		mutex_enter(&slotinfop->slot_mutex);
2774
2775		/* +++ HOOK for RCM to report this hotplug event? +++ */
2776
2777		break;
2778
2779	case HPC_EVENT_BUS_ENUM:
2780		/*
2781		 * Same as HPC_EVENT_SLOT_ENUM as defined the PSARC doc.
2782		 * This term is used for better clarity of its usage.
2783		 *
2784		 * ENUM signal occurred on the bus. It may be from this
2785		 * slot or any other hotplug slot on the bus.
2786		 *
2787		 * It is NOT recommended that the hotswap controller uses
2788		 * event without queuing as NDI and other DDI calls may not
2789		 * necessarily be invokable in interrupt context.
2790		 * Hence the hotswap controller driver should use the
2791		 * CLEAR_ENUM event which returns the slot device number
2792		 * and then call HPC_EVENT_PROCESS_ENUM event with queuing.
2793		 *
2794		 * This can be used when the hotswap controller is
2795		 * implementing a polled event mechanism to do the
2796		 * necessary actions in a single call.
2797		 */
2798		PCIHP_DEBUG((CE_NOTE, "pcihp (%s%d): ENUM# is generated"
2799		    " on the bus (for slot %s ?)",
2800		    ddi_driver_name(pcihp_p->dip),
2801		    ddi_get_instance(pcihp_p->dip),
2802		    slotinfop->name));
2803
2804		mutex_exit(&slotinfop->slot_mutex);
2805		rv = pcihp_handle_enum(pcihp_p, pci_dev, PCIHP_HANDLE_ENUM,
2806		    KM_SLEEP);
2807		mutex_enter(&slotinfop->slot_mutex);
2808
2809		/* +++ HOOK for RCM to report this hotplug event? +++ */
2810
2811		break;
2812
2813	case HPC_EVENT_SLOT_BLUE_LED_ON:
2814
2815		/*
2816		 * Request to turn Hot Swap Blue LED on.
2817		 */
2818		PCIHP_DEBUG((CE_NOTE, "pcihp (%s%d): Request To Turn On Blue "
2819		    "LED on the bus (for slot %s ?)",
2820		    ddi_driver_name(pcihp_p->dip),
2821		    ddi_get_instance(pcihp_p->dip),
2822		    slotinfop->name));
2823
2824		pcihp_hs_csr_op(pcihp_p, pci_dev, HPC_EVENT_SLOT_BLUE_LED_ON);
2825		break;
2826
2827	case HPC_EVENT_DISABLE_ENUM:
2828		/*
2829		 * Disable ENUM# which disables auto configuration on this slot
2830		 */
2831		if (slotinfop->slot_type & HPC_SLOT_TYPE_CPCI) {
2832			pcihp_hs_csr_op(pcihp_p, pci_dev,
2833			    HPC_EVENT_DISABLE_ENUM);
2834			slotinfop->slot_flags &= ~PCIHP_SLOT_AUTO_CFG_EN;
2835		}
2836		break;
2837
2838	case HPC_EVENT_ENABLE_ENUM:
2839		/*
2840		 * Enable ENUM# which enables auto configuration on this slot.
2841		 */
2842		if (slotinfop->slot_type & HPC_SLOT_TYPE_CPCI) {
2843			pcihp_hs_csr_op(pcihp_p, pci_dev,
2844			    HPC_EVENT_ENABLE_ENUM);
2845			slotinfop->slot_flags |= PCIHP_SLOT_AUTO_CFG_EN;
2846		}
2847		break;
2848
2849	case HPC_EVENT_SLOT_BLUE_LED_OFF:
2850
2851		/*
2852		 * Request to turn Hot Swap Blue LED off.
2853		 */
2854		PCIHP_DEBUG((CE_NOTE, "pcihp (%s%d): Request To Turn Off Blue "
2855		    "LED on the bus (for slot %s ?)",
2856		    ddi_driver_name(pcihp_p->dip),
2857		    ddi_get_instance(pcihp_p->dip),
2858		    slotinfop->name));
2859
2860		pcihp_hs_csr_op(pcihp_p, pci_dev, HPC_EVENT_SLOT_BLUE_LED_OFF);
2861
2862		break;
2863
2864	case HPC_EVENT_SLOT_NOT_HEALTHY:
2865		/*
2866		 * HEALTHY# signal on this slot is not OK.
2867		 */
2868		PCIHP_DEBUG((CE_NOTE, "pcihp (%s%d): HEALTHY# signal is not OK"
2869		    " for this slot %s",
2870		    ddi_driver_name(pcihp_p->dip),
2871		    ddi_get_instance(pcihp_p->dip),
2872		    slotinfop->name));
2873
2874		/* record the state in slot_flags field */
2875		slotinfop->slot_flags |= PCIHP_SLOT_NOT_HEALTHY;
2876		slotinfop->condition = AP_COND_FAILED;
2877
2878		/* +++ HOOK for RCM to report this hotplug event? +++ */
2879
2880		break;
2881
2882	case HPC_EVENT_SLOT_HEALTHY_OK:
2883		/*
2884		 * HEALTHY# signal on this slot is OK now.
2885		 */
2886		PCIHP_DEBUG((CE_NOTE, "pcihp (%s%d): HEALTHY# signal is OK now"
2887		    " for this slot %s",
2888		    ddi_driver_name(pcihp_p->dip),
2889		    ddi_get_instance(pcihp_p->dip),
2890		    slotinfop->name));
2891
2892		/* update the state in slot_flags field */
2893		slotinfop->slot_flags &= ~PCIHP_SLOT_NOT_HEALTHY;
2894		slotinfop->condition = AP_COND_OK;
2895
2896		/* +++ HOOK for RCM to report this hotplug event? +++ */
2897
2898		break;
2899
2900	case HPC_EVENT_SLOT_ATTN:
2901		/*
2902		 * Attention button is pressed.
2903		 */
2904		if (((slotinfop->slot_flags & PCIHP_SLOT_AUTO_CFG_EN) == 0) ||
2905		    (slotinfop->slot_flags & PCIHP_SLOT_DISABLED)) {
2906			/*
2907			 * either auto-conifiguration or the slot is disabled,
2908			 * ignore this event.
2909			 */
2910			break;
2911		}
2912
2913		if (slotinfop->ostate == AP_OSTATE_UNCONFIGURED)
2914			hint = SE_INCOMING_RES;
2915		else
2916			hint = SE_OUTGOING_RES;
2917
2918		if (ddi_getprop(DDI_DEV_T_ANY, pcihp_p->dip, DDI_PROP_DONTPASS,
2919		    "inkernel-autoconfig", 0) == 0) {
2920			pcihp_gen_sysevent(slotinfop->name, PCIHP_DR_REQ, hint,
2921			    pcihp_p->dip, KM_SLEEP);
2922			break;
2923		}
2924
2925		if ((slotinfop->ostate == AP_OSTATE_UNCONFIGURED) &&
2926		    (slotinfop->rstate != AP_RSTATE_EMPTY) &&
2927		    (slotinfop->condition != AP_COND_FAILED)) {
2928			if (slotinfop->rstate == AP_RSTATE_DISCONNECTED) {
2929				rv = hpc_nexus_connect(slotinfop->slot_hdl,
2930				    NULL, 0);
2931				if (rv == HPC_SUCCESS)
2932					slotinfop->rstate = AP_RSTATE_CONNECTED;
2933				else
2934					break;
2935			}
2936
2937			rv = pcihp_configure_ap(pcihp_p, pci_dev);
2938
2939		} else if ((slotinfop->ostate == AP_OSTATE_CONFIGURED) &&
2940		    (slotinfop->rstate == AP_RSTATE_CONNECTED) &&
2941		    (slotinfop->condition != AP_COND_FAILED)) {
2942			rv = pcihp_unconfigure_ap(pcihp_p, pci_dev);
2943
2944			if (rv != HPC_SUCCESS)
2945				break;
2946
2947			rv = hpc_nexus_disconnect(slotinfop->slot_hdl,
2948			    NULL, 0);
2949			if (rv == HPC_SUCCESS)
2950				slotinfop->rstate = AP_RSTATE_DISCONNECTED;
2951		}
2952
2953		break;
2954
2955	case HPC_EVENT_SLOT_POWER_FAULT:
2956		/*
2957		 * Power fault is detected.
2958		 */
2959		cmn_err(CE_NOTE, "pcihp (%s%d): power-fault"
2960		    " for this slot %s",
2961		    ddi_driver_name(pcihp_p->dip),
2962		    ddi_get_instance(pcihp_p->dip),
2963		    slotinfop->name);
2964
2965		/* turn on ATTN led */
2966		led_info.led = HPC_ATTN_LED;
2967		led_info.state = HPC_LED_ON;
2968		rv = hpc_nexus_control(slotinfop->slot_hdl,
2969		    HPC_CTRL_SET_LED_STATE, (caddr_t)&led_info);
2970
2971		if (slotinfop->rstate == AP_RSTATE_CONNECTED)
2972			(void) hpc_nexus_disconnect(slotinfop->slot_hdl,
2973			    NULL, 0);
2974
2975		slotinfop->condition = AP_COND_FAILED;
2976
2977		pcihp_gen_sysevent(slotinfop->name, PCIHP_DR_AP_STATE_CHANGE,
2978		    SE_NO_HINT, pcihp_p->dip, KM_SLEEP);
2979
2980		break;
2981
2982	default:
2983		cmn_err(CE_NOTE, "pcihp (%s%d): unknown event %x"
2984		    " for this slot %s",
2985		    ddi_driver_name(pcihp_p->dip),
2986		    ddi_get_instance(pcihp_p->dip), event_mask,
2987		    slotinfop->name);
2988
2989		/* +++ HOOK for RCM to report this hotplug event? +++ */
2990
2991		break;
2992	}
2993
2994	mutex_exit(&slotinfop->slot_mutex);
2995
2996	(void) pcihp_get_soft_state(self, PCIHP_DR_SLOT_EXIT, &rval);
2997
2998	return (rv);
2999}
3000
3001/*
3002 * This function is called to online or offline the devices for an
3003 * attachment point. If the PCI device number of the node matches
3004 * with the device number of the specified hot plug slot then
3005 * the operation is performed.
3006 */
3007static int
3008pcihp_configure(dev_info_t *dip, void *hdl)
3009{
3010	int pci_dev;
3011	struct pcihp_config_ctrl *ctrl = (struct pcihp_config_ctrl *)hdl;
3012	int rv;
3013	pci_regspec_t *pci_rp;
3014	int length;
3015
3016	/*
3017	 * Get the PCI device number information from the devinfo
3018	 * node. Since the node may not have the address field
3019	 * setup (this is done in the DDI_INITCHILD of the parent)
3020	 * we look up the 'reg' property to decode that information.
3021	 */
3022	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
3023	    "reg", (int **)&pci_rp, (uint_t *)&length) != DDI_PROP_SUCCESS) {
3024		ctrl->rv = DDI_FAILURE;
3025		ctrl->dip = dip;
3026		return (DDI_WALK_TERMINATE);
3027	}
3028
3029	/* get the pci device id information */
3030	pci_dev = PCI_REG_DEV_G(pci_rp->pci_phys_hi);
3031
3032	/*
3033	 * free the memory allocated by ddi_prop_lookup_int_array
3034	 */
3035	ddi_prop_free(pci_rp);
3036
3037	/*
3038	 * Match the node for the device number of the slot.
3039	 */
3040	if (pci_dev == ctrl->pci_dev) {	/* node is a match */
3041		if (ctrl->op == PCIHP_ONLINE) {
3042			/* it is CONFIGURE operation */
3043
3044			/* skip this device if it is disabled or faulty */
3045			if (pcihp_check_status(dip) == B_FALSE) {
3046				return (DDI_WALK_PRUNECHILD);
3047			}
3048
3049			rv = ndi_devi_online(dip, NDI_ONLINE_ATTACH|NDI_CONFIG);
3050		} else {
3051			/*
3052			 * it is UNCONFIGURE operation.
3053			 */
3054			rv = ndi_devi_offline(dip, NDI_UNCONFIG);
3055		}
3056		if (rv != NDI_SUCCESS) {
3057			/* failed to attach/detach the driver(s) */
3058			ctrl->rv = rv;
3059			ctrl->dip = dip;
3060			/* terminate the search if specified */
3061			if (!(ctrl->flags & PCIHP_CFG_CONTINUE))
3062				return (DDI_WALK_TERMINATE);
3063		}
3064	}
3065
3066	/*
3067	 * continue the walk to the next sibling to look for a match
3068	 * or to find other nodes if this card is a multi-function card.
3069	 */
3070	return (DDI_WALK_PRUNECHILD);
3071}
3072
3073/*
3074 * Check the device for a 'status' property.  A conforming device
3075 * should have a status of "okay", "disabled", "fail", or "fail-xxx".
3076 *
3077 * Return FALSE for a conforming device that is disabled or faulted.
3078 * Return TRUE in every other case.
3079 */
3080static bool_t
3081pcihp_check_status(dev_info_t *dip)
3082{
3083	char *status_prop;
3084	bool_t rv = B_TRUE;
3085
3086	/* try to get the 'status' property */
3087	if (ddi_prop_lookup_string(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
3088	    "status", &status_prop) == DDI_PROP_SUCCESS) {
3089
3090		/*
3091		 * test if the status is "disabled", "fail", or
3092		 * "fail-xxx".
3093		 */
3094		if (strcmp(status_prop, "disabled") == 0) {
3095			rv = B_FALSE;
3096			PCIHP_DEBUG((CE_NOTE,
3097			    "pcihp (%s%d): device is in disabled state",
3098			    ddi_driver_name(dip), ddi_get_instance(dip)));
3099		} else if (strncmp(status_prop, "fail", 4) == 0) {
3100			rv = B_FALSE;
3101			cmn_err(CE_WARN,
3102			    "pcihp (%s%d): device is in fault state (%s)",
3103			    ddi_driver_name(dip), ddi_get_instance(dip),
3104			    status_prop);
3105		}
3106
3107		ddi_prop_free(status_prop);
3108	}
3109
3110	return (rv);
3111}
3112
3113/* control structure used to find a device in the devinfo tree */
3114struct pcihp_find_ctrl {
3115	uint_t		device;
3116	uint_t		function;
3117	dev_info_t	*dip;
3118};
3119
3120static dev_info_t *
3121pcihp_devi_find(dev_info_t *dip, uint_t device, uint_t function)
3122{
3123	struct pcihp_find_ctrl ctrl;
3124	int circular_count;
3125
3126	ctrl.device = device;
3127	ctrl.function = function;
3128	ctrl.dip = NULL;
3129
3130	ndi_devi_enter(dip, &circular_count);
3131	ddi_walk_devs(ddi_get_child(dip), pcihp_match_dev, (void *)&ctrl);
3132	ndi_devi_exit(dip, circular_count);
3133
3134	return (ctrl.dip);
3135}
3136
3137static int
3138pcihp_match_dev(dev_info_t *dip, void *hdl)
3139{
3140	struct pcihp_find_ctrl *ctrl = (struct pcihp_find_ctrl *)hdl;
3141	pci_regspec_t *pci_rp;
3142	int length;
3143	int pci_dev;
3144	int pci_func;
3145
3146	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
3147	    "reg", (int **)&pci_rp, (uint_t *)&length) != DDI_PROP_SUCCESS) {
3148		ctrl->dip = NULL;
3149		return (DDI_WALK_TERMINATE);
3150	}
3151
3152	/* get the PCI device address info */
3153	pci_dev = PCI_REG_DEV_G(pci_rp->pci_phys_hi);
3154	pci_func = PCI_REG_FUNC_G(pci_rp->pci_phys_hi);
3155
3156	/*
3157	 * free the memory allocated by ddi_prop_lookup_int_array
3158	 */
3159	ddi_prop_free(pci_rp);
3160
3161
3162	if ((pci_dev == ctrl->device) && (pci_func == ctrl->function)) {
3163		/* found the match for the specified device address */
3164		ctrl->dip = dip;
3165		return (DDI_WALK_TERMINATE);
3166	}
3167
3168	/*
3169	 * continue the walk to the next sibling to look for a match.
3170	 */
3171	return (DDI_WALK_PRUNECHILD);
3172}
3173
3174#if 0
3175/*
3176 * Probe the configuration space of the slot to determine the receptacle
3177 * state. There may not be any devinfo tree created for this slot.
3178 */
3179static void
3180pcihp_probe_slot_state(dev_info_t *dip, int dev, hpc_slot_state_t *rstatep)
3181{
3182	/* XXX FIX IT */
3183}
3184#endif
3185
3186/*
3187 * This routine is called when a ENUM# assertion is detected for a bus.
3188 * Since ENUM# may be bussed, the slot that asserted ENUM# may not be known.
3189 * The HPC Driver passes the handle of a slot that is its best guess.
3190 * If the best guess slot is the one that asserted ENUM#, the proper handling
3191 * will be done.  If its not, all possible slots will be locked at until
3192 * one that is asserting ENUM is found.
3193 * Also, indicate to the HSC to turn on ENUM# after it is serviced,
3194 * incase if it was disabled by the HSC due to the nature of asynchronous
3195 * delivery of interrupt by the framework.
3196 *
3197 * opcode has the following meanings.
3198 * PCIHP_CLEAR_ENUM = just clear interrupt and return the PCI device no. if
3199 *			success, else return -1.
3200 * PCIHP_HANDLE_ENUM = clear interrupt and handle interrupt also.
3201 *
3202 */
3203static int
3204pcihp_handle_enum(pcihp_t *pcihp_p, int favorite_pci_dev, int opcode,
3205	int kmflag)
3206{
3207	struct pcihp_slotinfo *slotinfop;
3208	int pci_dev, rc, event_serviced = 0;
3209
3210	/*
3211	 * Handle ENUM# condition for the "favorite" slot first.
3212	 */
3213	slotinfop = &pcihp_p->slotinfo[favorite_pci_dev];
3214	if (slotinfop) {
3215		/*
3216		 * First try the "favorite" pci device.  This is the device
3217		 * associated with the handle passed by the HPC Driver.
3218		 */
3219		rc = pcihp_enum_slot(pcihp_p, slotinfop, favorite_pci_dev,
3220		    opcode, kmflag);
3221		if (rc != HPC_EVENT_UNCLAIMED) {	/* indicates success */
3222			event_serviced = 1;
3223			/* This MUST be a non-DEBUG feature. */
3224			if (! pcihp_enum_scan_all) {
3225				return (rc);
3226			}
3227		}
3228	}
3229
3230	/*
3231	 * If ENUM# is implemented as a radial signal, then there is no
3232	 * need to further poll the slots.
3233	 */
3234	if (pcihp_p->bus_flags & PCIHP_BUS_ENUM_RADIAL)
3235		goto enum_service_check;
3236
3237	/*
3238	 * If the "favorite" pci device didn't assert ENUM#, then
3239	 * try the rest.  Once we find and handle a device that asserted
3240	 * ENUM#, then we will terminate the walk by returning unless
3241	 * scan-all flag is set.
3242	 */
3243	for (pci_dev = 0; pci_dev < PCI_MAX_DEVS; pci_dev++) {
3244		if (pci_dev != favorite_pci_dev) {
3245			slotinfop = &pcihp_p->slotinfo[pci_dev];
3246			if (slotinfop == NULL) {
3247				continue;
3248			}
3249			/* Only CPCI devices support ENUM# generation. */
3250			if (!(slotinfop->slot_type & HPC_SLOT_TYPE_CPCI))
3251				continue;
3252			rc = pcihp_enum_slot(pcihp_p, slotinfop, pci_dev,
3253			    opcode, kmflag);
3254			if (rc != HPC_EVENT_UNCLAIMED) {
3255				event_serviced = 1;
3256				/* This MUST be a non-DEBUG feature. */
3257				if (! pcihp_enum_scan_all)
3258					break;
3259			}
3260		}
3261	}
3262
3263enum_service_check:
3264	if (event_serviced) {
3265		return (rc);
3266	}
3267
3268	/* No ENUM# event found, Return */
3269	return (HPC_EVENT_UNCLAIMED);
3270}
3271
3272/*
3273 * This routine attempts to handle a possible ENUM# assertion case for a
3274 * specified slot.  This only works for adapters that implement Hot Swap
3275 * Friendly Silicon.  If the slot's HS_CSR is read and it specifies ENUM#
3276 * has been asserted, either the insertion or removal handlers will be
3277 * called.
3278 */
3279static int
3280pcihp_enum_slot(pcihp_t *pcihp_p, struct pcihp_slotinfo *slotinfop, int pci_dev,
3281		int opcode, int kmflag)
3282{
3283	ddi_acc_handle_t handle;
3284	dev_info_t *dip, *new_child = NULL;
3285	int result, rv = -1;
3286	uint8_t hs_csr;
3287
3288	if (pcihp_config_setup(&dip, &handle, &new_child, pci_dev,
3289	    pcihp_p) != DDI_SUCCESS) {
3290		return (HPC_EVENT_UNCLAIMED);
3291	}
3292
3293	/*
3294	 * Read the device's HS_CSR.
3295	 */
3296	result = pcihp_get_hs_csr(slotinfop, handle, (uint8_t *)&hs_csr);
3297	PCIHP_DEBUG((CE_NOTE, "pcihp (%s%d): hs_csr = %x, flags = %x",
3298	    ddi_driver_name(pcihp_p->dip), ddi_get_instance(pcihp_p->dip),
3299	    hs_csr, slotinfop->slot_flags));
3300	/*
3301	 * we teardown our device map here, because in case of an
3302	 * extraction event, our nodes would be freed and a teardown
3303	 * will cause problems.
3304	 */
3305	pcihp_config_teardown(&handle, &new_child, pci_dev, pcihp_p);
3306
3307	if (result == PCIHP_SUCCESS) {
3308
3309		/* If ENUM# is masked, then it is not us. Some other device */
3310		if ((hs_csr & HS_CSR_EIM) && (opcode == PCIHP_CLEAR_ENUM))
3311			return (HPC_EVENT_UNCLAIMED);
3312		/*
3313		 * This device supports Full Hot Swap and implements
3314		 * the Hot Swap Control and Status Register.
3315		 */
3316		if ((hs_csr & HS_CSR_INS) ||
3317		    (slotinfop->slot_flags & PCIHP_SLOT_ENUM_INS_PENDING)) {
3318			/* handle insertion ENUM */
3319			PCIHP_DEBUG((CE_NOTE, "pcihp (%s%d): "
3320			    "Handle Insertion ENUM (INS) "
3321			    "on the bus (for slot %s ?)",
3322			    ddi_driver_name(pcihp_p->dip),
3323			    ddi_get_instance(pcihp_p->dip),
3324			    slotinfop->name));
3325
3326			/*
3327			 * generate sysevent
3328			 */
3329
3330			if (opcode == PCIHP_CLEAR_ENUM)
3331				pcihp_gen_sysevent(slotinfop->name,
3332				    PCIHP_DR_REQ,
3333				    SE_INCOMING_RES, pcihp_p->dip,
3334				    kmflag);
3335
3336			rv = pcihp_handle_enum_insertion(pcihp_p, pci_dev,
3337			    opcode, kmflag);
3338
3339		} else if ((hs_csr & HS_CSR_EXT) ||
3340		    (slotinfop->slot_flags & PCIHP_SLOT_ENUM_EXT_PENDING)) {
3341			/* handle extraction ENUM */
3342			PCIHP_DEBUG((CE_NOTE, "pcihp (%s%d): "
3343			    "Handle Extraction ENUM (EXT) "
3344			    "on the bus (for slot %s ?)",
3345			    ddi_driver_name(pcihp_p->dip),
3346			    ddi_get_instance(pcihp_p->dip),
3347			    slotinfop->name));
3348
3349			/*
3350			 * generate sysevent
3351			 */
3352
3353			if (opcode == PCIHP_CLEAR_ENUM)
3354				pcihp_gen_sysevent(slotinfop->name,
3355				    PCIHP_DR_REQ,
3356				    SE_OUTGOING_RES,
3357				    pcihp_p->dip,
3358				    kmflag);
3359
3360			rv = pcihp_handle_enum_extraction(pcihp_p, pci_dev,
3361			    opcode, kmflag);
3362		}
3363		if (opcode == PCIHP_CLEAR_ENUM) {
3364			if (rv == PCIHP_SUCCESS)
3365				rv = pci_dev;
3366			else
3367				rv = HPC_EVENT_UNCLAIMED;
3368		}
3369	}
3370
3371	return (rv);
3372}
3373
3374/*
3375 * This routine is called when a ENUM# caused by lifting the lever
3376 * is detected.  If the occupant is configured, it will be unconfigured.
3377 * If the occupant is already unconfigured or is successfully unconfigured,
3378 * the blue LED on the adapter is illuminated which means its OK to remove.
3379 * Please note that the lock must be released before invoking the
3380 * generic AP unconfigure function.
3381 */
3382static int
3383pcihp_handle_enum_extraction(pcihp_t *pcihp_p, int pci_dev, int opcode,
3384	int kmflag)
3385{
3386	struct pcihp_slotinfo *slotinfop;
3387	int rv = PCIHP_FAILURE;
3388
3389	slotinfop = &pcihp_p->slotinfo[pci_dev];
3390
3391	/*
3392	 * It was observed that, clearing the EXT bit turned the LED ON.
3393	 * This is a BIG problem in case if the unconfigure operation
3394	 * failed because the board was busy.
3395	 * In order to avoid this confusing situation (LED ON but the board
3396	 * is not unconfigured), we instead decided not to clear EXT but
3397	 * disable further ENUM# from this slot. Disabling ENUM# clears
3398	 * the interrupt.
3399	 * Finally before returning we clear the interrupt and enable
3400	 * ENUM# back again from this slot.
3401	 */
3402	pcihp_hs_csr_op(pcihp_p, pci_dev, HPC_EVENT_DISABLE_ENUM);
3403	if (opcode == PCIHP_CLEAR_ENUM) {
3404		slotinfop->slot_flags |= PCIHP_SLOT_ENUM_EXT_PENDING;
3405		return (PCIHP_SUCCESS);
3406	}
3407
3408	mutex_enter(&slotinfop->slot_mutex);
3409	rv = pcihp_unconfigure_ap(pcihp_p, pci_dev);
3410	mutex_exit(&slotinfop->slot_mutex);
3411	if (rv != HPC_SUCCESS && rv != EBUSY) {
3412		cmn_err(CE_NOTE, "%s%d: PCI device %x Failed on Unconfigure",
3413		    ddi_driver_name(pcihp_p->dip),
3414		    ddi_get_instance(pcihp_p->dip), pci_dev);
3415	}
3416	if (rv == EBUSY)
3417		cmn_err(CE_NOTE, "%s%d: PCI device %x Busy",
3418		    ddi_driver_name(pcihp_p->dip),
3419		    ddi_get_instance(pcihp_p->dip), pci_dev);
3420	if (rv) {
3421		if (pcihp_cpci_blue_led)
3422			pcihp_hs_csr_op(pcihp_p, pci_dev,
3423			    HPC_EVENT_SLOT_BLUE_LED_OFF);
3424	}
3425	/*
3426	 * we must clear interrupt in case the unconfigure didn't do it
3427	 * due to a duplicate interrupt. Extraction is success.
3428	 */
3429	pcihp_hs_csr_op(pcihp_p, pci_dev, HPC_EVENT_SLOT_UNCONFIGURE);
3430
3431	if (!rv) {
3432		/*
3433		 * Sys Event Notification.
3434		 */
3435		pcihp_gen_sysevent(slotinfop->name, PCIHP_DR_AP_STATE_CHANGE,
3436		    SE_HINT_REMOVE, pcihp_p->dip, kmflag);
3437	}
3438
3439	/*
3440	 * Enable interrupts back from this board.
3441	 * This could potentially be problematic in case if the user is
3442	 * quick enough to extract the board.
3443	 * But we must do it just in case if the switch is closed again.
3444	 */
3445	pcihp_hs_csr_op(pcihp_p, pci_dev, HPC_EVENT_ENABLE_ENUM);
3446	slotinfop->slot_flags &= ~PCIHP_SLOT_ENUM_EXT_PENDING;
3447	return (rv);
3448}
3449
3450/*
3451 * This routine is called when a ENUM# caused by when an adapter insertion
3452 * is detected.  If the occupant is successfully configured (i.e. PCI resources
3453 * successfully assigned, the blue LED is left off, otherwise if configuration
3454 * is not successful, the blue LED is illuminated.
3455 * Please note that the lock must be released before invoking the
3456 * generic AP configure function.
3457 */
3458static int
3459pcihp_handle_enum_insertion(pcihp_t *pcihp_p, int pci_dev, int opcode,
3460	int kmflag)
3461{
3462	struct pcihp_slotinfo *slotinfop;
3463	int rv = PCIHP_FAILURE;
3464	minor_t ap_minor;
3465	major_t ap_major;
3466
3467	slotinfop = &pcihp_p->slotinfo[pci_dev];
3468	slotinfop->hs_csr_location = 0;
3469	/* we clear the interrupt here. This is a must here. */
3470	pcihp_hs_csr_op(pcihp_p, pci_dev, HPC_EVENT_SLOT_CONFIGURE);
3471	/*
3472	 * disable further interrupt from this board till it is
3473	 * configured.
3474	 */
3475	pcihp_hs_csr_op(pcihp_p, pci_dev, HPC_EVENT_DISABLE_ENUM);
3476	if (opcode == PCIHP_CLEAR_ENUM) {
3477		slotinfop->slot_flags |= PCIHP_SLOT_ENUM_INS_PENDING;
3478		return (PCIHP_SUCCESS);
3479	}
3480
3481	if ((slotinfop->slot_flags & PCIHP_SLOT_AUTO_CFG_EN) ==
3482	    PCIHP_SLOT_AUTO_CFG_EN) {
3483		mutex_enter(&slotinfop->slot_mutex);
3484		rv = pcihp_configure_ap(pcihp_p, pci_dev);
3485		mutex_exit(&slotinfop->slot_mutex);
3486		if (rv != HPC_SUCCESS) {	/* configure failed */
3487			cmn_err(CE_NOTE, "%s%d: PCI device %x Failed on"
3488			    " Configure", ddi_driver_name(pcihp_p->dip),
3489			    ddi_get_instance(pcihp_p->dip), pci_dev);
3490			if (pcihp_cpci_blue_led)
3491				pcihp_hs_csr_op(pcihp_p, pci_dev,
3492				    HPC_EVENT_SLOT_BLUE_LED_ON);
3493		}
3494
3495		/* pcihp_hs_csr_op(pcihp_p, pci_dev, HPC_EVENT_CLEAR_ENUM); */
3496		pcihp_hs_csr_op(pcihp_p, pci_dev, HPC_EVENT_ENABLE_ENUM);
3497
3498		if (!rv) {
3499			ap_major = ddi_driver_major(pcihp_p->dip);
3500			ap_minor = PCIHP_AP_MINOR_NUM(
3501			    ddi_get_instance(pcihp_p->dip), pci_dev);
3502			pcihp_create_occupant_props(pcihp_p->dip,
3503			    makedevice(ap_major, ap_minor), pci_dev);
3504
3505			/*
3506			 * Sys Event Notification.
3507			 */
3508			pcihp_gen_sysevent(slotinfop->name,
3509			    PCIHP_DR_AP_STATE_CHANGE,
3510			    SE_HINT_INSERT, pcihp_p->dip, kmflag);
3511		}
3512
3513	} else
3514		rv = PCIHP_SUCCESS;
3515	slotinfop->slot_flags &= ~PCIHP_SLOT_ENUM_INS_PENDING;
3516	return (rv);
3517}
3518
3519/*
3520 * Read the Hot Swap Control and Status Register (HS_CSR) and
3521 * place the result in the location pointed to be hs_csr.
3522 */
3523static int
3524pcihp_get_hs_csr(struct pcihp_slotinfo *slotinfop,
3525    ddi_acc_handle_t config_handle, uint8_t *hs_csr)
3526{
3527	if (slotinfop->hs_csr_location == -1)
3528		return (PCIHP_FAILURE);
3529
3530	if (slotinfop->hs_csr_location == 0) {
3531		slotinfop->hs_csr_location =
3532		    pcihp_get_hs_csr_location(config_handle);
3533
3534		if (slotinfop->hs_csr_location == -1)
3535			return (PCIHP_FAILURE);
3536	}
3537	*hs_csr = pci_config_get8(config_handle, slotinfop->hs_csr_location);
3538	return (PCIHP_SUCCESS);
3539}
3540
3541/*
3542 * Write the Hot Swap Control and Status Register (HS_CSR) with
3543 * the value being pointed at by hs_csr.
3544 */
3545static void
3546pcihp_set_hs_csr(struct pcihp_slotinfo *slotinfop,
3547    ddi_acc_handle_t config_handle, uint8_t *hs_csr)
3548{
3549	if (slotinfop->hs_csr_location == -1)
3550		return;
3551	if (slotinfop->hs_csr_location == 0) {
3552		slotinfop->hs_csr_location =
3553		    pcihp_get_hs_csr_location(config_handle);
3554		if (slotinfop->hs_csr_location == -1)
3555			return;
3556	}
3557	pci_config_put8(config_handle, slotinfop->hs_csr_location, *hs_csr);
3558	PCIHP_DEBUG((CE_NOTE, "hs_csr wrote %x, read %x", *hs_csr,
3559	    pci_config_get8(config_handle, slotinfop->hs_csr_location)));
3560}
3561
3562static int
3563pcihp_get_hs_csr_location(ddi_acc_handle_t config_handle)
3564{
3565	uint8_t	cap_id;
3566	uint_t	cap_id_loc;
3567	uint16_t	status;
3568	int location = -1;
3569#define	PCI_STAT_ECP_SUPP	0x10
3570
3571	/*
3572	 * Need to check the Status register for ECP support first.
3573	 * Also please note that for type 1 devices, the
3574	 * offset could change. Should support type 1 next.
3575	 */
3576	status = pci_config_get16(config_handle, PCI_CONF_STAT);
3577	if (!(status & PCI_STAT_ECP_SUPP)) {
3578		PCIHP_DEBUG((CE_NOTE, "No Ext Capabilities for device\n"));
3579		return (-1);
3580	}
3581	cap_id_loc = pci_config_get8(config_handle, PCI_CONF_EXTCAP);
3582
3583	/*
3584	 * Walk the list of capabilities, but don't walk past the end
3585	 * of the Configuration Space Header.
3586	 */
3587	while ((cap_id_loc) && (cap_id_loc < PCI_CONF_HDR_SIZE)) {
3588
3589		cap_id = pci_config_get8(config_handle, cap_id_loc);
3590
3591		if (cap_id == CPCI_HOTSWAP_CAPID) {
3592			location = cap_id_loc + PCI_ECP_HS_CSR;
3593			break;
3594		}
3595		cap_id_loc = pci_config_get8(config_handle,
3596		    cap_id_loc + 1);
3597	}
3598	return (location);
3599}
3600
3601static int
3602pcihp_add_dummy_reg_property(dev_info_t *dip,
3603    uint_t bus, uint_t device, uint_t func)
3604{
3605	pci_regspec_t dummy_reg;
3606
3607	bzero(&dummy_reg, sizeof (dummy_reg));
3608
3609	dummy_reg.pci_phys_hi = PCIHP_MAKE_REG_HIGH(bus, device, func, 0);
3610
3611	return (ndi_prop_update_int_array(DDI_DEV_T_NONE, dip,
3612	    "reg", (int *)&dummy_reg, sizeof (pci_regspec_t)/sizeof (int)));
3613}
3614
3615static void
3616pcihp_hs_csr_op(pcihp_t *pcihp_p, int pci_dev, int event)
3617{
3618	struct pcihp_slotinfo *slotinfop;
3619	ddi_acc_handle_t config_handle;
3620	dev_info_t *dip, *new_child = NULL;
3621	uint8_t hs_csr;
3622	int result;
3623
3624	slotinfop = &pcihp_p->slotinfo[pci_dev];
3625
3626	if (pcihp_config_setup(&dip, &config_handle, &new_child, pci_dev,
3627	    pcihp_p) != DDI_SUCCESS) {
3628		return;
3629	}
3630
3631	result = pcihp_get_hs_csr(slotinfop, config_handle, (uint8_t *)&hs_csr);
3632	if ((result != PCIHP_SUCCESS) || (event == -1)) {
3633		pcihp_config_teardown(&config_handle, &new_child, pci_dev,
3634		    pcihp_p);
3635		return;
3636	}
3637
3638	hs_csr &= 0xf;
3639	switch (event) {
3640		case HPC_EVENT_SLOT_BLUE_LED_ON:
3641			hs_csr |= HS_CSR_LOO;
3642			break;
3643		case HPC_EVENT_SLOT_BLUE_LED_OFF:
3644			hs_csr &= ~HS_CSR_LOO;
3645			break;
3646		case HPC_EVENT_SLOT_CONFIGURE:
3647			hs_csr |= HS_CSR_INS;	/* clear INS */
3648			break;
3649		case HPC_EVENT_CLEAR_ENUM:
3650			hs_csr |= (HS_CSR_INS | HS_CSR_EXT);
3651			break;
3652		case HPC_EVENT_SLOT_UNCONFIGURE:
3653			hs_csr |= HS_CSR_EXT;	/* clear EXT */
3654			break;
3655		case HPC_EVENT_ENABLE_ENUM:
3656			hs_csr &= ~HS_CSR_EIM;
3657			break;
3658		case HPC_EVENT_DISABLE_ENUM:
3659			hs_csr |= HS_CSR_EIM;
3660			break;
3661		case HPC_EVENT_SLOT_NOT_HEALTHY:
3662		case HPC_EVENT_SLOT_HEALTHY_OK:
3663		default:
3664			break;
3665	}
3666	pcihp_set_hs_csr(slotinfop, config_handle, (uint8_t *)&hs_csr);
3667	pcihp_config_teardown(&config_handle, &new_child, pci_dev, pcihp_p);
3668}
3669
3670static int
3671pcihp_config_setup(dev_info_t **dip, ddi_acc_handle_t *handle,
3672			dev_info_t **new_child, int pci_dev, pcihp_t *pcihp_p)
3673{
3674	dev_info_t *pdip = pcihp_p->dip;
3675	int bus, len, rc = DDI_SUCCESS;
3676	struct pcihp_slotinfo *slotinfop;
3677	hpc_slot_state_t rstate;
3678	ddi_acc_hdl_t *hp;
3679	pci_bus_range_t pci_bus_range;
3680
3681	slotinfop = &pcihp_p->slotinfo[pci_dev];
3682
3683	/*
3684	 * If declared failed, don't allow Config operations.
3685	 * Otherwise, if good or failing, it is assumed Ok
3686	 * to get config data.
3687	 */
3688	if (slotinfop->condition == AP_COND_FAILED) {
3689		return (PCIHP_FAILURE);
3690	}
3691	/*
3692	 * check to see if there is a hardware present first.
3693	 * If no hardware present, no need to probe this slot.
3694	 * We can do this first probably as a first step towards
3695	 * safeguarding from accidental removal (we don't support it!).
3696	 */
3697	if (hpc_nexus_control(slotinfop->slot_hdl, HPC_CTRL_GET_SLOT_STATE,
3698	    (caddr_t)&rstate) != 0) {
3699		return (DDI_FAILURE);
3700	}
3701
3702	if (rstate != HPC_SLOT_CONNECTED) {
3703		/* error. slot must be connected */
3704		return (DDI_FAILURE);
3705	}
3706	*new_child = NULL;
3707
3708	/*
3709	 * If there is no dip then we need to see if an
3710	 * adapter has just been hot plugged.
3711	 */
3712	len = sizeof (pci_bus_range_t);
3713	if (ddi_getlongprop_buf(DDI_DEV_T_ANY, pdip,
3714	    0, "bus-range",
3715	    (caddr_t)&pci_bus_range, &len) != DDI_SUCCESS) {
3716
3717		return (PCIHP_FAILURE);
3718	}
3719
3720	/* primary bus number of this bus node */
3721	bus = pci_bus_range.lo;
3722
3723	if (ndi_devi_alloc(pdip, DEVI_PSEUDO_NEXNAME,
3724	    (pnode_t)DEVI_SID_NODEID, dip) != NDI_SUCCESS) {
3725
3726		PCIHP_DEBUG((CE_NOTE, "Failed to alloc probe node\n"));
3727		return (PCIHP_FAILURE);
3728	}
3729
3730	if (pcihp_add_dummy_reg_property(*dip, bus,
3731	    pci_dev, 0) != DDI_SUCCESS) {
3732
3733		(void) ndi_devi_free(*dip);
3734		return (PCIHP_FAILURE);
3735	}
3736
3737	/*
3738	 * Probe for a device. Possibly a non (c)PCI board could be sitting
3739	 * here which would never respond to PCI config cycles - in which
3740	 * case we return. Eventually a configure operation would fail.
3741	 */
3742	if (pci_config_setup(*dip, handle) != DDI_SUCCESS) {
3743		cmn_err(CE_WARN, "Cannot set config space map for"
3744		    " pci device number %d", pci_dev);
3745		(void) ndi_devi_free(*dip);
3746		return (PCIHP_FAILURE);
3747	}
3748
3749	/*
3750	 * See if there is any PCI HW at this location
3751	 * by reading the Vendor ID.  If it returns with 0xffff
3752	 * then there is no hardware at this location.
3753	 */
3754	if (pcihp_indirect_map(*dip) == DDI_SUCCESS) {
3755		if (pci_config_get16(*handle, 0) == 0xffff) {
3756			pci_config_teardown(handle);
3757			(void) ndi_devi_free(*dip);
3758			return (PCIHP_FAILURE);
3759		}
3760	} else {
3761		/* Check if mapping is OK */
3762		hp = impl_acc_hdl_get(*handle);
3763
3764		if (ddi_peek16(*dip, (int16_t *)(hp->ah_addr),
3765		    (int16_t *)0) != DDI_SUCCESS) {
3766#ifdef DEBUG
3767			cmn_err(CE_WARN, "Cannot Map PCI config space for "
3768			    "device number %d", pci_dev);
3769#endif
3770			pci_config_teardown(handle);
3771			(void) ndi_devi_free(*dip);
3772			return (PCIHP_FAILURE);
3773		}
3774	}
3775
3776	*new_child = *dip;
3777	return (rc);
3778
3779}
3780
3781static void
3782pcihp_config_teardown(ddi_acc_handle_t *handle,
3783			dev_info_t **new_child, int pci_dev, pcihp_t *pcihp_p)
3784{
3785	struct pcihp_slotinfo *slotinfop = &pcihp_p->slotinfo[pci_dev];
3786
3787	pci_config_teardown(handle);
3788	if (*new_child) {
3789		(void) ndi_devi_free(*new_child);
3790		/*
3791		 * If occupant not configured, reset HS_CSR location
3792		 * so that we reprobe. This covers cases where
3793		 * the receptacle had a status change without a
3794		 * notification to the framework.
3795		 */
3796		if (slotinfop->ostate != AP_OSTATE_CONFIGURED)
3797			slotinfop->hs_csr_location = 0;
3798	}
3799}
3800
3801static int
3802pcihp_get_board_type(struct pcihp_slotinfo *slotinfop)
3803{
3804	hpc_board_type_t board_type;
3805
3806	/*
3807	 * Get board type data structure, hpc_board_type_t.
3808	 */
3809	if (hpc_nexus_control(slotinfop->slot_hdl, HPC_CTRL_GET_BOARD_TYPE,
3810	    (caddr_t)&board_type) != 0) {
3811
3812		cmn_err(CE_WARN, "Cannot Get Board Type..");
3813		return (-1);
3814	}
3815
3816	/*
3817	 * We expect the Hotswap Controller to tell us if the board is
3818	 * a hotswap board or not, as it probably cannot differentiate
3819	 * between a basic hotswap board, a non hotswap board and a
3820	 * hotswap nonfriendly board.
3821	 * So here is the logic to differentiate between the various
3822	 * types of cPCI boards.
3823	 * In case if the HSC returns board type as unknown, we assign
3824	 * the default board type as defined by a configurable variable
3825	 * for a BHS, nonfriendly FHS and non HS board.
3826	 */
3827	if (slotinfop->slot_type & HPC_SLOT_TYPE_CPCI) {
3828		if (slotinfop->hs_csr_location > 0)
3829			board_type = HPC_BOARD_CPCI_FULL_HS;
3830		else {
3831			if (board_type == HPC_BOARD_CPCI_HS) {
3832				if (slotinfop->hs_csr_location == -1)
3833					board_type = HPC_BOARD_CPCI_BASIC_HS;
3834			}
3835			if (board_type == HPC_BOARD_UNKNOWN) {
3836				if (slotinfop->hs_csr_location == -1) {
3837					board_type = pcihp_cpci_board_type;
3838				} else if (slotinfop->hs_csr_location != 0) {
3839					board_type = HPC_BOARD_CPCI_FULL_HS;
3840				}
3841			}
3842		}
3843		/*
3844		 * If board type is a non hotswap board, then we must
3845		 * deny a unconfigure operation. So set this flag.
3846		 * Strictly speaking, there is no reason not to disallow
3847		 * a unconfigure operation on nonhotswap boards. But this
3848		 * is the only way we can prevent a user from accidentally
3849		 * removing the board and damaging it.
3850		 */
3851		if (board_type == HPC_BOARD_CPCI_NON_HS)
3852			slotinfop->slot_flags |= PCIHP_SLOT_DEV_NON_HOTPLUG;
3853		else
3854			slotinfop->slot_flags &= ~PCIHP_SLOT_DEV_NON_HOTPLUG;
3855	}
3856	return (board_type);
3857}
3858
3859
3860/*
3861 * Generate the System Event with a possible hint.
3862 */
3863static void
3864pcihp_gen_sysevent(char *slot_name, int event_sub_class, int hint,
3865				dev_info_t *self, int kmflag)
3866{
3867
3868	int err;
3869	char *ev_subclass = NULL;
3870	sysevent_id_t eid;
3871	nvlist_t *ev_attr_list = NULL;
3872	char attach_pnt[MAXPATHLEN];
3873
3874	/*
3875	 * Minor device name (AP) will be bus path
3876	 * concatenated with slot name
3877	 */
3878
3879	(void) strcpy(attach_pnt, PCIHP_DEVICES_STR);
3880	(void) ddi_pathname(self, attach_pnt + strlen(PCIHP_DEVICES_STR));
3881	(void) strcat(attach_pnt, ":");
3882	(void) strcat(attach_pnt, slot_name);
3883	err = nvlist_alloc(&ev_attr_list, NV_UNIQUE_NAME_TYPE, kmflag);
3884	if (err != 0) {
3885		cmn_err(CE_WARN,
3886		    "%s%d: Failed to allocate memory "
3887		    "for event attributes%s", ddi_driver_name(self),
3888		    ddi_get_instance(self), ESC_DR_AP_STATE_CHANGE);
3889		return;
3890	}
3891
3892	switch (event_sub_class) {
3893
3894	/* event sub class: ESC_DR_AP_STATE_CHANGE */
3895	case PCIHP_DR_AP_STATE_CHANGE:
3896
3897		ev_subclass = ESC_DR_AP_STATE_CHANGE;
3898
3899		switch (hint) {
3900
3901		case SE_NO_HINT:	/* fall through */
3902		case SE_HINT_INSERT:	/* fall through */
3903		case SE_HINT_REMOVE:
3904
3905
3906			err = nvlist_add_string(ev_attr_list, DR_HINT,
3907			    SE_HINT2STR(hint));
3908
3909			if (err != 0) {
3910				cmn_err(CE_WARN, "%s%d: Failed to add attr [%s]"
3911				    " for %s event", ddi_driver_name(self),
3912				    ddi_get_instance(self),
3913				    DR_HINT, ESC_DR_AP_STATE_CHANGE);
3914				nvlist_free(ev_attr_list);
3915				return;
3916			}
3917			break;
3918
3919		default:
3920			cmn_err(CE_WARN, "%s%d: Unknown hint on sysevent",
3921			    ddi_driver_name(self), ddi_get_instance(self));
3922			nvlist_free(ev_attr_list);
3923			return;
3924		}
3925
3926		break;
3927
3928	/* event sub class: ESC_DR_REQ */
3929	case PCIHP_DR_REQ:
3930
3931		ev_subclass = ESC_DR_REQ;
3932
3933		switch (hint) {
3934
3935		case SE_INVESTIGATE_RES:	/* fall through */
3936		case SE_INCOMING_RES:	/* fall through */
3937		case SE_OUTGOING_RES:	/* fall through */
3938
3939			err = nvlist_add_string(ev_attr_list, DR_REQ_TYPE,
3940			    SE_REQ2STR(hint));
3941
3942			if (err != 0) {
3943				cmn_err(CE_WARN,
3944				    "%s%d: Failed to add attr [%s] "
3945				    "for %s event", ddi_driver_name(self),
3946				    ddi_get_instance(self),
3947				    DR_REQ_TYPE, ESC_DR_REQ);
3948				nvlist_free(ev_attr_list);
3949				return;
3950			}
3951			break;
3952
3953		default:
3954			cmn_err(CE_WARN, "%s%d:  Unknown hint on sysevent",
3955			    ddi_driver_name(self), ddi_get_instance(self));
3956			nvlist_free(ev_attr_list);
3957			return;
3958		}
3959
3960		break;
3961
3962	default:
3963		cmn_err(CE_WARN, "%s%d:  Unknown Event subclass",
3964		    ddi_driver_name(self), ddi_get_instance(self));
3965		nvlist_free(ev_attr_list);
3966		return;
3967	}
3968
3969	/*
3970	 * Add attachment point as attribute (common attribute)
3971	 */
3972
3973	err = nvlist_add_string(ev_attr_list, DR_AP_ID, attach_pnt);
3974
3975	if (err != 0) {
3976		cmn_err(CE_WARN, "%s%d: Failed to add attr [%s] for %s event",
3977		    ddi_driver_name(self), ddi_get_instance(self),
3978		    DR_AP_ID, EC_DR);
3979		nvlist_free(ev_attr_list);
3980		return;
3981	}
3982
3983
3984	/*
3985	 * Log this event with sysevent framework.
3986	 */
3987
3988	err = ddi_log_sysevent(self, DDI_VENDOR_SUNW, EC_DR,
3989	    ev_subclass, ev_attr_list, &eid,
3990	    ((kmflag == KM_SLEEP) ? DDI_SLEEP : DDI_NOSLEEP));
3991	if (err != 0) {
3992		cmn_err(CE_WARN, "%s%d: Failed to log %s event",
3993		    ddi_driver_name(self), ddi_get_instance(self), EC_DR);
3994	}
3995
3996	nvlist_free(ev_attr_list);
3997}
3998
3999int
4000pcihp_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op,
4001    int flags, char *name, caddr_t valuep, int *lengthp)
4002{
4003	int pci_dev;
4004
4005	if (dev == DDI_DEV_T_ANY)
4006		goto skip;
4007
4008	if (strcmp(name, "pci-occupant") == 0) {
4009		pci_dev = PCIHP_AP_MINOR_NUM_TO_PCI_DEVNUM(getminor(dev));
4010		pcihp_create_occupant_props(dip, dev, pci_dev);
4011	}
4012	/* other cases... */
4013skip:
4014	return (ddi_prop_op(dev, dip, prop_op, flags, name, valuep, lengthp));
4015}
4016
4017/*
4018 * this function is called only for SPARC platforms, where we may have
4019 * a mix n' match of direct vs indirectly mapped configuration space.
4020 * On x86, this function should always return success since the configuration
4021 * space is always indirect mapped.
4022 */
4023/*ARGSUSED*/
4024static int
4025pcihp_indirect_map(dev_info_t *dip)
4026{
4027#if defined(__sparc)
4028	int rc = DDI_FAILURE;
4029
4030	if (ddi_prop_get_int(DDI_DEV_T_ANY, ddi_get_parent(dip), 0,
4031	    PCI_DEV_CONF_MAP_PROP, DDI_FAILURE) != DDI_FAILURE)
4032		rc = DDI_SUCCESS;
4033	else
4034		if (ddi_prop_get_int(DDI_DEV_T_ANY, ddi_get_parent(dip),
4035		    0, PCI_BUS_CONF_MAP_PROP, DDI_FAILURE) != DDI_FAILURE)
4036			rc = DDI_SUCCESS;
4037	return (rc);
4038#else
4039	return (DDI_SUCCESS);
4040#endif
4041}
4042