xref: /onnv-gate/usr/src/uts/intel/io/dktp/hba/ghd/ghd_timer.c (revision 7671:561e0c8d4bc8)
11709Smlf /*
21709Smlf  * CDDL HEADER START
31709Smlf  *
41709Smlf  * The contents of this file are subject to the terms of the
51709Smlf  * Common Development and Distribution License (the "License").
61709Smlf  * You may not use this file except in compliance with the License.
71709Smlf  *
81709Smlf  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
91709Smlf  * or http://www.opensolaris.org/os/licensing.
101709Smlf  * See the License for the specific language governing permissions
111709Smlf  * and limitations under the License.
121709Smlf  *
131709Smlf  * When distributing Covered Code, include this CDDL HEADER in each
141709Smlf  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
151709Smlf  * If applicable, add the following below this CDDL HEADER, with the
161709Smlf  * fields enclosed by brackets "[]" replaced with your own identifying
171709Smlf  * information: Portions Copyright [yyyy] [name of copyright owner]
181709Smlf  *
191709Smlf  * CDDL HEADER END
201709Smlf  */
211709Smlf 
221709Smlf /*
237240Srh87107  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
241709Smlf  * Use is subject to license terms.
251709Smlf  */
261709Smlf 
271709Smlf 
281709Smlf #include <sys/types.h>
291709Smlf #include <sys/conf.h>
301709Smlf #include <sys/ddi.h>
311709Smlf #include <sys/sunddi.h>
321709Smlf #include <sys/ksynch.h>
331709Smlf #include <sys/scsi/conf/autoconf.h>
341709Smlf #include <sys/reboot.h>
351709Smlf 
361709Smlf #include "ghd.h"
371709Smlf 
381709Smlf /*
391709Smlf  * Local functions
401709Smlf  */
411709Smlf 
421709Smlf static	gcmd_t	*ghd_timeout_get(ccc_t *cccp);
431709Smlf static	int	 ghd_timeout_loop(ccc_t *cccp);
441709Smlf static	uint_t	 ghd_timeout_softintr(caddr_t arg);
451709Smlf static	void	 ghd_timeout(void *arg);
461709Smlf static	void	 ghd_timeout_disable(tmr_t *tmrp);
471709Smlf static	void	 ghd_timeout_enable(tmr_t *tmrp);
481709Smlf 
491709Smlf /*
501709Smlf  * Local data
511709Smlf  */
521709Smlf long	ghd_HZ;
531709Smlf static	kmutex_t tglobal_mutex;
541709Smlf 
551709Smlf /* table of timeouts for abort processing steps */
561709Smlf cmdstate_t ghd_timeout_table[GCMD_NSTATES];
571709Smlf 
581709Smlf /* This table indirectly initializes the ghd_timeout_table */
591709Smlf struct {
601709Smlf 	int		valid;
611709Smlf 	cmdstate_t	state;
621709Smlf 	long		value;
631709Smlf } ghd_time_inits[] = {
641709Smlf 	{ TRUE, GCMD_STATE_ABORTING_CMD, 3 },
651709Smlf 	{ TRUE, GCMD_STATE_ABORTING_DEV, 3 },
661709Smlf 	{ TRUE, GCMD_STATE_RESETTING_DEV, 5 },
671709Smlf 	{ TRUE, GCMD_STATE_RESETTING_BUS, 10 },
681709Smlf 	{ TRUE, GCMD_STATE_HUNG, 60},
691709Smlf 	{ FALSE, 0, 0 },	/* spare entry */
701709Smlf 	{ FALSE, 0, 0 },	/* spare entry */
711709Smlf 	{ FALSE, 0, 0 },	/* spare entry */
721709Smlf 	{ FALSE, 0, 0 },	/* spare entry */
731709Smlf 	{ FALSE, 0, 0 }		/* spare entry */
741709Smlf };
751709Smlf int	ghd_ntime_inits = sizeof (ghd_time_inits)
761709Smlf 				/ sizeof (ghd_time_inits[0]);
771709Smlf 
781709Smlf /*
791709Smlf  * Locally-used macros
801709Smlf  */
811709Smlf 
821709Smlf /*
831709Smlf  * Compare two gcmd_t's to see if they're for the same device (same gdev_t)
841709Smlf  */
851709Smlf #define	GCMD_SAME_DEV(gcmdp1, gcmdp2)		\
861709Smlf 	(GCMDP2GDEVP(gcmdp1) == GCMDP2GDEVP(gcmdp2))
871709Smlf 
881709Smlf /*
891709Smlf  * Compare two gcmd_t's to see if they're for the same bus (same HBA inst)
901709Smlf  */
911709Smlf #define	GCMD_SAME_BUS(gcmdp1, gcmdp2)		\
921709Smlf 	(GCMDP2CCCP(gcmdp1) == GCMDP2CCCP(gcmdp2))
931709Smlf 
941709Smlf 
951709Smlf /*
961709Smlf  * Update state of gcmdp (in one direction, increasing state number, only)
971709Smlf  */
981709Smlf #define	GCMD_UPDATE_STATE(gcmdp, newstate) 		\
991709Smlf {							\
1001709Smlf 	if ((gcmdp)->cmd_state < (newstate)) {		\
1011709Smlf 		((gcmdp)->cmd_state = (newstate));	\
1021709Smlf 	}						\
1031709Smlf }
1041709Smlf 
1051709Smlf #ifdef ___notyet___
1061709Smlf 
1071709Smlf #include <sys/modctl.h>
1081709Smlf extern struct mod_ops mod_miscops;
1091709Smlf static struct modlmisc modlmisc = {
1101709Smlf 	&mod_miscops,	/* Type of module */
1111709Smlf 	"CCB Timeout Utility Routines"
1121709Smlf };
1131709Smlf static struct modlinkage modlinkage = {
1141709Smlf 	MODREV_1, (void *)&modlmisc, NULL
1151709Smlf };
1161709Smlf 
1171709Smlf /*
1181709Smlf  * If this is a loadable module then there's a single CCB timer configure
1191709Smlf  * structure for all HBA drivers (rather than one per HBA driver).
1201709Smlf  */
1211709Smlf static	tmr_t	tmr_conf;
1221709Smlf 
1231709Smlf int
_init()1241709Smlf _init()
1251709Smlf {
1261709Smlf 	int	err;
1271709Smlf 
1281709Smlf 	ghd_timer_init(&tmr_conf, 0);
1291709Smlf 	return ((err = mod_install(&modlinkage)) != 0)
1307240Srh87107 	    ghd_timer_fini(&tmr_conf);
1311709Smlf 	return (err);
1321709Smlf }
1331709Smlf 
1341709Smlf int
_fini()1351709Smlf _fini()
1361709Smlf {
1371709Smlf 	int	err;
1381709Smlf 
1391709Smlf 	if ((err = mod_remove(&modlinkage)) == 0)
1401709Smlf 		ghd_timer_fini(&tmr_conf);
1411709Smlf 	return (err);
1421709Smlf }
1431709Smlf 
1441709Smlf int
_info(struct modinfo * modinfop)1451709Smlf _info(struct modinfo *modinfop)
1461709Smlf {
1471709Smlf 	return (mod_info(&modlinkage, modinfop));
1481709Smlf }
1491709Smlf 
1501709Smlf #endif /* ___notyet___ */
1511709Smlf 
1521709Smlf 
1531709Smlf 
1541709Smlf /*
1551709Smlf  *
1561709Smlf  * ghd_timeout_loop()
1571709Smlf  *
1581709Smlf  *	Check the CCB timer value for every active CCB for this
1591709Smlf  * HBA driver instance.
1601709Smlf  *
1611709Smlf  *	This function is called both by the ghd_timeout() interrupt
1621709Smlf  * handler when called via the timer callout, and by ghd_timer_poll()
1631709Smlf  * while procesing "polled" (FLAG_NOINTR) requests.
1641709Smlf  *
1651709Smlf  * 	The ccc_activel_mutex is held while a CCB list is being scanned.
1661709Smlf  * This prevents the HBA driver's transport or interrupt functions
1671709Smlf  * from changing the active CCB list. But we wake up very infrequently
1681709Smlf  * and do as little as possible so it shouldn't affect performance.
1691709Smlf  *
1701709Smlf  */
1711709Smlf 
1721709Smlf static int
ghd_timeout_loop(ccc_t * cccp)1731709Smlf ghd_timeout_loop(ccc_t *cccp)
1741709Smlf {
1751709Smlf 	int	 got_any = FALSE;
1761709Smlf 	gcmd_t	*gcmdp;
1771709Smlf 	ulong_t	 lbolt;
1781709Smlf 
1791709Smlf 	mutex_enter(&cccp->ccc_activel_mutex);
1801709Smlf 	lbolt = ddi_get_lbolt();
1811709Smlf 	gcmdp = (gcmd_t *)L2_next(&cccp->ccc_activel);
1821709Smlf 	while (gcmdp) {
1831709Smlf 		/*
1841709Smlf 		 * check to see if this one has timed out
1851709Smlf 		 */
1861709Smlf 		if ((gcmdp->cmd_timeout > 0) &&
1871709Smlf 		    (lbolt - gcmdp->cmd_start_time >= gcmdp->cmd_timeout)) {
1881709Smlf 			got_any = TRUE;
1891709Smlf 		}
1901709Smlf 		gcmdp = (gcmd_t *)L2_next(&gcmdp->cmd_timer_link);
1911709Smlf 	}
1921709Smlf 	mutex_exit(&cccp->ccc_activel_mutex);
1931709Smlf 	return (got_any);
1941709Smlf }
1951709Smlf 
1961709Smlf /*
1971709Smlf  *
1981709Smlf  * ghd_timeout()
1991709Smlf  *
2001709Smlf  *	Called every t_ticks ticks to scan the CCB timer lists
2011709Smlf  *
2021709Smlf  *	The t_mutex mutex is held the entire time this routine is active.
2031709Smlf  *	It protects the list of ccc_t's.
2041709Smlf  *
2051709Smlf  *	The list of cmd_t's is protected by the ccc_activel_mutex mutex
2061709Smlf  *	in the ghd_timeout_loop() routine.
2071709Smlf  *
2081709Smlf  * 	We also check to see if the waitq is frozen, and if so,
2091709Smlf  * 	adjust our timeout to call back sooner if necessary (to
2101709Smlf  * 	unfreeze the waitq as soon as possible).
2111709Smlf  *
2121709Smlf  *
2131709Smlf  *	+------------+
2141709Smlf  *	|   tmr_t    |----+
2151709Smlf  *	+------------+    |
2161709Smlf  *			  |
2171709Smlf  *			  V
2181709Smlf  *			  +---------+
2191709Smlf  *			  |  ccc_t  |----+
2201709Smlf  *			  +---------+    |
2211709Smlf  *			  |		 V
2221709Smlf  *			  |		 +--------+   +--------+
2231709Smlf  *			  |		 | gcmd_t |-->| gcmd_t |--> ...
2241709Smlf  *			  |		 +--------+   +--------+
2251709Smlf  *			  V
2261709Smlf  *			  +---------+
2271709Smlf  *			  |  ccc_t  |----+
2281709Smlf  *			  +---------+    |
2291709Smlf  *			  |		 V
2301709Smlf  *			  |		 +--------+
2311709Smlf  *			  |		 | gcmd_t |
2321709Smlf  *			  V		 +--------+
2331709Smlf  *			  ...
2341709Smlf  *
2351709Smlf  *
2361709Smlf  *
2371709Smlf  */
2381709Smlf 
2391709Smlf static void
ghd_timeout(void * arg)2401709Smlf ghd_timeout(void *arg)
2411709Smlf {
2421709Smlf 	tmr_t	*tmrp = (tmr_t *)arg;
2431709Smlf 	ccc_t	*cccp;
2441709Smlf 	clock_t	ufdelay_curr;
2451709Smlf 	clock_t	lbolt, delay_in_hz;
2461709Smlf 	clock_t	resched = (clock_t)0x7FFFFFFF;
2471709Smlf 
2481709Smlf 	/*
2491709Smlf 	 * Each HBA driver instance has a separate CCB timer list.  Skip
2501709Smlf 	 * timeout processing if there are no more active timeout lists
2511709Smlf 	 * to process.  (There are no lists only if there are no attached
2521709Smlf 	 * HBA instances; the list still exists if there are no outstanding
2531709Smlf 	 * active commands.)
2541709Smlf 	 */
2551709Smlf 	mutex_enter(&tmrp->t_mutex);
2561709Smlf 	if ((cccp = tmrp->t_ccc_listp) == NULL) {
2571709Smlf 		mutex_exit(&tmrp->t_mutex);
2581709Smlf 		return;
2591709Smlf 	}
2601709Smlf 
2611709Smlf 	lbolt = ddi_get_lbolt();
2621709Smlf 
2631709Smlf 	do {
2641709Smlf 		/*
2651709Smlf 		 * If any active CCBs on this HBA have timed out
2661709Smlf 		 * then kick off the HBA driver's softintr
2671709Smlf 		 * handler to do the timeout processing
2681709Smlf 		 */
2691709Smlf 		if (ghd_timeout_loop(cccp)) {
2701709Smlf 			cccp->ccc_timeout_pending = 1;
2711709Smlf 			ddi_trigger_softintr(cccp->ccc_soft_id);
2721709Smlf 		}
2731709Smlf 
2741709Smlf 		/* Record closest unfreeze time for use in next timeout */
2751709Smlf 
2761709Smlf 		mutex_enter(&cccp->ccc_waitq_mutex);
2771709Smlf 		if (cccp->ccc_waitq_frozen) {
2781709Smlf 
2791709Smlf 			delay_in_hz =
2801709Smlf 			    drv_usectohz(cccp->ccc_waitq_freezedelay * 1000);
2811709Smlf 			ufdelay_curr = delay_in_hz -
2821709Smlf 			    (lbolt - cccp->ccc_waitq_freezetime);
2831709Smlf 
2841709Smlf 			if (ufdelay_curr < resched)
2851709Smlf 				resched = ufdelay_curr;
2861709Smlf 
2871709Smlf 			/* frozen; trigger softintr to maybe unfreeze */
2881709Smlf 			ddi_trigger_softintr(cccp->ccc_soft_id);
2891709Smlf 		}
2901709Smlf 		mutex_exit(&cccp->ccc_waitq_mutex);
2911709Smlf 
2921709Smlf 	} while ((cccp = cccp->ccc_nextp) != NULL);
2931709Smlf 
2941709Smlf 	/* don't allow any unfreeze delays to increase the timeout delay */
2951709Smlf 	if (resched > tmrp->t_ticks)
2961709Smlf 		resched = tmrp->t_ticks;
2971709Smlf 
2981709Smlf 	/* re-establish the timeout callback */
2991709Smlf 	tmrp->t_timeout_id = timeout(ghd_timeout, (void *)tmrp, resched);
3001709Smlf 
3011709Smlf 	mutex_exit(&tmrp->t_mutex);
3021709Smlf }
3031709Smlf 
3041709Smlf 
3051709Smlf /*
3061709Smlf  *
3071709Smlf  * ghd_timer_newstate()
3081709Smlf  *
3091709Smlf  *	The HBA mutex is held by my caller.
3101709Smlf  *
3111709Smlf  */
3121709Smlf 
3131709Smlf void
ghd_timer_newstate(ccc_t * cccp,gcmd_t * gcmdp,gtgt_t * gtgtp,gact_t action,int calltype)3141709Smlf ghd_timer_newstate(ccc_t *cccp, gcmd_t *gcmdp, gtgt_t *gtgtp,
3151709Smlf     gact_t action, int calltype)
3161709Smlf {
3171709Smlf 	gact_t	next_action;
3181709Smlf 	cmdstate_t next_state;
3191709Smlf 	char	*msgp;
3201709Smlf 	long	new_timeout;
3211709Smlf 	int	(*func)(void *, gcmd_t *, gtgt_t *, gact_t, int);
3221709Smlf 	void	*hba_handle;
3231709Smlf 	gcmd_t	gsav;
3241709Smlf 	int	gsav_used = 0;
3251709Smlf 	gcmd_t	*gcmdp_scan;
3261709Smlf 
3271709Smlf 	ASSERT(mutex_owned(&cccp->ccc_hba_mutex));
3281709Smlf 
3291709Smlf #ifdef	DEBUG
3301709Smlf 	/* it shouldn't be on the timer active list */
3311709Smlf 	if (gcmdp != NULL) {
3321709Smlf 		L2el_t	*lp = &gcmdp->cmd_timer_link;
3331709Smlf 		ASSERT(lp->l2_nextp == lp);
3341709Smlf 		ASSERT(lp->l2_prevp == lp);
3351709Smlf 	}
3361709Smlf #endif
3371709Smlf 
3381709Smlf 	func = cccp->ccc_timeout_func;
3391709Smlf 	hba_handle = cccp->ccc_hba_handle;
3401709Smlf 
3411709Smlf 	for (;;) {
3421709Smlf 		switch (action) {
3431709Smlf 		case GACTION_EARLY_ABORT:
3441709Smlf 			/* done before it started */
3451709Smlf 			ASSERT(gcmdp != NULL);
3461709Smlf 			msgp = "early abort";
3471709Smlf 			next_state = GCMD_STATE_DONEQ;
3481709Smlf 			next_action = GACTION_ABORT_CMD;
3491709Smlf 			break;
3501709Smlf 
3511709Smlf 		case GACTION_EARLY_TIMEOUT:
3521709Smlf 			/* done before it started */
3531709Smlf 			ASSERT(gcmdp != NULL);
3541709Smlf 			msgp = "early timeout";
3551709Smlf 			next_state = GCMD_STATE_DONEQ;
3561709Smlf 			next_action = GACTION_ABORT_CMD;
3571709Smlf 			break;
3581709Smlf 
3591709Smlf 		case GACTION_ABORT_CMD:
3601709Smlf 			msgp = "abort request";
3611709Smlf 			ASSERT(gcmdp != NULL);
3621709Smlf 			next_state = GCMD_STATE_ABORTING_CMD;
3631709Smlf 			next_action = GACTION_ABORT_DEV;
3641709Smlf 			break;
3651709Smlf 
3661709Smlf 		case GACTION_ABORT_DEV:
3671709Smlf 			msgp = "abort device";
3681709Smlf 			next_state = GCMD_STATE_ABORTING_DEV;
3691709Smlf 			next_action = GACTION_RESET_TARGET;
3701709Smlf 			break;
3711709Smlf 
3721709Smlf 		case GACTION_RESET_TARGET:
3731709Smlf 			msgp = "reset target";
3741709Smlf 			next_state = GCMD_STATE_RESETTING_DEV;
3751709Smlf 			next_action = GACTION_RESET_BUS;
3761709Smlf 			break;
3771709Smlf 
3781709Smlf 		case GACTION_RESET_BUS:
3791709Smlf 			msgp = "reset bus";
3801709Smlf 			next_state = GCMD_STATE_RESETTING_BUS;
3811709Smlf 			next_action = GACTION_INCOMPLETE;
3821709Smlf 			break;
3831709Smlf 
3841709Smlf 		case GACTION_INCOMPLETE:
3851709Smlf 		default:
3861709Smlf 			/* be verbose about HBA resets */
3871709Smlf 			GDBG_ERROR(("?ghd_timer_newstate: HBA reset failed "
3881709Smlf 			    "hba 0x%p gcmdp 0x%p gtgtp 0x%p\n",
3891709Smlf 			    (void *)hba_handle, (void *)gcmdp, (void *)gtgtp));
3901709Smlf 			/*
3911709Smlf 			 * When all else fails, punt.
3921709Smlf 			 *
3931709Smlf 			 * We're in big trouble if we get to this point.
3941709Smlf 			 * Maybe we should try to re-initialize the HBA.
3951709Smlf 			 */
3961709Smlf 			msgp = "HBA reset";
3971709Smlf 			next_state = GCMD_STATE_HUNG;
3981709Smlf 			next_action = GACTION_INCOMPLETE;
3991709Smlf 			break;
4001709Smlf 		}
4011709Smlf 
4021709Smlf 		/*
4031709Smlf 		 * I want to see target requests only if verbose, but
4041709Smlf 		 * scsi_log() only prints the device pathname if level
4051709Smlf 		 * is CE_WARN or CE_PANIC...so I guess we can't use
4061709Smlf 		 * scsi_log for TGTREQ messages, or they must come to
4071709Smlf 		 * the console.  How silly.  Looking for "verbose boot"
4081709Smlf 		 * is non-DDI-compliant, but let's do it anyway.
4091709Smlf 		 */
4101709Smlf 
4111709Smlf 		if (calltype == GHD_TGTREQ) {
4121709Smlf 			if ((boothowto & RB_VERBOSE)) {
4131709Smlf 				scsi_log(cccp->ccc_hba_dip, cccp->ccc_label,
4141709Smlf 				    CE_WARN,
4151709Smlf 				    "target request: %s, target=%d lun=%d",
4161709Smlf 				    msgp, gtgtp->gt_target, gtgtp->gt_lun);
4171709Smlf 			}
4181709Smlf 		} else {
4191709Smlf 			scsi_log(cccp->ccc_hba_dip, cccp->ccc_label, CE_WARN,
4201709Smlf 			    "timeout: %s, target=%d lun=%d", msgp,
4217240Srh87107 			    gtgtp->gt_target, gtgtp->gt_lun);
4221709Smlf 		}
4231709Smlf 
4241709Smlf 		/*
4251709Smlf 		 * Before firing off the HBA action, restart the timer
4261709Smlf 		 * using the timeout value from ghd_timeout_table[].
4271709Smlf 		 *
4281709Smlf 		 * The table entries should never restart the timer
4291709Smlf 		 * for the GHD_STATE_IDLE and GHD_STATE_DONEQ states.
4301709Smlf 		 *
4311709Smlf 		 */
4321709Smlf 		if (gcmdp) {
4331709Smlf 			gcmdp->cmd_state = next_state;
4341709Smlf 			new_timeout = ghd_timeout_table[gcmdp->cmd_state];
4351709Smlf 			if (new_timeout != 0)
4361709Smlf 				ghd_timer_start(cccp, gcmdp, new_timeout);
4371709Smlf 
4381709Smlf 			/* save a copy in case action function frees it */
4391709Smlf 			gsav = *gcmdp;
4401709Smlf 			gsav_used = 1;
4411709Smlf 		}
4421709Smlf 
4431709Smlf 		if (action == GACTION_RESET_BUS && cccp->ccc_waitq_frozen) {
4441709Smlf 			GDBG_WARN(("avoiding bus reset while waitq frozen\n"));
4451709Smlf 			break;
4461709Smlf 		}
4471709Smlf 
4481709Smlf 		/* invoke the HBA's action function */
4491709Smlf 		if ((*func)(hba_handle, gcmdp, gtgtp, action, calltype)) {
4501709Smlf 			/* if it took wait for an interrupt or timeout */
4511709Smlf 			break;
4521709Smlf 		}
4531709Smlf 		/*
4541709Smlf 		 * if the HBA reset fails leave the retry
4551709Smlf 		 * timer running and just exit.
4561709Smlf 		 */
4571709Smlf 		if (action == GACTION_INCOMPLETE)
4581709Smlf 			return;
4591709Smlf 
4601709Smlf 		/* all other failures cause transition to next action */
4611709Smlf 		if (gcmdp != NULL && new_timeout != 0) {
4621709Smlf 			/*
4631709Smlf 			 * But stop the old timer prior to
4641709Smlf 			 * restarting a new timer because each step may
4651709Smlf 			 * have a different timeout value.
4661709Smlf 			 */
4671709Smlf 			GHD_TIMER_STOP(cccp, gcmdp);
4681709Smlf 		}
4691709Smlf 		action = next_action;
4701709Smlf 	}
4711709Smlf 
4721709Smlf 	/*
4731709Smlf 	 * HBA action function is done with gsav (if used)
4741709Smlf 	 * or gtgtp/cccp (if gsav not used).  We need to mark other
4751709Smlf 	 * outstanding requests if they were affected by this action
4761709Smlf 	 * (say, a device reset which also cancels all outstanding
4771709Smlf 	 * requests on this device) to prevent multiple timeouts/HBA
4781709Smlf 	 * actions for the same device or bus condition.  Scan the timer
4791709Smlf 	 * list (all active requests) and update states as necessary.
4801709Smlf 	 * Hold the activel_mutex while scanning the active list.  Check
4811709Smlf 	 * for either same dev/bus as gsav (if used) or for same
4821709Smlf 	 * dev/bus as gtgtp or cccp (if gsav is not used).
4831709Smlf 	 */
4841709Smlf 
4851709Smlf 	mutex_enter(&cccp->ccc_activel_mutex);
4861709Smlf 
4871709Smlf 	for (gcmdp_scan = (gcmd_t *)L2_next(&cccp->ccc_activel);
4881709Smlf 	    gcmdp_scan != NULL;
4891709Smlf 	    gcmdp_scan = (gcmd_t *)L2_next(&gcmdp_scan->cmd_timer_link)) {
4901709Smlf 
4911709Smlf 		/* skip idle or waitq commands */
4921709Smlf 		if (gcmdp_scan->cmd_state <= GCMD_STATE_WAITQ)
4931709Smlf 			continue;
4941709Smlf 
4951709Smlf 		switch (action) {
4961709Smlf 
4971709Smlf 		case GACTION_ABORT_DEV:
4981709Smlf 			if ((gsav_used && GCMD_SAME_DEV(&gsav, gcmdp_scan)) ||
4991709Smlf 			    (GCMDP2GDEVP(gcmdp_scan) == GTGTP2GDEVP(gtgtp))) {
5001709Smlf 				GCMD_UPDATE_STATE(gcmdp_scan,
5011709Smlf 				    GCMD_STATE_ABORTING_DEV);
5021709Smlf 			}
5031709Smlf 			break;
5041709Smlf 
5051709Smlf 		case GACTION_RESET_TARGET:
5061709Smlf 			if ((gsav_used && GCMD_SAME_DEV(&gsav, gcmdp_scan)) ||
5071709Smlf 			    (GCMDP2GDEVP(gcmdp_scan) == GTGTP2GDEVP(gtgtp))) {
5081709Smlf 				GCMD_UPDATE_STATE(gcmdp_scan,
5091709Smlf 				    GCMD_STATE_RESETTING_DEV);
5101709Smlf 			}
5111709Smlf 			break;
5121709Smlf 
5131709Smlf 		case GACTION_RESET_BUS:
5141709Smlf 			if ((gsav_used && GCMD_SAME_BUS(&gsav, gcmdp_scan)) ||
5151709Smlf 			    (GCMDP2CCCP(gcmdp_scan) == cccp)) {
5161709Smlf 				GCMD_UPDATE_STATE(gcmdp_scan,
5171709Smlf 				    GCMD_STATE_RESETTING_BUS);
5181709Smlf 			}
5191709Smlf 			break;
5201709Smlf 		default:
5211709Smlf 			break;
5221709Smlf 		}
5231709Smlf 	}
5241709Smlf 
5251709Smlf 	mutex_exit(&cccp->ccc_activel_mutex);
5261709Smlf }
5271709Smlf 
5281709Smlf 
5291709Smlf /*
5301709Smlf  *
5311709Smlf  * ghd_timeout_softintr()
5321709Smlf  *
5331709Smlf  *	This interrupt is scheduled if a particular HBA instance's
5341709Smlf  *	CCB timer list has a timed out CCB, or if the waitq is in a
5351709Smlf  * 	frozen state.
5361709Smlf  *
5371709Smlf  *	Find the timed out CCB and then call the HBA driver's timeout
5381709Smlf  *	function.
5391709Smlf  *
5401709Smlf  *	In order to avoid race conditions all processing must be done
5411709Smlf  *	while holding the HBA instance's mutex. If the mutex wasn't
5421709Smlf  *	held the HBA driver's hardware interrupt routine could be
5431709Smlf  *	triggered and it might try to remove a CCB from the list at
5441709Smlf  *	same time as were trying to abort it.
5451709Smlf  *
5461709Smlf  *	For frozen-waitq processing, just call ghd_waitq_process...
5471709Smlf  *	it takes care of the time calculations.
5481709Smlf  *
5491709Smlf  */
5501709Smlf 
5511709Smlf static uint_t
ghd_timeout_softintr(caddr_t arg)5521709Smlf ghd_timeout_softintr(caddr_t arg)
5531709Smlf {
5541709Smlf 	ccc_t	*cccp = (ccc_t *)arg;
5551709Smlf 
5561709Smlf 	if (cccp->ccc_timeout_pending) {
5571709Smlf 
5581709Smlf 		/* grab this HBA instance's mutex */
5591709Smlf 		mutex_enter(&cccp->ccc_hba_mutex);
5601709Smlf 
5611709Smlf 		/*
5621709Smlf 		 * The claim is we could reset "pending" outside the mutex, but
5631709Smlf 		 * since we have to acquire the mutex anyway, it doesn't hurt
5641709Smlf 		 */
5651709Smlf 		cccp->ccc_timeout_pending = 0;
5661709Smlf 
5671709Smlf 		/* timeout each expired CCB */
5681709Smlf 		ghd_timer_poll(cccp, GHD_TIMER_POLL_ALL);
5691709Smlf 
5701709Smlf 		mutex_enter(&cccp->ccc_waitq_mutex);
5711709Smlf 		ghd_waitq_process_and_mutex_exit(cccp);
5721709Smlf 
5731709Smlf 	} else if (cccp->ccc_waitq_frozen) {
5741709Smlf 		mutex_enter(&cccp->ccc_hba_mutex);
5751709Smlf 		mutex_enter(&cccp->ccc_waitq_mutex);
5761709Smlf 		ghd_waitq_process_and_mutex_exit(cccp);
5771709Smlf 	}
5781709Smlf 
5791709Smlf 	return (DDI_INTR_UNCLAIMED);
5801709Smlf }
5811709Smlf 
5821709Smlf 
5831709Smlf /*
5841709Smlf  * ghd_timer_poll()
5851709Smlf  *
5861709Smlf  * This function steps a packet to the next action in the recovery
5871709Smlf  * procedure.
5881709Smlf  *
5891709Smlf  * The caller must be  already holding the HBA mutex and take care of
5901709Smlf  * running the pkt completion functions.
5911709Smlf  *
5921709Smlf  */
5931709Smlf 
5941709Smlf void
ghd_timer_poll(ccc_t * cccp,gtimer_poll_t calltype)5951709Smlf ghd_timer_poll(ccc_t *cccp, gtimer_poll_t calltype)
5961709Smlf {
5971709Smlf 	gcmd_t	*gcmdp;
5981709Smlf 	gact_t	 action;
5991709Smlf 
6001709Smlf 	ASSERT(mutex_owned(&cccp->ccc_hba_mutex));
6011709Smlf 
6021709Smlf 	/* abort each expired CCB */
6031709Smlf 	while (gcmdp = ghd_timeout_get(cccp)) {
6041709Smlf 
6051709Smlf 		GDBG_INTR(("?ghd_timer_poll: cccp=0x%p gcmdp=0x%p\n",
6067240Srh87107 		    (void *)cccp, (void *)gcmdp));
6071709Smlf 
6081709Smlf 		switch (gcmdp->cmd_state) {
6091709Smlf 		case GCMD_STATE_IDLE:
6101709Smlf 		case GCMD_STATE_DONEQ:
6111709Smlf 		default:
6121709Smlf 			/* not supposed to happen */
6131709Smlf 			GDBG_ERROR(("ghd_timer_poll: invalid state %d\n",
6141709Smlf 			    gcmdp->cmd_state));
6151709Smlf 			return;
6161709Smlf 
6171709Smlf 		case GCMD_STATE_WAITQ:
6181709Smlf 			action = GACTION_EARLY_TIMEOUT;
6191709Smlf 			break;
6201709Smlf 
6211709Smlf 		case GCMD_STATE_ACTIVE:
6221709Smlf 			action = GACTION_ABORT_CMD;
6231709Smlf 			break;
6241709Smlf 
6251709Smlf 		case GCMD_STATE_ABORTING_CMD:
6261709Smlf 			action = GACTION_ABORT_DEV;
6271709Smlf 			break;
6281709Smlf 
6291709Smlf 		case GCMD_STATE_ABORTING_DEV:
6301709Smlf 			action = GACTION_RESET_TARGET;
6311709Smlf 			break;
6321709Smlf 
6331709Smlf 		case GCMD_STATE_RESETTING_DEV:
6341709Smlf 			action = GACTION_RESET_BUS;
6351709Smlf 			break;
6361709Smlf 
6371709Smlf 		case GCMD_STATE_RESETTING_BUS:
6381709Smlf 			action = GACTION_INCOMPLETE;
6391709Smlf 			break;
6401709Smlf 
6411709Smlf 		case GCMD_STATE_HUNG:
6421709Smlf 			action = GACTION_INCOMPLETE;
6431709Smlf 			break;
6441709Smlf 		}
6451709Smlf 
6461709Smlf 		ghd_timer_newstate(cccp, gcmdp, gcmdp->cmd_gtgtp, action,
6471709Smlf 		    GHD_TIMEOUT);
6481709Smlf 
6491709Smlf 		/* return after processing first cmd if requested */
6501709Smlf 
6511709Smlf 		if (calltype == GHD_TIMER_POLL_ONE)
6521709Smlf 			return;
6531709Smlf 	}
6541709Smlf }
6551709Smlf 
6561709Smlf 
6571709Smlf 
6581709Smlf 
6591709Smlf /*
6601709Smlf  *
6611709Smlf  * ghd_timeout_get()
6621709Smlf  *
6631709Smlf  *	Remove the first expired CCB from a particular timer list.
6641709Smlf  *
6651709Smlf  */
6661709Smlf 
6671709Smlf static gcmd_t *
ghd_timeout_get(ccc_t * cccp)6681709Smlf ghd_timeout_get(ccc_t *cccp)
6691709Smlf {
6701709Smlf 	gcmd_t	*gcmdp;
6711709Smlf 	ulong_t	lbolt;
6721709Smlf 
6731709Smlf 	ASSERT(mutex_owned(&cccp->ccc_hba_mutex));
6741709Smlf 
6751709Smlf 	mutex_enter(&cccp->ccc_activel_mutex);
6761709Smlf 	lbolt = ddi_get_lbolt();
6771709Smlf 	gcmdp = (gcmd_t *)L2_next(&cccp->ccc_activel);
6781709Smlf 	while (gcmdp != NULL) {
6791709Smlf 		if ((gcmdp->cmd_timeout > 0) &&
6801709Smlf 		    (lbolt - gcmdp->cmd_start_time >= gcmdp->cmd_timeout))
6811709Smlf 			goto expired;
6821709Smlf 		gcmdp = (gcmd_t *)L2_next(&gcmdp->cmd_timer_link);
6831709Smlf 	}
6841709Smlf 	mutex_exit(&cccp->ccc_activel_mutex);
6851709Smlf 	return (NULL);
6861709Smlf 
6871709Smlf expired:
6881709Smlf 	/* unlink if from the CCB timer list */
6891709Smlf 	L2_delete(&gcmdp->cmd_timer_link);
6901709Smlf 	mutex_exit(&cccp->ccc_activel_mutex);
6911709Smlf 	return (gcmdp);
6921709Smlf }
6931709Smlf 
6941709Smlf 
6951709Smlf /*
6961709Smlf  *
6971709Smlf  * ghd_timeout_enable()
6981709Smlf  *
6991709Smlf  *	Only start a single timeout callback for each HBA driver
7001709Smlf  *	regardless of the number of boards it supports.
7011709Smlf  *
7021709Smlf  */
7031709Smlf 
7041709Smlf static void
ghd_timeout_enable(tmr_t * tmrp)7051709Smlf ghd_timeout_enable(tmr_t *tmrp)
7061709Smlf {
7071709Smlf 	mutex_enter(&tglobal_mutex);
7081709Smlf 	if (tmrp->t_refs++ == 0)  {
7091709Smlf 		/* establish the timeout callback */
7101709Smlf 		tmrp->t_timeout_id = timeout(ghd_timeout, (void *)tmrp,
7117240Srh87107 		    tmrp->t_ticks);
7121709Smlf 	}
7131709Smlf 	mutex_exit(&tglobal_mutex);
7141709Smlf }
7151709Smlf 
7161709Smlf static void
ghd_timeout_disable(tmr_t * tmrp)7171709Smlf ghd_timeout_disable(tmr_t *tmrp)
7181709Smlf {
7191709Smlf 	ASSERT(tmrp != NULL);
7201709Smlf 
7211709Smlf 	mutex_enter(&tglobal_mutex);
7225162Smlf 	if (tmrp->t_refs-- <= 1) {
7231709Smlf 		(void) untimeout(tmrp->t_timeout_id);
7245162Smlf 	}
7251709Smlf 	mutex_exit(&tglobal_mutex);
7261709Smlf }
7271709Smlf 
7281709Smlf /* ************************************************************************ */
7291709Smlf 
7301709Smlf 	/* these are the externally callable routines */
7311709Smlf 
7321709Smlf 
7331709Smlf void
ghd_timer_init(tmr_t * tmrp,long ticks)7341709Smlf ghd_timer_init(tmr_t *tmrp, long ticks)
7351709Smlf {
7361709Smlf 	int	indx;
7371709Smlf 
7381709Smlf 	mutex_init(&tglobal_mutex, NULL, MUTEX_DRIVER, NULL);
7391709Smlf 	mutex_init(&tmrp->t_mutex, NULL, MUTEX_DRIVER, NULL);
7401709Smlf 
7411709Smlf 	/*
7421709Smlf 	 * determine default timeout value
7431709Smlf 	 */
7441709Smlf 	ghd_HZ = drv_usectohz(1000000);
7451709Smlf 	if (ticks == 0)
7461709Smlf 		ticks = scsi_watchdog_tick * ghd_HZ;
7471709Smlf 	tmrp->t_ticks = ticks;
7481709Smlf 
7491709Smlf 
7501709Smlf 	/*
7511709Smlf 	 * Initialize the table of abort timer values using an
7521709Smlf 	 * indirect lookup table so that this code isn't dependant
7531709Smlf 	 * on the cmdstate_t enum values or order.
7541709Smlf 	 */
7551709Smlf 	for (indx = 0; indx < ghd_ntime_inits; indx++) {
7561709Smlf 		int	state;
7571709Smlf 		ulong_t	value;
7581709Smlf 
7591709Smlf 		if (!ghd_time_inits[indx].valid)
7601709Smlf 			continue;
7611709Smlf 		state = ghd_time_inits[indx].state;
7621709Smlf 		value = ghd_time_inits[indx].value;
763*7671SZhongyan.Gu@Sun.COM 		ghd_timeout_table[state] = (cmdstate_t)value;
7641709Smlf 	}
7651709Smlf }
7661709Smlf 
7671709Smlf void
ghd_timer_fini(tmr_t * tmrp)7681709Smlf ghd_timer_fini(tmr_t *tmrp)
7691709Smlf {
7701709Smlf 	mutex_destroy(&tmrp->t_mutex);
7711709Smlf 	mutex_destroy(&tglobal_mutex);
7721709Smlf }
7731709Smlf 
7741709Smlf int
ghd_timer_attach(ccc_t * cccp,tmr_t * tmrp,int (* timeout_func)(void *,gcmd_t *,gtgt_t *,gact_t,int))7751709Smlf ghd_timer_attach(ccc_t *cccp, tmr_t *tmrp,
7761709Smlf     int (*timeout_func)(void *, gcmd_t *, gtgt_t *, gact_t, int))
7771709Smlf {
7781709Smlf 	ddi_iblock_cookie_t iblock;
7791709Smlf 
7801709Smlf 	if (ddi_add_softintr(cccp->ccc_hba_dip, DDI_SOFTINT_LOW,
7811709Smlf 	    &cccp->ccc_soft_id, &iblock, NULL,
7821709Smlf 	    ghd_timeout_softintr, (caddr_t)cccp) != DDI_SUCCESS) {
7831709Smlf 		GDBG_ERROR((
7841709Smlf 		    "ghd_timer_attach: add softintr failed cccp 0x%p\n",
7851709Smlf 		    (void *)cccp));
7861709Smlf 		return (FALSE);
7871709Smlf 	}
7881709Smlf 
7891709Smlf 	/* init the per HBA-instance control fields */
7901709Smlf 	mutex_init(&cccp->ccc_activel_mutex, NULL, MUTEX_DRIVER, iblock);
7911709Smlf 	L2_INIT(&cccp->ccc_activel);
7921709Smlf 	cccp->ccc_timeout_func = timeout_func;
7931709Smlf 
7941709Smlf 	/* stick this HBA's control structure on the master list */
7951709Smlf 	mutex_enter(&tmrp->t_mutex);
7961709Smlf 
7971709Smlf 	cccp->ccc_nextp = tmrp->t_ccc_listp;
7981709Smlf 	tmrp->t_ccc_listp = cccp;
7991709Smlf 	cccp->ccc_tmrp = tmrp;
8001709Smlf 	mutex_exit(&tmrp->t_mutex);
8011709Smlf 
8021709Smlf 	/*
8031709Smlf 	 * The enable and disable routines use a separate mutex than
8041709Smlf 	 * t_mutex which is used by the timeout callback function.
8051709Smlf 	 * This is to avoid a deadlock when calling untimeout() from
8061709Smlf 	 * the disable routine.
8071709Smlf 	 */
8081709Smlf 	ghd_timeout_enable(tmrp);
8091709Smlf 
8101709Smlf 	return (TRUE);
8111709Smlf }
8121709Smlf 
8131709Smlf 
8141709Smlf /*
8151709Smlf  *
8161709Smlf  * ghd_timer_detach()
8171709Smlf  *
8181709Smlf  *	clean up for a detaching HBA instance
8191709Smlf  *
8201709Smlf  */
8211709Smlf 
8221709Smlf void
ghd_timer_detach(ccc_t * cccp)8231709Smlf ghd_timer_detach(ccc_t *cccp)
8241709Smlf {
8251709Smlf 	tmr_t	*tmrp = cccp->ccc_tmrp;
8261709Smlf 	ccc_t	**prevpp;
8271709Smlf 
8281709Smlf 	/* make certain the CCB list is empty */
8291709Smlf 	ASSERT(cccp->ccc_activel.l2_nextp == &cccp->ccc_activel);
8301709Smlf 	ASSERT(cccp->ccc_activel.l2_nextp == cccp->ccc_activel.l2_prevp);
8311709Smlf 
8321709Smlf 	mutex_enter(&tmrp->t_mutex);
8331709Smlf 
8341709Smlf 	prevpp = &tmrp->t_ccc_listp;
8351709Smlf 	ASSERT(*prevpp != NULL);
8361709Smlf 
8371709Smlf 	/* run down the linked list to find the entry that preceeds this one */
8381709Smlf 	do {
8391709Smlf 		if (*prevpp == cccp)
8401709Smlf 			goto remove_it;
8411709Smlf 		prevpp = &(*prevpp)->ccc_nextp;
8421709Smlf 	} while (*prevpp != NULL);
8431709Smlf 
8441709Smlf 	/* fell off the end of the list */
8451709Smlf 	GDBG_ERROR(("ghd_timer_detach: corrupt list, cccp=0x%p\n",
8461709Smlf 	    (void *)cccp));
8471709Smlf 
8481709Smlf remove_it:
8491709Smlf 	*prevpp = cccp->ccc_nextp;
8501709Smlf 	mutex_exit(&tmrp->t_mutex);
8511709Smlf 	mutex_destroy(&cccp->ccc_activel_mutex);
8521709Smlf 
8531709Smlf 	ddi_remove_softintr(cccp->ccc_soft_id);
8541709Smlf 
8551709Smlf 	ghd_timeout_disable(tmrp);
8561709Smlf }
8571709Smlf 
8581709Smlf /*
8591709Smlf  *
8601709Smlf  * ghd_timer_start()
8611709Smlf  *
8621709Smlf  *	Add a CCB to the CCB timer list.
8631709Smlf  */
8641709Smlf 
8651709Smlf void
ghd_timer_start(ccc_t * cccp,gcmd_t * gcmdp,long cmd_timeout)8661709Smlf ghd_timer_start(ccc_t *cccp, gcmd_t *gcmdp, long cmd_timeout)
8671709Smlf {
8681709Smlf 	ulong_t	lbolt;
8691709Smlf 
8701709Smlf 	mutex_enter(&cccp->ccc_activel_mutex);
8711709Smlf 	lbolt = ddi_get_lbolt();
8721709Smlf 
8731709Smlf 	/* initialize this CCB's timer */
8741709Smlf 	gcmdp->cmd_start_time = lbolt;
8751709Smlf 	gcmdp->cmd_timeout = (cmd_timeout * ghd_HZ);
8761709Smlf 
8771709Smlf 	/* add it to the list */
8781709Smlf 	L2_add(&cccp->ccc_activel, &gcmdp->cmd_timer_link, gcmdp);
8791709Smlf 	mutex_exit(&cccp->ccc_activel_mutex);
8801709Smlf }
8811709Smlf 
8821709Smlf 
8831709Smlf /*
8841709Smlf  *
8851709Smlf  * ghd_timer_stop()
8861709Smlf  *
8871709Smlf  *	Remove a completed CCB from the CCB timer list.
8881709Smlf  *
8891709Smlf  *	See the GHD_TIMER_STOP_INLINE() macro in ghd.h for
8901709Smlf  *	the actual code.
8911709Smlf  */
8921709Smlf 
8931709Smlf void
ghd_timer_stop(ccc_t * cccp,gcmd_t * gcmdp)8941709Smlf ghd_timer_stop(ccc_t *cccp, gcmd_t *gcmdp)
8951709Smlf {
8961709Smlf 	GHD_TIMER_STOP_INLINE(cccp, gcmdp);
8971709Smlf }
898