Commit 4fe48187 authored by adam radford's avatar adam radford Committed by James Bottomley
Browse files

[SCSI] 3ware 8000 serialize reset code



The attached patch updates the 3ware 8000 driver:

- Free irq handler in __tw_shutdown().
- Turn on RCD bit for caching mode page.
- Serialize reset code.

Signed-off-by: default avatarAdam Radford <linuxraid@amcc.com>
Signed-off-by: default avatarJames Bottomley <James.Bottomley@SteelEye.com>
parent 6397256b
Loading
Loading
Loading
Loading
+29 −31
Original line number Diff line number Diff line
@@ -6,7 +6,7 @@
   		     Arnaldo Carvalho de Melo <acme@conectiva.com.br>
                     Brad Strand <linux@3ware.com>

   Copyright (C) 1999-2005 3ware Inc.
   Copyright (C) 1999-2007 3ware Inc.

   Kernel compatiblity By: 	Andre Hedrick <andre@suse.com>
   Non-Copyright (C) 2000	Andre Hedrick <andre@suse.com>
@@ -191,6 +191,9 @@
                 before shutting down card.
                 Change to new 'change_queue_depth' api.
                 Fix 'handled=1' ISR usage, remove bogus IRQ check.
   1.26.02.002 - Free irq handler in __tw_shutdown().
                 Turn on RCD bit for caching mode page.
                 Serialize reset code.
*/

#include <linux/module.h>
@@ -214,7 +217,7 @@
#include "3w-xxxx.h"

/* Globals */
#define TW_DRIVER_VERSION "1.26.02.001"
#define TW_DRIVER_VERSION "1.26.02.002"
static TW_Device_Extension *tw_device_extension_list[TW_MAX_SLOT];
static int tw_device_extension_count = 0;
static int twe_major = -1;
@@ -226,7 +229,7 @@ MODULE_LICENSE("GPL");
MODULE_VERSION(TW_DRIVER_VERSION);

/* Function prototypes */
static int tw_reset_device_extension(TW_Device_Extension *tw_dev, int ioctl_reset);
static int tw_reset_device_extension(TW_Device_Extension *tw_dev);

/* Functions */

