/*
 *  scsi_error.c Copyright (C) 1997 Eric Youngdale
 *
 *  SCSI error/timeout handling
 *      Initial versions: Eric Youngdale.  Based upon conversations with
 *                        Leonard Zubkoff and David Miller at Linux Expo, 
 *                        ideas originating from all over the place.
 *
 */

#define __NO_VERSION__
#include <linux/module.h>

#include <linux/sched.h>
#include <linux/timer.h>
#include <linux/string.h>
#include <linux/slab.h>
#include <linux/ioport.h>
#include <linux/kernel.h>
#include <linux/stat.h>
#include <linux/blk.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/smp_lock.h>

#define __KERNEL_SYSCALLS__

#include <linux/unistd.h>

#include <asm/system.h>
#include <asm/irq.h>
#include <asm/dma.h>

#include "scsi.h"
#include "hosts.h"
#include "constants.h"

#include <scsi/scsi_ioctl.h> /* grr */

/*
 * We must always allow SHUTDOWN_SIGS.  Even if we are not a module,
 * the host drivers that we are using may be loaded as modules, and
 * when we unload these,  we need to ensure that the error handler thread
 * can be shut down.
 *
 * Note - when we unload a module, we send a SIGHUP.  We mustn't
 * enable SIGTERM, as this is how the init shuts things down when you
 * go to single-user mode.  For that matter, init also sends SIGKILL,
 * so we mustn't enable that one either.  We use SIGHUP instead.  Other
 * options would be SIGPWR, I suppose.
 */
#define SHUTDOWN_SIGS	(sigmask(SIGHUP))

/*
 * The number of times we retry a REQUEST SENSE and TEST UNIT READY
 * respectively.  This is arbitary.
 */
#define SENSE_RETRIES	5
#define TUR_RETRIES	5

#ifdef DEBUG
#define SENSE_TIMEOUT SCSI_TIMEOUT
#define ABORT_TIMEOUT SCSI_TIMEOUT
#define RESET_TIMEOUT SCSI_TIMEOUT
#else
#define SENSE_TIMEOUT (10*HZ)
#define RESET_TIMEOUT (2*HZ)
#define ABORT_TIMEOUT (15*HZ)
#endif

#define STATIC

/*
 * These should *probably* be handled by the host itself.
 * Since it is allowed to sleep, it probably should.
 */
#define BUS_RESET_SETTLE_TIME   5*HZ
#define HOST_RESET_SETTLE_TIME  10*HZ


static const char RCSid[] = "$Header: /cvsroot/ts-7200/dist/linux24/drivers/scsi/scsi_error.c,v 1.2 2004/08/04 01:29:37 joff Exp $";

STATIC int scsi_check_sense(Scsi_Cmnd * SCpnt);
STATIC int scsi_request_sense(Scsi_Cmnd *);
STATIC void scsi_send_eh_cmnd(Scsi_Cmnd * SCpnt, int timeout);
STATIC int scsi_try_to_abort_command(Scsi_Cmnd *, int);
STATIC int scsi_test_unit_ready(Scsi_Cmnd *);
STATIC int scsi_try_bus_device_reset(Scsi_Cmnd *, int timeout);
STATIC int scsi_try_bus_reset(Scsi_Cmnd *);
STATIC int scsi_try_host_reset(Scsi_Cmnd *);
STATIC int scsi_unit_is_ready(Scsi_Cmnd *);
STATIC void scsi_eh_action_done(Scsi_Cmnd *, int);
STATIC int scsi_eh_retry_command(Scsi_Cmnd *);
STATIC int scsi_eh_completed_normally(Scsi_Cmnd * SCpnt);
STATIC void scsi_restart_operations(struct Scsi_Host *);
STATIC void scsi_eh_finish_command(Scsi_Cmnd ** SClist, Scsi_Cmnd * SCpnt);


/*
 * Function:    scsi_add_timer()
 *
 * Purpose:     Start timeout timer for a single scsi command.
 *
 * Arguments:   SCset   - command that is about to start running.
 *              timeout - amount of time to allow this command to run.
 *              complete - timeout function to call if timer isn't
 *                      canceled.
 *
 * Returns:     Nothing
 *
 * Notes:       This should be turned into an inline function.
 *
 * More Notes:  Each scsi command has it's own timer, and as it is added to
 *              the queue, we set up the timer.  When the command completes,
 *              we cancel the timer.  Pretty simple, really, especially
 *              compared to the old way of handling this crap.
 */
void scsi_add_timer(Scsi_Cmnd * SCset,
		    int timeout,
		    void (*complete) (Scsi_Cmnd *))
{
	SCset->eh_timeout.data = (unsigned long) SCset;
	SCset->eh_timeout.function = (void (*)(unsigned long)) complete;
	mod_timer(&SCset->eh_timeout, jiffies + timeout);

	SCset->done_late = 0;

	SCSI_LOG_ERROR_RECOVERY(5, printk("Adding timer for command %p at %d (%p)\n", SCset, timeout, complete));
}

/*
 * Function:    scsi_delete_timer()
 *
 * Purpose:     Delete/cancel timer for a given function.
 *
 * Arguments:   SCset   - command that we are canceling timer for.
 *
 * Returns:     1 if we were able to detach the timer.  0 if we
 *              blew it, and the timer function has already started
 *              to run.
 *
 * Notes:       This should be turned into an inline function.
 */
int scsi_delete_timer(Scsi_Cmnd * SCset)
{
	int rtn;

	rtn = del_timer(&SCset->eh_timeout);

	SCSI_LOG_ERROR_RECOVERY(5, printk("Clearing timer for command %p %d\n", SCset, rtn));

	SCset->eh_timeout.data = (unsigned long) NULL;
	SCset->eh_timeout.function = NULL;

	return rtn;
}

/*
 * Function:    scsi_times_out()
 *
 * Purpose:     Timeout function for normal scsi commands..
 *
 * Arguments:   SCpnt   - command that is timing out.
 *
 * Returns:     Nothing.
 *
 * Notes:       We do not need to lock this.  There is the potential for
 *              a race only in that the normal completion handling might
 *              run, but if the normal completion function determines
 *              that the timer has already fired, then it mustn't do
 *              anything.
 */
void scsi_times_out(Scsi_Cmnd * SCpnt)
{
	/* 
	 * Notify the low-level code that this operation failed and we are
	 * reposessing the command.  
	 */
#ifdef ERIC_neverdef
	/*
	 * FIXME(eric)
	 * Allow the host adapter to push a queue ordering tag
	 * out to the bus to force the command in question to complete.
	 * If the host wants to do this, then we just restart the timer
	 * for the command.  Before we really do this, some real thought
	 * as to the optimum way to handle this should be done.  We *do*
	 * need to force ordering every so often to ensure that all requests
	 * do eventually complete, but I am not sure if this is the best way
	 * to actually go about it.
	 *
	 * Better yet, force a sync here, but don't block since we are in an
	 * interrupt.
	 */
	if (SCpnt->host->hostt->eh_ordered_queue_tag) {
		if ((*SCpnt->host->hostt->eh_ordered_queue_tag) (SCpnt)) {
			scsi_add_timer(SCpnt, SCpnt->internal_timeout,
				       scsi_times_out);
			return;
		}
	}
	/*
	 * FIXME(eric) - add a second special interface to handle this
	 * case.  Ideally that interface can also be used to request
	 * a queu
	 */
	if (SCpnt->host->can_queue) {
		SCpnt->host->hostt->queuecommand(SCpnt, NULL);
	}
#endif

	/* Set the serial_number_at_timeout to the current serial_number */
	SCpnt->serial_number_at_timeout = SCpnt->serial_number;

	SCpnt->eh_state = FAILED;
	SCpnt->state = SCSI_STATE_TIMEOUT;
	SCpnt->owner = SCSI_OWNER_ERROR_HANDLER;

	SCpnt->host->in_recovery = 1;
	SCpnt->host->host_failed++;

	SCSI_LOG_TIMEOUT(3, printk("Command timed out active=%d busy=%d failed=%d\n",
				   atomic_read(&SCpnt->host->host_active),
				   SCpnt->host->host_busy,
				   SCpnt->host->host_failed));

	/*
	 * If the host is having troubles, then look to see if this was the last
	 * command that might have failed.  If so, wake up the error handler.
	 */
	if( SCpnt->host->eh_wait == NULL ) {
		panic("Error handler thread not present at %p %p %s %d", 
		      SCpnt, SCpnt->host, __FILE__, __LINE__);
	}
	if (SCpnt->host->host_busy == SCpnt->host->host_failed) {
		up(SCpnt->host->eh_wait);
	}
}

/*
 * Function     scsi_block_when_processing_errors
 *
 * Purpose:     Prevent more commands from being queued while error recovery
 *              is taking place.
 *
 * Arguments:   SDpnt - device on which we are performing recovery.
 *
 * Returns:     FALSE   The device was taken offline by error recovery.
 *              TRUE    OK to proceed.
 *
 * Notes:       We block until the host is out of error recovery, and then
 *              check to see whether the host or the device is offline.
 */
int scsi_block_when_processing_errors(Scsi_Device * SDpnt)
{

	SCSI_SLEEP(&SDpnt->host->host_wait, SDpnt->host->in_recovery);

	SCSI_LOG_ERROR_RECOVERY(5, printk("Open returning %d\n", SDpnt->online));

	return SDpnt->online;
}

/*
 * Function:    scsi_eh_times_out()
 *
 * Purpose:     Timeout function for error handling.
 *
 * Arguments:   SCpnt   - command that is timing out.
 *
 * Returns:     Nothing.
 *
 * Notes:       During error handling, the kernel thread will be sleeping
 *              waiting for some action to complete on the device.  Our only
 *              job is to record that it timed out, and to wake up the
 *              thread.
 */
