xref: /titanic_41/usr/src/uts/sun4u/io/pci/simba.c (revision d58fda4376e4bf67072ce2e69f6f47036f9dbb68)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 /*
30  *	PCI to PCI bus bridge nexus driver
31  */
32 
33 #include <sys/conf.h>
34 #include <sys/kmem.h>
35 #include <sys/debug.h>
36 #include <sys/modctl.h>
37 #include <sys/autoconf.h>
38 #include <sys/ddi_impldefs.h>
39 #include <sys/ddi_subrdefs.h>
40 #include <sys/ddifm.h>
41 #include <sys/fm/util.h>
42 #include <sys/fm/protocol.h>
43 #include <sys/fm/io/pci.h>
44 #include <sys/pci.h>
45 #include <sys/pci/pci_nexus.h>
46 #include <sys/pci/pci_regs.h>
47 #include <sys/pci/pci_simba.h>
48 #include <sys/ddi.h>
49 #include <sys/sunddi.h>
50 #include <sys/sunndi.h>
51 #include <sys/promif.h>		/* prom_printf */
52 #include <sys/open.h>
53 #include <sys/stat.h>
54 #include <sys/file.h>
55 
56 #if defined(DEBUG) && !defined(lint)
57 static uint_t simba_debug_flags = 0;
58 #define	D_IDENTIFY	0x00000001
59 #define	D_ATTACH	0x00000002
60 #define	D_DETACH	0x00000004
61 #define	D_MAP		0x00000008
62 #define	D_CTLOPS	0x00000010
63 #define	D_G_ISPEC	0x00000020
64 #define	D_A_ISPEC	0x00000040
65 #define	D_INIT_CLD	0x00400000
66 #define	D_FAULT		0x00000080
67 
68 #define	DEBUG0(f, s) if ((f)& simba_debug_flags) \
69 	prom_printf("simba: " s "\n")
70 
71 #define	DEBUG1(f, s, a) if ((f)& simba_debug_flags) \
72 	prom_printf("simba: " s "\n", a)
73 
74 #define	DEBUG2(f, s, a, b) if ((f)& simba_debug_flags) \
75 	prom_printf("simba: " s "\n", a, b)
76 
77 #define	DEBUG3(f, s, a, b, c) if ((f)& simba_debug_flags) \
78 	prom_printf("simba: " s "\n", a, b, c)
79 
80 #define	DEBUG4(f, s, a, b, c, d) if ((f)& simba_debug_flags) \
81 	prom_printf("simba: " s "\n", a, b, c, d)
82 
83 #define	DEBUG5(f, s, a, b, c, d, e) if ((f)& simba_debug_flags) \
84 	prom_printf("simba: " s "\n", a, b, c, d, e)
85 
86 #define	DEBUG6(f, s, a, b, c, d, e, ff) if ((f)& simba_debug_flags) \
87 	prom_printf("simba: " s "\n", a, b, c, d, e, ff)
88 
89 #else
90 
91 #define	DEBUG0(f, s)
92 #define	DEBUG1(f, s, a)
93 #define	DEBUG2(f, s, a, b)
94 #define	DEBUG3(f, s, a, b, c)
95 #define	DEBUG4(f, s, a, b, c, d)
96 #define	DEBUG5(f, s, a, b, c, d, e)
97 #define	DEBUG6(f, s, a, b, c, d, e, ff)
98 
99 #endif
100 
101 /*
102  * The variable controls the default setting of the command register
103  * for pci devices.  See simba_initchild() for details.
104  */
105 static ushort_t simba_command_default = PCI_COMM_SERR_ENABLE |
106 					PCI_COMM_WAIT_CYC_ENAB |
107 					PCI_COMM_PARITY_DETECT |
108 					PCI_COMM_ME |
109 					PCI_COMM_MAE |
110 					PCI_COMM_IO;
111 
112 static int simba_bus_map(dev_info_t *, dev_info_t *, ddi_map_req_t *,
113 	off_t, off_t, caddr_t *);
114 static int simba_ctlops(dev_info_t *, dev_info_t *, ddi_ctl_enum_t,
115 	void *, void *);
116 static int simba_fm_init_child(dev_info_t *dip, dev_info_t *tdip, int cap,
117 		ddi_iblock_cookie_t *ibc);
118 static void simba_bus_enter(dev_info_t *dip, ddi_acc_handle_t handle);
119 static void simba_bus_exit(dev_info_t *dip, ddi_acc_handle_t handle);
120 
121 struct bus_ops simba_bus_ops = {
122 	BUSO_REV,
123 	simba_bus_map,
124 	0,
125 	0,
126 	0,
127 	i_ddi_map_fault,
128 	ddi_dma_map,
129 	ddi_dma_allochdl,
130 	ddi_dma_freehdl,
131 	ddi_dma_bindhdl,
132 	ddi_dma_unbindhdl,
133 	ddi_dma_flush,
134 	ddi_dma_win,
135 	ddi_dma_mctl,
136 	simba_ctlops,
137 	ddi_bus_prop_op,
138 	ndi_busop_get_eventcookie,
139 	ndi_busop_add_eventcall,
140 	ndi_busop_remove_eventcall,
141 	ndi_post_event,
142 	0,
143 	0,
144 	0,
145 	simba_fm_init_child,
146 	NULL,
147 	simba_bus_enter,
148 	simba_bus_exit,
149 	0,
150 	i_ddi_intr_ops
151 };
152 
153 static int simba_open(dev_t *devp, int flags, int otyp, cred_t *credp);
154 static int simba_close(dev_t dev, int flags, int otyp, cred_t *credp);
155 static int simba_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
156     cred_t *credp, int *rvalp);
157 
158 static struct cb_ops simba_cb_ops = {
159 	simba_open,			/* open */
160 	simba_close,			/* close */
161 	nulldev,			/* strategy */
162 	nulldev,			/* print */
163 	nulldev,			/* dump */
164 	nulldev,			/* read */
165 	nulldev,			/* write */
166 	simba_ioctl,			/* ioctl */
167 	nodev,				/* devmap */
168 	nodev,				/* mmap */
169 	nodev,				/* segmap */
170 	nochpoll,			/* poll */
171 	ddi_prop_op,			/* cb_prop_op */
172 	NULL,				/* streamtab */
173 	D_NEW | D_MP | D_HOTPLUG,	/* Driver compatibility flag */
174 	CB_REV,				/* rev */
175 	nodev,				/* int (*cb_aread)() */
176 	nodev				/* int (*cb_awrite)() */
177 };
178 
179 static int simba_probe(dev_info_t *);
180 static int simba_attach(dev_info_t *devi, ddi_attach_cmd_t cmd);
181 static int simba_detach(dev_info_t *devi, ddi_detach_cmd_t cmd);
182 static int simba_info(dev_info_t *dip, ddi_info_cmd_t infocmd,
183 	void *arg, void **result);
184 
185 struct dev_ops simba_ops = {
186 	DEVO_REV,		/* devo_rev */
187 	0,			/* refcnt  */
188 	simba_info,		/* info */
189 	nulldev,		/* identify */
190 	simba_probe,		/* probe */
191 	simba_attach,		/* attach */
192 	simba_detach,		/* detach */
193 	nulldev,		/* reset */
194 	&simba_cb_ops,		/* driver operations */
195 	&simba_bus_ops		/* bus operations */
196 
197 };
198 
199 /*
200  * Module linkage information for the kernel.
201  */
202 
203 static struct modldrv modldrv = {
204 	&mod_driverops, /* Type of module */
205 	"SIMBA PCI to PCI bridge nexus driver %I%",
206 	&simba_ops,	/* driver ops */
207 };
208 
209 static struct modlinkage modlinkage = {
210 	MODREV_1,
211 	(void *)&modldrv,
212 	NULL
213 };
214 
215 /*
216  * Simba specific error state structure
217  */
218 static struct simba_errstate {
219 	char *error;
220 	ushort_t pci_cfg_stat;
221 	ushort_t pci_cfg_sec_stat;
222 	uint64_t afsr;
223 	uint64_t afar;
224 	int bridge_secondary;
225 };
226 
227 static struct simba_cfg_state {
228 	dev_info_t *dip;
229 	ushort_t command;
230 	uchar_t cache_line_size;
231 	uchar_t latency_timer;
232 	uchar_t header_type;
233 	uchar_t bus_number;
234 	uchar_t sec_bus_number;
235 	uchar_t sub_bus_number;
236 	uchar_t sec_latency_timer;
237 	ushort_t bridge_control;
238 };
239 
240 /*
241  * soft state pointer and structure template:
242  */
243 static void *simba_state;
244 
245 typedef struct {
246 
247 	dev_info_t *dip;
248 
249 	/*
250 	 * configuration register state for the bus:
251 	 */
252 	ddi_acc_handle_t config_handle;
253 	uchar_t simba_cache_line_size;
254 	uchar_t simba_latency_timer;
255 
256 	/*
257 	 * cpr support:
258 	 */
259 	uint_t config_state_index;
260 	struct simba_cfg_state *simba_config_state_p;
261 	ddi_iblock_cookie_t fm_ibc;
262 	int fm_cap;
263 	kmutex_t simba_mutex;
264 	uint_t simba_soft_state;
265 #define	SIMBA_SOFT_STATE_CLOSED		0x00
266 #define	SIMBA_SOFT_STATE_OPEN		0x01
267 #define	SIMBA_SOFT_STATE_OPEN_EXCL	0x02
268 } simba_devstate_t;
269 
270 /*
271  * The following variable enables a workaround for the following obp bug:
272  *
273  *	1234181 - obp should set latency timer registers in pci
274  *		configuration header
275  *
276  * Until this bug gets fixed in the obp, the following workaround should
277  * be enabled.
278  */
279 static uint_t simba_set_latency_timer_register = 1;
280 
281 /*
282  * The following variable enables a workaround for an obp bug to be
283  * submitted.  A bug requesting a workaround fof this problem has
284  * been filed:
285  *
286  *	1235094 - need workarounds on positron nexus drivers to set cache
287  *		line size registers
288  *
289  * Until this bug gets fixed in the obp, the following workaround should
290  * be enabled.
291  */
292 static uint_t simba_set_cache_line_size_register = 1;
293 
294 
295 /*
296  * forward function declarations:
297  */
298 static void simba_uninitchild(dev_info_t *);
299 static int simba_initchild(dev_info_t *child);
300 static void simba_save_config_regs(simba_devstate_t *simba_p);
301 static void simba_restore_config_regs(simba_devstate_t *simba_p);
302 static int simba_err_callback(dev_info_t *dip, ddi_fm_error_t *derr,
303 		const void *impl_data);
304 
305 int
306 _init(void)
307 {
308 	int e;
309 
310 	DEBUG0(D_ATTACH, "_init() installing module...\n");
311 	if ((e = ddi_soft_state_init(&simba_state, sizeof (simba_devstate_t),
312 	    1)) == 0 && (e = mod_install(&modlinkage)) != 0)
313 		ddi_soft_state_fini(&simba_state);
314 
315 	DEBUG0(D_ATTACH, "_init() module installed\n");
316 	return (e);
317 }
318 
319 int
320 _fini(void)
321 {
322 	int e;
323 	DEBUG0(D_ATTACH, "_fini() removing module...\n");
324 	if ((e = mod_remove(&modlinkage)) == 0)
325 		ddi_soft_state_fini(&simba_state);
326 	return (e);
327 }
328 
329 int
330 _info(struct modinfo *modinfop)
331 {
332 	DEBUG0(D_ATTACH, "_info() called.\n");
333 	return (mod_info(&modlinkage, modinfop));
334 }
335 
336 /*ARGSUSED*/
337 static int
338 simba_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
339 {
340 	simba_devstate_t *simba_p;	/* per simba state pointer */
341 	int instance;
342 
343 	instance = getminor((dev_t)arg);
344 	simba_p = (simba_devstate_t *)ddi_get_soft_state(simba_state,
345 	    instance);
346 
347 	switch (infocmd) {
348 	default:
349 		return (DDI_FAILURE);
350 
351 	case DDI_INFO_DEVT2INSTANCE:
352 		*result = (void *)instance;
353 		return (DDI_SUCCESS);
354 
355 	case DDI_INFO_DEVT2DEVINFO:
356 		if (simba_p == NULL)
357 			return (DDI_FAILURE);
358 		*result = (void *)simba_p->dip;
359 		return (DDI_SUCCESS);
360 	}
361 }
362 
363 /*ARGSUSED*/
364 static int
365 simba_probe(register dev_info_t *devi)
366 {
367 	DEBUG0(D_ATTACH, "simba_probe() called.\n");
368 	return (DDI_PROBE_SUCCESS);
369 }
370 
371 /*ARGSUSED*/
372 static int
373 simba_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
374 {
375 	int instance;
376 	simba_devstate_t *simba;
377 	ddi_fm_error_t derr;
378 
379 	switch (cmd) {
380 	case DDI_ATTACH:
381 
382 		DEBUG1(D_ATTACH, "attach(%x) ATTACH\n", (int)devi);
383 
384 		/*
385 		 * Make sure the "device_type" property exists.
386 		 */
387 		(void) ddi_prop_update_string(DDI_DEV_T_NONE, devi,
388 			"device_type", "pci");
389 
390 		/*
391 		 * Allocate and get soft state structure.
392 		 */
393 		instance = ddi_get_instance(devi);
394 		if (ddi_soft_state_zalloc(simba_state, instance) != DDI_SUCCESS)
395 			return (DDI_FAILURE);
396 		simba = (simba_devstate_t *)ddi_get_soft_state(simba_state,
397 		    instance);
398 		simba->dip = devi;
399 		mutex_init(&simba->simba_mutex, NULL, MUTEX_DRIVER, NULL);
400 		simba->simba_soft_state = SIMBA_SOFT_STATE_CLOSED;
401 
402 		/*
403 		 * create minor node for devctl interfaces
404 		 */
405 		if (ddi_create_minor_node(devi, "devctl", S_IFCHR, instance,
406 		    DDI_NT_NEXUS, 0) != DDI_SUCCESS) {
407 			mutex_destroy(&simba->simba_mutex);
408 			ddi_soft_state_free(simba_state, instance);
409 			return (DDI_FAILURE);
410 		}
411 
412 		if (pci_config_setup(devi, &simba->config_handle) !=
413 		    DDI_SUCCESS) {
414 			ddi_remove_minor_node(devi, "devctl");
415 			mutex_destroy(&simba->simba_mutex);
416 			ddi_soft_state_free(simba_state, instance);
417 			return (DDI_FAILURE);
418 		}
419 
420 		/*
421 		 * Simba cache line size is 64 bytes and hardwired.
422 		 */
423 		simba->simba_cache_line_size =
424 		    pci_config_get8(simba->config_handle,
425 			PCI_CONF_CACHE_LINESZ);
426 		simba->simba_latency_timer =
427 		    pci_config_get8(simba->config_handle,
428 			PCI_CONF_LATENCY_TIMER);
429 
430 		/* simba specific, clears up the pri/sec status registers */
431 		pci_config_put16(simba->config_handle, 0x6, 0xffff);
432 		pci_config_put16(simba->config_handle, 0x1e, 0xffff);
433 
434 		DEBUG2(D_ATTACH, "simba_attach(): clsz=%x, lt=%x\n",
435 			simba->simba_cache_line_size,
436 			simba->simba_latency_timer);
437 
438 		/*
439 		 * Initialize FMA support
440 		 */
441 		simba->fm_cap = DDI_FM_EREPORT_CAPABLE | DDI_FM_ERRCB_CAPABLE |
442 			DDI_FM_ACCCHK_CAPABLE | DDI_FM_DMACHK_CAPABLE;
443 
444 		/*
445 		 * Call parent to get it's capablity
446 		 */
447 		ddi_fm_init(devi, &simba->fm_cap, &simba->fm_ibc);
448 
449 		ASSERT((simba->fm_cap & DDI_FM_ERRCB_CAPABLE) &&
450 		    (simba->fm_cap & DDI_FM_EREPORT_CAPABLE));
451 
452 		pci_ereport_setup(devi);
453 
454 		/*
455 		 * clear any outstanding error bits
456 		 */
457 		bzero(&derr, sizeof (ddi_fm_error_t));
458 		derr.fme_version = DDI_FME_VERSION;
459 		derr.fme_flag = DDI_FM_ERR_EXPECTED;
460 		pci_ereport_post(devi, &derr, NULL);
461 		pci_bdg_ereport_post(devi, &derr, NULL);
462 
463 		ddi_fm_handler_register(devi, simba_err_callback, simba);
464 
465 		ddi_report_dev(devi);
466 		DEBUG0(D_ATTACH, "attach(): ATTACH done\n");
467 		return (DDI_SUCCESS);
468 
469 	case DDI_RESUME:
470 
471 		/*
472 		 * Get the soft state structure for the bridge.
473 		 */
474 		simba = (simba_devstate_t *)
475 			ddi_get_soft_state(simba_state, ddi_get_instance(devi));
476 		simba_restore_config_regs(simba);
477 		return (DDI_SUCCESS);
478 	}
479 	return (DDI_FAILURE);
480 }
481 
482 /*ARGSUSED*/
483 static int
484 simba_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
485 {
486 	simba_devstate_t *simba;
487 	simba = (simba_devstate_t *)
488 		ddi_get_soft_state(simba_state, ddi_get_instance(devi));
489 
490 	switch (cmd) {
491 	case DDI_DETACH:
492 		DEBUG0(D_DETACH, "detach() called\n");
493 		ddi_fm_handler_unregister(devi);
494 		pci_ereport_teardown(devi);
495 		ddi_fm_fini(devi);
496 		pci_config_teardown(&simba->config_handle);
497 		(void) ddi_prop_remove(DDI_DEV_T_NONE, devi, "device_type");
498 		ddi_remove_minor_node(devi, "devctl");
499 		mutex_destroy(&simba->simba_mutex);
500 		ddi_soft_state_free(simba_state, ddi_get_instance(devi));
501 		return (DDI_SUCCESS);
502 
503 	case DDI_SUSPEND:
504 		simba_save_config_regs(simba);
505 		return (DDI_SUCCESS);
506 	}
507 	return (DDI_FAILURE);
508 }
509 
510 /*ARGSUSED*/
511 static int
512 simba_bus_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp,
513 	off_t offset, off_t len, caddr_t *vaddrp)
514 {
515 	register dev_info_t *pdip;
516 
517 	DEBUG3(D_MAP, "simba_bus_map(): dip=%x, rdip=%x, mp=%x", dip, rdip, mp);
518 	DEBUG3(D_MAP, "simba_bus_map(): offset=%x, len=%x, vaddrp=%x",
519 	    offset, len, vaddrp);
520 
521 	pdip = (dev_info_t *)DEVI(dip)->devi_parent;
522 	return ((DEVI(pdip)->devi_ops->devo_bus_ops->bus_map)
523 	    (pdip, rdip, mp, offset, len, vaddrp));
524 }
525 
526 /*
527  * Registered error handling callback with our parent
528  */
529 static int
530 simba_err_callback(dev_info_t *dip, ddi_fm_error_t *derr, const void *impl_data)
531 {
532 	simba_devstate_t *simba = (simba_devstate_t *)impl_data;
533 	struct simba_errstate simba_err;
534 	int ret = 0;
535 
536 	bzero(&simba_err, sizeof (struct simba_errstate));
537 	simba_err.afsr = pci_config_get64(simba->config_handle, 0xe8);
538 	simba_err.afar = pci_config_get64(simba->config_handle, 0xf0);
539 	derr->fme_ena = fm_ena_generate(0, FM_ENA_FMT1);
540 
541 	pci_ereport_post(dip, derr, &simba_err.pci_cfg_stat);
542 	pci_bdg_ereport_post(dip, derr, &simba_err.pci_cfg_sec_stat);
543 	ret = pci_bdg_check_status(dip, derr, simba_err.pci_cfg_stat,
544 	    simba_err.pci_cfg_sec_stat);
545 
546 	DEBUG6(D_FAULT, "%s-%d: cleaning up fault bits %x %x %x.%8x\n",
547 			ddi_driver_name(simba->dip),
548 			ddi_get_instance(simba->dip), simba_err.pci_cfg_stat,
549 			simba_err.pci_cfg_sec_stat,
550 			(uint_t)(simba_err.afsr >> 32),
551 			(uint_t)simba_err.afsr);
552 	pci_config_put64(simba->config_handle, 0xe8, simba_err.afsr);
553 
554 	return (ret);
555 }
556 
557 #if defined(DEBUG) && !defined(lint)
558 static char *ops[] =
559 {
560 	"DDI_CTLOPS_DMAPMAPC",
561 	"DDI_CTLOPS_INITCHILD",
562 	"DDI_CTLOPS_UNINITCHILD",
563 	"DDI_CTLOPS_REPORTDEV",
564 	"DDI_CTLOPS_REPORTINT",
565 	"DDI_CTLOPS_REGSIZE",
566 	"DDI_CTLOPS_NREGS",
567 	"DDI_CTLOPS_RESERVED0",
568 	"DDI_CTLOPS_SIDDEV",
569 	"DDI_CTLOPS_SLAVEONLY",
570 	"DDI_CTLOPS_AFFINITY",
571 	"DDI_CTLOPS_IOMIN",
572 	"DDI_CTLOPS_PTOB",
573 	"DDI_CTLOPS_BTOP",
574 	"DDI_CTLOPS_BTOPR",
575 	"DDI_CTLOPS_RESERVED1",
576 	"DDI_CTLOPS_RESERVED2",
577 	"DDI_CTLOPS_RESERVED3",
578 	"DDI_CTLOPS_RESERVED4",
579 	"DDI_CTLOPS_RESERVED5",
580 	"DDI_CTLOPS_DVMAPAGESIZE",
581 	"DDI_CTLOPS_POWER",
582 	"DDI_CTLOPS_ATTACH",
583 	"DDI_CTLOPS_DETACH",
584 	"DDI_CTLOPS_POKE",
585 	"DDI_CTLOPS_PEEK"
586 };
587 #endif
588 
589 /*ARGSUSED*/
590 static int
591 simba_ctlops(dev_info_t *dip, dev_info_t *rdip, ddi_ctl_enum_t ctlop,
592 	void *arg, void *result)
593 {
594 	int reglen;
595 	int rn;
596 	int totreg;
597 	pci_regspec_t *drv_regp;
598 
599 	DEBUG6(D_CTLOPS,
600 		"simba_ctlops(): dip=%x rdip=%x ctlop=%x-%s arg=%x result=%x",
601 		dip, rdip, ctlop, ctlop < (sizeof (ops) / sizeof (ops[0])) ?
602 		ops[ctlop] : "Unknown", arg, result);
603 
604 	switch (ctlop) {
605 	case DDI_CTLOPS_REPORTDEV:
606 		if (rdip == (dev_info_t *)0)
607 			return (DDI_FAILURE);
608 		cmn_err(CE_CONT, "?PCI-device: %s@%s, %s%d\n",
609 		    ddi_node_name(rdip), ddi_get_name_addr(rdip),
610 		    ddi_driver_name(rdip),
611 		    ddi_get_instance(rdip));
612 		return (DDI_SUCCESS);
613 
614 	case DDI_CTLOPS_INITCHILD:
615 		return (simba_initchild((dev_info_t *)arg));
616 
617 	case DDI_CTLOPS_UNINITCHILD:
618 		simba_uninitchild((dev_info_t *)arg);
619 		return (DDI_SUCCESS);
620 
621 	case DDI_CTLOPS_SIDDEV:
622 		return (DDI_SUCCESS);
623 
624 	case DDI_CTLOPS_REGSIZE:
625 	case DDI_CTLOPS_NREGS:
626 		if (rdip == (dev_info_t *)0)
627 			return (DDI_FAILURE);
628 		break;
629 
630 	default:
631 		DEBUG0(D_CTLOPS, "simba_ctlops(): calling ddi_ctlops()");
632 		return (ddi_ctlops(dip, rdip, ctlop, arg, result));
633 	}
634 
635 	*(int *)result = 0;
636 	if (ddi_getlongprop(DDI_DEV_T_ANY, rdip,
637 		DDI_PROP_DONTPASS | DDI_PROP_CANSLEEP, "reg",
638 		(caddr_t)&drv_regp, &reglen) != DDI_SUCCESS)
639 		return (DDI_FAILURE);
640 
641 	totreg = reglen / sizeof (pci_regspec_t);
642 	if (ctlop == DDI_CTLOPS_NREGS)
643 		*(int *)result = totreg;
644 	else if (ctlop == DDI_CTLOPS_REGSIZE) {
645 		rn = *(int *)arg;
646 		if (rn >= totreg) {
647 			kmem_free(drv_regp, reglen);
648 			return (DDI_FAILURE);
649 		}
650 		*(off_t *)result = drv_regp[rn].pci_size_low |
651 			((uint64_t)drv_regp[rn].pci_size_hi << 32);
652 	}
653 
654 	kmem_free(drv_regp, reglen);
655 	DEBUG1(D_CTLOPS, "simba_ctlops(): *result=%x\n", *(off_t *)result);
656 	return (DDI_SUCCESS);
657 }
658 
659 static int
660 simba_name_child(dev_info_t *child, char *name, int namelen)
661 {
662 	uint_t n, slot, func;
663 	pci_regspec_t *pci_rp;
664 
665 	if (ndi_dev_is_persistent_node(child) == 0) {
666 		char **unit_addr;
667 
668 		/* name .conf nodes by "unit-address" property" */
669 		if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, child,
670 		    DDI_PROP_DONTPASS, "unit-address", &unit_addr, &n) !=
671 		    DDI_PROP_SUCCESS) {
672 			cmn_err(CE_WARN, "cannot name node from %s.conf",
673 			    ddi_driver_name(child));
674 			return (DDI_FAILURE);
675 		}
676 		if (n != 1 || *unit_addr == NULL || **unit_addr == 0) {
677 			cmn_err(CE_WARN, "unit-address property in %s.conf"
678 			    " not well-formed", ddi_driver_name(child));
679 			ddi_prop_free(unit_addr);
680 			return (DDI_FAILURE);
681 		}
682 
683 		(void) snprintf(name, namelen, "%s", *unit_addr);
684 		ddi_prop_free(unit_addr);
685 		return (DDI_SUCCESS);
686 	}
687 
688 	/* name hardware nodes by "reg" property */
689 	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, child, 0, "reg",
690 	    (int **)&pci_rp, &n) != DDI_SUCCESS)
691 		return (DDI_FAILURE);
692 
693 	/* get the device identifications */
694 	slot = PCI_REG_DEV_G(pci_rp->pci_phys_hi);
695 	func = PCI_REG_FUNC_G(pci_rp->pci_phys_hi);
696 
697 	if (func != 0)
698 		(void) snprintf(name, namelen, "%x,%x", slot, func);
699 	else
700 		(void) snprintf(name, namelen, "%x", slot);
701 
702 	ddi_prop_free(pci_rp);
703 	return (DDI_SUCCESS);
704 }
705 
706 static int
707 simba_initchild(dev_info_t *child)
708 {
709 	char name[MAXNAMELEN];
710 	int i;
711 	ddi_acc_handle_t config_handle;
712 	ushort_t command_preserve, command;
713 	uchar_t header_type;
714 	uchar_t min_gnt, latency_timer;
715 	simba_devstate_t *simba;
716 	uint_t n;
717 
718 	DEBUG1(D_INIT_CLD, "simba_initchild(): child=%x\n", child);
719 
720 	/*
721 	 * Pseudo nodes indicate a prototype node with per-instance
722 	 * properties to be merged into the real h/w device node.
723 	 * The interpretation of the unit-address is DD[,F]
724 	 * where DD is the device id and F is the function.
725 	 */
726 	if (ndi_dev_is_persistent_node(child) == 0) {
727 		extern int pci_allow_pseudo_children;
728 		pci_regspec_t *pci_rp;
729 
730 		if (ddi_getlongprop(DDI_DEV_T_ANY, child,
731 		    DDI_PROP_DONTPASS, "reg", (caddr_t)&pci_rp, &i) ==
732 		    DDI_SUCCESS) {
733 			cmn_err(CE_WARN,
734 			    "cannot merge prototype from %s.conf",
735 			    ddi_driver_name(child));
736 			kmem_free(pci_rp, i);
737 			return (DDI_NOT_WELL_FORMED);
738 		}
739 
740 		if (simba_name_child(child, name, MAXNAMELEN) != DDI_SUCCESS)
741 			return (DDI_NOT_WELL_FORMED);
742 
743 		ddi_set_name_addr(child, name);
744 		ddi_set_parent_data(child, NULL);
745 
746 		/*
747 		 * Try to merge the properties from this prototype
748 		 * node into real h/w nodes.
749 		 */
750 		if (ndi_merge_node(child, simba_name_child) == DDI_SUCCESS) {
751 			/*
752 			 * Merged ok - return failure to remove the node.
753 			 */
754 			simba_uninitchild(child);
755 			return (DDI_FAILURE);
756 		}
757 
758 		/* workaround for ddivs to run under PCI */
759 		if (pci_allow_pseudo_children)
760 			return (DDI_SUCCESS);
761 
762 		/*
763 		 * The child was not merged into a h/w node,
764 		 * but there's not much we can do with it other
765 		 * than return failure to cause the node to be removed.
766 		 */
767 		cmn_err(CE_WARN, "!%s@%s: %s.conf properties not merged",
768 		    ddi_driver_name(child), ddi_get_name_addr(child),
769 		    ddi_driver_name(child));
770 		simba_uninitchild(child);
771 		return (DDI_NOT_WELL_FORMED);
772 	}
773 
774 	/*
775 	 * Initialize real h/w nodes
776 	 */
777 	if (simba_name_child(child, name, MAXNAMELEN) != DDI_SUCCESS)
778 		return (DDI_FAILURE);
779 
780 	ddi_set_name_addr(child, name);
781 	ddi_set_parent_data(child, NULL);
782 
783 	if (pci_config_setup(child, &config_handle) != DDI_SUCCESS) {
784 		simba_uninitchild(child);
785 		return (DDI_FAILURE);
786 	}
787 
788 	DEBUG0(D_INIT_CLD, "simba_initchild(): pci_config_setup success!\n");
789 
790 	/*
791 	 * Determine the configuration header type.
792 	 */
793 	header_type = pci_config_get8(config_handle, PCI_CONF_HEADER);
794 
795 	/*
796 	 * Support for the "command-preserve" property.
797 	 */
798 	command_preserve = ddi_prop_get_int(DDI_DEV_T_ANY, child,
799 	    DDI_PROP_DONTPASS, "command-preserve", 0);
800 	command = pci_config_get16(config_handle, PCI_CONF_COMM);
801 	command &= (command_preserve | PCI_COMM_BACK2BACK_ENAB);
802 	command |= (simba_command_default & ~command_preserve);
803 	pci_config_put16(config_handle, PCI_CONF_COMM, command);
804 
805 	/* clean up all PCI child devices status register */
806 	pci_config_put16(config_handle, PCI_CONF_STAT, 0xffff);
807 
808 	/*
809 	 * If the device has a primary bus control register then program it
810 	 * based on the settings in the command register.
811 	 */
812 	if ((header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_ONE) {
813 		ushort_t bcr =
814 		    pci_config_get16(config_handle, PCI_BCNF_BCNTRL);
815 		if (simba_command_default & PCI_COMM_PARITY_DETECT)
816 			bcr |= PCI_BCNF_BCNTRL_PARITY_ENABLE;
817 		if (simba_command_default & PCI_COMM_SERR_ENABLE)
818 			bcr |= PCI_BCNF_BCNTRL_SERR_ENABLE;
819 		bcr |= PCI_BCNF_BCNTRL_MAST_AB_MODE;
820 		pci_config_put8(config_handle, PCI_BCNF_BCNTRL, bcr);
821 	}
822 
823 	simba = (simba_devstate_t *)ddi_get_soft_state(simba_state,
824 		ddi_get_instance(ddi_get_parent(child)));
825 	/*
826 	 * Initialize cache-line-size configuration register if needed.
827 	 */
828 	if (simba_set_cache_line_size_register &&
829 	    ddi_getprop(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS,
830 		"cache-line-size", 0) == 0) {
831 		pci_config_put8(config_handle, PCI_CONF_CACHE_LINESZ,
832 		    simba->simba_cache_line_size);
833 		n = pci_config_get8(config_handle, PCI_CONF_CACHE_LINESZ);
834 		if (n != 0)
835 			(void) ndi_prop_update_int(DDI_DEV_T_NONE, child,
836 				"cache-line-size", n);
837 	}
838 
839 	/*
840 	 * Initialize latency timer configuration registers if needed.
841 	 */
842 	if (simba_set_latency_timer_register &&
843 	    ddi_getprop(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS,
844 		"latency-timer", 0) == 0) {
845 
846 		if ((header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_ONE) {
847 			latency_timer = simba->simba_latency_timer;
848 			pci_config_put8(config_handle, PCI_BCNF_LATENCY_TIMER,
849 			    simba->simba_latency_timer);
850 		} else {
851 			min_gnt = pci_config_get8(config_handle,
852 			    PCI_CONF_MIN_G);
853 			latency_timer = min_gnt * 8;
854 		}
855 		pci_config_put8(config_handle, PCI_CONF_LATENCY_TIMER,
856 		    latency_timer);
857 		n = pci_config_get8(config_handle, PCI_CONF_LATENCY_TIMER);
858 		if (n != 0)
859 			(void) ndi_prop_update_int(DDI_DEV_T_NONE, child,
860 			    "latency-timer", n);
861 	}
862 
863 	pci_config_teardown(&config_handle);
864 	DEBUG0(D_INIT_CLD, "simba_initchild(): pci_config_teardown called\n");
865 	return (DDI_SUCCESS);
866 }
867 
868 static void
869 simba_uninitchild(dev_info_t *dip)
870 {
871 	ddi_set_name_addr(dip, NULL);
872 
873 	/*
874 	 * Strip the node to properly convert it back to prototype form
875 	 */
876 	impl_rem_dev_props(dip);
877 }
878 
879 /*
880  * simba_save_config_regs
881  *
882  * This routine saves the state of the configuration registers of all
883  * the child nodes of each PBM.
884  *
885  * used by: simba_detach() on suspends
886  *
887  * return value: none
888  */
889 static void
890 simba_save_config_regs(simba_devstate_t *simba_p)
891 {
892 	int i;
893 	dev_info_t *dip;
894 	ddi_acc_handle_t ch;
895 	struct simba_cfg_state *statep;
896 
897 	for (i = 0, dip = ddi_get_child(simba_p->dip); dip != NULL;
898 		dip = ddi_get_next_sibling(dip)) {
899 		if (i_ddi_node_state(dip) >= DS_ATTACHED)
900 			i++;
901 	}
902 	if (!i)
903 		return;
904 	simba_p->simba_config_state_p =
905 		kmem_zalloc(i * sizeof (struct simba_cfg_state), KM_NOSLEEP);
906 	if (!simba_p->simba_config_state_p) {
907 		cmn_err(CE_WARN, "not enough memrory to save simba child\n");
908 		return;
909 	}
910 	simba_p->config_state_index = i;
911 
912 	for (statep = simba_p->simba_config_state_p,
913 		dip = ddi_get_child(simba_p->dip);
914 		dip != NULL;
915 		dip = ddi_get_next_sibling(dip)) {
916 
917 		if (i_ddi_node_state(dip) < DS_ATTACHED) {
918 			DEBUG4(D_DETACH, "%s%d: skipping unattached %s%d\n",
919 				ddi_driver_name(simba_p->dip),
920 				ddi_get_instance(simba_p->dip),
921 				ddi_driver_name(dip),
922 				ddi_get_instance(dip));
923 			continue;
924 		}
925 
926 		DEBUG4(D_DETACH, "%s%d: saving regs for %s%d\n",
927 			ddi_driver_name(simba_p->dip),
928 			ddi_get_instance(simba_p->dip),
929 			ddi_driver_name(dip),
930 			ddi_get_instance(dip));
931 
932 		if (pci_config_setup(dip, &ch) != DDI_SUCCESS) {
933 			DEBUG4(D_DETACH, "%s%d: can't config space for %s%d\n",
934 				ddi_driver_name(simba_p->dip),
935 				ddi_get_instance(simba_p->dip),
936 				ddi_driver_name(dip),
937 				ddi_get_instance(dip));
938 			continue;
939 		}
940 
941 		DEBUG3(D_DETACH, "%s%d: saving child dip=%x\n",
942 			ddi_driver_name(simba_p->dip),
943 			ddi_get_instance(simba_p->dip),
944 			dip);
945 
946 		statep->dip = dip;
947 		statep->command = pci_config_get16(ch, PCI_CONF_COMM);
948 		statep->header_type = pci_config_get8(ch, PCI_CONF_HEADER);
949 		if ((statep->header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_ONE)
950 			statep->bridge_control =
951 			    pci_config_get16(ch, PCI_BCNF_BCNTRL);
952 		statep->cache_line_size =
953 			pci_config_get8(ch, PCI_CONF_CACHE_LINESZ);
954 		statep->latency_timer =
955 			pci_config_get8(ch, PCI_CONF_LATENCY_TIMER);
956 		if ((statep->header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_ONE)
957 			statep->sec_latency_timer =
958 				pci_config_get8(ch, PCI_BCNF_LATENCY_TIMER);
959 		/*
960 		 * Simba specific.
961 		 */
962 		if (pci_config_get16(ch, PCI_CONF_VENID) == PCI_SIMBA_VENID &&
963 		    pci_config_get16(ch, PCI_CONF_DEVID) == PCI_SIMBA_DEVID) {
964 
965 			statep->bus_number =
966 				pci_config_get8(ch, PCI_BCNF_PRIBUS);
967 			statep->sec_bus_number =
968 				pci_config_get8(ch, PCI_BCNF_SECBUS);
969 			statep->sub_bus_number =
970 				pci_config_get8(ch, PCI_BCNF_SUBBUS);
971 			statep->bridge_control =
972 				pci_config_get16(ch, PCI_BCNF_BCNTRL);
973 		}
974 		pci_config_teardown(&ch);
975 		statep++;
976 	}
977 }
978 
979 
980 /*
981  * simba_restore_config_regs
982  *
983  * This routine restores the state of the configuration registers of all
984  * the child nodes of each PBM.
985  *
986  * used by: simba_attach() on resume
987  *
988  * return value: none
989  */
990 static void
991 simba_restore_config_regs(simba_devstate_t *simba_p)
992 {
993 	int i;
994 	dev_info_t *dip;
995 	ddi_acc_handle_t ch;
996 	struct simba_cfg_state *statep = simba_p->simba_config_state_p;
997 	if (!simba_p->config_state_index)
998 		return;
999 
1000 	for (i = 0; i < simba_p->config_state_index; i++, statep++) {
1001 		dip = statep->dip;
1002 		if (!dip) {
1003 			cmn_err(CE_WARN,
1004 				"%s%d: skipping bad dev info (%d)\n",
1005 				ddi_driver_name(simba_p->dip),
1006 				ddi_get_instance(simba_p->dip),
1007 				i);
1008 			continue;
1009 		}
1010 
1011 		DEBUG5(D_ATTACH, "%s%d: restoring regs for %x-%s%d\n",
1012 			ddi_driver_name(simba_p->dip),
1013 			ddi_get_instance(simba_p->dip),
1014 			dip,
1015 			ddi_driver_name(dip),
1016 			ddi_get_instance(dip));
1017 
1018 		if (pci_config_setup(dip, &ch) != DDI_SUCCESS) {
1019 			DEBUG4(D_ATTACH, "%s%d: can't config space for %s%d\n",
1020 				ddi_driver_name(simba_p->dip),
1021 				ddi_get_instance(simba_p->dip),
1022 				ddi_driver_name(dip),
1023 				ddi_get_instance(dip));
1024 			continue;
1025 		}
1026 		pci_config_put16(ch, PCI_CONF_COMM, statep->command);
1027 		if ((statep->header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_ONE)
1028 			pci_config_put16(ch, PCI_BCNF_BCNTRL,
1029 				statep->bridge_control);
1030 		/*
1031 		 * Simba specific.
1032 		 */
1033 		if (pci_config_get16(ch, PCI_CONF_VENID) == PCI_SIMBA_VENID &&
1034 		    pci_config_get16(ch, PCI_CONF_DEVID) == PCI_SIMBA_DEVID) {
1035 			pci_config_put8(ch, PCI_BCNF_PRIBUS,
1036 				statep->bus_number);
1037 			pci_config_put8(ch, PCI_BCNF_SECBUS,
1038 				statep->sec_bus_number);
1039 			pci_config_put8(ch, PCI_BCNF_SUBBUS,
1040 				statep->sub_bus_number);
1041 			pci_config_put16(ch, PCI_BCNF_BCNTRL,
1042 				statep->bridge_control);
1043 		}
1044 
1045 		pci_config_put8(ch, PCI_CONF_CACHE_LINESZ,
1046 			statep->cache_line_size);
1047 		pci_config_put8(ch, PCI_CONF_LATENCY_TIMER,
1048 			statep->latency_timer);
1049 		if ((statep->header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_ONE)
1050 			pci_config_put8(ch, PCI_BCNF_LATENCY_TIMER,
1051 				statep->sec_latency_timer);
1052 		pci_config_teardown(&ch);
1053 	}
1054 
1055 	kmem_free(simba_p->simba_config_state_p,
1056 		simba_p->config_state_index * sizeof (struct simba_cfg_state));
1057 	simba_p->simba_config_state_p = NULL;
1058 	simba_p->config_state_index = 0;
1059 }
1060 
1061 /* ARGSUSED */
1062 static int
1063 simba_open(dev_t *devp, int flags, int otyp, cred_t *credp)
1064 {
1065 	simba_devstate_t *simba_p;
1066 
1067 	/*
1068 	 * Make sure the open is for the right file type.
1069 	 */
1070 	if (otyp != OTYP_CHR)
1071 		return (EINVAL);
1072 
1073 	/*
1074 	 * Get the soft state structure for the device.
1075 	 */
1076 	simba_p = (simba_devstate_t *)ddi_get_soft_state(simba_state,
1077 	    getminor(*devp));
1078 	if (simba_p == NULL)
1079 		return (ENXIO);
1080 
1081 	/*
1082 	 * Handle the open by tracking the device state.
1083 	 */
1084 	mutex_enter(&simba_p->simba_mutex);
1085 	if (flags & FEXCL) {
1086 		if (simba_p->simba_soft_state != SIMBA_SOFT_STATE_CLOSED) {
1087 			mutex_exit(&simba_p->simba_mutex);
1088 			return (EBUSY);
1089 		}
1090 		simba_p->simba_soft_state = SIMBA_SOFT_STATE_OPEN_EXCL;
1091 	} else {
1092 		if (simba_p->simba_soft_state == SIMBA_SOFT_STATE_OPEN_EXCL) {
1093 			mutex_exit(&simba_p->simba_mutex);
1094 			return (EBUSY);
1095 		}
1096 		simba_p->simba_soft_state = SIMBA_SOFT_STATE_OPEN;
1097 	}
1098 	mutex_exit(&simba_p->simba_mutex);
1099 	return (0);
1100 }
1101 
1102 
1103 /* ARGSUSED */
1104 static int
1105 simba_close(dev_t dev, int flags, int otyp, cred_t *credp)
1106 {
1107 	simba_devstate_t *simba_p;
1108 
1109 	if (otyp != OTYP_CHR)
1110 		return (EINVAL);
1111 
1112 	simba_p = (simba_devstate_t *)ddi_get_soft_state(simba_state,
1113 	    getminor(dev));
1114 	if (simba_p == NULL)
1115 		return (ENXIO);
1116 
1117 	mutex_enter(&simba_p->simba_mutex);
1118 	simba_p->simba_soft_state = SIMBA_SOFT_STATE_CLOSED;
1119 	mutex_exit(&simba_p->simba_mutex);
1120 	return (0);
1121 }
1122 
1123 
1124 /*
1125  * simba_ioctl: devctl hotplug controls
1126  */
1127 /* ARGSUSED */
1128 static int
1129 simba_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
1130 	int *rvalp)
1131 {
1132 	simba_devstate_t *simba_p;
1133 	dev_info_t *self;
1134 	struct devctl_iocdata *dcp;
1135 	uint_t bus_state;
1136 	int rv = 0;
1137 
1138 	simba_p = (simba_devstate_t *)ddi_get_soft_state(simba_state,
1139 	    getminor(dev));
1140 	if (simba_p == NULL)
1141 		return (ENXIO);
1142 
1143 	self = simba_p->dip;
1144 
1145 	/*
1146 	 * We can use the generic implementation for these ioctls
1147 	 */
1148 	switch (cmd) {
1149 	case DEVCTL_DEVICE_GETSTATE:
1150 	case DEVCTL_DEVICE_ONLINE:
1151 	case DEVCTL_DEVICE_OFFLINE:
1152 	case DEVCTL_BUS_GETSTATE:
1153 		return (ndi_devctl_ioctl(self, cmd, arg, mode, 0));
1154 	}
1155 
1156 	/*
1157 	 * read devctl ioctl data
1158 	 */
1159 	if (ndi_dc_allochdl((void *)arg, &dcp) != NDI_SUCCESS)
1160 		return (EFAULT);
1161 
1162 	switch (cmd) {
1163 
1164 	case DEVCTL_DEVICE_RESET:
1165 		rv = ENOTSUP;
1166 		break;
1167 
1168 
1169 	case DEVCTL_BUS_QUIESCE:
1170 		if (ndi_get_bus_state(self, &bus_state) == NDI_SUCCESS)
1171 			if (bus_state == BUS_QUIESCED)
1172 				break;
1173 		(void) ndi_set_bus_state(self, BUS_QUIESCED);
1174 		break;
1175 
1176 	case DEVCTL_BUS_UNQUIESCE:
1177 		if (ndi_get_bus_state(self, &bus_state) == NDI_SUCCESS)
1178 			if (bus_state == BUS_ACTIVE)
1179 				break;
1180 		(void) ndi_set_bus_state(self, BUS_ACTIVE);
1181 		break;
1182 
1183 	case DEVCTL_BUS_RESET:
1184 		rv = ENOTSUP;
1185 		break;
1186 
1187 	case DEVCTL_BUS_RESETALL:
1188 		rv = ENOTSUP;
1189 		break;
1190 
1191 	default:
1192 		rv = ENOTTY;
1193 	}
1194 
1195 	ndi_dc_freehdl(dcp);
1196 	return (rv);
1197 }
1198 
1199 /*
1200  * Initialize FMA resources for children devices. Called when
1201  * child calls ddi_fm_init().
1202  */
1203 /*ARGSUSED*/
1204 static int
1205 simba_fm_init_child(dev_info_t *dip, dev_info_t *tdip, int cap,
1206 		ddi_iblock_cookie_t *ibc)
1207 {
1208 	simba_devstate_t *simba_p = ddi_get_soft_state(simba_state,
1209 			ddi_get_instance(dip));
1210 
1211 	*ibc = simba_p->fm_ibc;
1212 	return (simba_p->fm_cap);
1213 }
1214 
1215 static void
1216 simba_bus_enter(dev_info_t *dip, ddi_acc_handle_t handle)
1217 {
1218 	i_ndi_busop_access_enter(dip, handle);
1219 }
1220 
1221 /* ARGSUSED */
1222 static void
1223 simba_bus_exit(dev_info_t *dip, ddi_acc_handle_t handle)
1224 {
1225 	i_ndi_busop_access_exit(dip, handle);
1226 }
1227