@@ -984,24 +987,12 @@ static int tw_chrdev_ioctl(struct inode *inode, struct file *file, unsigned int
			/* Now wait for the command to complete */
			timeout = wait_event_timeout(tw_dev->ioctl_wqueue, tw_dev->chrdev_request_id == TW_IOCTL_CHRDEV_FREE, timeout);

			/* See if we reset while waiting for the ioctl to complete */
			if (test_bit(TW_IN_RESET, &tw_dev->flags)) {
				clear_bit(TW_IN_RESET, &tw_dev->flags);
				retval = -ERESTARTSYS;
				goto out2;
			}

			/* We timed out, and didn't get an interrupt */
			if (tw_dev->chrdev_request_id != TW_IOCTL_CHRDEV_FREE) {
				/* Now we need to reset the board */
				printk(KERN_WARNING "3w-xxxx: scsi%d: Character ioctl (0x%x) timed out, resetting card.\n", tw_dev->host->host_no, cmd);
				retval = -EIO;
				spin_lock_irqsave(tw_dev->host->host_lock, flags);
				tw_dev->state[request_id] = TW_S_COMPLETED;
				tw_state_request_finish(tw_dev, request_id);
				tw_dev->posted_request_count--;
				spin_unlock_irqrestore(tw_dev->host->host_lock, flags);
				if (tw_reset_device_extension(tw_dev, 1)) {
				if (tw_reset_device_extension(tw_dev)) {
					printk(KERN_WARNING "3w-xxxx: tw_chrdev_ioctl(): Reset failed for card %d.\n", tw_dev->host->host_no);
				}
				goto out2;
@@ -1336,7 +1327,7 @@ static void tw_unmap_scsi_data(struct pci_dev *pdev, struct scsi_cmnd *cmd)
} /* End tw_unmap_scsi_data() */

/* This function will reset a device extension */
static int tw_reset_device_extension(TW_Device_Extension *tw_dev, int ioctl_reset) 
static int tw_reset_device_extension(TW_Device_Extension *tw_dev)
{
	int i = 0;
	struct scsi_cmnd *srb;
@@ -1382,15 +1373,10 @@ static int tw_reset_device_extension(TW_Device_Extension *tw_dev, int ioctl_rese
		printk(KERN_WARNING "3w-xxxx: scsi%d: Reset sequence failed.\n", tw_dev->host->host_no);
		return 1;
	}
	TW_ENABLE_AND_CLEAR_INTERRUPTS(tw_dev);

	/* Wake up any ioctl that was pending before the reset */
	if ((tw_dev->chrdev_request_id == TW_IOCTL_CHRDEV_FREE) || (ioctl_reset)) {
	TW_ENABLE_AND_CLEAR_INTERRUPTS(tw_dev);
	clear_bit(TW_IN_RESET, &tw_dev->flags);
	} else {
	tw_dev->chrdev_request_id = TW_IOCTL_CHRDEV_FREE;
		wake_up(&tw_dev->ioctl_wqueue);
	}

	return 0;
} /* End tw_reset_device_extension() */
@@ -1437,14 +1423,18 @@ static int tw_scsi_eh_reset(struct scsi_cmnd *SCpnt)
		"WARNING: Command (0x%x) timed out, resetting card.\n",
		SCpnt->cmnd[0]);

	/* Make sure we are not issuing an ioctl or resetting from ioctl */
	mutex_lock(&tw_dev->ioctl_lock);

	/* Now reset the card and some of the device extension data */
	if (tw_reset_device_extension(tw_dev, 0)) {
	if (tw_reset_device_extension(tw_dev)) {
		printk(KERN_WARNING "3w-xxxx: scsi%d: Reset failed.\n", tw_dev->host->host_no);
		goto out;
	}

	retval = SUCCESS;
out:
	mutex_unlock(&tw_dev->ioctl_lock);
	return retval;
} /* End tw_scsi_eh_reset() */

@@ -1660,9 +1650,9 @@ static int tw_scsiop_mode_sense_complete(TW_Device_Extension *tw_dev, int reques
	request_buffer[4] = 0x8;        /* caching page */
	request_buffer[5] = 0xa;        /* page length */
	if (*flags & 0x1)
		request_buffer[6] = 0x4;        /* WCE on */
		request_buffer[6] = 0x5;        /* WCE on, RCD on */
	else
		request_buffer[6] = 0x0;        /* WCE off */
		request_buffer[6] = 0x1;        /* WCE off, RCD on */
	tw_transfer_internal(tw_dev, request_id, request_buffer,
			     sizeof(request_buffer));

@@ -2012,6 +2002,10 @@ static int tw_scsi_queue(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd
	int retval = 1;
	TW_Device_Extension *tw_dev = (TW_Device_Extension *)SCpnt->device->host->hostdata;

	/* If we are resetting due to timed out ioctl, report as busy */
	if (test_bit(TW_IN_RESET, &tw_dev->flags))
		return SCSI_MLQUEUE_HOST_BUSY;

	/* Save done function into Scsi_Cmnd struct */
	SCpnt->scsi_done = done;
		 
@@ -2100,6 +2094,10 @@ static irqreturn_t tw_interrupt(int irq, void *dev_instance)

	handled = 1;

	/* If we are resetting, bail */
	if (test_bit(TW_IN_RESET, &tw_dev->flags))
		goto tw_interrupt_bail;

	/* Check controller for errors */
	if (tw_check_bits(status_reg_value)) {
		dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Unexpected bits.\n");
@@ -2276,6 +2274,9 @@ static void __tw_shutdown(TW_Device_Extension *tw_dev)
	/* Disable interrupts */
	TW_DISABLE_INTERRUPTS(tw_dev);

	/* Free up the IRQ */
	free_irq(tw_dev->tw_pci_dev->irq, tw_dev);

	printk(KERN_WARNING "3w-xxxx: Shutting down host %d.\n", tw_dev->host->host_no);

	/* Tell the card we are shutting down */
@@ -2444,9 +2445,6 @@ static void tw_remove(struct pci_dev *pdev)
		twe_major = -1;
	}

	/* Free up the IRQ */
	free_irq(tw_dev->tw_pci_dev->irq, tw_dev);

	/* Shutdown the card */
	__tw_shutdown(tw_dev);

+1 −1
Original line number Diff line number Diff line
@@ -6,7 +6,7 @@
   		     Arnaldo Carvalho de Melo <acme@conectiva.com.br>
                     Brad Strand <linux@3ware.com>

   Copyright (C) 1999-2005 3ware Inc.
   Copyright (C) 1999-2007 3ware Inc.

   Kernel compatiblity By:	Andre Hedrick <andre@suse.com>
   Non-Copyright (C) 2000	Andre Hedrick <andre@suse.com>