STATIC
void scsi_eh_times_out(Scsi_Cmnd * SCpnt)
{
	SCpnt->eh_state = SCSI_STATE_TIMEOUT;
	SCSI_LOG_ERROR_RECOVERY(5, printk("In scsi_eh_times_out %p\n", SCpnt));

	if (SCpnt->host->eh_action != NULL)
		up(SCpnt->host->eh_action);
	else
		printk("Missing scsi error handler thread\n");
}


/*
 * Function:    scsi_eh_done()
 *
 * Purpose:     Completion function for error handling.
 *
 * Arguments:   SCpnt   - command that is timing out.
 *
 * Returns:     Nothing.
 *
 * Notes:       During error handling, the kernel thread will be sleeping
 *              waiting for some action to complete on the device.  Our only
 *              job is to record that the action completed, and to wake up the
 *              thread.
 */
STATIC
void scsi_eh_done(Scsi_Cmnd * SCpnt)
{
	int     rtn;

	/*
	 * If the timeout handler is already running, then just set the
	 * flag which says we finished late, and return.  We have no
	 * way of stopping the timeout handler from running, so we must
	 * always defer to it.
	 */
	rtn = del_timer(&SCpnt->eh_timeout);
	if (!rtn) {
		SCpnt->done_late = 1;
		return;
	}

	SCpnt->request.rq_status = RQ_SCSI_DONE;

	SCpnt->owner = SCSI_OWNER_ERROR_HANDLER;
	SCpnt->eh_state = SUCCESS;

	SCSI_LOG_ERROR_RECOVERY(5, printk("In eh_done %p result:%x\n", SCpnt,
					  SCpnt->result));

	if (SCpnt->host->eh_action != NULL)
		up(SCpnt->host->eh_action);
}

/*
 * Function:    scsi_eh_action_done()
 *
 * Purpose:     Completion function for error handling.
 *
 * Arguments:   SCpnt   - command that is timing out.
 *              answer  - boolean that indicates whether operation succeeded.
 *
 * Returns:     Nothing.
 *
 * Notes:       This callback is only used for abort and reset operations.
 */
STATIC
void scsi_eh_action_done(Scsi_Cmnd * SCpnt, int answer)
{
	SCpnt->request.rq_status = RQ_SCSI_DONE;

	SCpnt->owner = SCSI_OWNER_ERROR_HANDLER;
	SCpnt->eh_state = (answer ? SUCCESS : FAILED);

	if (SCpnt->host->eh_action != NULL)
		up(SCpnt->host->eh_action);
}

/*
 * Function:  scsi_sense_valid()
 *
 * Purpose:     Determine whether a host has automatically obtained sense
 *              information or not.  If we have it, then give a recommendation
 *              as to what we should do next.
 */
int scsi_sense_valid(Scsi_Cmnd * SCpnt)
{
	if (((SCpnt->sense_buffer[0] & 0x70) >> 4) != 7) {
		return FALSE;
	}
	return TRUE;
}

/*
 * Function:  scsi_eh_retry_command()
 *
 * Purpose:     Retry the original command
 *
 * Returns:     SUCCESS - we were able to get the sense data.
 *              FAILED  - we were not able to get the sense data.
 * 
 * Notes:       This function will *NOT* return until the command either
 *              times out, or it completes.
 */
STATIC int scsi_eh_retry_command(Scsi_Cmnd * SCpnt)
{
	int tries = 0;

	do {
		scsi_setup_cmd_retry(SCpnt);
		scsi_send_eh_cmnd(SCpnt, SCpnt->timeout_per_command);
	} while (SCpnt->eh_state == NEEDS_RETRY && tries++ < SCpnt->allowed);

	/*
	 * Hey, we are done.  Let's look to see what happened.
	 */
	return SCpnt->eh_state;
}

/*
 * Function:  scsi_request_sense()
 *
 * Purpose:     Request sense data from a particular target.
 *
 * Returns:     SUCCESS - we were able to get the sense data.
 *              FAILED  - we were not able to get the sense data.
 * 
 * Notes:       Some hosts automatically obtain this information, others
 *              require that we obtain it on our own.
 *
 *              This function will *NOT* return until the command either
 *              times out, or it completes.
 */
STATIC int scsi_request_sense(Scsi_Cmnd * SCpnt)
{
	static unsigned char generic_sense[6] =
	{REQUEST_SENSE, 0, 0, 0, 255, 0};
	unsigned char scsi_result0[256], *scsi_result = NULL;
	int saved_result, tries;

	ASSERT_LOCK(&io_request_lock, 0);

	scsi_result = (!SCpnt->host->hostt->unchecked_isa_dma)
	    ? &scsi_result0[0] : kmalloc(512, GFP_ATOMIC | GFP_DMA);

	if (scsi_result == NULL) {
		printk("cannot allocate scsi_result in scsi_request_sense.\n");
		return FAILED;
	}

	saved_result = SCpnt->result;

	tries = 0;
	do {
		memcpy((void *) SCpnt->cmnd, (void *) generic_sense,
		       sizeof(generic_sense));

		if (SCpnt->device->scsi_level <= SCSI_2)
			SCpnt->cmnd[1] = SCpnt->lun << 5;

		/*
		 * Zero the sense buffer.  Some host adapters automatically
		 * always request sense, so it is not a good idea that
		 * SCpnt->request_buffer and SCpnt->sense_buffer point to
		 * the same address (DB).  0 is not a valid sense code. 
		 */
		memset((void *) SCpnt->sense_buffer, 0,
		       sizeof(SCpnt->sense_buffer));
		memset((void *) scsi_result, 0, 256);

		SCpnt->request_buffer = scsi_result;
		SCpnt->request_bufflen = 256;
		SCpnt->use_sg = 0;
		SCpnt->cmd_len = COMMAND_SIZE(SCpnt->cmnd[0]);
		SCpnt->sc_data_direction = SCSI_DATA_READ;
		SCpnt->underflow = 0;

		scsi_send_eh_cmnd(SCpnt, SENSE_TIMEOUT);
		/*
		 * If the SCSI device responded with "logical unit
		 * is in process of becoming ready", we need to
		 * retry this command.
		 */
	} while (SCpnt->eh_state == NEEDS_RETRY && tries++ < SENSE_RETRIES);

	/* Last chance to have valid sense data */
	if (!scsi_sense_valid(SCpnt))
		memcpy((void *) SCpnt->sense_buffer,
		       SCpnt->request_buffer,
		       sizeof(SCpnt->sense_buffer));

	if (scsi_result != &scsi_result0[0] && scsi_result != NULL)
		kfree(scsi_result);

	/*
	 * When we eventually call scsi_finish, we really wish to complete
	 * the original request, so let's restore the original data. (DB)
	 */
	SCpnt->result = saved_result;
	scsi_setup_cmd_retry(SCpnt);

	/*
	 * Hey, we are done.  Let's look to see what happened.
	 */
	return SCpnt->eh_state;
}

/*
 * Function:  scsi_test_unit_ready()
 *
 * Purpose:     Run test unit ready command to see if the device is talking to us or not.
 *
 */
STATIC int scsi_test_unit_ready(Scsi_Cmnd * SCpnt)
{
	static unsigned char tur_command[6] =
	{TEST_UNIT_READY, 0, 0, 0, 0, 0};
	int tries = 0;

	do {
		memcpy((void *) SCpnt->cmnd, (void *) tur_command,
		       sizeof(tur_command));

		if (SCpnt->device->scsi_level <= SCSI_2)
			SCpnt->cmnd[1] = SCpnt->lun << 5;

		/*
		 * Zero the sense buffer.  The SCSI spec mandates that any
		 * untransferred sense data should be interpreted as being zero.
		 */
		memset((void *) SCpnt->sense_buffer, 0,
		       sizeof(SCpnt->sense_buffer));

		SCpnt->request_buffer = NULL;
		SCpnt->request_bufflen = 0;
		SCpnt->use_sg = 0;
		SCpnt->cmd_len = COMMAND_SIZE(SCpnt->cmnd[0]);
		SCpnt->underflow = 0;
		SCpnt->sc_data_direction = SCSI_DATA_NONE;

		scsi_send_eh_cmnd(SCpnt, SENSE_TIMEOUT);
		/*
		 * If the SCSI device responded with "logical unit
		 * is in process of becoming ready", we need to
		 * retry this command.
		 */
	} while (SCpnt->eh_state == NEEDS_RETRY && tries++ < TUR_RETRIES);

	/*
	 * When we eventually call scsi_finish, we really wish to complete
	 * the original request, so let's restore the original data. (DB)
	 */
	scsi_setup_cmd_retry(SCpnt);

	/*
	 * Hey, we are done.  Let's look to see what happened.
	 */
	SCSI_LOG_ERROR_RECOVERY(3,
		printk("scsi_test_unit_ready: SCpnt %p eh_state %x\n",
		SCpnt, SCpnt->eh_state));
	return SCpnt->eh_state;
}

/*
 * This would normally need to get the IO request lock,
 * but as it doesn't actually touch anything that needs
 * to be locked we can avoid the lock here..
 */
STATIC
void scsi_sleep_done(struct semaphore *sem)
{
	if (sem != NULL) {
		up(sem);
	}
}

void scsi_sleep(int timeout)
{
	DECLARE_MUTEX_LOCKED(sem);
	struct timer_list timer;

	init_timer(&timer);
	timer.data = (unsigned long) &sem;
	timer.expires = jiffies + timeout;
	timer.function = (void (*)(unsigned long)) scsi_sleep_done;

	SCSI_LOG_ERROR_RECOVERY(5, printk("Sleeping for timer tics %d\n", timeout));

	add_timer(&timer);

	down(&sem);
	del_timer(&timer);
}

