507c32411f3f101e90ca2120f042b5ee698ba1d5mlf/*
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * CDDL HEADER START
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf *
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * The contents of this file are subject to the terms of the
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * Common Development and Distribution License (the "License").
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * You may not use this file except in compliance with the License.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf *
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * or http://www.opensolaris.org/os/licensing.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * See the License for the specific language governing permissions
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * and limitations under the License.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf *
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * When distributing Covered Code, include this CDDL HEADER in each
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * If applicable, add the following below this CDDL HEADER, with the
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * fields enclosed by brackets "[]" replaced with your own identifying
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * information: Portions Copyright [yyyy] [name of copyright owner]
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf *
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * CDDL HEADER END
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf/*
903a11ebdc8df157c4700150f41f1f262f4a8ae8rh * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * Use is subject to license terms.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf#include <sys/types.h>
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf#include <sys/conf.h>
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf#include <sys/ddi.h>
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf#include <sys/sunddi.h>
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf#include <sys/ksynch.h>
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf#include <sys/scsi/conf/autoconf.h>
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf#include <sys/reboot.h>
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf#include "ghd.h"
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf/*
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * Local functions
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlfstatic gcmd_t *ghd_timeout_get(ccc_t *cccp);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlfstatic int ghd_timeout_loop(ccc_t *cccp);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlfstatic uint_t ghd_timeout_softintr(caddr_t arg);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlfstatic void ghd_timeout(void *arg);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlfstatic void ghd_timeout_disable(tmr_t *tmrp);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlfstatic void ghd_timeout_enable(tmr_t *tmrp);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf/*
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * Local data
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlflong ghd_HZ;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlfstatic kmutex_t tglobal_mutex;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf/* table of timeouts for abort processing steps */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlfcmdstate_t ghd_timeout_table[GCMD_NSTATES];
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf/* This table indirectly initializes the ghd_timeout_table */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlfstruct {
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf int valid;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf cmdstate_t state;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf long value;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf} ghd_time_inits[] = {
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf { TRUE, GCMD_STATE_ABORTING_CMD, 3 },
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf { TRUE, GCMD_STATE_ABORTING_DEV, 3 },
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf { TRUE, GCMD_STATE_RESETTING_DEV, 5 },
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf { TRUE, GCMD_STATE_RESETTING_BUS, 10 },
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf { TRUE, GCMD_STATE_HUNG, 60},
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf { FALSE, 0, 0 }, /* spare entry */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf { FALSE, 0, 0 }, /* spare entry */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf { FALSE, 0, 0 }, /* spare entry */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf { FALSE, 0, 0 }, /* spare entry */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf { FALSE, 0, 0 } /* spare entry */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf};
507c32411f3f101e90ca2120f042b5ee698ba1d5mlfint ghd_ntime_inits = sizeof (ghd_time_inits)
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf / sizeof (ghd_time_inits[0]);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf/*
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * Locally-used macros
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf/*
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * Compare two gcmd_t's to see if they're for the same device (same gdev_t)
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf#define GCMD_SAME_DEV(gcmdp1, gcmdp2) \
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf (GCMDP2GDEVP(gcmdp1) == GCMDP2GDEVP(gcmdp2))
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf/*
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * Compare two gcmd_t's to see if they're for the same bus (same HBA inst)
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf#define GCMD_SAME_BUS(gcmdp1, gcmdp2) \
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf (GCMDP2CCCP(gcmdp1) == GCMDP2CCCP(gcmdp2))
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf/*
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * Update state of gcmdp (in one direction, increasing state number, only)
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf#define GCMD_UPDATE_STATE(gcmdp, newstate) \
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf{ \
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf if ((gcmdp)->cmd_state < (newstate)) { \
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf ((gcmdp)->cmd_state = (newstate)); \
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf } \
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf}
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf#ifdef ___notyet___
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf#include <sys/modctl.h>
507c32411f3f101e90ca2120f042b5ee698ba1d5mlfextern struct mod_ops mod_miscops;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlfstatic struct modlmisc modlmisc = {
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf &mod_miscops, /* Type of module */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf "CCB Timeout Utility Routines"
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf};
507c32411f3f101e90ca2120f042b5ee698ba1d5mlfstatic struct modlinkage modlinkage = {
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf MODREV_1, (void *)&modlmisc, NULL
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf};
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf/*
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * If this is a loadable module then there's a single CCB timer configure
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * structure for all HBA drivers (rather than one per HBA driver).
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlfstatic tmr_t tmr_conf;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlfint
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf_init()
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf{
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf int err;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf ghd_timer_init(&tmr_conf, 0);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf return ((err = mod_install(&modlinkage)) != 0)
903a11ebdc8df157c4700150f41f1f262f4a8ae8rh ghd_timer_fini(&tmr_conf);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf return (err);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf}
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlfint
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf_fini()
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf{
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf int err;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf if ((err = mod_remove(&modlinkage)) == 0)
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf ghd_timer_fini(&tmr_conf);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf return (err);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf}
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlfint
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf_info(struct modinfo *modinfop)
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf{
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf return (mod_info(&modlinkage, modinfop));
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf}
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf#endif /* ___notyet___ */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf/*
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf *
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * ghd_timeout_loop()
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf *
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * Check the CCB timer value for every active CCB for this
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * HBA driver instance.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf *
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * This function is called both by the ghd_timeout() interrupt
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * handler when called via the timer callout, and by ghd_timer_poll()
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * while procesing "polled" (FLAG_NOINTR) requests.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf *
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * The ccc_activel_mutex is held while a CCB list is being scanned.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * This prevents the HBA driver's transport or interrupt functions
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * from changing the active CCB list. But we wake up very infrequently
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * and do as little as possible so it shouldn't affect performance.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf *
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlfstatic int
507c32411f3f101e90ca2120f042b5ee698ba1d5mlfghd_timeout_loop(ccc_t *cccp)
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf{
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf int got_any = FALSE;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf gcmd_t *gcmdp;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf ulong_t lbolt;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf mutex_enter(&cccp->ccc_activel_mutex);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf lbolt = ddi_get_lbolt();
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf gcmdp = (gcmd_t *)L2_next(&cccp->ccc_activel);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf while (gcmdp) {
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf /*
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * check to see if this one has timed out
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf if ((gcmdp->cmd_timeout > 0) &&
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf (lbolt - gcmdp->cmd_start_time >= gcmdp->cmd_timeout)) {
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf got_any = TRUE;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf }
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf gcmdp = (gcmd_t *)L2_next(&gcmdp->cmd_timer_link);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf }
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf mutex_exit(&cccp->ccc_activel_mutex);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf return (got_any);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf}
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf/*
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf *
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * ghd_timeout()
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf *
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * Called every t_ticks ticks to scan the CCB timer lists
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf *
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * The t_mutex mutex is held the entire time this routine is active.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * It protects the list of ccc_t's.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf *
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * The list of cmd_t's is protected by the ccc_activel_mutex mutex
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * in the ghd_timeout_loop() routine.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf *
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * We also check to see if the waitq is frozen, and if so,
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * adjust our timeout to call back sooner if necessary (to
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * unfreeze the waitq as soon as possible).
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf *
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf *
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * +------------+
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * | tmr_t |----+
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * +------------+ |
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * |
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * V
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * +---------+
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * | ccc_t |----+
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * +---------+ |
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * | V
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * | +--------+ +--------+
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * | | gcmd_t |-->| gcmd_t |--> ...
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * | +--------+ +--------+
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * V
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * +---------+
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * | ccc_t |----+
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * +---------+ |
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * | V
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * | +--------+
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * | | gcmd_t |
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * V +--------+
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * ...
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf *
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf *
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf *
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlfstatic void
507c32411f3f101e90ca2120f042b5ee698ba1d5mlfghd_timeout(void *arg)
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf{
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf tmr_t *tmrp = (tmr_t *)arg;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf ccc_t *cccp;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf clock_t ufdelay_curr;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf clock_t lbolt, delay_in_hz;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf clock_t resched = (clock_t)0x7FFFFFFF;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf /*
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * Each HBA driver instance has a separate CCB timer list. Skip
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * timeout processing if there are no more active timeout lists
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * to process. (There are no lists only if there are no attached
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * HBA instances; the list still exists if there are no outstanding
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * active commands.)
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf mutex_enter(&tmrp->t_mutex);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf if ((cccp = tmrp->t_ccc_listp) == NULL) {
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf mutex_exit(&tmrp->t_mutex);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf return;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf }
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf lbolt = ddi_get_lbolt();
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf do {
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf /*
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * If any active CCBs on this HBA have timed out
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * then kick off the HBA driver's softintr
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * handler to do the timeout processing
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf if (ghd_timeout_loop(cccp)) {
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf cccp->ccc_timeout_pending = 1;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf ddi_trigger_softintr(cccp->ccc_soft_id);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf }
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf /* Record closest unfreeze time for use in next timeout */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf mutex_enter(&cccp->ccc_waitq_mutex);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf if (cccp->ccc_waitq_frozen) {
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf delay_in_hz =
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf drv_usectohz(cccp->ccc_waitq_freezedelay * 1000);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf ufdelay_curr = delay_in_hz -
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf (lbolt - cccp->ccc_waitq_freezetime);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf if (ufdelay_curr < resched)
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf resched = ufdelay_curr;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf /* frozen; trigger softintr to maybe unfreeze */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf ddi_trigger_softintr(cccp->ccc_soft_id);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf }
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf mutex_exit(&cccp->ccc_waitq_mutex);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf } while ((cccp = cccp->ccc_nextp) != NULL);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf /* don't allow any unfreeze delays to increase the timeout delay */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf if (resched > tmrp->t_ticks)
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf resched = tmrp->t_ticks;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf /* re-establish the timeout callback */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf tmrp->t_timeout_id = timeout(ghd_timeout, (void *)tmrp, resched);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf mutex_exit(&tmrp->t_mutex);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf}
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf/*
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf *
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * ghd_timer_newstate()
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf *
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * The HBA mutex is held by my caller.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf *
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlfvoid
507c32411f3f101e90ca2120f042b5ee698ba1d5mlfghd_timer_newstate(ccc_t *cccp, gcmd_t *gcmdp, gtgt_t *gtgtp,
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf gact_t action, int calltype)
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf{
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf gact_t next_action;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf cmdstate_t next_state;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf char *msgp;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf long new_timeout;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf int (*func)(void *, gcmd_t *, gtgt_t *, gact_t, int);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf void *hba_handle;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf gcmd_t gsav;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf int gsav_used = 0;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf gcmd_t *gcmdp_scan;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf ASSERT(mutex_owned(&cccp->ccc_hba_mutex));
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf#ifdef DEBUG
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf /* it shouldn't be on the timer active list */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf if (gcmdp != NULL) {
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf L2el_t *lp = &gcmdp->cmd_timer_link;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf ASSERT(lp->l2_nextp == lp);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf ASSERT(lp->l2_prevp == lp);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf }
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf#endif
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf func = cccp->ccc_timeout_func;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf hba_handle = cccp->ccc_hba_handle;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf for (;;) {
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf switch (action) {
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf case GACTION_EARLY_ABORT:
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf /* done before it started */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf ASSERT(gcmdp != NULL);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf msgp = "early abort";
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf next_state = GCMD_STATE_DONEQ;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf next_action = GACTION_ABORT_CMD;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf break;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf case GACTION_EARLY_TIMEOUT:
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf /* done before it started */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf ASSERT(gcmdp != NULL);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf msgp = "early timeout";
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf next_state = GCMD_STATE_DONEQ;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf next_action = GACTION_ABORT_CMD;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf break;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf case GACTION_ABORT_CMD:
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf msgp = "abort request";
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf ASSERT(gcmdp != NULL);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf next_state = GCMD_STATE_ABORTING_CMD;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf next_action = GACTION_ABORT_DEV;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf break;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf case GACTION_ABORT_DEV:
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf msgp = "abort device";
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf next_state = GCMD_STATE_ABORTING_DEV;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf next_action = GACTION_RESET_TARGET;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf break;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf case GACTION_RESET_TARGET:
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf msgp = "reset target";
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf next_state = GCMD_STATE_RESETTING_DEV;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf next_action = GACTION_RESET_BUS;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf break;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf case GACTION_RESET_BUS:
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf msgp = "reset bus";
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf next_state = GCMD_STATE_RESETTING_BUS;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf next_action = GACTION_INCOMPLETE;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf break;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf case GACTION_INCOMPLETE:
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf default:
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf /* be verbose about HBA resets */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf GDBG_ERROR(("?ghd_timer_newstate: HBA reset failed "
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf "hba 0x%p gcmdp 0x%p gtgtp 0x%p\n",
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf (void *)hba_handle, (void *)gcmdp, (void *)gtgtp));
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf /*
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * When all else fails, punt.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf *
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * We're in big trouble if we get to this point.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * Maybe we should try to re-initialize the HBA.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf msgp = "HBA reset";
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf next_state = GCMD_STATE_HUNG;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf next_action = GACTION_INCOMPLETE;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf break;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf }
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf /*
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * I want to see target requests only if verbose, but
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * scsi_log() only prints the device pathname if level
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * is CE_WARN or CE_PANIC...so I guess we can't use
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * scsi_log for TGTREQ messages, or they must come to
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * the console. How silly. Looking for "verbose boot"
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * is non-DDI-compliant, but let's do it anyway.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf if (calltype == GHD_TGTREQ) {
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf if ((boothowto & RB_VERBOSE)) {
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf scsi_log(cccp->ccc_hba_dip, cccp->ccc_label,
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf CE_WARN,
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf "target request: %s, target=%d lun=%d",
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf msgp, gtgtp->gt_target, gtgtp->gt_lun);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf }
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf } else {
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf scsi_log(cccp->ccc_hba_dip, cccp->ccc_label, CE_WARN,
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf "timeout: %s, target=%d lun=%d", msgp,
903a11ebdc8df157c4700150f41f1f262f4a8ae8rh gtgtp->gt_target, gtgtp->gt_lun);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf }
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf /*
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * Before firing off the HBA action, restart the timer
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * using the timeout value from ghd_timeout_table[].
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf *
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * The table entries should never restart the timer
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * for the GHD_STATE_IDLE and GHD_STATE_DONEQ states.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf *
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf if (gcmdp) {
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf gcmdp->cmd_state = next_state;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf new_timeout = ghd_timeout_table[gcmdp->cmd_state];
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf if (new_timeout != 0)
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf ghd_timer_start(cccp, gcmdp, new_timeout);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf /* save a copy in case action function frees it */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf gsav = *gcmdp;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf gsav_used = 1;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf }
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf if (action == GACTION_RESET_BUS && cccp->ccc_waitq_frozen) {
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf GDBG_WARN(("avoiding bus reset while waitq frozen\n"));
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf break;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf }
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf /* invoke the HBA's action function */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf if ((*func)(hba_handle, gcmdp, gtgtp, action, calltype)) {
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf /* if it took wait for an interrupt or timeout */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf break;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf }
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf /*
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * if the HBA reset fails leave the retry
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * timer running and just exit.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf if (action == GACTION_INCOMPLETE)
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf return;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf /* all other failures cause transition to next action */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf if (gcmdp != NULL && new_timeout != 0) {
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf /*
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * But stop the old timer prior to
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * restarting a new timer because each step may
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * have a different timeout value.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf GHD_TIMER_STOP(cccp, gcmdp);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf }
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf action = next_action;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf }
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf /*
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * HBA action function is done with gsav (if used)
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * or gtgtp/cccp (if gsav not used). We need to mark other
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * outstanding requests if they were affected by this action
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * (say, a device reset which also cancels all outstanding
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * requests on this device) to prevent multiple timeouts/HBA
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * actions for the same device or bus condition. Scan the timer
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * list (all active requests) and update states as necessary.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * Hold the activel_mutex while scanning the active list. Check
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * for either same dev/bus as gsav (if used) or for same
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * dev/bus as gtgtp or cccp (if gsav is not used).
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf mutex_enter(&cccp->ccc_activel_mutex);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf for (gcmdp_scan = (gcmd_t *)L2_next(&cccp->ccc_activel);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf gcmdp_scan != NULL;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf gcmdp_scan = (gcmd_t *)L2_next(&gcmdp_scan->cmd_timer_link)) {
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf /* skip idle or waitq commands */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf if (gcmdp_scan->cmd_state <= GCMD_STATE_WAITQ)
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf continue;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf switch (action) {
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf case GACTION_ABORT_DEV:
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf if ((gsav_used && GCMD_SAME_DEV(&gsav, gcmdp_scan)) ||
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf (GCMDP2GDEVP(gcmdp_scan) == GTGTP2GDEVP(gtgtp))) {
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf GCMD_UPDATE_STATE(gcmdp_scan,
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf GCMD_STATE_ABORTING_DEV);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf }
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf break;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf case GACTION_RESET_TARGET:
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf if ((gsav_used && GCMD_SAME_DEV(&gsav, gcmdp_scan)) ||
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf (GCMDP2GDEVP(gcmdp_scan) == GTGTP2GDEVP(gtgtp))) {
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf GCMD_UPDATE_STATE(gcmdp_scan,
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf GCMD_STATE_RESETTING_DEV);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf }
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf break;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf case GACTION_RESET_BUS:
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf if ((gsav_used && GCMD_SAME_BUS(&gsav, gcmdp_scan)) ||
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf (GCMDP2CCCP(gcmdp_scan) == cccp)) {
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf GCMD_UPDATE_STATE(gcmdp_scan,
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf GCMD_STATE_RESETTING_BUS);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf }
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf break;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf default:
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf break;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf }
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf }
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf mutex_exit(&cccp->ccc_activel_mutex);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf}
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf/*
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf *
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * ghd_timeout_softintr()
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf *
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * This interrupt is scheduled if a particular HBA instance's
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * CCB timer list has a timed out CCB, or if the waitq is in a
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * frozen state.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf *
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * Find the timed out CCB and then call the HBA driver's timeout
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * function.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf *
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * In order to avoid race conditions all processing must be done
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * while holding the HBA instance's mutex. If the mutex wasn't
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * held the HBA driver's hardware interrupt routine could be
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * triggered and it might try to remove a CCB from the list at
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * same time as were trying to abort it.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf *
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * For frozen-waitq processing, just call ghd_waitq_process...
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * it takes care of the time calculations.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf *
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlfstatic uint_t
507c32411f3f101e90ca2120f042b5ee698ba1d5mlfghd_timeout_softintr(caddr_t arg)
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf{
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf ccc_t *cccp = (ccc_t *)arg;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf if (cccp->ccc_timeout_pending) {
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf /* grab this HBA instance's mutex */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf mutex_enter(&cccp->ccc_hba_mutex);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf /*
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * The claim is we could reset "pending" outside the mutex, but
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * since we have to acquire the mutex anyway, it doesn't hurt
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf cccp->ccc_timeout_pending = 0;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf /* timeout each expired CCB */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf ghd_timer_poll(cccp, GHD_TIMER_POLL_ALL);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf mutex_enter(&cccp->ccc_waitq_mutex);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf ghd_waitq_process_and_mutex_exit(cccp);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf } else if (cccp->ccc_waitq_frozen) {
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf mutex_enter(&cccp->ccc_hba_mutex);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf mutex_enter(&cccp->ccc_waitq_mutex);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf ghd_waitq_process_and_mutex_exit(cccp);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf }
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf return (DDI_INTR_UNCLAIMED);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf}
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf/*
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * ghd_timer_poll()
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf *
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * This function steps a packet to the next action in the recovery
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * procedure.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf *
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * The caller must be already holding the HBA mutex and take care of
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * running the pkt completion functions.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf *
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlfvoid
507c32411f3f101e90ca2120f042b5ee698ba1d5mlfghd_timer_poll(ccc_t *cccp, gtimer_poll_t calltype)
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf{
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf gcmd_t *gcmdp;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf gact_t action;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf ASSERT(mutex_owned(&cccp->ccc_hba_mutex));
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf /* abort each expired CCB */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf while (gcmdp = ghd_timeout_get(cccp)) {
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf GDBG_INTR(("?ghd_timer_poll: cccp=0x%p gcmdp=0x%p\n",
903a11ebdc8df157c4700150f41f1f262f4a8ae8rh (void *)cccp, (void *)gcmdp));
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf switch (gcmdp->cmd_state) {
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf case GCMD_STATE_IDLE:
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf case GCMD_STATE_DONEQ:
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf default:
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf /* not supposed to happen */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf GDBG_ERROR(("ghd_timer_poll: invalid state %d\n",
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf gcmdp->cmd_state));
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf return;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf case GCMD_STATE_WAITQ:
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf action = GACTION_EARLY_TIMEOUT;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf break;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf case GCMD_STATE_ACTIVE:
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf action = GACTION_ABORT_CMD;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf break;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf case GCMD_STATE_ABORTING_CMD:
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf action = GACTION_ABORT_DEV;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf break;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf case GCMD_STATE_ABORTING_DEV:
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf action = GACTION_RESET_TARGET;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf break;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf case GCMD_STATE_RESETTING_DEV:
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf action = GACTION_RESET_BUS;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf break;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf case GCMD_STATE_RESETTING_BUS:
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf action = GACTION_INCOMPLETE;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf break;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf case GCMD_STATE_HUNG:
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf action = GACTION_INCOMPLETE;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf break;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf }
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf ghd_timer_newstate(cccp, gcmdp, gcmdp->cmd_gtgtp, action,
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf GHD_TIMEOUT);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf /* return after processing first cmd if requested */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf if (calltype == GHD_TIMER_POLL_ONE)
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf return;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf }
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf}
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf/*
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf *
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * ghd_timeout_get()
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf *
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * Remove the first expired CCB from a particular timer list.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf *
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlfstatic gcmd_t *
507c32411f3f101e90ca2120f042b5ee698ba1d5mlfghd_timeout_get(ccc_t *cccp)
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf{
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf gcmd_t *gcmdp;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf ulong_t lbolt;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf ASSERT(mutex_owned(&cccp->ccc_hba_mutex));
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf mutex_enter(&cccp->ccc_activel_mutex);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf lbolt = ddi_get_lbolt();
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf gcmdp = (gcmd_t *)L2_next(&cccp->ccc_activel);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf while (gcmdp != NULL) {
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf if ((gcmdp->cmd_timeout > 0) &&
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf (lbolt - gcmdp->cmd_start_time >= gcmdp->cmd_timeout))
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf goto expired;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf gcmdp = (gcmd_t *)L2_next(&gcmdp->cmd_timer_link);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf }
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf mutex_exit(&cccp->ccc_activel_mutex);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf return (NULL);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlfexpired:
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf /* unlink if from the CCB timer list */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf L2_delete(&gcmdp->cmd_timer_link);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf mutex_exit(&cccp->ccc_activel_mutex);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf return (gcmdp);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf}
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf/*
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf *
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * ghd_timeout_enable()
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf *
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * Only start a single timeout callback for each HBA driver
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * regardless of the number of boards it supports.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf *
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlfstatic void
507c32411f3f101e90ca2120f042b5ee698ba1d5mlfghd_timeout_enable(tmr_t *tmrp)
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf{
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf mutex_enter(&tglobal_mutex);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf if (tmrp->t_refs++ == 0) {
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf /* establish the timeout callback */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf tmrp->t_timeout_id = timeout(ghd_timeout, (void *)tmrp,
903a11ebdc8df157c4700150f41f1f262f4a8ae8rh tmrp->t_ticks);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf }
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf mutex_exit(&tglobal_mutex);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf}
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlfstatic void
507c32411f3f101e90ca2120f042b5ee698ba1d5mlfghd_timeout_disable(tmr_t *tmrp)
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf{
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf ASSERT(tmrp != NULL);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf mutex_enter(&tglobal_mutex);
b3c0e203b148ecc85043c9da9d327d45c6e7c470mlf if (tmrp->t_refs-- <= 1) {
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf (void) untimeout(tmrp->t_timeout_id);
b3c0e203b148ecc85043c9da9d327d45c6e7c470mlf }
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf mutex_exit(&tglobal_mutex);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf}
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf/* ************************************************************************ */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf /* these are the externally callable routines */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlfvoid
507c32411f3f101e90ca2120f042b5ee698ba1d5mlfghd_timer_init(tmr_t *tmrp, long ticks)
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf{
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf int indx;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf mutex_init(&tglobal_mutex, NULL, MUTEX_DRIVER, NULL);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf mutex_init(&tmrp->t_mutex, NULL, MUTEX_DRIVER, NULL);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf /*
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * determine default timeout value
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf ghd_HZ = drv_usectohz(1000000);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf if (ticks == 0)
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf ticks = scsi_watchdog_tick * ghd_HZ;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf tmrp->t_ticks = ticks;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf /*
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * Initialize the table of abort timer values using an
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * indirect lookup table so that this code isn't dependant
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * on the cmdstate_t enum values or order.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf for (indx = 0; indx < ghd_ntime_inits; indx++) {
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf int state;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf ulong_t value;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf if (!ghd_time_inits[indx].valid)
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf continue;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf state = ghd_time_inits[indx].state;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf value = ghd_time_inits[indx].value;
f304523c1c8b168f5db72cb0e24ee8318a974f8dzhongyan gu - Sun Microsystems - Beijing China ghd_timeout_table[state] = (cmdstate_t)value;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf }
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf}
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlfvoid
507c32411f3f101e90ca2120f042b5ee698ba1d5mlfghd_timer_fini(tmr_t *tmrp)
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf{
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf mutex_destroy(&tmrp->t_mutex);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf mutex_destroy(&tglobal_mutex);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf}
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlfint
507c32411f3f101e90ca2120f042b5ee698ba1d5mlfghd_timer_attach(ccc_t *cccp, tmr_t *tmrp,
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf int (*timeout_func)(void *, gcmd_t *, gtgt_t *, gact_t, int))
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf{
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf ddi_iblock_cookie_t iblock;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf if (ddi_add_softintr(cccp->ccc_hba_dip, DDI_SOFTINT_LOW,
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf &cccp->ccc_soft_id, &iblock, NULL,
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf ghd_timeout_softintr, (caddr_t)cccp) != DDI_SUCCESS) {
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf GDBG_ERROR((
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf "ghd_timer_attach: add softintr failed cccp 0x%p\n",
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf (void *)cccp));
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf return (FALSE);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf }
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf /* init the per HBA-instance control fields */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf mutex_init(&cccp->ccc_activel_mutex, NULL, MUTEX_DRIVER, iblock);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf L2_INIT(&cccp->ccc_activel);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf cccp->ccc_timeout_func = timeout_func;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf /* stick this HBA's control structure on the master list */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf mutex_enter(&tmrp->t_mutex);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf cccp->ccc_nextp = tmrp->t_ccc_listp;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf tmrp->t_ccc_listp = cccp;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf cccp->ccc_tmrp = tmrp;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf mutex_exit(&tmrp->t_mutex);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf /*
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * The enable and disable routines use a separate mutex than
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * t_mutex which is used by the timeout callback function.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * This is to avoid a deadlock when calling untimeout() from
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * the disable routine.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf ghd_timeout_enable(tmrp);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf return (TRUE);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf}
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf/*
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf *
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * ghd_timer_detach()
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf *
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * clean up for a detaching HBA instance
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf *
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlfvoid
507c32411f3f101e90ca2120f042b5ee698ba1d5mlfghd_timer_detach(ccc_t *cccp)
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf{
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf tmr_t *tmrp = cccp->ccc_tmrp;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf ccc_t **prevpp;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf /* make certain the CCB list is empty */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf ASSERT(cccp->ccc_activel.l2_nextp == &cccp->ccc_activel);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf ASSERT(cccp->ccc_activel.l2_nextp == cccp->ccc_activel.l2_prevp);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf mutex_enter(&tmrp->t_mutex);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf prevpp = &tmrp->t_ccc_listp;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf ASSERT(*prevpp != NULL);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf /* run down the linked list to find the entry that preceeds this one */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf do {
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf if (*prevpp == cccp)
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf goto remove_it;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf prevpp = &(*prevpp)->ccc_nextp;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf } while (*prevpp != NULL);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf /* fell off the end of the list */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf GDBG_ERROR(("ghd_timer_detach: corrupt list, cccp=0x%p\n",
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf (void *)cccp));
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlfremove_it:
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf *prevpp = cccp->ccc_nextp;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf mutex_exit(&tmrp->t_mutex);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf mutex_destroy(&cccp->ccc_activel_mutex);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf ddi_remove_softintr(cccp->ccc_soft_id);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf ghd_timeout_disable(tmrp);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf}
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf/*
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf *
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * ghd_timer_start()
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf *
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * Add a CCB to the CCB timer list.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlfvoid
507c32411f3f101e90ca2120f042b5ee698ba1d5mlfghd_timer_start(ccc_t *cccp, gcmd_t *gcmdp, long cmd_timeout)
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf{
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf ulong_t lbolt;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf mutex_enter(&cccp->ccc_activel_mutex);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf lbolt = ddi_get_lbolt();
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf /* initialize this CCB's timer */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf gcmdp->cmd_start_time = lbolt;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf gcmdp->cmd_timeout = (cmd_timeout * ghd_HZ);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf /* add it to the list */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf L2_add(&cccp->ccc_activel, &gcmdp->cmd_timer_link, gcmdp);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf mutex_exit(&cccp->ccc_activel_mutex);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf}
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf/*
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf *
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * ghd_timer_stop()
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf *
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * Remove a completed CCB from the CCB timer list.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf *
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * See the GHD_TIMER_STOP_INLINE() macro in ghd.h for
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * the actual code.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf
507c32411f3f101e90ca2120f042b5ee698ba1d5mlfvoid
507c32411f3f101e90ca2120f042b5ee698ba1d5mlfghd_timer_stop(ccc_t *cccp, gcmd_t *gcmdp)
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf{
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf GHD_TIMER_STOP_INLINE(cccp, gcmdp);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf}