xref: /illumos-gate/usr/src/uts/sun4u/io/sbd_io.c (revision df3cd224)
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
525e8c5aaSvikram  * Common Development and Distribution License (the "License").
625e8c5aaSvikram  * 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 /*
22*df3cd224SVijay S Balakrishna  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate #include <sys/debug.h>
277c478bd9Sstevel@tonic-gate #include <sys/types.h>
287c478bd9Sstevel@tonic-gate #include <sys/errno.h>
297c478bd9Sstevel@tonic-gate #include <sys/cred.h>
307c478bd9Sstevel@tonic-gate #include <sys/dditypes.h>
317c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
327c478bd9Sstevel@tonic-gate #include <sys/sunndi.h>
337c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
347c478bd9Sstevel@tonic-gate #include <sys/ddi_impldefs.h>
357c478bd9Sstevel@tonic-gate #include <sys/ndi_impldefs.h>
367c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
377c478bd9Sstevel@tonic-gate #include <sys/note.h>
387c478bd9Sstevel@tonic-gate 
397c478bd9Sstevel@tonic-gate #include <sys/sbdpriv.h>
407c478bd9Sstevel@tonic-gate #include <sys/sbd_io.h>
417c478bd9Sstevel@tonic-gate #include <sys/machsystm.h>
427c478bd9Sstevel@tonic-gate 
437c478bd9Sstevel@tonic-gate 
447c478bd9Sstevel@tonic-gate extern void sbd_errno_decode(int err, sbderror_t *ep, dev_info_t *dip);
457c478bd9Sstevel@tonic-gate extern sbd_state_t ostate_cvt(sbd_istate_t);
467c478bd9Sstevel@tonic-gate 
477c478bd9Sstevel@tonic-gate /*
487c478bd9Sstevel@tonic-gate  * Given a dev_info_t of a branch root, walk down the
497c478bd9Sstevel@tonic-gate  * branch to attach drivers
507c478bd9Sstevel@tonic-gate  */
517c478bd9Sstevel@tonic-gate /*ARGSUSED*/
527c478bd9Sstevel@tonic-gate void
sbd_attach_io(sbd_handle_t * hp,sbderror_t * ep,dev_info_t * dip,int unit)537c478bd9Sstevel@tonic-gate sbd_attach_io(sbd_handle_t *hp, sbderror_t *ep, dev_info_t *dip, int unit)
547c478bd9Sstevel@tonic-gate {
557c478bd9Sstevel@tonic-gate 	sbd_board_t	*sbp = SBDH2BD(hp->h_sbd);
567c478bd9Sstevel@tonic-gate 
577c478bd9Sstevel@tonic-gate 	ASSERT(e_ddi_branch_held(dip));
587c478bd9Sstevel@tonic-gate 
597c478bd9Sstevel@tonic-gate 	(void) e_ddi_branch_configure(dip, NULL, 0);
607c478bd9Sstevel@tonic-gate 
617c478bd9Sstevel@tonic-gate 	ASSERT(sbp->sb_iopath[unit] != NULL);
627c478bd9Sstevel@tonic-gate 
637c478bd9Sstevel@tonic-gate 	(void) ddi_pathname(dip, sbp->sb_iopath[unit]);
647c478bd9Sstevel@tonic-gate }
657c478bd9Sstevel@tonic-gate 
667c478bd9Sstevel@tonic-gate /*
677c478bd9Sstevel@tonic-gate  * remove device nodes for the branch indicated by dip
687c478bd9Sstevel@tonic-gate  * Hold the status lock so that status can safely do ddi_pathname().
697c478bd9Sstevel@tonic-gate  */
707c478bd9Sstevel@tonic-gate /*ARGSUSED*/
717c478bd9Sstevel@tonic-gate void
sbd_detach_io(sbd_handle_t * hp,sbderror_t * ep,dev_info_t * dip,int unit)727c478bd9Sstevel@tonic-gate sbd_detach_io(sbd_handle_t *hp, sbderror_t *ep, dev_info_t *dip, int unit)
737c478bd9Sstevel@tonic-gate {
747c478bd9Sstevel@tonic-gate 	int rv;
757c478bd9Sstevel@tonic-gate 	dev_info_t *fdip = NULL;
767c478bd9Sstevel@tonic-gate 	sbd_board_t *sbp = SBDH2BD(hp->h_sbd);
777c478bd9Sstevel@tonic-gate 
787c478bd9Sstevel@tonic-gate 	ASSERT(e_ddi_branch_held(dip));
797c478bd9Sstevel@tonic-gate 	mutex_enter(&sbp->sb_slock);
807c478bd9Sstevel@tonic-gate 	rv = e_ddi_branch_unconfigure(dip, &fdip, DEVI_BRANCH_EVENT);
817c478bd9Sstevel@tonic-gate 	mutex_exit(&sbp->sb_slock);
827c478bd9Sstevel@tonic-gate 	if (rv) {
837c478bd9Sstevel@tonic-gate 		/*
847c478bd9Sstevel@tonic-gate 		 * If non-NULL, fdip is returned held and must be released.
857c478bd9Sstevel@tonic-gate 		 */
867c478bd9Sstevel@tonic-gate 		if (fdip != NULL) {
877c478bd9Sstevel@tonic-gate 			sbd_errno_decode(rv, ep, fdip);
887c478bd9Sstevel@tonic-gate 			ddi_release_devi(fdip);
897c478bd9Sstevel@tonic-gate 		} else {
907c478bd9Sstevel@tonic-gate 			sbd_errno_decode(rv, ep, dip);
917c478bd9Sstevel@tonic-gate 		}
927c478bd9Sstevel@tonic-gate 	}
937c478bd9Sstevel@tonic-gate }
947c478bd9Sstevel@tonic-gate 
957c478bd9Sstevel@tonic-gate /*ARGSUSED*/
967c478bd9Sstevel@tonic-gate void
sbd_init_io_unit(sbd_board_t * sbp,int unit)977c478bd9Sstevel@tonic-gate sbd_init_io_unit(sbd_board_t *sbp, int unit)
987c478bd9Sstevel@tonic-gate {
997c478bd9Sstevel@tonic-gate 	sbd_istate_t	new_state;
1007c478bd9Sstevel@tonic-gate 	sbd_io_unit_t	*ip;
1017c478bd9Sstevel@tonic-gate 	dev_info_t	*dip;
1027c478bd9Sstevel@tonic-gate 
1037c478bd9Sstevel@tonic-gate 	ip = SBD_GET_BOARD_IOUNIT(sbp, unit);
1047c478bd9Sstevel@tonic-gate 
1057c478bd9Sstevel@tonic-gate 	if (SBD_DEV_IS_ATTACHED(sbp, SBD_COMP_IO, unit)) {
1067c478bd9Sstevel@tonic-gate 		new_state = SBD_STATE_CONFIGURED;
1077c478bd9Sstevel@tonic-gate 	} else if (SBD_DEV_IS_PRESENT(sbp, SBD_COMP_IO, unit)) {
1087c478bd9Sstevel@tonic-gate 		new_state = SBD_STATE_CONNECTED;
1097c478bd9Sstevel@tonic-gate 	} else {
1107c478bd9Sstevel@tonic-gate 		new_state = SBD_STATE_EMPTY;
1117c478bd9Sstevel@tonic-gate 	}
1127c478bd9Sstevel@tonic-gate 	dip = sbp->sb_devlist[NIX(SBD_COMP_IO)][unit];
1137c478bd9Sstevel@tonic-gate 	ip->sbi_cm.sbdev_cond = sbd_get_comp_cond(dip);
1147c478bd9Sstevel@tonic-gate 
1157c478bd9Sstevel@tonic-gate 	/*
1167c478bd9Sstevel@tonic-gate 	 * Any changes to this io component should be performed above
1177c478bd9Sstevel@tonic-gate 	 * this call to ensure the component is fully initialized
1187c478bd9Sstevel@tonic-gate 	 * before transitioning to the new state.
1197c478bd9Sstevel@tonic-gate 	 */
1207c478bd9Sstevel@tonic-gate 	SBD_DEVICE_TRANSITION(sbp, SBD_COMP_IO, unit, new_state);
1217c478bd9Sstevel@tonic-gate }
1227c478bd9Sstevel@tonic-gate 
1237c478bd9Sstevel@tonic-gate /*ARGSUSED*/
1247c478bd9Sstevel@tonic-gate int
sbd_disconnect_io(sbd_handle_t * hp,int unit)1257c478bd9Sstevel@tonic-gate sbd_disconnect_io(sbd_handle_t *hp, int unit)
1267c478bd9Sstevel@tonic-gate {
1277c478bd9Sstevel@tonic-gate 	return (0);
1287c478bd9Sstevel@tonic-gate }
1297c478bd9Sstevel@tonic-gate 
1307c478bd9Sstevel@tonic-gate int
sbd_pre_attach_io(sbd_handle_t * hp,sbd_devlist_t * devlist,int devnum)1317c478bd9Sstevel@tonic-gate sbd_pre_attach_io(sbd_handle_t *hp, sbd_devlist_t *devlist, int devnum)
1327c478bd9Sstevel@tonic-gate {
1337c478bd9Sstevel@tonic-gate 	_NOTE(ARGUNUSED(hp))
1347c478bd9Sstevel@tonic-gate 	_NOTE(ARGUNUSED(devlist))
1357c478bd9Sstevel@tonic-gate 	_NOTE(ARGUNUSED(devnum))
1367c478bd9Sstevel@tonic-gate 
1377c478bd9Sstevel@tonic-gate 	return (0);
1387c478bd9Sstevel@tonic-gate }
1397c478bd9Sstevel@tonic-gate 
1407c478bd9Sstevel@tonic-gate /*ARGSUSED*/
1417c478bd9Sstevel@tonic-gate int
sbd_pre_detach_io(sbd_handle_t * hp,sbd_devlist_t * devlist,int devnum)1427c478bd9Sstevel@tonic-gate sbd_pre_detach_io(sbd_handle_t *hp, sbd_devlist_t *devlist, int devnum)
1437c478bd9Sstevel@tonic-gate {
1447c478bd9Sstevel@tonic-gate 	fn_t	f = "sbd_pre_detach_io";
1457c478bd9Sstevel@tonic-gate 
1467c478bd9Sstevel@tonic-gate 	PR_IO("%s...\n", f);
1477c478bd9Sstevel@tonic-gate 
1487c478bd9Sstevel@tonic-gate 	if (devnum <= 0)
1497c478bd9Sstevel@tonic-gate 		return (-1);
1507c478bd9Sstevel@tonic-gate 
1517c478bd9Sstevel@tonic-gate 	/* fail if any I/O devices are referenced */
1527c478bd9Sstevel@tonic-gate 	if (sbd_check_io_refs(hp, devlist, devnum) > 0) {
1537c478bd9Sstevel@tonic-gate 		PR_IO("%s: failed - I/O devices ref'd\n", f);
1547c478bd9Sstevel@tonic-gate 		return (-1);
1557c478bd9Sstevel@tonic-gate 	}
1567c478bd9Sstevel@tonic-gate 
1577c478bd9Sstevel@tonic-gate 	return (0);
1587c478bd9Sstevel@tonic-gate }
1597c478bd9Sstevel@tonic-gate 
1607c478bd9Sstevel@tonic-gate /*ARGSUSED*/
1617c478bd9Sstevel@tonic-gate int
sbd_post_attach_io(sbd_handle_t * hp,sbd_devlist_t * devlist,int devnum)1627c478bd9Sstevel@tonic-gate sbd_post_attach_io(sbd_handle_t *hp, sbd_devlist_t *devlist, int devnum)
1637c478bd9Sstevel@tonic-gate {
1647c478bd9Sstevel@tonic-gate 	_NOTE(ARGUNUSED(hp))
1657c478bd9Sstevel@tonic-gate 	_NOTE(ARGUNUSED(devlist))
1667c478bd9Sstevel@tonic-gate 	_NOTE(ARGUNUSED(devnum))
1677c478bd9Sstevel@tonic-gate 
1687c478bd9Sstevel@tonic-gate 	return (0);
1697c478bd9Sstevel@tonic-gate }
1707c478bd9Sstevel@tonic-gate 
1717c478bd9Sstevel@tonic-gate /*ARGSUSED*/
1727c478bd9Sstevel@tonic-gate int
sbd_post_detach_io(sbd_handle_t * hp,sbd_devlist_t * devlist,int devnum)1737c478bd9Sstevel@tonic-gate sbd_post_detach_io(sbd_handle_t *hp, sbd_devlist_t *devlist, int devnum)
1747c478bd9Sstevel@tonic-gate {
1757c478bd9Sstevel@tonic-gate 	return (0);
1767c478bd9Sstevel@tonic-gate }
1777c478bd9Sstevel@tonic-gate 
1787c478bd9Sstevel@tonic-gate /*ARGSUSED*/
1797c478bd9Sstevel@tonic-gate int
sbd_io_status(sbd_handle_t * hp,sbd_devset_t devset,sbd_dev_stat_t * dsp)1807c478bd9Sstevel@tonic-gate sbd_io_status(sbd_handle_t *hp, sbd_devset_t devset, sbd_dev_stat_t *dsp)
1817c478bd9Sstevel@tonic-gate {
1827c478bd9Sstevel@tonic-gate 	int		i, ix;
1837c478bd9Sstevel@tonic-gate 	sbd_board_t	*sbp;
1847c478bd9Sstevel@tonic-gate 	sbd_io_stat_t	*isp;
1857c478bd9Sstevel@tonic-gate 	sbd_io_unit_t	*ip;
1867c478bd9Sstevel@tonic-gate 	sbd_istate_t	dstate;
1877c478bd9Sstevel@tonic-gate 	sbdp_handle_t	*hdp;
1887c478bd9Sstevel@tonic-gate 	sbderror_t	*ep;
1897c478bd9Sstevel@tonic-gate 	sbd_error_t	*sep;
1907c478bd9Sstevel@tonic-gate 
1917c478bd9Sstevel@tonic-gate 	/*
1927c478bd9Sstevel@tonic-gate 	 * Only look for requested devices that are actually present.
1937c478bd9Sstevel@tonic-gate 	 */
1947c478bd9Sstevel@tonic-gate 	sbp = SBDH2BD(hp->h_sbd);
1957c478bd9Sstevel@tonic-gate 
1967c478bd9Sstevel@tonic-gate 	ep = HD2MACHERR(hp);
1977c478bd9Sstevel@tonic-gate 	sep = kmem_zalloc(sizeof (sbd_error_t), KM_SLEEP);
1987c478bd9Sstevel@tonic-gate 	hdp = sbd_get_sbdp_handle(sbp, hp);
1997c478bd9Sstevel@tonic-gate 
2007c478bd9Sstevel@tonic-gate 	/*
2017c478bd9Sstevel@tonic-gate 	 * Concurrent status and unconfigure, disconnect are allowed.
2027c478bd9Sstevel@tonic-gate 	 * To prevent DR code from accessing stale dips, check the
2037c478bd9Sstevel@tonic-gate 	 * present devset and access the dips with status lock held.
2047c478bd9Sstevel@tonic-gate 	 * Disconnect and unconfigure code change dip state with
2057c478bd9Sstevel@tonic-gate 	 * status lock (sb_slock) held.
2067c478bd9Sstevel@tonic-gate 	 */
2077c478bd9Sstevel@tonic-gate 	mutex_enter(&sbp->sb_slock);
2087c478bd9Sstevel@tonic-gate 
2097c478bd9Sstevel@tonic-gate 	devset &= SBD_DEVS_PRESENT(sbp);
2107c478bd9Sstevel@tonic-gate 
2117c478bd9Sstevel@tonic-gate 	for (i = ix = 0; i < MAX_IO_UNITS_PER_BOARD; i++) {
2127c478bd9Sstevel@tonic-gate 		dev_info_t	*dip;
2137c478bd9Sstevel@tonic-gate 		int		unit;
2147c478bd9Sstevel@tonic-gate 		int		namelen;
2157c478bd9Sstevel@tonic-gate 		int		refcount = 0;
2167c478bd9Sstevel@tonic-gate 
2177c478bd9Sstevel@tonic-gate 		if (DEVSET_IN_SET(devset, SBD_COMP_IO, i) == 0)
2187c478bd9Sstevel@tonic-gate 			continue;
2197c478bd9Sstevel@tonic-gate 		/*
2207c478bd9Sstevel@tonic-gate 		 * Check to make sure the io component is in a state
2217c478bd9Sstevel@tonic-gate 		 * where its fully initialized.
2227c478bd9Sstevel@tonic-gate 		 */
2237c478bd9Sstevel@tonic-gate 		if (SBD_DEVICE_STATE(sbp, SBD_COMP_IO, i) == SBD_STATE_EMPTY)
2247c478bd9Sstevel@tonic-gate 			continue;
2257c478bd9Sstevel@tonic-gate 
2267c478bd9Sstevel@tonic-gate 		dip = sbp->sb_devlist[NIX(SBD_COMP_IO)][i];
2277c478bd9Sstevel@tonic-gate 		if (dip == NULL)
2287c478bd9Sstevel@tonic-gate 			continue;
2297c478bd9Sstevel@tonic-gate 
2307c478bd9Sstevel@tonic-gate 		isp = &dsp->d_io;
2317c478bd9Sstevel@tonic-gate 
2327c478bd9Sstevel@tonic-gate 		bzero((caddr_t)isp, sizeof (*isp));
2337c478bd9Sstevel@tonic-gate 		namelen = sizeof (isp->is_name);
2347c478bd9Sstevel@tonic-gate 		(void) ddi_getlongprop_buf(DDI_DEV_T_ANY, dip,
2357c478bd9Sstevel@tonic-gate 		    DDI_PROP_DONTPASS, OBP_DEVICETYPE,
2367c478bd9Sstevel@tonic-gate 		    (caddr_t)isp->is_name, &namelen);
2377c478bd9Sstevel@tonic-gate 
2387c478bd9Sstevel@tonic-gate 		isp->is_unit = sbdp_get_unit_num(hdp, dip);
2397c478bd9Sstevel@tonic-gate 		if (isp->is_unit < 0) {
2407c478bd9Sstevel@tonic-gate 			if (hp->h_flags & SBD_IOCTL_FLAG_FORCE)
2417c478bd9Sstevel@tonic-gate 				continue;
2427c478bd9Sstevel@tonic-gate 			else {
2437c478bd9Sstevel@tonic-gate 				SBD_GET_PERR(hdp->h_err, SBD_HD2ERR(hp));
2447c478bd9Sstevel@tonic-gate 				break;
2457c478bd9Sstevel@tonic-gate 			}
2467c478bd9Sstevel@tonic-gate 		}
2477c478bd9Sstevel@tonic-gate 		unit = isp->is_unit;
2487c478bd9Sstevel@tonic-gate 
2497c478bd9Sstevel@tonic-gate 		dstate = SBD_DEVICE_STATE(sbp, SBD_COMP_IO, unit);
2507c478bd9Sstevel@tonic-gate 		isp->is_ostate	= ostate_cvt(dstate);
2517c478bd9Sstevel@tonic-gate 		isp->is_type = SBD_COMP_IO;
2527c478bd9Sstevel@tonic-gate 		ip = SBD_GET_BOARD_IOUNIT(sbp, unit);
25325e8c5aaSvikram 		ip->sbi_cm.sbdev_cond = sbd_get_comp_cond(dip);
2547c478bd9Sstevel@tonic-gate 		isp->is_cm.c_cond = ip->sbi_cm.sbdev_cond;
2557c478bd9Sstevel@tonic-gate 		isp->is_cm.c_busy = ip->sbi_cm.sbdev_busy;
2567c478bd9Sstevel@tonic-gate 		isp->is_cm.c_time = ip->sbi_cm.sbdev_time;
2577c478bd9Sstevel@tonic-gate 
2587c478bd9Sstevel@tonic-gate 
2597c478bd9Sstevel@tonic-gate 		/*
2607c478bd9Sstevel@tonic-gate 		 * This is safe to do as unconfigure and disconnect
2617c478bd9Sstevel@tonic-gate 		 * hold the status lock while changing dip state.
2627c478bd9Sstevel@tonic-gate 		 */
2637c478bd9Sstevel@tonic-gate 		(void) ddi_pathname(dip, isp->is_pathname);
2647c478bd9Sstevel@tonic-gate 
2657c478bd9Sstevel@tonic-gate 		/*
2667c478bd9Sstevel@tonic-gate 		 * We use a dummy handle in which to collect
2677c478bd9Sstevel@tonic-gate 		 * the major numbers of unsafe devices.
2687c478bd9Sstevel@tonic-gate 		 */
269*df3cd224SVijay S Balakrishna 		sbdp_check_devices(dip, &refcount, sep, NULL);
2707c478bd9Sstevel@tonic-gate 
2717c478bd9Sstevel@tonic-gate 		isp->is_referenced = (refcount == 0) ? 0 : 1;
2727c478bd9Sstevel@tonic-gate 
2737c478bd9Sstevel@tonic-gate 		isp->is_unsafe_count = 0;
2747c478bd9Sstevel@tonic-gate 
2757c478bd9Sstevel@tonic-gate 		/*
2767c478bd9Sstevel@tonic-gate 		 * Reset error field since we don't care about
2777c478bd9Sstevel@tonic-gate 		 * errors at this level.  The unsafe devices
2787c478bd9Sstevel@tonic-gate 		 * will be reported in the structure.
2797c478bd9Sstevel@tonic-gate 		 */
2807c478bd9Sstevel@tonic-gate 		SBD_SET_ERR(ep, ESBD_NOERROR);
2817c478bd9Sstevel@tonic-gate 		ep->e_rsc[0] = '\0';
2827c478bd9Sstevel@tonic-gate 
2837c478bd9Sstevel@tonic-gate 		ix++;
2847c478bd9Sstevel@tonic-gate 		dsp++;
2857c478bd9Sstevel@tonic-gate 	}
2867c478bd9Sstevel@tonic-gate 
2877c478bd9Sstevel@tonic-gate 	mutex_exit(&sbp->sb_slock);
2887c478bd9Sstevel@tonic-gate 
2897c478bd9Sstevel@tonic-gate 	kmem_free(sep, sizeof (sbd_error_t));
2907c478bd9Sstevel@tonic-gate 	sbd_release_sbdp_handle(hdp);
2917c478bd9Sstevel@tonic-gate 
2927c478bd9Sstevel@tonic-gate 	return (ix);
2937c478bd9Sstevel@tonic-gate }
2947c478bd9Sstevel@tonic-gate 
2957c478bd9Sstevel@tonic-gate /*ARGSUSED*/
2967c478bd9Sstevel@tonic-gate int
sbd_io_cnt(sbd_handle_t * hp,sbd_devset_t devset)2977c478bd9Sstevel@tonic-gate sbd_io_cnt(sbd_handle_t *hp, sbd_devset_t devset)
2987c478bd9Sstevel@tonic-gate {
2997c478bd9Sstevel@tonic-gate 	int		i, ix;
3007c478bd9Sstevel@tonic-gate 	sbd_board_t	*sbp;
3017c478bd9Sstevel@tonic-gate 
3027c478bd9Sstevel@tonic-gate 	sbp = SBDH2BD(hp->h_sbd);
3037c478bd9Sstevel@tonic-gate 
3047c478bd9Sstevel@tonic-gate 	/*
3057c478bd9Sstevel@tonic-gate 	 * Only look for requested devices that are actually present.
3067c478bd9Sstevel@tonic-gate 	 */
3077c478bd9Sstevel@tonic-gate 	devset &= SBD_DEVS_PRESENT(sbp);
3087c478bd9Sstevel@tonic-gate 
3097c478bd9Sstevel@tonic-gate 	for (i = ix = 0; i < MAX_IO_UNITS_PER_BOARD; i++) {
3107c478bd9Sstevel@tonic-gate 		dev_info_t	*dip;
3117c478bd9Sstevel@tonic-gate 
3127c478bd9Sstevel@tonic-gate 		if (DEVSET_IN_SET(devset, SBD_COMP_IO, i) == 0)
3137c478bd9Sstevel@tonic-gate 			continue;
3147c478bd9Sstevel@tonic-gate 
3157c478bd9Sstevel@tonic-gate 		dip = sbp->sb_devlist[NIX(SBD_COMP_IO)][i];
3167c478bd9Sstevel@tonic-gate 		if (dip == NULL)
3177c478bd9Sstevel@tonic-gate 			continue;
3187c478bd9Sstevel@tonic-gate 
3197c478bd9Sstevel@tonic-gate 		ix++;
3207c478bd9Sstevel@tonic-gate 	}
3217c478bd9Sstevel@tonic-gate 
3227c478bd9Sstevel@tonic-gate 	return (ix);
3237c478bd9Sstevel@tonic-gate }
3247c478bd9Sstevel@tonic-gate 
3257c478bd9Sstevel@tonic-gate int
sbd_check_io_refs(sbd_handle_t * hp,sbd_devlist_t devlist[],int devnum)3267c478bd9Sstevel@tonic-gate sbd_check_io_refs(sbd_handle_t *hp, sbd_devlist_t devlist[], int devnum)
3277c478bd9Sstevel@tonic-gate {
3287c478bd9Sstevel@tonic-gate 	register int	i, reftotal = 0;
3297c478bd9Sstevel@tonic-gate 	fn_t	f = "sbd_check_io_refs";
3307c478bd9Sstevel@tonic-gate 	sbd_error_t *sep;
3317c478bd9Sstevel@tonic-gate 	sbderror_t *ep;
3327c478bd9Sstevel@tonic-gate 
3337c478bd9Sstevel@tonic-gate 	sep = kmem_zalloc(sizeof (sbd_error_t), KM_SLEEP);
3347c478bd9Sstevel@tonic-gate 	ep = HD2MACHERR(hp);
3357c478bd9Sstevel@tonic-gate 
3367c478bd9Sstevel@tonic-gate 	for (i = 0; i < devnum; i++) {
3377c478bd9Sstevel@tonic-gate 		dev_info_t	*dip;
3387c478bd9Sstevel@tonic-gate 		int		ref;
339*df3cd224SVijay S Balakrishna 		int		refcount_non_gldv3;
3407c478bd9Sstevel@tonic-gate 
3417c478bd9Sstevel@tonic-gate 		dip = devlist[i].dv_dip;
3427c478bd9Sstevel@tonic-gate 		ref = 0;
343*df3cd224SVijay S Balakrishna 		refcount_non_gldv3 = 0;
344*df3cd224SVijay S Balakrishna 		sbdp_check_devices(dip, &ref, sep, &refcount_non_gldv3);
345*df3cd224SVijay S Balakrishna 		ASSERT(refcount_non_gldv3 >= 0);
346*df3cd224SVijay S Balakrishna 		ASSERT(ref >= refcount_non_gldv3);
347*df3cd224SVijay S Balakrishna 		/*
348*df3cd224SVijay S Balakrishna 		 * Ignore reference counts of non-gldv3 network devices
349*df3cd224SVijay S Balakrishna 		 * as Crossbow creates reference counts for non-active
350*df3cd224SVijay S Balakrishna 		 * (unplumbed) instances.  Reference count check in
351*df3cd224SVijay S Balakrishna 		 * detach() known to prevent device from detaching
352*df3cd224SVijay S Balakrishna 		 * as necessary.
353*df3cd224SVijay S Balakrishna 		 */
354*df3cd224SVijay S Balakrishna 		ref -= refcount_non_gldv3;
3557c478bd9Sstevel@tonic-gate 		if (ref) {
3567c478bd9Sstevel@tonic-gate 			if (SBD_GET_ERR(ep) == 0) {
3577c478bd9Sstevel@tonic-gate 				SBD_GET_PERR(sep, ep);
3587c478bd9Sstevel@tonic-gate 			}
3597c478bd9Sstevel@tonic-gate 			SBD_GET_PERR(sep, &devlist[i].dv_error);
3607c478bd9Sstevel@tonic-gate 		}
361*df3cd224SVijay S Balakrishna 		PR_IO("%s: dip(%s) ref = %d\n", f, ddi_get_name(dip), ref);
3627c478bd9Sstevel@tonic-gate 		reftotal += ref;
3637c478bd9Sstevel@tonic-gate 	}
3647c478bd9Sstevel@tonic-gate 
3657c478bd9Sstevel@tonic-gate 	kmem_free(sep, sizeof (sbd_error_t));
3667c478bd9Sstevel@tonic-gate 
3677c478bd9Sstevel@tonic-gate 	return (reftotal);
3687c478bd9Sstevel@tonic-gate }
3697c478bd9Sstevel@tonic-gate 
3707c478bd9Sstevel@tonic-gate int
sbd_check_io_attached(dev_info_t * dip,void * arg)3717c478bd9Sstevel@tonic-gate sbd_check_io_attached(dev_info_t *dip, void *arg)
3727c478bd9Sstevel@tonic-gate {
3737c478bd9Sstevel@tonic-gate 	dev_info_t **tdip;
3747c478bd9Sstevel@tonic-gate 
3757c478bd9Sstevel@tonic-gate 	tdip = (dev_info_t **)arg;
3767c478bd9Sstevel@tonic-gate 
3777c478bd9Sstevel@tonic-gate 	if (dip == *tdip) {
3787c478bd9Sstevel@tonic-gate 		int state;
3797c478bd9Sstevel@tonic-gate 
3807c478bd9Sstevel@tonic-gate 		state = ddi_get_devstate(dip);
381737d277aScth 		if (i_ddi_devi_attached(dip) || (state == DDI_DEVSTATE_UP)) {
3827c478bd9Sstevel@tonic-gate 			*tdip = NULL;
3837c478bd9Sstevel@tonic-gate 			return (DDI_WALK_TERMINATE);
3847c478bd9Sstevel@tonic-gate 		}
3857c478bd9Sstevel@tonic-gate 	}
3867c478bd9Sstevel@tonic-gate 	return (DDI_WALK_CONTINUE);
3877c478bd9Sstevel@tonic-gate }
3887c478bd9Sstevel@tonic-gate 
3897c478bd9Sstevel@tonic-gate int
sbd_pre_release_io(sbd_handle_t * hp,sbd_devlist_t * devlist,int devnum)3907c478bd9Sstevel@tonic-gate sbd_pre_release_io(sbd_handle_t *hp,
3917c478bd9Sstevel@tonic-gate 	sbd_devlist_t *devlist, int devnum)
3927c478bd9Sstevel@tonic-gate {
3937c478bd9Sstevel@tonic-gate 	fn_t	f = "sbd_pre_release_io";
3947c478bd9Sstevel@tonic-gate 	int	rv = 0;
3957c478bd9Sstevel@tonic-gate 	int	i;
3967c478bd9Sstevel@tonic-gate 
3977c478bd9Sstevel@tonic-gate 	ASSERT(devnum > 0);
3987c478bd9Sstevel@tonic-gate 
3997c478bd9Sstevel@tonic-gate 	/* fail if any I/O devices are referenced */
4007c478bd9Sstevel@tonic-gate 	if ((rv = sbd_check_io_refs(hp, devlist, devnum)) > 0) {
4017c478bd9Sstevel@tonic-gate 		/*
4027c478bd9Sstevel@tonic-gate 		 * One of the devices may have failed check to see which
4037c478bd9Sstevel@tonic-gate 		 * and set in the main handle
4047c478bd9Sstevel@tonic-gate 		 */
4057c478bd9Sstevel@tonic-gate 		for (i = 0; i < devnum; i++) {
4067c478bd9Sstevel@tonic-gate 			if (SBD_GET_ERR(&devlist[i].dv_error) != 0) {
4077c478bd9Sstevel@tonic-gate 				(void) sbd_set_err_in_hdl(hp,
4087c478bd9Sstevel@tonic-gate 				    &devlist[i].dv_error);
4097c478bd9Sstevel@tonic-gate 				break;
4107c478bd9Sstevel@tonic-gate 			}
4117c478bd9Sstevel@tonic-gate 		}
4127c478bd9Sstevel@tonic-gate 		PR_IO("%s: failed - I/O devices ref'd\n", f);
4137c478bd9Sstevel@tonic-gate 	}
4147c478bd9Sstevel@tonic-gate 
4157c478bd9Sstevel@tonic-gate 	return (rv);
4167c478bd9Sstevel@tonic-gate }
417