/*
 * Function:  scsi_send_eh_cmnd
 *
 * Purpose:     Send a command out to a device as part of error recovery.
 *
 * Notes:       The initialization of the structures is quite a bit different
 *              in this case, and furthermore, there is a different completion
 *              handler.
 */
STATIC void scsi_send_eh_cmnd(Scsi_Cmnd * SCpnt, int timeout)
{
	unsigned long flags;
	struct Scsi_Host *host;

	ASSERT_LOCK(&io_request_lock, 0);

	host = SCpnt->host;

	/*
	 * We will use a queued command if possible, otherwise we will emulate the
	 * queuing and calling of completion function ourselves.
	 */
	SCpnt->owner = SCSI_OWNER_LOWLEVEL;

	if (host->can_queue) {
		DECLARE_MUTEX_LOCKED(sem);

		SCpnt->eh_state = SCSI_STATE_QUEUED;

		scsi_add_timer(SCpnt, timeout, scsi_eh_times_out);

		/*
		 * Set up the semaphore so we wait for the command to complete.
		 */
		SCpnt->host->eh_action = &sem;
		SCpnt->request.rq_status = RQ_SCSI_BUSY;

		spin_lock_irqsave(&io_request_lock, flags);
		host->hostt->queuecommand(SCpnt, scsi_eh_done);
		spin_unlock_irqrestore(&io_request_lock, flags);

		down(&sem);

		SCpnt->host->eh_action = NULL;

		/*
		 * See if timeout.  If so, tell the host to forget about it.
		 * In other words, we don't want a callback any more.
		 */
		if (SCpnt->eh_state == SCSI_STATE_TIMEOUT) {
                        SCpnt->owner = SCSI_OWNER_LOWLEVEL;

			/*
			 * As far as the low level driver is
			 * concerned, this command is still active, so
			 * we must give the low level driver a chance
			 * to abort it. (DB) 
			 *
			 * FIXME(eric) - we are not tracking whether we could
			 * abort a timed out command or not.  Not sure how
			 * we should treat them differently anyways.
			 */
			spin_lock_irqsave(&io_request_lock, flags);
			if (SCpnt->host->hostt->eh_abort_handler)
				SCpnt->host->hostt->eh_abort_handler(SCpnt);
			spin_unlock_irqrestore(&io_request_lock, flags);
			
			SCpnt->request.rq_status = RQ_SCSI_DONE;
			SCpnt->owner = SCSI_OWNER_ERROR_HANDLER;
			
			SCpnt->eh_state = FAILED;
		}
		SCSI_LOG_ERROR_RECOVERY(5, printk("send_eh_cmnd: %p eh_state:%x\n",
						SCpnt, SCpnt->eh_state));
	} else {
		int temp;

		/*
		 * We damn well had better never use this code.  There is no timeout
		 * protection here, since we would end up waiting in the actual low
		 * level driver, we don't know how to wake it up.
		 */
		spin_lock_irqsave(&io_request_lock, flags);
		temp = host->hostt->command(SCpnt);
		spin_unlock_irqrestore(&io_request_lock, flags);

		SCpnt->result = temp;
		/* Fall through to code below to examine status. */
		SCpnt->eh_state = SUCCESS;
	}

	/*
	 * Now examine the actual status codes to see whether the command actually
	 * did complete normally.
	 */
	if (SCpnt->eh_state == SUCCESS) {
		int ret = scsi_eh_completed_normally(SCpnt);
		SCSI_LOG_ERROR_RECOVERY(3,
			printk("scsi_send_eh_cmnd: scsi_eh_completed_normally %x\n", ret));
		switch (ret) {
		default:
			ret = FAILED;
			/*FALLTHROUGH*/
		case FAILED:
		case NEEDS_RETRY:
		case SUCCESS:
			SCpnt->eh_state = ret;
			break;
		}
	} else {
		SCpnt->eh_state = FAILED;
	}
}

/*
 * Function:  scsi_unit_is_ready()
 *
 * Purpose:     Called after TEST_UNIT_READY is run, to test to see if
 *              the unit responded in a way that indicates it is ready.
 */
STATIC int scsi_unit_is_ready(Scsi_Cmnd * SCpnt)
{
	if (SCpnt->result) {
		if (((driver_byte(SCpnt->result) & DRIVER_SENSE) ||
		     (status_byte(SCpnt->result) & CHECK_CONDITION)) &&
		    ((SCpnt->sense_buffer[0] & 0x70) >> 4) == 7) {
			if (((SCpnt->sense_buffer[2] & 0xf) != NOT_READY) &&
			    ((SCpnt->sense_buffer[2] & 0xf) != UNIT_ATTENTION) &&
			    ((SCpnt->sense_buffer[2] & 0xf) != ILLEGAL_REQUEST)) {
				return 0;
			}
		}
	}
	return 1;
}

/*
 * Function:    scsi_eh_finish_command
 *
 * Purpose:     Handle a command that we are finished with WRT error handling.
 *
 * Arguments:   SClist - pointer to list into which we are putting completed commands.
 *              SCpnt  - command that is completing
 *
 * Notes:       We don't want to use the normal command completion while we are
 *              are still handling errors - it may cause other commands to be queued,
 *              and that would disturb what we are doing.  Thus we really want to keep
 *              a list of pending commands for final completion, and once we
 *              are ready to leave error handling we handle completion for real.
 */
STATIC void scsi_eh_finish_command(Scsi_Cmnd ** SClist, Scsi_Cmnd * SCpnt)
{
	SCpnt->state = SCSI_STATE_BHQUEUE;
	SCpnt->bh_next = *SClist;
	/*
	 * Set this back so that the upper level can correctly free up
	 * things.
	 */
	SCpnt->use_sg = SCpnt->old_use_sg;
	SCpnt->sc_data_direction = SCpnt->sc_old_data_direction;
	SCpnt->underflow = SCpnt->old_underflow;
	*SClist = SCpnt;
}

/*
 * Function:  scsi_try_to_abort_command
 *
 * Purpose:     Ask host adapter to abort a running command.
 *
 * Returns:     FAILED          Operation failed or not supported.
 *              SUCCESS         Succeeded.
 *
 * Notes:       This function will not return until the user's completion
 *              function has been called.  There is no timeout on this
 *              operation.  If the author of the low-level driver wishes
 *              this operation to be timed, they can provide this facility
 *              themselves.  Helper functions in scsi_error.c can be supplied
 *              to make this easier to do.
 *
 * Notes:       It may be possible to combine this with all of the reset
 *              handling to eliminate a lot of code duplication.  I don't
 *              know what makes more sense at the moment - this is just a
 *              prototype.
 */
STATIC int scsi_try_to_abort_command(Scsi_Cmnd * SCpnt, int timeout)
{
	int rtn;
	unsigned long flags;

	SCpnt->eh_state = FAILED;	/* Until we come up with something better */

	if (SCpnt->host->hostt->eh_abort_handler == NULL) {
		return FAILED;
	}
	/* 
	 * scsi_done was called just after the command timed out and before
	 * we had a chance to process it. (DB)
	 */
	if (SCpnt->serial_number == 0)
		return SUCCESS;

	SCpnt->owner = SCSI_OWNER_LOWLEVEL;

	spin_lock_irqsave(&io_request_lock, flags);
	rtn = SCpnt->host->hostt->eh_abort_handler(SCpnt);
	spin_unlock_irqrestore(&io_request_lock, flags);
	return rtn;
}

/*
 * Function:  scsi_try_bus_device_reset
 *
 * Purpose:     Ask host adapter to perform a bus device reset for a given
 *              device.
 *
 * Returns:     FAILED          Operation failed or not supported.
 *              SUCCESS         Succeeded.
 *
 * Notes:       There is no timeout for this operation.  If this operation is
 *              unreliable for a given host, then the host itself needs to put a
 *              timer on it, and set the host back to a consistent state prior
 *              to returning.
 */
STATIC int scsi_try_bus_device_reset(Scsi_Cmnd * SCpnt, int timeout)
{
	unsigned long flags;
	int rtn;

	SCpnt->eh_state = FAILED;	/* Until we come up with something better */

	if (SCpnt->host->hostt->eh_device_reset_handler == NULL) {
		return FAILED;
	}
	SCpnt->owner = SCSI_OWNER_LOWLEVEL;

	spin_lock_irqsave(&io_request_lock, flags);
	rtn = SCpnt->host->hostt->eh_device_reset_handler(SCpnt);
	spin_unlock_irqrestore(&io_request_lock, flags);

	if (rtn == SUCCESS)
		SCpnt->eh_state = SUCCESS;

	return SCpnt->eh_state;
}

/*
 * Function:  scsi_try_bus_reset
 *
 * Purpose:     Ask host adapter to perform a bus reset for a host.
 *
 * Returns:     FAILED          Operation failed or not supported.
 *              SUCCESS         Succeeded.
 *
 * Notes:       
 */
STATIC int scsi_try_bus_reset(Scsi_Cmnd * SCpnt)
{
	unsigned long flags;
	int rtn;

	SCpnt->eh_state = FAILED;	/* Until we come up with something better */
	SCpnt->owner = SCSI_OWNER_LOWLEVEL;
	SCpnt->serial_number_at_timeout = SCpnt->serial_number;

	if (SCpnt->host->hostt->eh_bus_reset_handler == NULL) {
		return FAILED;
	}

	spin_lock_irqsave(&io_request_lock, flags);
	rtn = SCpnt->host->hostt->eh_bus_reset_handler(SCpnt);
	spin_unlock_irqrestore(&io_request_lock, flags);

	if (rtn == SUCCESS)
		SCpnt->eh_state = SUCCESS;

	/*
	 * If we had a successful bus reset, mark the command blocks to expect
	 * a condition code of unit attention.
	 */
	scsi_sleep(BUS_RESET_SETTLE_TIME);
	if (SCpnt->eh_state == SUCCESS) {
		Scsi_Device *SDloop;
		for (SDloop = SCpnt->host->host_queue; SDloop; SDloop = SDloop->next) {
			if (SCpnt->channel == SDloop->channel) {
				SDloop->was_reset = 1;
				SDloop->expecting_cc_ua = 1;
			}
		}
	}
	return SCpnt->eh_state;
}

