xref: /illumos-gate/usr/src/uts/sun4u/daktari/io/hpc3130_dak.c (revision baa111a1f46457da764bd7a40234b4f9a2de1885)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
58e03c085Szk194757  * Common Development and Distribution License (the "License").
68e03c085Szk194757  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22d3d50737SRafael Vanoni  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate /*
277c478bd9Sstevel@tonic-gate  * Daktari platform specific hotplug controller. This
287c478bd9Sstevel@tonic-gate  * driver exports the same interfaces to user space
297c478bd9Sstevel@tonic-gate  * as the generic hpc3130 driver.  It adds specific
307c478bd9Sstevel@tonic-gate  * functionality found on Daktari, such as slot button
317c478bd9Sstevel@tonic-gate  * and platform specific LED displays.  Placed in
327c478bd9Sstevel@tonic-gate  * the daktari specific platform directory, it will
337c478bd9Sstevel@tonic-gate  * be loaded instead of the generic module.
347c478bd9Sstevel@tonic-gate  */
357c478bd9Sstevel@tonic-gate 
367c478bd9Sstevel@tonic-gate 
377c478bd9Sstevel@tonic-gate #include <sys/types.h>
387c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
397c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
407c478bd9Sstevel@tonic-gate #include <sys/errno.h>
417c478bd9Sstevel@tonic-gate #include <sys/cpuvar.h>
427c478bd9Sstevel@tonic-gate #include <sys/open.h>
437c478bd9Sstevel@tonic-gate #include <sys/stat.h>
447c478bd9Sstevel@tonic-gate #include <sys/conf.h>
457c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
467c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
477c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
487c478bd9Sstevel@tonic-gate #include <sys/note.h>
497c478bd9Sstevel@tonic-gate #include <sys/hotplug/hpctrl.h>
507c478bd9Sstevel@tonic-gate #include <sys/hotplug/hpcsvc.h>
517c478bd9Sstevel@tonic-gate #include <sys/i2c/clients/hpc3130.h>
527c478bd9Sstevel@tonic-gate #include <sys/hpc3130_events.h>
537c478bd9Sstevel@tonic-gate #include <sys/daktari.h>
547c478bd9Sstevel@tonic-gate #include <sys/hpc3130_dak.h>
557c478bd9Sstevel@tonic-gate 
567c478bd9Sstevel@tonic-gate #ifdef DEBUG
577c478bd9Sstevel@tonic-gate static int hpc3130debug = 0;
587c478bd9Sstevel@tonic-gate 
597c478bd9Sstevel@tonic-gate #define	D1CMN_ERR(ARGS) if (hpc3130debug & 0x1) cmn_err ARGS;
607c478bd9Sstevel@tonic-gate #define	D2CMN_ERR(ARGS) if (hpc3130debug & 0x2) cmn_err ARGS;
617c478bd9Sstevel@tonic-gate 
627c478bd9Sstevel@tonic-gate #else
637c478bd9Sstevel@tonic-gate 
647c478bd9Sstevel@tonic-gate #define	D1CMN_ERR(ARGS)
657c478bd9Sstevel@tonic-gate #define	D2CMN_ERR(ARGS)
667c478bd9Sstevel@tonic-gate 
677c478bd9Sstevel@tonic-gate #endif /* DEBUG */
687c478bd9Sstevel@tonic-gate 
697c478bd9Sstevel@tonic-gate #define	HPC3130_REG(offset, slot) ((offset) + ((slot)*8))
707c478bd9Sstevel@tonic-gate #define	HPC3130_PIL	1
717c478bd9Sstevel@tonic-gate struct tuple {
727c478bd9Sstevel@tonic-gate 	uint8_t reg;
737c478bd9Sstevel@tonic-gate 	uint8_t val;
747c478bd9Sstevel@tonic-gate };
757c478bd9Sstevel@tonic-gate 
767c478bd9Sstevel@tonic-gate struct connect_command {
777c478bd9Sstevel@tonic-gate 	boolean_t set_bit;
787c478bd9Sstevel@tonic-gate 	uint8_t value;
797c478bd9Sstevel@tonic-gate };
807c478bd9Sstevel@tonic-gate 
817c478bd9Sstevel@tonic-gate struct tuple pci_sequence [] =
827c478bd9Sstevel@tonic-gate {
837c478bd9Sstevel@tonic-gate 	{HPC3130_GCR, HPC3130_AUTO2_SEQ},
847c478bd9Sstevel@tonic-gate 	{HPC3130_INTERRUPT, HPC3130_PWRGOOD |
857c478bd9Sstevel@tonic-gate 		HPC3130_DETECT0 | HPC3130_PRSNT1 | HPC3130_PRSNT2},
867c478bd9Sstevel@tonic-gate 	{HPC3130_EVENT_STATUS, 0xff},
877c478bd9Sstevel@tonic-gate 	{HPC3130_NO_REGISTER, 0},
887c478bd9Sstevel@tonic-gate };
897c478bd9Sstevel@tonic-gate 
907c478bd9Sstevel@tonic-gate struct tuple cpu_sequence [] =
917c478bd9Sstevel@tonic-gate {
927c478bd9Sstevel@tonic-gate 	{HPC3130_INTERRUPT,
937c478bd9Sstevel@tonic-gate 		HPC3130_PRSNT1 | HPC3130_DETECT0},
947c478bd9Sstevel@tonic-gate 	{HPC3130_EVENT_STATUS, 0xff},
957c478bd9Sstevel@tonic-gate 	{HPC3130_NO_REGISTER, 0},
967c478bd9Sstevel@tonic-gate };
977c478bd9Sstevel@tonic-gate 
987c478bd9Sstevel@tonic-gate struct connect_command connect_sequence [] =
997c478bd9Sstevel@tonic-gate {
1007c478bd9Sstevel@tonic-gate 	{B_TRUE,  HPC3130_SLOTREQ64},
1017c478bd9Sstevel@tonic-gate 	{B_FALSE, HPC3130_SLOTRST},
1027c478bd9Sstevel@tonic-gate 	{B_FALSE, HPC3130_CLKON},
1037c478bd9Sstevel@tonic-gate 	{B_FALSE, HPC3130_REQ64},
1047c478bd9Sstevel@tonic-gate 	{B_FALSE, HPC3130_SLOTREQ64},
1057c478bd9Sstevel@tonic-gate 	{B_TRUE,  HPC3130_SLOTRST},
1067c478bd9Sstevel@tonic-gate 	{B_FALSE, HPC3130_BUS_CTL},
1077c478bd9Sstevel@tonic-gate };
1087c478bd9Sstevel@tonic-gate 
1097c478bd9Sstevel@tonic-gate #define	HPC3130_CONNECT_SEQ_COUNT (sizeof (connect_sequence)/ \
1107c478bd9Sstevel@tonic-gate 	sizeof (struct connect_command))
1117c478bd9Sstevel@tonic-gate 
1127c478bd9Sstevel@tonic-gate struct xlate_entry {
1137c478bd9Sstevel@tonic-gate 	char	*nexus;
1147c478bd9Sstevel@tonic-gate 	int	pcidev;
1157c478bd9Sstevel@tonic-gate };
1167c478bd9Sstevel@tonic-gate /*
1177c478bd9Sstevel@tonic-gate  * The order here is significant.  Its the order
1187c478bd9Sstevel@tonic-gate  * of appearance of slots from bottom to top
1197c478bd9Sstevel@tonic-gate  * on a Sun-Fire-880
1207c478bd9Sstevel@tonic-gate  */
1217c478bd9Sstevel@tonic-gate static struct xlate_entry slot_translate[] =
1227c478bd9Sstevel@tonic-gate {
1237c478bd9Sstevel@tonic-gate 	{"/pci@8,700000", 5},	/* PCI0 */
1247c478bd9Sstevel@tonic-gate 	{"/pci@8,700000", 4},	/* PCI1 */
1257c478bd9Sstevel@tonic-gate 	{"/pci@8,700000", 3},	/* PCI2 */
1267c478bd9Sstevel@tonic-gate 	{"/pci@8,700000", 2},	/* PCI3 */
1277c478bd9Sstevel@tonic-gate 
1287c478bd9Sstevel@tonic-gate 	{"/pci@9,700000", 4},	/* PCI4 */
1297c478bd9Sstevel@tonic-gate 	{"/pci@9,700000", 3},	/* PCI5 */
1307c478bd9Sstevel@tonic-gate 	{"/pci@9,700000", 2},	/* PCI6 */
1317c478bd9Sstevel@tonic-gate 
1327c478bd9Sstevel@tonic-gate 	{"/pci@9,600000", 2},	/* PCI7 */
1337c478bd9Sstevel@tonic-gate 	{"/pci@9,600000", 1}	/* PCI8 */
1347c478bd9Sstevel@tonic-gate };
1357c478bd9Sstevel@tonic-gate 
1367c478bd9Sstevel@tonic-gate #define	HPC3130_LOOKUP_SLOTS (sizeof (slot_translate)/ \
1377c478bd9Sstevel@tonic-gate 	sizeof (struct xlate_entry))
1387c478bd9Sstevel@tonic-gate 
1397c478bd9Sstevel@tonic-gate static int control_slot_control = HPC3130_SLOT_CONTROL_ENABLE;
1407c478bd9Sstevel@tonic-gate 
1417c478bd9Sstevel@tonic-gate hpc3130_unit_t *hpc3130soft_statep;
1427c478bd9Sstevel@tonic-gate 
1437c478bd9Sstevel@tonic-gate static int hpc3130_atoi(const char *);
1447c478bd9Sstevel@tonic-gate int hpc3130_lookup_slot(char *, int);
1457c478bd9Sstevel@tonic-gate 
1467c478bd9Sstevel@tonic-gate static int hpc3130_init(dev_info_t *, struct tuple *);
1477c478bd9Sstevel@tonic-gate static uint_t hpc3130_hard_intr(caddr_t);
1487c478bd9Sstevel@tonic-gate 
1497c478bd9Sstevel@tonic-gate static int hpc3130_cpu_init(hpc3130_unit_t *, int, i2c_client_hdl_t);
1507c478bd9Sstevel@tonic-gate static int hpc3130_debounce_status(i2c_client_hdl_t, int, uint8_t *);
1517c478bd9Sstevel@tonic-gate static int hpc3130_read(i2c_client_hdl_t, uint8_t, uint8_t, uint8_t *);
1527c478bd9Sstevel@tonic-gate static int hpc3130_write(i2c_client_hdl_t, uint8_t, uint8_t, uint8_t);
1537c478bd9Sstevel@tonic-gate static int hpc3130_rw(i2c_client_hdl_t, uint8_t, boolean_t, uint8_t *);
1547c478bd9Sstevel@tonic-gate 
1557c478bd9Sstevel@tonic-gate static int hpc3130_do_attach(dev_info_t *);
1567c478bd9Sstevel@tonic-gate static int hpc3130_do_detach(dev_info_t *);
1577c478bd9Sstevel@tonic-gate static int hpc3130_do_resume(void);
1587c478bd9Sstevel@tonic-gate static int hpc3130_do_suspend();
1597c478bd9Sstevel@tonic-gate static int hpc3130_get(intptr_t, int, hpc3130_unit_t *, int);
1607c478bd9Sstevel@tonic-gate static int hpc3130_set(intptr_t, int, hpc3130_unit_t *, int);
1617c478bd9Sstevel@tonic-gate 
1627c478bd9Sstevel@tonic-gate static int hpc3130_slot_connect(caddr_t, hpc_slot_t, void *, uint_t);
1637c478bd9Sstevel@tonic-gate static int hpc3130_slot_disconnect(caddr_t, hpc_slot_t, void *, uint_t);
1647c478bd9Sstevel@tonic-gate static int hpc3130_verify_slot_power(hpc3130_unit_t *, i2c_client_hdl_t,
1657c478bd9Sstevel@tonic-gate 					uint8_t, char *, boolean_t);
1667c478bd9Sstevel@tonic-gate static int hpc3130_slot_insert(caddr_t, hpc_slot_t, void *, uint_t);
1677c478bd9Sstevel@tonic-gate static int hpc3130_slot_remove(caddr_t, hpc_slot_t, void *, uint_t);
1687c478bd9Sstevel@tonic-gate static int hpc3130_slot_control(caddr_t, hpc_slot_t, int, caddr_t);
1697c478bd9Sstevel@tonic-gate /*
1707c478bd9Sstevel@tonic-gate  * cb ops
1717c478bd9Sstevel@tonic-gate  */
1727c478bd9Sstevel@tonic-gate static int hpc3130_open(dev_t *, int, int, cred_t *);
1737c478bd9Sstevel@tonic-gate static int hpc3130_close(dev_t, int, int, cred_t *);
1747c478bd9Sstevel@tonic-gate static int hpc3130_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
1757c478bd9Sstevel@tonic-gate static int hpc3130_poll(dev_t dev, short events, int anyyet,  short
1767c478bd9Sstevel@tonic-gate 			*reventsp, struct pollhead **phpp);
1777c478bd9Sstevel@tonic-gate 
1787c478bd9Sstevel@tonic-gate static struct cb_ops hpc3130_cbops = {
1797c478bd9Sstevel@tonic-gate 	hpc3130_open,			/* open  */
1807c478bd9Sstevel@tonic-gate 	hpc3130_close,			/* close */
1817c478bd9Sstevel@tonic-gate 	nodev,				/* strategy */
1827c478bd9Sstevel@tonic-gate 	nodev,				/* print */
1837c478bd9Sstevel@tonic-gate 	nodev,				/* dump */
1847c478bd9Sstevel@tonic-gate 	nodev,				/* read */
1857c478bd9Sstevel@tonic-gate 	nodev,				/* write */
1867c478bd9Sstevel@tonic-gate 	hpc3130_ioctl,			/* ioctl */
1877c478bd9Sstevel@tonic-gate 	nodev,				/* devmap */
1887c478bd9Sstevel@tonic-gate 	nodev,				/* mmap */
1897c478bd9Sstevel@tonic-gate 	nodev,				/* segmap */
1907c478bd9Sstevel@tonic-gate 	hpc3130_poll,			/* poll */
1917c478bd9Sstevel@tonic-gate 	ddi_prop_op,			/* cb_prop_op */
1927c478bd9Sstevel@tonic-gate 	NULL,				/* streamtab */
1937c478bd9Sstevel@tonic-gate 	D_NEW | D_MP | D_HOTPLUG,	/* Driver compatibility flag */
1947c478bd9Sstevel@tonic-gate 	CB_REV,				/* rev */
1957c478bd9Sstevel@tonic-gate 	nodev,				/* int (*cb_aread)() */
1967c478bd9Sstevel@tonic-gate 	nodev				/* int (*cb_awrite)() */
1977c478bd9Sstevel@tonic-gate };
1987c478bd9Sstevel@tonic-gate 
1997c478bd9Sstevel@tonic-gate /*
2007c478bd9Sstevel@tonic-gate  * dev ops
2017c478bd9Sstevel@tonic-gate  */
2027c478bd9Sstevel@tonic-gate static int hpc3130_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
2037c478bd9Sstevel@tonic-gate 		void **result);
2047c478bd9Sstevel@tonic-gate static int hpc3130_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
2057c478bd9Sstevel@tonic-gate static int hpc3130_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
2067c478bd9Sstevel@tonic-gate 
2077c478bd9Sstevel@tonic-gate static struct dev_ops hpc3130_ops = {
2087c478bd9Sstevel@tonic-gate 	DEVO_REV,
2097c478bd9Sstevel@tonic-gate 	0,
2107c478bd9Sstevel@tonic-gate 	hpc3130_info,
2117c478bd9Sstevel@tonic-gate 	nulldev,
2127c478bd9Sstevel@tonic-gate 	nulldev,
2137c478bd9Sstevel@tonic-gate 	hpc3130_attach,
2147c478bd9Sstevel@tonic-gate 	hpc3130_detach,
2157c478bd9Sstevel@tonic-gate 	nodev,
2167c478bd9Sstevel@tonic-gate 	&hpc3130_cbops,
21719397407SSherry Moore 	NULL,			/* bus_ops */
21819397407SSherry Moore 	NULL,			/* power */
21919397407SSherry Moore 	ddi_quiesce_not_needed,		/* quiesce */
2207c478bd9Sstevel@tonic-gate };
2217c478bd9Sstevel@tonic-gate 
2227c478bd9Sstevel@tonic-gate extern struct mod_ops mod_driverops;
2237c478bd9Sstevel@tonic-gate 
2247c478bd9Sstevel@tonic-gate static struct modldrv hpc3130_modldrv = {
2257c478bd9Sstevel@tonic-gate 	&mod_driverops,			/* type of module - driver */
22619397407SSherry Moore 	"Hotplug controller driver",
2277c478bd9Sstevel@tonic-gate 	&hpc3130_ops
2287c478bd9Sstevel@tonic-gate };
2297c478bd9Sstevel@tonic-gate 
2307c478bd9Sstevel@tonic-gate static struct modlinkage hpc3130_modlinkage = {
2317c478bd9Sstevel@tonic-gate 	MODREV_1,
2327c478bd9Sstevel@tonic-gate 	&hpc3130_modldrv,
2337c478bd9Sstevel@tonic-gate 	0
2347c478bd9Sstevel@tonic-gate };
2357c478bd9Sstevel@tonic-gate 
2367c478bd9Sstevel@tonic-gate int
_init(void)2377c478bd9Sstevel@tonic-gate _init(void)
2387c478bd9Sstevel@tonic-gate {
2397c478bd9Sstevel@tonic-gate 	int error;
2407c478bd9Sstevel@tonic-gate 
2417c478bd9Sstevel@tonic-gate 	error = mod_install(&hpc3130_modlinkage);
2427c478bd9Sstevel@tonic-gate 
2437c478bd9Sstevel@tonic-gate 	if (!error)
2447c478bd9Sstevel@tonic-gate 		(void) ddi_soft_state_init((void *)&hpc3130soft_statep,
2457c478bd9Sstevel@tonic-gate 		    sizeof (hpc3130_unit_t), 4);
2467c478bd9Sstevel@tonic-gate 	return (error);
2477c478bd9Sstevel@tonic-gate }
2487c478bd9Sstevel@tonic-gate 
2497c478bd9Sstevel@tonic-gate int
_fini(void)2507c478bd9Sstevel@tonic-gate _fini(void)
2517c478bd9Sstevel@tonic-gate {
2527c478bd9Sstevel@tonic-gate 	int error;
2537c478bd9Sstevel@tonic-gate 
2547c478bd9Sstevel@tonic-gate 	error = mod_remove(&hpc3130_modlinkage);
2557c478bd9Sstevel@tonic-gate 	if (!error)
2567c478bd9Sstevel@tonic-gate 		ddi_soft_state_fini((void *)&hpc3130soft_statep);
2577c478bd9Sstevel@tonic-gate 
2587c478bd9Sstevel@tonic-gate 	return (error);
2597c478bd9Sstevel@tonic-gate }
2607c478bd9Sstevel@tonic-gate 
2617c478bd9Sstevel@tonic-gate int
_info(struct modinfo * modinfop)2627c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop)
2637c478bd9Sstevel@tonic-gate {
2647c478bd9Sstevel@tonic-gate 	return (mod_info(&hpc3130_modlinkage, modinfop));
2657c478bd9Sstevel@tonic-gate }
2667c478bd9Sstevel@tonic-gate 
2677c478bd9Sstevel@tonic-gate static int
hpc3130_open(dev_t * devp,int flags,int otyp,cred_t * credp)2687c478bd9Sstevel@tonic-gate hpc3130_open(dev_t *devp, int flags, int otyp, cred_t *credp)
2697c478bd9Sstevel@tonic-gate {
2707c478bd9Sstevel@tonic-gate 	_NOTE(ARGUNUSED(credp))
2717c478bd9Sstevel@tonic-gate 	hpc3130_unit_t *unitp;
2727c478bd9Sstevel@tonic-gate 	int instance;
2737c478bd9Sstevel@tonic-gate 	int error = 0;
2747c478bd9Sstevel@tonic-gate 
2757c478bd9Sstevel@tonic-gate 	if (otyp != OTYP_CHR) {
2767c478bd9Sstevel@tonic-gate 		return (EINVAL);
2777c478bd9Sstevel@tonic-gate 	}
2787c478bd9Sstevel@tonic-gate 
2797c478bd9Sstevel@tonic-gate 	instance = MINOR_TO_INST(getminor(*devp));
2807c478bd9Sstevel@tonic-gate 
2817c478bd9Sstevel@tonic-gate 	unitp = (hpc3130_unit_t *)
2827c478bd9Sstevel@tonic-gate 	    ddi_get_soft_state(hpc3130soft_statep, instance);
2837c478bd9Sstevel@tonic-gate 
2847c478bd9Sstevel@tonic-gate 	if (unitp == NULL) {
2857c478bd9Sstevel@tonic-gate 		return (ENXIO);
2867c478bd9Sstevel@tonic-gate 	}
2877c478bd9Sstevel@tonic-gate 
2887c478bd9Sstevel@tonic-gate 	mutex_enter(&unitp->hpc3130_mutex);
2897c478bd9Sstevel@tonic-gate 
2907c478bd9Sstevel@tonic-gate 	if (flags & FEXCL) {
2917c478bd9Sstevel@tonic-gate 		if (unitp->hpc3130_oflag != 0) {
2927c478bd9Sstevel@tonic-gate 			error = EBUSY;
2937c478bd9Sstevel@tonic-gate 		} else {
2947c478bd9Sstevel@tonic-gate 			unitp->hpc3130_oflag = FEXCL;
2957c478bd9Sstevel@tonic-gate 		}
2967c478bd9Sstevel@tonic-gate 	} else {
2977c478bd9Sstevel@tonic-gate 		if (unitp->hpc3130_oflag == FEXCL) {
2987c478bd9Sstevel@tonic-gate 			error = EBUSY;
2997c478bd9Sstevel@tonic-gate 		} else {
3007c478bd9Sstevel@tonic-gate 			unitp->hpc3130_oflag = FOPEN;
3017c478bd9Sstevel@tonic-gate 		}
3027c478bd9Sstevel@tonic-gate 	}
3037c478bd9Sstevel@tonic-gate 
3047c478bd9Sstevel@tonic-gate 	mutex_exit(&unitp->hpc3130_mutex);
3057c478bd9Sstevel@tonic-gate 
3067c478bd9Sstevel@tonic-gate 	return (error);
3077c478bd9Sstevel@tonic-gate }
3087c478bd9Sstevel@tonic-gate 
3097c478bd9Sstevel@tonic-gate static int
hpc3130_close(dev_t dev,int flags,int otyp,cred_t * credp)3107c478bd9Sstevel@tonic-gate hpc3130_close(dev_t dev, int flags, int otyp, cred_t *credp)
3117c478bd9Sstevel@tonic-gate {
3127c478bd9Sstevel@tonic-gate 	_NOTE(ARGUNUSED(flags, otyp, credp))
3137c478bd9Sstevel@tonic-gate 	hpc3130_unit_t *unitp;
3147c478bd9Sstevel@tonic-gate 	int instance;
3157c478bd9Sstevel@tonic-gate 
3167c478bd9Sstevel@tonic-gate 	instance = MINOR_TO_INST(getminor(dev));
3177c478bd9Sstevel@tonic-gate 
3187c478bd9Sstevel@tonic-gate 	unitp = (hpc3130_unit_t *)
3197c478bd9Sstevel@tonic-gate 	    ddi_get_soft_state(hpc3130soft_statep, instance);
3207c478bd9Sstevel@tonic-gate 
3217c478bd9Sstevel@tonic-gate 	if (unitp == NULL) {
3227c478bd9Sstevel@tonic-gate 		return (ENXIO);
3237c478bd9Sstevel@tonic-gate 	}
3247c478bd9Sstevel@tonic-gate 
3257c478bd9Sstevel@tonic-gate 	mutex_enter(&unitp->hpc3130_mutex);
3267c478bd9Sstevel@tonic-gate 
3277c478bd9Sstevel@tonic-gate 	unitp->hpc3130_oflag = 0;
3287c478bd9Sstevel@tonic-gate 
3297c478bd9Sstevel@tonic-gate 	mutex_exit(&unitp->hpc3130_mutex);
3307c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
3317c478bd9Sstevel@tonic-gate }
3327c478bd9Sstevel@tonic-gate 
3337c478bd9Sstevel@tonic-gate static int
hpc3130_get(intptr_t arg,int reg,hpc3130_unit_t * unitp,int mode)3347c478bd9Sstevel@tonic-gate hpc3130_get(intptr_t arg, int reg, hpc3130_unit_t *unitp, int mode)
3357c478bd9Sstevel@tonic-gate {
3367c478bd9Sstevel@tonic-gate 	i2c_transfer_t		*i2c_tran_pointer;
3377c478bd9Sstevel@tonic-gate 	int err = DDI_SUCCESS;
3387c478bd9Sstevel@tonic-gate 
339*baa111a1SToomas Soome 	if (arg == (intptr_t)NULL) {
3407c478bd9Sstevel@tonic-gate 		D2CMN_ERR((CE_WARN, "ioctl: arg passed in to "
3417c478bd9Sstevel@tonic-gate 		    "ioctl = NULL"));
3427c478bd9Sstevel@tonic-gate 		return (EINVAL);
3437c478bd9Sstevel@tonic-gate 	}
3447c478bd9Sstevel@tonic-gate 	(void) i2c_transfer_alloc(unitp->hpc3130_hdl, &i2c_tran_pointer,
3457c478bd9Sstevel@tonic-gate 	    1, 1, I2C_SLEEP);
3467c478bd9Sstevel@tonic-gate 	if (i2c_tran_pointer == NULL) {
3477c478bd9Sstevel@tonic-gate 		D2CMN_ERR((CE_WARN, "Failed in HPC3130_GET_STATUS"
3487c478bd9Sstevel@tonic-gate 		    " i2c_tran_pointer not allocated"));
3497c478bd9Sstevel@tonic-gate 		return (ENOMEM);
3507c478bd9Sstevel@tonic-gate 	}
3517c478bd9Sstevel@tonic-gate 
3527c478bd9Sstevel@tonic-gate 	i2c_tran_pointer->i2c_flags = I2C_WR_RD;
3537c478bd9Sstevel@tonic-gate 	i2c_tran_pointer->i2c_wbuf[0] = (uchar_t)reg;
3547c478bd9Sstevel@tonic-gate 
3557c478bd9Sstevel@tonic-gate 	err = i2c_transfer(unitp->hpc3130_hdl, i2c_tran_pointer);
3567c478bd9Sstevel@tonic-gate 	if (err) {
3577c478bd9Sstevel@tonic-gate 		D2CMN_ERR((CE_WARN, "Failed in HPC3130_GET_STATUS"
3587c478bd9Sstevel@tonic-gate 		    " i2c_trasfer routine"));
3597c478bd9Sstevel@tonic-gate 		i2c_transfer_free(unitp->hpc3130_hdl, i2c_tran_pointer);
3607c478bd9Sstevel@tonic-gate 		return (err);
3617c478bd9Sstevel@tonic-gate 	}
3627c478bd9Sstevel@tonic-gate 	D1CMN_ERR((CE_NOTE, "The i2c_rbuf contains %x",
3637c478bd9Sstevel@tonic-gate 	    i2c_tran_pointer->i2c_rbuf[0]));
3647c478bd9Sstevel@tonic-gate 
3657c478bd9Sstevel@tonic-gate 	if (ddi_copyout((caddr_t)i2c_tran_pointer->i2c_rbuf,
3667c478bd9Sstevel@tonic-gate 	    (caddr_t)arg,
3677c478bd9Sstevel@tonic-gate 	    sizeof (uint8_t), mode) != DDI_SUCCESS) {
3687c478bd9Sstevel@tonic-gate 		D2CMN_ERR((CE_WARN, "Failed in HPC3130_GET_STATUS"
3697c478bd9Sstevel@tonic-gate 		    " ddi_copyout routine"));
3707c478bd9Sstevel@tonic-gate 		err = EFAULT;
3717c478bd9Sstevel@tonic-gate 	}
3727c478bd9Sstevel@tonic-gate 	i2c_transfer_free(unitp->hpc3130_hdl, i2c_tran_pointer);
3737c478bd9Sstevel@tonic-gate 	return (err);
3747c478bd9Sstevel@tonic-gate }
3757c478bd9Sstevel@tonic-gate 
3767c478bd9Sstevel@tonic-gate static int
hpc3130_set(intptr_t arg,int reg,hpc3130_unit_t * unitp,int mode)3777c478bd9Sstevel@tonic-gate hpc3130_set(intptr_t arg, int reg, hpc3130_unit_t *unitp, int mode)
3787c478bd9Sstevel@tonic-gate {
3797c478bd9Sstevel@tonic-gate 	i2c_transfer_t		*i2c_tran_pointer;
3807c478bd9Sstevel@tonic-gate 	int err = DDI_SUCCESS;
3817c478bd9Sstevel@tonic-gate 	uint8_t passin_byte;
3827c478bd9Sstevel@tonic-gate 
383*baa111a1SToomas Soome 	if (arg == (intptr_t)NULL) {
3847c478bd9Sstevel@tonic-gate 		D2CMN_ERR((CE_WARN, "ioctl: arg passed in to "
3857c478bd9Sstevel@tonic-gate 		    "ioctl = NULL"));
3867c478bd9Sstevel@tonic-gate 		return (EINVAL);
3877c478bd9Sstevel@tonic-gate 	}
3887c478bd9Sstevel@tonic-gate 	if (ddi_copyin((caddr_t)arg, (caddr_t)&passin_byte,
3897c478bd9Sstevel@tonic-gate 	    sizeof (uint8_t), mode) != DDI_SUCCESS) {
3907c478bd9Sstevel@tonic-gate 		D2CMN_ERR((CE_WARN, "Failed in HPC3130_SET_CONTROL "
3917c478bd9Sstevel@tonic-gate 		    "ddi_copyin routine"));
3927c478bd9Sstevel@tonic-gate 
3937c478bd9Sstevel@tonic-gate 		return (EFAULT);
3947c478bd9Sstevel@tonic-gate 	}
3957c478bd9Sstevel@tonic-gate 	(void) i2c_transfer_alloc(unitp->hpc3130_hdl, &i2c_tran_pointer,
3967c478bd9Sstevel@tonic-gate 	    2, 0, I2C_SLEEP);
3977c478bd9Sstevel@tonic-gate 	if (i2c_tran_pointer == NULL) {
3987c478bd9Sstevel@tonic-gate 		D2CMN_ERR((CE_WARN, "Failed in "
3997c478bd9Sstevel@tonic-gate 		    "HPC3130_SET_CONTROL i2c_tran_pointer not allocated"));
4007c478bd9Sstevel@tonic-gate 
4017c478bd9Sstevel@tonic-gate 		return (ENOMEM);
4027c478bd9Sstevel@tonic-gate 	}
4037c478bd9Sstevel@tonic-gate 
4047c478bd9Sstevel@tonic-gate 	i2c_tran_pointer->i2c_flags = I2C_WR;
4057c478bd9Sstevel@tonic-gate 	i2c_tran_pointer->i2c_wbuf[0] = (uchar_t)reg;
4067c478bd9Sstevel@tonic-gate 	i2c_tran_pointer->i2c_wbuf[1] = passin_byte;
4077c478bd9Sstevel@tonic-gate 
4087c478bd9Sstevel@tonic-gate 	err = i2c_transfer(unitp->hpc3130_hdl, i2c_tran_pointer);
4097c478bd9Sstevel@tonic-gate 	i2c_transfer_free(unitp->hpc3130_hdl, i2c_tran_pointer);
4107c478bd9Sstevel@tonic-gate 
4117c478bd9Sstevel@tonic-gate 	return (err);
4127c478bd9Sstevel@tonic-gate }
4137c478bd9Sstevel@tonic-gate 
4147c478bd9Sstevel@tonic-gate static int
hpc3130_ioctl(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * credp,int * rvalp)4157c478bd9Sstevel@tonic-gate hpc3130_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
4167c478bd9Sstevel@tonic-gate     int *rvalp)
4177c478bd9Sstevel@tonic-gate {
4187c478bd9Sstevel@tonic-gate 	_NOTE(ARGUNUSED(credp, rvalp))
4197c478bd9Sstevel@tonic-gate 	hpc3130_unit_t		*unitp;
4207c478bd9Sstevel@tonic-gate 	int			err = DDI_SUCCESS;
4217c478bd9Sstevel@tonic-gate 	i2c_transfer_t		*i2c_tran_pointer;
4227c478bd9Sstevel@tonic-gate 	i2c_reg_t		ioctl_reg;
4237c478bd9Sstevel@tonic-gate 	int port = MINOR_TO_PORT(getminor(dev));
4247c478bd9Sstevel@tonic-gate 	int instance = MINOR_TO_INST(getminor(dev));
4257c478bd9Sstevel@tonic-gate 	hpc3130_slot_table_entry_t *ste;
4267c478bd9Sstevel@tonic-gate 
4277c478bd9Sstevel@tonic-gate 	unitp = (hpc3130_unit_t *)
4287c478bd9Sstevel@tonic-gate 	    ddi_get_soft_state(hpc3130soft_statep, instance);
4297c478bd9Sstevel@tonic-gate 
4307c478bd9Sstevel@tonic-gate 	if (unitp == NULL) {
4317c478bd9Sstevel@tonic-gate 		D1CMN_ERR((CE_WARN, "unitp not filled"));
4327c478bd9Sstevel@tonic-gate 		return (ENOMEM);
4337c478bd9Sstevel@tonic-gate 	}
4347c478bd9Sstevel@tonic-gate 
4358e03c085Szk194757 	/*
4368e03c085Szk194757 	 * It should be the case that the port number is a valid
4378e03c085Szk194757 	 * index in the per instance slot table. If it is not
4388e03c085Szk194757 	 * then we should fail out.
4398e03c085Szk194757 	 */
4408e03c085Szk194757 	if (!(port >= 0 && port < unitp->hpc3130_slot_table_length)) {
4418e03c085Szk194757 		return (EINVAL);
4428e03c085Szk194757 	}
4438e03c085Szk194757 
4447c478bd9Sstevel@tonic-gate 	mutex_enter(&unitp->hpc3130_mutex);
4457c478bd9Sstevel@tonic-gate 
4467c478bd9Sstevel@tonic-gate 	ste = &unitp->hpc3130_slot_table[port];
4477c478bd9Sstevel@tonic-gate 
4487c478bd9Sstevel@tonic-gate 	D2CMN_ERR((CE_NOTE, "ioctl: port = %d  instance = %d",
4497c478bd9Sstevel@tonic-gate 	    port, instance));
4507c478bd9Sstevel@tonic-gate 
4517c478bd9Sstevel@tonic-gate 	switch (cmd) {
4527c478bd9Sstevel@tonic-gate 	case HPC3130_GET_STATUS:
4537c478bd9Sstevel@tonic-gate 		err = hpc3130_get(arg, HPC3130_HP_STATUS_REG(port), unitp,
4547c478bd9Sstevel@tonic-gate 		    mode);
4557c478bd9Sstevel@tonic-gate 		break;
4567c478bd9Sstevel@tonic-gate 
4577c478bd9Sstevel@tonic-gate 	case HPC3130_GET_CONTROL:
4587c478bd9Sstevel@tonic-gate 		err = hpc3130_get(arg, HPC3130_HP_CONTROL_REG(port), unitp,
4597c478bd9Sstevel@tonic-gate 		    mode);
4607c478bd9Sstevel@tonic-gate 		break;
4617c478bd9Sstevel@tonic-gate 
4627c478bd9Sstevel@tonic-gate 	case HPC3130_SET_CONTROL:
4637c478bd9Sstevel@tonic-gate 		if (control_slot_control == HPC3130_SLOT_CONTROL_DISABLE) {
4647c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN, "Cannot change control register.");
4657c478bd9Sstevel@tonic-gate 			err = EINVAL;
4667c478bd9Sstevel@tonic-gate 			break;
4677c478bd9Sstevel@tonic-gate 		}
4687c478bd9Sstevel@tonic-gate 		err = hpc3130_set(arg, HPC3130_HP_CONTROL_REG(port), unitp,
4697c478bd9Sstevel@tonic-gate 		    mode);
4707c478bd9Sstevel@tonic-gate 		break;
4717c478bd9Sstevel@tonic-gate 
4727c478bd9Sstevel@tonic-gate 	case HPC3130_GET_EVENT_STATUS:
4737c478bd9Sstevel@tonic-gate 		err = hpc3130_get(arg, HPC3130_INTERRUPT_STATUS_REG(port),
4747c478bd9Sstevel@tonic-gate 		    unitp, mode);
4757c478bd9Sstevel@tonic-gate 		break;
4767c478bd9Sstevel@tonic-gate 
4777c478bd9Sstevel@tonic-gate 	case HPC3130_SET_EVENT_STATUS:
4787c478bd9Sstevel@tonic-gate 		err = hpc3130_set(arg, HPC3130_INTERRUPT_STATUS_REG(port),
4797c478bd9Sstevel@tonic-gate 		    unitp, mode);
4807c478bd9Sstevel@tonic-gate 		break;
4817c478bd9Sstevel@tonic-gate 
4827c478bd9Sstevel@tonic-gate 	case HPC3130_GET_GENERAL_CONFIG:
4837c478bd9Sstevel@tonic-gate 		err = hpc3130_get(arg, HPC3130_GENERAL_CONFIG_REG(port),
4847c478bd9Sstevel@tonic-gate 		    unitp, mode);
4857c478bd9Sstevel@tonic-gate 		break;
4867c478bd9Sstevel@tonic-gate 
4877c478bd9Sstevel@tonic-gate 	case HPC3130_SET_GENERAL_CONFIG:
4887c478bd9Sstevel@tonic-gate 		err = hpc3130_set(arg, HPC3130_GENERAL_CONFIG_REG(port),
4897c478bd9Sstevel@tonic-gate 		    unitp, mode);
4907c478bd9Sstevel@tonic-gate 		break;
4917c478bd9Sstevel@tonic-gate 
4927c478bd9Sstevel@tonic-gate 	case HPC3130_GET_INDICATOR_CONTROL:
4937c478bd9Sstevel@tonic-gate 		err = hpc3130_get(arg, HPC3130_ATTENTION_INDICATOR(port),
4947c478bd9Sstevel@tonic-gate 		    unitp, mode);
4957c478bd9Sstevel@tonic-gate 		break;
4967c478bd9Sstevel@tonic-gate 
4977c478bd9Sstevel@tonic-gate 	case HPC3130_SET_INDICATOR_CONTROL:
4987c478bd9Sstevel@tonic-gate 		err = hpc3130_set(arg, HPC3130_ATTENTION_INDICATOR(port),
4997c478bd9Sstevel@tonic-gate 		    unitp, mode);
5007c478bd9Sstevel@tonic-gate 		break;
5017c478bd9Sstevel@tonic-gate 
5027c478bd9Sstevel@tonic-gate 	case HPC3130_GET_EVENT_ENABLE:
5037c478bd9Sstevel@tonic-gate 		err = hpc3130_get(arg, HPC3130_INTERRUPT_ENABLE_REG(port),
5047c478bd9Sstevel@tonic-gate 		    unitp, mode);
5057c478bd9Sstevel@tonic-gate 		break;
5067c478bd9Sstevel@tonic-gate 
5077c478bd9Sstevel@tonic-gate 	case HPC3130_SET_EVENT_ENABLE:
5087c478bd9Sstevel@tonic-gate 		err = hpc3130_set(arg, HPC3130_INTERRUPT_ENABLE_REG(port),
5097c478bd9Sstevel@tonic-gate 		    unitp, mode);
5107c478bd9Sstevel@tonic-gate 		break;
5117c478bd9Sstevel@tonic-gate 
5127c478bd9Sstevel@tonic-gate 	case HPC3130_ENABLE_SLOT_CONTROL:
5137c478bd9Sstevel@tonic-gate 		control_slot_control = HPC3130_SLOT_CONTROL_ENABLE;
5147c478bd9Sstevel@tonic-gate 		D2CMN_ERR((CE_NOTE, "Set the control_slot_control variable to"
5157c478bd9Sstevel@tonic-gate 		    "HPC3130_SLOT_CONTROL_ENABLE"));
5167c478bd9Sstevel@tonic-gate 		break;
5177c478bd9Sstevel@tonic-gate 
5187c478bd9Sstevel@tonic-gate 	case HPC3130_DISABLE_SLOT_CONTROL:
5197c478bd9Sstevel@tonic-gate 		control_slot_control = HPC3130_SLOT_CONTROL_DISABLE;
5207c478bd9Sstevel@tonic-gate 		D2CMN_ERR((CE_NOTE, "Set the control_slot_control variable to"
5217c478bd9Sstevel@tonic-gate 		    "HPC3130_SLOT_CONTROL_DISABLE"));
5227c478bd9Sstevel@tonic-gate 		break;
5237c478bd9Sstevel@tonic-gate 
5247c478bd9Sstevel@tonic-gate 	case I2C_GET_REG:
525*baa111a1SToomas Soome 		if (arg == (intptr_t)NULL) {
5267c478bd9Sstevel@tonic-gate 			D2CMN_ERR((CE_WARN, "ioctl: arg passed in to "
5277c478bd9Sstevel@tonic-gate 			    "ioctl = NULL"));
5287c478bd9Sstevel@tonic-gate 			err = EINVAL;
5297c478bd9Sstevel@tonic-gate 			break;
5307c478bd9Sstevel@tonic-gate 		}
5317c478bd9Sstevel@tonic-gate 		if (ddi_copyin((caddr_t)arg, (caddr_t)&ioctl_reg,
5327c478bd9Sstevel@tonic-gate 		    sizeof (i2c_reg_t), mode) != DDI_SUCCESS) {
5337c478bd9Sstevel@tonic-gate 			D2CMN_ERR((CE_WARN, "Failed in I2C_GET_REG "
5347c478bd9Sstevel@tonic-gate 			    "ddi_copyin routine"));
5357c478bd9Sstevel@tonic-gate 			err = EFAULT;
5367c478bd9Sstevel@tonic-gate 			break;
5377c478bd9Sstevel@tonic-gate 		}
5387c478bd9Sstevel@tonic-gate 		(void) i2c_transfer_alloc(unitp->hpc3130_hdl, &i2c_tran_pointer,
5397c478bd9Sstevel@tonic-gate 		    1, 1, I2C_SLEEP);
5407c478bd9Sstevel@tonic-gate 		if (i2c_tran_pointer == NULL) {
5417c478bd9Sstevel@tonic-gate 			D2CMN_ERR((CE_WARN, "Failed in I2C_GET_REG "
5427c478bd9Sstevel@tonic-gate 			    "i2c_tran_pointer not allocated"));
5437c478bd9Sstevel@tonic-gate 			err = ENOMEM;
5447c478bd9Sstevel@tonic-gate 			break;
5457c478bd9Sstevel@tonic-gate 		}
5467c478bd9Sstevel@tonic-gate 
5477c478bd9Sstevel@tonic-gate 		i2c_tran_pointer->i2c_flags = I2C_WR_RD;
5487c478bd9Sstevel@tonic-gate 		i2c_tran_pointer->i2c_wbuf[0] = ioctl_reg.reg_num;
5497c478bd9Sstevel@tonic-gate 
5507c478bd9Sstevel@tonic-gate 		err = i2c_transfer(unitp->hpc3130_hdl, i2c_tran_pointer);
5517c478bd9Sstevel@tonic-gate 		if (err) {
5527c478bd9Sstevel@tonic-gate 			D2CMN_ERR((CE_WARN, "Failed in I2C_GET_REG "
5537c478bd9Sstevel@tonic-gate 			    "i2c_transfer routine"));
5547c478bd9Sstevel@tonic-gate 			i2c_transfer_free(unitp->hpc3130_hdl, i2c_tran_pointer);
5557c478bd9Sstevel@tonic-gate 			break;
5567c478bd9Sstevel@tonic-gate 		}
5577c478bd9Sstevel@tonic-gate 		ioctl_reg.reg_value = i2c_tran_pointer->i2c_rbuf[0];
5587c478bd9Sstevel@tonic-gate 		if (ddi_copyout((caddr_t)&ioctl_reg, (caddr_t)arg,
5597c478bd9Sstevel@tonic-gate 		    sizeof (i2c_reg_t), mode) != DDI_SUCCESS) {
5607c478bd9Sstevel@tonic-gate 			D2CMN_ERR((CE_WARN, "Failed in I2C_GET_REG "
5617c478bd9Sstevel@tonic-gate 			    "ddi_copyout routine"));
5627c478bd9Sstevel@tonic-gate 			err = EFAULT;
5637c478bd9Sstevel@tonic-gate 		}
5647c478bd9Sstevel@tonic-gate 
5657c478bd9Sstevel@tonic-gate 		i2c_transfer_free(unitp->hpc3130_hdl, i2c_tran_pointer);
5667c478bd9Sstevel@tonic-gate 		break;
5677c478bd9Sstevel@tonic-gate 
5687c478bd9Sstevel@tonic-gate 	case I2C_SET_REG:
569*baa111a1SToomas Soome 		if (arg == (intptr_t)NULL) {
5707c478bd9Sstevel@tonic-gate 			D2CMN_ERR((CE_WARN, "ioctl: arg passed in to "
5717c478bd9Sstevel@tonic-gate 			    "ioctl = NULL"));
5727c478bd9Sstevel@tonic-gate 			err = EINVAL;
5737c478bd9Sstevel@tonic-gate 			break;
5747c478bd9Sstevel@tonic-gate 		}
5757c478bd9Sstevel@tonic-gate 		if (ddi_copyin((caddr_t)arg, (caddr_t)&ioctl_reg,
5767c478bd9Sstevel@tonic-gate 		    sizeof (i2c_reg_t), mode) != DDI_SUCCESS) {
5777c478bd9Sstevel@tonic-gate 			D2CMN_ERR((CE_WARN, "Failed in I2C_SET_REG "
5787c478bd9Sstevel@tonic-gate 			    "ddi_copyin routine"));
5797c478bd9Sstevel@tonic-gate 			err = EFAULT;
5807c478bd9Sstevel@tonic-gate 			break;
5817c478bd9Sstevel@tonic-gate 		}
5827c478bd9Sstevel@tonic-gate 		(void) i2c_transfer_alloc(unitp->hpc3130_hdl, &i2c_tran_pointer,
5837c478bd9Sstevel@tonic-gate 		    2, 0, I2C_SLEEP);
5847c478bd9Sstevel@tonic-gate 		if (i2c_tran_pointer == NULL) {
5857c478bd9Sstevel@tonic-gate 			D2CMN_ERR((CE_WARN, "Failed in I2C_GET_REG "
5867c478bd9Sstevel@tonic-gate 			    "i2c_tran_pointer not allocated"));
5877c478bd9Sstevel@tonic-gate 			err = ENOMEM;
5887c478bd9Sstevel@tonic-gate 			break;
5897c478bd9Sstevel@tonic-gate 		}
5907c478bd9Sstevel@tonic-gate 
5917c478bd9Sstevel@tonic-gate 		i2c_tran_pointer->i2c_flags = I2C_WR;
5927c478bd9Sstevel@tonic-gate 		i2c_tran_pointer->i2c_wbuf[0] = ioctl_reg.reg_num;
5937c478bd9Sstevel@tonic-gate 		i2c_tran_pointer->i2c_wbuf[1] = (uchar_t)ioctl_reg.reg_value;
5947c478bd9Sstevel@tonic-gate 
5957c478bd9Sstevel@tonic-gate 		err = i2c_transfer(unitp->hpc3130_hdl, i2c_tran_pointer);
5967c478bd9Sstevel@tonic-gate 		if (err) {
5977c478bd9Sstevel@tonic-gate 			D2CMN_ERR((CE_WARN, "Failed in I2C_SET_REG "
5987c478bd9Sstevel@tonic-gate 			    "i2c_transfer routine"));
5997c478bd9Sstevel@tonic-gate 			i2c_transfer_free(unitp->hpc3130_hdl, i2c_tran_pointer);
6007c478bd9Sstevel@tonic-gate 			break;
6017c478bd9Sstevel@tonic-gate 		}
6027c478bd9Sstevel@tonic-gate 
6037c478bd9Sstevel@tonic-gate 		i2c_transfer_free(unitp->hpc3130_hdl, i2c_tran_pointer);
6047c478bd9Sstevel@tonic-gate 		break;
6057c478bd9Sstevel@tonic-gate 
6067c478bd9Sstevel@tonic-gate 	case HPC3130_GET_EVENT: {
6077c478bd9Sstevel@tonic-gate 		struct hpc3130_event ev;
6087c478bd9Sstevel@tonic-gate 
6097c478bd9Sstevel@tonic-gate 		bzero(&ev, sizeof (struct hpc3130_event));
6107c478bd9Sstevel@tonic-gate 
6117c478bd9Sstevel@tonic-gate 		if (unitp->slots_are == HPC3130_SLOT_TYPE_SBD) {
6127c478bd9Sstevel@tonic-gate 			DAK_GET_SBD_APID(ev.name, sizeof (ev.name), port);
6137c478bd9Sstevel@tonic-gate 		} else {
61407d06da5SSurya Prakki 			(void) snprintf(ev.name, HPC3130_NAME_MAX,
6157c478bd9Sstevel@tonic-gate 			    "/devices%s:", ste->nexus);
6167c478bd9Sstevel@tonic-gate 			ASSERT(strlen(ev.name) < HPC3130_NAME_MAX - 1);
6177c478bd9Sstevel@tonic-gate 			DAK_GET_PCI_APID(ev.name + strlen(ev.name),
6187c478bd9Sstevel@tonic-gate 			    HPC3130_NAME_MAX - strlen(ev.name),
6197c478bd9Sstevel@tonic-gate 			    hpc3130_lookup_slot(ste->nexus,
6207c478bd9Sstevel@tonic-gate 			    ste->hpc3130_slot_info.pci_dev_num));
6217c478bd9Sstevel@tonic-gate 		}
6227c478bd9Sstevel@tonic-gate 
6237c478bd9Sstevel@tonic-gate 		if (unitp->events[port] & HPC3130_IEVENT_OCCUPANCY) {
6247c478bd9Sstevel@tonic-gate 			unitp->events[port] &= ~HPC3130_IEVENT_OCCUPANCY;
6257c478bd9Sstevel@tonic-gate 			ev.id = (unitp->present[port] == B_FALSE ?
6267c478bd9Sstevel@tonic-gate 			    HPC3130_EVENT_REMOVAL :
6277c478bd9Sstevel@tonic-gate 			    HPC3130_EVENT_INSERTION);
6287c478bd9Sstevel@tonic-gate 		} else if (unitp->events[port] & HPC3130_IEVENT_POWER) {
6297c478bd9Sstevel@tonic-gate 			unitp->events[port] &= ~HPC3130_IEVENT_POWER;
6307c478bd9Sstevel@tonic-gate 			ev.id = (unitp->power[port] == B_TRUE ?
6317c478bd9Sstevel@tonic-gate 			    HPC3130_EVENT_POWERON :
6327c478bd9Sstevel@tonic-gate 			    HPC3130_EVENT_POWEROFF);
6337c478bd9Sstevel@tonic-gate 		} else if (unitp->events[port] & HPC3130_IEVENT_BUTTON) {
6347c478bd9Sstevel@tonic-gate 			unitp->events[port] &= ~HPC3130_IEVENT_BUTTON;
6357c478bd9Sstevel@tonic-gate 			ev.id = HPC3130_EVENT_BUTTON;
6367c478bd9Sstevel@tonic-gate 		} else if (unitp->events[port] & HPC3130_IEVENT_FAULT) {
6377c478bd9Sstevel@tonic-gate 			unitp->events[port] &= ~HPC3130_IEVENT_FAULT;
6387c478bd9Sstevel@tonic-gate 			ev.id = (unitp->fault_led[port] == HPC3130_ATTN_ON ?
6397c478bd9Sstevel@tonic-gate 			    HPC3130_LED_FAULT_ON :
6407c478bd9Sstevel@tonic-gate 			    HPC3130_LED_FAULT_OFF);
6417c478bd9Sstevel@tonic-gate 		} else if (unitp->events[port] & HPC3130_IEVENT_OK2REM) {
6427c478bd9Sstevel@tonic-gate 			unitp->events[port] &= ~HPC3130_IEVENT_OK2REM;
6437c478bd9Sstevel@tonic-gate 			ev.id = (unitp->ok2rem_led[port] == HPC3130_ATTN_ON ?
6447c478bd9Sstevel@tonic-gate 			    HPC3130_LED_REMOVABLE_ON :
6457c478bd9Sstevel@tonic-gate 			    HPC3130_LED_REMOVABLE_OFF);
6467c478bd9Sstevel@tonic-gate 		}
6477c478bd9Sstevel@tonic-gate 
6487c478bd9Sstevel@tonic-gate 		D1CMN_ERR((CE_NOTE,
6497c478bd9Sstevel@tonic-gate 		    "sending EVENT: ap_id=%s, event=%d", ev.name, ev.id));
6507c478bd9Sstevel@tonic-gate 
6517c478bd9Sstevel@tonic-gate 		if (ddi_copyout((caddr_t)&ev, (caddr_t)arg,
6527c478bd9Sstevel@tonic-gate 			sizeof (struct hpc3130_event), mode) != DDI_SUCCESS) {
6537c478bd9Sstevel@tonic-gate 			D1CMN_ERR((CE_WARN, "Failed in hpc3130_ioctl"
6547c478bd9Sstevel@tonic-gate 			    " ddi_copyout routine"));
6557c478bd9Sstevel@tonic-gate 			err = EFAULT;
6567c478bd9Sstevel@tonic-gate 		}
6577c478bd9Sstevel@tonic-gate 		break;
6587c478bd9Sstevel@tonic-gate 	}
6597c478bd9Sstevel@tonic-gate 	case HPC3130_CONF_DR: {
6607c478bd9Sstevel@tonic-gate 		uint8_t offset;
6617c478bd9Sstevel@tonic-gate 		int dr_conf;
6627c478bd9Sstevel@tonic-gate 
6637c478bd9Sstevel@tonic-gate 		if (ddi_copyin((caddr_t)arg, (caddr_t)&dr_conf,
6647c478bd9Sstevel@tonic-gate 		    sizeof (int), mode) != DDI_SUCCESS) {
6657c478bd9Sstevel@tonic-gate 			D2CMN_ERR((CE_WARN, "Failed in HPC3130_CONF_DR "
6667c478bd9Sstevel@tonic-gate 			    "ddi_copyin routine"))
6677c478bd9Sstevel@tonic-gate 			err = EFAULT;
6687c478bd9Sstevel@tonic-gate 			break;
6697c478bd9Sstevel@tonic-gate 		}
6707c478bd9Sstevel@tonic-gate 
6717c478bd9Sstevel@tonic-gate 		offset = ste->callback_info.offset;
6727c478bd9Sstevel@tonic-gate 
6737c478bd9Sstevel@tonic-gate 		unitp->enabled[offset] =
6747c478bd9Sstevel@tonic-gate 		    (dr_conf == HPC3130_DR_DISABLE ? B_FALSE : B_TRUE);
6757c478bd9Sstevel@tonic-gate 
6767c478bd9Sstevel@tonic-gate 		break;
6777c478bd9Sstevel@tonic-gate 	}
6787c478bd9Sstevel@tonic-gate 	default:
6797c478bd9Sstevel@tonic-gate 		D2CMN_ERR((CE_WARN, "Invalid IOCTL cmd: %x", cmd));
6807c478bd9Sstevel@tonic-gate 		err = EINVAL;
6817c478bd9Sstevel@tonic-gate 	}
6827c478bd9Sstevel@tonic-gate 
6837c478bd9Sstevel@tonic-gate 	mutex_exit(&unitp->hpc3130_mutex);
6847c478bd9Sstevel@tonic-gate 	return (err);
6857c478bd9Sstevel@tonic-gate }
6867c478bd9Sstevel@tonic-gate 
6877c478bd9Sstevel@tonic-gate static int
hpc3130_poll(dev_t dev,short events,int anyyet,short * reventsp,struct pollhead ** phpp)688*baa111a1SToomas Soome hpc3130_poll(dev_t dev, short events, int anyyet, short *reventsp,
689*baa111a1SToomas Soome     struct pollhead **phpp)
6907c478bd9Sstevel@tonic-gate {
6917c478bd9Sstevel@tonic-gate 	_NOTE(ARGUNUSED(events))
6927c478bd9Sstevel@tonic-gate 	hpc3130_unit_t *unitp;
6937c478bd9Sstevel@tonic-gate 	int port = MINOR_TO_PORT(getminor(dev));
6947c478bd9Sstevel@tonic-gate 	int instance = MINOR_TO_INST(getminor(dev));
6957c478bd9Sstevel@tonic-gate 
6967c478bd9Sstevel@tonic-gate 	if (!(port >= 0 && port < HPC3130_MAX_SLOT)) {
6977c478bd9Sstevel@tonic-gate 		return (EINVAL);
6987c478bd9Sstevel@tonic-gate 	}
6997c478bd9Sstevel@tonic-gate 	unitp = (hpc3130_unit_t *)
7007c478bd9Sstevel@tonic-gate 	    ddi_get_soft_state(hpc3130soft_statep, instance);
7017c478bd9Sstevel@tonic-gate 
7027c478bd9Sstevel@tonic-gate 	mutex_enter(&unitp->hpc3130_mutex);
7037c478bd9Sstevel@tonic-gate 	if (unitp->events[port]) {
7047c478bd9Sstevel@tonic-gate 		*reventsp = POLLIN;
7057c478bd9Sstevel@tonic-gate 	} else {
7067c478bd9Sstevel@tonic-gate 		*reventsp = 0;
7077c478bd9Sstevel@tonic-gate 		if (!anyyet)
7087c478bd9Sstevel@tonic-gate 			*phpp = &unitp->pollhead[port];
7097c478bd9Sstevel@tonic-gate 	}
7107c478bd9Sstevel@tonic-gate 	mutex_exit(&unitp->hpc3130_mutex);
7117c478bd9Sstevel@tonic-gate 	return (0);
7127c478bd9Sstevel@tonic-gate }
7137c478bd9Sstevel@tonic-gate 
7147c478bd9Sstevel@tonic-gate /* ARGSUSED */
7157c478bd9Sstevel@tonic-gate static int
hpc3130_info(dev_info_t * dip,ddi_info_cmd_t infocmd,void * arg,void ** result)7167c478bd9Sstevel@tonic-gate hpc3130_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
7177c478bd9Sstevel@tonic-gate {
7187c478bd9Sstevel@tonic-gate 	dev_t	dev;
7197c478bd9Sstevel@tonic-gate 	int	instance;
7207c478bd9Sstevel@tonic-gate 
7217c478bd9Sstevel@tonic-gate 	if (infocmd == DDI_INFO_DEVT2INSTANCE) {
7227c478bd9Sstevel@tonic-gate 		dev = (dev_t)arg;
7237c478bd9Sstevel@tonic-gate 		instance = MINOR_TO_INST(getminor(dev));
7247c478bd9Sstevel@tonic-gate 		*result = (void *)(uintptr_t)instance;
7257c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
7267c478bd9Sstevel@tonic-gate 	}
7277c478bd9Sstevel@tonic-gate 	return (DDI_FAILURE);
7287c478bd9Sstevel@tonic-gate }
7297c478bd9Sstevel@tonic-gate 
7307c478bd9Sstevel@tonic-gate static int
hpc3130_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)7317c478bd9Sstevel@tonic-gate hpc3130_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
7327c478bd9Sstevel@tonic-gate {
7337c478bd9Sstevel@tonic-gate 	switch (cmd) {
7347c478bd9Sstevel@tonic-gate 	case DDI_ATTACH:
7357c478bd9Sstevel@tonic-gate 		return (hpc3130_do_attach(dip));
7367c478bd9Sstevel@tonic-gate 	case DDI_RESUME:
7377c478bd9Sstevel@tonic-gate 		return (hpc3130_do_resume());
7387c478bd9Sstevel@tonic-gate 	default:
7397c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
7407c478bd9Sstevel@tonic-gate 	}
7417c478bd9Sstevel@tonic-gate }
7427c478bd9Sstevel@tonic-gate 
7437c478bd9Sstevel@tonic-gate static int
hpc3130_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)7447c478bd9Sstevel@tonic-gate hpc3130_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
7457c478bd9Sstevel@tonic-gate {
7467c478bd9Sstevel@tonic-gate 	switch (cmd) {
7477c478bd9Sstevel@tonic-gate 	case DDI_DETACH:
7487c478bd9Sstevel@tonic-gate 		return (hpc3130_do_detach(dip));
7497c478bd9Sstevel@tonic-gate 	case DDI_SUSPEND:
7507c478bd9Sstevel@tonic-gate 		return (hpc3130_do_suspend());
7517c478bd9Sstevel@tonic-gate 	default:
7527c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
7537c478bd9Sstevel@tonic-gate 	}
7547c478bd9Sstevel@tonic-gate }
7557c478bd9Sstevel@tonic-gate 
7567c478bd9Sstevel@tonic-gate static int
hpc3130_do_attach(dev_info_t * dip)7577c478bd9Sstevel@tonic-gate hpc3130_do_attach(dev_info_t *dip)
7587c478bd9Sstevel@tonic-gate {
7597c478bd9Sstevel@tonic-gate 	hpc3130_unit_t	*hpc3130_p;
7607c478bd9Sstevel@tonic-gate 	char		*s;
7617c478bd9Sstevel@tonic-gate 	char		*nexus;
7627c478bd9Sstevel@tonic-gate 	char		*pcidev;
7637c478bd9Sstevel@tonic-gate 	char		*reg_offset;
7647c478bd9Sstevel@tonic-gate 	int		r, i, n, j;
7657c478bd9Sstevel@tonic-gate 	char		name[MAXNAMELEN];
7667c478bd9Sstevel@tonic-gate 	minor_t		minor_number;
7677c478bd9Sstevel@tonic-gate 	int		hpc3130_pil = HPC3130_PIL;
7687c478bd9Sstevel@tonic-gate 	int		instance = ddi_get_instance(dip);
7697c478bd9Sstevel@tonic-gate 
7707c478bd9Sstevel@tonic-gate 	/*
7717c478bd9Sstevel@tonic-gate 	 * Allocate the soft state structure for this instance.
7727c478bd9Sstevel@tonic-gate 	 */
7737c478bd9Sstevel@tonic-gate 	r = ddi_soft_state_zalloc(hpc3130soft_statep, instance);
7747c478bd9Sstevel@tonic-gate 	if (r != DDI_SUCCESS) {
7757c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
7767c478bd9Sstevel@tonic-gate 	}
7777c478bd9Sstevel@tonic-gate 
7787c478bd9Sstevel@tonic-gate 	hpc3130_p =
7797c478bd9Sstevel@tonic-gate 	    (hpc3130_unit_t *)ddi_get_soft_state(hpc3130soft_statep, instance);
7807c478bd9Sstevel@tonic-gate 	ASSERT(hpc3130_p);
7817c478bd9Sstevel@tonic-gate 
7827c478bd9Sstevel@tonic-gate 	if (ddi_prop_create(DDI_DEV_T_NONE, dip, DDI_PROP_CANSLEEP,
7837c478bd9Sstevel@tonic-gate 	    "interrupt-priorities", (caddr_t)&hpc3130_pil,
7847c478bd9Sstevel@tonic-gate 	    sizeof (hpc3130_pil)) != DDI_PROP_SUCCESS) {
7857c478bd9Sstevel@tonic-gate 		goto failout0;
7867c478bd9Sstevel@tonic-gate 	}
7877c478bd9Sstevel@tonic-gate 
7887c478bd9Sstevel@tonic-gate 	if (ddi_intr_hilevel(dip, 0)) {
7897c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "High level interrupt not supported");
7907c478bd9Sstevel@tonic-gate 		goto failout0;
7917c478bd9Sstevel@tonic-gate 	}
7927c478bd9Sstevel@tonic-gate 
7937c478bd9Sstevel@tonic-gate 	/*
7947c478bd9Sstevel@tonic-gate 	 * Get the "slot-table" property which defines the list of
7957c478bd9Sstevel@tonic-gate 	 * hot-pluggable slots for this controller along with the
7967c478bd9Sstevel@tonic-gate 	 * corresponding bus nexus node and device identification
7977c478bd9Sstevel@tonic-gate 	 * for each slot.
7987c478bd9Sstevel@tonic-gate 	 */
7997c478bd9Sstevel@tonic-gate 	r = ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
8007c478bd9Sstevel@tonic-gate 	    "slot-table", (caddr_t)&hpc3130_p->hpc3130_slot_table_data,
8017c478bd9Sstevel@tonic-gate 	    &hpc3130_p->hpc3130_slot_table_size);
8027c478bd9Sstevel@tonic-gate 
8037c478bd9Sstevel@tonic-gate 	switch (r) {
8047c478bd9Sstevel@tonic-gate 	case DDI_PROP_SUCCESS:
8057c478bd9Sstevel@tonic-gate 		break;
8067c478bd9Sstevel@tonic-gate 	case DDI_PROP_NOT_FOUND:
8077c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN,
8087c478bd9Sstevel@tonic-gate 		    "couldn't find slot-table property");
8097c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
8107c478bd9Sstevel@tonic-gate 	case DDI_PROP_UNDEFINED:
8117c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN,
8127c478bd9Sstevel@tonic-gate 		    "slot-table undefined");
8137c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
8147c478bd9Sstevel@tonic-gate 	case DDI_PROP_NO_MEMORY:
8157c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN,
8167c478bd9Sstevel@tonic-gate 		    "can't allocate memory for slot-table");
8177c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
8187c478bd9Sstevel@tonic-gate 	}
8197c478bd9Sstevel@tonic-gate 
8207c478bd9Sstevel@tonic-gate 	/*
8217c478bd9Sstevel@tonic-gate 	 * Determine the size of the slot table from the OBP property and
8227c478bd9Sstevel@tonic-gate 	 * allocate the slot table arrary..
8237c478bd9Sstevel@tonic-gate 	 */
8247c478bd9Sstevel@tonic-gate 	for (i = 0, n = 0; i < hpc3130_p->hpc3130_slot_table_size; i++) {
8257c478bd9Sstevel@tonic-gate 		if (hpc3130_p->hpc3130_slot_table_data[i] == 0) {
8267c478bd9Sstevel@tonic-gate 			n++;
8277c478bd9Sstevel@tonic-gate 		}
8287c478bd9Sstevel@tonic-gate 	}
8297c478bd9Sstevel@tonic-gate 
8307c478bd9Sstevel@tonic-gate 	D1CMN_ERR((CE_NOTE, "hpc3130_attach(): slot table has %d entries", n));
8317c478bd9Sstevel@tonic-gate 
8327c478bd9Sstevel@tonic-gate 	/*
8337c478bd9Sstevel@tonic-gate 	 * There should be HPC3130_TABLE_COLUMNS elements per entry
8347c478bd9Sstevel@tonic-gate 	 */
8357c478bd9Sstevel@tonic-gate 	if (n % HPC3130_TABLE_COLUMNS) {
8367c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "bad format in slot-table");
8377c478bd9Sstevel@tonic-gate 		goto failout1;
8387c478bd9Sstevel@tonic-gate 	}
8397c478bd9Sstevel@tonic-gate 
8407c478bd9Sstevel@tonic-gate 	hpc3130_p->dip = dip;
8417c478bd9Sstevel@tonic-gate 	hpc3130_p->hpc3130_slot_table_length = n / HPC3130_TABLE_COLUMNS;
8427c478bd9Sstevel@tonic-gate 
8437c478bd9Sstevel@tonic-gate 	if (ddi_get_iblock_cookie(dip, 0, &hpc3130_p->ic_trap_cookie) !=
8447c478bd9Sstevel@tonic-gate 	    DDI_SUCCESS)  {
8457c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "ddi_get_iblock_cookie FAILED");
8467c478bd9Sstevel@tonic-gate 		goto failout1;
8477c478bd9Sstevel@tonic-gate 	}
8487c478bd9Sstevel@tonic-gate 
8497c478bd9Sstevel@tonic-gate 	mutex_init(&hpc3130_p->hpc3130_mutex, NULL, MUTEX_DRIVER,
8507c478bd9Sstevel@tonic-gate 	    (void *)hpc3130_p->ic_trap_cookie);
8517c478bd9Sstevel@tonic-gate 	/*
8527c478bd9Sstevel@tonic-gate 	 * Create enough space for each slot table entry
8537c478bd9Sstevel@tonic-gate 	 * based on how many entries in the property
8547c478bd9Sstevel@tonic-gate 	 */
8557c478bd9Sstevel@tonic-gate 	hpc3130_p->hpc3130_slot_table = (hpc3130_slot_table_entry_t *)
8567c478bd9Sstevel@tonic-gate 	    kmem_zalloc(hpc3130_p->hpc3130_slot_table_length *
8577c478bd9Sstevel@tonic-gate 	    sizeof (hpc3130_slot_table_entry_t), KM_SLEEP);
8587c478bd9Sstevel@tonic-gate 
8597c478bd9Sstevel@tonic-gate 	/*
8607c478bd9Sstevel@tonic-gate 	 * Setup to talk to the i2c nexus
8617c478bd9Sstevel@tonic-gate 	 */
8627c478bd9Sstevel@tonic-gate 	if (i2c_client_register(dip, &hpc3130_p->hpc3130_hdl) != I2C_SUCCESS) {
8637c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "failed to register as i2c client");
8647c478bd9Sstevel@tonic-gate 		goto failout2;
8657c478bd9Sstevel@tonic-gate 	}
8667c478bd9Sstevel@tonic-gate 
8677c478bd9Sstevel@tonic-gate 	s = hpc3130_p->hpc3130_slot_table_data;
8687c478bd9Sstevel@tonic-gate 	for (i = 0; i < hpc3130_p->hpc3130_slot_table_length; i++) {
8697c478bd9Sstevel@tonic-gate 		hpc3130_slot_table_entry_t *ste;
8707c478bd9Sstevel@tonic-gate 
8717c478bd9Sstevel@tonic-gate 		/* Pick off pointer to nexus path */
8727c478bd9Sstevel@tonic-gate 		nexus = s;
8737c478bd9Sstevel@tonic-gate 		s = s + strlen(s) + 1;
8747c478bd9Sstevel@tonic-gate 
8757c478bd9Sstevel@tonic-gate 		/* Pick off pointer to 3130 register offset */
8767c478bd9Sstevel@tonic-gate 		reg_offset = s;
8777c478bd9Sstevel@tonic-gate 		s = s + strlen(s) + 1;
8787c478bd9Sstevel@tonic-gate 
8797c478bd9Sstevel@tonic-gate 		/* Pick off pointer to the device number */
8807c478bd9Sstevel@tonic-gate 		pcidev = s;
8817c478bd9Sstevel@tonic-gate 
8827c478bd9Sstevel@tonic-gate 		s = s + strlen(s) + 1;
8837c478bd9Sstevel@tonic-gate 
8847c478bd9Sstevel@tonic-gate 		j = hpc3130_atoi(reg_offset);
8857c478bd9Sstevel@tonic-gate 
8867c478bd9Sstevel@tonic-gate 		if (j < 0 || j >= HPC3130_MAX_SLOT) {
8877c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN,
8887c478bd9Sstevel@tonic-gate 			    "invalid register offset value");
8897c478bd9Sstevel@tonic-gate 			goto failout3;
8907c478bd9Sstevel@tonic-gate 		}
8917c478bd9Sstevel@tonic-gate 
8927c478bd9Sstevel@tonic-gate 		ste = &hpc3130_p->hpc3130_slot_table[j];
8937c478bd9Sstevel@tonic-gate 
89407d06da5SSurya Prakki 		(void) strcpy(ste->nexus, nexus);
8957c478bd9Sstevel@tonic-gate 
8967c478bd9Sstevel@tonic-gate 		if (strncmp(ste->nexus, "/pci", 4) == 0) {
8977c478bd9Sstevel@tonic-gate 
8987c478bd9Sstevel@tonic-gate 			ste->hpc3130_slot_info.pci_dev_num =
8997c478bd9Sstevel@tonic-gate 			    hpc3130_atoi(pcidev);
9007c478bd9Sstevel@tonic-gate 
9017c478bd9Sstevel@tonic-gate 			DAK_GET_PCI_APID(ste->hpc3130_slot_info.pci_slot_name,
9027c478bd9Sstevel@tonic-gate 			    PCI_SLOT_NAME_LEN,
9037c478bd9Sstevel@tonic-gate 			    hpc3130_lookup_slot(ste->nexus,
9047c478bd9Sstevel@tonic-gate 			    hpc3130_atoi(pcidev)));
9057c478bd9Sstevel@tonic-gate 
9067c478bd9Sstevel@tonic-gate 			ste->hpc3130_slot_info.slot_type = HPC_SLOT_TYPE_PCI;
9077c478bd9Sstevel@tonic-gate 			ste->hpc3130_slot_info.slot_flags =
9087c478bd9Sstevel@tonic-gate 			    HPC_SLOT_CREATE_DEVLINK;
9097c478bd9Sstevel@tonic-gate 			hpc3130_p->slots_are = HPC3130_SLOT_TYPE_PCI;
9107c478bd9Sstevel@tonic-gate 
9117c478bd9Sstevel@tonic-gate 		} else {
9127c478bd9Sstevel@tonic-gate 
9137c478bd9Sstevel@tonic-gate 			ste->hpc3130_slot_info.sbd_slot_num =
9147c478bd9Sstevel@tonic-gate 			    hpc3130_atoi(reg_offset);
9157c478bd9Sstevel@tonic-gate 
9167c478bd9Sstevel@tonic-gate 			ste->hpc3130_slot_info.slot_type = HPC_SLOT_TYPE_SBD;
9177c478bd9Sstevel@tonic-gate 
9187c478bd9Sstevel@tonic-gate 			hpc3130_p->slots_are = HPC3130_SLOT_TYPE_SBD;
9197c478bd9Sstevel@tonic-gate 		}
9207c478bd9Sstevel@tonic-gate 
9217c478bd9Sstevel@tonic-gate 		hpc3130_p->present[j] = B_FALSE;
9227c478bd9Sstevel@tonic-gate 		hpc3130_p->enabled[j] = B_TRUE;
9237c478bd9Sstevel@tonic-gate 
9247c478bd9Sstevel@tonic-gate 		/*
9257c478bd9Sstevel@tonic-gate 		 * The "callback_info" structure of the slot_table is what gets
9267c478bd9Sstevel@tonic-gate 		 * passed back in the callback routines.  All that is needed
9277c478bd9Sstevel@tonic-gate 		 * at that point is the device handle  and the register offset
9287c478bd9Sstevel@tonic-gate 		 * within it the chip it represents.
9297c478bd9Sstevel@tonic-gate 		 */
9307c478bd9Sstevel@tonic-gate 		ste->callback_info.handle = (caddr_t)hpc3130_p->hpc3130_hdl;
9317c478bd9Sstevel@tonic-gate 
9327c478bd9Sstevel@tonic-gate 		ste->callback_info.offset = hpc3130_atoi(reg_offset);
9337c478bd9Sstevel@tonic-gate 
9347c478bd9Sstevel@tonic-gate 		ste->callback_info.statep = (caddr_t)hpc3130_p;
9357c478bd9Sstevel@tonic-gate 	}
9367c478bd9Sstevel@tonic-gate 
9377c478bd9Sstevel@tonic-gate 	hpc3130_p->hpc3130_slot_ops = hpc_alloc_slot_ops(KM_SLEEP);
9387c478bd9Sstevel@tonic-gate 	hpc3130_p->hpc3130_slot_ops->hpc_version = 0;
9397c478bd9Sstevel@tonic-gate 
9407c478bd9Sstevel@tonic-gate 	hpc3130_p->hpc3130_slot_ops->hpc_op_connect = hpc3130_slot_connect;
9417c478bd9Sstevel@tonic-gate 	hpc3130_p->hpc3130_slot_ops->hpc_op_disconnect =
9427c478bd9Sstevel@tonic-gate 	    hpc3130_slot_disconnect;
9437c478bd9Sstevel@tonic-gate 	hpc3130_p->hpc3130_slot_ops->hpc_op_insert = hpc3130_slot_insert;
9447c478bd9Sstevel@tonic-gate 	hpc3130_p->hpc3130_slot_ops->hpc_op_remove = hpc3130_slot_remove;
9457c478bd9Sstevel@tonic-gate 	hpc3130_p->hpc3130_slot_ops->hpc_op_control = hpc3130_slot_control;
9467c478bd9Sstevel@tonic-gate 
9477c478bd9Sstevel@tonic-gate 	cv_init(&hpc3130_p->hpc3130_cond, NULL, CV_DEFAULT, NULL);
9487c478bd9Sstevel@tonic-gate 
9497c478bd9Sstevel@tonic-gate 	if (hpc3130_init(dip, (hpc3130_p->slots_are == HPC3130_SLOT_TYPE_SBD) ?
9507c478bd9Sstevel@tonic-gate 	    cpu_sequence : pci_sequence) != DDI_SUCCESS) {
9517c478bd9Sstevel@tonic-gate 			goto failout4;
9527c478bd9Sstevel@tonic-gate 	}
9537c478bd9Sstevel@tonic-gate 
9547c478bd9Sstevel@tonic-gate 	if (ddi_add_intr(dip, 0, &hpc3130_p->ic_trap_cookie,
9557c478bd9Sstevel@tonic-gate 	    NULL, hpc3130_hard_intr,
9567c478bd9Sstevel@tonic-gate 	    (caddr_t)hpc3130_p) != DDI_SUCCESS) {
9577c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "failed to add interrupt");
9587c478bd9Sstevel@tonic-gate 		goto failout4;
9597c478bd9Sstevel@tonic-gate 	}
9607c478bd9Sstevel@tonic-gate 
9617c478bd9Sstevel@tonic-gate 	/*
9627c478bd9Sstevel@tonic-gate 	 * Register with the "services" module
9637c478bd9Sstevel@tonic-gate 	 */
9647c478bd9Sstevel@tonic-gate 	for (i = 0; i < hpc3130_p->hpc3130_slot_table_length; i++) {
9657c478bd9Sstevel@tonic-gate 		hpc3130_slot_table_entry_t *ste =
9667c478bd9Sstevel@tonic-gate 		    &hpc3130_p->hpc3130_slot_table[i];
9677c478bd9Sstevel@tonic-gate 		hpc3130_p->power[i] = B_TRUE;
9687c478bd9Sstevel@tonic-gate 		if (ste->callback_info.handle != NULL) {
96907d06da5SSurya Prakki 			(void) hpc_slot_register(dip, ste->nexus,
9707c478bd9Sstevel@tonic-gate 			    &ste->hpc3130_slot_info,
9717c478bd9Sstevel@tonic-gate 			    &ste->hpc3130_slot_handle,
9727c478bd9Sstevel@tonic-gate 			    hpc3130_p->hpc3130_slot_ops,
9737c478bd9Sstevel@tonic-gate 			    (caddr_t)&ste->callback_info, 0);
9747c478bd9Sstevel@tonic-gate 		}
9757c478bd9Sstevel@tonic-gate 	}
9767c478bd9Sstevel@tonic-gate 
9777c478bd9Sstevel@tonic-gate 	(void) snprintf(hpc3130_p->hpc3130_name,
9787c478bd9Sstevel@tonic-gate 	    sizeof (hpc3130_p->hpc3130_name),
9797c478bd9Sstevel@tonic-gate 	    "%s%d", ddi_node_name(dip), instance);
9807c478bd9Sstevel@tonic-gate 
9817c478bd9Sstevel@tonic-gate 	for (i = 0; i < HPC3130_MAX_SLOT; i++) {
9827c478bd9Sstevel@tonic-gate 		(void) snprintf(name, MAXNAMELEN, "port_%d", i);
9837c478bd9Sstevel@tonic-gate 		minor_number = INST_TO_MINOR(instance) |
9847c478bd9Sstevel@tonic-gate 		    PORT_TO_MINOR(I2C_PORT(i));
9857c478bd9Sstevel@tonic-gate 		if (ddi_create_minor_node(dip, name, S_IFCHR, minor_number,
986*baa111a1SToomas Soome 		    "ddi_i2c:controller", 0) == DDI_FAILURE) {
9877c478bd9Sstevel@tonic-gate 			D1CMN_ERR((CE_WARN, "ddi_create_minor_node failed "
9887c478bd9Sstevel@tonic-gate 			    "for %s", name));
9897c478bd9Sstevel@tonic-gate 			ddi_remove_intr(dip, 0u,
9907c478bd9Sstevel@tonic-gate 			    hpc3130_p->ic_trap_cookie);
9917c478bd9Sstevel@tonic-gate 			goto failout4;
9927c478bd9Sstevel@tonic-gate 		}
9937c478bd9Sstevel@tonic-gate 	}
9947c478bd9Sstevel@tonic-gate 
9957c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
9967c478bd9Sstevel@tonic-gate 
9977c478bd9Sstevel@tonic-gate failout4:
9987c478bd9Sstevel@tonic-gate 	hpc_free_slot_ops(hpc3130_p->hpc3130_slot_ops);
9997c478bd9Sstevel@tonic-gate failout3:
10007c478bd9Sstevel@tonic-gate 	i2c_client_unregister(hpc3130_p->hpc3130_hdl);
10017c478bd9Sstevel@tonic-gate failout2:
10027c478bd9Sstevel@tonic-gate 	mutex_destroy(&hpc3130_p->hpc3130_mutex);
10037c478bd9Sstevel@tonic-gate 	kmem_free(hpc3130_p->hpc3130_slot_table,
10047c478bd9Sstevel@tonic-gate 	    hpc3130_p->hpc3130_slot_table_length *
10057c478bd9Sstevel@tonic-gate 	    sizeof (hpc3130_slot_table_entry_t));
10067c478bd9Sstevel@tonic-gate failout1:
10077c478bd9Sstevel@tonic-gate 	kmem_free(hpc3130_p->hpc3130_slot_table_data,
10087c478bd9Sstevel@tonic-gate 	    hpc3130_p->hpc3130_slot_table_size);
10097c478bd9Sstevel@tonic-gate failout0:
10107c478bd9Sstevel@tonic-gate 	ddi_soft_state_free(hpc3130soft_statep, instance);
10117c478bd9Sstevel@tonic-gate 
10127c478bd9Sstevel@tonic-gate 	return (DDI_FAILURE);
10137c478bd9Sstevel@tonic-gate }
10147c478bd9Sstevel@tonic-gate 
10157c478bd9Sstevel@tonic-gate static int
hpc3130_do_resume()10167c478bd9Sstevel@tonic-gate hpc3130_do_resume()
10177c478bd9Sstevel@tonic-gate {
10187c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
10197c478bd9Sstevel@tonic-gate }
10207c478bd9Sstevel@tonic-gate 
10217c478bd9Sstevel@tonic-gate static int
hpc3130_do_suspend()10227c478bd9Sstevel@tonic-gate hpc3130_do_suspend()
10237c478bd9Sstevel@tonic-gate {
10247c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
10257c478bd9Sstevel@tonic-gate }
10267c478bd9Sstevel@tonic-gate 
10277c478bd9Sstevel@tonic-gate static int
hpc3130_do_detach(dev_info_t * dip)10287c478bd9Sstevel@tonic-gate hpc3130_do_detach(dev_info_t *dip)
10297c478bd9Sstevel@tonic-gate {
10307c478bd9Sstevel@tonic-gate 	int i;
10317c478bd9Sstevel@tonic-gate 	int instance = ddi_get_instance(dip);
10327c478bd9Sstevel@tonic-gate 	hpc3130_unit_t *hpc3130_p;
10337c478bd9Sstevel@tonic-gate 
10347c478bd9Sstevel@tonic-gate 	hpc3130_p = (hpc3130_unit_t *)ddi_get_soft_state(hpc3130soft_statep,
10357c478bd9Sstevel@tonic-gate 	    instance);
10367c478bd9Sstevel@tonic-gate 	if (hpc3130_p == NULL)
10377c478bd9Sstevel@tonic-gate 		return (ENXIO);
10387c478bd9Sstevel@tonic-gate 
10397c478bd9Sstevel@tonic-gate 	i2c_client_unregister(hpc3130_p->hpc3130_hdl);
10407c478bd9Sstevel@tonic-gate 
10417c478bd9Sstevel@tonic-gate 	ddi_remove_intr(dip, 0u, hpc3130_p->ic_trap_cookie);
10427c478bd9Sstevel@tonic-gate 
10437c478bd9Sstevel@tonic-gate 	cv_destroy(&hpc3130_p->hpc3130_cond);
10447c478bd9Sstevel@tonic-gate 
10457c478bd9Sstevel@tonic-gate 	for (i = 0; i < hpc3130_p->hpc3130_slot_table_length; i++) {
104607d06da5SSurya Prakki 		(void) hpc_slot_unregister(
10477c478bd9Sstevel@tonic-gate 		    &hpc3130_p->hpc3130_slot_table[i].hpc3130_slot_handle);
10487c478bd9Sstevel@tonic-gate 	}
10497c478bd9Sstevel@tonic-gate 
10507c478bd9Sstevel@tonic-gate 	kmem_free(hpc3130_p->hpc3130_slot_table,
10517c478bd9Sstevel@tonic-gate 	    hpc3130_p->hpc3130_slot_table_length *
10527c478bd9Sstevel@tonic-gate 	    sizeof (hpc3130_slot_table_entry_t));
10537c478bd9Sstevel@tonic-gate 
10547c478bd9Sstevel@tonic-gate 	kmem_free(hpc3130_p->hpc3130_slot_table_data,
10557c478bd9Sstevel@tonic-gate 	    hpc3130_p->hpc3130_slot_table_size);
10567c478bd9Sstevel@tonic-gate 
10577c478bd9Sstevel@tonic-gate 	hpc_free_slot_ops(hpc3130_p->hpc3130_slot_ops);
10587c478bd9Sstevel@tonic-gate 
10597c478bd9Sstevel@tonic-gate 	mutex_destroy(&hpc3130_p->hpc3130_mutex);
10607c478bd9Sstevel@tonic-gate 
10617c478bd9Sstevel@tonic-gate 	ddi_soft_state_free(hpc3130soft_statep, instance);
10627c478bd9Sstevel@tonic-gate 
10637c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
10647c478bd9Sstevel@tonic-gate }
10657c478bd9Sstevel@tonic-gate 
10667c478bd9Sstevel@tonic-gate int
hpc3130_set_led(hpc3130_unit_t * unitp,int slot,int led,uint8_t value)10677c478bd9Sstevel@tonic-gate hpc3130_set_led(hpc3130_unit_t *unitp, int slot, int led, uint8_t value)
10687c478bd9Sstevel@tonic-gate {
10697c478bd9Sstevel@tonic-gate 	i2c_client_hdl_t handle = unitp->hpc3130_hdl;
10707c478bd9Sstevel@tonic-gate 	uint8_t old;
10717c478bd9Sstevel@tonic-gate 	uint8_t	new;
10727c478bd9Sstevel@tonic-gate 
10737c478bd9Sstevel@tonic-gate 	if (hpc3130_read(handle, HPC3130_ATTEN, slot, &old) != DDI_SUCCESS) {
10747c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
10757c478bd9Sstevel@tonic-gate 	}
10767c478bd9Sstevel@tonic-gate 	new = (old & ~HPC3130_ATTN_MASK(led)) |
10777c478bd9Sstevel@tonic-gate 	    value << HPC3130_ATTN_SHIFT(led);
10787c478bd9Sstevel@tonic-gate 
10797c478bd9Sstevel@tonic-gate 	D1CMN_ERR((CE_NOTE, "setting led %d to %x", led, value));
10807c478bd9Sstevel@tonic-gate 
10817c478bd9Sstevel@tonic-gate 	if (hpc3130_write(handle, HPC3130_ATTEN, slot, new) != DDI_SUCCESS) {
10827c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
10837c478bd9Sstevel@tonic-gate 	}
10847c478bd9Sstevel@tonic-gate 
10857c478bd9Sstevel@tonic-gate 	if ((value == HPC3130_ATTN_OFF || value == HPC3130_ATTN_ON) &&
10867c478bd9Sstevel@tonic-gate 	    ((old & HPC3130_ATTN_MASK(led)) !=
10877c478bd9Sstevel@tonic-gate 	    (new & HPC3130_ATTN_MASK(led)))) {
10887c478bd9Sstevel@tonic-gate 		/*
10897c478bd9Sstevel@tonic-gate 		 * We're turning a LED on or off (i.e., not blinking), and
10907c478bd9Sstevel@tonic-gate 		 * the value actually did change.
10917c478bd9Sstevel@tonic-gate 		 */
10927c478bd9Sstevel@tonic-gate 		if (led == HPC3130_LED_OK2REM) {
10937c478bd9Sstevel@tonic-gate 			unitp->events[slot] |= HPC3130_IEVENT_OK2REM;
10947c478bd9Sstevel@tonic-gate 			unitp->ok2rem_led[slot] = value;
10957c478bd9Sstevel@tonic-gate 			D1CMN_ERR((CE_NOTE,
10967c478bd9Sstevel@tonic-gate 			    "recording IEVENT_OK2REM slot=%d, val=%d",
10977c478bd9Sstevel@tonic-gate 			    slot, value));
10987c478bd9Sstevel@tonic-gate 		} else {
10997c478bd9Sstevel@tonic-gate 			unitp->events[slot] |= HPC3130_IEVENT_FAULT;
11007c478bd9Sstevel@tonic-gate 			unitp->fault_led[slot] = value;
11017c478bd9Sstevel@tonic-gate 			D1CMN_ERR((CE_NOTE,
11027c478bd9Sstevel@tonic-gate 			    "recording IEVENT_FAULT slot=%d, val=%d",
11037c478bd9Sstevel@tonic-gate 			    slot, value));
11047c478bd9Sstevel@tonic-gate 		}
11057c478bd9Sstevel@tonic-gate 		ASSERT(MUTEX_HELD(&unitp->hpc3130_mutex));
11067c478bd9Sstevel@tonic-gate 		mutex_exit(&unitp->hpc3130_mutex);
11077c478bd9Sstevel@tonic-gate 		pollwakeup(&unitp->pollhead[slot], POLLIN);
11087c478bd9Sstevel@tonic-gate 		mutex_enter(&unitp->hpc3130_mutex);
11097c478bd9Sstevel@tonic-gate 	}
11107c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
11117c478bd9Sstevel@tonic-gate }
11127c478bd9Sstevel@tonic-gate 
11137c478bd9Sstevel@tonic-gate int
hpc3130_get_led(i2c_client_hdl_t handle,int slot,int led,uint8_t * value)11147c478bd9Sstevel@tonic-gate hpc3130_get_led(i2c_client_hdl_t handle, int slot,
11157c478bd9Sstevel@tonic-gate     int led, uint8_t *value)
11167c478bd9Sstevel@tonic-gate {
11177c478bd9Sstevel@tonic-gate 	uint8_t	temp;
11187c478bd9Sstevel@tonic-gate 
11197c478bd9Sstevel@tonic-gate 	if (hpc3130_read(handle, HPC3130_ATTEN, slot, &temp) != DDI_SUCCESS) {
11207c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
11217c478bd9Sstevel@tonic-gate 	}
11227c478bd9Sstevel@tonic-gate 
11237c478bd9Sstevel@tonic-gate 	*value = (temp & HPC3130_ATTN_MASK(led)) >> HPC3130_ATTN_SHIFT(led);
11247c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
11257c478bd9Sstevel@tonic-gate }
11267c478bd9Sstevel@tonic-gate 
11277c478bd9Sstevel@tonic-gate static int
hpc3130_write(i2c_client_hdl_t handle,uint8_t offset,uint8_t port,uint8_t data)11287c478bd9Sstevel@tonic-gate hpc3130_write(i2c_client_hdl_t handle, uint8_t offset,
11297c478bd9Sstevel@tonic-gate     uint8_t port, uint8_t data)
11307c478bd9Sstevel@tonic-gate {
1131f47a9c50Smathue 	ASSERT(port < HPC3130_MAX_SLOT);
11327c478bd9Sstevel@tonic-gate 	ASSERT(handle);
11337c478bd9Sstevel@tonic-gate 
11347c478bd9Sstevel@tonic-gate 	return (hpc3130_rw(handle,
11357c478bd9Sstevel@tonic-gate 	    HPC3130_REG(offset, port), B_TRUE, &data));
11367c478bd9Sstevel@tonic-gate }
11377c478bd9Sstevel@tonic-gate 
11387c478bd9Sstevel@tonic-gate static int
hpc3130_read(i2c_client_hdl_t handle,uint8_t offset,uint8_t port,uint8_t * data)11397c478bd9Sstevel@tonic-gate hpc3130_read(i2c_client_hdl_t handle, uint8_t offset,
11407c478bd9Sstevel@tonic-gate     uint8_t port, uint8_t *data)
11417c478bd9Sstevel@tonic-gate {
1142f47a9c50Smathue 	ASSERT(port < HPC3130_MAX_SLOT);
11437c478bd9Sstevel@tonic-gate 	ASSERT(handle);
11447c478bd9Sstevel@tonic-gate 
11457c478bd9Sstevel@tonic-gate 	return (hpc3130_rw(handle,
11467c478bd9Sstevel@tonic-gate 	    HPC3130_REG(offset, port), B_FALSE, data));
11477c478bd9Sstevel@tonic-gate }
11487c478bd9Sstevel@tonic-gate 
11497c478bd9Sstevel@tonic-gate static int
hpc3130_rw(i2c_client_hdl_t handle,uint8_t reg,boolean_t write,uint8_t * data)11507c478bd9Sstevel@tonic-gate hpc3130_rw(i2c_client_hdl_t handle, uint8_t reg,
11517c478bd9Sstevel@tonic-gate     boolean_t write, uint8_t *data)
11527c478bd9Sstevel@tonic-gate {
11537c478bd9Sstevel@tonic-gate 	i2c_transfer_t	*i2c_tran_pointer;
11547c478bd9Sstevel@tonic-gate 	int		err;
11557c478bd9Sstevel@tonic-gate 	int		rlen;
11567c478bd9Sstevel@tonic-gate 	int		wlen;
11577c478bd9Sstevel@tonic-gate 
11587c478bd9Sstevel@tonic-gate 	if (write == B_TRUE) {
11597c478bd9Sstevel@tonic-gate 		wlen = 2;
11607c478bd9Sstevel@tonic-gate 		rlen = 0;
11617c478bd9Sstevel@tonic-gate 	} else {
11627c478bd9Sstevel@tonic-gate 		wlen = 1;
11637c478bd9Sstevel@tonic-gate 		rlen = 1;
11647c478bd9Sstevel@tonic-gate 	}
11657c478bd9Sstevel@tonic-gate 
11667c478bd9Sstevel@tonic-gate 	(void) i2c_transfer_alloc(handle,
11677c478bd9Sstevel@tonic-gate 	    &i2c_tran_pointer, wlen, rlen, I2C_SLEEP);
11687c478bd9Sstevel@tonic-gate 
11697c478bd9Sstevel@tonic-gate 	if (i2c_tran_pointer == NULL) {
11707c478bd9Sstevel@tonic-gate 		D1CMN_ERR((CE_WARN, "Failed in hpc3130_rw: "
11717c478bd9Sstevel@tonic-gate 		    "no transfer structure 0x%x", reg));
11727c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
11737c478bd9Sstevel@tonic-gate 	}
11747c478bd9Sstevel@tonic-gate 	i2c_tran_pointer->i2c_wbuf[0] = reg;
11757c478bd9Sstevel@tonic-gate 	if (write == B_TRUE) {
11767c478bd9Sstevel@tonic-gate 		i2c_tran_pointer->i2c_flags = I2C_WR;
11777c478bd9Sstevel@tonic-gate 		i2c_tran_pointer->i2c_wbuf[1] = *data;
11787c478bd9Sstevel@tonic-gate 	} else {
11797c478bd9Sstevel@tonic-gate 		i2c_tran_pointer->i2c_flags = I2C_WR_RD;
11807c478bd9Sstevel@tonic-gate 	}
11817c478bd9Sstevel@tonic-gate 
11827c478bd9Sstevel@tonic-gate 	err = i2c_transfer(handle, i2c_tran_pointer);
11837c478bd9Sstevel@tonic-gate 	if (err) {
11847c478bd9Sstevel@tonic-gate 		D1CMN_ERR((CE_WARN, "Failed in hpc3130_rw: "
11857c478bd9Sstevel@tonic-gate 		    "no I2C data transfered 0x%x", reg));
11867c478bd9Sstevel@tonic-gate 		(void) i2c_transfer_free(handle, i2c_tran_pointer);
11877c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
11887c478bd9Sstevel@tonic-gate 	}
11897c478bd9Sstevel@tonic-gate 
11907c478bd9Sstevel@tonic-gate 	if (write == B_FALSE)
11917c478bd9Sstevel@tonic-gate 		*data = i2c_tran_pointer->i2c_rbuf[0];
11927c478bd9Sstevel@tonic-gate 
11937c478bd9Sstevel@tonic-gate 	(void) i2c_transfer_free(handle, i2c_tran_pointer);
11947c478bd9Sstevel@tonic-gate 
11957c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
11967c478bd9Sstevel@tonic-gate }
11977c478bd9Sstevel@tonic-gate 
11987c478bd9Sstevel@tonic-gate /*
11997c478bd9Sstevel@tonic-gate  * Put the hot plug controller(s) in proper mode for further
12007c478bd9Sstevel@tonic-gate  * operations.
12017c478bd9Sstevel@tonic-gate  */
12027c478bd9Sstevel@tonic-gate static int
hpc3130_init(dev_info_t * dip,struct tuple * init_sequence)12037c478bd9Sstevel@tonic-gate hpc3130_init(dev_info_t *dip,
12047c478bd9Sstevel@tonic-gate     struct tuple *init_sequence)
12057c478bd9Sstevel@tonic-gate {
12067c478bd9Sstevel@tonic-gate 
12077c478bd9Sstevel@tonic-gate 	int			slot;
12087c478bd9Sstevel@tonic-gate 	i2c_client_hdl_t	handle;
12097c478bd9Sstevel@tonic-gate 	hpc3130_unit_t		*hpc3130_p;
12107c478bd9Sstevel@tonic-gate 	int			instance = ddi_get_instance(dip);
12117c478bd9Sstevel@tonic-gate 	int			error = DDI_FAILURE;
12127c478bd9Sstevel@tonic-gate 	struct tuple		*tp;
12137c478bd9Sstevel@tonic-gate 
12147c478bd9Sstevel@tonic-gate 	hpc3130_p =
12157c478bd9Sstevel@tonic-gate 	    (hpc3130_unit_t *)ddi_get_soft_state(hpc3130soft_statep,
12167c478bd9Sstevel@tonic-gate 	    instance);
12177c478bd9Sstevel@tonic-gate 	ASSERT(hpc3130_p);
12187c478bd9Sstevel@tonic-gate 
12197c478bd9Sstevel@tonic-gate 	mutex_enter(&hpc3130_p->hpc3130_mutex);
12207c478bd9Sstevel@tonic-gate 
12217c478bd9Sstevel@tonic-gate 	handle = hpc3130_p->hpc3130_hdl;
12227c478bd9Sstevel@tonic-gate 
12237c478bd9Sstevel@tonic-gate 	for (slot = 0; slot < HPC3130_MAX_SLOT; slot++) {
12247c478bd9Sstevel@tonic-gate 		tp = init_sequence;
12257c478bd9Sstevel@tonic-gate 		while (tp->reg != HPC3130_NO_REGISTER) {
12267c478bd9Sstevel@tonic-gate 			if (hpc3130_write(handle, tp->reg, slot,
12277c478bd9Sstevel@tonic-gate 			    tp->val) != DDI_SUCCESS) {
12287c478bd9Sstevel@tonic-gate 				goto out;
12297c478bd9Sstevel@tonic-gate 			}
12307c478bd9Sstevel@tonic-gate 			tp++;
12317c478bd9Sstevel@tonic-gate 		}
12327c478bd9Sstevel@tonic-gate 		/*
12337c478bd9Sstevel@tonic-gate 		 * CPU slots need some special initialization
12347c478bd9Sstevel@tonic-gate 		 * attention.
12357c478bd9Sstevel@tonic-gate 		 */
12367c478bd9Sstevel@tonic-gate 		if (hpc3130_p->slots_are == HPC3130_SLOT_TYPE_SBD) {
12377c478bd9Sstevel@tonic-gate 			if (hpc3130_cpu_init(hpc3130_p, slot, handle)
12387c478bd9Sstevel@tonic-gate 			    != DDI_SUCCESS) {
12397c478bd9Sstevel@tonic-gate 				goto out;
12407c478bd9Sstevel@tonic-gate 			}
12417c478bd9Sstevel@tonic-gate 		}
12427c478bd9Sstevel@tonic-gate 	}
12437c478bd9Sstevel@tonic-gate 	error = DDI_SUCCESS;
12447c478bd9Sstevel@tonic-gate out:
12457c478bd9Sstevel@tonic-gate 	mutex_exit(&hpc3130_p->hpc3130_mutex);
12467c478bd9Sstevel@tonic-gate 
12477c478bd9Sstevel@tonic-gate 	return (error);
12487c478bd9Sstevel@tonic-gate }
12497c478bd9Sstevel@tonic-gate 
12507c478bd9Sstevel@tonic-gate /*
12517c478bd9Sstevel@tonic-gate  * When the TI 3130 produces an interrupt,
12527c478bd9Sstevel@tonic-gate  * this routine is called to sort it out.
12537c478bd9Sstevel@tonic-gate  */
12547c478bd9Sstevel@tonic-gate static uint_t
hpc3130_hard_intr(caddr_t arg)12557c478bd9Sstevel@tonic-gate hpc3130_hard_intr(caddr_t arg)
12567c478bd9Sstevel@tonic-gate {
12577c478bd9Sstevel@tonic-gate 	uint8_t			interrupt;
12587c478bd9Sstevel@tonic-gate 	uint8_t			status;
12597c478bd9Sstevel@tonic-gate 	uint8_t			slot;
12607c478bd9Sstevel@tonic-gate 	i2c_client_hdl_t	handle;
12617c478bd9Sstevel@tonic-gate 	hpc3130_slot_type_t	slot_type;
12627c478bd9Sstevel@tonic-gate 	uint_t			rc = DDI_INTR_UNCLAIMED;
12637c478bd9Sstevel@tonic-gate 
12647c478bd9Sstevel@tonic-gate 	hpc3130_unit_t		*hpc3130_p = (hpc3130_unit_t *)arg;
12657c478bd9Sstevel@tonic-gate 	ASSERT(hpc3130_p);
12667c478bd9Sstevel@tonic-gate 
12677c478bd9Sstevel@tonic-gate 	mutex_enter(&hpc3130_p->hpc3130_mutex);
12687c478bd9Sstevel@tonic-gate 
12697c478bd9Sstevel@tonic-gate 	slot_type = hpc3130_p->slots_are;
12707c478bd9Sstevel@tonic-gate 	handle = hpc3130_p->hpc3130_hdl;
12717c478bd9Sstevel@tonic-gate 
12727c478bd9Sstevel@tonic-gate 	for (slot = 0; slot < HPC3130_MAX_SLOT; slot++) {
12737c478bd9Sstevel@tonic-gate 
12747c478bd9Sstevel@tonic-gate 		/*
12757c478bd9Sstevel@tonic-gate 		 * Read the interrupt event register - see
12767c478bd9Sstevel@tonic-gate 		 * which event(s) took place.
12777c478bd9Sstevel@tonic-gate 		 */
12787c478bd9Sstevel@tonic-gate 		if (hpc3130_read(handle, HPC3130_EVENT_STATUS, slot,
12797c478bd9Sstevel@tonic-gate 		    &interrupt)) {
12807c478bd9Sstevel@tonic-gate 			continue;
12817c478bd9Sstevel@tonic-gate 		}
12827c478bd9Sstevel@tonic-gate 
12837c478bd9Sstevel@tonic-gate 		if (interrupt == 0)
12847c478bd9Sstevel@tonic-gate 			continue;
12857c478bd9Sstevel@tonic-gate 
12867c478bd9Sstevel@tonic-gate 		rc = DDI_INTR_CLAIMED;
12877c478bd9Sstevel@tonic-gate 
12887c478bd9Sstevel@tonic-gate 		if (hpc3130_debounce_status(handle,
12897c478bd9Sstevel@tonic-gate 		    slot, &status) != DDI_SUCCESS) {
12907c478bd9Sstevel@tonic-gate 			continue;
12917c478bd9Sstevel@tonic-gate 		}
12927c478bd9Sstevel@tonic-gate 
12937c478bd9Sstevel@tonic-gate 		if (interrupt & HPC3130_PWRGOOD) {
12947c478bd9Sstevel@tonic-gate 			hpc3130_p->power[slot] = B_FALSE;
12957c478bd9Sstevel@tonic-gate 			if (!(status & HPC3130_PWRGOOD)) {
12967c478bd9Sstevel@tonic-gate 				hpc3130_p->power[slot] = B_TRUE;
12977c478bd9Sstevel@tonic-gate 			}
12987c478bd9Sstevel@tonic-gate 			cv_signal(&hpc3130_p->hpc3130_cond);
12997c478bd9Sstevel@tonic-gate 			hpc3130_p->events[slot] |= HPC3130_IEVENT_POWER;
13007c478bd9Sstevel@tonic-gate 		}
13017c478bd9Sstevel@tonic-gate 
13027c478bd9Sstevel@tonic-gate 		if (interrupt & HPC3130_DETECT0) {
13037c478bd9Sstevel@tonic-gate 			if (slot_type == HPC3130_SLOT_TYPE_SBD) {
13047c478bd9Sstevel@tonic-gate 				boolean_t present = !(status&HPC3130_DETECT0);
13057c478bd9Sstevel@tonic-gate 
13067c478bd9Sstevel@tonic-gate 				/* Turn ON/OFF OK-to-remove LED */
13077c478bd9Sstevel@tonic-gate 				(void) hpc3130_set_led(hpc3130_p,
13087c478bd9Sstevel@tonic-gate 				    slot,
13097c478bd9Sstevel@tonic-gate 				    HPC3130_LED_OK2REM,
13107c478bd9Sstevel@tonic-gate 				    (present ? HPC3130_ATTN_ON :
13117c478bd9Sstevel@tonic-gate 				    HPC3130_ATTN_OFF));
13127c478bd9Sstevel@tonic-gate 				if (!present) {
13137c478bd9Sstevel@tonic-gate 					/* Clear the FAULT LED on removal */
13147c478bd9Sstevel@tonic-gate 					(void) hpc3130_set_led(hpc3130_p,
13157c478bd9Sstevel@tonic-gate 					    slot,
13167c478bd9Sstevel@tonic-gate 					    HPC3130_LED_FAULT,
13177c478bd9Sstevel@tonic-gate 					    HPC3130_ATTN_OFF);
13187c478bd9Sstevel@tonic-gate 				}
13197c478bd9Sstevel@tonic-gate 
13207c478bd9Sstevel@tonic-gate 				hpc3130_p->present[slot] = present;
13217c478bd9Sstevel@tonic-gate 				hpc3130_p->events[slot] |=
13227c478bd9Sstevel@tonic-gate 				    HPC3130_IEVENT_OCCUPANCY;
13237c478bd9Sstevel@tonic-gate 			} else {
13247c478bd9Sstevel@tonic-gate 				ASSERT(slot_type == HPC3130_SLOT_TYPE_PCI);
13257c478bd9Sstevel@tonic-gate 
13267c478bd9Sstevel@tonic-gate 				if (!(status & HPC3130_DETECT0)) {
13277c478bd9Sstevel@tonic-gate 					/*
13287c478bd9Sstevel@tonic-gate 					 * Event on the downward
13297c478bd9Sstevel@tonic-gate 					 * stroke of the button.
13307c478bd9Sstevel@tonic-gate 					 */
13317c478bd9Sstevel@tonic-gate 					hpc3130_p->events[slot] |=
13327c478bd9Sstevel@tonic-gate 					    HPC3130_IEVENT_BUTTON;
13337c478bd9Sstevel@tonic-gate 				}
13347c478bd9Sstevel@tonic-gate 			}
13357c478bd9Sstevel@tonic-gate 		}
13367c478bd9Sstevel@tonic-gate 
13377c478bd9Sstevel@tonic-gate 		if (interrupt & (HPC3130_PRSNT1 | HPC3130_PRSNT2)) {
13387c478bd9Sstevel@tonic-gate 			if (slot_type == HPC3130_SLOT_TYPE_SBD) {
13397c478bd9Sstevel@tonic-gate 				if (!(status & HPC3130_PRSNT1)) {
13407c478bd9Sstevel@tonic-gate 					/*
13417c478bd9Sstevel@tonic-gate 					 * Event only on the downward
13427c478bd9Sstevel@tonic-gate 					 * stroke of the button.
13437c478bd9Sstevel@tonic-gate 					 */
13447c478bd9Sstevel@tonic-gate 					hpc3130_p->events[slot] |=
13457c478bd9Sstevel@tonic-gate 					    HPC3130_IEVENT_BUTTON;
13467c478bd9Sstevel@tonic-gate 				}
13477c478bd9Sstevel@tonic-gate 			} else {
13487c478bd9Sstevel@tonic-gate 				ASSERT(slot_type == HPC3130_SLOT_TYPE_PCI);
13497c478bd9Sstevel@tonic-gate 				if ((status & (HPC3130_PRSNT1 |
13507c478bd9Sstevel@tonic-gate 				    HPC3130_PRSNT2)) ==
13517c478bd9Sstevel@tonic-gate 				    (HPC3130_PRSNT1 | HPC3130_PRSNT2)) {
13527c478bd9Sstevel@tonic-gate 
13537c478bd9Sstevel@tonic-gate 					hpc3130_p->present[slot] = B_FALSE;
13547c478bd9Sstevel@tonic-gate 
13557c478bd9Sstevel@tonic-gate 					/* Turn OFF Fault LED */
13567c478bd9Sstevel@tonic-gate 					(void) hpc3130_set_led(hpc3130_p,
13577c478bd9Sstevel@tonic-gate 					    slot,
13587c478bd9Sstevel@tonic-gate 					    HPC3130_LED_FAULT,
13597c478bd9Sstevel@tonic-gate 					    HPC3130_ATTN_OFF);
13607c478bd9Sstevel@tonic-gate 					/* Turn OFF OK-to-remove LED */
13617c478bd9Sstevel@tonic-gate 					(void) hpc3130_set_led(hpc3130_p,
13627c478bd9Sstevel@tonic-gate 					    slot,
13637c478bd9Sstevel@tonic-gate 					    HPC3130_LED_OK2REM,
13647c478bd9Sstevel@tonic-gate 					    HPC3130_ATTN_OFF);
13657c478bd9Sstevel@tonic-gate 				} else {
13667c478bd9Sstevel@tonic-gate 
13677c478bd9Sstevel@tonic-gate 					hpc3130_p->present[slot] = B_TRUE;
13687c478bd9Sstevel@tonic-gate 
13697c478bd9Sstevel@tonic-gate 					/* Turn ON OK-to-remove LED */
13707c478bd9Sstevel@tonic-gate 					(void) hpc3130_set_led(hpc3130_p,
13717c478bd9Sstevel@tonic-gate 					    slot,
13727c478bd9Sstevel@tonic-gate 					    HPC3130_LED_OK2REM,
13737c478bd9Sstevel@tonic-gate 					    HPC3130_ATTN_ON);
13747c478bd9Sstevel@tonic-gate 				}
13757c478bd9Sstevel@tonic-gate 
13767c478bd9Sstevel@tonic-gate 				hpc3130_p->events[slot] |=
13777c478bd9Sstevel@tonic-gate 				    HPC3130_IEVENT_OCCUPANCY;
13787c478bd9Sstevel@tonic-gate 			}
13797c478bd9Sstevel@tonic-gate 		}
13807c478bd9Sstevel@tonic-gate 		if (hpc3130_p->events[slot] &&
13817c478bd9Sstevel@tonic-gate 		    (hpc3130_p->present[slot] == B_TRUE)) {
13827c478bd9Sstevel@tonic-gate 			mutex_exit(&hpc3130_p->hpc3130_mutex);
13837c478bd9Sstevel@tonic-gate 			pollwakeup(&hpc3130_p->pollhead[slot], POLLIN);
13847c478bd9Sstevel@tonic-gate 			mutex_enter(&hpc3130_p->hpc3130_mutex);
13857c478bd9Sstevel@tonic-gate 		}
13867c478bd9Sstevel@tonic-gate 		(void) hpc3130_write(handle, HPC3130_EVENT_STATUS,
13877c478bd9Sstevel@tonic-gate 		    slot, interrupt);
13887c478bd9Sstevel@tonic-gate 	}
13897c478bd9Sstevel@tonic-gate 
13907c478bd9Sstevel@tonic-gate 	mutex_exit(&hpc3130_p->hpc3130_mutex);
13917c478bd9Sstevel@tonic-gate 
13927c478bd9Sstevel@tonic-gate 	return (rc);
13937c478bd9Sstevel@tonic-gate }
13947c478bd9Sstevel@tonic-gate 
13957c478bd9Sstevel@tonic-gate static int
hpc3130_cpu_init(hpc3130_unit_t * hpc3130_p,int slot,i2c_client_hdl_t handle)13967c478bd9Sstevel@tonic-gate hpc3130_cpu_init(hpc3130_unit_t *hpc3130_p, int slot, i2c_client_hdl_t handle)
13977c478bd9Sstevel@tonic-gate {
13987c478bd9Sstevel@tonic-gate 	uint8_t	slot_status;
13997c478bd9Sstevel@tonic-gate 	uint8_t	control_reg;
14007c478bd9Sstevel@tonic-gate 
14017c478bd9Sstevel@tonic-gate 	int	result = HPC_ERR_FAILED;
14027c478bd9Sstevel@tonic-gate 
14037c478bd9Sstevel@tonic-gate 	if (hpc3130_read(handle, HPC3130_STATUS, slot,
14047c478bd9Sstevel@tonic-gate 	    &slot_status)) {
14057c478bd9Sstevel@tonic-gate 		goto out;
14067c478bd9Sstevel@tonic-gate 	}
14077c478bd9Sstevel@tonic-gate 
14087c478bd9Sstevel@tonic-gate 	if (hpc3130_read(handle, HPC3130_CONTROL, slot,
14097c478bd9Sstevel@tonic-gate 	    &control_reg)) {
14107c478bd9Sstevel@tonic-gate 		goto out;
14117c478bd9Sstevel@tonic-gate 	}
14127c478bd9Sstevel@tonic-gate 
14137c478bd9Sstevel@tonic-gate 	/*
14147c478bd9Sstevel@tonic-gate 	 * For the CPU slots, the DETECT[0] pin on the HPC3130
14157c478bd9Sstevel@tonic-gate 	 * goes low when a CPU module is in the slot. Pulled
14167c478bd9Sstevel@tonic-gate 	 * high otherwise.
14177c478bd9Sstevel@tonic-gate 	 */
14187c478bd9Sstevel@tonic-gate 	if (slot_status & HPC3130_DETECT0) {
14197c478bd9Sstevel@tonic-gate 		D1CMN_ERR((CE_NOTE, "hpc3130_cpu_init(): "
14207c478bd9Sstevel@tonic-gate 		    "[0x%x]Power off....[%d]",
14217c478bd9Sstevel@tonic-gate 		    slot_status, slot));
14227c478bd9Sstevel@tonic-gate 		control_reg = control_reg & ~HPC3130_SLTPWRCTL;
14237c478bd9Sstevel@tonic-gate 	} else {
14247c478bd9Sstevel@tonic-gate 		D1CMN_ERR((CE_NOTE, "hpc3130_cpu_init(): "
14257c478bd9Sstevel@tonic-gate 		    "[0x%x]Power LEFT on!!!....[%d]",
14267c478bd9Sstevel@tonic-gate 		    slot_status, slot));
14277c478bd9Sstevel@tonic-gate 		hpc3130_p->present[slot] = B_TRUE;
14287c478bd9Sstevel@tonic-gate 		control_reg = control_reg | HPC3130_SLTPWRCTL;
14297c478bd9Sstevel@tonic-gate 
14307c478bd9Sstevel@tonic-gate 	}
14317c478bd9Sstevel@tonic-gate 
14327c478bd9Sstevel@tonic-gate 	/*
14337c478bd9Sstevel@tonic-gate 	 * Set the control register accordingly
14347c478bd9Sstevel@tonic-gate 	 */
14357c478bd9Sstevel@tonic-gate 	if (hpc3130_write(handle, HPC3130_CONTROL,
14367c478bd9Sstevel@tonic-gate 	    slot, control_reg) != DDI_SUCCESS) {
14377c478bd9Sstevel@tonic-gate 		goto out;
14387c478bd9Sstevel@tonic-gate 	}
14397c478bd9Sstevel@tonic-gate 
14407c478bd9Sstevel@tonic-gate 	result = DDI_SUCCESS;
14417c478bd9Sstevel@tonic-gate out:
14427c478bd9Sstevel@tonic-gate 
14437c478bd9Sstevel@tonic-gate 	return (result);
14447c478bd9Sstevel@tonic-gate }
14457c478bd9Sstevel@tonic-gate 
14467c478bd9Sstevel@tonic-gate static int
hpc3130_debounce_status(i2c_client_hdl_t handle,int slot,uint8_t * status)14477c478bd9Sstevel@tonic-gate hpc3130_debounce_status(i2c_client_hdl_t handle,
14487c478bd9Sstevel@tonic-gate     int slot, uint8_t *status)
14497c478bd9Sstevel@tonic-gate {
14507c478bd9Sstevel@tonic-gate 	int	count, limit;
14517c478bd9Sstevel@tonic-gate 	uint8_t	old;
14527c478bd9Sstevel@tonic-gate 
14537c478bd9Sstevel@tonic-gate 	ASSERT(status);
14547c478bd9Sstevel@tonic-gate 
14557c478bd9Sstevel@tonic-gate 	/*
14567c478bd9Sstevel@tonic-gate 	 * Get HPC3130_DEBOUNCE_COUNT consecutive equal
14577c478bd9Sstevel@tonic-gate 	 * readings from the status register
14587c478bd9Sstevel@tonic-gate 	 */
14597c478bd9Sstevel@tonic-gate 
14607c478bd9Sstevel@tonic-gate 	count = 0; limit = 0; old = 0xff;
14617c478bd9Sstevel@tonic-gate 	do {
14627c478bd9Sstevel@tonic-gate 		if (hpc3130_read(handle, HPC3130_STATUS,
14637c478bd9Sstevel@tonic-gate 		    slot, status)) {
14647c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
14657c478bd9Sstevel@tonic-gate 		}
14667c478bd9Sstevel@tonic-gate 		if (old != *status) {
14677c478bd9Sstevel@tonic-gate 			count = 0;
14687c478bd9Sstevel@tonic-gate 		} else {
14697c478bd9Sstevel@tonic-gate 			count += 1;
14707c478bd9Sstevel@tonic-gate 		}
14717c478bd9Sstevel@tonic-gate 
14727c478bd9Sstevel@tonic-gate 		limit += 1;
14737c478bd9Sstevel@tonic-gate 		old = *status;
14747c478bd9Sstevel@tonic-gate 
14757c478bd9Sstevel@tonic-gate 	} while (count < HPC3130_DEBOUNCE_COUNT &&
14767c478bd9Sstevel@tonic-gate 	    limit < HPC3130_DEBOUNCE_LIMIT);
14777c478bd9Sstevel@tonic-gate 
14787c478bd9Sstevel@tonic-gate 	if (limit == HPC3130_DEBOUNCE_LIMIT) {
14797c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
14807c478bd9Sstevel@tonic-gate 	}
14817c478bd9Sstevel@tonic-gate 
14827c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
14837c478bd9Sstevel@tonic-gate }
14847c478bd9Sstevel@tonic-gate 
14857c478bd9Sstevel@tonic-gate static int
hpc3130_slot_connect(caddr_t ops_arg,hpc_slot_t slot_hdl,void * data,uint_t flags)14867c478bd9Sstevel@tonic-gate hpc3130_slot_connect(caddr_t ops_arg, hpc_slot_t slot_hdl,
14877c478bd9Sstevel@tonic-gate     void *data, uint_t flags)
14887c478bd9Sstevel@tonic-gate {
14897c478bd9Sstevel@tonic-gate 	_NOTE(ARGUNUSED(slot_hdl, data, flags))
14907c478bd9Sstevel@tonic-gate 	uint8_t			control;
14917c478bd9Sstevel@tonic-gate 	uint8_t			offset;
14927c478bd9Sstevel@tonic-gate 	uint8_t			config;
14937c478bd9Sstevel@tonic-gate 	uint8_t			status;
14947c478bd9Sstevel@tonic-gate 	hpc3130_unit_t		*hpc3130_p;
14957c478bd9Sstevel@tonic-gate 	i2c_client_hdl_t	handle;
14967c478bd9Sstevel@tonic-gate 	int			i;
14977c478bd9Sstevel@tonic-gate 	int			result = HPC_ERR_FAILED;
14987c478bd9Sstevel@tonic-gate 	hpc3130_slot_type_t	slot_type;
14997c478bd9Sstevel@tonic-gate 	hpc3130_slot_table_entry_t *ste;
15007c478bd9Sstevel@tonic-gate 	char			phys_slot[MAXPATHLEN];
15017c478bd9Sstevel@tonic-gate 	boolean_t		needs_to_be_powered_off = B_FALSE;
15027c478bd9Sstevel@tonic-gate 
15037c478bd9Sstevel@tonic-gate 	hpc3130_callback_arg_t	*info_p = (hpc3130_callback_arg_t *)ops_arg;
15047c478bd9Sstevel@tonic-gate 
15057c478bd9Sstevel@tonic-gate 	/*
15067c478bd9Sstevel@tonic-gate 	 * Callback parameter has specific device handle and offset
15077c478bd9Sstevel@tonic-gate 	 * information in it.
15087c478bd9Sstevel@tonic-gate 	 */
15097c478bd9Sstevel@tonic-gate 
15107c478bd9Sstevel@tonic-gate 	hpc3130_p = (hpc3130_unit_t *)info_p->statep;
15117c478bd9Sstevel@tonic-gate 	ASSERT(hpc3130_p);
15127c478bd9Sstevel@tonic-gate 
15137c478bd9Sstevel@tonic-gate 	mutex_enter(&hpc3130_p->hpc3130_mutex);
15147c478bd9Sstevel@tonic-gate 
15157c478bd9Sstevel@tonic-gate 	handle = (i2c_client_hdl_t)info_p->handle;
15167c478bd9Sstevel@tonic-gate 	offset = info_p->offset;
15177c478bd9Sstevel@tonic-gate 
15187c478bd9Sstevel@tonic-gate 	ste = &hpc3130_p->hpc3130_slot_table[offset];
15197c478bd9Sstevel@tonic-gate 
15207c478bd9Sstevel@tonic-gate 	if (hpc3130_p->slots_are == HPC3130_SLOT_TYPE_SBD) {
15217c478bd9Sstevel@tonic-gate 		DAK_GET_SBD_APID(phys_slot, MAXPATHLEN, offset);
15227c478bd9Sstevel@tonic-gate 	} else {
15237c478bd9Sstevel@tonic-gate 		DAK_GET_PCI_APID(phys_slot, MAXPATHLEN,
15247c478bd9Sstevel@tonic-gate 		    hpc3130_lookup_slot(ste->nexus,
15257c478bd9Sstevel@tonic-gate 		    ste->hpc3130_slot_info.pci_dev_num));
15267c478bd9Sstevel@tonic-gate 	}
15277c478bd9Sstevel@tonic-gate 
15287c478bd9Sstevel@tonic-gate 	ASSERT(ste->hpc3130_slot_handle != NULL);
15297c478bd9Sstevel@tonic-gate 
15307c478bd9Sstevel@tonic-gate 	slot_type = hpc3130_p->slots_are;
15317c478bd9Sstevel@tonic-gate 
15327c478bd9Sstevel@tonic-gate 	if (hpc3130_p->enabled[offset] == B_FALSE) {
15337c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "hot-plug disabled on %s", phys_slot);
15347c478bd9Sstevel@tonic-gate 		goto out;
15357c478bd9Sstevel@tonic-gate 	}
15367c478bd9Sstevel@tonic-gate 
15377c478bd9Sstevel@tonic-gate 	/* Return (do nothing) if power already applied */
15387c478bd9Sstevel@tonic-gate 	if (hpc3130_p->power[offset] == B_TRUE) {
15397c478bd9Sstevel@tonic-gate 		D1CMN_ERR((CE_NOTE, "Slot power already on %s", phys_slot));
15407c478bd9Sstevel@tonic-gate 		mutex_exit(&hpc3130_p->hpc3130_mutex);
15417c478bd9Sstevel@tonic-gate 		return (HPC_SUCCESS);
15427c478bd9Sstevel@tonic-gate 	}
15437c478bd9Sstevel@tonic-gate 
15447c478bd9Sstevel@tonic-gate 	if (hpc3130_read(handle, HPC3130_STATUS, offset,
15457c478bd9Sstevel@tonic-gate 	    &status)) {
15467c478bd9Sstevel@tonic-gate 		goto out;
15477c478bd9Sstevel@tonic-gate 	}
15487c478bd9Sstevel@tonic-gate 
15497c478bd9Sstevel@tonic-gate 	/* Read the slot control register to get current value */
15507c478bd9Sstevel@tonic-gate 	if (hpc3130_read(handle, HPC3130_CONTROL, offset,
15517c478bd9Sstevel@tonic-gate 	    &control)) {
15527c478bd9Sstevel@tonic-gate 		goto out;
15537c478bd9Sstevel@tonic-gate 	}
15547c478bd9Sstevel@tonic-gate 
15557c478bd9Sstevel@tonic-gate 	if (slot_type == HPC3130_SLOT_TYPE_SBD) {
15567c478bd9Sstevel@tonic-gate 
15577c478bd9Sstevel@tonic-gate 		D1CMN_ERR((CE_NOTE, "CPU connect %d control=%x status=%x",
15587c478bd9Sstevel@tonic-gate 		    offset, control, status));
15597c478bd9Sstevel@tonic-gate 
15607c478bd9Sstevel@tonic-gate 		control = control | HPC3130_SLTPWRCTL;
15617c478bd9Sstevel@tonic-gate 		if (hpc3130_write(handle, HPC3130_CONTROL, offset,
15627c478bd9Sstevel@tonic-gate 		    control) != DDI_SUCCESS) {
15637c478bd9Sstevel@tonic-gate 			goto out;
15647c478bd9Sstevel@tonic-gate 		}
15657c478bd9Sstevel@tonic-gate 
15667c478bd9Sstevel@tonic-gate 	} else {
15677c478bd9Sstevel@tonic-gate 
15687c478bd9Sstevel@tonic-gate 		D1CMN_ERR((CE_NOTE, "PCI connect %d", offset));
15697c478bd9Sstevel@tonic-gate 
15707c478bd9Sstevel@tonic-gate 		/*
15717c478bd9Sstevel@tonic-gate 		 * PCI needs special sequencing of the control signals.
15727c478bd9Sstevel@tonic-gate 		 */
15737c478bd9Sstevel@tonic-gate 
15747c478bd9Sstevel@tonic-gate 		if (hpc3130_read(handle, HPC3130_GCR, offset,
15757c478bd9Sstevel@tonic-gate 		    &config)) {
15767c478bd9Sstevel@tonic-gate 			goto out;
15777c478bd9Sstevel@tonic-gate 		}
15787c478bd9Sstevel@tonic-gate 
15797c478bd9Sstevel@tonic-gate 		/* Assert RST to comply with PCI spec. */
15807c478bd9Sstevel@tonic-gate 		control &= ~HPC3130_SLOTRST;
15817c478bd9Sstevel@tonic-gate 		if (hpc3130_write(handle, HPC3130_CONTROL, offset,
15827c478bd9Sstevel@tonic-gate 		    control) != DDI_SUCCESS) {
15837c478bd9Sstevel@tonic-gate 			goto out;
15847c478bd9Sstevel@tonic-gate 		}
15857c478bd9Sstevel@tonic-gate 		drv_usecwait(HPC3130_ADEQUATE_PAUSE);
15867c478bd9Sstevel@tonic-gate 
15877c478bd9Sstevel@tonic-gate 		/* Send the power on signal and verify the result */
15887c478bd9Sstevel@tonic-gate 		control = control | HPC3130_SLTPWRCTL;
15897c478bd9Sstevel@tonic-gate 		if ((hpc3130_write(handle, HPC3130_CONTROL, offset,
15907c478bd9Sstevel@tonic-gate 		    control) != DDI_SUCCESS) ||
15917c478bd9Sstevel@tonic-gate 		    (hpc3130_verify_slot_power(hpc3130_p, handle, offset,
15927c478bd9Sstevel@tonic-gate 		    phys_slot, B_TRUE) == HPC_ERR_FAILED)) {
15937c478bd9Sstevel@tonic-gate 			goto out;
15947c478bd9Sstevel@tonic-gate 		}
15957c478bd9Sstevel@tonic-gate 
15967c478bd9Sstevel@tonic-gate 		/* The slot is now powered on. */
15977c478bd9Sstevel@tonic-gate 
15987c478bd9Sstevel@tonic-gate 		drv_usecwait(HPC3130_ADEQUATE_PAUSE);
15997c478bd9Sstevel@tonic-gate 
16007c478bd9Sstevel@tonic-gate 		/* Extinguish the "OK-to-remove" indicator */
16017c478bd9Sstevel@tonic-gate 		(void) hpc3130_set_led(hpc3130_p, offset, HPC3130_LED_OK2REM,
16027c478bd9Sstevel@tonic-gate 		    HPC3130_ATTN_OFF);
16037c478bd9Sstevel@tonic-gate 
16047c478bd9Sstevel@tonic-gate 		/*
16057c478bd9Sstevel@tonic-gate 		 * Perform bus/card speed check functions.
16067c478bd9Sstevel@tonic-gate 		 */
16077c478bd9Sstevel@tonic-gate 		if (hpc3130_read(handle, HPC3130_STATUS, offset, &status)) {
16087c478bd9Sstevel@tonic-gate 			goto out;
16097c478bd9Sstevel@tonic-gate 		}
16107c478bd9Sstevel@tonic-gate 		if ((config & HPC3130_SYSM66STAT) &&
16117c478bd9Sstevel@tonic-gate 		    !(status & HPC3130_M66EN)) {
16127c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN, "66Mhz bus can't accept "
16137c478bd9Sstevel@tonic-gate 			    "33Mhz card in %s", phys_slot);
16147c478bd9Sstevel@tonic-gate 			needs_to_be_powered_off = B_TRUE;
16157c478bd9Sstevel@tonic-gate 			goto out;
16167c478bd9Sstevel@tonic-gate 		}
16177c478bd9Sstevel@tonic-gate 		if (!(config & HPC3130_SYSM66STAT) &&
16187c478bd9Sstevel@tonic-gate 		    (status & HPC3130_M66EN)) {
16197c478bd9Sstevel@tonic-gate 			cmn_err(CE_NOTE, "66Mhz capable card throttled "
16207c478bd9Sstevel@tonic-gate 			    "back to 33Mhz in %s", phys_slot);
16217c478bd9Sstevel@tonic-gate 		}
16227c478bd9Sstevel@tonic-gate 
16237c478bd9Sstevel@tonic-gate 		/*
16247c478bd9Sstevel@tonic-gate 		 * Send the connect sequence (see struct connect_sequence)
16257c478bd9Sstevel@tonic-gate 		 */
16267c478bd9Sstevel@tonic-gate 		for (i = 0; i < HPC3130_CONNECT_SEQ_COUNT; i++) {
16277c478bd9Sstevel@tonic-gate 			if (connect_sequence[i].set_bit == B_TRUE) {
16287c478bd9Sstevel@tonic-gate 				control |= connect_sequence[i].value;
16297c478bd9Sstevel@tonic-gate 			} else {
16307c478bd9Sstevel@tonic-gate 				control &= ~connect_sequence[i].value;
16317c478bd9Sstevel@tonic-gate 			}
16327c478bd9Sstevel@tonic-gate 			if (hpc3130_write(handle, HPC3130_CONTROL, offset,
16337c478bd9Sstevel@tonic-gate 			    control) != DDI_SUCCESS) {
16347c478bd9Sstevel@tonic-gate 				goto out;
16357c478bd9Sstevel@tonic-gate 			}
16367c478bd9Sstevel@tonic-gate 			drv_usecwait(HPC3130_ADEQUATE_PAUSE);
16377c478bd9Sstevel@tonic-gate 		}
16387c478bd9Sstevel@tonic-gate 	}
16397c478bd9Sstevel@tonic-gate 
164007d06da5SSurya Prakki 	(void) hpc_slot_event_notify(ste->hpc3130_slot_handle,
16417c478bd9Sstevel@tonic-gate 	    HPC_EVENT_SLOT_POWER_ON, 0);
16427c478bd9Sstevel@tonic-gate 
16437c478bd9Sstevel@tonic-gate 	/* Flash the "fault" indicator */
16447c478bd9Sstevel@tonic-gate 	(void) hpc3130_set_led(hpc3130_p, offset, HPC3130_LED_FAULT,
16457c478bd9Sstevel@tonic-gate 	    HPC3130_ATTN_SLO);
16467c478bd9Sstevel@tonic-gate 
16477c478bd9Sstevel@tonic-gate 	result = HPC_SUCCESS;
16487c478bd9Sstevel@tonic-gate 
16497c478bd9Sstevel@tonic-gate out:
16507c478bd9Sstevel@tonic-gate 	if (needs_to_be_powered_off == B_TRUE) {
16517c478bd9Sstevel@tonic-gate 		/*
16527c478bd9Sstevel@tonic-gate 		 * We are in an error state where the slot is powered on, and
16537c478bd9Sstevel@tonic-gate 		 * it must be powered off.
16547c478bd9Sstevel@tonic-gate 		 */
16557c478bd9Sstevel@tonic-gate 
16567c478bd9Sstevel@tonic-gate 		/* Send the power off signal and verify the result */
16577c478bd9Sstevel@tonic-gate 		control = control & ~HPC3130_SLTPWRCTL;
16587c478bd9Sstevel@tonic-gate 		if ((hpc3130_write(handle, HPC3130_CONTROL, offset,
16597c478bd9Sstevel@tonic-gate 		    control) == DDI_SUCCESS) &&
16607c478bd9Sstevel@tonic-gate 		    (hpc3130_verify_slot_power(hpc3130_p, handle, offset,
16617c478bd9Sstevel@tonic-gate 		    phys_slot, B_FALSE) == HPC_SUCCESS)) {
16627c478bd9Sstevel@tonic-gate 			/* Re-light "OK-to-remove" LED */
16637c478bd9Sstevel@tonic-gate 			(void) hpc3130_set_led(hpc3130_p, offset,
16647c478bd9Sstevel@tonic-gate 			    HPC3130_LED_OK2REM, HPC3130_ATTN_ON);
16657c478bd9Sstevel@tonic-gate 		}
16667c478bd9Sstevel@tonic-gate 	}
16677c478bd9Sstevel@tonic-gate 
16687c478bd9Sstevel@tonic-gate 	mutex_exit(&hpc3130_p->hpc3130_mutex);
16697c478bd9Sstevel@tonic-gate 
16707c478bd9Sstevel@tonic-gate 	return (result);
16717c478bd9Sstevel@tonic-gate }
16727c478bd9Sstevel@tonic-gate 
16737c478bd9Sstevel@tonic-gate 
16747c478bd9Sstevel@tonic-gate static int
hpc3130_slot_disconnect(caddr_t ops_arg,hpc_slot_t slot_hdl,void * data,uint_t flags)16757c478bd9Sstevel@tonic-gate hpc3130_slot_disconnect(caddr_t ops_arg, hpc_slot_t slot_hdl,
16767c478bd9Sstevel@tonic-gate     void *data, uint_t flags)
16777c478bd9Sstevel@tonic-gate {
16787c478bd9Sstevel@tonic-gate 	_NOTE(ARGUNUSED(slot_hdl, data, flags))
16797c478bd9Sstevel@tonic-gate 	uint8_t			control;
16807c478bd9Sstevel@tonic-gate 	uint8_t			offset;
16817c478bd9Sstevel@tonic-gate 	i2c_client_hdl_t	handle;
16827c478bd9Sstevel@tonic-gate 	hpc3130_unit_t		*hpc3130_p;
16837c478bd9Sstevel@tonic-gate 	int			result = HPC_ERR_FAILED;
16847c478bd9Sstevel@tonic-gate 	hpc3130_slot_type_t	slot_type;
16857c478bd9Sstevel@tonic-gate 	hpc3130_slot_table_entry_t *ste;
16867c478bd9Sstevel@tonic-gate 	char			phys_slot[MAXPATHLEN];
16877c478bd9Sstevel@tonic-gate 
16887c478bd9Sstevel@tonic-gate 	hpc3130_callback_arg_t	*info_p = (hpc3130_callback_arg_t *)ops_arg;
16897c478bd9Sstevel@tonic-gate 
16907c478bd9Sstevel@tonic-gate 	/*
16917c478bd9Sstevel@tonic-gate 	 * Callback parameter has specific device handle and offset
16927c478bd9Sstevel@tonic-gate 	 * information in it.
16937c478bd9Sstevel@tonic-gate 	 */
16947c478bd9Sstevel@tonic-gate 	hpc3130_p = (hpc3130_unit_t *)info_p->statep;
16957c478bd9Sstevel@tonic-gate 	ASSERT(hpc3130_p);
16967c478bd9Sstevel@tonic-gate 
16977c478bd9Sstevel@tonic-gate 	mutex_enter(&hpc3130_p->hpc3130_mutex);
16987c478bd9Sstevel@tonic-gate 
16997c478bd9Sstevel@tonic-gate 	handle = (i2c_client_hdl_t)info_p->handle;
17007c478bd9Sstevel@tonic-gate 	offset = info_p->offset;
17017c478bd9Sstevel@tonic-gate 
17027c478bd9Sstevel@tonic-gate 	ASSERT(handle == hpc3130_p->hpc3130_hdl);
17037c478bd9Sstevel@tonic-gate 
17047c478bd9Sstevel@tonic-gate 	ste = &hpc3130_p->hpc3130_slot_table[offset];
17057c478bd9Sstevel@tonic-gate 
17067c478bd9Sstevel@tonic-gate 	if (hpc3130_p->slots_are == HPC3130_SLOT_TYPE_SBD) {
17077c478bd9Sstevel@tonic-gate 		DAK_GET_SBD_APID(phys_slot, MAXPATHLEN, offset);
17087c478bd9Sstevel@tonic-gate 	} else {
17097c478bd9Sstevel@tonic-gate 		DAK_GET_PCI_APID(phys_slot, MAXPATHLEN,
17107c478bd9Sstevel@tonic-gate 		    hpc3130_lookup_slot(ste->nexus,
17117c478bd9Sstevel@tonic-gate 		    ste->hpc3130_slot_info.pci_dev_num));
17127c478bd9Sstevel@tonic-gate 	}
17137c478bd9Sstevel@tonic-gate 
17147c478bd9Sstevel@tonic-gate 	ASSERT(ste->hpc3130_slot_handle != NULL);
17157c478bd9Sstevel@tonic-gate 
17167c478bd9Sstevel@tonic-gate 	slot_type = hpc3130_p->slots_are;
17177c478bd9Sstevel@tonic-gate 
17187c478bd9Sstevel@tonic-gate 	/*
17197c478bd9Sstevel@tonic-gate 	 * Read the slot control register to get current value
17207c478bd9Sstevel@tonic-gate 	 */
17217c478bd9Sstevel@tonic-gate 	if (hpc3130_read(handle, HPC3130_CONTROL, offset,
17227c478bd9Sstevel@tonic-gate 	    &control)) {
17237c478bd9Sstevel@tonic-gate 		goto out;
17247c478bd9Sstevel@tonic-gate 	}
17257c478bd9Sstevel@tonic-gate 
17267c478bd9Sstevel@tonic-gate 	if (slot_type == HPC3130_SLOT_TYPE_SBD) {
17277c478bd9Sstevel@tonic-gate 
17287c478bd9Sstevel@tonic-gate 		D1CMN_ERR((CE_NOTE, "CPU disconnect %d", offset));
17297c478bd9Sstevel@tonic-gate 
17307c478bd9Sstevel@tonic-gate 		control = control & ~HPC3130_SLTPWRCTL;
17317c478bd9Sstevel@tonic-gate 		/*
17327c478bd9Sstevel@tonic-gate 		 * Write out the modified control register
17337c478bd9Sstevel@tonic-gate 		 */
17347c478bd9Sstevel@tonic-gate 		if (hpc3130_write(handle, HPC3130_CONTROL, offset,
17357c478bd9Sstevel@tonic-gate 		    control) != DDI_SUCCESS) {
17367c478bd9Sstevel@tonic-gate 			goto out;
17377c478bd9Sstevel@tonic-gate 		}
17387c478bd9Sstevel@tonic-gate 	} else {
17397c478bd9Sstevel@tonic-gate 
17407c478bd9Sstevel@tonic-gate 		D1CMN_ERR((CE_NOTE, "PCI disconnect %d", offset));
17417c478bd9Sstevel@tonic-gate 
17427c478bd9Sstevel@tonic-gate 		control &= ~HPC3130_SLOTRST;
17437c478bd9Sstevel@tonic-gate 		if (hpc3130_write(handle, HPC3130_CONTROL, offset,
17447c478bd9Sstevel@tonic-gate 		    control) != DDI_SUCCESS) {
17457c478bd9Sstevel@tonic-gate 			goto out;
17467c478bd9Sstevel@tonic-gate 		}
17477c478bd9Sstevel@tonic-gate 
17487c478bd9Sstevel@tonic-gate 		control |= HPC3130_BUS_CTL;
17497c478bd9Sstevel@tonic-gate 		if (hpc3130_write(handle, HPC3130_CONTROL, offset,
17507c478bd9Sstevel@tonic-gate 		    control) != DDI_SUCCESS) {
17517c478bd9Sstevel@tonic-gate 			goto out;
17527c478bd9Sstevel@tonic-gate 		}
17537c478bd9Sstevel@tonic-gate 	}
17547c478bd9Sstevel@tonic-gate 
17557c478bd9Sstevel@tonic-gate 	D1CMN_ERR((CE_WARN, "disconnect present[%d]==%d",
17567c478bd9Sstevel@tonic-gate 	    offset, hpc3130_p->present[offset]));
17577c478bd9Sstevel@tonic-gate 
17587c478bd9Sstevel@tonic-gate 	if (hpc3130_verify_slot_power(hpc3130_p, handle, offset,
17597c478bd9Sstevel@tonic-gate 	    phys_slot, B_FALSE) == HPC_ERR_FAILED) {
17607c478bd9Sstevel@tonic-gate 		goto out;
17617c478bd9Sstevel@tonic-gate 	}
17627c478bd9Sstevel@tonic-gate 
176307d06da5SSurya Prakki 	(void) hpc_slot_event_notify(ste->hpc3130_slot_handle,
17647c478bd9Sstevel@tonic-gate 	    HPC_EVENT_SLOT_POWER_OFF, 0);
17657c478bd9Sstevel@tonic-gate 
17667c478bd9Sstevel@tonic-gate 	if (hpc3130_p->present[offset] == B_TRUE) {
17677c478bd9Sstevel@tonic-gate 		/*
17687c478bd9Sstevel@tonic-gate 		 * Illuminate the "OK-to-remove" indicator
17697c478bd9Sstevel@tonic-gate 		 * if there is a card in the slot.
17707c478bd9Sstevel@tonic-gate 		 */
17717c478bd9Sstevel@tonic-gate 
17727c478bd9Sstevel@tonic-gate 		(void) hpc3130_set_led(hpc3130_p, offset, HPC3130_LED_OK2REM,
17737c478bd9Sstevel@tonic-gate 		    HPC3130_ATTN_ON);
17747c478bd9Sstevel@tonic-gate 
17757c478bd9Sstevel@tonic-gate 		/*
17767c478bd9Sstevel@tonic-gate 		 * Turn off the "fault" indicator
17777c478bd9Sstevel@tonic-gate 		 */
17787c478bd9Sstevel@tonic-gate 		(void) hpc3130_set_led(hpc3130_p, offset, HPC3130_LED_FAULT,
17797c478bd9Sstevel@tonic-gate 		    HPC3130_ATTN_OFF);
17807c478bd9Sstevel@tonic-gate 	} else {
17817c478bd9Sstevel@tonic-gate 		/*
17827c478bd9Sstevel@tonic-gate 		 * If the slot is being powered off with
17837c478bd9Sstevel@tonic-gate 		 * no cards in there, its at "boot time",
17847c478bd9Sstevel@tonic-gate 		 * put the LEDs in a sane state
17857c478bd9Sstevel@tonic-gate 		 */
17867c478bd9Sstevel@tonic-gate 		if (slot_type == HPC3130_SLOT_TYPE_PCI) {
17877c478bd9Sstevel@tonic-gate 			(void) hpc3130_set_led(hpc3130_p, offset,
17887c478bd9Sstevel@tonic-gate 			    HPC3130_LED_FAULT, HPC3130_ATTN_OFF);
17897c478bd9Sstevel@tonic-gate 			(void) hpc3130_set_led(hpc3130_p, offset,
17907c478bd9Sstevel@tonic-gate 			    HPC3130_LED_OK2REM, HPC3130_ATTN_OFF);
17917c478bd9Sstevel@tonic-gate 		}
17927c478bd9Sstevel@tonic-gate 	}
17937c478bd9Sstevel@tonic-gate 
17947c478bd9Sstevel@tonic-gate 	result = HPC_SUCCESS;
17957c478bd9Sstevel@tonic-gate out:
17967c478bd9Sstevel@tonic-gate 	mutex_exit(&hpc3130_p->hpc3130_mutex);
17977c478bd9Sstevel@tonic-gate 
17987c478bd9Sstevel@tonic-gate 	return (result);
17997c478bd9Sstevel@tonic-gate }
18007c478bd9Sstevel@tonic-gate 
18017c478bd9Sstevel@tonic-gate static int
hpc3130_verify_slot_power(hpc3130_unit_t * hpc3130_p,i2c_client_hdl_t handle,uint8_t offset,char * phys_slot,boolean_t slot_target_state)18027c478bd9Sstevel@tonic-gate hpc3130_verify_slot_power(hpc3130_unit_t *hpc3130_p, i2c_client_hdl_t handle,
18037c478bd9Sstevel@tonic-gate     uint8_t offset, char *phys_slot, boolean_t slot_target_state)
18047c478bd9Sstevel@tonic-gate {
18057c478bd9Sstevel@tonic-gate 	uint8_t			tries = 0;
18067c478bd9Sstevel@tonic-gate 	uint8_t			status;
18077c478bd9Sstevel@tonic-gate 	int			result = HPC_SUCCESS;
1808d3d50737SRafael Vanoni 	clock_t			timeleft;
1809d3d50737SRafael Vanoni 	clock_t			tm = drv_usectohz(300000);
18107c478bd9Sstevel@tonic-gate 	boolean_t		slot_actual_state;
18117c478bd9Sstevel@tonic-gate 	boolean_t		failure = B_FALSE;
18127c478bd9Sstevel@tonic-gate 	hpc3130_slot_table_entry_t *ste;
18137c478bd9Sstevel@tonic-gate 
18147c478bd9Sstevel@tonic-gate 	/* This function is called while holding the hpc3130 mutex. */
18157c478bd9Sstevel@tonic-gate 
18167c478bd9Sstevel@tonic-gate 	/*
18177c478bd9Sstevel@tonic-gate 	 * For slot_target_state and slot_actual_state:
18187c478bd9Sstevel@tonic-gate 	 *    B_TRUE  == the slot is powered on
18197c478bd9Sstevel@tonic-gate 	 *    B_FALSE == the slot is powered off
18207c478bd9Sstevel@tonic-gate 	 */
18217c478bd9Sstevel@tonic-gate 
18227c478bd9Sstevel@tonic-gate 	ste = &hpc3130_p->hpc3130_slot_table[offset];
18237c478bd9Sstevel@tonic-gate 	slot_actual_state = hpc3130_p->power[offset];
18247c478bd9Sstevel@tonic-gate 
18257c478bd9Sstevel@tonic-gate 	while ((slot_actual_state != slot_target_state) &&
18267c478bd9Sstevel@tonic-gate 	    (failure != B_TRUE)) {
1827d3d50737SRafael Vanoni 		timeleft = cv_reltimedwait(&hpc3130_p->hpc3130_cond,
1828d3d50737SRafael Vanoni 		    &hpc3130_p->hpc3130_mutex, tm, TR_CLOCK_TICK);
18297c478bd9Sstevel@tonic-gate 		if (timeleft == -1) {
18307c478bd9Sstevel@tonic-gate 			if (tries++ < HPC3130_POWER_TRIES) {
18317c478bd9Sstevel@tonic-gate 				/*
18327c478bd9Sstevel@tonic-gate 				 * The interrupt was missed - explicitly
18337c478bd9Sstevel@tonic-gate 				 * check the status.
18347c478bd9Sstevel@tonic-gate 				 */
18357c478bd9Sstevel@tonic-gate 				if (hpc3130_read(handle,
18367c478bd9Sstevel@tonic-gate 				    HPC3130_STATUS, offset, &status)) {
18377c478bd9Sstevel@tonic-gate 					failure = B_TRUE;
18387c478bd9Sstevel@tonic-gate 					continue;
18397c478bd9Sstevel@tonic-gate 				}
18407c478bd9Sstevel@tonic-gate 				if (status & HPC3130_PWRGOOD) {
18417c478bd9Sstevel@tonic-gate 					slot_actual_state = B_FALSE;
18427c478bd9Sstevel@tonic-gate 				} else {
18437c478bd9Sstevel@tonic-gate 					slot_actual_state = B_TRUE;
18447c478bd9Sstevel@tonic-gate 				}
18457c478bd9Sstevel@tonic-gate 				hpc3130_p->power[offset] = slot_actual_state;
18467c478bd9Sstevel@tonic-gate 			} else {
18477c478bd9Sstevel@tonic-gate 				/* Too many tries.  We failed. */
18487c478bd9Sstevel@tonic-gate 				failure = B_TRUE;
18497c478bd9Sstevel@tonic-gate 			}
18507c478bd9Sstevel@tonic-gate 		}
18517c478bd9Sstevel@tonic-gate 	}
18527c478bd9Sstevel@tonic-gate 
18537c478bd9Sstevel@tonic-gate 	if (failure == B_TRUE) {
18547c478bd9Sstevel@tonic-gate 		result = HPC_ERR_FAILED;
18557c478bd9Sstevel@tonic-gate 		if (slot_target_state == B_TRUE) {
18567c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN,
18577c478bd9Sstevel@tonic-gate 			    "Could not power on slot %s", phys_slot);
18587c478bd9Sstevel@tonic-gate 		} else {
18597c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN,
18607c478bd9Sstevel@tonic-gate 			    "Could not power off slot %s", phys_slot);
18617c478bd9Sstevel@tonic-gate 		}
18627c478bd9Sstevel@tonic-gate 		(void) hpc3130_set_led(hpc3130_p, offset, HPC3130_LED_FAULT,
18637c478bd9Sstevel@tonic-gate 		    HPC3130_ATTN_ON);
186407d06da5SSurya Prakki 		(void) hpc_slot_event_notify(ste->hpc3130_slot_handle,
18657c478bd9Sstevel@tonic-gate 		    HPC_EVENT_SLOT_NOT_HEALTHY, 0);
18667c478bd9Sstevel@tonic-gate 	}
18677c478bd9Sstevel@tonic-gate 
18687c478bd9Sstevel@tonic-gate 	return (result);
18697c478bd9Sstevel@tonic-gate }
18707c478bd9Sstevel@tonic-gate 
18717c478bd9Sstevel@tonic-gate static int
hpc3130_slot_insert(caddr_t ops_arg,hpc_slot_t slot_hdl,void * data,uint_t flags)18727c478bd9Sstevel@tonic-gate hpc3130_slot_insert(caddr_t ops_arg, hpc_slot_t slot_hdl,
18737c478bd9Sstevel@tonic-gate     void *data, uint_t flags)
18747c478bd9Sstevel@tonic-gate {
18757c478bd9Sstevel@tonic-gate 	_NOTE(ARGUNUSED(ops_arg, slot_hdl, data, flags))
18767c478bd9Sstevel@tonic-gate 	return (HPC_ERR_NOTSUPPORTED);
18777c478bd9Sstevel@tonic-gate }
18787c478bd9Sstevel@tonic-gate 
18797c478bd9Sstevel@tonic-gate static int
hpc3130_slot_remove(caddr_t ops_arg,hpc_slot_t slot_hdl,void * data,uint_t flags)18807c478bd9Sstevel@tonic-gate hpc3130_slot_remove(caddr_t ops_arg, hpc_slot_t slot_hdl,
18817c478bd9Sstevel@tonic-gate     void *data, uint_t flags)
18827c478bd9Sstevel@tonic-gate {
18837c478bd9Sstevel@tonic-gate 	_NOTE(ARGUNUSED(ops_arg, slot_hdl, data, flags))
18847c478bd9Sstevel@tonic-gate 	return (HPC_ERR_NOTSUPPORTED);
18857c478bd9Sstevel@tonic-gate }
18867c478bd9Sstevel@tonic-gate 
18877c478bd9Sstevel@tonic-gate static int
hpc3130_slot_control(caddr_t ops_arg,hpc_slot_t slot_hdl,int request,caddr_t arg)18887c478bd9Sstevel@tonic-gate hpc3130_slot_control(caddr_t ops_arg, hpc_slot_t slot_hdl,
18897c478bd9Sstevel@tonic-gate     int request, caddr_t arg)
18907c478bd9Sstevel@tonic-gate {
18917c478bd9Sstevel@tonic-gate 	_NOTE(ARGUNUSED(slot_hdl))
18927c478bd9Sstevel@tonic-gate 	i2c_client_hdl_t	handle;
18937c478bd9Sstevel@tonic-gate 	uint8_t			offset;
18947c478bd9Sstevel@tonic-gate 	uint8_t			state;
18957c478bd9Sstevel@tonic-gate 	hpc_led_info_t		*led_info;
18967c478bd9Sstevel@tonic-gate 	hpc3130_unit_t		*hpc3130_p;
18977c478bd9Sstevel@tonic-gate 	hpc3130_slot_type_t	slot_type;
18987c478bd9Sstevel@tonic-gate 
18997c478bd9Sstevel@tonic-gate 	hpc3130_callback_arg_t	*info_p = (hpc3130_callback_arg_t *)ops_arg;
19007c478bd9Sstevel@tonic-gate 
19017c478bd9Sstevel@tonic-gate 	/*
19027c478bd9Sstevel@tonic-gate 	 * Callback parameter has specific device handle and offset
19037c478bd9Sstevel@tonic-gate 	 * information in it.
19047c478bd9Sstevel@tonic-gate 	 */
19057c478bd9Sstevel@tonic-gate 
19067c478bd9Sstevel@tonic-gate 	hpc3130_p = (hpc3130_unit_t *)info_p->statep;
19077c478bd9Sstevel@tonic-gate 	ASSERT(hpc3130_p);
19087c478bd9Sstevel@tonic-gate 
19097c478bd9Sstevel@tonic-gate 	mutex_enter(&hpc3130_p->hpc3130_mutex);
19107c478bd9Sstevel@tonic-gate 
19117c478bd9Sstevel@tonic-gate 	handle = (i2c_client_hdl_t)info_p->handle;
19127c478bd9Sstevel@tonic-gate 	offset = info_p->offset;
19137c478bd9Sstevel@tonic-gate 
19147c478bd9Sstevel@tonic-gate 	ASSERT(handle == hpc3130_p->hpc3130_hdl);
19157c478bd9Sstevel@tonic-gate 
19167c478bd9Sstevel@tonic-gate 	slot_type = hpc3130_p->slots_are;
19177c478bd9Sstevel@tonic-gate 
19187c478bd9Sstevel@tonic-gate 	switch (request) {
19197c478bd9Sstevel@tonic-gate 		case HPC_CTRL_GET_LED_STATE: {
19207c478bd9Sstevel@tonic-gate 			int led;
19217c478bd9Sstevel@tonic-gate 
19227c478bd9Sstevel@tonic-gate 			led_info = (hpc_led_info_t *)arg;
19237c478bd9Sstevel@tonic-gate 			if (led_info->led != HPC_FAULT_LED &&
19247c478bd9Sstevel@tonic-gate 			    led_info->led != HPC_ATTN_LED) {
19257c478bd9Sstevel@tonic-gate 				D1CMN_ERR((CE_WARN,
19267c478bd9Sstevel@tonic-gate 				    "Only FAULT and ATTN leds allowed"));
19277c478bd9Sstevel@tonic-gate 				mutex_exit(&hpc3130_p->hpc3130_mutex);
19287c478bd9Sstevel@tonic-gate 				return (HPC_ERR_INVALID);
19297c478bd9Sstevel@tonic-gate 			}
19307c478bd9Sstevel@tonic-gate 
19317c478bd9Sstevel@tonic-gate 			if (led_info->led == HPC_FAULT_LED)
19327c478bd9Sstevel@tonic-gate 				led = HPC3130_LED_FAULT;
19337c478bd9Sstevel@tonic-gate 			else
19347c478bd9Sstevel@tonic-gate 				led = HPC3130_LED_OK2REM;
19357c478bd9Sstevel@tonic-gate 
19367c478bd9Sstevel@tonic-gate 			if (hpc3130_get_led(handle, offset, led, &state) !=
19377c478bd9Sstevel@tonic-gate 			    DDI_SUCCESS) {
19387c478bd9Sstevel@tonic-gate 				mutex_exit(&hpc3130_p->hpc3130_mutex);
19397c478bd9Sstevel@tonic-gate 				return (HPC_ERR_FAILED);
19407c478bd9Sstevel@tonic-gate 			}
19417c478bd9Sstevel@tonic-gate 
19427c478bd9Sstevel@tonic-gate 			/* Make sure that no one broke the conversion macros */
19437c478bd9Sstevel@tonic-gate 			ASSERT(state < sizeof (hpc3130_to_hpc_led_map));
19447c478bd9Sstevel@tonic-gate 			ASSERT(state ==
19457c478bd9Sstevel@tonic-gate 			    HPC3130_FROM_HPC_LED(HPC3130_TO_HPC_LED(state)));
19467c478bd9Sstevel@tonic-gate 
19477c478bd9Sstevel@tonic-gate 			led_info->state = HPC3130_TO_HPC_LED(state);
19487c478bd9Sstevel@tonic-gate 		}
19497c478bd9Sstevel@tonic-gate 		break;
19507c478bd9Sstevel@tonic-gate 		case HPC_CTRL_SET_LED_STATE: {
19517c478bd9Sstevel@tonic-gate 			int led;
19527c478bd9Sstevel@tonic-gate 
19537c478bd9Sstevel@tonic-gate 			/*
19547c478bd9Sstevel@tonic-gate 			 * The HPC3130 support modifications to the Fault and
19557c478bd9Sstevel@tonic-gate 			 * Ok-to-remove LEDs.
19567c478bd9Sstevel@tonic-gate 			 */
19577c478bd9Sstevel@tonic-gate 			led_info = (hpc_led_info_t *)arg;
19587c478bd9Sstevel@tonic-gate 			if (led_info->led != HPC_FAULT_LED &&
19597c478bd9Sstevel@tonic-gate 			    led_info->led != HPC_ATTN_LED) {
19607c478bd9Sstevel@tonic-gate 				D1CMN_ERR((CE_WARN,
19617c478bd9Sstevel@tonic-gate 				    "Only FAULT and ATTN leds allowed"));
19627c478bd9Sstevel@tonic-gate 				mutex_exit(&hpc3130_p->hpc3130_mutex);
19637c478bd9Sstevel@tonic-gate 				return (HPC_ERR_INVALID);
19647c478bd9Sstevel@tonic-gate 			}
19657c478bd9Sstevel@tonic-gate 
19667c478bd9Sstevel@tonic-gate 			if (led_info->led == HPC_FAULT_LED)
19677c478bd9Sstevel@tonic-gate 				led = HPC3130_LED_FAULT;
19687c478bd9Sstevel@tonic-gate 			else
19697c478bd9Sstevel@tonic-gate 				led = HPC3130_LED_OK2REM;
19707c478bd9Sstevel@tonic-gate 
19717c478bd9Sstevel@tonic-gate 			state = led_info->state;
19727c478bd9Sstevel@tonic-gate 			if (state >= sizeof (hpc3130_from_hpc_led_map) ||
19737c478bd9Sstevel@tonic-gate 			    (state != HPC3130_TO_HPC_LED(
19747c478bd9Sstevel@tonic-gate 			    HPC3130_FROM_HPC_LED(state)))) {
19757c478bd9Sstevel@tonic-gate 				D1CMN_ERR((CE_WARN,
19767c478bd9Sstevel@tonic-gate 				    "Improper LED value: %d %d", state,
19777c478bd9Sstevel@tonic-gate 				    HPC3130_TO_HPC_LED(
19787c478bd9Sstevel@tonic-gate 				    HPC3130_FROM_HPC_LED(state))));
19797c478bd9Sstevel@tonic-gate 				mutex_exit(&hpc3130_p->hpc3130_mutex);
19807c478bd9Sstevel@tonic-gate 				return (HPC_ERR_INVALID);
19817c478bd9Sstevel@tonic-gate 			}
19827c478bd9Sstevel@tonic-gate 
19837c478bd9Sstevel@tonic-gate 			(void) hpc3130_set_led(hpc3130_p, offset, led,
19847c478bd9Sstevel@tonic-gate 			    HPC3130_FROM_HPC_LED(state));
19857c478bd9Sstevel@tonic-gate 		}
19867c478bd9Sstevel@tonic-gate 		break;
19877c478bd9Sstevel@tonic-gate 		case HPC_CTRL_GET_SLOT_STATE: {
19887c478bd9Sstevel@tonic-gate 			if (hpc3130_p->power[offset] == B_FALSE) {
19897c478bd9Sstevel@tonic-gate 				if (hpc3130_p->present[offset] == B_FALSE) {
19907c478bd9Sstevel@tonic-gate 					*(ap_rstate_t *)arg =
19917c478bd9Sstevel@tonic-gate 					    AP_RSTATE_EMPTY;
19927c478bd9Sstevel@tonic-gate 				} else {
19937c478bd9Sstevel@tonic-gate 					*(ap_rstate_t *)arg =
19947c478bd9Sstevel@tonic-gate 					    AP_RSTATE_DISCONNECTED;
19957c478bd9Sstevel@tonic-gate 				}
19967c478bd9Sstevel@tonic-gate 			} else {
19977c478bd9Sstevel@tonic-gate 				*(ap_rstate_t *)arg =
19987c478bd9Sstevel@tonic-gate 				    AP_RSTATE_CONNECTED;
19997c478bd9Sstevel@tonic-gate 			}
20007c478bd9Sstevel@tonic-gate 		}
20017c478bd9Sstevel@tonic-gate 		break;
20027c478bd9Sstevel@tonic-gate 		case HPC_CTRL_GET_BOARD_TYPE: {
20037c478bd9Sstevel@tonic-gate 			*(hpc_board_type_t *)arg =
20047c478bd9Sstevel@tonic-gate 			    (slot_type == HPC3130_SLOT_TYPE_SBD ?
20057c478bd9Sstevel@tonic-gate 			    HPC_BOARD_UNKNOWN : HPC_BOARD_PCI_HOTPLUG);
20067c478bd9Sstevel@tonic-gate 		}
20077c478bd9Sstevel@tonic-gate 		break;
20087c478bd9Sstevel@tonic-gate 		case HPC_CTRL_DEV_CONFIG_START:
20097c478bd9Sstevel@tonic-gate 		case HPC_CTRL_DEV_UNCONFIG_START:
201007d06da5SSurya Prakki 			(void) hpc3130_set_led(hpc3130_p, offset,
201107d06da5SSurya Prakki 			    HPC3130_LED_FAULT, HPC3130_ATTN_SLO);
20127c478bd9Sstevel@tonic-gate 		break;
20137c478bd9Sstevel@tonic-gate 		case HPC_CTRL_DEV_CONFIG_FAILURE:
201407d06da5SSurya Prakki 			(void) hpc3130_set_led(hpc3130_p, offset,
201507d06da5SSurya Prakki 			    HPC3130_LED_FAULT, HPC3130_ATTN_ON);
20167c478bd9Sstevel@tonic-gate 		break;
20177c478bd9Sstevel@tonic-gate 		case HPC_CTRL_DEV_CONFIGURED:
201807d06da5SSurya Prakki 			(void) hpc3130_set_led(hpc3130_p, offset,
201907d06da5SSurya Prakki 			    HPC3130_LED_FAULT, HPC3130_ATTN_OFF);
20207c478bd9Sstevel@tonic-gate 			hpc3130_p->present[offset] = B_TRUE;
20217c478bd9Sstevel@tonic-gate 		break;
20227c478bd9Sstevel@tonic-gate 		case HPC_CTRL_DEV_UNCONFIGURED:
20237c478bd9Sstevel@tonic-gate 			if (hpc3130_p->power[offset] == B_TRUE) {
202407d06da5SSurya Prakki 				(void) hpc3130_set_led(hpc3130_p, offset,
20257c478bd9Sstevel@tonic-gate 				    HPC3130_LED_FAULT, HPC3130_ATTN_SLO);
20267c478bd9Sstevel@tonic-gate 			} else {
202707d06da5SSurya Prakki 				(void) hpc3130_set_led(hpc3130_p, offset,
20287c478bd9Sstevel@tonic-gate 				    HPC3130_LED_FAULT, HPC3130_ATTN_OFF);
20297c478bd9Sstevel@tonic-gate 			}
20307c478bd9Sstevel@tonic-gate 		break;
20317c478bd9Sstevel@tonic-gate 		case HPC_CTRL_DISABLE_SLOT: {
20327c478bd9Sstevel@tonic-gate 			hpc3130_p->enabled[offset] = B_FALSE;
20337c478bd9Sstevel@tonic-gate 		}
20347c478bd9Sstevel@tonic-gate 		break;
20357c478bd9Sstevel@tonic-gate 		case HPC_CTRL_ENABLE_SLOT: {
20367c478bd9Sstevel@tonic-gate 			hpc3130_p->enabled[offset] = B_TRUE;
20377c478bd9Sstevel@tonic-gate 		}
20387c478bd9Sstevel@tonic-gate 		break;
20397c478bd9Sstevel@tonic-gate 		default:
20407c478bd9Sstevel@tonic-gate 			mutex_exit(&hpc3130_p->hpc3130_mutex);
20417c478bd9Sstevel@tonic-gate 			return (HPC_ERR_FAILED);
20427c478bd9Sstevel@tonic-gate 	}
20437c478bd9Sstevel@tonic-gate 	mutex_exit(&hpc3130_p->hpc3130_mutex);
20447c478bd9Sstevel@tonic-gate 	return (HPC_SUCCESS);
20457c478bd9Sstevel@tonic-gate }
20467c478bd9Sstevel@tonic-gate 
20477c478bd9Sstevel@tonic-gate int
hpc3130_lookup_slot(char * nexus,int pcidev)20487c478bd9Sstevel@tonic-gate hpc3130_lookup_slot(char *nexus, int pcidev)
20497c478bd9Sstevel@tonic-gate {
20507c478bd9Sstevel@tonic-gate 	int	i = 0;
20517c478bd9Sstevel@tonic-gate 
2052*baa111a1SToomas Soome 	while (i < HPC3130_LOOKUP_SLOTS &&
2053*baa111a1SToomas Soome 	    (slot_translate[i].pcidev != pcidev ||
2054*baa111a1SToomas Soome 	    strcmp(nexus, slot_translate[i].nexus) != 0))
205519397407SSherry Moore 		i++;
20567c478bd9Sstevel@tonic-gate 	ASSERT(i != HPC3130_LOOKUP_SLOTS);
20577c478bd9Sstevel@tonic-gate 	return (i);
20587c478bd9Sstevel@tonic-gate }
20597c478bd9Sstevel@tonic-gate 
20607c478bd9Sstevel@tonic-gate /*
20617c478bd9Sstevel@tonic-gate  * A routine to convert a number (represented as a string) to
20627c478bd9Sstevel@tonic-gate  * the integer value it represents.
20637c478bd9Sstevel@tonic-gate  */
20647c478bd9Sstevel@tonic-gate 
20657c478bd9Sstevel@tonic-gate static int
isdigit(int ch)20667c478bd9Sstevel@tonic-gate isdigit(int ch)
20677c478bd9Sstevel@tonic-gate {
20687c478bd9Sstevel@tonic-gate 	return (ch >= '0' && ch <= '9');
20697c478bd9Sstevel@tonic-gate }
20707c478bd9Sstevel@tonic-gate 
20717c478bd9Sstevel@tonic-gate #define	isspace(c)	((c) == ' ' || (c) == '\t' || (c) == '\n')
20727c478bd9Sstevel@tonic-gate #define	bad(val)	(val == NULL || !isdigit(*val))
20737c478bd9Sstevel@tonic-gate 
20747c478bd9Sstevel@tonic-gate static int
hpc3130_atoi(const char * p)20757c478bd9Sstevel@tonic-gate hpc3130_atoi(const char *p)
20767c478bd9Sstevel@tonic-gate {
20777c478bd9Sstevel@tonic-gate 	int n;
20787c478bd9Sstevel@tonic-gate 	int c, neg = 0;
20797c478bd9Sstevel@tonic-gate 
20807c478bd9Sstevel@tonic-gate 	if (!isdigit(c = *p)) {
20817c478bd9Sstevel@tonic-gate 		while (isspace(c))
20827c478bd9Sstevel@tonic-gate 			c = *++p;
20837c478bd9Sstevel@tonic-gate 		switch (c) {
20847c478bd9Sstevel@tonic-gate 		case '-':
20857c478bd9Sstevel@tonic-gate 			neg++;
20867c478bd9Sstevel@tonic-gate 			/* FALLTHROUGH */
20877c478bd9Sstevel@tonic-gate 		case '+':
20887c478bd9Sstevel@tonic-gate 			c = *++p;
20897c478bd9Sstevel@tonic-gate 		}
20907c478bd9Sstevel@tonic-gate 		if (!isdigit(c))
20917c478bd9Sstevel@tonic-gate 			return (0);
20927c478bd9Sstevel@tonic-gate 	}
20937c478bd9Sstevel@tonic-gate 	for (n = '0' - c; isdigit(c = *++p); ) {
20947c478bd9Sstevel@tonic-gate 		n *= 10; /* two steps to avoid unnecessary overflow */
20957c478bd9Sstevel@tonic-gate 		n += '0' - c; /* accum neg to avoid surprises at MAX */
20967c478bd9Sstevel@tonic-gate 	}
20977c478bd9Sstevel@tonic-gate 	return (neg ? n : -n);
20987c478bd9Sstevel@tonic-gate }
2099