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