/*
 * Function:  scsi_try_host_reset
 *
 * Purpose:     Ask host adapter to reset itself, and the bus.
 *
 * Returns:     FAILED          Operation failed or not supported.
 *              SUCCESS         Succeeded.
 *
 * Notes:
 */
STATIC int scsi_try_host_reset(Scsi_Cmnd * SCpnt)
{
	unsigned long flags;
	int rtn;

	SCpnt->eh_state = FAILED;	/* Until we come up with something better */
	SCpnt->owner = SCSI_OWNER_LOWLEVEL;
	SCpnt->serial_number_at_timeout = SCpnt->serial_number;

	if (SCpnt->host->hostt->eh_host_reset_handler == NULL) {
		return FAILED;
	}
	spin_lock_irqsave(&io_request_lock, flags);
	rtn = SCpnt->host->hostt->eh_host_reset_handler(SCpnt);
	spin_unlock_irqrestore(&io_request_lock, flags);

	if (rtn == SUCCESS)
		SCpnt->eh_state = SUCCESS;

	/*
	 * If we had a successful host reset, mark the command blocks to expect
	 * a condition code of unit attention.
	 */
	scsi_sleep(HOST_RESET_SETTLE_TIME);
	if (SCpnt->eh_state == SUCCESS) {
		Scsi_Device *SDloop;
		for (SDloop = SCpnt->host->host_queue; SDloop; SDloop = SDloop->next) {
			SDloop->was_reset = 1;
			SDloop->expecting_cc_ua = 1;
		}
	}
	return SCpnt->eh_state;
}

/*
 * Function:  scsi_decide_disposition
 *
 * Purpose:     Examine a command block that has come back from the low-level
 *              and figure out what to do next.
 *
 * Returns:     SUCCESS         - pass on to upper level.
 *              FAILED          - pass on to error handler thread.
 *              RETRY           - command should be retried.
 *              SOFTERR         - command succeeded, but we need to log
 *                                a soft error.
 *
 * Notes:       This is *ONLY* called when we are examining the status
 *              after sending out the actual data command.  Any commands
 *              that are queued for error recovery (i.e. TEST_UNIT_READY)
 *              do *NOT* come through here.
 *
 *              NOTE - When this routine returns FAILED, it means the error
 *              handler thread is woken.  In cases where the error code
 *              indicates an error that doesn't require the error handler
 *              thread (i.e. we don't need to abort/reset), then this function
 *              should return SUCCESS.
 */
int scsi_decide_disposition(Scsi_Cmnd * SCpnt)
{
	int rtn;

	/*
	 * If the device is offline, then we clearly just pass the result back
	 * up to the top level.
	 */
	if (SCpnt->device->online == FALSE) {
		SCSI_LOG_ERROR_RECOVERY(5, printk("scsi_error.c: device offline - report as SUCCESS\n"));
		return SUCCESS;
	}
	/*
	 * First check the host byte, to see if there is anything in there
	 * that would indicate what we need to do.
	 */

	switch (host_byte(SCpnt->result)) {
	case DID_PASSTHROUGH:
		/*
		 * No matter what, pass this through to the upper layer.
		 * Nuke this special code so that it looks like we are saying
		 * DID_OK.
		 */
		SCpnt->result &= 0xff00ffff;
		return SUCCESS;
	case DID_OK:
		/*
		 * Looks good.  Drop through, and check the next byte.
		 */
		break;
	case DID_NO_CONNECT:
	case DID_BAD_TARGET:
	case DID_ABORT:
		/*
		 * Note - this means that we just report the status back to the
		 * top level driver, not that we actually think that it indicates
		 * success.
		 */
		return SUCCESS;
		/*
		 * When the low level driver returns DID_SOFT_ERROR,
		 * it is responsible for keeping an internal retry counter 
		 * in order to avoid endless loops (DB)
		 *
		 * Actually this is a bug in this function here.  We should
		 * be mindful of the maximum number of retries specified
		 * and not get stuck in a loop.
		 */
	case DID_SOFT_ERROR:
		goto maybe_retry;

	case DID_ERROR:
		if (msg_byte(SCpnt->result) == COMMAND_COMPLETE &&
		    status_byte(SCpnt->result) == RESERVATION_CONFLICT)
			/*
			 * execute reservation conflict processing code
			 * lower down
			 */
			break;
		/* FALLTHROUGH */

	case DID_BUS_BUSY:
	case DID_PARITY:
		goto maybe_retry;
	case DID_TIME_OUT:
		/*
		 * When we scan the bus, we get timeout messages for
		 * these commands if there is no device available.
		 * Other hosts report DID_NO_CONNECT for the same thing.
		 */
		if ((SCpnt->cmnd[0] == TEST_UNIT_READY ||
		     SCpnt->cmnd[0] == INQUIRY)) {
			return SUCCESS;
		} else {
			return FAILED;
		}
	case DID_RESET:
		/*
		 * In the normal case where we haven't initiated a reset, this is
		 * a failure.
		 */
		if (SCpnt->flags & IS_RESETTING) {
			SCpnt->flags &= ~IS_RESETTING;
			goto maybe_retry;
		}
		return SUCCESS;
	default:
		return FAILED;
	}

	/*
	 * Next, check the message byte.
	 */
	if (msg_byte(SCpnt->result) != COMMAND_COMPLETE) {
		return FAILED;
	}
	/*
	 * Now, check the status byte to see if this indicates anything special.
	 */
	switch (status_byte(SCpnt->result)) {
	case QUEUE_FULL:
		/*
		 * The case of trying to send too many commands to a tagged queueing
		 * device.
		 */
		return ADD_TO_MLQUEUE;
	case GOOD:
	case COMMAND_TERMINATED:
		return SUCCESS;
	case CHECK_CONDITION:
		rtn = scsi_check_sense(SCpnt);
		if (rtn == NEEDS_RETRY) {
			goto maybe_retry;
		}
		return rtn;
	case CONDITION_GOOD:
	case INTERMEDIATE_GOOD:
	case INTERMEDIATE_C_GOOD:
		/*
		 * Who knows?  FIXME(eric)
		 */
		return SUCCESS;
	case BUSY:
		goto maybe_retry;

	case RESERVATION_CONFLICT:
		printk("scsi%d (%d,%d,%d) : RESERVATION CONFLICT\n", 
		       SCpnt->host->host_no, SCpnt->channel,
		       SCpnt->device->id, SCpnt->device->lun);
		return SUCCESS; /* causes immediate I/O error */
	default:
		return FAILED;
	}
	return FAILED;

      maybe_retry:

	if ((++SCpnt->retries) < SCpnt->allowed) {
		return NEEDS_RETRY;
	} else {
                /*
                 * No more retries - report this one back to upper level.
                 */
		return SUCCESS;
	}
}

/*
 * Function:  scsi_eh_completed_normally
 *
 * Purpose:     Examine a command block that has come back from the low-level
 *              and figure out what to do next.
 *
 * Returns:     SUCCESS         - pass on to upper level.
 *              FAILED          - pass on to error handler thread.
 *              RETRY           - command should be retried.
 *              SOFTERR         - command succeeded, but we need to log
 *                                a soft error.
 *
 * Notes:       This is *ONLY* called when we are examining the status
 *              of commands queued during error recovery.  The main
 *              difference here is that we don't allow for the possibility
 *              of retries here, and we are a lot more restrictive about what
 *              we consider acceptable.
 */
STATIC int scsi_eh_completed_normally(Scsi_Cmnd * SCpnt)
{
	/*
	 * First check the host byte, to see if there is anything in there
	 * that would indicate what we need to do.
	 */
	if (host_byte(SCpnt->result) == DID_RESET) {
		if (SCpnt->flags & IS_RESETTING) {
			/*
			 * OK, this is normal.  We don't know whether in fact the
			 * command in question really needs to be rerun or not - 
			 * if this was the original data command then the answer is yes,
			 * otherwise we just flag it as success.
			 */
			SCpnt->flags &= ~IS_RESETTING;
			return NEEDS_RETRY;
		}
		/*
		 * Rats.  We are already in the error handler, so we now get to try
		 * and figure out what to do next.  If the sense is valid, we have
		 * a pretty good idea of what to do.  If not, we mark it as failed.
		 */
		return scsi_check_sense(SCpnt);
	}
	if (host_byte(SCpnt->result) != DID_OK) {
		return FAILED;
	}
	/*
	 * Next, check the message byte.
	 */
	if (msg_byte(SCpnt->result) != COMMAND_COMPLETE) {
		return FAILED;
	}
	/*
	 * Now, check the status byte to see if this indicates anything special.
	 */
	switch (status_byte(SCpnt->result)) {
	case GOOD:
	case COMMAND_TERMINATED:
		return SUCCESS;
	case CHECK_CONDITION:
		return scsi_check_sense(SCpnt);
	case CONDITION_GOOD:
	case INTERMEDIATE_GOOD:
	case INTERMEDIATE_C_GOOD:
		/*
		 * Who knows?  FIXME(eric)
		 */
		return SUCCESS;
	case BUSY:
	case QUEUE_FULL:
	case RESERVATION_CONFLICT:
	default:
		return FAILED;
	}
	return FAILED;
}

