507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * CDDL HEADER START
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 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * See the License for the specific language governing permissions
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * and limitations under the License.
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 * CDDL HEADER END
903a11ebdc8df157c4700150f41f1f262f4a8ae8rh * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * Use is subject to license terms.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * Local functions
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * Local data
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf/* table of timeouts for abort processing steps */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf/* This table indirectly initializes the ghd_timeout_table */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf / sizeof (ghd_time_inits[0]);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * Locally-used macros
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * Compare two gcmd_t's to see if they're for the same device (same gdev_t)
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * Compare two gcmd_t's to see if they're for the same bus (same HBA inst)
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * Update state of gcmdp (in one direction, increasing state number, only)
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf "CCB Timeout Utility Routines"
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#endif /* ___notyet___ */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * ghd_timeout_loop()
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * Check the CCB timer value for every active CCB for this
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * HBA driver instance.
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 * 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 * check to see if this one has timed out
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf (lbolt - gcmdp->cmd_start_time >= gcmdp->cmd_timeout)) {
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * ghd_timeout()
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * Called every t_ticks ticks to scan the CCB timer lists
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * The t_mutex mutex is held the entire time this routine is active.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * It protects the list of ccc_t's.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * The list of cmd_t's is protected by the ccc_activel_mutex mutex
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * in the ghd_timeout_loop() routine.
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 * | tmr_t |----+
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * +------------+ |
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * +---------+
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * | ccc_t |----+
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * +---------+ |
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * | +--------+ +--------+
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * | | gcmd_t |-->| gcmd_t |--> ...
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * | +--------+ +--------+
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * +---------+
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * | ccc_t |----+
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * +---------+ |
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * | +--------+
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * | | gcmd_t |
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * V +--------+
507c32411f3f101e90ca2120f042b5ee698ba1d5mlfstatic void
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 * 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 /* Record closest unfreeze time for use in next timeout */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf /* frozen; trigger softintr to maybe unfreeze */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf /* don't allow any unfreeze delays to increase the timeout delay */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf /* re-establish the timeout callback */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf tmrp->t_timeout_id = timeout(ghd_timeout, (void *)tmrp, resched);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * ghd_timer_newstate()
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * The HBA mutex is held by my caller.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlfghd_timer_newstate(ccc_t *cccp, gcmd_t *gcmdp, gtgt_t *gtgtp,
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf /* it shouldn't be on the timer active list */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf for (;;) {
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf /* done before it started */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf /* done before it started */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf /* be verbose about HBA resets */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf "hba 0x%p gcmdp 0x%p gtgtp 0x%p\n",
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * When all else fails, punt.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * We're in big trouble if we get to this point.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * Maybe we should try to re-initialize the HBA.
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 "target request: %s, target=%d lun=%d",
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * Before firing off the HBA action, restart the timer
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * using the timeout value from ghd_timeout_table[].
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * The table entries should never restart the timer
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * for the GHD_STATE_IDLE and GHD_STATE_DONEQ states.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf /* save a copy in case action function frees it */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf if (action == GACTION_RESET_BUS && cccp->ccc_waitq_frozen) {
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 * if the HBA reset fails leave the retry
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * timer running and just exit.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf /* all other failures cause transition to next action */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * But stop the old timer prior to
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * restarting a new timer because each step may
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * have a different timeout value.
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 for (gcmdp_scan = (gcmd_t *)L2_next(&cccp->ccc_activel);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf gcmdp_scan = (gcmd_t *)L2_next(&gcmdp_scan->cmd_timer_link)) {
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf /* skip idle or waitq commands */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * ghd_timeout_softintr()
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 * Find the timed out CCB and then call the HBA driver's timeout
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * function.
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 * For frozen-waitq processing, just call ghd_waitq_process...
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * it takes care of the time calculations.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf /* grab this HBA instance's mutex */
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 /* timeout each expired CCB */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * ghd_timer_poll()
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * This function steps a packet to the next action in the recovery
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * procedure.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * The caller must be already holding the HBA mutex and take care of
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * running the pkt completion functions.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf /* abort each expired CCB */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf /* not supposed to happen */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf ghd_timer_newstate(cccp, gcmdp, gcmdp->cmd_gtgtp, action,
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf /* return after processing first cmd if requested */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * ghd_timeout_get()
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * Remove the first expired CCB from a particular timer list.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf /* unlink if from the CCB timer list */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * ghd_timeout_enable()
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * Only start a single timeout callback for each HBA driver
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * regardless of the number of boards it supports.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlfstatic void
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf /* establish the timeout callback */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlfstatic void
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf/* ************************************************************************ */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf /* these are the externally callable routines */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * determine default timeout value
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.
f304523c1c8b168f5db72cb0e24ee8318a974f8dzhongyan gu - Sun Microsystems - Beijing China ghd_timeout_table[state] = (cmdstate_t)value;
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf int (*timeout_func)(void *, gcmd_t *, gtgt_t *, gact_t, int))
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf if (ddi_add_softintr(cccp->ccc_hba_dip, DDI_SOFTINT_LOW,
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf "ghd_timer_attach: add softintr failed cccp 0x%p\n",
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf (void *)cccp));
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf /* init the per HBA-instance control fields */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf mutex_init(&cccp->ccc_activel_mutex, NULL, MUTEX_DRIVER, iblock);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf /* stick this HBA's control structure on the master list */
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 * ghd_timer_detach()
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * clean up for a detaching HBA instance
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 /* run down the linked list to find the entry that preceeds this one */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf /* fell off the end of the list */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf GDBG_ERROR(("ghd_timer_detach: corrupt list, cccp=0x%p\n",
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf (void *)cccp));
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * ghd_timer_start()
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * Add a CCB to the CCB timer list.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlfghd_timer_start(ccc_t *cccp, gcmd_t *gcmdp, long cmd_timeout)
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf /* initialize this CCB's timer */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf /* add it to the list */
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf L2_add(&cccp->ccc_activel, &gcmdp->cmd_timer_link, gcmdp);
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * ghd_timer_stop()
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * Remove a completed CCB from the CCB timer list.
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * See the GHD_TIMER_STOP_INLINE() macro in ghd.h for
507c32411f3f101e90ca2120f042b5ee698ba1d5mlf * the actual code.