/*
 * Function:  scsi_check_sense
 *
 * Purpose:     Examine sense information - give suggestion as to what
 *              we should do with it.
 */
STATIC int scsi_check_sense(Scsi_Cmnd * SCpnt)
{
	if (!scsi_sense_valid(SCpnt)) {
		return FAILED;
	}
	if (SCpnt->sense_buffer[2] & 0xe0)
		return SUCCESS;

	switch (SCpnt->sense_buffer[2] & 0xf) {
	case NO_SENSE:
		return SUCCESS;
	case RECOVERED_ERROR:
		return /* SOFT_ERROR */ SUCCESS;

	case ABORTED_COMMAND:
		return NEEDS_RETRY;
	case NOT_READY:
	case UNIT_ATTENTION:
		/*
		 * If we are expecting a CC/UA because of a bus reset that we
		 * performed, treat this just as a retry.  Otherwise this is
		 * information that we should pass up to the upper-level driver
		 * so that we can deal with it there.
		 */
		if (SCpnt->device->expecting_cc_ua) {
			SCpnt->device->expecting_cc_ua = 0;
			return NEEDS_RETRY;
		}
		/*
		 * If the device is in the process of becoming ready, we 
		 * should retry.
		 */
		if ((SCpnt->sense_buffer[12] == 0x04) &&
			(SCpnt->sense_buffer[13] == 0x01)) {
			return NEEDS_RETRY;
		}
		return SUCCESS;

		/* these three are not supported */
	case COPY_ABORTED:
	case VOLUME_OVERFLOW:
	case MISCOMPARE:
		return SUCCESS;

	case MEDIUM_ERROR:
		return NEEDS_RETRY;

	case ILLEGAL_REQUEST:
	case BLANK_CHECK:
	case DATA_PROTECT:
	case HARDWARE_ERROR:
	default:
		return SUCCESS;
	}
}


/*
 * Function:	scsi_eh_lock_done
 *
 * Purpose:	free the command and request structures associated
 *		with the error handlers door lock request
 *
 * Arguments:	SCpnt - the SCSI command block for the door lock request.
 *
 * Returns:	Nothing
 *
 * Notes:	We completed the asynchronous door lock request, and
 *		it has either locked the door or failed.  We must free
 *		the command structures associated with this request.
 */
static void scsi_eh_lock_done(struct scsi_cmnd *SCpnt)
{
	struct scsi_request *SRpnt = SCpnt->sc_request;

	SCpnt->sc_request = NULL;
	SRpnt->sr_command = NULL;

	scsi_release_command(SCpnt);
	scsi_release_request(SRpnt);
}


/*
 * Function:	scsi_eh_lock_door
 *
 * Purpose:	Prevent medium removal for the specified device
 *
 * Arguments:	dev - SCSI device to prevent medium removal
 *
 * Locking:	We must be called from process context;
 *		scsi_allocate_request() may sleep.
 *
 * Returns:	Nothing
 *
 * Notes:	We queue up an asynchronous "ALLOW MEDIUM REMOVAL" request
 *		on the head of the devices request queue, and continue.
 *
 * Bugs:	scsi_allocate_request() may sleep waiting for existing
 *		requests to be processed.  However, since we haven't
 *		kicked off any request processing for this host, this
 *		may deadlock.
 *
 *		If scsi_allocate_request() fails for what ever reason,
 *		we completely forget to lock the door.
 */
STATIC void scsi_eh_lock_door(struct scsi_device *dev)
{
	struct scsi_request *SRpnt = scsi_allocate_request(dev);

	if (SRpnt == NULL) {
		/* what now? */
		return;
	}

	SRpnt->sr_cmnd[0] = ALLOW_MEDIUM_REMOVAL;
	SRpnt->sr_cmnd[1] = (dev->scsi_level <= SCSI_2) ? (dev->lun << 5) : 0;
	SRpnt->sr_cmnd[2] = 0;
	SRpnt->sr_cmnd[3] = 0;
	SRpnt->sr_cmnd[4] = SCSI_REMOVAL_PREVENT;
	SRpnt->sr_cmnd[5] = 0;
	SRpnt->sr_data_direction = SCSI_DATA_NONE;
	SRpnt->sr_bufflen = 0;
	SRpnt->sr_buffer = NULL;
	SRpnt->sr_allowed = 5;
	SRpnt->sr_done = scsi_eh_lock_done;
	SRpnt->sr_timeout_per_command = 10 * HZ;
	SRpnt->sr_cmd_len = COMMAND_SIZE(SRpnt->sr_cmnd[0]);

	scsi_insert_special_req(SRpnt, 1);
}


/*
 * Function:  scsi_restart_operations
 *
 * Purpose:     Restart IO operations to the specified host.
 *
 * Arguments:   host  - host that we are restarting
 *
 * Lock status: Assumed that locks are not held upon entry.
 *
 * Returns:     Nothing
 *
 * Notes:       When we entered the error handler, we blocked all further
 *              I/O to this device.  We need to 'reverse' this process.
 */
STATIC void scsi_restart_operations(struct Scsi_Host *host)
{
	Scsi_Device *SDpnt;
	unsigned long flags;

	ASSERT_LOCK(&io_request_lock, 0);

	/*
	 * If the door was locked, we need to insert a door lock request
	 * onto the head of the SCSI request queue for the device.  There
	 * is no point trying to lock the door of an off-line device.
	 */
	for (SDpnt = host->host_queue; SDpnt; SDpnt = SDpnt->next)
		if (SDpnt->online && SDpnt->locked)
			scsi_eh_lock_door(SDpnt);

	/*
	 * Next free up anything directly waiting upon the host.  This will be
	 * requests for character device operations, and also for ioctls to queued
	 * block devices.
	 */
	SCSI_LOG_ERROR_RECOVERY(5, printk("scsi_error.c: Waking up host to restart\n"));

	wake_up(&host->host_wait);

	/*
	 * Finally we need to re-initiate requests that may be pending.  We will
	 * have had everything blocked while error handling is taking place, and
	 * now that error recovery is done, we will need to ensure that these
	 * requests are started.
	 */
	spin_lock_irqsave(&io_request_lock, flags);
	for (SDpnt = host->host_queue; SDpnt; SDpnt = SDpnt->next) {
		request_queue_t *q;
		if ((host->can_queue > 0 && (host->host_busy >= host->can_queue))
		    || (host->host_blocked)
		    || (host->host_self_blocked)) {
			break;
		}
		q = &SDpnt->request_queue;
		q->request_fn(q);
	}
	spin_unlock_irqrestore(&io_request_lock, flags);
}

/*
 * Function:	scsi_eh_find_failed_command
 *
 * Purpose:	Find a failed Scsi_Cmnd structure on a device.
 *
 * Arguments:	SDpnt	- Scsi_Device structure
 *
 * Returns:	Pointer to Scsi_Cmnd structure, or NULL on failure
 */
STATIC Scsi_Cmnd *scsi_eh_find_failed_command(Scsi_Device *SDpnt)
{
	Scsi_Cmnd *SCpnt;

	for (SCpnt = SDpnt->device_queue; SCpnt; SCpnt = SCpnt->next)
		if (SCpnt->state == SCSI_STATE_FAILED ||
		    SCpnt->state == SCSI_STATE_TIMEOUT)
			return SCpnt;

	return NULL;
}


/*
 * Function:	scsi_eh_test_and_retry
 *
 * Purpose:	Try to retry a failed command.
 *
 * Arguments:	SCpnt	- scsi command structure
 *		done	- list of commands that have been successfully
 *			  completed.
 *
 * Returns:	SUCCESS or FAILED
 *
 * Note:	If the TEST UNIT READY command successfully executes,
 *		but returns some form of "device not ready", we wait
 *		a while, and retry 3 times.  The device could be still
 *		re-initialising.
 */
STATIC int scsi_eh_test_and_retry(Scsi_Cmnd *SCpnt, Scsi_Cmnd **done)
{
	int rtn, tries = 3;

	do {
		rtn = scsi_test_unit_ready(SCpnt);
		if (rtn != SUCCESS)
			return rtn;

		if (scsi_unit_is_ready(SCpnt))
			break;

		if (tries-- == 0)
			return FAILED;

		scsi_sleep(5 * HZ);
	} while (1);

	rtn = scsi_eh_retry_command(SCpnt);
	if (rtn == SUCCESS) {
		SCpnt->host->host_failed--;
		scsi_eh_finish_command(done, SCpnt);
	}

	return rtn;
}


/*
 * Function:	scsi_eh_restart_device
 *
 * Purpose:	Retry all failed or timed out commands for a device
 *
 * Arguments:	SDpnt	- SCSI device to retry
 *		done	- list of commands that have been successfully
 *			  completed.
 *
 * Returns:	SUCCESS or failure code
 */
STATIC int scsi_eh_restart_device(Scsi_Device *SDpnt, Scsi_Cmnd **done)
{
	Scsi_Cmnd *SCpnt, *SCnext;
	int rtn = SUCCESS;

	for (SCpnt = SDpnt->device_queue; SCpnt; SCpnt = SCnext) {
		SCnext = SCpnt->next;

		if (SCpnt->state == SCSI_STATE_FAILED ||
		    SCpnt->state == SCSI_STATE_TIMEOUT) {
			rtn = scsi_eh_test_and_retry(SCpnt, done);
			if (rtn != SUCCESS)
				break;
		}
	}

	return rtn;
}

/*
 * Function:	scsi_eh_set_device_offline
 *
 * Purpose:	set a device off line
 *
 * Arguments:	SDpnt	- SCSI device to take off line
 *		done	- list of commands that have been successfully
 *			  completed.
 *		reason	- text string describing why the device is off-line
 *
 * Returns:	Nothing
 *
 * Notes:	In addition, we complete each failed or timed out command
 *		attached to this device.
 */
STATIC void scsi_eh_set_device_offline(Scsi_Device *SDpnt, Scsi_Cmnd **done,
				       const char *reason)
{
	Scsi_Cmnd *SCpnt, *SCnext;

	printk(KERN_ERR "scsi: device set offline - %s: "
		"host %d channel %d id %d lun %d\n",
		reason, SDpnt->host->host_no, SDpnt->channel,
		SDpnt->id, SDpnt->lun);

	SDpnt->online = FALSE;

	for (SCpnt = SDpnt->device_queue; SCpnt; SCpnt = SCnext) {
		SCnext = SCpnt->next;

		switch (SCpnt->state) {
		case SCSI_STATE_TIMEOUT:
			SCpnt->result |= DRIVER_TIMEOUT;
			/*FALLTHROUGH*/

		case SCSI_STATE_FAILED:
			SCSI_LOG_ERROR_RECOVERY(3,
				printk("Finishing command for device %d %x\n",
					SDpnt->id, SCpnt->result));

			SDpnt->host->host_failed--;
			scsi_eh_finish_command(done, SCpnt);
			break;

		default:
			break;
		}
	}
}

static void scsi_unjam_request_sense(struct Scsi_Host *host, Scsi_Cmnd **done)
{
	int rtn;
	int result;
	Scsi_Cmnd *SCpnt;
	Scsi_Device *SDpnt;

	/*
	 * Next, see if we need to request sense information.  if so,
	 * then get it now, so we have a better idea of what to do.
	 * FIXME(eric) this has the unfortunate side effect that if a
	 * host adapter does not automatically request sense information,
	 * that we end up shutting it down before we request it.  All
	 * hosts should be doing this anyways, so for now all I have
	 * to say is tough noogies if you end up in here.  On second
	 * thought, this is probably a good idea.  We *really* want
	 * to give authors an incentive to automatically request this.
	 */
	SCSI_LOG_ERROR_RECOVERY(3,
		printk("scsi_unjam_host: Checking to see if we need to request sense\n"));

	for (SDpnt = host->host_queue; SDpnt; SDpnt = SDpnt->next) {
		for (SCpnt = SDpnt->device_queue; SCpnt; SCpnt = SCpnt->next) {
			if (SCpnt->state != SCSI_STATE_FAILED || scsi_sense_valid(SCpnt))
				continue;

			SCSI_LOG_ERROR_RECOVERY(2,
				printk("scsi_unjam_host: Requesting sense for %d\n",
					  SCpnt->target));
			rtn = scsi_request_sense(SCpnt);
			if (rtn != SUCCESS)
				continue;

			SCSI_LOG_ERROR_RECOVERY(3,
				printk("Sense requested for %p - result %x\n",
					  SCpnt, SCpnt->result));
			SCSI_LOG_ERROR_RECOVERY(3, print_sense("bh", SCpnt));

			result = scsi_decide_disposition(SCpnt);

			/*
			 * If the result was normal, then just pass
			 * it along to the upper level.
			 */
			if (result == SUCCESS) {
				SCpnt->host->host_failed--;
				scsi_eh_finish_command(done, SCpnt);
			}
			if (result != NEEDS_RETRY)
				continue;

			/* 
			 * We only come in here if we want to retry a
			 * command.  The test to see whether the command
			 * should be retried should be keeping track of the
			 * number of tries, so we don't end up looping, of
			 * course.  
			 */
			SCpnt->state = NEEDS_RETRY;
			rtn = scsi_eh_retry_command(SCpnt);
			if (rtn != SUCCESS)
				continue;

			/*
			 * We eventually hand this one back to the top level.
			 */
			SCpnt->host->host_failed--;
			scsi_eh_finish_command(done, SCpnt);
		}
	}
}

static void scsi_unjam_count(struct Scsi_Host *host, Scsi_Cmnd **done)
{
	Scsi_Device *SDpnt;
	Scsi_Cmnd *SCpnt;
	int devices_failed;
	int numfailed;
	int timed_out;

	/*
	 * Go through the list of commands and figure out where we
	 * stand and how bad things really are.
	 */
	numfailed = 0;
	timed_out = 0;
	devices_failed = 0;
	for (SDpnt = host->host_queue; SDpnt; SDpnt = SDpnt->next) {
		unsigned int device_error = 0;

		for (SCpnt = SDpnt->device_queue; SCpnt; SCpnt = SCpnt->next) {
			if (SCpnt->state == SCSI_STATE_FAILED) {
				SCSI_LOG_ERROR_RECOVERY(5,
					printk("Command to ID %d failed\n",
						 SCpnt->target));
				numfailed++;
				device_error++;
			}
			if (SCpnt->state == SCSI_STATE_TIMEOUT) {
				SCSI_LOG_ERROR_RECOVERY(5,
					printk("Command to ID %d timedout\n",
						 SCpnt->target));
				timed_out++;
				device_error++;
			}
		}
		if (device_error > 0)
			devices_failed++;
	}

	SCSI_LOG_ERROR_RECOVERY(2,
		printk("Total of %d+%d commands on %d devices require eh work\n",
			  numfailed, timed_out, devices_failed));
}

static void scsi_unjam_abort(struct Scsi_Host *host, Scsi_Cmnd **done)
{
	Scsi_Device *SDpnt;
	Scsi_Cmnd *SCpnt;
	int rtn;

	/*
	 * Next, try and see whether or not it makes sense to try and
	 * abort the running command.  This only works out to be the
	 * case if we have one command that has timed out.  If the
	 * command simply failed, it makes no sense to try and abort
	 * the command, since as far as the host adapter is concerned,
	 * it isn't running.
	 */

	SCSI_LOG_ERROR_RECOVERY(3,
		printk("scsi_unjam_host: Checking to see if we want to try abort\n"));

	for (SDpnt = host->host_queue; SDpnt; SDpnt = SDpnt->next) {
		for (SCpnt = SDpnt->device_queue; SCpnt; SCpnt = SCpnt->next) {
			if (SCpnt->state != SCSI_STATE_TIMEOUT)
				continue;

			rtn = scsi_try_to_abort_command(SCpnt, ABORT_TIMEOUT);
			if (rtn == SUCCESS)
				scsi_eh_test_and_retry(SCpnt, done);
		}
	}
}

static void scsi_unjam_device_reset(struct Scsi_Host *host, Scsi_Cmnd **done)
{
	Scsi_Device *SDpnt;
	Scsi_Cmnd *SCpnt;
	int rtn;

	/*
	 * Either the abort wasn't appropriate, or it didn't succeed.
	 * Now try a bus device reset.  Still, look to see whether we
	 * have multiple devices that are jammed or not - if we have
	 * multiple devices, it makes no sense to try BUS_DEVICE_RESET
	 * - we really would need to try a BUS_RESET instead.
	 *
	 * Does this make sense - should we try BDR on each device
	 * individually?  Yes, definitely.
	 */
	SCSI_LOG_ERROR_RECOVERY(3,
		printk("scsi_unjam_host: Checking to see if we want to try BDR\n"));

	for (SDpnt = host->host_queue; SDpnt; SDpnt = SDpnt->next) {
		SCpnt = scsi_eh_find_failed_command(SDpnt);
		if (SCpnt == NULL)
			continue;

		/*
		 * OK, we have a device that is having problems.
		 * Try and send a bus device reset to it.
		 */
		rtn = scsi_try_bus_device_reset(SCpnt, RESET_TIMEOUT);

		/*
		 * A successful bus device reset causes all commands
		 * currently executing on the device to terminate.
		 * We expect the HBA driver to "forget" all commands
		 * associated with this device.
		 *
		 * Retry each failed or timed out command currently
		 * outstanding for this device.
		 *
		 * If any command fails, bail out.  We will try a
		 * bus reset instead.
		 */
		if (rtn == SUCCESS)
			scsi_eh_restart_device(SDpnt, done);
	}
}

static void scsi_unjam_bus_reset(struct Scsi_Host *host, Scsi_Cmnd **done)
{
	Scsi_Device *SDpnt;
	Scsi_Cmnd *SCpnt;
	int rtn, channel, max_channel = 0;

	/*
	 * If we ended up here, we have serious problems.  The only thing
	 * left to try is a full bus reset.  If someone has grabbed the
	 * bus and isn't letting go, then perhaps this will help.
	 */
	SCSI_LOG_ERROR_RECOVERY(3,
		printk("scsi_unjam_host: Try hard bus reset\n"));

	/*
	 * Find the maximum channel number for this host.
	 */
	for (SDpnt = host->host_queue; SDpnt; SDpnt = SDpnt->next)
		if (SDpnt->channel > max_channel)
			max_channel = SDpnt->channel;

	/*
	 * Loop over each channel, and see if it any device on
	 * each channel has failed.
	 */
	for (channel = 0; channel <= max_channel; channel++) {
		Scsi_Cmnd *failed_command;
		int soft_reset;

 try_again:
 		failed_command = NULL;
 		soft_reset = 0;

		/*
		 * Loop over each device on this channel locating any
		 * failed command.  We need a Scsi_Cmnd structure to
		 * call the bus reset function.
		 *
		 * We also need to check if any of the failed commands
		 * are on soft_reset devices, and if so, skip the reset.  
		 */
		for (SDpnt = host->host_queue; SDpnt; SDpnt = SDpnt->next) {
			if (SDpnt->channel != channel)
				continue;

			SCpnt = scsi_eh_find_failed_command(SDpnt);
			if (SCpnt)
				failed_command = SCpnt;

			/*
			 * If this device has timed out or failed commands,
			 * and uses the soft_reset option.
			 */
			if (SCpnt && SDpnt->soft_reset)
				soft_reset = 1;
		}

		/*
		 * If this channel hasn't failed, we
		 * don't need to reset it.
		 */
		if (!failed_command)
			continue;

		/* 
		 * If this device uses the soft reset option, and this
		 * is one of the devices acting up, then our only
		 * option is to wait a bit, since the command is
		 * supposedly still running.  
		 *
		 * FIXME(eric) - right now we will just end up falling
		 * through to the 'take device offline' case.
		 *
		 * FIXME(eric) - It is possible that the command completed
		 * *after* the error recovery procedure started, and if
		 * this is the case, we are worrying about nothing here.
		 *
		 * FIXME(rmk) - This should be bounded; we shouldn't wait
		 * for an infinite amount of time for any device.
		 */
		if (soft_reset) {
			SCSI_LOG_ERROR_RECOVERY(3,
				printk("scsi_unjam_host: unable to try bus "
					"reset for host %d channel %d\n",
					host->host_no, channel));
			scsi_sleep(1 * HZ);
			goto try_again;
		}

		/*
		 * We now know that we are able to perform a reset for the
		 * bus that SCpnt points to.  There are no soft-reset devices
		 * with outstanding timed out commands.
		 */
		rtn = scsi_try_bus_reset(failed_command);

		/*
		 * If we failed to reset the bus, move on to the next bus.
		 */
		if (rtn != SUCCESS)
			continue;

		/*
		 * We succeeded.  Retry each failed command.
		 */
		for (SDpnt = host->host_queue; SDpnt; SDpnt = SDpnt->next) {
			if (SDpnt->channel != channel)
				continue;

			rtn = scsi_eh_restart_device(SDpnt, done);

			if (rtn != SUCCESS) {
				SCpnt = scsi_eh_find_failed_command(SDpnt);

				/*
				 * This device failed again.  Since a bus
				 * reset freed it up, chances are we've
				 * hit the same problem, so try the same
				 * solution.  We also need to ensure that
				 * the SCSI bus is in the BUS FREE state
				 * so we can try to talk to other devices.
				 */
				scsi_try_bus_reset(SCpnt);
				scsi_eh_set_device_offline(SDpnt, done,
					"not ready or command retry "
					"failed after bus reset");
			}
		}
	}
}

static void scsi_unjam_host_reset(struct Scsi_Host *host, Scsi_Cmnd **done)
{
	Scsi_Device *SDpnt;
	Scsi_Cmnd *SCpnt;
	Scsi_Cmnd *failed_command = NULL;
	int rtn, soft_reset;

	/*
	 * If we ended up here, we have serious problems.  The only thing
	 * left to try is a full host reset - perhaps the firmware on the
	 * device crashed, or something like that.
	 *
	 * It is assumed that a succesful host reset will cause *all*
	 * information about the command to be flushed from both the host
	 * adapter *and* the device.
	 *
	 * FIXME(eric) - it isn't clear that devices that implement the
	 * soft reset option can ever be cleared except via cycling the
	 * power.  The problem is that sending the host reset command will
	 * cause the host to forget about the pending command, but the
	 * device won't forget.  For now, we skip the host reset option
	 * if any of the failed devices are configured to use the soft
	 * reset option.
	 */
	SCSI_LOG_ERROR_RECOVERY(3,
		printk("scsi_unjam_host: Try host reset\n"));

 try_again:
	failed_command = NULL;
	soft_reset = 0;

	for (SDpnt = host->host_queue; SDpnt; SDpnt = SDpnt->next) {
		/*
		 * Locate any failed commands for this device.
		 */
		SCpnt = scsi_eh_find_failed_command(SDpnt);
		if (SCpnt)
			failed_command = SCpnt;

		/*
		 * If this device has timed out or failed commands,
		 * and uses the soft_reset option.
		 */
		if (SCpnt && SDpnt->soft_reset)
			soft_reset = 1;
	}

	/* 
	 * If this device uses the soft reset option, and this
	 * is one of the devices acting up, then our only
	 * option is to wait a bit, since the command is
	 * supposedly still running.  
	 *
	 * FIXME(eric) - right now we will just end up falling
	 * through to the 'take device offline' case.
	 *
	 * FIXME(rmk) - This should be bounded; we shouldn't wait
	 * for an infinite amount of time for any device.
	 */
	if (soft_reset) {
		SCSI_LOG_ERROR_RECOVERY(3,
			printk("scsi_unjam_host: unable to try "
				"hard host reset\n"));

			/*
			 * Due to the spinlock, we will never get out of this
			 * loop without a proper wait. (DB)
			 */
			scsi_sleep(1 * HZ);

			goto try_again;
	}

	SCSI_LOG_ERROR_RECOVERY(3,
		printk("scsi_unjam_host: Try hard host reset\n"));

	/*
	 * FIXME(eric) - we need to obtain a valid SCpnt to perform this call.
	 */
	rtn = scsi_try_host_reset(failed_command);
	if (rtn == SUCCESS) {
		/*
		 * FIXME(eric) we assume that all commands are flushed from
		 * the controller.  We should get a DID_RESET for all of the
		 * commands that were pending.  We should ignore these so
		 * that we can guarantee that we are in a consistent state.
		 *
		 * I believe this to be the case right now, but this needs
		 * to be tested.
		 */
		for (SDpnt = host->host_queue; SDpnt; SDpnt = SDpnt->next) {
			rtn = scsi_eh_restart_device(SDpnt, done);

			if (rtn != SUCCESS) {
				SCpnt = scsi_eh_find_failed_command(SDpnt);

				/*
				 * This device failed again.  Since a host
				 * reset freed it up, chances are we've
				 * hit the same problem, so try the same
				 * solution.  We also need to ensure that
				 * the SCSI bus is in the BUS FREE state
				 * so we can try to talk to other devices.
				 */
				scsi_try_host_reset(SCpnt);
				scsi_eh_set_device_offline(SDpnt, done,
					"not ready or command retry "
					"failed after host reset");
			}
		}
	}
}

static void scsi_unjam_failure(struct Scsi_Host *host, Scsi_Cmnd **done)
{
	Scsi_Device *SDpnt;

	/*
	 * If the HOST RESET failed, then for now we assume that the
	 * entire host adapter is too hosed to be of any use.  For our
	 * purposes, however, it is easier to simply take the devices
	 * offline that correspond to commands that failed.
	 */
	SCSI_LOG_ERROR_RECOVERY(1,
		printk("scsi_unjam_host: Take device offline\n"));

	for (SDpnt = host->host_queue; SDpnt; SDpnt = SDpnt->next)
		scsi_eh_set_device_offline(SDpnt, done,
			"command error recover failed");

	if (host->host_failed != 0)
		panic("scsi_unjam_host: Miscount of number of failed commands.\n");

	SCSI_LOG_ERROR_RECOVERY(3, printk("scsi_unjam_host: Returning\n"));
}

static void (*unjam_method[])(struct Scsi_Host *, Scsi_Cmnd **) = {
	scsi_unjam_request_sense,
	scsi_unjam_count,
	scsi_unjam_abort,
	scsi_unjam_device_reset,
	scsi_unjam_bus_reset,
	scsi_unjam_host_reset,
	scsi_unjam_failure,
};

/*
 * Function:  scsi_unjam_host
 *
 * Purpose:     Attempt to fix a host which has a command that failed for
 *              some reason.
 *
 * Arguments:   host    - host that needs unjamming.
 * 
 * Returns:     Nothing
 *
 * Notes:       When we come in here, we *know* that all commands on the
 *              bus have either completed, failed or timed out.  We also
 *              know that no further commands are being sent to the host,
 *              so things are relatively quiet and we have freedom to
 *              fiddle with things as we wish.
 *
 * Additional note:  This is only the *default* implementation.  It is possible
 *              for individual drivers to supply their own version of this
 *              function, and if the maintainer wishes to do this, it is
 *              strongly suggested that this function be taken as a template
 *              and modified.  This function was designed to correctly handle
 *              problems for about 95% of the different cases out there, and
 *              it should always provide at least a reasonable amount of error
 *              recovery.
 *
 * Note3:       Any command marked 'FAILED' or 'TIMEOUT' must eventually
 *              have scsi_finish_command() called for it.  We do all of
 *              the retry stuff here, so when we restart the host after we
 *              return it should have an empty queue.
 */
STATIC int scsi_unjam_host(struct Scsi_Host *host)
{
	Scsi_Cmnd *SCdone = NULL;
	Scsi_Cmnd *SCpnt;
	Scsi_Device *SDpnt;
	int ourrtn = FALSE;
	int i;

	ASSERT_LOCK(&io_request_lock, 0);

	/*
	 * First, protect against any sort of race condition.  If any of the outstanding
	 * commands are in states that indicate that we are not yet blocked (i.e. we are
	 * not in a quiet state) then we got woken up in error.  If we ever end up here,
	 * we need to re-examine some of the assumptions.
	 */
	for (SDpnt = host->host_queue; SDpnt; SDpnt = SDpnt->next) {
		for (SCpnt = SDpnt->device_queue; SCpnt; SCpnt = SCpnt->next) {
			if (SCpnt->state == SCSI_STATE_FAILED
			    || SCpnt->state == SCSI_STATE_TIMEOUT
			    || SCpnt->state == SCSI_STATE_INITIALIZING
			    || SCpnt->state == SCSI_STATE_UNUSED) {
				continue;
			}
			/*
			 * Rats.  Something is still floating around out there.  This could
			 * be the result of the fact that the upper level drivers are still frobbing
			 * commands that might have succeeded.  There are two outcomes.  One is that
			 * the command block will eventually be freed, and the other one is that
			 * the command will be queued and will be finished along the way.
			 */
			SCSI_LOG_ERROR_RECOVERY(1, printk("Error handler prematurely woken - commands still active (%p %x %d)\n", SCpnt, SCpnt->state, SCpnt->target));

/*
 *        panic("SCSI Error handler woken too early\n");
 *
 * This is no longer a problem, since now the code cares only about
 * SCSI_STATE_TIMEOUT and SCSI_STATE_FAILED.
 * Other states are useful only to release active commands when devices are
 * set offline. If (host->host_active == host->host_busy) we can safely assume
 * that there are no commands in state other then TIMEOUT od FAILED. (DB)
 *
 * FIXME:
 * It is not easy to release correctly commands according to their state when 
 * devices are set offline, when the state is neither TIMEOUT nor FAILED.
 * When a device is set offline, we can have some command with
 * rq_status=RQ_SCSY_BUSY, owner=SCSI_STATE_HIGHLEVEL, 
 * state=SCSI_STATE_INITIALIZING and the driver module cannot be released.
 * (DB, 17 May 1998)
 */
		}
	}

	for (i = 0; i < ARRAY_SIZE(unjam_method); i++) {
		unjam_method[i](host, &SCdone);

		/*
		 * If we solved all of the problems, then
		 * let's rev up the engines again.
		 */
		if (host->host_failed == 0) {
			ourrtn = TRUE;
			break;
		}
	}

	/*
	 * We should have a list of commands that we 'finished' during the course of
	 * error recovery.  This should be the same as the list of commands that timed out
	 * or failed.  We are currently holding these things in a linked list - we didn't
	 * put them in the bottom half queue because we wanted to keep things quiet while
	 * we were working on recovery, and passing them up to the top level could easily
	 * cause the top level to try and queue something else again.
	 *
	 * Start by marking that the host is no longer in error recovery.
	 */
	host->in_recovery = 0;

	/*
	 * Take the list of commands, and stick them in the bottom half queue.
	 * The current implementation of scsi_done will do this for us - if need
	 * be we can create a special version of this function to do the
	 * same job for us.
	 */
	for (SCpnt = SCdone; SCpnt != NULL; SCpnt = SCdone) {
		SCdone = SCpnt->bh_next;
		SCpnt->bh_next = NULL;
                /*
                 * Oh, this is a vile hack.  scsi_done() expects a timer
                 * to be running on the command.  If there isn't, it assumes
                 * that the command has actually timed out, and a timer
                 * handler is running.  That may well be how we got into
                 * this fix, but right now things are stable.  We add
                 * a timer back again so that we can report completion.
                 * scsi_done() will immediately remove said timer from
                 * the command, and then process it.
                 */
		scsi_add_timer(SCpnt, 100, scsi_eh_times_out);
		scsi_done(SCpnt);
	}

	return (ourrtn);
}


/*
 * Function:  scsi_error_handler
 *
 * Purpose:     Handle errors/timeouts of scsi commands, try and clean up
 *              and unjam the bus, and restart things.
 *
 * Arguments:   host    - host for which we are running.
 *
 * Returns:     Never returns.
 *
 * Notes:       This is always run in the context of a kernel thread.  The
 *              idea is that we start this thing up when the kernel starts
 *              up (one per host that we detect), and it immediately goes to
 *              sleep and waits for some event (i.e. failure).  When this
 *              takes place, we have the job of trying to unjam the bus
 *              and restarting things.
 *
 */
void scsi_error_handler(void *data)
{
	struct Scsi_Host *host = (struct Scsi_Host *) data;
	int rtn;
	DECLARE_MUTEX_LOCKED(sem);

        /*
         * We only listen to signals if the HA was loaded as a module.
         * If the HA was compiled into the kernel, then we don't listen
         * to any signals.
         */
        if( host->loaded_as_module ) {
	siginitsetinv(&current->blocked, SHUTDOWN_SIGS);
	} else {
	siginitsetinv(&current->blocked, 0);
        }

	lock_kernel();

	/*
	 *    Flush resources
	 */

	daemonize();
	reparent_to_init();

	/*
	 * Set the name of this process.
	 */

	sprintf(current->comm, "scsi_eh_%d", host->host_no);

	host->eh_wait = &sem;
	host->ehandler = current;

	unlock_kernel();

	/*
	 * Wake up the thread that created us.
	 */
	SCSI_LOG_ERROR_RECOVERY(3, printk("Wake up parent %d\n", sem_getcount(host->eh_notify)));

	up(host->eh_notify);

	while (1) {
		/*
		 * If we get a signal, it means we are supposed to go
		 * away and die.  This typically happens if the user is
		 * trying to unload a module.
		 */
		SCSI_LOG_ERROR_RECOVERY(1, printk("Error handler sleeping\n"));

		/*
		 * Note - we always use down_interruptible with the semaphore
		 * even if the module was loaded as part of the kernel.  The
		 * reason is that down() will cause this thread to be counted
		 * in the load average as a running process, and down
		 * interruptible doesn't.  Given that we need to allow this
		 * thread to die if the driver was loaded as a module, using
		 * semaphores isn't unreasonable.
		 */
		down_interruptible(&sem);
		if( host->loaded_as_module ) {
			if (signal_pending(current))
				break;
                }

		SCSI_LOG_ERROR_RECOVERY(1, printk("Error handler waking up\n"));

		host->eh_active = 1;

		/*
		 * We have a host that is failing for some reason.  Figure out
		 * what we need to do to get it up and online again (if we can).
		 * If we fail, we end up taking the thing offline.
		 */
		if (host->hostt->eh_strategy_handler != NULL) {
			rtn = host->hostt->eh_strategy_handler(host);
		} else {
			rtn = scsi_unjam_host(host);
		}

		host->eh_active = 0;

		/*
		 * Note - if the above fails completely, the action is to take
		 * individual devices offline and flush the queue of any
		 * outstanding requests that may have been pending.  When we
		 * restart, we restart any I/O to any other devices on the bus
		 * which are still online.
		 */
		scsi_restart_operations(host);

	}

	SCSI_LOG_ERROR_RECOVERY(1, printk("Error handler exiting\n"));

	/*
	 * Make sure that nobody tries to wake us up again.
	 */
	host->eh_wait = NULL;

	/*
	 * Knock this down too.  From this point on, the host is flying
	 * without a pilot.  If this is because the module is being unloaded,
	 * that's fine.  If the user sent a signal to this thing, we are
	 * potentially in real danger.
	 */
	host->in_recovery = 0;
	host->eh_active = 0;
	host->ehandler = NULL;

	/*
	 * If anyone is waiting for us to exit (i.e. someone trying to unload
	 * a driver), then wake up that process to let them know we are on
	 * the way out the door.  This may be overkill - I *think* that we
	 * could probably just unload the driver and send the signal, and when
	 * the error handling thread wakes up that it would just exit without
	 * needing to touch any memory associated with the driver itself.
	 */
	if (host->eh_notify != NULL)
		up(host->eh_notify);
}

/*
 * Function:	scsi_new_reset
 *
 * Purpose:	Send requested reset to a bus or device at any phase.
 *
 * Arguments:	SCpnt	- command ptr to send reset with (usually a dummy)
 *		flag - reset type (see scsi.h)
 *
 * Returns:	SUCCESS/FAILURE.
 *
 * Notes:	This is used by the SCSI Generic driver to provide
 *		Bus/Device reset capability.
 */
int
scsi_new_reset(Scsi_Cmnd *SCpnt, int flag)
{
	int rtn;

	switch(flag) {
	case SCSI_TRY_RESET_DEVICE:
		rtn = scsi_try_bus_device_reset(SCpnt, 0);
		if (rtn == SUCCESS)
			break;
		/* FALLTHROUGH */
	case SCSI_TRY_RESET_BUS:
		rtn = scsi_try_bus_reset(SCpnt);
		if (rtn == SUCCESS)
			break;
		/* FALLTHROUGH */
	case SCSI_TRY_RESET_HOST:
		rtn = scsi_try_host_reset(SCpnt);
		break;
	default:
		rtn = FAILED;
	}

	return rtn;
}

/*
 * Overrides for Emacs so that we follow Linus's tabbing style.
 * Emacs will notice this stuff at the end of the file and automatically
 * adjust the settings for this buffer only.  This must remain at the end
 * of the file.
 * ---------------------------------------------------------------------------
 * Local variables:
 * c-indent-level: 4
 * c-brace-imaginary-offset: 0
 * c-brace-offset: -4
 * c-argdecl-indent: 4
 * c-label-offset: -4
 * c-continued-statement-offset: 4
 * c-continued-brace-offset: 0
 * indent-tabs-mode: nil
 * tab-width: 8
 * End:
 */

EXPORT_SYMBOL(scsi_eh_times_out);
EXPORT_SYMBOL(scsi_eh_retry_command);
EXPORT_SYMBOL(scsi_request_sense);
EXPORT_SYMBOL(scsi_test_unit_ready);
EXPORT_SYMBOL(scsi_unit_is_ready);
EXPORT_SYMBOL(scsi_eh_finish_command);
EXPORT_SYMBOL(scsi_try_to_abort_command);
EXPORT_SYMBOL(scsi_try_bus_device_reset);
EXPORT_SYMBOL(scsi_try_bus_reset);
EXPORT_SYMBOL(scsi_try_host_reset);
EXPORT_SYMBOL(scsi_sense_valid);
EXPORT_SYMBOL(scsi_done);
EXPORT_SYMBOL(scsi_decide_disposition);
