mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* 3ware driver update for 2.5.6-pre2 (new DMA mapping)
@ 2002-02-27 21:45 adam@mailhost.nmt.edu
  2002-02-27 22:46 ` Jeff V. Merkey
  2002-02-27 22:58 ` Jeff V. Merkey
  0 siblings, 2 replies; 4+ messages in thread
From: adam@mailhost.nmt.edu @ 2002-02-27 21:45 UTC (permalink / raw)
  To: alan; +Cc: linux-kernel

Alan,

Please apply this patch for kernel 2.5.6-pre2 for the 3ware driver to
support the new DMA mapping code, and several other fixes.

Thanks.

--
Adam Radford
Software Engineer
3ware, Inc.

diff -Naur linux-2.5.6-pre1/drivers/scsi/3w-xxxx.c linux-2.5.6-pre2/drivers/scsi/3w-xxxx.c
--- linux-2.5.6-pre1/drivers/scsi/3w-xxxx.c	Tue Feb 19 18:11:00 2002
+++ linux-2.5.6-pre2/drivers/scsi/3w-xxxx.c	Wed Feb 27 11:53:49 2002
@@ -6,7 +6,7 @@
    		     Arnaldo Carvalho de Melo <acme@conectiva.com.br>
                      Brad Strand <linux@3ware.com>

-   Copyright (C) 1999-2001 3ware Inc.
+   Copyright (C) 1999-2002 3ware Inc.

    Kernel compatablity By: 	Andre Hedrick <andre@suse.com>
    Non-Copyright (C) 2000	Andre Hedrick <andre@suse.com>
@@ -106,17 +106,41 @@
                  Add entire aen code string list.
    1.02.00.010 - Cleanup queueing code, fix jbod thoughput.
                  Fix get_param for specific units.
+   1.02.00.011 - Fix bug in tw_aen_complete() where aen's could be lost.
+                 Fix tw_aen_drain_queue() to display useful info at init.
+                 Set tw_host->max_id for 12 port cards.
+                 Add ioctl support for raw command packet post from userspace
+                 with sglist fragments (parameter and io).
+   1.02.00.012 - Fix read capacity to under report by 1 sector to fix get
+                 last sector ioctl.
+   1.02.00.013 - Fix bug where more AEN codes weren't coming out during
+                 driver initialization.
+                 Improved handling of PCI aborts.
+   1.02.00.014 - Fix bug in tw_findcards() where AEN code could be lost.
+                 Increase timeout in tw_aen_drain_queue() to 30 seconds.
+   1.02.00.015 - Re-write raw command post with data ioctl method.
+                 Remove raid5 bounce buffers for raid5 for 6XXX for kernel 2.5
+                 Add tw_map/unmap_scsi_sg/single_data() for kernel 2.5
+                 Replace io_request_lock with host_lock for kernel 2.5
+                 Set max_cmd_len to 16 for 3dm for kernel 2.5
+   1.02.00.016 - Set host->max_sectors back up to 256.
+   1.02.00.017 - Modified pci parity error handling/clearing from config space
+                 during initialization.
+   1.02.00.018 - Better handling of request sense opcode and sense information
+                 for failed commands.  Add tw_decode_sense().
+                 Replace all mdelay()'s with scsi_sleep().
+   1.02.00.019 - Revert mdelay's and scsi_sleep's, this caused problems on
+                 some SMP systems.
+   1.02.00.020 - Add pci_set_dma_mask(), rewrite kmalloc()/virt_to_bus() to
+                 pci_alloc/free_consistent().
 */

-#error Please convert me to Documentation/DMA-mapping.txt
-
 #include <linux/module.h>

 MODULE_AUTHOR ("3ware Inc.");
 MODULE_DESCRIPTION ("3ware Storage Controller Linux Driver");
 MODULE_LICENSE("GPL");

-
 #include <linux/kernel.h>
 #include <linux/pci.h>
 #include <linux/time.h>
@@ -148,14 +172,17 @@
 static void tw_copy_mem_info(TW_Info *info, char *data, int len);
 static void tw_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
 static int tw_halt(struct notifier_block *nb, ulong event, void *buf);
+static int tw_map_scsi_sg_data(struct pci_dev *pdev, Scsi_Cmnd *cmd);
+static u32 tw_map_scsi_single_data(struct pci_dev *pdev, Scsi_Cmnd *cmd);
+static void tw_unmap_scsi_data(struct pci_dev *pdev, Scsi_Cmnd *cmd);

 /* Notifier block to get a notify on system shutdown/halt/reboot */
 static struct notifier_block tw_notifier = {
-  tw_halt, NULL, 0
+	tw_halt, NULL, 0
 };

 /* Globals */
-char *tw_driver_version="1.02.00.010";
+char *tw_driver_version="1.02.00.020";
 TW_Device_Extension *tw_device_extension_list[TW_MAX_SLOT];
 int tw_device_extension_count = 0;

@@ -166,6 +193,7 @@
 {
 	TW_Param *param;
 	unsigned short aen;
+	int error = 0;

 	dprintk(KERN_WARNING "3w-xxxx: tw_aen_complete()\n");
 	if (tw_dev->alignment_virtual_address[request_id] == NULL) {
@@ -184,12 +212,15 @@
 			if ((tw_aen_string[aen & 0xff][strlen(tw_aen_string[aen & 0xff])-1]) == '#') {
 				printk(KERN_WARNING "3w-xxxx: scsi%d: AEN: %s%d.\n", tw_dev->host->host_no, tw_aen_string[aen & 0xff], aen >> 8);
 			} else {
-				printk(KERN_WARNING "3w-xxxx: scsi%d: AEN: %s.\n", tw_dev->host->host_no, tw_aen_string[aen & 0xff]);
+				if (aen != 0x0)
+					printk(KERN_WARNING "3w-xxxx: scsi%d: AEN: %s.\n", tw_dev->host->host_no, tw_aen_string[aen & 0xff]);
 			}
-		} else
+		} else {
 			printk(KERN_WARNING "3w-xxxx: scsi%d: Received AEN %d.\n", tw_dev->host->host_no, aen);
+		}
 	}
-	tw_dev->aen_count++;
+	if (aen != 0x0)
+		tw_dev->aen_count++;

 	/* Now queue the code */
 	tw_dev->aen_queue[tw_dev->aen_tail] = aen;
@@ -205,8 +236,18 @@
 			tw_dev->aen_head = tw_dev->aen_head + 1;
 		}
 	}
-	tw_dev->state[request_id] = TW_S_COMPLETED;
-	tw_state_request_finish(tw_dev, request_id);
+
+	if (aen != TW_AEN_QUEUE_EMPTY) {
+		error = tw_aen_read_queue(tw_dev, request_id);
+		if (error) {
+			printk(KERN_WARNING "3w-xxxx: scsi%d: Error completing AEN.\n", tw_dev->host->host_no);
+			tw_dev->state[request_id] = TW_S_COMPLETED;
+			tw_state_request_finish(tw_dev, request_id);
+		}
+	} else {
+		tw_dev->state[request_id] = TW_S_COMPLETED;
+		tw_state_request_finish(tw_dev, request_id);
+	}

 	return 0;
 } /* End tw_aen_complete() */
@@ -237,10 +278,11 @@
 	status_reg_addr = tw_dev->registers.status_reg_addr;
 	response_que_addr = tw_dev->registers.response_que_addr;

-	if (tw_poll_status(tw_dev, TW_STATUS_ATTENTION_INTERRUPT, 15)) {
+	if (tw_poll_status(tw_dev, TW_STATUS_ATTENTION_INTERRUPT, 30)) {
 		dprintk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): No attention interrupt for card %d.\n", tw_device_extension_count);
 		return 1;
 	}
+	tw_clear_attention_interrupt(tw_dev);

 	/* Initialize command packet */
 	if (tw_dev->command_packet_virtual_address[request_id] == NULL) {
@@ -288,7 +330,7 @@
 	do {
 		/* Post command packet */
 		outl(command_que_value, command_que_addr);
-
+
 		/* Now poll for completion */
 		for (i=0;i<imax;i++) {
 			mdelay(5);
@@ -311,8 +353,7 @@
 				if (command_packet->status != 0) {
 					if (command_packet->flags != TW_AEN_TABLE_UNDEFINED) {
 						/* Bad response */
-						dprintk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): Bad response, status = 0x%x, flags = 0x%x.\n", command_packet->status, command_packet->flags);
-						tw_decode_error(tw_dev, command_packet->status, command_packet->flags, command_packet->byte3.unit);
+						tw_decode_sense(tw_dev, request_id, 0);
 						return 1;
 					} else {
 						/* We know this is a 3w-1x00, and doesn't support aen's */
@@ -326,7 +367,7 @@
 				queue = 0;
 				switch (aen_code) {
 					case TW_AEN_QUEUE_EMPTY:
-						dprintk(KERN_NOTICE "3w-xxxx: tw_aen_drain_queue(): Found TW_AEN_QUEUE_EMPTY.\n");
+						dprintk(KERN_WARNING "3w-xxxx: AEN: %s.\n", tw_aen_string[aen & 0xff]);
 						if (first_reset != 1) {
 							continue;
 						} else {
@@ -334,51 +375,28 @@
 						}
 						break;
 					case TW_AEN_SOFT_RESET:
-						dprintk(KERN_NOTICE "3w-xxxx: tw_aen_drain_queue(): Found TW_AEN_SOFT_RESET.\n");
 						if (first_reset == 0) {
 							first_reset = 1;
 						} else {
+							printk(KERN_WARNING "3w-xxxx: AEN: %s.\n", tw_aen_string[aen & 0xff]);
+							tw_dev->aen_count++;
 							queue = 1;
 						}
 						break;
-					case TW_AEN_DEGRADED_MIRROR:
-						dprintk(KERN_NOTICE "3w-xxxx: tw_aen_drain_queue(): Found TW_AEN_DEGRADED_MIRROR.\n");
-						queue = 1;
-						break;
-					case TW_AEN_CONTROLLER_ERROR:
-						dprintk(KERN_NOTICE "3w-xxxx: tw_aen_drain_queue(): Found TW_AEN_CONTROLLER_ERROR.\n");
-						queue = 1;
-						break;
-					case TW_AEN_REBUILD_FAIL:
-						dprintk(KERN_NOTICE "3w-xxxx: tw_aen_drain_queue(): Found TW_AEN_REBUILD_FAIL.\n");
-						queue = 1;
-						break;
-					case TW_AEN_REBUILD_DONE:
-						dprintk(KERN_NOTICE "3w-xxxx: tw_aen_drain_queue(): Found TW_AEN_REBUILD_DONE.\n");
-						queue = 1;
-						break;
-					case TW_AEN_QUEUE_FULL:
-						dprintk(KERN_NOTICE "3w-xxxx: tw_aen_drain_queue(): Found TW_AEN_QUEUE_FULL.\n");
-						queue = 1;
-						break;
-					case TW_AEN_APORT_TIMEOUT:
-						printk(KERN_WARNING "3w-xxxx: Received drive timeout AEN on port %d, check drive and drive cables.\n", aen >> 8);
-						queue = 1;
-						break;
-					case TW_AEN_DRIVE_ERROR:
-						printk(KERN_WARNING "3w-xxxx: Received drive error AEN on port %d, check/replace cabling, or possible bad drive.\n", aen >> 8);
-						queue = 1;
-						break;
-					case TW_AEN_SMART_FAIL:
-						printk(KERN_WARNING "3w-xxxx: Received S.M.A.R.T. threshold AEN on port %d, check drive/cooling, or possible bad drive.\n", aen >> 8);
-						queue = 1;
-						break;
-					case TW_AEN_SBUF_FAIL:
-						printk(KERN_WARNING "3w-xxxx: Received SBUF integrity check failure AEN, reseat card or bad card.\n");
-						queue = 1;
-						break;
 					default:
-						dprintk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): Unknown AEN code 0x%x.\n", aen_code);
+						if (aen == 0x0ff) {
+							printk(KERN_WARNING "3w-xxxx: AEN: AEN queue overflow.\n");
+						} else {
+							if ((aen & 0x0ff) < TW_AEN_STRING_MAX) {
+								if ((tw_aen_string[aen & 0xff][strlen(tw_aen_string[aen & 0xff])-1]) == '#') {
+									printk(KERN_WARNING "3w-xxxx: AEN: %s%d.\n", tw_aen_string[aen & 0xff], aen >> 8);
+								} else {
+									printk(KERN_WARNING "3w-xxxx: AEN: %s.\n", tw_aen_string[aen & 0xff]);
+								}
+							} else
+								printk(KERN_WARNING "3w-xxxx: Received AEN %d.\n", aen);
+						}
+						tw_dev->aen_count++;
 						queue = 1;
 				}

@@ -488,40 +506,44 @@
 	return 0;
 } /* End tw_aen_read_queue() */

-/* This function will allocate memory and check if it is 16 d-word aligned */
-int tw_allocate_memory(TW_Device_Extension *tw_dev, int request_id, int size, int which)
+/* This function will allocate memory */
+int tw_allocate_memory(TW_Device_Extension *tw_dev, int size, int which)
 {
-	u32 *virt_addr = kmalloc(size, GFP_ATOMIC);
+	int i;
+	dma_addr_t dma_handle;
+	u32 *cpu_addr = NULL;

 	dprintk(KERN_NOTICE "3w-xxxx: tw_allocate_memory()\n");

-	if (!virt_addr) {
-		printk(KERN_WARNING "3w-xxxx: tw_allocate_memory(): kmalloc() failed.\n");
-		return 1;
-	}
+	for (i=0;i<TW_Q_LENGTH;i++) {
+		cpu_addr = pci_alloc_consistent(tw_dev->tw_pci_dev, size, &dma_handle);
+		if (cpu_addr == NULL) {
+			printk(KERN_WARNING "3w-xxxx: pci_alloc_consistent() failed.\n");
+			return 1;
+		}

-	if ((u32)virt_addr % TW_ALIGNMENT) {
-		kfree(virt_addr);
-		printk(KERN_WARNING "3w-xxxx: tw_allocate_memory(): Found unaligned address.\n");
-		return 1;
-	}
+		if ((u32)cpu_addr % (tw_dev->tw_pci_dev->device == TW_DEVICE_ID ? TW_ALIGNMENT_6000 : TW_ALIGNMENT_7000)) {
+			printk(KERN_WARNING "3w-xxxx: Couldn't allocate correctly aligned memory.\n");
+			return 1;
+		}

-	switch(which) {
-	case 0:
-		tw_dev->command_packet_virtual_address[request_id] = virt_addr;
-		tw_dev->command_packet_physical_address[request_id] = virt_to_bus(virt_addr);
-		break;
-	case 1:
-		tw_dev->alignment_virtual_address[request_id] = virt_addr;
-		tw_dev->alignment_physical_address[request_id] = virt_to_bus(virt_addr);
-		break;
-	case 2:
-		tw_dev->bounce_buffer[request_id] = virt_addr;
-		break;
-	default:
-		printk(KERN_WARNING "3w-xxxx: tw_allocate_memory(): case slip in tw_allocate_memory()\n");
-		return 1;
+		switch(which) {
+		case 0:
+			tw_dev->command_packet_virtual_address[i] = cpu_addr;
+			tw_dev->command_packet_physical_address[i] = dma_handle;
+			memset(tw_dev->command_packet_virtual_address[i], 0, size);
+			break;
+		case 1:
+			tw_dev->alignment_virtual_address[i] = cpu_addr;
+			tw_dev->alignment_physical_address[i] = dma_handle;
+			memset(tw_dev->alignment_virtual_address[i], 0, size);
+			break;
+		default:
+			printk(KERN_WARNING "3w-xxxx: tw_allocate_memory(): case slip in tw_allocate_memory()\n");
+			return 1;
+		}
 	}
+
 	return 0;
 } /* End tw_allocate_memory() */

@@ -548,8 +570,10 @@
 	status_reg_addr = tw_dev->registers.status_reg_addr;
 	status_reg_value = inl(status_reg_addr);

-	if (TW_STATUS_ERRORS(status_reg_value) || tw_check_bits(status_reg_value))
+	if (TW_STATUS_ERRORS(status_reg_value) || tw_check_bits(status_reg_value)) {
+		tw_decode_bits(tw_dev, status_reg_value);
 		return 1;
+	}

 	return 0;
 } /* End tw_check_errors() */
@@ -614,37 +638,62 @@
 	dprintk(KERN_WARNING "3w-xxxx: tw_decode_bits()\n");
 	switch (status_reg_value & TW_STATUS_UNEXPECTED_BITS) {
 	case TW_STATUS_PCI_PARITY_ERROR:
-		printk(KERN_WARNING "3w-xxxx: PCI Parity Error: Reseat card, move card, or buggy device on the bus.\n");
+		printk(KERN_WARNING "3w-xxxx: PCI Parity Error: clearing.\n");
 		outl(TW_CONTROL_CLEAR_PARITY_ERROR, tw_dev->registers.control_reg_addr);
-		pci_write_config_word(tw_dev->tw_pci_dev, PCI_STATUS, TW_PCI_CLEAR_PARITY_ERRORS);
 		break;
 	case TW_STATUS_MICROCONTROLLER_ERROR:
 		printk(KERN_WARNING "3w-xxxx: Microcontroller Error.\n");
 		break;
+	case TW_STATUS_PCI_ABORT:
+		printk(KERN_WARNING "3w-xxxx: PCI Abort: clearing.\n");
+		outl(TW_CONTROL_CLEAR_PCI_ABORT, tw_dev->registers.control_reg_addr);
+		pci_write_config_word(tw_dev->tw_pci_dev, PCI_STATUS, TW_PCI_CLEAR_PCI_ABORT);
+		break;
   }
 } /* End tw_decode_bits() */

-/* This function will print readable messages from flags and status values */
-void tw_decode_error(TW_Device_Extension *tw_dev, unsigned char status, unsigned char flags, unsigned char unit)
+/* This function will return valid sense buffer information for failed cmds */
+void tw_decode_sense(TW_Device_Extension *tw_dev, int request_id, int fill_sense)
 {
-	dprintk(KERN_WARNING "3w-xxxx: tw_decode_error()\n");
-	switch (status) {
-	case 0xc7:
-		switch (flags) {
-		case 0x1b:
-			printk(KERN_WARNING "3w-xxxx: scsi%d: Drive timeout on unit %d, check drive and drive cables.\n", tw_dev->host->host_no, unit);
-			break;
-		case 0x51:
-			printk(KERN_WARNING "3w-xxxx: scsi%d: Unrecoverable drive error on unit %d, check/replace cabling, or possible bad drive.\n", tw_dev->host->host_no, unit);
-			break;
-		default:
-			printk(KERN_WARNING "3w-xxxx: scsi%d: Controller error: status = 0x%x, flags = 0x%x, unit #%d.\n", tw_dev->host->host_no, status, flags, unit);
+	int i, found=0;
+	TW_Command *command;
+
+        dprintk(KERN_WARNING "3w-xxxx: tw_decode_sense()\n");
+	command = (TW_Command *)tw_dev->command_packet_virtual_address[request_id];
+
+	printk(KERN_WARNING "3w-xxxx: scsi%d: Command failed: status = 0x%x, flags = 0x%x, unit #%d.\n", tw_dev->host->host_no, command->status, command->flags, command->byte3.unit);
+
+	/* Attempt to return intelligent sense information */
+	if (fill_sense) {
+		if ((command->status == 0xc7) || (command->status == 0xcb)) {
+			for (i=0;i<(sizeof(tw_sense_table)/sizeof(tw_sense_table[0]));i++) {
+				if (command->flags == tw_sense_table[i][0]) {
+					found=1;
+
+					/* Valid bit and 'current errors' */
+					tw_dev->srb[request_id]->sense_buffer[0] = (0x1 << 7 | 0x70);
+
+					/* Sense key */
+					tw_dev->srb[request_id]->sense_buffer[2] = tw_sense_table[i][1];
+
+					/* Additional sense length */
+					tw_dev->srb[request_id]->sense_buffer[7] = 0xa; /* 10 bytes */
+
+					/* Additional sense code */
+					tw_dev->srb[request_id]->sense_buffer[12] = tw_sense_table[i][2];
+
+					/* Additional sense code qualifier */
+					tw_dev->srb[request_id]->sense_buffer[13] = tw_sense_table[i][3];
+
+					tw_dev->srb[request_id]->result = (DID_OK << 16) | (CHECK_CONDITION << 1);
+				}
+			}
 		}
-		break;
-	default:
-		printk(KERN_WARNING "3w-xxxx: scsi%d: Controller error: status = 0x%x, flags = 0x%x, unit #%d.\n", tw_dev->host->host_no, status, flags, unit);
+		/* If no table match, error so we get a reset */
+		if (found == 0)
+			tw_dev->srb[request_id]->result = (DID_RESET << 16);
 	}
-} /* End tw_decode_error() */
+} /* End tw_decode_sense() */

 /* This function will disable interrupts on the controller */
 void tw_disable_interrupts(TW_Device_Extension *tw_dev)
@@ -691,11 +740,22 @@
 	u32 control_reg_value, control_reg_addr;

 	control_reg_addr = tw_dev->registers.control_reg_addr;
+	control_reg_value = (TW_CONTROL_ENABLE_INTERRUPTS |
+			     TW_CONTROL_UNMASK_RESPONSE_INTERRUPT);
+	outl(control_reg_value, control_reg_addr);
+} /* End tw_enable_interrupts() */
+
+/* This function will enable interrupts on the controller */
+void tw_enable_and_clear_interrupts(TW_Device_Extension *tw_dev)
+{
+	u32 control_reg_value, control_reg_addr;
+
+	control_reg_addr = tw_dev->registers.control_reg_addr;
 	control_reg_value = (TW_CONTROL_CLEAR_ATTENTION_INTERRUPT |
 			     TW_CONTROL_UNMASK_RESPONSE_INTERRUPT |
 			     TW_CONTROL_ENABLE_INTERRUPTS);
 	outl(control_reg_value, control_reg_addr);
-} /* End tw_enable_interrupts() */
+} /* End tw_enable_and_clear_interrupts() */

 /* This function will find and initialize all cards */
 int tw_findcards(Scsi_Host_Template *tw_host)
@@ -716,6 +776,13 @@
 		while ((tw_pci_dev = pci_find_device(TW_VENDOR_ID, device[i], tw_pci_dev))) {
 			if (pci_enable_device(tw_pci_dev))
 				continue;
+
+			/* We only need 32-bit addressing for 5,6,7xxx cards */
+			if (pci_set_dma_mask(tw_pci_dev, 0xffffffff)) {
+				printk(KERN_WARNING "3w-xxxx: No suitable DMA available.\n");
+				continue;
+			}
+
 			/* Prepare temporary device extension */
 			tw_dev=(TW_Device_Extension *)kmalloc(sizeof(TW_Device_Extension), GFP_ATOMIC);
 			if (tw_dev == NULL) {
@@ -724,6 +791,9 @@
 			}
 			memset(tw_dev, 0, sizeof(TW_Device_Extension));

+			/* Save pci_dev struct to device extension */
+			tw_dev->tw_pci_dev = tw_pci_dev;
+
 			error = tw_initialize_device_extension(tw_dev);
 			if (error) {
 				printk(KERN_WARNING "3w-xxxx: tw_findcards(): Couldn't initialize device extension for card %d.\n", numcards);
@@ -738,8 +808,6 @@
 			tw_dev->registers.status_reg_addr = pci_resource_start(tw_pci_dev, 0) + 0x4;
 			tw_dev->registers.command_que_addr = pci_resource_start(tw_pci_dev, 0) + 0x8;
 			tw_dev->registers.response_que_addr = pci_resource_start(tw_pci_dev, 0) + 0xC;
-			/* Save pci_dev struct to device extension */
-			tw_dev->tw_pci_dev = tw_pci_dev;

 			/* Check for errors and clear them */
 			status_reg_value = inl(tw_dev->registers.status_reg_addr);
@@ -763,14 +831,14 @@

 				error = tw_aen_drain_queue(tw_dev);
 				if (error) {
-					printk(KERN_WARNING "3w-xxxx: tw_findcards(): No attention interrupt for card %d.\n", numcards);
+					printk(KERN_WARNING "3w-xxxx: AEN drain failed for card %d.\n", numcards);
 					tries++;
 					continue;
 				}

 				/* Check for controller errors */
 				if (tw_check_errors(tw_dev)) {
-					printk(KERN_WARNING "3w-xxxx: tw_findcards(): Controller errors found, soft resetting card %d.\n", numcards);
+					printk(KERN_WARNING "3w-xxxx: Controller errors found, retrying for card %d.\n", numcards);
 					tries++;
 					continue;
 				}
@@ -778,7 +846,7 @@
 				/* Empty the response queue */
 				error = tw_empty_response_que(tw_dev);
 				if (error) {
-					printk(KERN_WARNING "3w-xxxx: tw_findcards(): Couldn't empty response queue for card %d.\n", numcards);
+					printk(KERN_WARNING "3w-xxxx: Couldn't empty response queue, retrying for card %d.\n", numcards);
 					tries++;
 					continue;
 				}
@@ -788,7 +856,7 @@
 			}

 			if (tries >= TW_MAX_RESET_TRIES) {
-				printk(KERN_WARNING "3w-xxxx: tw_findcards(): Controller error or no attention interrupt: giving up for card %d.\n", numcards);
+				printk(KERN_WARNING "3w-xxxx: Controller errors, card not responding, check all cabling for card %d.\n", numcards);
 				tw_free_device_extension(tw_dev);
 				kfree(tw_dev);
 				continue;
@@ -818,7 +886,7 @@

 			error = tw_initconnection(tw_dev, TW_INIT_MESSAGE_CREDITS);
 			if (error) {
-				printk(KERN_WARNING "3w-xxxx: tw_findcards(): Couldn't initconnection for card %d.\n", numcards);
+				printk(KERN_WARNING "3w-xxxx: Connection initialization failed for card %d.\n", numcards);
 				release_region((tw_dev->tw_pci_dev->resource[0].start), TW_IO_ADDRESS_RANGE);
 				tw_free_device_extension(tw_dev);
 				kfree(tw_dev);
@@ -827,29 +895,28 @@

 			/* Calculate max cmds per lun, and setup queues */
 			if (tw_dev->num_units > 0) {
-				if ((tw_dev->num_raid_five > 0) && (tw_dev->tw_pci_dev->device == TW_DEVICE_ID)) {
-					tw_host->cmd_per_lun = (TW_MAX_BOUNCEBUF-1)/tw_dev->num_units;
-					tw_dev->free_head = TW_Q_START;
-					tw_dev->free_tail = TW_MAX_BOUNCEBUF - 1;
-					tw_dev->free_wrap = TW_MAX_BOUNCEBUF - 1;
-				} else {
-					tw_host->cmd_per_lun = (TW_Q_LENGTH-1)/tw_dev->num_units;
-					tw_dev->free_head = TW_Q_START;
-					tw_dev->free_tail = TW_Q_LENGTH - 1;
-					tw_dev->free_wrap = TW_Q_LENGTH - 1;
-				}
+				tw_host->cmd_per_lun = (TW_Q_LENGTH-1)/tw_dev->num_units;
+				tw_dev->free_head = TW_Q_START;
+				tw_dev->free_tail = TW_Q_LENGTH - 1;
+				tw_dev->free_wrap = TW_Q_LENGTH - 1;
 			}

-		/* Register the card with the kernel SCSI layer */
+			/* Register the card with the kernel SCSI layer */
 			host = scsi_register(tw_host, sizeof(TW_Device_Extension));
 			if (host == NULL) {
-				printk(KERN_WARNING "3w-xxxx: tw_findcards(): scsi_register() failed for card %d.\n", numcards-1);
+				printk(KERN_WARNING "3w-xxxx: tw_findcards(): scsi_register() failed for card %d.\n", numcards);
 				release_region((tw_dev->tw_pci_dev->resource[0].start), TW_IO_ADDRESS_RANGE);
 				tw_free_device_extension(tw_dev);
 				kfree(tw_dev);
 				continue;
 			}

+			/* Set max target id's */
+			host->max_id = TW_MAX_UNITS;
+
+			/* Set max cdb size in bytes */
+			host->max_cmd_len = 16;
+
 			/* Set max sectors per io */
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,7)
 			host->max_sectors = TW_MAX_SECTORS;
@@ -874,7 +941,7 @@
 				tw_device_extension_count = numcards;
 				tw_dev2->host = host;
 			} else {
-				printk(KERN_WARNING "3w-xxxx: tw_findcards(): Bad scsi host data for card %d.\n", numcards-1);
+				printk(KERN_WARNING "3w-xxxx: tw_findcards(): Bad scsi host data for card %d.\n", numcards);
 				scsi_unregister(host);
 				release_region((tw_dev->tw_pci_dev->resource[0].start), TW_IO_ADDRESS_RANGE);
 				tw_free_device_extension(tw_dev);
@@ -924,15 +991,10 @@
 	/* Free command packet and generic buffer memory */
 	for (i=0;i<TW_Q_LENGTH;i++) {
 		if (tw_dev->command_packet_virtual_address[i])
-			kfree(tw_dev->command_packet_virtual_address[i]);
+			pci_free_consistent(tw_dev->tw_pci_dev, sizeof(TW_Sector), tw_dev->command_packet_virtual_address[i], tw_dev->command_packet_physical_address[i]);

 		if (tw_dev->alignment_virtual_address[i])
-			kfree(tw_dev->alignment_virtual_address[i]);
-
-	}
-	for (i=0;i<TW_MAX_BOUNCEBUF;i++) {
-		if (tw_dev->bounce_buffer[i])
-			kfree(tw_dev->bounce_buffer[i]);
+			pci_free_consistent(tw_dev->tw_pci_dev, sizeof(TW_Sector), tw_dev->alignment_virtual_address[i], tw_dev->alignment_physical_address[i]);
 	}
 } /* End tw_free_device_extension() */

@@ -1015,8 +1077,7 @@
 			}
 			if (command_packet->status != 0) {
 				/* bad response */
-				dprintk(KERN_WARNING "3w-xxxx: tw_initconnection(): Bad response, status = 0x%x, flags = 0x%x.\n", command_packet->status, command_packet->flags);
-				tw_decode_error(tw_dev, command_packet->status, command_packet->flags, command_packet->byte3.unit);
+				tw_decode_sense(tw_dev, request_id, 0);
 				return 1;
 			}
 			break;	/* Response was okay, so we exit */
@@ -1028,57 +1089,33 @@
 /* This function will initialize the fields of a device extension */
 int tw_initialize_device_extension(TW_Device_Extension *tw_dev)
 {
-	int i, imax;
+	int i, error=0;

 	dprintk(KERN_NOTICE "3w-xxxx: tw_initialize_device_extension()\n");
-	imax = TW_Q_LENGTH;

-	for (i=0; i<imax; i++) {
-		/* Initialize command packet buffers */
-		tw_allocate_memory(tw_dev, i, sizeof(TW_Sector), 0);
-		if (tw_dev->command_packet_virtual_address[i] == NULL) {
-			printk(KERN_WARNING "3w-xxxx: tw_initialize_device_extension(): Bad command packet virtual address.\n");
-			return 1;
-		}
-		memset(tw_dev->command_packet_virtual_address[i], 0, sizeof(TW_Sector));
-
-		/* Initialize generic buffer */
-		tw_allocate_memory(tw_dev, i, sizeof(TW_Sector), 1);
-		if (tw_dev->alignment_virtual_address[i] == NULL) {
-			printk(KERN_WARNING "3w-xxxx: tw_initialize_device_extension(): Bad alignment virtual address.\n");
-			return 1;
-		}
-		memset(tw_dev->alignment_virtual_address[i], 0, sizeof(TW_Sector));
+	/* Initialize command packet buffers */
+	error = tw_allocate_memory(tw_dev, sizeof(TW_Command), 0);
+	if (error) {
+		printk(KERN_WARNING "3w-xxxx: Command packet memory allocation failed.\n");
+		return 1;
+	}

-		tw_dev->free_queue[i] = i;
-		tw_dev->state[i] = TW_S_INITIAL;
-		tw_dev->ioctl_size[i] = 0;
-		tw_dev->aen_queue[i] = 0;
+	/* Initialize generic buffer */
+	error = tw_allocate_memory(tw_dev, sizeof(TW_Sector), 1);
+	if (error) {
+		printk(KERN_WARNING "3w-xxxx: Generic memory allocation failed.\n");
+		return 1;
 	}

-	for (i=0;i<TW_MAX_UNITS;i++) {
-		tw_dev->is_unit_present[i] = 0;
-		tw_dev->is_raid_five[i] = 0;
+	for (i=0;i<TW_Q_LENGTH;i++) {
+		tw_dev->free_queue[i] = i;
+		tw_dev->state[i] = TW_S_INITIAL;
 	}

-	tw_dev->num_units = 0;
-	tw_dev->num_aborts = 0;
-	tw_dev->num_resets = 0;
-	tw_dev->posted_request_count = 0;
-	tw_dev->max_posted_request_count = 0;
-	tw_dev->max_sgl_entries = 0;
-	tw_dev->sgl_entries = 0;
-	tw_dev->host = NULL;
 	tw_dev->pending_head = TW_Q_START;
 	tw_dev->pending_tail = TW_Q_START;
-	tw_dev->aen_head = 0;
-	tw_dev->aen_tail = 0;
-	tw_dev->sector_count = 0;
-	tw_dev->max_sector_count = 0;
-	tw_dev->aen_count = 0;
-	tw_dev->num_raid_five = 0;
 	spin_lock_init(&tw_dev->tw_lock);
-	tw_dev->flags = 0;
+
 	return 0;
 } /* End tw_initialize_device_extension() */

@@ -1089,14 +1126,13 @@
 	unsigned char request_id = 0;
 	TW_Command *command_packet;
 	TW_Param *param;
-	int i, j, imax, num_units = 0, num_raid_five = 0;
+	int i, imax, num_units = 0;
 	u32 status_reg_addr, status_reg_value;
 	u32 command_que_addr, command_que_value;
 	u32 response_que_addr;
 	TW_Response_Queue response_queue;
 	u32 param_value;
 	unsigned char *is_unit_present;
-	unsigned char *raid_level;

 	dprintk(KERN_NOTICE "3w-xxxx: tw_initialize_units()\n");

@@ -1168,8 +1204,7 @@
 			}
 			if (command_packet->status != 0) {
 				/* bad response */
-				dprintk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Bad response, status = 0x%x, flags = 0x%x.\n", command_packet->status, command_packet->flags);
-				tw_decode_error(tw_dev, command_packet->status, command_packet->flags, command_packet->byte3.unit);
+				tw_decode_sense(tw_dev, request_id, 0);
 				return 1;
 			}
 			found = 1;
@@ -1205,109 +1240,6 @@
 		return 1;
 	}

-	/* Find raid 5 arrays */
-	for (j=0;j<TW_MAX_UNITS;j++) {
-		if (tw_dev->is_unit_present[j] == 0)
-			continue;
-		command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id];
-		if (command_packet == NULL) {
-			printk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Bad command packet virtual address.\n");
-			return 1;
-		}
-		memset(command_packet, 0, sizeof(TW_Sector));
-		command_packet->byte0.opcode      = TW_OP_GET_PARAM;
-		command_packet->byte0.sgl_offset  = 2;
-		command_packet->size              = 4;
-		command_packet->request_id        = request_id;
-		command_packet->byte3.unit        = 0;
-		command_packet->byte3.host_id     = 0;
-		command_packet->status            = 0;
-		command_packet->flags             = 0;
-		command_packet->byte6.block_count = 1;
-
-		/* Now setup the param */
-		if (tw_dev->alignment_virtual_address[request_id] == NULL) {
-			printk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Bad alignment virtual address.\n");
-			return 1;
-		}
-		param = (TW_Param *)tw_dev->alignment_virtual_address[request_id];
-		memset(param, 0, sizeof(TW_Sector));
-		param->table_id = 0x300+j; /* unit summary table */
-		param->parameter_id = 0x6; /* unit descriptor */
-		param->parameter_size_bytes = 0xc;
-		param_value = tw_dev->alignment_physical_address[request_id];
-		if (param_value == 0) {
-			printk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Bad alignment physical address.\n");
-			return 1;
-		}
-
-		command_packet->byte8.param.sgl[0].address = param_value;
-		command_packet->byte8.param.sgl[0].length = sizeof(TW_Sector);
-
-		/* Post the command packet to the board */
-		command_que_value = tw_dev->command_packet_physical_address[request_id];
-		if (command_que_value == 0) {
-			printk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Bad command packet physical address.\n");
-			return 1;
-		}
-		outl(command_que_value, command_que_addr);
-
-		/* Poll for completion */
-		imax = TW_POLL_MAX_RETRIES;
-		for(i=0; i<imax; i++) {
-			mdelay(5);
-			status_reg_value = inl(status_reg_addr);
-			if (tw_check_bits(status_reg_value)) {
-				dprintk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Unexpected bits.\n");
-				tw_decode_bits(tw_dev, status_reg_value);
-				return 1;
-			}
-			if ((status_reg_value & TW_STATUS_RESPONSE_QUEUE_EMPTY) == 0) {
-				response_queue.value = inl(response_que_addr);
-				request_id = (unsigned char)response_queue.u.response_id;
-				if (request_id != 0) {
-					/* unexpected request id */
-					printk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Unexpected request id.\n");
-					return 1;
-				}
-				if (command_packet->status != 0) {
-					/* bad response */
-					dprintk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Bad response, status = 0x%x, flags = 0x%x.\n", command_packet->status, command_packet->flags);
-					tw_decode_error(tw_dev, command_packet->status, command_packet->flags, command_packet->byte3.unit);
-					return 1;
-				}
-				found = 1;
-				break;
-			}
-		}
-		if (found == 0) {
-			/* response never received */
-			printk(KERN_WARNING "3w-xxxx: tw_initialize_units(): No response.\n");
-			return 1;
-		}
-
-		param = (TW_Param *)tw_dev->alignment_virtual_address[request_id];
-		raid_level = (unsigned char *)&(param->data[1]);
-		if (*raid_level == 5) {
-			dprintk(KERN_WARNING "3w-xxxx: Found unit %d to be a raid5 unit.\n", j);
-			tw_dev->is_raid_five[j] = 1;
-			num_raid_five++;
-		}
-	}
-	tw_dev->num_raid_five = num_raid_five;
-
-	/* Now allocate raid5 bounce buffers */
-	if ((num_raid_five != 0) && (tw_dev->tw_pci_dev->device == TW_DEVICE_ID)) {
-		for (i=0;i<TW_MAX_BOUNCEBUF;i++) {
-			tw_allocate_memory(tw_dev, i, sizeof(TW_Sector)*TW_MAX_SECTORS, 2);
-			if (tw_dev->bounce_buffer[i] == NULL) {
-				printk(KERN_WARNING "3w-xxxx: Bounce buffer allocation failed.\n");
-				return 1;
-			}
-			memset(tw_dev->bounce_buffer[i], 0, sizeof(TW_Sector)*TW_MAX_SECTORS);
-		}
-	}
-
 	return 0;
 } /* End tw_initialize_units() */

@@ -1332,13 +1264,18 @@

 	if (tw_dev->tw_pci_dev->irq == irq) {
 		spin_lock(&tw_dev->tw_lock);
-		dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt()\n");
+		dprintk(KERN_WARNING "3w-xxxx: tw_interrupt()\n");

 		/* Read the registers */
 		status_reg_addr = tw_dev->registers.status_reg_addr;
 		response_que_addr = tw_dev->registers.response_que_addr;
 		status_reg_value = inl(status_reg_addr);

+		if (tw_check_bits(status_reg_value)) {
+			dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Unexpected bits.\n");
+			tw_decode_bits(tw_dev, status_reg_value);
+		}
+
 		/* Check which interrupt */
 		if (status_reg_value & TW_STATUS_HOST_INTERRUPT)
 			do_host_interrupt=1;
@@ -1403,17 +1340,18 @@
 				command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id];
 				error = 0;
 				if (command_packet->status != 0) {
-					dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Bad response, status = 0x%x, flags = 0x%x, unit = 0x%x.\n", command_packet->status, command_packet->flags, command_packet->byte3.unit);
-					tw_decode_error(tw_dev, command_packet->status, command_packet->flags, command_packet->byte3.unit);
-					error = 1;
+					/* Bad response */
+					if (tw_dev->srb[request_id] != 0)
+						tw_decode_sense(tw_dev, request_id, 1);
+					error = 3;
 				}
 				if (tw_dev->state[request_id] != TW_S_POSTED) {
 					printk(KERN_WARNING "3w-xxxx: scsi%d: Received a request id (%d) (opcode = 0x%x) that wasn't posted.\n", tw_dev->host->host_no, request_id, command_packet->byte0.opcode);
 					error = 1;
 				}
 				if (TW_STATUS_ERRORS(status_reg_value)) {
-				  tw_decode_bits(tw_dev, status_reg_value);
-				  error = 1;
+					tw_decode_bits(tw_dev, status_reg_value);
+					error = 1;
 				}
 				dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): Response queue request id: %d.\n", request_id);
 				/* Check for internal command */
@@ -1428,7 +1366,7 @@
 						dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Unexpected bits.\n");
 						tw_decode_bits(tw_dev, status_reg_value);
 					}
-		} else {
+				} else {
 				switch (tw_dev->srb[request_id]->cmnd[0]) {
 					case READ_10:
 					case READ_6:
@@ -1455,18 +1393,23 @@
 						tw_dev->srb[request_id]->result = (DID_BAD_TARGET << 16);
 						tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]);
 					}
-					if (error) {
+					if (error == 1) {
 						/* Tell scsi layer there was an error */
 						dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Scsi Error.\n");
 						tw_dev->srb[request_id]->result = (DID_RESET << 16);
-					} else {
+					}
+					if (error == 0) {
 						/* Tell scsi layer command was a success */
 						tw_dev->srb[request_id]->result = (DID_OK << 16);
 					}
-					tw_dev->state[request_id] = TW_S_COMPLETED;
-					tw_state_request_finish(tw_dev, request_id);
-					tw_dev->posted_request_count--;
-					tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]);
+					if (error != 2) {
+						tw_dev->state[request_id] = TW_S_COMPLETED;
+						tw_state_request_finish(tw_dev, request_id);
+						tw_dev->posted_request_count--;
+						tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]);
+
+						tw_unmap_scsi_data(tw_dev->tw_pci_dev, tw_dev->srb[request_id]);
+					}
 					status_reg_value = inl(status_reg_addr);
 					if (tw_check_bits(status_reg_value)) {
 						dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Unexpected bits.\n");
@@ -1479,19 +1422,22 @@
 	}
 	spin_unlock_irqrestore(tw_dev->host->host_lock, flags);
 	clear_bit(TW_IN_INTR, &tw_dev->flags);
-}	/* End tw_interrupt() */
+} /* End tw_interrupt() */

 /* This function handles ioctls from userspace to the driver */
 int tw_ioctl(TW_Device_Extension *tw_dev, int request_id)
 {
 	unsigned char opcode;
-	int bufflen;
+	int bufflen, error = 0;
 	TW_Param *param;
-	TW_Command *command_packet;
+	TW_Command *command_packet, *command_save;
 	u32 param_value;
 	TW_Ioctl *ioctl = NULL;
 	TW_Passthru *passthru = NULL;
-	int tw_aen_code;
+	int tw_aen_code, i, use_sg;
+	char *data_ptr;
+	int total_bytes = 0;
+	dma_addr_t dma_handle;

 	ioctl = (TW_Ioctl *)tw_dev->srb[request_id]->request_buffer;
 	if (ioctl == NULL) {
@@ -1598,7 +1544,7 @@
 				printk(KERN_WARNING "3w-xxxx: tw_ioctl(): Passthru size (%ld) too big.\n", passthru->sg_list[0].length);
 				return 1;
 			}
-			passthru->sg_list[0].address = virt_to_bus(tw_dev->alignment_virtual_address[request_id]);
+			passthru->sg_list[0].address = tw_dev->alignment_physical_address[request_id];
 			tw_post_command_packet(tw_dev, request_id);
 			return 0;
 		case TW_CMD_PACKET:
@@ -1612,6 +1558,161 @@
 				printk(KERN_WARNING "3w-xxxx: tw_ioctl(): ioctl->data NULL.\n");
 				return 1;
 			}
+		case TW_CMD_PACKET_WITH_DATA:
+			dprintk(KERN_WARNING "3w-xxxx: tw_ioctl(): caught TW_CMD_PACKET_WITH_DATA.\n");
+			command_save = (TW_Command *)tw_dev->alignment_virtual_address[request_id];
+			if (command_save == NULL) {
+				printk(KERN_WARNING "3w-xxxx: scsi%d: tw_ioctl(): Bad alignment virtual address.\n", tw_dev->host->host_no);
+				return 1;
+			}
+			if (ioctl->data != NULL) {
+				/* Copy down the command packet */
+				memcpy(command_packet, ioctl->data, sizeof(TW_Command));
+				memcpy(command_save, ioctl->data, sizeof(TW_Command));
+				command_packet->request_id = request_id;
+
+				/* Now deal with the two possible sglists */
+				if (command_packet->byte0.sgl_offset == 2) {
+					use_sg = command_packet->size - 3;
+					for (i=0;i<use_sg;i++)
+						total_bytes+=command_packet->byte8.param.sgl[i].length;
+					tw_dev->ioctl_data[request_id] = pci_alloc_consistent(tw_dev->tw_pci_dev, total_bytes, &dma_handle);
+
+					if (!tw_dev->ioctl_data[request_id]) {
+						printk(KERN_WARNING "3w-xxxx: scsi%d: tw_ioctl(): kmalloc failed for request_id %d.\n", tw_dev->host->host_no, request_id);
+						return 1;
+					}
+
+					/* Copy param sglist into the kernel */
+					data_ptr = tw_dev->ioctl_data[request_id];
+					for (i=0;i<use_sg;i++) {
+						if ((u32 *)command_packet->byte8.param.sgl[i].address != NULL) {
+							error = copy_from_user(data_ptr, (u32 *)command_packet->byte8.param.sgl[i].address, command_packet->byte8.param.sgl[i].length);
+							if (error) {
+								printk(KERN_WARNING "3w-xxxx: scsi%d: Error copying param sglist from userspace.\n", tw_dev->host->host_no);
+								goto tw_ioctl_bail;
+							}
+						} else {
+							printk(KERN_WARNING "3w-xxxx: scsi%d: tw_ioctl(): Bad param sgl address.\n", tw_dev->host->host_no);
+							tw_dev->srb[request_id]->result = (DID_RESET << 16);
+							goto tw_ioctl_bail;
+						}
+						data_ptr+=command_packet->byte8.param.sgl[i].length;
+					}
+					command_packet->size = 4;
+					command_packet->byte8.param.sgl[0].address = dma_handle;
+					command_packet->byte8.param.sgl[0].length = total_bytes;
+				}
+				if (command_packet->byte0.sgl_offset == 3) {
+					use_sg = command_packet->size - 4;
+					for (i=0;i<use_sg;i++)
+						total_bytes+=command_packet->byte8.io.sgl[i].length;
+					tw_dev->ioctl_data[request_id] = pci_alloc_consistent(tw_dev->tw_pci_dev, total_bytes, &dma_handle);
+
+					if (!tw_dev->ioctl_data[request_id]) {
+						printk(KERN_WARNING "3w-xxxx: scsi%d: tw_ioctl(): pci_alloc_consistent() failed for request_id %d.\n", tw_dev->host->host_no, request_id);
+						return 1;
+					}
+					if (command_packet->byte0.opcode == TW_OP_WRITE) {
+						/* Copy io sglist into the kernel */
+						data_ptr = tw_dev->ioctl_data[request_id];
+						for (i=0;i<use_sg;i++) {
+							if ((u32 *)command_packet->byte8.io.sgl[i].address != NULL) {
+								error = copy_from_user(data_ptr, (u32 *)command_packet->byte8.io.sgl[i].address, command_packet->byte8.io.sgl[i].length);
+								if (error) {
+									printk(KERN_WARNING "3w-xxxx: scsi%d: Error copying io sglist from userspace.\n", tw_dev->host->host_no);
+									goto tw_ioctl_bail;
+								}
+							} else {
+								printk(KERN_WARNING "3w-xxxx: scsi%d: tw_ioctl(): Bad io sgl address.\n", tw_dev->host->host_no);
+								tw_dev->srb[request_id]->result = (DID_RESET << 16);
+								goto tw_ioctl_bail;
+							}
+							data_ptr+=command_packet->byte8.io.sgl[i].length;
+						}
+					}
+					command_packet->size = 5;
+					command_packet->byte8.io.sgl[0].address = dma_handle;
+					command_packet->byte8.io.sgl[0].length = total_bytes;
+				}
+
+				spin_unlock_irq(tw_dev->host->host_lock);
+				spin_unlock_irq(&tw_dev->tw_lock);
+
+				/* Finally post the command packet */
+				tw_post_command_packet(tw_dev, request_id);
+
+				mdelay(TW_IOCTL_WAIT_TIME);
+				spin_lock_irq(&tw_dev->tw_lock);
+				spin_lock_irq(tw_dev->host->host_lock);
+
+				if (signal_pending(current)) {
+					dprintk(KERN_WARNING "3w-xxxx: scsi%d: tw_ioctl(): Signal pending, aborting ioctl().\n", tw_dev->host->host_no);
+					tw_dev->srb[request_id]->result = (DID_OK << 16);
+					goto tw_ioctl_bail;
+				}
+
+				tw_dev->srb[request_id]->result = (DID_OK << 16);
+				/* Now copy up the param or io sglist to userspace */
+				if (command_packet->byte0.sgl_offset == 2) {
+					use_sg = command_save->size - 3;
+					data_ptr = phys_to_virt(command_packet->byte8.param.sgl[0].address);
+					for (i=0;i<use_sg;i++) {
+						if ((u32 *)command_save->byte8.param.sgl[i].address != NULL) {
+							error = copy_to_user((u32 *)command_save->byte8.param.sgl[i].address, data_ptr, command_save->byte8.param.sgl[i].length);
+							if (error) {
+								printk(KERN_WARNING "3w-xxxx: scsi%d: Error copying param sglist to userspace.\n", tw_dev->host->host_no);
+								goto tw_ioctl_bail;
+							}
+							dprintk(KERN_WARNING "3w-xxxx: scsi%d: Copied %ld bytes to pid %d.\n", tw_dev->host->host_no, command_save->byte8.param.sgl[i].length, current->pid);
+							data_ptr+=command_save->byte8.param.sgl[i].length;
+						} else {
+							printk(KERN_WARNING "3w-xxxx: scsi%d: tw_ioctl(): Bad param sgl address.\n", tw_dev->host->host_no);
+							tw_dev->srb[request_id]->result = (DID_RESET << 16);
+							goto tw_ioctl_bail;
+						}
+					}
+				}
+				if (command_packet->byte0.sgl_offset == 3) {
+					use_sg = command_save->size - 4;
+					if (command_packet->byte0.opcode == TW_OP_READ) {
+						data_ptr = phys_to_virt(command_packet->byte8.io.sgl[0].address);
+						for(i=0;i<use_sg;i++) {
+							if ((u32 *)command_save->byte8.io.sgl[i].address != NULL) {
+								error = copy_to_user((u32 *)command_save->byte8.io.sgl[i].address, data_ptr, command_save->byte8.io.sgl[i].length);
+								if (error) {
+									printk(KERN_WARNING "3w-xxxx: scsi%d: Error copying io sglist to userspace.\n", tw_dev->host->host_no);
+									goto tw_ioctl_bail;
+								}
+								dprintk(KERN_WARNING "3w-xxxx: scsi%d: Copied %ld bytes to pid %d.\n", tw_dev->host->host_no, command_save->byte8.io.sgl[i].length, current->pid);
+								data_ptr+=command_save->byte8.io.sgl[i].length;
+							} else {
+								printk(KERN_WARNING "3w-xxxx: scsi%d: tw_ioctl(): Bad io sgl address.\n", tw_dev->host->host_no);
+								tw_dev->srb[request_id]->result = (DID_RESET << 16);
+								goto tw_ioctl_bail;
+							}
+						}
+					}
+				}
+
+			tw_ioctl_bail:
+
+				/* Free up sglist memory */
+				if (tw_dev->ioctl_data[request_id])
+					pci_free_consistent(tw_dev->tw_pci_dev, total_bytes, tw_dev->ioctl_data[request_id], dma_handle);
+				else
+					printk(KERN_WARNING "3w-xxxx: scsi%d: tw_ioctl(): Error freeing ioctl data.\n", tw_dev->host->host_no);
+
+				/* Now complete the io */
+				tw_dev->state[request_id] = TW_S_COMPLETED;
+				tw_state_request_finish(tw_dev, request_id);
+				tw_dev->posted_request_count--;
+				tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]);
+				return 0;
+			} else {
+				printk(KERN_WARNING "3w-xxxx: tw_ioctl(): ioctl->data NULL.\n");
+				return 1;
+			}
 		default:
 			printk(KERN_WARNING "3w-xxxx: Unknown ioctl 0x%x.\n", opcode);
 			tw_dev->state[request_id] = TW_S_COMPLETED;
@@ -1655,6 +1756,7 @@
 	TW_Param *param;
 	TW_Ioctl *ioctl = NULL;
 	TW_Passthru *passthru = NULL;
+	TW_Command *command_packet;

 	ioctl = (TW_Ioctl *)tw_dev->srb[request_id]->request_buffer;
 	dprintk(KERN_NOTICE "3w-xxxx: tw_ioctl_complete()\n");
@@ -1663,6 +1765,13 @@
 		printk(KERN_WARNING "3w-xxxx: tw_ioctl_complete(): Request buffer NULL.\n");
 		return 1;
 	}
+
+	command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id];
+	if (command_packet == NULL) {
+		printk(KERN_WARNING "3w-xxxx: scsi%d: tw_ioctl_complete(): Bad command packet virtual address.\n", tw_dev->host->host_no);
+		return 1;
+	}
+
 	dprintk(KERN_NOTICE "3w-xxxx: tw_ioctl_complete(): Request_bufflen = %d\n", tw_dev->srb[request_id]->request_bufflen);

 	ioctl = (TW_Ioctl *)buff;
@@ -1671,6 +1780,9 @@
 			passthru = (TW_Passthru *)ioctl->data;
 			memcpy(buff, tw_dev->alignment_virtual_address[request_id], passthru->sector_count * 512);
 			break;
+		case TW_CMD_PACKET_WITH_DATA:
+			dprintk(KERN_WARNING "3w-xxxx: tw_ioctl_complete(): caught TW_CMD_PACKET_WITH_DATA.\n");
+			return 2; /* Special case for isr to not complete io */
 		default:
 			memset(buff, 0, tw_dev->srb[request_id]->request_bufflen);
 			param = (TW_Param *)tw_dev->alignment_virtual_address[request_id];
@@ -1684,6 +1796,40 @@
 	return 0;
 } /* End tw_ioctl_complete() */

+static int tw_map_scsi_sg_data(struct pci_dev *pdev, Scsi_Cmnd *cmd)
+{
+	int use_sg;
+	int dma_dir = scsi_to_pci_dma_dir(cmd->sc_data_direction);
+
+	dprintk(KERN_WARNING "3w-xxxx: tw_map_scsi_sg_data()\n");
+
+	if (cmd->use_sg == 0)
+		return 0;
+
+	use_sg = pci_map_sg(pdev, cmd->buffer, cmd->use_sg, dma_dir);
+	cmd->SCp.phase = 2;
+	cmd->SCp.have_data_in = use_sg;
+
+	return use_sg;
+} /* End tw_map_scsi_sg_data() */
+
+static u32 tw_map_scsi_single_data(struct pci_dev *pdev, Scsi_Cmnd *cmd)
+{
+	dma_addr_t mapping;
+	int dma_dir = scsi_to_pci_dma_dir(cmd->sc_data_direction);
+
+	dprintk(KERN_WARNING "3w-xxxx: tw_map_scsi_single_data()\n");
+
+	if (cmd->request_bufflen == 0)
+		return 0;
+
+	mapping = pci_map_single(pdev, cmd->request_buffer, cmd->request_bufflen, dma_dir);
+	cmd->SCp.phase = 2;
+	cmd->SCp.have_data_in = mapping;
+
+	return mapping;
+} /* End tw_map_scsi_single_data() */
+
 /* This function will mask the command interrupt */
 void tw_mask_command_interrupt(TW_Device_Extension *tw_dev)
 {
@@ -1704,14 +1850,25 @@
 	do_gettimeofday(&before);
 	status_reg_value = inl(status_reg_addr);

+	if (tw_check_bits(status_reg_value)) {
+		dprintk(KERN_WARNING "3w-xxxx: tw_poll_status(): Unexpected bits.\n");
+		tw_decode_bits(tw_dev, status_reg_value);
+	}
+
 	while ((status_reg_value & flag) != flag) {
 		status_reg_value = inl(status_reg_addr);
+
+		if (tw_check_bits(status_reg_value)) {
+			dprintk(KERN_WARNING "3w-xxxx: tw_poll_status(): Unexpected bits.\n");
+			tw_decode_bits(tw_dev, status_reg_value);
+		}
+
 		do_gettimeofday(&timeout);
 		if (before.tv_sec + seconds < timeout.tv_sec) {
 			dprintk(KERN_WARNING "3w-xxxx: tw_poll_status(): Flag 0x%x not found.\n", flag);
 			return 1;
 		}
-		mdelay(1);
+		mdelay(5);
 	}
 	return 0;
 } /* End tw_poll_status() */
@@ -1787,6 +1944,7 @@
 				srb = tw_dev->srb[i];
 				srb->result = (DID_RESET << 16);
 				tw_dev->srb[i]->scsi_done(tw_dev->srb[i]);
+				tw_unmap_scsi_data(tw_dev->tw_pci_dev, tw_dev->srb[i]);
 			}
 		}
 	}
@@ -1821,7 +1979,7 @@

 		error = tw_aen_drain_queue(tw_dev);
 		if (error) {
-			printk(KERN_WARNING "3w-xxxx: scsi%d: Card not responding, retrying.\n", tw_dev->host->host_no);
+			printk(KERN_WARNING "3w-xxxx: scsi%d: AEN drain failed, retrying.\n", tw_dev->host->host_no);
 			tries++;
 			continue;
 		}
@@ -1857,7 +2015,7 @@
 	}

 	/* Re-enable interrupts */
-	tw_enable_interrupts(tw_dev);
+	tw_enable_and_clear_interrupts(tw_dev);

 	return 0;
 } /* End tw_reset_sequence() */
@@ -2381,6 +2539,9 @@
 	capacity = (param_data[3] << 24) | (param_data[2] << 16) |
 		   (param_data[1] << 8) | param_data[0];

+	/* Subtract one sector to fix get last sector ioctl */
+	capacity -= 1;
+
 	dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_read_capacity_complete(): Capacity = 0x%x.\n", capacity);

 	/* Number of LBA's */
@@ -2403,8 +2564,8 @@
 {
 	TW_Command *command_packet;
 	u32 command_que_addr, command_que_value = 0;
-	u32 lba = 0x0, num_sectors = 0x0;
-	int i, count = 0;
+	u32 lba = 0x0, num_sectors = 0x0, buffaddr = 0x0;
+	int i, use_sg;
 	Scsi_Cmnd *srb;
 	struct scatterlist *sglist;

@@ -2461,45 +2622,25 @@
 	command_packet->byte8.io.lba = lba;
 	command_packet->byte6.block_count = num_sectors;

-	if ((tw_dev->is_raid_five[tw_dev->srb[request_id]->target] == 0) || (srb->cmnd[0] == READ_6) || (srb->cmnd[0] == READ_10) || (tw_dev->tw_pci_dev->device == TW_DEVICE_ID2)) {
-		/* Do this if there are no sg list entries */
-		if (tw_dev->srb[request_id]->use_sg == 0) {
-			dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_read_write(): SG = 0\n");
-			command_packet->byte8.io.sgl[0].address = virt_to_bus(tw_dev->srb[request_id]->request_buffer);
-			command_packet->byte8.io.sgl[0].length = tw_dev->srb[request_id]->request_bufflen;
-		}
-
-		/* Do this if we have multiple sg list entries */
-		if (tw_dev->srb[request_id]->use_sg > 0) {
-			for (i=0;i<tw_dev->srb[request_id]->use_sg; i++) {
-				command_packet->byte8.io.sgl[i].address = virt_to_bus(sglist[i].address);
-				command_packet->byte8.io.sgl[i].length = sglist[i].length;
-				command_packet->size+=2;
-			}
-			if (tw_dev->srb[request_id]->use_sg >= 1)
-				command_packet->size-=2;
+	/* Do this if there are no sg list entries */
+	if (tw_dev->srb[request_id]->use_sg == 0) {
+		dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_read_write(): SG = 0\n");
+		buffaddr = tw_map_scsi_single_data(tw_dev->tw_pci_dev, tw_dev->srb[request_id]);
+		command_packet->byte8.io.sgl[0].address = buffaddr;
+		command_packet->byte8.io.sgl[0].length = tw_dev->srb[request_id]->request_bufflen;
+	}
+
+	/* Do this if we have multiple sg list entries */
+	if (tw_dev->srb[request_id]->use_sg > 0) {
+		use_sg = tw_map_scsi_sg_data(tw_dev->tw_pci_dev, tw_dev->srb[request_id]);;
+		for (i=0;i<use_sg; i++) {
+			command_packet->byte8.io.sgl[i].address = sg_dma_address(&sglist[i]);
+			command_packet->byte8.io.sgl[i].length = sg_dma_len(&sglist[i]);
+			command_packet->size+=2;
 		}
-	} else {
-                /* Do this if there are no sg list entries for raid 5 */
-                if (tw_dev->srb[request_id]->use_sg == 0) {
-			dprintk(KERN_WARNING "doing raid 5 write use_sg = 0, bounce_buffer[%d] = 0x%p\n", request_id, tw_dev->bounce_buffer[request_id]);
-			memcpy(tw_dev->bounce_buffer[request_id], tw_dev->srb[request_id]->request_buffer, tw_dev->srb[request_id]->request_bufflen);
-			command_packet->byte8.io.sgl[0].address = virt_to_bus(tw_dev->bounce_buffer[request_id]);
-			command_packet->byte8.io.sgl[0].length = tw_dev->srb[request_id]->request_bufflen;
-                }
-
-                /* Do this if we have multiple sg list entries for raid 5 */
-                if (tw_dev->srb[request_id]->use_sg > 0) {
-                        dprintk(KERN_WARNING "doing raid 5 write use_sg = %d, sglist[0].length = %d\n", tw_dev->srb[request_id]->use_sg, sglist[0].length);
-                        for (i=0;i<tw_dev->srb[request_id]->use_sg; i++) {
-                                memcpy((char *)(tw_dev->bounce_buffer[request_id])+count, sglist[i].address, sglist[i].length);
-				count+=sglist[i].length;
-                        }
-                        command_packet->byte8.io.sgl[0].address = virt_to_bus(tw_dev->bounce_buffer[request_id]);
-                        command_packet->byte8.io.sgl[0].length = count;
-                        command_packet->size = 5; /* single sgl */
-                }
-        }
+		if (tw_dev->srb[request_id]->use_sg >= 1)
+			command_packet->size-=2;
+	}

 	/* Update SG statistics */
 	tw_dev->sgl_entries = tw_dev->srb[request_id]->use_sg;
@@ -2521,18 +2662,18 @@
 /* This function will handle the request sense scsi command */
 int tw_scsiop_request_sense(TW_Device_Extension *tw_dev, int request_id)
 {
-       dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_request_sense()\n");
-
-       /* For now we just zero the sense buffer */
-       memset(tw_dev->srb[request_id]->request_buffer, 0, tw_dev->srb[request_id]->request_bufflen);
-       tw_dev->state[request_id] = TW_S_COMPLETED;
-       tw_state_request_finish(tw_dev, request_id);
-
-       /* If we got a request_sense, we probably want a reset, return error */
-       tw_dev->srb[request_id]->result = (DID_ERROR << 16);
-       tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]);
-
-       return 0;
+	dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_request_sense()\n");
+
+	/* For now we just zero the request buffer */
+	memset(tw_dev->srb[request_id]->request_buffer, 0, tw_dev->srb[request_id]->request_bufflen);
+	tw_dev->state[request_id] = TW_S_COMPLETED;
+	tw_state_request_finish(tw_dev, request_id);
+
+	/* If we got a request_sense, we probably want a reset, return error */
+	tw_dev->srb[request_id]->result = (DID_ERROR << 16);
+	tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]);
+
+	return 0;
 } /* End tw_scsiop_request_sense() */

 /* This function will handle test unit ready scsi command */
@@ -2626,8 +2767,7 @@
 			}
 			if (command_packet->status != 0) {
 				/* bad response */
-				dprintk(KERN_WARNING "3w-xxxx: tw_setfeature(): Bad response, status = 0x%x, flags = 0x%x.\n", command_packet->status, command_packet->flags);
-				tw_decode_error(tw_dev, command_packet->status, command_packet->flags, command_packet->byte3.unit);
+				tw_decode_sense(tw_dev, request_id, 0);
 				return 1;
 			}
 			break; /* Response was okay, so we exit */
@@ -2671,7 +2811,7 @@
 	}

 	/* Re-enable interrupts */
-	tw_enable_interrupts(tw_dev);
+	tw_enable_and_clear_interrupts(tw_dev);

 	return 0;
 } /* End tw_shutdown_device() */
@@ -2719,7 +2859,7 @@
 	int id = 0;

 	dprintk(KERN_NOTICE "3w-xxxx: tw_state_request_start()\n");
-
+
 	/* Obtain next free request_id */
 	do {
 		if (tw_dev->free_head == tw_dev->free_wrap) {
@@ -2738,6 +2878,19 @@
 	return 0;
 } /* End tw_state_request_start() */

+static void tw_unmap_scsi_data(struct pci_dev *pdev, Scsi_Cmnd *cmd)
+{
+	int dma_dir = scsi_to_pci_dma_dir(cmd->sc_data_direction);
+
+	dprintk(KERN_WARNING "3w-xxxx: tw_unmap_scsi_data()\n");
+
+	if (cmd->use_sg) {
+		pci_unmap_sg(pdev, cmd->request_buffer, cmd->use_sg, dma_dir);
+	} else {
+		pci_unmap_single(pdev, cmd->SCp.have_data_in, cmd->request_bufflen, dma_dir);
+	}
+} /* End tw_unmap_scsi_data() */
+
 /* This function will unmask the command interrupt on the controller */
 void tw_unmask_command_interrupt(TW_Device_Extension *tw_dev)
 {
@@ -2749,7 +2902,6 @@
 } /* End tw_unmask_command_interrupt() */

 /* Now get things going */
-
 static Scsi_Host_Template driver_template = TWXXXX;
 #include "scsi_module.c"

diff -Naur linux-2.5.6-pre1/drivers/scsi/3w-xxxx.h linux-2.5.6-pre2/drivers/scsi/3w-xxxx.h
--- linux-2.5.6-pre1/drivers/scsi/3w-xxxx.h	Tue Feb 19 18:10:58 2002
+++ linux-2.5.6-pre2/drivers/scsi/3w-xxxx.h	Wed Feb 27 11:53:52 2002
@@ -6,7 +6,7 @@
    		     Arnaldo Carvalho de Melo <acme@conectiva.com.br>
                      Brad Strand <linux@3ware.com>

-   Copyright (C) 1999-2001 3ware Inc.
+   Copyright (C) 1999-2002 3ware Inc.

    Kernel compatablity By:	Andre Hedrick <andre@suse.com>
    Non-Copyright (C) 2000	Andre Hedrick <andre@suse.com>
@@ -62,7 +62,7 @@
 static char *tw_aen_string[] = {
 	"AEN queue empty",                      // 0x000
 	"Soft reset occurred",                  // 0x001
-	"Mirorr degraded: Unit #",              // 0x002
+	"Unit degraded: Unit #",                // 0x002
 	"Controller error",                     // 0x003
 	"Rebuild failed: Unit #",               // 0x004
 	"Rebuild complete: Unit #",             // 0x005
@@ -90,10 +90,36 @@
 	"DCB unsupported version: Port #",      // 0x028
 	"Verify started: Unit #",               // 0x029
 	"Verify failed: Port #",                // 0x02A
-	"Verify complete: Unit #"               // 0x02B
+	"Verify complete: Unit #",              // 0x02B
+	"Overwrote bad sector during rebuild: Port #",  //0x2C
+	"Encountered bad sector during rebuild: Port #" //0x2D
 };

-#define TW_AEN_STRING_MAX                      0x02C
+#define TW_AEN_STRING_MAX                      0x02E
+
+/*
+   Sense key lookup table
+   Format: ESDC/flags,SenseKey,AdditionalSenseCode,AdditionalSenseCodeQualifier
+*/
+static unsigned char tw_sense_table[][4] =
+{
+  /* Codes for newer firmware */
+                            // ATA Error                    SCSI Error
+  {0x01, 0x03, 0x13, 0x00}, // Address mark not found       Address mark not found for data field
+  {0x04, 0x0b, 0x00, 0x00}, // Aborted command              Aborted command
+  {0x10, 0x0b, 0x14, 0x00}, // ID not found                 Recorded entity not found
+  {0x40, 0x03, 0x11, 0x00}, // Uncorrectable ECC error      Unrecovered read error
+  {0x61, 0x04, 0x00, 0x00}, // Device fault                 Hardware error
+  {0x84, 0x0b, 0x47, 0x00}, // Data CRC error               SCSI parity error
+  {0xd0, 0x0b, 0x00, 0x00}, // Device busy                  Aborted command
+  {0xd1, 0x0b, 0x00, 0x00}, // Device busy                  Aborted command
+
+  /* Codes for older firmware */
+                            // 3ware Error                  SCSI Error
+  {0x09, 0x0b, 0x00, 0x00}, // Unrecovered disk error       Aborted command
+  {0x37, 0x0b, 0x04, 0x00}, // Unit offline                 Logical unit not ready
+  {0x51, 0x0b, 0x00, 0x00}  // Unspecified                  Aborted command
+};

 /* Control register bit definitions */
 #define TW_CONTROL_CLEAR_HOST_INTERRUPT	       0x00080000
@@ -108,6 +134,7 @@
 #define TW_CONTROL_DISABLE_INTERRUPTS	       0x00000040
 #define TW_CONTROL_ISSUE_HOST_INTERRUPT	       0x00000020
 #define TW_CONTROL_CLEAR_PARITY_ERROR          0x00800000
+#define TW_CONTROL_CLEAR_PCI_ABORT             0x00100000

 /* Status register bit definitions */
 #define TW_STATUS_MAJOR_VERSION_MASK	       0xF0000000
@@ -140,6 +167,7 @@
 #define TW_DEVICE_ID2 (0x1001)  /* 7000 series controller */
 #define TW_NUMDEVICES 2
 #define TW_PCI_CLEAR_PARITY_ERRORS 0xc100
+#define TW_PCI_CLEAR_PCI_ABORT     0x2000

 /* Command packet opcodes */
 #define TW_OP_NOP	      0x0
@@ -153,6 +181,7 @@
 #define TW_OP_AEN_LISTEN      0x1c
 #define TW_CMD_PACKET         0x1d
 #define TW_ATA_PASSTHRU       0x1e
+#define TW_CMD_PACKET_WITH_DATA 0x1f

 /* Asynchronous Event Notification (AEN) Codes */
 #define TW_AEN_QUEUE_EMPTY       0x0000
@@ -169,7 +198,8 @@
 #define TW_AEN_SBUF_FAIL         0x0024

 /* Misc defines */
-#define TW_ALIGNMENT			      0x200 /* 16 D-WORDS */
+#define TW_ALIGNMENT_6000		      64 /* 64 bytes */
+#define TW_ALIGNMENT_7000                     4  /* 4 bytes */
 #define TW_MAX_UNITS			      16
 #define TW_COMMAND_ALIGNMENT_MASK	      0x1ff
 #define TW_INIT_MESSAGE_CREDITS		      0x100
@@ -179,7 +209,6 @@
 #define TW_ATA_PASS_SGL_MAX                   60
 #define TW_MAX_PASSTHRU_BYTES                 4096
 #define TW_Q_LENGTH			      256
-#define TW_MAX_BOUNCEBUF                      16
 #define TW_Q_START			      0
 #define TW_MAX_SLOT			      32
 #define TW_MAX_PCI_BUSES		      255
@@ -191,12 +220,9 @@
 #define TW_MAX_AEN_TRIES                      100
 #define TW_UNIT_ONLINE                        1
 #define TW_IN_INTR                            1
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,7)
 #define TW_MAX_SECTORS                        256
-#else
-#define TW_MAX_SECTORS                        128
-#endif
 #define TW_AEN_WAIT_TIME                      1000
+#define TW_IOCTL_WAIT_TIME                    (1 * HZ) /* 1 second */

 /* Macros */
 #define TW_STATUS_ERRORS(x) \
@@ -262,7 +288,6 @@
 } TW_Command;

 typedef struct TAG_TW_Ioctl {
-	int buffer;
 	unsigned char opcode;
 	unsigned short table_id;
 	unsigned char parameter_id;
@@ -345,11 +370,8 @@
 	TW_Registers		registers;
 	u32			*alignment_virtual_address[TW_Q_LENGTH];
 	u32			alignment_physical_address[TW_Q_LENGTH];
-	u32			*bounce_buffer[TW_Q_LENGTH];
 	int			is_unit_present[TW_MAX_UNITS];
-	int			is_raid_five[TW_MAX_UNITS];
 	int			num_units;
-	int			num_raid_five;
 	u32			*command_packet_virtual_address[TW_Q_LENGTH];
 	u32			command_packet_physical_address[TW_Q_LENGTH];
 	struct pci_dev		*tw_pci_dev;
@@ -381,22 +403,24 @@
 	unsigned char		aen_head;
 	unsigned char		aen_tail;
 	long			flags; /* long req'd for set_bit --RR */
+	char			*ioctl_data[TW_Q_LENGTH];
 } TW_Device_Extension;

 /* Function prototypes */
 int tw_aen_complete(TW_Device_Extension *tw_dev, int request_id);
 int tw_aen_drain_queue(TW_Device_Extension *tw_dev);
 int tw_aen_read_queue(TW_Device_Extension *tw_dev, int request_id);
-int tw_allocate_memory(TW_Device_Extension *tw_dev, int request_id, int size, int which);
+int tw_allocate_memory(TW_Device_Extension *tw_dev, int size, int which);
 int tw_check_bits(u32 status_reg_value);
 int tw_check_errors(TW_Device_Extension *tw_dev);
 void tw_clear_attention_interrupt(TW_Device_Extension *tw_dev);
 void tw_clear_host_interrupt(TW_Device_Extension *tw_dev);
 void tw_decode_bits(TW_Device_Extension *tw_dev, u32 status_reg_value);
-void tw_decode_error(TW_Device_Extension *tw_dev, unsigned char status, unsigned char flags, unsigned char unit);
+void tw_decode_sense(TW_Device_Extension *tw_dev, int request_id, int fill_sense);
 void tw_disable_interrupts(TW_Device_Extension *tw_dev);
 int tw_empty_response_que(TW_Device_Extension *tw_dev);
 void tw_enable_interrupts(TW_Device_Extension *tw_dev);
+void tw_enable_and_clear_interrupts(TW_Device_Extension *tw_dev);
 int tw_findcards(Scsi_Host_Template *tw_host);
 void tw_free_device_extension(TW_Device_Extension *tw_dev);
 int tw_initconnection(TW_Device_Extension *tw_dev, int message_credits);



^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: 3ware driver update for 2.5.6-pre2 (new DMA mapping)
  2002-02-27 21:45 3ware driver update for 2.5.6-pre2 (new DMA mapping) adam@mailhost.nmt.edu
@ 2002-02-27 22:46 ` Jeff V. Merkey
  2002-02-27 22:58 ` Jeff V. Merkey
  1 sibling, 0 replies; 4+ messages in thread
From: Jeff V. Merkey @ 2002-02-27 22:46 UTC (permalink / raw)
  To: adam@mailhost.nmt.edu; +Cc: alan, linux-kernel



Adam,

Any ideas on the problem I reported earlier?  Does this patch 
correct the problems we are seeing with your cards?

Jeff


On Wed, Feb 27, 2002 at 02:45:04PM -0700, adam@mailhost.nmt.edu wrote:
> Alan,
> 
> Please apply this patch for kernel 2.5.6-pre2 for the 3ware driver to
> support the new DMA mapping code, and several other fixes.
> 
> Thanks.
> 
> --
> Adam Radford
> Software Engineer
> 3ware, Inc.
> 
> diff -Naur linux-2.5.6-pre1/drivers/scsi/3w-xxxx.c linux-2.5.6-pre2/drivers/scsi/3w-xxxx.c
> --- linux-2.5.6-pre1/drivers/scsi/3w-xxxx.c	Tue Feb 19 18:11:00 2002
> +++ linux-2.5.6-pre2/drivers/scsi/3w-xxxx.c	Wed Feb 27 11:53:49 2002
> @@ -6,7 +6,7 @@
>     		     Arnaldo Carvalho de Melo <acme@conectiva.com.br>
>                       Brad Strand <linux@3ware.com>
> 
> -   Copyright (C) 1999-2001 3ware Inc.
> +   Copyright (C) 1999-2002 3ware Inc.
> 
>     Kernel compatablity By: 	Andre Hedrick <andre@suse.com>
>     Non-Copyright (C) 2000	Andre Hedrick <andre@suse.com>
> @@ -106,17 +106,41 @@
>                   Add entire aen code string list.
>     1.02.00.010 - Cleanup queueing code, fix jbod thoughput.
>                   Fix get_param for specific units.
> +   1.02.00.011 - Fix bug in tw_aen_complete() where aen's could be lost.
> +                 Fix tw_aen_drain_queue() to display useful info at init.
> +                 Set tw_host->max_id for 12 port cards.
> +                 Add ioctl support for raw command packet post from userspace
> +                 with sglist fragments (parameter and io).
> +   1.02.00.012 - Fix read capacity to under report by 1 sector to fix get
> +                 last sector ioctl.
> +   1.02.00.013 - Fix bug where more AEN codes weren't coming out during
> +                 driver initialization.
> +                 Improved handling of PCI aborts.
> +   1.02.00.014 - Fix bug in tw_findcards() where AEN code could be lost.
> +                 Increase timeout in tw_aen_drain_queue() to 30 seconds.
> +   1.02.00.015 - Re-write raw command post with data ioctl method.
> +                 Remove raid5 bounce buffers for raid5 for 6XXX for kernel 2.5
> +                 Add tw_map/unmap_scsi_sg/single_data() for kernel 2.5
> +                 Replace io_request_lock with host_lock for kernel 2.5
> +                 Set max_cmd_len to 16 for 3dm for kernel 2.5
> +   1.02.00.016 - Set host->max_sectors back up to 256.
> +   1.02.00.017 - Modified pci parity error handling/clearing from config space
> +                 during initialization.
> +   1.02.00.018 - Better handling of request sense opcode and sense information
> +                 for failed commands.  Add tw_decode_sense().
> +                 Replace all mdelay()'s with scsi_sleep().
> +   1.02.00.019 - Revert mdelay's and scsi_sleep's, this caused problems on
> +                 some SMP systems.
> +   1.02.00.020 - Add pci_set_dma_mask(), rewrite kmalloc()/virt_to_bus() to
> +                 pci_alloc/free_consistent().
>  */
> 
> -#error Please convert me to Documentation/DMA-mapping.txt
> -
>  #include <linux/module.h>
> 
>  MODULE_AUTHOR ("3ware Inc.");
>  MODULE_DESCRIPTION ("3ware Storage Controller Linux Driver");
>  MODULE_LICENSE("GPL");
> 
> -
>  #include <linux/kernel.h>
>  #include <linux/pci.h>
>  #include <linux/time.h>
> @@ -148,14 +172,17 @@
>  static void tw_copy_mem_info(TW_Info *info, char *data, int len);
>  static void tw_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
>  static int tw_halt(struct notifier_block *nb, ulong event, void *buf);
> +static int tw_map_scsi_sg_data(struct pci_dev *pdev, Scsi_Cmnd *cmd);
> +static u32 tw_map_scsi_single_data(struct pci_dev *pdev, Scsi_Cmnd *cmd);
> +static void tw_unmap_scsi_data(struct pci_dev *pdev, Scsi_Cmnd *cmd);
> 
>  /* Notifier block to get a notify on system shutdown/halt/reboot */
>  static struct notifier_block tw_notifier = {
> -  tw_halt, NULL, 0
> +	tw_halt, NULL, 0
>  };
> 
>  /* Globals */
> -char *tw_driver_version="1.02.00.010";
> +char *tw_driver_version="1.02.00.020";
>  TW_Device_Extension *tw_device_extension_list[TW_MAX_SLOT];
>  int tw_device_extension_count = 0;
> 
> @@ -166,6 +193,7 @@
>  {
>  	TW_Param *param;
>  	unsigned short aen;
> +	int error = 0;
> 
>  	dprintk(KERN_WARNING "3w-xxxx: tw_aen_complete()\n");
>  	if (tw_dev->alignment_virtual_address[request_id] == NULL) {
> @@ -184,12 +212,15 @@
>  			if ((tw_aen_string[aen & 0xff][strlen(tw_aen_string[aen & 0xff])-1]) == '#') {
>  				printk(KERN_WARNING "3w-xxxx: scsi%d: AEN: %s%d.\n", tw_dev->host->host_no, tw_aen_string[aen & 0xff], aen >> 8);
>  			} else {
> -				printk(KERN_WARNING "3w-xxxx: scsi%d: AEN: %s.\n", tw_dev->host->host_no, tw_aen_string[aen & 0xff]);
> +				if (aen != 0x0)
> +					printk(KERN_WARNING "3w-xxxx: scsi%d: AEN: %s.\n", tw_dev->host->host_no, tw_aen_string[aen & 0xff]);
>  			}
> -		} else
> +		} else {
>  			printk(KERN_WARNING "3w-xxxx: scsi%d: Received AEN %d.\n", tw_dev->host->host_no, aen);
> +		}
>  	}
> -	tw_dev->aen_count++;
> +	if (aen != 0x0)
> +		tw_dev->aen_count++;
> 
>  	/* Now queue the code */
>  	tw_dev->aen_queue[tw_dev->aen_tail] = aen;
> @@ -205,8 +236,18 @@
>  			tw_dev->aen_head = tw_dev->aen_head + 1;
>  		}
>  	}
> -	tw_dev->state[request_id] = TW_S_COMPLETED;
> -	tw_state_request_finish(tw_dev, request_id);
> +
> +	if (aen != TW_AEN_QUEUE_EMPTY) {
> +		error = tw_aen_read_queue(tw_dev, request_id);
> +		if (error) {
> +			printk(KERN_WARNING "3w-xxxx: scsi%d: Error completing AEN.\n", tw_dev->host->host_no);
> +			tw_dev->state[request_id] = TW_S_COMPLETED;
> +			tw_state_request_finish(tw_dev, request_id);
> +		}
> +	} else {
> +		tw_dev->state[request_id] = TW_S_COMPLETED;
> +		tw_state_request_finish(tw_dev, request_id);
> +	}
> 
>  	return 0;
>  } /* End tw_aen_complete() */
> @@ -237,10 +278,11 @@
>  	status_reg_addr = tw_dev->registers.status_reg_addr;
>  	response_que_addr = tw_dev->registers.response_que_addr;
> 
> -	if (tw_poll_status(tw_dev, TW_STATUS_ATTENTION_INTERRUPT, 15)) {
> +	if (tw_poll_status(tw_dev, TW_STATUS_ATTENTION_INTERRUPT, 30)) {
>  		dprintk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): No attention interrupt for card %d.\n", tw_device_extension_count);
>  		return 1;
>  	}
> +	tw_clear_attention_interrupt(tw_dev);
> 
>  	/* Initialize command packet */
>  	if (tw_dev->command_packet_virtual_address[request_id] == NULL) {
> @@ -288,7 +330,7 @@
>  	do {
>  		/* Post command packet */
>  		outl(command_que_value, command_que_addr);
> -
> +
>  		/* Now poll for completion */
>  		for (i=0;i<imax;i++) {
>  			mdelay(5);
> @@ -311,8 +353,7 @@
>  				if (command_packet->status != 0) {
>  					if (command_packet->flags != TW_AEN_TABLE_UNDEFINED) {
>  						/* Bad response */
> -						dprintk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): Bad response, status = 0x%x, flags = 0x%x.\n", command_packet->status, command_packet->flags);
> -						tw_decode_error(tw_dev, command_packet->status, command_packet->flags, command_packet->byte3.unit);
> +						tw_decode_sense(tw_dev, request_id, 0);
>  						return 1;
>  					} else {
>  						/* We know this is a 3w-1x00, and doesn't support aen's */
> @@ -326,7 +367,7 @@
>  				queue = 0;
>  				switch (aen_code) {
>  					case TW_AEN_QUEUE_EMPTY:
> -						dprintk(KERN_NOTICE "3w-xxxx: tw_aen_drain_queue(): Found TW_AEN_QUEUE_EMPTY.\n");
> +						dprintk(KERN_WARNING "3w-xxxx: AEN: %s.\n", tw_aen_string[aen & 0xff]);
>  						if (first_reset != 1) {
>  							continue;
>  						} else {
> @@ -334,51 +375,28 @@
>  						}
>  						break;
>  					case TW_AEN_SOFT_RESET:
> -						dprintk(KERN_NOTICE "3w-xxxx: tw_aen_drain_queue(): Found TW_AEN_SOFT_RESET.\n");
>  						if (first_reset == 0) {
>  							first_reset = 1;
>  						} else {
> +							printk(KERN_WARNING "3w-xxxx: AEN: %s.\n", tw_aen_string[aen & 0xff]);
> +							tw_dev->aen_count++;
>  							queue = 1;
>  						}
>  						break;
> -					case TW_AEN_DEGRADED_MIRROR:
> -						dprintk(KERN_NOTICE "3w-xxxx: tw_aen_drain_queue(): Found TW_AEN_DEGRADED_MIRROR.\n");
> -						queue = 1;
> -						break;
> -					case TW_AEN_CONTROLLER_ERROR:
> -						dprintk(KERN_NOTICE "3w-xxxx: tw_aen_drain_queue(): Found TW_AEN_CONTROLLER_ERROR.\n");
> -						queue = 1;
> -						break;
> -					case TW_AEN_REBUILD_FAIL:
> -						dprintk(KERN_NOTICE "3w-xxxx: tw_aen_drain_queue(): Found TW_AEN_REBUILD_FAIL.\n");
> -						queue = 1;
> -						break;
> -					case TW_AEN_REBUILD_DONE:
> -						dprintk(KERN_NOTICE "3w-xxxx: tw_aen_drain_queue(): Found TW_AEN_REBUILD_DONE.\n");
> -						queue = 1;
> -						break;
> -					case TW_AEN_QUEUE_FULL:
> -						dprintk(KERN_NOTICE "3w-xxxx: tw_aen_drain_queue(): Found TW_AEN_QUEUE_FULL.\n");
> -						queue = 1;
> -						break;
> -					case TW_AEN_APORT_TIMEOUT:
> -						printk(KERN_WARNING "3w-xxxx: Received drive timeout AEN on port %d, check drive and drive cables.\n", aen >> 8);
> -						queue = 1;
> -						break;
> -					case TW_AEN_DRIVE_ERROR:
> -						printk(KERN_WARNING "3w-xxxx: Received drive error AEN on port %d, check/replace cabling, or possible bad drive.\n", aen >> 8);
> -						queue = 1;
> -						break;
> -					case TW_AEN_SMART_FAIL:
> -						printk(KERN_WARNING "3w-xxxx: Received S.M.A.R.T. threshold AEN on port %d, check drive/cooling, or possible bad drive.\n", aen >> 8);
> -						queue = 1;
> -						break;
> -					case TW_AEN_SBUF_FAIL:
> -						printk(KERN_WARNING "3w-xxxx: Received SBUF integrity check failure AEN, reseat card or bad card.\n");
> -						queue = 1;
> -						break;
>  					default:
> -						dprintk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): Unknown AEN code 0x%x.\n", aen_code);
> +						if (aen == 0x0ff) {
> +							printk(KERN_WARNING "3w-xxxx: AEN: AEN queue overflow.\n");
> +						} else {
> +							if ((aen & 0x0ff) < TW_AEN_STRING_MAX) {
> +								if ((tw_aen_string[aen & 0xff][strlen(tw_aen_string[aen & 0xff])-1]) == '#') {
> +									printk(KERN_WARNING "3w-xxxx: AEN: %s%d.\n", tw_aen_string[aen & 0xff], aen >> 8);
> +								} else {
> +									printk(KERN_WARNING "3w-xxxx: AEN: %s.\n", tw_aen_string[aen & 0xff]);
> +								}
> +							} else
> +								printk(KERN_WARNING "3w-xxxx: Received AEN %d.\n", aen);
> +						}
> +						tw_dev->aen_count++;
>  						queue = 1;
>  				}
> 
> @@ -488,40 +506,44 @@
>  	return 0;
>  } /* End tw_aen_read_queue() */
> 
> -/* This function will allocate memory and check if it is 16 d-word aligned */
> -int tw_allocate_memory(TW_Device_Extension *tw_dev, int request_id, int size, int which)
> +/* This function will allocate memory */
> +int tw_allocate_memory(TW_Device_Extension *tw_dev, int size, int which)
>  {
> -	u32 *virt_addr = kmalloc(size, GFP_ATOMIC);
> +	int i;
> +	dma_addr_t dma_handle;
> +	u32 *cpu_addr = NULL;
> 
>  	dprintk(KERN_NOTICE "3w-xxxx: tw_allocate_memory()\n");
> 
> -	if (!virt_addr) {
> -		printk(KERN_WARNING "3w-xxxx: tw_allocate_memory(): kmalloc() failed.\n");
> -		return 1;
> -	}
> +	for (i=0;i<TW_Q_LENGTH;i++) {
> +		cpu_addr = pci_alloc_consistent(tw_dev->tw_pci_dev, size, &dma_handle);
> +		if (cpu_addr == NULL) {
> +			printk(KERN_WARNING "3w-xxxx: pci_alloc_consistent() failed.\n");
> +			return 1;
> +		}
> 
> -	if ((u32)virt_addr % TW_ALIGNMENT) {
> -		kfree(virt_addr);
> -		printk(KERN_WARNING "3w-xxxx: tw_allocate_memory(): Found unaligned address.\n");
> -		return 1;
> -	}
> +		if ((u32)cpu_addr % (tw_dev->tw_pci_dev->device == TW_DEVICE_ID ? TW_ALIGNMENT_6000 : TW_ALIGNMENT_7000)) {
> +			printk(KERN_WARNING "3w-xxxx: Couldn't allocate correctly aligned memory.\n");
> +			return 1;
> +		}
> 
> -	switch(which) {
> -	case 0:
> -		tw_dev->command_packet_virtual_address[request_id] = virt_addr;
> -		tw_dev->command_packet_physical_address[request_id] = virt_to_bus(virt_addr);
> -		break;
> -	case 1:
> -		tw_dev->alignment_virtual_address[request_id] = virt_addr;
> -		tw_dev->alignment_physical_address[request_id] = virt_to_bus(virt_addr);
> -		break;
> -	case 2:
> -		tw_dev->bounce_buffer[request_id] = virt_addr;
> -		break;
> -	default:
> -		printk(KERN_WARNING "3w-xxxx: tw_allocate_memory(): case slip in tw_allocate_memory()\n");
> -		return 1;
> +		switch(which) {
> +		case 0:
> +			tw_dev->command_packet_virtual_address[i] = cpu_addr;
> +			tw_dev->command_packet_physical_address[i] = dma_handle;
> +			memset(tw_dev->command_packet_virtual_address[i], 0, size);
> +			break;
> +		case 1:
> +			tw_dev->alignment_virtual_address[i] = cpu_addr;
> +			tw_dev->alignment_physical_address[i] = dma_handle;
> +			memset(tw_dev->alignment_virtual_address[i], 0, size);
> +			break;
> +		default:
> +			printk(KERN_WARNING "3w-xxxx: tw_allocate_memory(): case slip in tw_allocate_memory()\n");
> +			return 1;
> +		}
>  	}
> +
>  	return 0;
>  } /* End tw_allocate_memory() */
> 
> @@ -548,8 +570,10 @@
>  	status_reg_addr = tw_dev->registers.status_reg_addr;
>  	status_reg_value = inl(status_reg_addr);
> 
> -	if (TW_STATUS_ERRORS(status_reg_value) || tw_check_bits(status_reg_value))
> +	if (TW_STATUS_ERRORS(status_reg_value) || tw_check_bits(status_reg_value)) {
> +		tw_decode_bits(tw_dev, status_reg_value);
>  		return 1;
> +	}
> 
>  	return 0;
>  } /* End tw_check_errors() */
> @@ -614,37 +638,62 @@
>  	dprintk(KERN_WARNING "3w-xxxx: tw_decode_bits()\n");
>  	switch (status_reg_value & TW_STATUS_UNEXPECTED_BITS) {
>  	case TW_STATUS_PCI_PARITY_ERROR:
> -		printk(KERN_WARNING "3w-xxxx: PCI Parity Error: Reseat card, move card, or buggy device on the bus.\n");
> +		printk(KERN_WARNING "3w-xxxx: PCI Parity Error: clearing.\n");
>  		outl(TW_CONTROL_CLEAR_PARITY_ERROR, tw_dev->registers.control_reg_addr);
> -		pci_write_config_word(tw_dev->tw_pci_dev, PCI_STATUS, TW_PCI_CLEAR_PARITY_ERRORS);
>  		break;
>  	case TW_STATUS_MICROCONTROLLER_ERROR:
>  		printk(KERN_WARNING "3w-xxxx: Microcontroller Error.\n");
>  		break;
> +	case TW_STATUS_PCI_ABORT:
> +		printk(KERN_WARNING "3w-xxxx: PCI Abort: clearing.\n");
> +		outl(TW_CONTROL_CLEAR_PCI_ABORT, tw_dev->registers.control_reg_addr);
> +		pci_write_config_word(tw_dev->tw_pci_dev, PCI_STATUS, TW_PCI_CLEAR_PCI_ABORT);
> +		break;
>    }
>  } /* End tw_decode_bits() */
> 
> -/* This function will print readable messages from flags and status values */
> -void tw_decode_error(TW_Device_Extension *tw_dev, unsigned char status, unsigned char flags, unsigned char unit)
> +/* This function will return valid sense buffer information for failed cmds */
> +void tw_decode_sense(TW_Device_Extension *tw_dev, int request_id, int fill_sense)
>  {
> -	dprintk(KERN_WARNING "3w-xxxx: tw_decode_error()\n");
> -	switch (status) {
> -	case 0xc7:
> -		switch (flags) {
> -		case 0x1b:
> -			printk(KERN_WARNING "3w-xxxx: scsi%d: Drive timeout on unit %d, check drive and drive cables.\n", tw_dev->host->host_no, unit);
> -			break;
> -		case 0x51:
> -			printk(KERN_WARNING "3w-xxxx: scsi%d: Unrecoverable drive error on unit %d, check/replace cabling, or possible bad drive.\n", tw_dev->host->host_no, unit);
> -			break;
> -		default:
> -			printk(KERN_WARNING "3w-xxxx: scsi%d: Controller error: status = 0x%x, flags = 0x%x, unit #%d.\n", tw_dev->host->host_no, status, flags, unit);
> +	int i, found=0;
> +	TW_Command *command;
> +
> +        dprintk(KERN_WARNING "3w-xxxx: tw_decode_sense()\n");
> +	command = (TW_Command *)tw_dev->command_packet_virtual_address[request_id];
> +
> +	printk(KERN_WARNING "3w-xxxx: scsi%d: Command failed: status = 0x%x, flags = 0x%x, unit #%d.\n", tw_dev->host->host_no, command->status, command->flags, command->byte3.unit);
> +
> +	/* Attempt to return intelligent sense information */
> +	if (fill_sense) {
> +		if ((command->status == 0xc7) || (command->status == 0xcb)) {
> +			for (i=0;i<(sizeof(tw_sense_table)/sizeof(tw_sense_table[0]));i++) {
> +				if (command->flags == tw_sense_table[i][0]) {
> +					found=1;
> +
> +					/* Valid bit and 'current errors' */
> +					tw_dev->srb[request_id]->sense_buffer[0] = (0x1 << 7 | 0x70);
> +
> +					/* Sense key */
> +					tw_dev->srb[request_id]->sense_buffer[2] = tw_sense_table[i][1];
> +
> +					/* Additional sense length */
> +					tw_dev->srb[request_id]->sense_buffer[7] = 0xa; /* 10 bytes */
> +
> +					/* Additional sense code */
> +					tw_dev->srb[request_id]->sense_buffer[12] = tw_sense_table[i][2];
> +
> +					/* Additional sense code qualifier */
> +					tw_dev->srb[request_id]->sense_buffer[13] = tw_sense_table[i][3];
> +
> +					tw_dev->srb[request_id]->result = (DID_OK << 16) | (CHECK_CONDITION << 1);
> +				}
> +			}
>  		}
> -		break;
> -	default:
> -		printk(KERN_WARNING "3w-xxxx: scsi%d: Controller error: status = 0x%x, flags = 0x%x, unit #%d.\n", tw_dev->host->host_no, status, flags, unit);
> +		/* If no table match, error so we get a reset */
> +		if (found == 0)
> +			tw_dev->srb[request_id]->result = (DID_RESET << 16);
>  	}
> -} /* End tw_decode_error() */
> +} /* End tw_decode_sense() */
> 
>  /* This function will disable interrupts on the controller */
>  void tw_disable_interrupts(TW_Device_Extension *tw_dev)
> @@ -691,11 +740,22 @@
>  	u32 control_reg_value, control_reg_addr;
> 
>  	control_reg_addr = tw_dev->registers.control_reg_addr;
> +	control_reg_value = (TW_CONTROL_ENABLE_INTERRUPTS |
> +			     TW_CONTROL_UNMASK_RESPONSE_INTERRUPT);
> +	outl(control_reg_value, control_reg_addr);
> +} /* End tw_enable_interrupts() */
> +
> +/* This function will enable interrupts on the controller */
> +void tw_enable_and_clear_interrupts(TW_Device_Extension *tw_dev)
> +{
> +	u32 control_reg_value, control_reg_addr;
> +
> +	control_reg_addr = tw_dev->registers.control_reg_addr;
>  	control_reg_value = (TW_CONTROL_CLEAR_ATTENTION_INTERRUPT |
>  			     TW_CONTROL_UNMASK_RESPONSE_INTERRUPT |
>  			     TW_CONTROL_ENABLE_INTERRUPTS);
>  	outl(control_reg_value, control_reg_addr);
> -} /* End tw_enable_interrupts() */
> +} /* End tw_enable_and_clear_interrupts() */
> 
>  /* This function will find and initialize all cards */
>  int tw_findcards(Scsi_Host_Template *tw_host)
> @@ -716,6 +776,13 @@
>  		while ((tw_pci_dev = pci_find_device(TW_VENDOR_ID, device[i], tw_pci_dev))) {
>  			if (pci_enable_device(tw_pci_dev))
>  				continue;
> +
> +			/* We only need 32-bit addressing for 5,6,7xxx cards */
> +			if (pci_set_dma_mask(tw_pci_dev, 0xffffffff)) {
> +				printk(KERN_WARNING "3w-xxxx: No suitable DMA available.\n");
> +				continue;
> +			}
> +
>  			/* Prepare temporary device extension */
>  			tw_dev=(TW_Device_Extension *)kmalloc(sizeof(TW_Device_Extension), GFP_ATOMIC);
>  			if (tw_dev == NULL) {
> @@ -724,6 +791,9 @@
>  			}
>  			memset(tw_dev, 0, sizeof(TW_Device_Extension));
> 
> +			/* Save pci_dev struct to device extension */
> +			tw_dev->tw_pci_dev = tw_pci_dev;
> +
>  			error = tw_initialize_device_extension(tw_dev);
>  			if (error) {
>  				printk(KERN_WARNING "3w-xxxx: tw_findcards(): Couldn't initialize device extension for card %d.\n", numcards);
> @@ -738,8 +808,6 @@
>  			tw_dev->registers.status_reg_addr = pci_resource_start(tw_pci_dev, 0) + 0x4;
>  			tw_dev->registers.command_que_addr = pci_resource_start(tw_pci_dev, 0) + 0x8;
>  			tw_dev->registers.response_que_addr = pci_resource_start(tw_pci_dev, 0) + 0xC;
> -			/* Save pci_dev struct to device extension */
> -			tw_dev->tw_pci_dev = tw_pci_dev;
> 
>  			/* Check for errors and clear them */
>  			status_reg_value = inl(tw_dev->registers.status_reg_addr);
> @@ -763,14 +831,14 @@
> 
>  				error = tw_aen_drain_queue(tw_dev);
>  				if (error) {
> -					printk(KERN_WARNING "3w-xxxx: tw_findcards(): No attention interrupt for card %d.\n", numcards);
> +					printk(KERN_WARNING "3w-xxxx: AEN drain failed for card %d.\n", numcards);
>  					tries++;
>  					continue;
>  				}
> 
>  				/* Check for controller errors */
>  				if (tw_check_errors(tw_dev)) {
> -					printk(KERN_WARNING "3w-xxxx: tw_findcards(): Controller errors found, soft resetting card %d.\n", numcards);
> +					printk(KERN_WARNING "3w-xxxx: Controller errors found, retrying for card %d.\n", numcards);
>  					tries++;
>  					continue;
>  				}
> @@ -778,7 +846,7 @@
>  				/* Empty the response queue */
>  				error = tw_empty_response_que(tw_dev);
>  				if (error) {
> -					printk(KERN_WARNING "3w-xxxx: tw_findcards(): Couldn't empty response queue for card %d.\n", numcards);
> +					printk(KERN_WARNING "3w-xxxx: Couldn't empty response queue, retrying for card %d.\n", numcards);
>  					tries++;
>  					continue;
>  				}
> @@ -788,7 +856,7 @@
>  			}
> 
>  			if (tries >= TW_MAX_RESET_TRIES) {
> -				printk(KERN_WARNING "3w-xxxx: tw_findcards(): Controller error or no attention interrupt: giving up for card %d.\n", numcards);
> +				printk(KERN_WARNING "3w-xxxx: Controller errors, card not responding, check all cabling for card %d.\n", numcards);
>  				tw_free_device_extension(tw_dev);
>  				kfree(tw_dev);
>  				continue;
> @@ -818,7 +886,7 @@
> 
>  			error = tw_initconnection(tw_dev, TW_INIT_MESSAGE_CREDITS);
>  			if (error) {
> -				printk(KERN_WARNING "3w-xxxx: tw_findcards(): Couldn't initconnection for card %d.\n", numcards);
> +				printk(KERN_WARNING "3w-xxxx: Connection initialization failed for card %d.\n", numcards);
>  				release_region((tw_dev->tw_pci_dev->resource[0].start), TW_IO_ADDRESS_RANGE);
>  				tw_free_device_extension(tw_dev);
>  				kfree(tw_dev);
> @@ -827,29 +895,28 @@
> 
>  			/* Calculate max cmds per lun, and setup queues */
>  			if (tw_dev->num_units > 0) {
> -				if ((tw_dev->num_raid_five > 0) && (tw_dev->tw_pci_dev->device == TW_DEVICE_ID)) {
> -					tw_host->cmd_per_lun = (TW_MAX_BOUNCEBUF-1)/tw_dev->num_units;
> -					tw_dev->free_head = TW_Q_START;
> -					tw_dev->free_tail = TW_MAX_BOUNCEBUF - 1;
> -					tw_dev->free_wrap = TW_MAX_BOUNCEBUF - 1;
> -				} else {
> -					tw_host->cmd_per_lun = (TW_Q_LENGTH-1)/tw_dev->num_units;
> -					tw_dev->free_head = TW_Q_START;
> -					tw_dev->free_tail = TW_Q_LENGTH - 1;
> -					tw_dev->free_wrap = TW_Q_LENGTH - 1;
> -				}
> +				tw_host->cmd_per_lun = (TW_Q_LENGTH-1)/tw_dev->num_units;
> +				tw_dev->free_head = TW_Q_START;
> +				tw_dev->free_tail = TW_Q_LENGTH - 1;
> +				tw_dev->free_wrap = TW_Q_LENGTH - 1;
>  			}
> 
> -		/* Register the card with the kernel SCSI layer */
> +			/* Register the card with the kernel SCSI layer */
>  			host = scsi_register(tw_host, sizeof(TW_Device_Extension));
>  			if (host == NULL) {
> -				printk(KERN_WARNING "3w-xxxx: tw_findcards(): scsi_register() failed for card %d.\n", numcards-1);
> +				printk(KERN_WARNING "3w-xxxx: tw_findcards(): scsi_register() failed for card %d.\n", numcards);
>  				release_region((tw_dev->tw_pci_dev->resource[0].start), TW_IO_ADDRESS_RANGE);
>  				tw_free_device_extension(tw_dev);
>  				kfree(tw_dev);
>  				continue;
>  			}
> 
> +			/* Set max target id's */
> +			host->max_id = TW_MAX_UNITS;
> +
> +			/* Set max cdb size in bytes */
> +			host->max_cmd_len = 16;
> +
>  			/* Set max sectors per io */
>  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,7)
>  			host->max_sectors = TW_MAX_SECTORS;
> @@ -874,7 +941,7 @@
>  				tw_device_extension_count = numcards;
>  				tw_dev2->host = host;
>  			} else {
> -				printk(KERN_WARNING "3w-xxxx: tw_findcards(): Bad scsi host data for card %d.\n", numcards-1);
> +				printk(KERN_WARNING "3w-xxxx: tw_findcards(): Bad scsi host data for card %d.\n", numcards);
>  				scsi_unregister(host);
>  				release_region((tw_dev->tw_pci_dev->resource[0].start), TW_IO_ADDRESS_RANGE);
>  				tw_free_device_extension(tw_dev);
> @@ -924,15 +991,10 @@
>  	/* Free command packet and generic buffer memory */
>  	for (i=0;i<TW_Q_LENGTH;i++) {
>  		if (tw_dev->command_packet_virtual_address[i])
> -			kfree(tw_dev->command_packet_virtual_address[i]);
> +			pci_free_consistent(tw_dev->tw_pci_dev, sizeof(TW_Sector), tw_dev->command_packet_virtual_address[i], tw_dev->command_packet_physical_address[i]);
> 
>  		if (tw_dev->alignment_virtual_address[i])
> -			kfree(tw_dev->alignment_virtual_address[i]);
> -
> -	}
> -	for (i=0;i<TW_MAX_BOUNCEBUF;i++) {
> -		if (tw_dev->bounce_buffer[i])
> -			kfree(tw_dev->bounce_buffer[i]);
> +			pci_free_consistent(tw_dev->tw_pci_dev, sizeof(TW_Sector), tw_dev->alignment_virtual_address[i], tw_dev->alignment_physical_address[i]);
>  	}
>  } /* End tw_free_device_extension() */
> 
> @@ -1015,8 +1077,7 @@
>  			}
>  			if (command_packet->status != 0) {
>  				/* bad response */
> -				dprintk(KERN_WARNING "3w-xxxx: tw_initconnection(): Bad response, status = 0x%x, flags = 0x%x.\n", command_packet->status, command_packet->flags);
> -				tw_decode_error(tw_dev, command_packet->status, command_packet->flags, command_packet->byte3.unit);
> +				tw_decode_sense(tw_dev, request_id, 0);
>  				return 1;
>  			}
>  			break;	/* Response was okay, so we exit */
> @@ -1028,57 +1089,33 @@
>  /* This function will initialize the fields of a device extension */
>  int tw_initialize_device_extension(TW_Device_Extension *tw_dev)
>  {
> -	int i, imax;
> +	int i, error=0;
> 
>  	dprintk(KERN_NOTICE "3w-xxxx: tw_initialize_device_extension()\n");
> -	imax = TW_Q_LENGTH;
> 
> -	for (i=0; i<imax; i++) {
> -		/* Initialize command packet buffers */
> -		tw_allocate_memory(tw_dev, i, sizeof(TW_Sector), 0);
> -		if (tw_dev->command_packet_virtual_address[i] == NULL) {
> -			printk(KERN_WARNING "3w-xxxx: tw_initialize_device_extension(): Bad command packet virtual address.\n");
> -			return 1;
> -		}
> -		memset(tw_dev->command_packet_virtual_address[i], 0, sizeof(TW_Sector));
> -
> -		/* Initialize generic buffer */
> -		tw_allocate_memory(tw_dev, i, sizeof(TW_Sector), 1);
> -		if (tw_dev->alignment_virtual_address[i] == NULL) {
> -			printk(KERN_WARNING "3w-xxxx: tw_initialize_device_extension(): Bad alignment virtual address.\n");
> -			return 1;
> -		}
> -		memset(tw_dev->alignment_virtual_address[i], 0, sizeof(TW_Sector));
> +	/* Initialize command packet buffers */
> +	error = tw_allocate_memory(tw_dev, sizeof(TW_Command), 0);
> +	if (error) {
> +		printk(KERN_WARNING "3w-xxxx: Command packet memory allocation failed.\n");
> +		return 1;
> +	}
> 
> -		tw_dev->free_queue[i] = i;
> -		tw_dev->state[i] = TW_S_INITIAL;
> -		tw_dev->ioctl_size[i] = 0;
> -		tw_dev->aen_queue[i] = 0;
> +	/* Initialize generic buffer */
> +	error = tw_allocate_memory(tw_dev, sizeof(TW_Sector), 1);
> +	if (error) {
> +		printk(KERN_WARNING "3w-xxxx: Generic memory allocation failed.\n");
> +		return 1;
>  	}
> 
> -	for (i=0;i<TW_MAX_UNITS;i++) {
> -		tw_dev->is_unit_present[i] = 0;
> -		tw_dev->is_raid_five[i] = 0;
> +	for (i=0;i<TW_Q_LENGTH;i++) {
> +		tw_dev->free_queue[i] = i;
> +		tw_dev->state[i] = TW_S_INITIAL;
>  	}
> 
> -	tw_dev->num_units = 0;
> -	tw_dev->num_aborts = 0;
> -	tw_dev->num_resets = 0;
> -	tw_dev->posted_request_count = 0;
> -	tw_dev->max_posted_request_count = 0;
> -	tw_dev->max_sgl_entries = 0;
> -	tw_dev->sgl_entries = 0;
> -	tw_dev->host = NULL;
>  	tw_dev->pending_head = TW_Q_START;
>  	tw_dev->pending_tail = TW_Q_START;
> -	tw_dev->aen_head = 0;
> -	tw_dev->aen_tail = 0;
> -	tw_dev->sector_count = 0;
> -	tw_dev->max_sector_count = 0;
> -	tw_dev->aen_count = 0;
> -	tw_dev->num_raid_five = 0;
>  	spin_lock_init(&tw_dev->tw_lock);
> -	tw_dev->flags = 0;
> +
>  	return 0;
>  } /* End tw_initialize_device_extension() */
> 
> @@ -1089,14 +1126,13 @@
>  	unsigned char request_id = 0;
>  	TW_Command *command_packet;
>  	TW_Param *param;
> -	int i, j, imax, num_units = 0, num_raid_five = 0;
> +	int i, imax, num_units = 0;
>  	u32 status_reg_addr, status_reg_value;
>  	u32 command_que_addr, command_que_value;
>  	u32 response_que_addr;
>  	TW_Response_Queue response_queue;
>  	u32 param_value;
>  	unsigned char *is_unit_present;
> -	unsigned char *raid_level;
> 
>  	dprintk(KERN_NOTICE "3w-xxxx: tw_initialize_units()\n");
> 
> @@ -1168,8 +1204,7 @@
>  			}
>  			if (command_packet->status != 0) {
>  				/* bad response */
> -				dprintk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Bad response, status = 0x%x, flags = 0x%x.\n", command_packet->status, command_packet->flags);
> -				tw_decode_error(tw_dev, command_packet->status, command_packet->flags, command_packet->byte3.unit);
> +				tw_decode_sense(tw_dev, request_id, 0);
>  				return 1;
>  			}
>  			found = 1;
> @@ -1205,109 +1240,6 @@
>  		return 1;
>  	}
> 
> -	/* Find raid 5 arrays */
> -	for (j=0;j<TW_MAX_UNITS;j++) {
> -		if (tw_dev->is_unit_present[j] == 0)
> -			continue;
> -		command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id];
> -		if (command_packet == NULL) {
> -			printk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Bad command packet virtual address.\n");
> -			return 1;
> -		}
> -		memset(command_packet, 0, sizeof(TW_Sector));
> -		command_packet->byte0.opcode      = TW_OP_GET_PARAM;
> -		command_packet->byte0.sgl_offset  = 2;
> -		command_packet->size              = 4;
> -		command_packet->request_id        = request_id;
> -		command_packet->byte3.unit        = 0;
> -		command_packet->byte3.host_id     = 0;
> -		command_packet->status            = 0;
> -		command_packet->flags             = 0;
> -		command_packet->byte6.block_count = 1;
> -
> -		/* Now setup the param */
> -		if (tw_dev->alignment_virtual_address[request_id] == NULL) {
> -			printk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Bad alignment virtual address.\n");
> -			return 1;
> -		}
> -		param = (TW_Param *)tw_dev->alignment_virtual_address[request_id];
> -		memset(param, 0, sizeof(TW_Sector));
> -		param->table_id = 0x300+j; /* unit summary table */
> -		param->parameter_id = 0x6; /* unit descriptor */
> -		param->parameter_size_bytes = 0xc;
> -		param_value = tw_dev->alignment_physical_address[request_id];
> -		if (param_value == 0) {
> -			printk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Bad alignment physical address.\n");
> -			return 1;
> -		}
> -
> -		command_packet->byte8.param.sgl[0].address = param_value;
> -		command_packet->byte8.param.sgl[0].length = sizeof(TW_Sector);
> -
> -		/* Post the command packet to the board */
> -		command_que_value = tw_dev->command_packet_physical_address[request_id];
> -		if (command_que_value == 0) {
> -			printk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Bad command packet physical address.\n");
> -			return 1;
> -		}
> -		outl(command_que_value, command_que_addr);
> -
> -		/* Poll for completion */
> -		imax = TW_POLL_MAX_RETRIES;
> -		for(i=0; i<imax; i++) {
> -			mdelay(5);
> -			status_reg_value = inl(status_reg_addr);
> -			if (tw_check_bits(status_reg_value)) {
> -				dprintk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Unexpected bits.\n");
> -				tw_decode_bits(tw_dev, status_reg_value);
> -				return 1;
> -			}
> -			if ((status_reg_value & TW_STATUS_RESPONSE_QUEUE_EMPTY) == 0) {
> -				response_queue.value = inl(response_que_addr);
> -				request_id = (unsigned char)response_queue.u.response_id;
> -				if (request_id != 0) {
> -					/* unexpected request id */
> -					printk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Unexpected request id.\n");
> -					return 1;
> -				}
> -				if (command_packet->status != 0) {
> -					/* bad response */
> -					dprintk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Bad response, status = 0x%x, flags = 0x%x.\n", command_packet->status, command_packet->flags);
> -					tw_decode_error(tw_dev, command_packet->status, command_packet->flags, command_packet->byte3.unit);
> -					return 1;
> -				}
> -				found = 1;
> -				break;
> -			}
> -		}
> -		if (found == 0) {
> -			/* response never received */
> -			printk(KERN_WARNING "3w-xxxx: tw_initialize_units(): No response.\n");
> -			return 1;
> -		}
> -
> -		param = (TW_Param *)tw_dev->alignment_virtual_address[request_id];
> -		raid_level = (unsigned char *)&(param->data[1]);
> -		if (*raid_level == 5) {
> -			dprintk(KERN_WARNING "3w-xxxx: Found unit %d to be a raid5 unit.\n", j);
> -			tw_dev->is_raid_five[j] = 1;
> -			num_raid_five++;
> -		}
> -	}
> -	tw_dev->num_raid_five = num_raid_five;
> -
> -	/* Now allocate raid5 bounce buffers */
> -	if ((num_raid_five != 0) && (tw_dev->tw_pci_dev->device == TW_DEVICE_ID)) {
> -		for (i=0;i<TW_MAX_BOUNCEBUF;i++) {
> -			tw_allocate_memory(tw_dev, i, sizeof(TW_Sector)*TW_MAX_SECTORS, 2);
> -			if (tw_dev->bounce_buffer[i] == NULL) {
> -				printk(KERN_WARNING "3w-xxxx: Bounce buffer allocation failed.\n");
> -				return 1;
> -			}
> -			memset(tw_dev->bounce_buffer[i], 0, sizeof(TW_Sector)*TW_MAX_SECTORS);
> -		}
> -	}
> -
>  	return 0;
>  } /* End tw_initialize_units() */
> 
> @@ -1332,13 +1264,18 @@
> 
>  	if (tw_dev->tw_pci_dev->irq == irq) {
>  		spin_lock(&tw_dev->tw_lock);
> -		dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt()\n");
> +		dprintk(KERN_WARNING "3w-xxxx: tw_interrupt()\n");
> 
>  		/* Read the registers */
>  		status_reg_addr = tw_dev->registers.status_reg_addr;
>  		response_que_addr = tw_dev->registers.response_que_addr;
>  		status_reg_value = inl(status_reg_addr);
> 
> +		if (tw_check_bits(status_reg_value)) {
> +			dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Unexpected bits.\n");
> +			tw_decode_bits(tw_dev, status_reg_value);
> +		}
> +
>  		/* Check which interrupt */
>  		if (status_reg_value & TW_STATUS_HOST_INTERRUPT)
>  			do_host_interrupt=1;
> @@ -1403,17 +1340,18 @@
>  				command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id];
>  				error = 0;
>  				if (command_packet->status != 0) {
> -					dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Bad response, status = 0x%x, flags = 0x%x, unit = 0x%x.\n", command_packet->status, command_packet->flags, command_packet->byte3.unit);
> -					tw_decode_error(tw_dev, command_packet->status, command_packet->flags, command_packet->byte3.unit);
> -					error = 1;
> +					/* Bad response */
> +					if (tw_dev->srb[request_id] != 0)
> +						tw_decode_sense(tw_dev, request_id, 1);
> +					error = 3;
>  				}
>  				if (tw_dev->state[request_id] != TW_S_POSTED) {
>  					printk(KERN_WARNING "3w-xxxx: scsi%d: Received a request id (%d) (opcode = 0x%x) that wasn't posted.\n", tw_dev->host->host_no, request_id, command_packet->byte0.opcode);
>  					error = 1;
>  				}
>  				if (TW_STATUS_ERRORS(status_reg_value)) {
> -				  tw_decode_bits(tw_dev, status_reg_value);
> -				  error = 1;
> +					tw_decode_bits(tw_dev, status_reg_value);
> +					error = 1;
>  				}
>  				dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): Response queue request id: %d.\n", request_id);
>  				/* Check for internal command */
> @@ -1428,7 +1366,7 @@
>  						dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Unexpected bits.\n");
>  						tw_decode_bits(tw_dev, status_reg_value);
>  					}
> -		} else {
> +				} else {
>  				switch (tw_dev->srb[request_id]->cmnd[0]) {
>  					case READ_10:
>  					case READ_6:
> @@ -1455,18 +1393,23 @@
>  						tw_dev->srb[request_id]->result = (DID_BAD_TARGET << 16);
>  						tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]);
>  					}
> -					if (error) {
> +					if (error == 1) {
>  						/* Tell scsi layer there was an error */
>  						dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Scsi Error.\n");
>  						tw_dev->srb[request_id]->result = (DID_RESET << 16);
> -					} else {
> +					}
> +					if (error == 0) {
>  						/* Tell scsi layer command was a success */
>  						tw_dev->srb[request_id]->result = (DID_OK << 16);
>  					}
> -					tw_dev->state[request_id] = TW_S_COMPLETED;
> -					tw_state_request_finish(tw_dev, request_id);
> -					tw_dev->posted_request_count--;
> -					tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]);
> +					if (error != 2) {
> +						tw_dev->state[request_id] = TW_S_COMPLETED;
> +						tw_state_request_finish(tw_dev, request_id);
> +						tw_dev->posted_request_count--;
> +						tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]);
> +
> +						tw_unmap_scsi_data(tw_dev->tw_pci_dev, tw_dev->srb[request_id]);
> +					}
>  					status_reg_value = inl(status_reg_addr);
>  					if (tw_check_bits(status_reg_value)) {
>  						dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Unexpected bits.\n");
> @@ -1479,19 +1422,22 @@
>  	}
>  	spin_unlock_irqrestore(tw_dev->host->host_lock, flags);
>  	clear_bit(TW_IN_INTR, &tw_dev->flags);
> -}	/* End tw_interrupt() */
> +} /* End tw_interrupt() */
> 
>  /* This function handles ioctls from userspace to the driver */
>  int tw_ioctl(TW_Device_Extension *tw_dev, int request_id)
>  {
>  	unsigned char opcode;
> -	int bufflen;
> +	int bufflen, error = 0;
>  	TW_Param *param;
> -	TW_Command *command_packet;
> +	TW_Command *command_packet, *command_save;
>  	u32 param_value;
>  	TW_Ioctl *ioctl = NULL;
>  	TW_Passthru *passthru = NULL;
> -	int tw_aen_code;
> +	int tw_aen_code, i, use_sg;
> +	char *data_ptr;
> +	int total_bytes = 0;
> +	dma_addr_t dma_handle;
> 
>  	ioctl = (TW_Ioctl *)tw_dev->srb[request_id]->request_buffer;
>  	if (ioctl == NULL) {
> @@ -1598,7 +1544,7 @@
>  				printk(KERN_WARNING "3w-xxxx: tw_ioctl(): Passthru size (%ld) too big.\n", passthru->sg_list[0].length);
>  				return 1;
>  			}
> -			passthru->sg_list[0].address = virt_to_bus(tw_dev->alignment_virtual_address[request_id]);
> +			passthru->sg_list[0].address = tw_dev->alignment_physical_address[request_id];
>  			tw_post_command_packet(tw_dev, request_id);
>  			return 0;
>  		case TW_CMD_PACKET:
> @@ -1612,6 +1558,161 @@
>  				printk(KERN_WARNING "3w-xxxx: tw_ioctl(): ioctl->data NULL.\n");
>  				return 1;
>  			}
> +		case TW_CMD_PACKET_WITH_DATA:
> +			dprintk(KERN_WARNING "3w-xxxx: tw_ioctl(): caught TW_CMD_PACKET_WITH_DATA.\n");
> +			command_save = (TW_Command *)tw_dev->alignment_virtual_address[request_id];
> +			if (command_save == NULL) {
> +				printk(KERN_WARNING "3w-xxxx: scsi%d: tw_ioctl(): Bad alignment virtual address.\n", tw_dev->host->host_no);
> +				return 1;
> +			}
> +			if (ioctl->data != NULL) {
> +				/* Copy down the command packet */
> +				memcpy(command_packet, ioctl->data, sizeof(TW_Command));
> +				memcpy(command_save, ioctl->data, sizeof(TW_Command));
> +				command_packet->request_id = request_id;
> +
> +				/* Now deal with the two possible sglists */
> +				if (command_packet->byte0.sgl_offset == 2) {
> +					use_sg = command_packet->size - 3;
> +					for (i=0;i<use_sg;i++)
> +						total_bytes+=command_packet->byte8.param.sgl[i].length;
> +					tw_dev->ioctl_data[request_id] = pci_alloc_consistent(tw_dev->tw_pci_dev, total_bytes, &dma_handle);
> +
> +					if (!tw_dev->ioctl_data[request_id]) {
> +						printk(KERN_WARNING "3w-xxxx: scsi%d: tw_ioctl(): kmalloc failed for request_id %d.\n", tw_dev->host->host_no, request_id);
> +						return 1;
> +					}
> +
> +					/* Copy param sglist into the kernel */
> +					data_ptr = tw_dev->ioctl_data[request_id];
> +					for (i=0;i<use_sg;i++) {
> +						if ((u32 *)command_packet->byte8.param.sgl[i].address != NULL) {
> +							error = copy_from_user(data_ptr, (u32 *)command_packet->byte8.param.sgl[i].address, command_packet->byte8.param.sgl[i].length);
> +							if (error) {
> +								printk(KERN_WARNING "3w-xxxx: scsi%d: Error copying param sglist from userspace.\n", tw_dev->host->host_no);
> +								goto tw_ioctl_bail;
> +							}
> +						} else {
> +							printk(KERN_WARNING "3w-xxxx: scsi%d: tw_ioctl(): Bad param sgl address.\n", tw_dev->host->host_no);
> +							tw_dev->srb[request_id]->result = (DID_RESET << 16);
> +							goto tw_ioctl_bail;
> +						}
> +						data_ptr+=command_packet->byte8.param.sgl[i].length;
> +					}
> +					command_packet->size = 4;
> +					command_packet->byte8.param.sgl[0].address = dma_handle;
> +					command_packet->byte8.param.sgl[0].length = total_bytes;
> +				}
> +				if (command_packet->byte0.sgl_offset == 3) {
> +					use_sg = command_packet->size - 4;
> +					for (i=0;i<use_sg;i++)
> +						total_bytes+=command_packet->byte8.io.sgl[i].length;
> +					tw_dev->ioctl_data[request_id] = pci_alloc_consistent(tw_dev->tw_pci_dev, total_bytes, &dma_handle);
> +
> +					if (!tw_dev->ioctl_data[request_id]) {
> +						printk(KERN_WARNING "3w-xxxx: scsi%d: tw_ioctl(): pci_alloc_consistent() failed for request_id %d.\n", tw_dev->host->host_no, request_id);
> +						return 1;
> +					}
> +					if (command_packet->byte0.opcode == TW_OP_WRITE) {
> +						/* Copy io sglist into the kernel */
> +						data_ptr = tw_dev->ioctl_data[request_id];
> +						for (i=0;i<use_sg;i++) {
> +							if ((u32 *)command_packet->byte8.io.sgl[i].address != NULL) {
> +								error = copy_from_user(data_ptr, (u32 *)command_packet->byte8.io.sgl[i].address, command_packet->byte8.io.sgl[i].length);
> +								if (error) {
> +									printk(KERN_WARNING "3w-xxxx: scsi%d: Error copying io sglist from userspace.\n", tw_dev->host->host_no);
> +									goto tw_ioctl_bail;
> +								}
> +							} else {
> +								printk(KERN_WARNING "3w-xxxx: scsi%d: tw_ioctl(): Bad io sgl address.\n", tw_dev->host->host_no);
> +								tw_dev->srb[request_id]->result = (DID_RESET << 16);
> +								goto tw_ioctl_bail;
> +							}
> +							data_ptr+=command_packet->byte8.io.sgl[i].length;
> +						}
> +					}
> +					command_packet->size = 5;
> +					command_packet->byte8.io.sgl[0].address = dma_handle;
> +					command_packet->byte8.io.sgl[0].length = total_bytes;
> +				}
> +
> +				spin_unlock_irq(tw_dev->host->host_lock);
> +				spin_unlock_irq(&tw_dev->tw_lock);
> +
> +				/* Finally post the command packet */
> +				tw_post_command_packet(tw_dev, request_id);
> +
> +				mdelay(TW_IOCTL_WAIT_TIME);
> +				spin_lock_irq(&tw_dev->tw_lock);
> +				spin_lock_irq(tw_dev->host->host_lock);
> +
> +				if (signal_pending(current)) {
> +					dprintk(KERN_WARNING "3w-xxxx: scsi%d: tw_ioctl(): Signal pending, aborting ioctl().\n", tw_dev->host->host_no);
> +					tw_dev->srb[request_id]->result = (DID_OK << 16);
> +					goto tw_ioctl_bail;
> +				}
> +
> +				tw_dev->srb[request_id]->result = (DID_OK << 16);
> +				/* Now copy up the param or io sglist to userspace */
> +				if (command_packet->byte0.sgl_offset == 2) {
> +					use_sg = command_save->size - 3;
> +					data_ptr = phys_to_virt(command_packet->byte8.param.sgl[0].address);
> +					for (i=0;i<use_sg;i++) {
> +						if ((u32 *)command_save->byte8.param.sgl[i].address != NULL) {
> +							error = copy_to_user((u32 *)command_save->byte8.param.sgl[i].address, data_ptr, command_save->byte8.param.sgl[i].length);
> +							if (error) {
> +								printk(KERN_WARNING "3w-xxxx: scsi%d: Error copying param sglist to userspace.\n", tw_dev->host->host_no);
> +								goto tw_ioctl_bail;
> +							}
> +							dprintk(KERN_WARNING "3w-xxxx: scsi%d: Copied %ld bytes to pid %d.\n", tw_dev->host->host_no, command_save->byte8.param.sgl[i].length, current->pid);
> +							data_ptr+=command_save->byte8.param.sgl[i].length;
> +						} else {
> +							printk(KERN_WARNING "3w-xxxx: scsi%d: tw_ioctl(): Bad param sgl address.\n", tw_dev->host->host_no);
> +							tw_dev->srb[request_id]->result = (DID_RESET << 16);
> +							goto tw_ioctl_bail;
> +						}
> +					}
> +				}
> +				if (command_packet->byte0.sgl_offset == 3) {
> +					use_sg = command_save->size - 4;
> +					if (command_packet->byte0.opcode == TW_OP_READ) {
> +						data_ptr = phys_to_virt(command_packet->byte8.io.sgl[0].address);
> +						for(i=0;i<use_sg;i++) {
> +							if ((u32 *)command_save->byte8.io.sgl[i].address != NULL) {
> +								error = copy_to_user((u32 *)command_save->byte8.io.sgl[i].address, data_ptr, command_save->byte8.io.sgl[i].length);
> +								if (error) {
> +									printk(KERN_WARNING "3w-xxxx: scsi%d: Error copying io sglist to userspace.\n", tw_dev->host->host_no);
> +									goto tw_ioctl_bail;
> +								}
> +								dprintk(KERN_WARNING "3w-xxxx: scsi%d: Copied %ld bytes to pid %d.\n", tw_dev->host->host_no, command_save->byte8.io.sgl[i].length, current->pid);
> +								data_ptr+=command_save->byte8.io.sgl[i].length;
> +							} else {
> +								printk(KERN_WARNING "3w-xxxx: scsi%d: tw_ioctl(): Bad io sgl address.\n", tw_dev->host->host_no);
> +								tw_dev->srb[request_id]->result = (DID_RESET << 16);
> +								goto tw_ioctl_bail;
> +							}
> +						}
> +					}
> +				}
> +
> +			tw_ioctl_bail:
> +
> +				/* Free up sglist memory */
> +				if (tw_dev->ioctl_data[request_id])
> +					pci_free_consistent(tw_dev->tw_pci_dev, total_bytes, tw_dev->ioctl_data[request_id], dma_handle);
> +				else
> +					printk(KERN_WARNING "3w-xxxx: scsi%d: tw_ioctl(): Error freeing ioctl data.\n", tw_dev->host->host_no);
> +
> +				/* Now complete the io */
> +				tw_dev->state[request_id] = TW_S_COMPLETED;
> +				tw_state_request_finish(tw_dev, request_id);
> +				tw_dev->posted_request_count--;
> +				tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]);
> +				return 0;
> +			} else {
> +				printk(KERN_WARNING "3w-xxxx: tw_ioctl(): ioctl->data NULL.\n");
> +				return 1;
> +			}
>  		default:
>  			printk(KERN_WARNING "3w-xxxx: Unknown ioctl 0x%x.\n", opcode);
>  			tw_dev->state[request_id] = TW_S_COMPLETED;
> @@ -1655,6 +1756,7 @@
>  	TW_Param *param;
>  	TW_Ioctl *ioctl = NULL;
>  	TW_Passthru *passthru = NULL;
> +	TW_Command *command_packet;
> 
>  	ioctl = (TW_Ioctl *)tw_dev->srb[request_id]->request_buffer;
>  	dprintk(KERN_NOTICE "3w-xxxx: tw_ioctl_complete()\n");
> @@ -1663,6 +1765,13 @@
>  		printk(KERN_WARNING "3w-xxxx: tw_ioctl_complete(): Request buffer NULL.\n");
>  		return 1;
>  	}
> +
> +	command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id];
> +	if (command_packet == NULL) {
> +		printk(KERN_WARNING "3w-xxxx: scsi%d: tw_ioctl_complete(): Bad command packet virtual address.\n", tw_dev->host->host_no);
> +		return 1;
> +	}
> +
>  	dprintk(KERN_NOTICE "3w-xxxx: tw_ioctl_complete(): Request_bufflen = %d\n", tw_dev->srb[request_id]->request_bufflen);
> 
>  	ioctl = (TW_Ioctl *)buff;
> @@ -1671,6 +1780,9 @@
>  			passthru = (TW_Passthru *)ioctl->data;
>  			memcpy(buff, tw_dev->alignment_virtual_address[request_id], passthru->sector_count * 512);
>  			break;
> +		case TW_CMD_PACKET_WITH_DATA:
> +			dprintk(KERN_WARNING "3w-xxxx: tw_ioctl_complete(): caught TW_CMD_PACKET_WITH_DATA.\n");
> +			return 2; /* Special case for isr to not complete io */
>  		default:
>  			memset(buff, 0, tw_dev->srb[request_id]->request_bufflen);
>  			param = (TW_Param *)tw_dev->alignment_virtual_address[request_id];
> @@ -1684,6 +1796,40 @@
>  	return 0;
>  } /* End tw_ioctl_complete() */
> 
> +static int tw_map_scsi_sg_data(struct pci_dev *pdev, Scsi_Cmnd *cmd)
> +{
> +	int use_sg;
> +	int dma_dir = scsi_to_pci_dma_dir(cmd->sc_data_direction);
> +
> +	dprintk(KERN_WARNING "3w-xxxx: tw_map_scsi_sg_data()\n");
> +
> +	if (cmd->use_sg == 0)
> +		return 0;
> +
> +	use_sg = pci_map_sg(pdev, cmd->buffer, cmd->use_sg, dma_dir);
> +	cmd->SCp.phase = 2;
> +	cmd->SCp.have_data_in = use_sg;
> +
> +	return use_sg;
> +} /* End tw_map_scsi_sg_data() */
> +
> +static u32 tw_map_scsi_single_data(struct pci_dev *pdev, Scsi_Cmnd *cmd)
> +{
> +	dma_addr_t mapping;
> +	int dma_dir = scsi_to_pci_dma_dir(cmd->sc_data_direction);
> +
> +	dprintk(KERN_WARNING "3w-xxxx: tw_map_scsi_single_data()\n");
> +
> +	if (cmd->request_bufflen == 0)
> +		return 0;
> +
> +	mapping = pci_map_single(pdev, cmd->request_buffer, cmd->request_bufflen, dma_dir);
> +	cmd->SCp.phase = 2;
> +	cmd->SCp.have_data_in = mapping;
> +
> +	return mapping;
> +} /* End tw_map_scsi_single_data() */
> +
>  /* This function will mask the command interrupt */
>  void tw_mask_command_interrupt(TW_Device_Extension *tw_dev)
>  {
> @@ -1704,14 +1850,25 @@
>  	do_gettimeofday(&before);
>  	status_reg_value = inl(status_reg_addr);
> 
> +	if (tw_check_bits(status_reg_value)) {
> +		dprintk(KERN_WARNING "3w-xxxx: tw_poll_status(): Unexpected bits.\n");
> +		tw_decode_bits(tw_dev, status_reg_value);
> +	}
> +
>  	while ((status_reg_value & flag) != flag) {
>  		status_reg_value = inl(status_reg_addr);
> +
> +		if (tw_check_bits(status_reg_value)) {
> +			dprintk(KERN_WARNING "3w-xxxx: tw_poll_status(): Unexpected bits.\n");
> +			tw_decode_bits(tw_dev, status_reg_value);
> +		}
> +
>  		do_gettimeofday(&timeout);
>  		if (before.tv_sec + seconds < timeout.tv_sec) {
>  			dprintk(KERN_WARNING "3w-xxxx: tw_poll_status(): Flag 0x%x not found.\n", flag);
>  			return 1;
>  		}
> -		mdelay(1);
> +		mdelay(5);
>  	}
>  	return 0;
>  } /* End tw_poll_status() */
> @@ -1787,6 +1944,7 @@
>  				srb = tw_dev->srb[i];
>  				srb->result = (DID_RESET << 16);
>  				tw_dev->srb[i]->scsi_done(tw_dev->srb[i]);
> +				tw_unmap_scsi_data(tw_dev->tw_pci_dev, tw_dev->srb[i]);
>  			}
>  		}
>  	}
> @@ -1821,7 +1979,7 @@
> 
>  		error = tw_aen_drain_queue(tw_dev);
>  		if (error) {
> -			printk(KERN_WARNING "3w-xxxx: scsi%d: Card not responding, retrying.\n", tw_dev->host->host_no);
> +			printk(KERN_WARNING "3w-xxxx: scsi%d: AEN drain failed, retrying.\n", tw_dev->host->host_no);
>  			tries++;
>  			continue;
>  		}
> @@ -1857,7 +2015,7 @@
>  	}
> 
>  	/* Re-enable interrupts */
> -	tw_enable_interrupts(tw_dev);
> +	tw_enable_and_clear_interrupts(tw_dev);
> 
>  	return 0;
>  } /* End tw_reset_sequence() */
> @@ -2381,6 +2539,9 @@
>  	capacity = (param_data[3] << 24) | (param_data[2] << 16) |
>  		   (param_data[1] << 8) | param_data[0];
> 
> +	/* Subtract one sector to fix get last sector ioctl */
> +	capacity -= 1;
> +
>  	dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_read_capacity_complete(): Capacity = 0x%x.\n", capacity);
> 
>  	/* Number of LBA's */
> @@ -2403,8 +2564,8 @@
>  {
>  	TW_Command *command_packet;
>  	u32 command_que_addr, command_que_value = 0;
> -	u32 lba = 0x0, num_sectors = 0x0;
> -	int i, count = 0;
> +	u32 lba = 0x0, num_sectors = 0x0, buffaddr = 0x0;
> +	int i, use_sg;
>  	Scsi_Cmnd *srb;
>  	struct scatterlist *sglist;
> 
> @@ -2461,45 +2622,25 @@
>  	command_packet->byte8.io.lba = lba;
>  	command_packet->byte6.block_count = num_sectors;
> 
> -	if ((tw_dev->is_raid_five[tw_dev->srb[request_id]->target] == 0) || (srb->cmnd[0] == READ_6) || (srb->cmnd[0] == READ_10) || (tw_dev->tw_pci_dev->device == TW_DEVICE_ID2)) {
> -		/* Do this if there are no sg list entries */
> -		if (tw_dev->srb[request_id]->use_sg == 0) {
> -			dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_read_write(): SG = 0\n");
> -			command_packet->byte8.io.sgl[0].address = virt_to_bus(tw_dev->srb[request_id]->request_buffer);
> -			command_packet->byte8.io.sgl[0].length = tw_dev->srb[request_id]->request_bufflen;
> -		}
> -
> -		/* Do this if we have multiple sg list entries */
> -		if (tw_dev->srb[request_id]->use_sg > 0) {
> -			for (i=0;i<tw_dev->srb[request_id]->use_sg; i++) {
> -				command_packet->byte8.io.sgl[i].address = virt_to_bus(sglist[i].address);
> -				command_packet->byte8.io.sgl[i].length = sglist[i].length;
> -				command_packet->size+=2;
> -			}
> -			if (tw_dev->srb[request_id]->use_sg >= 1)
> -				command_packet->size-=2;
> +	/* Do this if there are no sg list entries */
> +	if (tw_dev->srb[request_id]->use_sg == 0) {
> +		dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_read_write(): SG = 0\n");
> +		buffaddr = tw_map_scsi_single_data(tw_dev->tw_pci_dev, tw_dev->srb[request_id]);
> +		command_packet->byte8.io.sgl[0].address = buffaddr;
> +		command_packet->byte8.io.sgl[0].length = tw_dev->srb[request_id]->request_bufflen;
> +	}
> +
> +	/* Do this if we have multiple sg list entries */
> +	if (tw_dev->srb[request_id]->use_sg > 0) {
> +		use_sg = tw_map_scsi_sg_data(tw_dev->tw_pci_dev, tw_dev->srb[request_id]);;
> +		for (i=0;i<use_sg; i++) {
> +			command_packet->byte8.io.sgl[i].address = sg_dma_address(&sglist[i]);
> +			command_packet->byte8.io.sgl[i].length = sg_dma_len(&sglist[i]);
> +			command_packet->size+=2;
>  		}
> -	} else {
> -                /* Do this if there are no sg list entries for raid 5 */
> -                if (tw_dev->srb[request_id]->use_sg == 0) {
> -			dprintk(KERN_WARNING "doing raid 5 write use_sg = 0, bounce_buffer[%d] = 0x%p\n", request_id, tw_dev->bounce_buffer[request_id]);
> -			memcpy(tw_dev->bounce_buffer[request_id], tw_dev->srb[request_id]->request_buffer, tw_dev->srb[request_id]->request_bufflen);
> -			command_packet->byte8.io.sgl[0].address = virt_to_bus(tw_dev->bounce_buffer[request_id]);
> -			command_packet->byte8.io.sgl[0].length = tw_dev->srb[request_id]->request_bufflen;
> -                }
> -
> -                /* Do this if we have multiple sg list entries for raid 5 */
> -                if (tw_dev->srb[request_id]->use_sg > 0) {
> -                        dprintk(KERN_WARNING "doing raid 5 write use_sg = %d, sglist[0].length = %d\n", tw_dev->srb[request_id]->use_sg, sglist[0].length);
> -                        for (i=0;i<tw_dev->srb[request_id]->use_sg; i++) {
> -                                memcpy((char *)(tw_dev->bounce_buffer[request_id])+count, sglist[i].address, sglist[i].length);
> -				count+=sglist[i].length;
> -                        }
> -                        command_packet->byte8.io.sgl[0].address = virt_to_bus(tw_dev->bounce_buffer[request_id]);
> -                        command_packet->byte8.io.sgl[0].length = count;
> -                        command_packet->size = 5; /* single sgl */
> -                }
> -        }
> +		if (tw_dev->srb[request_id]->use_sg >= 1)
> +			command_packet->size-=2;
> +	}
> 
>  	/* Update SG statistics */
>  	tw_dev->sgl_entries = tw_dev->srb[request_id]->use_sg;
> @@ -2521,18 +2662,18 @@
>  /* This function will handle the request sense scsi command */
>  int tw_scsiop_request_sense(TW_Device_Extension *tw_dev, int request_id)
>  {
> -       dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_request_sense()\n");
> -
> -       /* For now we just zero the sense buffer */
> -       memset(tw_dev->srb[request_id]->request_buffer, 0, tw_dev->srb[request_id]->request_bufflen);
> -       tw_dev->state[request_id] = TW_S_COMPLETED;
> -       tw_state_request_finish(tw_dev, request_id);
> -
> -       /* If we got a request_sense, we probably want a reset, return error */
> -       tw_dev->srb[request_id]->result = (DID_ERROR << 16);
> -       tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]);
> -
> -       return 0;
> +	dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_request_sense()\n");
> +
> +	/* For now we just zero the request buffer */
> +	memset(tw_dev->srb[request_id]->request_buffer, 0, tw_dev->srb[request_id]->request_bufflen);
> +	tw_dev->state[request_id] = TW_S_COMPLETED;
> +	tw_state_request_finish(tw_dev, request_id);
> +
> +	/* If we got a request_sense, we probably want a reset, return error */
> +	tw_dev->srb[request_id]->result = (DID_ERROR << 16);
> +	tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]);
> +
> +	return 0;
>  } /* End tw_scsiop_request_sense() */
> 
>  /* This function will handle test unit ready scsi command */
> @@ -2626,8 +2767,7 @@
>  			}
>  			if (command_packet->status != 0) {
>  				/* bad response */
> -				dprintk(KERN_WARNING "3w-xxxx: tw_setfeature(): Bad response, status = 0x%x, flags = 0x%x.\n", command_packet->status, command_packet->flags);
> -				tw_decode_error(tw_dev, command_packet->status, command_packet->flags, command_packet->byte3.unit);
> +				tw_decode_sense(tw_dev, request_id, 0);
>  				return 1;
>  			}
>  			break; /* Response was okay, so we exit */
> @@ -2671,7 +2811,7 @@
>  	}
> 
>  	/* Re-enable interrupts */
> -	tw_enable_interrupts(tw_dev);
> +	tw_enable_and_clear_interrupts(tw_dev);
> 
>  	return 0;
>  } /* End tw_shutdown_device() */
> @@ -2719,7 +2859,7 @@
>  	int id = 0;
> 
>  	dprintk(KERN_NOTICE "3w-xxxx: tw_state_request_start()\n");
> -
> +
>  	/* Obtain next free request_id */
>  	do {
>  		if (tw_dev->free_head == tw_dev->free_wrap) {
> @@ -2738,6 +2878,19 @@
>  	return 0;
>  } /* End tw_state_request_start() */
> 
> +static void tw_unmap_scsi_data(struct pci_dev *pdev, Scsi_Cmnd *cmd)
> +{
> +	int dma_dir = scsi_to_pci_dma_dir(cmd->sc_data_direction);
> +
> +	dprintk(KERN_WARNING "3w-xxxx: tw_unmap_scsi_data()\n");
> +
> +	if (cmd->use_sg) {
> +		pci_unmap_sg(pdev, cmd->request_buffer, cmd->use_sg, dma_dir);
> +	} else {
> +		pci_unmap_single(pdev, cmd->SCp.have_data_in, cmd->request_bufflen, dma_dir);
> +	}
> +} /* End tw_unmap_scsi_data() */
> +
>  /* This function will unmask the command interrupt on the controller */
>  void tw_unmask_command_interrupt(TW_Device_Extension *tw_dev)
>  {
> @@ -2749,7 +2902,6 @@
>  } /* End tw_unmask_command_interrupt() */
> 
>  /* Now get things going */
> -
>  static Scsi_Host_Template driver_template = TWXXXX;
>  #include "scsi_module.c"
> 
> diff -Naur linux-2.5.6-pre1/drivers/scsi/3w-xxxx.h linux-2.5.6-pre2/drivers/scsi/3w-xxxx.h
> --- linux-2.5.6-pre1/drivers/scsi/3w-xxxx.h	Tue Feb 19 18:10:58 2002
> +++ linux-2.5.6-pre2/drivers/scsi/3w-xxxx.h	Wed Feb 27 11:53:52 2002
> @@ -6,7 +6,7 @@
>     		     Arnaldo Carvalho de Melo <acme@conectiva.com.br>
>                       Brad Strand <linux@3ware.com>
> 
> -   Copyright (C) 1999-2001 3ware Inc.
> +   Copyright (C) 1999-2002 3ware Inc.
> 
>     Kernel compatablity By:	Andre Hedrick <andre@suse.com>
>     Non-Copyright (C) 2000	Andre Hedrick <andre@suse.com>
> @@ -62,7 +62,7 @@
>  static char *tw_aen_string[] = {
>  	"AEN queue empty",                      // 0x000
>  	"Soft reset occurred",                  // 0x001
> -	"Mirorr degraded: Unit #",              // 0x002
> +	"Unit degraded: Unit #",                // 0x002
>  	"Controller error",                     // 0x003
>  	"Rebuild failed: Unit #",               // 0x004
>  	"Rebuild complete: Unit #",             // 0x005
> @@ -90,10 +90,36 @@
>  	"DCB unsupported version: Port #",      // 0x028
>  	"Verify started: Unit #",               // 0x029
>  	"Verify failed: Port #",                // 0x02A
> -	"Verify complete: Unit #"               // 0x02B
> +	"Verify complete: Unit #",              // 0x02B
> +	"Overwrote bad sector during rebuild: Port #",  //0x2C
> +	"Encountered bad sector during rebuild: Port #" //0x2D
>  };
> 
> -#define TW_AEN_STRING_MAX                      0x02C
> +#define TW_AEN_STRING_MAX                      0x02E
> +
> +/*
> +   Sense key lookup table
> +   Format: ESDC/flags,SenseKey,AdditionalSenseCode,AdditionalSenseCodeQualifier
> +*/
> +static unsigned char tw_sense_table[][4] =
> +{
> +  /* Codes for newer firmware */
> +                            // ATA Error                    SCSI Error
> +  {0x01, 0x03, 0x13, 0x00}, // Address mark not found       Address mark not found for data field
> +  {0x04, 0x0b, 0x00, 0x00}, // Aborted command              Aborted command
> +  {0x10, 0x0b, 0x14, 0x00}, // ID not found                 Recorded entity not found
> +  {0x40, 0x03, 0x11, 0x00}, // Uncorrectable ECC error      Unrecovered read error
> +  {0x61, 0x04, 0x00, 0x00}, // Device fault                 Hardware error
> +  {0x84, 0x0b, 0x47, 0x00}, // Data CRC error               SCSI parity error
> +  {0xd0, 0x0b, 0x00, 0x00}, // Device busy                  Aborted command
> +  {0xd1, 0x0b, 0x00, 0x00}, // Device busy                  Aborted command
> +
> +  /* Codes for older firmware */
> +                            // 3ware Error                  SCSI Error
> +  {0x09, 0x0b, 0x00, 0x00}, // Unrecovered disk error       Aborted command
> +  {0x37, 0x0b, 0x04, 0x00}, // Unit offline                 Logical unit not ready
> +  {0x51, 0x0b, 0x00, 0x00}  // Unspecified                  Aborted command
> +};
> 
>  /* Control register bit definitions */
>  #define TW_CONTROL_CLEAR_HOST_INTERRUPT	       0x00080000
> @@ -108,6 +134,7 @@
>  #define TW_CONTROL_DISABLE_INTERRUPTS	       0x00000040
>  #define TW_CONTROL_ISSUE_HOST_INTERRUPT	       0x00000020
>  #define TW_CONTROL_CLEAR_PARITY_ERROR          0x00800000
> +#define TW_CONTROL_CLEAR_PCI_ABORT             0x00100000
> 
>  /* Status register bit definitions */
>  #define TW_STATUS_MAJOR_VERSION_MASK	       0xF0000000
> @@ -140,6 +167,7 @@
>  #define TW_DEVICE_ID2 (0x1001)  /* 7000 series controller */
>  #define TW_NUMDEVICES 2
>  #define TW_PCI_CLEAR_PARITY_ERRORS 0xc100
> +#define TW_PCI_CLEAR_PCI_ABORT     0x2000
> 
>  /* Command packet opcodes */
>  #define TW_OP_NOP	      0x0
> @@ -153,6 +181,7 @@
>  #define TW_OP_AEN_LISTEN      0x1c
>  #define TW_CMD_PACKET         0x1d
>  #define TW_ATA_PASSTHRU       0x1e
> +#define TW_CMD_PACKET_WITH_DATA 0x1f
> 
>  /* Asynchronous Event Notification (AEN) Codes */
>  #define TW_AEN_QUEUE_EMPTY       0x0000
> @@ -169,7 +198,8 @@
>  #define TW_AEN_SBUF_FAIL         0x0024
> 
>  /* Misc defines */
> -#define TW_ALIGNMENT			      0x200 /* 16 D-WORDS */
> +#define TW_ALIGNMENT_6000		      64 /* 64 bytes */
> +#define TW_ALIGNMENT_7000                     4  /* 4 bytes */
>  #define TW_MAX_UNITS			      16
>  #define TW_COMMAND_ALIGNMENT_MASK	      0x1ff
>  #define TW_INIT_MESSAGE_CREDITS		      0x100
> @@ -179,7 +209,6 @@
>  #define TW_ATA_PASS_SGL_MAX                   60
>  #define TW_MAX_PASSTHRU_BYTES                 4096
>  #define TW_Q_LENGTH			      256
> -#define TW_MAX_BOUNCEBUF                      16
>  #define TW_Q_START			      0
>  #define TW_MAX_SLOT			      32
>  #define TW_MAX_PCI_BUSES		      255
> @@ -191,12 +220,9 @@
>  #define TW_MAX_AEN_TRIES                      100
>  #define TW_UNIT_ONLINE                        1
>  #define TW_IN_INTR                            1
> -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,7)
>  #define TW_MAX_SECTORS                        256
> -#else
> -#define TW_MAX_SECTORS                        128
> -#endif
>  #define TW_AEN_WAIT_TIME                      1000
> +#define TW_IOCTL_WAIT_TIME                    (1 * HZ) /* 1 second */
> 
>  /* Macros */
>  #define TW_STATUS_ERRORS(x) \
> @@ -262,7 +288,6 @@
>  } TW_Command;
> 
>  typedef struct TAG_TW_Ioctl {
> -	int buffer;
>  	unsigned char opcode;
>  	unsigned short table_id;
>  	unsigned char parameter_id;
> @@ -345,11 +370,8 @@
>  	TW_Registers		registers;
>  	u32			*alignment_virtual_address[TW_Q_LENGTH];
>  	u32			alignment_physical_address[TW_Q_LENGTH];
> -	u32			*bounce_buffer[TW_Q_LENGTH];
>  	int			is_unit_present[TW_MAX_UNITS];
> -	int			is_raid_five[TW_MAX_UNITS];
>  	int			num_units;
> -	int			num_raid_five;
>  	u32			*command_packet_virtual_address[TW_Q_LENGTH];
>  	u32			command_packet_physical_address[TW_Q_LENGTH];
>  	struct pci_dev		*tw_pci_dev;
> @@ -381,22 +403,24 @@
>  	unsigned char		aen_head;
>  	unsigned char		aen_tail;
>  	long			flags; /* long req'd for set_bit --RR */
> +	char			*ioctl_data[TW_Q_LENGTH];
>  } TW_Device_Extension;
> 
>  /* Function prototypes */
>  int tw_aen_complete(TW_Device_Extension *tw_dev, int request_id);
>  int tw_aen_drain_queue(TW_Device_Extension *tw_dev);
>  int tw_aen_read_queue(TW_Device_Extension *tw_dev, int request_id);
> -int tw_allocate_memory(TW_Device_Extension *tw_dev, int request_id, int size, int which);
> +int tw_allocate_memory(TW_Device_Extension *tw_dev, int size, int which);
>  int tw_check_bits(u32 status_reg_value);
>  int tw_check_errors(TW_Device_Extension *tw_dev);
>  void tw_clear_attention_interrupt(TW_Device_Extension *tw_dev);
>  void tw_clear_host_interrupt(TW_Device_Extension *tw_dev);
>  void tw_decode_bits(TW_Device_Extension *tw_dev, u32 status_reg_value);
> -void tw_decode_error(TW_Device_Extension *tw_dev, unsigned char status, unsigned char flags, unsigned char unit);
> +void tw_decode_sense(TW_Device_Extension *tw_dev, int request_id, int fill_sense);
>  void tw_disable_interrupts(TW_Device_Extension *tw_dev);
>  int tw_empty_response_que(TW_Device_Extension *tw_dev);
>  void tw_enable_interrupts(TW_Device_Extension *tw_dev);
> +void tw_enable_and_clear_interrupts(TW_Device_Extension *tw_dev);
>  int tw_findcards(Scsi_Host_Template *tw_host);
>  void tw_free_device_extension(TW_Device_Extension *tw_dev);
>  int tw_initconnection(TW_Device_Extension *tw_dev, int message_credits);
> 
> 
> -
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: 3ware driver update for 2.5.6-pre2 (new DMA mapping)
  2002-02-27 21:45 3ware driver update for 2.5.6-pre2 (new DMA mapping) adam@mailhost.nmt.edu
  2002-02-27 22:46 ` Jeff V. Merkey
@ 2002-02-27 22:58 ` Jeff V. Merkey
  2002-02-27 23:28   ` Jeff V. Merkey
  1 sibling, 1 reply; 4+ messages in thread
From: Jeff V. Merkey @ 2002-02-27 22:58 UTC (permalink / raw)
  To: adam@mailhost.nmt.edu; +Cc: linux-kernel



HELLO ADAM,

The fixes you posted for the 3Ware drivers (AEN drain).  Would they affect 
the problems I reported this morning.

Thanks

Jeff



On Wed, Feb 27, 2002 at 02:45:04PM -0700, adam@mailhost.nmt.edu wrote:
> Alan,
> 
> Please apply this patch for kernel 2.5.6-pre2 for the 3ware driver to
> support the new DMA mapping code, and several other fixes.
> 
> Thanks.
> 
> --
> Adam Radford
> Software Engineer
> 3ware, Inc.
> 
> diff -Naur linux-2.5.6-pre1/drivers/scsi/3w-xxxx.c linux-2.5.6-pre2/drivers/scsi/3w-xxxx.c
> --- linux-2.5.6-pre1/drivers/scsi/3w-xxxx.c	Tue Feb 19 18:11:00 2002
> +++ linux-2.5.6-pre2/drivers/scsi/3w-xxxx.c	Wed Feb 27 11:53:49 2002
> @@ -6,7 +6,7 @@
>     		     Arnaldo Carvalho de Melo <acme@conectiva.com.br>
>                       Brad Strand <linux@3ware.com>
> 
> -   Copyright (C) 1999-2001 3ware Inc.
> +   Copyright (C) 1999-2002 3ware Inc.
> 
>     Kernel compatablity By: 	Andre Hedrick <andre@suse.com>
>     Non-Copyright (C) 2000	Andre Hedrick <andre@suse.com>
> @@ -106,17 +106,41 @@
>                   Add entire aen code string list.
>     1.02.00.010 - Cleanup queueing code, fix jbod thoughput.
>                   Fix get_param for specific units.
> +   1.02.00.011 - Fix bug in tw_aen_complete() where aen's could be lost.
> +                 Fix tw_aen_drain_queue() to display useful info at init.
> +                 Set tw_host->max_id for 12 port cards.
> +                 Add ioctl support for raw command packet post from userspace
> +                 with sglist fragments (parameter and io).
> +   1.02.00.012 - Fix read capacity to under report by 1 sector to fix get
> +                 last sector ioctl.
> +   1.02.00.013 - Fix bug where more AEN codes weren't coming out during
> +                 driver initialization.
> +                 Improved handling of PCI aborts.
> +   1.02.00.014 - Fix bug in tw_findcards() where AEN code could be lost.
> +                 Increase timeout in tw_aen_drain_queue() to 30 seconds.
> +   1.02.00.015 - Re-write raw command post with data ioctl method.
> +                 Remove raid5 bounce buffers for raid5 for 6XXX for kernel 2.5
> +                 Add tw_map/unmap_scsi_sg/single_data() for kernel 2.5
> +                 Replace io_request_lock with host_lock for kernel 2.5
> +                 Set max_cmd_len to 16 for 3dm for kernel 2.5
> +   1.02.00.016 - Set host->max_sectors back up to 256.
> +   1.02.00.017 - Modified pci parity error handling/clearing from config space
> +                 during initialization.
> +   1.02.00.018 - Better handling of request sense opcode and sense information
> +                 for failed commands.  Add tw_decode_sense().
> +                 Replace all mdelay()'s with scsi_sleep().
> +   1.02.00.019 - Revert mdelay's and scsi_sleep's, this caused problems on
> +                 some SMP systems.
> +   1.02.00.020 - Add pci_set_dma_mask(), rewrite kmalloc()/virt_to_bus() to
> +                 pci_alloc/free_consistent().
>  */
> 
> -#error Please convert me to Documentation/DMA-mapping.txt
> -
>  #include <linux/module.h>
> 
>  MODULE_AUTHOR ("3ware Inc.");
>  MODULE_DESCRIPTION ("3ware Storage Controller Linux Driver");
>  MODULE_LICENSE("GPL");
> 
> -
>  #include <linux/kernel.h>
>  #include <linux/pci.h>
>  #include <linux/time.h>
> @@ -148,14 +172,17 @@
>  static void tw_copy_mem_info(TW_Info *info, char *data, int len);
>  static void tw_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
>  static int tw_halt(struct notifier_block *nb, ulong event, void *buf);
> +static int tw_map_scsi_sg_data(struct pci_dev *pdev, Scsi_Cmnd *cmd);
> +static u32 tw_map_scsi_single_data(struct pci_dev *pdev, Scsi_Cmnd *cmd);
> +static void tw_unmap_scsi_data(struct pci_dev *pdev, Scsi_Cmnd *cmd);
> 
>  /* Notifier block to get a notify on system shutdown/halt/reboot */
>  static struct notifier_block tw_notifier = {
> -  tw_halt, NULL, 0
> +	tw_halt, NULL, 0
>  };
> 
>  /* Globals */
> -char *tw_driver_version="1.02.00.010";
> +char *tw_driver_version="1.02.00.020";
>  TW_Device_Extension *tw_device_extension_list[TW_MAX_SLOT];
>  int tw_device_extension_count = 0;
> 
> @@ -166,6 +193,7 @@
>  {
>  	TW_Param *param;
>  	unsigned short aen;
> +	int error = 0;
> 
>  	dprintk(KERN_WARNING "3w-xxxx: tw_aen_complete()\n");
>  	if (tw_dev->alignment_virtual_address[request_id] == NULL) {
> @@ -184,12 +212,15 @@
>  			if ((tw_aen_string[aen & 0xff][strlen(tw_aen_string[aen & 0xff])-1]) == '#') {
>  				printk(KERN_WARNING "3w-xxxx: scsi%d: AEN: %s%d.\n", tw_dev->host->host_no, tw_aen_string[aen & 0xff], aen >> 8);
>  			} else {
> -				printk(KERN_WARNING "3w-xxxx: scsi%d: AEN: %s.\n", tw_dev->host->host_no, tw_aen_string[aen & 0xff]);
> +				if (aen != 0x0)
> +					printk(KERN_WARNING "3w-xxxx: scsi%d: AEN: %s.\n", tw_dev->host->host_no, tw_aen_string[aen & 0xff]);
>  			}
> -		} else
> +		} else {
>  			printk(KERN_WARNING "3w-xxxx: scsi%d: Received AEN %d.\n", tw_dev->host->host_no, aen);
> +		}
>  	}
> -	tw_dev->aen_count++;
> +	if (aen != 0x0)
> +		tw_dev->aen_count++;
> 
>  	/* Now queue the code */
>  	tw_dev->aen_queue[tw_dev->aen_tail] = aen;
> @@ -205,8 +236,18 @@
>  			tw_dev->aen_head = tw_dev->aen_head + 1;
>  		}
>  	}
> -	tw_dev->state[request_id] = TW_S_COMPLETED;
> -	tw_state_request_finish(tw_dev, request_id);
> +
> +	if (aen != TW_AEN_QUEUE_EMPTY) {
> +		error = tw_aen_read_queue(tw_dev, request_id);
> +		if (error) {
> +			printk(KERN_WARNING "3w-xxxx: scsi%d: Error completing AEN.\n", tw_dev->host->host_no);
> +			tw_dev->state[request_id] = TW_S_COMPLETED;
> +			tw_state_request_finish(tw_dev, request_id);
> +		}
> +	} else {
> +		tw_dev->state[request_id] = TW_S_COMPLETED;
> +		tw_state_request_finish(tw_dev, request_id);
> +	}
> 
>  	return 0;
>  } /* End tw_aen_complete() */
> @@ -237,10 +278,11 @@
>  	status_reg_addr = tw_dev->registers.status_reg_addr;
>  	response_que_addr = tw_dev->registers.response_que_addr;
> 
> -	if (tw_poll_status(tw_dev, TW_STATUS_ATTENTION_INTERRUPT, 15)) {
> +	if (tw_poll_status(tw_dev, TW_STATUS_ATTENTION_INTERRUPT, 30)) {
>  		dprintk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): No attention interrupt for card %d.\n", tw_device_extension_count);
>  		return 1;
>  	}
> +	tw_clear_attention_interrupt(tw_dev);
> 
>  	/* Initialize command packet */
>  	if (tw_dev->command_packet_virtual_address[request_id] == NULL) {
> @@ -288,7 +330,7 @@
>  	do {
>  		/* Post command packet */
>  		outl(command_que_value, command_que_addr);
> -
> +
>  		/* Now poll for completion */
>  		for (i=0;i<imax;i++) {
>  			mdelay(5);
> @@ -311,8 +353,7 @@
>  				if (command_packet->status != 0) {
>  					if (command_packet->flags != TW_AEN_TABLE_UNDEFINED) {
>  						/* Bad response */
> -						dprintk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): Bad response, status = 0x%x, flags = 0x%x.\n", command_packet->status, command_packet->flags);
> -						tw_decode_error(tw_dev, command_packet->status, command_packet->flags, command_packet->byte3.unit);
> +						tw_decode_sense(tw_dev, request_id, 0);
>  						return 1;
>  					} else {
>  						/* We know this is a 3w-1x00, and doesn't support aen's */
> @@ -326,7 +367,7 @@
>  				queue = 0;
>  				switch (aen_code) {
>  					case TW_AEN_QUEUE_EMPTY:
> -						dprintk(KERN_NOTICE "3w-xxxx: tw_aen_drain_queue(): Found TW_AEN_QUEUE_EMPTY.\n");
> +						dprintk(KERN_WARNING "3w-xxxx: AEN: %s.\n", tw_aen_string[aen & 0xff]);
>  						if (first_reset != 1) {
>  							continue;
>  						} else {
> @@ -334,51 +375,28 @@
>  						}
>  						break;
>  					case TW_AEN_SOFT_RESET:
> -						dprintk(KERN_NOTICE "3w-xxxx: tw_aen_drain_queue(): Found TW_AEN_SOFT_RESET.\n");
>  						if (first_reset == 0) {
>  							first_reset = 1;
>  						} else {
> +							printk(KERN_WARNING "3w-xxxx: AEN: %s.\n", tw_aen_string[aen & 0xff]);
> +							tw_dev->aen_count++;
>  							queue = 1;
>  						}
>  						break;
> -					case TW_AEN_DEGRADED_MIRROR:
> -						dprintk(KERN_NOTICE "3w-xxxx: tw_aen_drain_queue(): Found TW_AEN_DEGRADED_MIRROR.\n");
> -						queue = 1;
> -						break;
> -					case TW_AEN_CONTROLLER_ERROR:
> -						dprintk(KERN_NOTICE "3w-xxxx: tw_aen_drain_queue(): Found TW_AEN_CONTROLLER_ERROR.\n");
> -						queue = 1;
> -						break;
> -					case TW_AEN_REBUILD_FAIL:
> -						dprintk(KERN_NOTICE "3w-xxxx: tw_aen_drain_queue(): Found TW_AEN_REBUILD_FAIL.\n");
> -						queue = 1;
> -						break;
> -					case TW_AEN_REBUILD_DONE:
> -						dprintk(KERN_NOTICE "3w-xxxx: tw_aen_drain_queue(): Found TW_AEN_REBUILD_DONE.\n");
> -						queue = 1;
> -						break;
> -					case TW_AEN_QUEUE_FULL:
> -						dprintk(KERN_NOTICE "3w-xxxx: tw_aen_drain_queue(): Found TW_AEN_QUEUE_FULL.\n");
> -						queue = 1;
> -						break;
> -					case TW_AEN_APORT_TIMEOUT:
> -						printk(KERN_WARNING "3w-xxxx: Received drive timeout AEN on port %d, check drive and drive cables.\n", aen >> 8);
> -						queue = 1;
> -						break;
> -					case TW_AEN_DRIVE_ERROR:
> -						printk(KERN_WARNING "3w-xxxx: Received drive error AEN on port %d, check/replace cabling, or possible bad drive.\n", aen >> 8);
> -						queue = 1;
> -						break;
> -					case TW_AEN_SMART_FAIL:
> -						printk(KERN_WARNING "3w-xxxx: Received S.M.A.R.T. threshold AEN on port %d, check drive/cooling, or possible bad drive.\n", aen >> 8);
> -						queue = 1;
> -						break;
> -					case TW_AEN_SBUF_FAIL:
> -						printk(KERN_WARNING "3w-xxxx: Received SBUF integrity check failure AEN, reseat card or bad card.\n");
> -						queue = 1;
> -						break;
>  					default:
> -						dprintk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): Unknown AEN code 0x%x.\n", aen_code);
> +						if (aen == 0x0ff) {
> +							printk(KERN_WARNING "3w-xxxx: AEN: AEN queue overflow.\n");
> +						} else {
> +							if ((aen & 0x0ff) < TW_AEN_STRING_MAX) {
> +								if ((tw_aen_string[aen & 0xff][strlen(tw_aen_string[aen & 0xff])-1]) == '#') {
> +									printk(KERN_WARNING "3w-xxxx: AEN: %s%d.\n", tw_aen_string[aen & 0xff], aen >> 8);
> +								} else {
> +									printk(KERN_WARNING "3w-xxxx: AEN: %s.\n", tw_aen_string[aen & 0xff]);
> +								}
> +							} else
> +								printk(KERN_WARNING "3w-xxxx: Received AEN %d.\n", aen);
> +						}
> +						tw_dev->aen_count++;
>  						queue = 1;
>  				}
> 
> @@ -488,40 +506,44 @@
>  	return 0;
>  } /* End tw_aen_read_queue() */
> 
> -/* This function will allocate memory and check if it is 16 d-word aligned */
> -int tw_allocate_memory(TW_Device_Extension *tw_dev, int request_id, int size, int which)
> +/* This function will allocate memory */
> +int tw_allocate_memory(TW_Device_Extension *tw_dev, int size, int which)
>  {
> -	u32 *virt_addr = kmalloc(size, GFP_ATOMIC);
> +	int i;
> +	dma_addr_t dma_handle;
> +	u32 *cpu_addr = NULL;
> 
>  	dprintk(KERN_NOTICE "3w-xxxx: tw_allocate_memory()\n");
> 
> -	if (!virt_addr) {
> -		printk(KERN_WARNING "3w-xxxx: tw_allocate_memory(): kmalloc() failed.\n");
> -		return 1;
> -	}
> +	for (i=0;i<TW_Q_LENGTH;i++) {
> +		cpu_addr = pci_alloc_consistent(tw_dev->tw_pci_dev, size, &dma_handle);
> +		if (cpu_addr == NULL) {
> +			printk(KERN_WARNING "3w-xxxx: pci_alloc_consistent() failed.\n");
> +			return 1;
> +		}
> 
> -	if ((u32)virt_addr % TW_ALIGNMENT) {
> -		kfree(virt_addr);
> -		printk(KERN_WARNING "3w-xxxx: tw_allocate_memory(): Found unaligned address.\n");
> -		return 1;
> -	}
> +		if ((u32)cpu_addr % (tw_dev->tw_pci_dev->device == TW_DEVICE_ID ? TW_ALIGNMENT_6000 : TW_ALIGNMENT_7000)) {
> +			printk(KERN_WARNING "3w-xxxx: Couldn't allocate correctly aligned memory.\n");
> +			return 1;
> +		}
> 
> -	switch(which) {
> -	case 0:
> -		tw_dev->command_packet_virtual_address[request_id] = virt_addr;
> -		tw_dev->command_packet_physical_address[request_id] = virt_to_bus(virt_addr);
> -		break;
> -	case 1:
> -		tw_dev->alignment_virtual_address[request_id] = virt_addr;
> -		tw_dev->alignment_physical_address[request_id] = virt_to_bus(virt_addr);
> -		break;
> -	case 2:
> -		tw_dev->bounce_buffer[request_id] = virt_addr;
> -		break;
> -	default:
> -		printk(KERN_WARNING "3w-xxxx: tw_allocate_memory(): case slip in tw_allocate_memory()\n");
> -		return 1;
> +		switch(which) {
> +		case 0:
> +			tw_dev->command_packet_virtual_address[i] = cpu_addr;
> +			tw_dev->command_packet_physical_address[i] = dma_handle;
> +			memset(tw_dev->command_packet_virtual_address[i], 0, size);
> +			break;
> +		case 1:
> +			tw_dev->alignment_virtual_address[i] = cpu_addr;
> +			tw_dev->alignment_physical_address[i] = dma_handle;
> +			memset(tw_dev->alignment_virtual_address[i], 0, size);
> +			break;
> +		default:
> +			printk(KERN_WARNING "3w-xxxx: tw_allocate_memory(): case slip in tw_allocate_memory()\n");
> +			return 1;
> +		}
>  	}
> +
>  	return 0;
>  } /* End tw_allocate_memory() */
> 
> @@ -548,8 +570,10 @@
>  	status_reg_addr = tw_dev->registers.status_reg_addr;
>  	status_reg_value = inl(status_reg_addr);
> 
> -	if (TW_STATUS_ERRORS(status_reg_value) || tw_check_bits(status_reg_value))
> +	if (TW_STATUS_ERRORS(status_reg_value) || tw_check_bits(status_reg_value)) {
> +		tw_decode_bits(tw_dev, status_reg_value);
>  		return 1;
> +	}
> 
>  	return 0;
>  } /* End tw_check_errors() */
> @@ -614,37 +638,62 @@
>  	dprintk(KERN_WARNING "3w-xxxx: tw_decode_bits()\n");
>  	switch (status_reg_value & TW_STATUS_UNEXPECTED_BITS) {
>  	case TW_STATUS_PCI_PARITY_ERROR:
> -		printk(KERN_WARNING "3w-xxxx: PCI Parity Error: Reseat card, move card, or buggy device on the bus.\n");
> +		printk(KERN_WARNING "3w-xxxx: PCI Parity Error: clearing.\n");
>  		outl(TW_CONTROL_CLEAR_PARITY_ERROR, tw_dev->registers.control_reg_addr);
> -		pci_write_config_word(tw_dev->tw_pci_dev, PCI_STATUS, TW_PCI_CLEAR_PARITY_ERRORS);
>  		break;
>  	case TW_STATUS_MICROCONTROLLER_ERROR:
>  		printk(KERN_WARNING "3w-xxxx: Microcontroller Error.\n");
>  		break;
> +	case TW_STATUS_PCI_ABORT:
> +		printk(KERN_WARNING "3w-xxxx: PCI Abort: clearing.\n");
> +		outl(TW_CONTROL_CLEAR_PCI_ABORT, tw_dev->registers.control_reg_addr);
> +		pci_write_config_word(tw_dev->tw_pci_dev, PCI_STATUS, TW_PCI_CLEAR_PCI_ABORT);
> +		break;
>    }
>  } /* End tw_decode_bits() */
> 
> -/* This function will print readable messages from flags and status values */
> -void tw_decode_error(TW_Device_Extension *tw_dev, unsigned char status, unsigned char flags, unsigned char unit)
> +/* This function will return valid sense buffer information for failed cmds */
> +void tw_decode_sense(TW_Device_Extension *tw_dev, int request_id, int fill_sense)
>  {
> -	dprintk(KERN_WARNING "3w-xxxx: tw_decode_error()\n");
> -	switch (status) {
> -	case 0xc7:
> -		switch (flags) {
> -		case 0x1b:
> -			printk(KERN_WARNING "3w-xxxx: scsi%d: Drive timeout on unit %d, check drive and drive cables.\n", tw_dev->host->host_no, unit);
> -			break;
> -		case 0x51:
> -			printk(KERN_WARNING "3w-xxxx: scsi%d: Unrecoverable drive error on unit %d, check/replace cabling, or possible bad drive.\n", tw_dev->host->host_no, unit);
> -			break;
> -		default:
> -			printk(KERN_WARNING "3w-xxxx: scsi%d: Controller error: status = 0x%x, flags = 0x%x, unit #%d.\n", tw_dev->host->host_no, status, flags, unit);
> +	int i, found=0;
> +	TW_Command *command;
> +
> +        dprintk(KERN_WARNING "3w-xxxx: tw_decode_sense()\n");
> +	command = (TW_Command *)tw_dev->command_packet_virtual_address[request_id];
> +
> +	printk(KERN_WARNING "3w-xxxx: scsi%d: Command failed: status = 0x%x, flags = 0x%x, unit #%d.\n", tw_dev->host->host_no, command->status, command->flags, command->byte3.unit);
> +
> +	/* Attempt to return intelligent sense information */
> +	if (fill_sense) {
> +		if ((command->status == 0xc7) || (command->status == 0xcb)) {
> +			for (i=0;i<(sizeof(tw_sense_table)/sizeof(tw_sense_table[0]));i++) {
> +				if (command->flags == tw_sense_table[i][0]) {
> +					found=1;
> +
> +					/* Valid bit and 'current errors' */
> +					tw_dev->srb[request_id]->sense_buffer[0] = (0x1 << 7 | 0x70);
> +
> +					/* Sense key */
> +					tw_dev->srb[request_id]->sense_buffer[2] = tw_sense_table[i][1];
> +
> +					/* Additional sense length */
> +					tw_dev->srb[request_id]->sense_buffer[7] = 0xa; /* 10 bytes */
> +
> +					/* Additional sense code */
> +					tw_dev->srb[request_id]->sense_buffer[12] = tw_sense_table[i][2];
> +
> +					/* Additional sense code qualifier */
> +					tw_dev->srb[request_id]->sense_buffer[13] = tw_sense_table[i][3];
> +
> +					tw_dev->srb[request_id]->result = (DID_OK << 16) | (CHECK_CONDITION << 1);
> +				}
> +			}
>  		}
> -		break;
> -	default:
> -		printk(KERN_WARNING "3w-xxxx: scsi%d: Controller error: status = 0x%x, flags = 0x%x, unit #%d.\n", tw_dev->host->host_no, status, flags, unit);
> +		/* If no table match, error so we get a reset */
> +		if (found == 0)
> +			tw_dev->srb[request_id]->result = (DID_RESET << 16);
>  	}
> -} /* End tw_decode_error() */
> +} /* End tw_decode_sense() */
> 
>  /* This function will disable interrupts on the controller */
>  void tw_disable_interrupts(TW_Device_Extension *tw_dev)
> @@ -691,11 +740,22 @@
>  	u32 control_reg_value, control_reg_addr;
> 
>  	control_reg_addr = tw_dev->registers.control_reg_addr;
> +	control_reg_value = (TW_CONTROL_ENABLE_INTERRUPTS |
> +			     TW_CONTROL_UNMASK_RESPONSE_INTERRUPT);
> +	outl(control_reg_value, control_reg_addr);
> +} /* End tw_enable_interrupts() */
> +
> +/* This function will enable interrupts on the controller */
> +void tw_enable_and_clear_interrupts(TW_Device_Extension *tw_dev)
> +{
> +	u32 control_reg_value, control_reg_addr;
> +
> +	control_reg_addr = tw_dev->registers.control_reg_addr;
>  	control_reg_value = (TW_CONTROL_CLEAR_ATTENTION_INTERRUPT |
>  			     TW_CONTROL_UNMASK_RESPONSE_INTERRUPT |
>  			     TW_CONTROL_ENABLE_INTERRUPTS);
>  	outl(control_reg_value, control_reg_addr);
> -} /* End tw_enable_interrupts() */
> +} /* End tw_enable_and_clear_interrupts() */
> 
>  /* This function will find and initialize all cards */
>  int tw_findcards(Scsi_Host_Template *tw_host)
> @@ -716,6 +776,13 @@
>  		while ((tw_pci_dev = pci_find_device(TW_VENDOR_ID, device[i], tw_pci_dev))) {
>  			if (pci_enable_device(tw_pci_dev))
>  				continue;
> +
> +			/* We only need 32-bit addressing for 5,6,7xxx cards */
> +			if (pci_set_dma_mask(tw_pci_dev, 0xffffffff)) {
> +				printk(KERN_WARNING "3w-xxxx: No suitable DMA available.\n");
> +				continue;
> +			}
> +
>  			/* Prepare temporary device extension */
>  			tw_dev=(TW_Device_Extension *)kmalloc(sizeof(TW_Device_Extension), GFP_ATOMIC);
>  			if (tw_dev == NULL) {
> @@ -724,6 +791,9 @@
>  			}
>  			memset(tw_dev, 0, sizeof(TW_Device_Extension));
> 
> +			/* Save pci_dev struct to device extension */
> +			tw_dev->tw_pci_dev = tw_pci_dev;
> +
>  			error = tw_initialize_device_extension(tw_dev);
>  			if (error) {
>  				printk(KERN_WARNING "3w-xxxx: tw_findcards(): Couldn't initialize device extension for card %d.\n", numcards);
> @@ -738,8 +808,6 @@
>  			tw_dev->registers.status_reg_addr = pci_resource_start(tw_pci_dev, 0) + 0x4;
>  			tw_dev->registers.command_que_addr = pci_resource_start(tw_pci_dev, 0) + 0x8;
>  			tw_dev->registers.response_que_addr = pci_resource_start(tw_pci_dev, 0) + 0xC;
> -			/* Save pci_dev struct to device extension */
> -			tw_dev->tw_pci_dev = tw_pci_dev;
> 
>  			/* Check for errors and clear them */
>  			status_reg_value = inl(tw_dev->registers.status_reg_addr);
> @@ -763,14 +831,14 @@
> 
>  				error = tw_aen_drain_queue(tw_dev);
>  				if (error) {
> -					printk(KERN_WARNING "3w-xxxx: tw_findcards(): No attention interrupt for card %d.\n", numcards);
> +					printk(KERN_WARNING "3w-xxxx: AEN drain failed for card %d.\n", numcards);
>  					tries++;
>  					continue;
>  				}
> 
>  				/* Check for controller errors */
>  				if (tw_check_errors(tw_dev)) {
> -					printk(KERN_WARNING "3w-xxxx: tw_findcards(): Controller errors found, soft resetting card %d.\n", numcards);
> +					printk(KERN_WARNING "3w-xxxx: Controller errors found, retrying for card %d.\n", numcards);
>  					tries++;
>  					continue;
>  				}
> @@ -778,7 +846,7 @@
>  				/* Empty the response queue */
>  				error = tw_empty_response_que(tw_dev);
>  				if (error) {
> -					printk(KERN_WARNING "3w-xxxx: tw_findcards(): Couldn't empty response queue for card %d.\n", numcards);
> +					printk(KERN_WARNING "3w-xxxx: Couldn't empty response queue, retrying for card %d.\n", numcards);
>  					tries++;
>  					continue;
>  				}
> @@ -788,7 +856,7 @@
>  			}
> 
>  			if (tries >= TW_MAX_RESET_TRIES) {
> -				printk(KERN_WARNING "3w-xxxx: tw_findcards(): Controller error or no attention interrupt: giving up for card %d.\n", numcards);
> +				printk(KERN_WARNING "3w-xxxx: Controller errors, card not responding, check all cabling for card %d.\n", numcards);
>  				tw_free_device_extension(tw_dev);
>  				kfree(tw_dev);
>  				continue;
> @@ -818,7 +886,7 @@
> 
>  			error = tw_initconnection(tw_dev, TW_INIT_MESSAGE_CREDITS);
>  			if (error) {
> -				printk(KERN_WARNING "3w-xxxx: tw_findcards(): Couldn't initconnection for card %d.\n", numcards);
> +				printk(KERN_WARNING "3w-xxxx: Connection initialization failed for card %d.\n", numcards);
>  				release_region((tw_dev->tw_pci_dev->resource[0].start), TW_IO_ADDRESS_RANGE);
>  				tw_free_device_extension(tw_dev);
>  				kfree(tw_dev);
> @@ -827,29 +895,28 @@
> 
>  			/* Calculate max cmds per lun, and setup queues */
>  			if (tw_dev->num_units > 0) {
> -				if ((tw_dev->num_raid_five > 0) && (tw_dev->tw_pci_dev->device == TW_DEVICE_ID)) {
> -					tw_host->cmd_per_lun = (TW_MAX_BOUNCEBUF-1)/tw_dev->num_units;
> -					tw_dev->free_head = TW_Q_START;
> -					tw_dev->free_tail = TW_MAX_BOUNCEBUF - 1;
> -					tw_dev->free_wrap = TW_MAX_BOUNCEBUF - 1;
> -				} else {
> -					tw_host->cmd_per_lun = (TW_Q_LENGTH-1)/tw_dev->num_units;
> -					tw_dev->free_head = TW_Q_START;
> -					tw_dev->free_tail = TW_Q_LENGTH - 1;
> -					tw_dev->free_wrap = TW_Q_LENGTH - 1;
> -				}
> +				tw_host->cmd_per_lun = (TW_Q_LENGTH-1)/tw_dev->num_units;
> +				tw_dev->free_head = TW_Q_START;
> +				tw_dev->free_tail = TW_Q_LENGTH - 1;
> +				tw_dev->free_wrap = TW_Q_LENGTH - 1;
>  			}
> 
> -		/* Register the card with the kernel SCSI layer */
> +			/* Register the card with the kernel SCSI layer */
>  			host = scsi_register(tw_host, sizeof(TW_Device_Extension));
>  			if (host == NULL) {
> -				printk(KERN_WARNING "3w-xxxx: tw_findcards(): scsi_register() failed for card %d.\n", numcards-1);
> +				printk(KERN_WARNING "3w-xxxx: tw_findcards(): scsi_register() failed for card %d.\n", numcards);
>  				release_region((tw_dev->tw_pci_dev->resource[0].start), TW_IO_ADDRESS_RANGE);
>  				tw_free_device_extension(tw_dev);
>  				kfree(tw_dev);
>  				continue;
>  			}
> 
> +			/* Set max target id's */
> +			host->max_id = TW_MAX_UNITS;
> +
> +			/* Set max cdb size in bytes */
> +			host->max_cmd_len = 16;
> +
>  			/* Set max sectors per io */
>  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,7)
>  			host->max_sectors = TW_MAX_SECTORS;
> @@ -874,7 +941,7 @@
>  				tw_device_extension_count = numcards;
>  				tw_dev2->host = host;
>  			} else {
> -				printk(KERN_WARNING "3w-xxxx: tw_findcards(): Bad scsi host data for card %d.\n", numcards-1);
> +				printk(KERN_WARNING "3w-xxxx: tw_findcards(): Bad scsi host data for card %d.\n", numcards);
>  				scsi_unregister(host);
>  				release_region((tw_dev->tw_pci_dev->resource[0].start), TW_IO_ADDRESS_RANGE);
>  				tw_free_device_extension(tw_dev);
> @@ -924,15 +991,10 @@
>  	/* Free command packet and generic buffer memory */
>  	for (i=0;i<TW_Q_LENGTH;i++) {
>  		if (tw_dev->command_packet_virtual_address[i])
> -			kfree(tw_dev->command_packet_virtual_address[i]);
> +			pci_free_consistent(tw_dev->tw_pci_dev, sizeof(TW_Sector), tw_dev->command_packet_virtual_address[i], tw_dev->command_packet_physical_address[i]);
> 
>  		if (tw_dev->alignment_virtual_address[i])
> -			kfree(tw_dev->alignment_virtual_address[i]);
> -
> -	}
> -	for (i=0;i<TW_MAX_BOUNCEBUF;i++) {
> -		if (tw_dev->bounce_buffer[i])
> -			kfree(tw_dev->bounce_buffer[i]);
> +			pci_free_consistent(tw_dev->tw_pci_dev, sizeof(TW_Sector), tw_dev->alignment_virtual_address[i], tw_dev->alignment_physical_address[i]);
>  	}
>  } /* End tw_free_device_extension() */
> 
> @@ -1015,8 +1077,7 @@
>  			}
>  			if (command_packet->status != 0) {
>  				/* bad response */
> -				dprintk(KERN_WARNING "3w-xxxx: tw_initconnection(): Bad response, status = 0x%x, flags = 0x%x.\n", command_packet->status, command_packet->flags);
> -				tw_decode_error(tw_dev, command_packet->status, command_packet->flags, command_packet->byte3.unit);
> +				tw_decode_sense(tw_dev, request_id, 0);
>  				return 1;
>  			}
>  			break;	/* Response was okay, so we exit */
> @@ -1028,57 +1089,33 @@
>  /* This function will initialize the fields of a device extension */
>  int tw_initialize_device_extension(TW_Device_Extension *tw_dev)
>  {
> -	int i, imax;
> +	int i, error=0;
> 
>  	dprintk(KERN_NOTICE "3w-xxxx: tw_initialize_device_extension()\n");
> -	imax = TW_Q_LENGTH;
> 
> -	for (i=0; i<imax; i++) {
> -		/* Initialize command packet buffers */
> -		tw_allocate_memory(tw_dev, i, sizeof(TW_Sector), 0);
> -		if (tw_dev->command_packet_virtual_address[i] == NULL) {
> -			printk(KERN_WARNING "3w-xxxx: tw_initialize_device_extension(): Bad command packet virtual address.\n");
> -			return 1;
> -		}
> -		memset(tw_dev->command_packet_virtual_address[i], 0, sizeof(TW_Sector));
> -
> -		/* Initialize generic buffer */
> -		tw_allocate_memory(tw_dev, i, sizeof(TW_Sector), 1);
> -		if (tw_dev->alignment_virtual_address[i] == NULL) {
> -			printk(KERN_WARNING "3w-xxxx: tw_initialize_device_extension(): Bad alignment virtual address.\n");
> -			return 1;
> -		}
> -		memset(tw_dev->alignment_virtual_address[i], 0, sizeof(TW_Sector));
> +	/* Initialize command packet buffers */
> +	error = tw_allocate_memory(tw_dev, sizeof(TW_Command), 0);
> +	if (error) {
> +		printk(KERN_WARNING "3w-xxxx: Command packet memory allocation failed.\n");
> +		return 1;
> +	}
> 
> -		tw_dev->free_queue[i] = i;
> -		tw_dev->state[i] = TW_S_INITIAL;
> -		tw_dev->ioctl_size[i] = 0;
> -		tw_dev->aen_queue[i] = 0;
> +	/* Initialize generic buffer */
> +	error = tw_allocate_memory(tw_dev, sizeof(TW_Sector), 1);
> +	if (error) {
> +		printk(KERN_WARNING "3w-xxxx: Generic memory allocation failed.\n");
> +		return 1;
>  	}
> 
> -	for (i=0;i<TW_MAX_UNITS;i++) {
> -		tw_dev->is_unit_present[i] = 0;
> -		tw_dev->is_raid_five[i] = 0;
> +	for (i=0;i<TW_Q_LENGTH;i++) {
> +		tw_dev->free_queue[i] = i;
> +		tw_dev->state[i] = TW_S_INITIAL;
>  	}
> 
> -	tw_dev->num_units = 0;
> -	tw_dev->num_aborts = 0;
> -	tw_dev->num_resets = 0;
> -	tw_dev->posted_request_count = 0;
> -	tw_dev->max_posted_request_count = 0;
> -	tw_dev->max_sgl_entries = 0;
> -	tw_dev->sgl_entries = 0;
> -	tw_dev->host = NULL;
>  	tw_dev->pending_head = TW_Q_START;
>  	tw_dev->pending_tail = TW_Q_START;
> -	tw_dev->aen_head = 0;
> -	tw_dev->aen_tail = 0;
> -	tw_dev->sector_count = 0;
> -	tw_dev->max_sector_count = 0;
> -	tw_dev->aen_count = 0;
> -	tw_dev->num_raid_five = 0;
>  	spin_lock_init(&tw_dev->tw_lock);
> -	tw_dev->flags = 0;
> +
>  	return 0;
>  } /* End tw_initialize_device_extension() */
> 
> @@ -1089,14 +1126,13 @@
>  	unsigned char request_id = 0;
>  	TW_Command *command_packet;
>  	TW_Param *param;
> -	int i, j, imax, num_units = 0, num_raid_five = 0;
> +	int i, imax, num_units = 0;
>  	u32 status_reg_addr, status_reg_value;
>  	u32 command_que_addr, command_que_value;
>  	u32 response_que_addr;
>  	TW_Response_Queue response_queue;
>  	u32 param_value;
>  	unsigned char *is_unit_present;
> -	unsigned char *raid_level;
> 
>  	dprintk(KERN_NOTICE "3w-xxxx: tw_initialize_units()\n");
> 
> @@ -1168,8 +1204,7 @@
>  			}
>  			if (command_packet->status != 0) {
>  				/* bad response */
> -				dprintk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Bad response, status = 0x%x, flags = 0x%x.\n", command_packet->status, command_packet->flags);
> -				tw_decode_error(tw_dev, command_packet->status, command_packet->flags, command_packet->byte3.unit);
> +				tw_decode_sense(tw_dev, request_id, 0);
>  				return 1;
>  			}
>  			found = 1;
> @@ -1205,109 +1240,6 @@
>  		return 1;
>  	}
> 
> -	/* Find raid 5 arrays */
> -	for (j=0;j<TW_MAX_UNITS;j++) {
> -		if (tw_dev->is_unit_present[j] == 0)
> -			continue;
> -		command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id];
> -		if (command_packet == NULL) {
> -			printk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Bad command packet virtual address.\n");
> -			return 1;
> -		}
> -		memset(command_packet, 0, sizeof(TW_Sector));
> -		command_packet->byte0.opcode      = TW_OP_GET_PARAM;
> -		command_packet->byte0.sgl_offset  = 2;
> -		command_packet->size              = 4;
> -		command_packet->request_id        = request_id;
> -		command_packet->byte3.unit        = 0;
> -		command_packet->byte3.host_id     = 0;
> -		command_packet->status            = 0;
> -		command_packet->flags             = 0;
> -		command_packet->byte6.block_count = 1;
> -
> -		/* Now setup the param */
> -		if (tw_dev->alignment_virtual_address[request_id] == NULL) {
> -			printk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Bad alignment virtual address.\n");
> -			return 1;
> -		}
> -		param = (TW_Param *)tw_dev->alignment_virtual_address[request_id];
> -		memset(param, 0, sizeof(TW_Sector));
> -		param->table_id = 0x300+j; /* unit summary table */
> -		param->parameter_id = 0x6; /* unit descriptor */
> -		param->parameter_size_bytes = 0xc;
> -		param_value = tw_dev->alignment_physical_address[request_id];
> -		if (param_value == 0) {
> -			printk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Bad alignment physical address.\n");
> -			return 1;
> -		}
> -
> -		command_packet->byte8.param.sgl[0].address = param_value;
> -		command_packet->byte8.param.sgl[0].length = sizeof(TW_Sector);
> -
> -		/* Post the command packet to the board */
> -		command_que_value = tw_dev->command_packet_physical_address[request_id];
> -		if (command_que_value == 0) {
> -			printk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Bad command packet physical address.\n");
> -			return 1;
> -		}
> -		outl(command_que_value, command_que_addr);
> -
> -		/* Poll for completion */
> -		imax = TW_POLL_MAX_RETRIES;
> -		for(i=0; i<imax; i++) {
> -			mdelay(5);
> -			status_reg_value = inl(status_reg_addr);
> -			if (tw_check_bits(status_reg_value)) {
> -				dprintk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Unexpected bits.\n");
> -				tw_decode_bits(tw_dev, status_reg_value);
> -				return 1;
> -			}
> -			if ((status_reg_value & TW_STATUS_RESPONSE_QUEUE_EMPTY) == 0) {
> -				response_queue.value = inl(response_que_addr);
> -				request_id = (unsigned char)response_queue.u.response_id;
> -				if (request_id != 0) {
> -					/* unexpected request id */
> -					printk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Unexpected request id.\n");
> -					return 1;
> -				}
> -				if (command_packet->status != 0) {
> -					/* bad response */
> -					dprintk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Bad response, status = 0x%x, flags = 0x%x.\n", command_packet->status, command_packet->flags);
> -					tw_decode_error(tw_dev, command_packet->status, command_packet->flags, command_packet->byte3.unit);
> -					return 1;
> -				}
> -				found = 1;
> -				break;
> -			}
> -		}
> -		if (found == 0) {
> -			/* response never received */
> -			printk(KERN_WARNING "3w-xxxx: tw_initialize_units(): No response.\n");
> -			return 1;
> -		}
> -
> -		param = (TW_Param *)tw_dev->alignment_virtual_address[request_id];
> -		raid_level = (unsigned char *)&(param->data[1]);
> -		if (*raid_level == 5) {
> -			dprintk(KERN_WARNING "3w-xxxx: Found unit %d to be a raid5 unit.\n", j);
> -			tw_dev->is_raid_five[j] = 1;
> -			num_raid_five++;
> -		}
> -	}
> -	tw_dev->num_raid_five = num_raid_five;
> -
> -	/* Now allocate raid5 bounce buffers */
> -	if ((num_raid_five != 0) && (tw_dev->tw_pci_dev->device == TW_DEVICE_ID)) {
> -		for (i=0;i<TW_MAX_BOUNCEBUF;i++) {
> -			tw_allocate_memory(tw_dev, i, sizeof(TW_Sector)*TW_MAX_SECTORS, 2);
> -			if (tw_dev->bounce_buffer[i] == NULL) {
> -				printk(KERN_WARNING "3w-xxxx: Bounce buffer allocation failed.\n");
> -				return 1;
> -			}
> -			memset(tw_dev->bounce_buffer[i], 0, sizeof(TW_Sector)*TW_MAX_SECTORS);
> -		}
> -	}
> -
>  	return 0;
>  } /* End tw_initialize_units() */
> 
> @@ -1332,13 +1264,18 @@
> 
>  	if (tw_dev->tw_pci_dev->irq == irq) {
>  		spin_lock(&tw_dev->tw_lock);
> -		dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt()\n");
> +		dprintk(KERN_WARNING "3w-xxxx: tw_interrupt()\n");
> 
>  		/* Read the registers */
>  		status_reg_addr = tw_dev->registers.status_reg_addr;
>  		response_que_addr = tw_dev->registers.response_que_addr;
>  		status_reg_value = inl(status_reg_addr);
> 
> +		if (tw_check_bits(status_reg_value)) {
> +			dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Unexpected bits.\n");
> +			tw_decode_bits(tw_dev, status_reg_value);
> +		}
> +
>  		/* Check which interrupt */
>  		if (status_reg_value & TW_STATUS_HOST_INTERRUPT)
>  			do_host_interrupt=1;
> @@ -1403,17 +1340,18 @@
>  				command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id];
>  				error = 0;
>  				if (command_packet->status != 0) {
> -					dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Bad response, status = 0x%x, flags = 0x%x, unit = 0x%x.\n", command_packet->status, command_packet->flags, command_packet->byte3.unit);
> -					tw_decode_error(tw_dev, command_packet->status, command_packet->flags, command_packet->byte3.unit);
> -					error = 1;
> +					/* Bad response */
> +					if (tw_dev->srb[request_id] != 0)
> +						tw_decode_sense(tw_dev, request_id, 1);
> +					error = 3;
>  				}
>  				if (tw_dev->state[request_id] != TW_S_POSTED) {
>  					printk(KERN_WARNING "3w-xxxx: scsi%d: Received a request id (%d) (opcode = 0x%x) that wasn't posted.\n", tw_dev->host->host_no, request_id, command_packet->byte0.opcode);
>  					error = 1;
>  				}
>  				if (TW_STATUS_ERRORS(status_reg_value)) {
> -				  tw_decode_bits(tw_dev, status_reg_value);
> -				  error = 1;
> +					tw_decode_bits(tw_dev, status_reg_value);
> +					error = 1;
>  				}
>  				dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): Response queue request id: %d.\n", request_id);
>  				/* Check for internal command */
> @@ -1428,7 +1366,7 @@
>  						dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Unexpected bits.\n");
>  						tw_decode_bits(tw_dev, status_reg_value);
>  					}
> -		} else {
> +				} else {
>  				switch (tw_dev->srb[request_id]->cmnd[0]) {
>  					case READ_10:
>  					case READ_6:
> @@ -1455,18 +1393,23 @@
>  						tw_dev->srb[request_id]->result = (DID_BAD_TARGET << 16);
>  						tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]);
>  					}
> -					if (error) {
> +					if (error == 1) {
>  						/* Tell scsi layer there was an error */
>  						dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Scsi Error.\n");
>  						tw_dev->srb[request_id]->result = (DID_RESET << 16);
> -					} else {
> +					}
> +					if (error == 0) {
>  						/* Tell scsi layer command was a success */
>  						tw_dev->srb[request_id]->result = (DID_OK << 16);
>  					}
> -					tw_dev->state[request_id] = TW_S_COMPLETED;
> -					tw_state_request_finish(tw_dev, request_id);
> -					tw_dev->posted_request_count--;
> -					tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]);
> +					if (error != 2) {
> +						tw_dev->state[request_id] = TW_S_COMPLETED;
> +						tw_state_request_finish(tw_dev, request_id);
> +						tw_dev->posted_request_count--;
> +						tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]);
> +
> +						tw_unmap_scsi_data(tw_dev->tw_pci_dev, tw_dev->srb[request_id]);
> +					}
>  					status_reg_value = inl(status_reg_addr);
>  					if (tw_check_bits(status_reg_value)) {
>  						dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Unexpected bits.\n");
> @@ -1479,19 +1422,22 @@
>  	}
>  	spin_unlock_irqrestore(tw_dev->host->host_lock, flags);
>  	clear_bit(TW_IN_INTR, &tw_dev->flags);
> -}	/* End tw_interrupt() */
> +} /* End tw_interrupt() */
> 
>  /* This function handles ioctls from userspace to the driver */
>  int tw_ioctl(TW_Device_Extension *tw_dev, int request_id)
>  {
>  	unsigned char opcode;
> -	int bufflen;
> +	int bufflen, error = 0;
>  	TW_Param *param;
> -	TW_Command *command_packet;
> +	TW_Command *command_packet, *command_save;
>  	u32 param_value;
>  	TW_Ioctl *ioctl = NULL;
>  	TW_Passthru *passthru = NULL;
> -	int tw_aen_code;
> +	int tw_aen_code, i, use_sg;
> +	char *data_ptr;
> +	int total_bytes = 0;
> +	dma_addr_t dma_handle;
> 
>  	ioctl = (TW_Ioctl *)tw_dev->srb[request_id]->request_buffer;
>  	if (ioctl == NULL) {
> @@ -1598,7 +1544,7 @@
>  				printk(KERN_WARNING "3w-xxxx: tw_ioctl(): Passthru size (%ld) too big.\n", passthru->sg_list[0].length);
>  				return 1;
>  			}
> -			passthru->sg_list[0].address = virt_to_bus(tw_dev->alignment_virtual_address[request_id]);
> +			passthru->sg_list[0].address = tw_dev->alignment_physical_address[request_id];
>  			tw_post_command_packet(tw_dev, request_id);
>  			return 0;
>  		case TW_CMD_PACKET:
> @@ -1612,6 +1558,161 @@
>  				printk(KERN_WARNING "3w-xxxx: tw_ioctl(): ioctl->data NULL.\n");
>  				return 1;
>  			}
> +		case TW_CMD_PACKET_WITH_DATA:
> +			dprintk(KERN_WARNING "3w-xxxx: tw_ioctl(): caught TW_CMD_PACKET_WITH_DATA.\n");
> +			command_save = (TW_Command *)tw_dev->alignment_virtual_address[request_id];
> +			if (command_save == NULL) {
> +				printk(KERN_WARNING "3w-xxxx: scsi%d: tw_ioctl(): Bad alignment virtual address.\n", tw_dev->host->host_no);
> +				return 1;
> +			}
> +			if (ioctl->data != NULL) {
> +				/* Copy down the command packet */
> +				memcpy(command_packet, ioctl->data, sizeof(TW_Command));
> +				memcpy(command_save, ioctl->data, sizeof(TW_Command));
> +				command_packet->request_id = request_id;
> +
> +				/* Now deal with the two possible sglists */
> +				if (command_packet->byte0.sgl_offset == 2) {
> +					use_sg = command_packet->size - 3;
> +					for (i=0;i<use_sg;i++)
> +						total_bytes+=command_packet->byte8.param.sgl[i].length;
> +					tw_dev->ioctl_data[request_id] = pci_alloc_consistent(tw_dev->tw_pci_dev, total_bytes, &dma_handle);
> +
> +					if (!tw_dev->ioctl_data[request_id]) {
> +						printk(KERN_WARNING "3w-xxxx: scsi%d: tw_ioctl(): kmalloc failed for request_id %d.\n", tw_dev->host->host_no, request_id);
> +						return 1;
> +					}
> +
> +					/* Copy param sglist into the kernel */
> +					data_ptr = tw_dev->ioctl_data[request_id];
> +					for (i=0;i<use_sg;i++) {
> +						if ((u32 *)command_packet->byte8.param.sgl[i].address != NULL) {
> +							error = copy_from_user(data_ptr, (u32 *)command_packet->byte8.param.sgl[i].address, command_packet->byte8.param.sgl[i].length);
> +							if (error) {
> +								printk(KERN_WARNING "3w-xxxx: scsi%d: Error copying param sglist from userspace.\n", tw_dev->host->host_no);
> +								goto tw_ioctl_bail;
> +							}
> +						} else {
> +							printk(KERN_WARNING "3w-xxxx: scsi%d: tw_ioctl(): Bad param sgl address.\n", tw_dev->host->host_no);
> +							tw_dev->srb[request_id]->result = (DID_RESET << 16);
> +							goto tw_ioctl_bail;
> +						}
> +						data_ptr+=command_packet->byte8.param.sgl[i].length;
> +					}
> +					command_packet->size = 4;
> +					command_packet->byte8.param.sgl[0].address = dma_handle;
> +					command_packet->byte8.param.sgl[0].length = total_bytes;
> +				}
> +				if (command_packet->byte0.sgl_offset == 3) {
> +					use_sg = command_packet->size - 4;
> +					for (i=0;i<use_sg;i++)
> +						total_bytes+=command_packet->byte8.io.sgl[i].length;
> +					tw_dev->ioctl_data[request_id] = pci_alloc_consistent(tw_dev->tw_pci_dev, total_bytes, &dma_handle);
> +
> +					if (!tw_dev->ioctl_data[request_id]) {
> +						printk(KERN_WARNING "3w-xxxx: scsi%d: tw_ioctl(): pci_alloc_consistent() failed for request_id %d.\n", tw_dev->host->host_no, request_id);
> +						return 1;
> +					}
> +					if (command_packet->byte0.opcode == TW_OP_WRITE) {
> +						/* Copy io sglist into the kernel */
> +						data_ptr = tw_dev->ioctl_data[request_id];
> +						for (i=0;i<use_sg;i++) {
> +							if ((u32 *)command_packet->byte8.io.sgl[i].address != NULL) {
> +								error = copy_from_user(data_ptr, (u32 *)command_packet->byte8.io.sgl[i].address, command_packet->byte8.io.sgl[i].length);
> +								if (error) {
> +									printk(KERN_WARNING "3w-xxxx: scsi%d: Error copying io sglist from userspace.\n", tw_dev->host->host_no);
> +									goto tw_ioctl_bail;
> +								}
> +							} else {
> +								printk(KERN_WARNING "3w-xxxx: scsi%d: tw_ioctl(): Bad io sgl address.\n", tw_dev->host->host_no);
> +								tw_dev->srb[request_id]->result = (DID_RESET << 16);
> +								goto tw_ioctl_bail;
> +							}
> +							data_ptr+=command_packet->byte8.io.sgl[i].length;
> +						}
> +					}
> +					command_packet->size = 5;
> +					command_packet->byte8.io.sgl[0].address = dma_handle;
> +					command_packet->byte8.io.sgl[0].length = total_bytes;
> +				}
> +
> +				spin_unlock_irq(tw_dev->host->host_lock);
> +				spin_unlock_irq(&tw_dev->tw_lock);
> +
> +				/* Finally post the command packet */
> +				tw_post_command_packet(tw_dev, request_id);
> +
> +				mdelay(TW_IOCTL_WAIT_TIME);
> +				spin_lock_irq(&tw_dev->tw_lock);
> +				spin_lock_irq(tw_dev->host->host_lock);
> +
> +				if (signal_pending(current)) {
> +					dprintk(KERN_WARNING "3w-xxxx: scsi%d: tw_ioctl(): Signal pending, aborting ioctl().\n", tw_dev->host->host_no);
> +					tw_dev->srb[request_id]->result = (DID_OK << 16);
> +					goto tw_ioctl_bail;
> +				}
> +
> +				tw_dev->srb[request_id]->result = (DID_OK << 16);
> +				/* Now copy up the param or io sglist to userspace */
> +				if (command_packet->byte0.sgl_offset == 2) {
> +					use_sg = command_save->size - 3;
> +					data_ptr = phys_to_virt(command_packet->byte8.param.sgl[0].address);
> +					for (i=0;i<use_sg;i++) {
> +						if ((u32 *)command_save->byte8.param.sgl[i].address != NULL) {
> +							error = copy_to_user((u32 *)command_save->byte8.param.sgl[i].address, data_ptr, command_save->byte8.param.sgl[i].length);
> +							if (error) {
> +								printk(KERN_WARNING "3w-xxxx: scsi%d: Error copying param sglist to userspace.\n", tw_dev->host->host_no);
> +								goto tw_ioctl_bail;
> +							}
> +							dprintk(KERN_WARNING "3w-xxxx: scsi%d: Copied %ld bytes to pid %d.\n", tw_dev->host->host_no, command_save->byte8.param.sgl[i].length, current->pid);
> +							data_ptr+=command_save->byte8.param.sgl[i].length;
> +						} else {
> +							printk(KERN_WARNING "3w-xxxx: scsi%d: tw_ioctl(): Bad param sgl address.\n", tw_dev->host->host_no);
> +							tw_dev->srb[request_id]->result = (DID_RESET << 16);
> +							goto tw_ioctl_bail;
> +						}
> +					}
> +				}
> +				if (command_packet->byte0.sgl_offset == 3) {
> +					use_sg = command_save->size - 4;
> +					if (command_packet->byte0.opcode == TW_OP_READ) {
> +						data_ptr = phys_to_virt(command_packet->byte8.io.sgl[0].address);
> +						for(i=0;i<use_sg;i++) {
> +							if ((u32 *)command_save->byte8.io.sgl[i].address != NULL) {
> +								error = copy_to_user((u32 *)command_save->byte8.io.sgl[i].address, data_ptr, command_save->byte8.io.sgl[i].length);
> +								if (error) {
> +									printk(KERN_WARNING "3w-xxxx: scsi%d: Error copying io sglist to userspace.\n", tw_dev->host->host_no);
> +									goto tw_ioctl_bail;
> +								}
> +								dprintk(KERN_WARNING "3w-xxxx: scsi%d: Copied %ld bytes to pid %d.\n", tw_dev->host->host_no, command_save->byte8.io.sgl[i].length, current->pid);
> +								data_ptr+=command_save->byte8.io.sgl[i].length;
> +							} else {
> +								printk(KERN_WARNING "3w-xxxx: scsi%d: tw_ioctl(): Bad io sgl address.\n", tw_dev->host->host_no);
> +								tw_dev->srb[request_id]->result = (DID_RESET << 16);
> +								goto tw_ioctl_bail;
> +							}
> +						}
> +					}
> +				}
> +
> +			tw_ioctl_bail:
> +
> +				/* Free up sglist memory */
> +				if (tw_dev->ioctl_data[request_id])
> +					pci_free_consistent(tw_dev->tw_pci_dev, total_bytes, tw_dev->ioctl_data[request_id], dma_handle);
> +				else
> +					printk(KERN_WARNING "3w-xxxx: scsi%d: tw_ioctl(): Error freeing ioctl data.\n", tw_dev->host->host_no);
> +
> +				/* Now complete the io */
> +				tw_dev->state[request_id] = TW_S_COMPLETED;
> +				tw_state_request_finish(tw_dev, request_id);
> +				tw_dev->posted_request_count--;
> +				tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]);
> +				return 0;
> +			} else {
> +				printk(KERN_WARNING "3w-xxxx: tw_ioctl(): ioctl->data NULL.\n");
> +				return 1;
> +			}
>  		default:
>  			printk(KERN_WARNING "3w-xxxx: Unknown ioctl 0x%x.\n", opcode);
>  			tw_dev->state[request_id] = TW_S_COMPLETED;
> @@ -1655,6 +1756,7 @@
>  	TW_Param *param;
>  	TW_Ioctl *ioctl = NULL;
>  	TW_Passthru *passthru = NULL;
> +	TW_Command *command_packet;
> 
>  	ioctl = (TW_Ioctl *)tw_dev->srb[request_id]->request_buffer;
>  	dprintk(KERN_NOTICE "3w-xxxx: tw_ioctl_complete()\n");
> @@ -1663,6 +1765,13 @@
>  		printk(KERN_WARNING "3w-xxxx: tw_ioctl_complete(): Request buffer NULL.\n");
>  		return 1;
>  	}
> +
> +	command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id];
> +	if (command_packet == NULL) {
> +		printk(KERN_WARNING "3w-xxxx: scsi%d: tw_ioctl_complete(): Bad command packet virtual address.\n", tw_dev->host->host_no);
> +		return 1;
> +	}
> +
>  	dprintk(KERN_NOTICE "3w-xxxx: tw_ioctl_complete(): Request_bufflen = %d\n", tw_dev->srb[request_id]->request_bufflen);
> 
>  	ioctl = (TW_Ioctl *)buff;
> @@ -1671,6 +1780,9 @@
>  			passthru = (TW_Passthru *)ioctl->data;
>  			memcpy(buff, tw_dev->alignment_virtual_address[request_id], passthru->sector_count * 512);
>  			break;
> +		case TW_CMD_PACKET_WITH_DATA:
> +			dprintk(KERN_WARNING "3w-xxxx: tw_ioctl_complete(): caught TW_CMD_PACKET_WITH_DATA.\n");
> +			return 2; /* Special case for isr to not complete io */
>  		default:
>  			memset(buff, 0, tw_dev->srb[request_id]->request_bufflen);
>  			param = (TW_Param *)tw_dev->alignment_virtual_address[request_id];
> @@ -1684,6 +1796,40 @@
>  	return 0;
>  } /* End tw_ioctl_complete() */
> 
> +static int tw_map_scsi_sg_data(struct pci_dev *pdev, Scsi_Cmnd *cmd)
> +{
> +	int use_sg;
> +	int dma_dir = scsi_to_pci_dma_dir(cmd->sc_data_direction);
> +
> +	dprintk(KERN_WARNING "3w-xxxx: tw_map_scsi_sg_data()\n");
> +
> +	if (cmd->use_sg == 0)
> +		return 0;
> +
> +	use_sg = pci_map_sg(pdev, cmd->buffer, cmd->use_sg, dma_dir);
> +	cmd->SCp.phase = 2;
> +	cmd->SCp.have_data_in = use_sg;
> +
> +	return use_sg;
> +} /* End tw_map_scsi_sg_data() */
> +
> +static u32 tw_map_scsi_single_data(struct pci_dev *pdev, Scsi_Cmnd *cmd)
> +{
> +	dma_addr_t mapping;
> +	int dma_dir = scsi_to_pci_dma_dir(cmd->sc_data_direction);
> +
> +	dprintk(KERN_WARNING "3w-xxxx: tw_map_scsi_single_data()\n");
> +
> +	if (cmd->request_bufflen == 0)
> +		return 0;
> +
> +	mapping = pci_map_single(pdev, cmd->request_buffer, cmd->request_bufflen, dma_dir);
> +	cmd->SCp.phase = 2;
> +	cmd->SCp.have_data_in = mapping;
> +
> +	return mapping;
> +} /* End tw_map_scsi_single_data() */
> +
>  /* This function will mask the command interrupt */
>  void tw_mask_command_interrupt(TW_Device_Extension *tw_dev)
>  {
> @@ -1704,14 +1850,25 @@
>  	do_gettimeofday(&before);
>  	status_reg_value = inl(status_reg_addr);
> 
> +	if (tw_check_bits(status_reg_value)) {
> +		dprintk(KERN_WARNING "3w-xxxx: tw_poll_status(): Unexpected bits.\n");
> +		tw_decode_bits(tw_dev, status_reg_value);
> +	}
> +
>  	while ((status_reg_value & flag) != flag) {
>  		status_reg_value = inl(status_reg_addr);
> +
> +		if (tw_check_bits(status_reg_value)) {
> +			dprintk(KERN_WARNING "3w-xxxx: tw_poll_status(): Unexpected bits.\n");
> +			tw_decode_bits(tw_dev, status_reg_value);
> +		}
> +
>  		do_gettimeofday(&timeout);
>  		if (before.tv_sec + seconds < timeout.tv_sec) {
>  			dprintk(KERN_WARNING "3w-xxxx: tw_poll_status(): Flag 0x%x not found.\n", flag);
>  			return 1;
>  		}
> -		mdelay(1);
> +		mdelay(5);
>  	}
>  	return 0;
>  } /* End tw_poll_status() */
> @@ -1787,6 +1944,7 @@
>  				srb = tw_dev->srb[i];
>  				srb->result = (DID_RESET << 16);
>  				tw_dev->srb[i]->scsi_done(tw_dev->srb[i]);
> +				tw_unmap_scsi_data(tw_dev->tw_pci_dev, tw_dev->srb[i]);
>  			}
>  		}
>  	}
> @@ -1821,7 +1979,7 @@
> 
>  		error = tw_aen_drain_queue(tw_dev);
>  		if (error) {
> -			printk(KERN_WARNING "3w-xxxx: scsi%d: Card not responding, retrying.\n", tw_dev->host->host_no);
> +			printk(KERN_WARNING "3w-xxxx: scsi%d: AEN drain failed, retrying.\n", tw_dev->host->host_no);
>  			tries++;
>  			continue;
>  		}
> @@ -1857,7 +2015,7 @@
>  	}
> 
>  	/* Re-enable interrupts */
> -	tw_enable_interrupts(tw_dev);
> +	tw_enable_and_clear_interrupts(tw_dev);
> 
>  	return 0;
>  } /* End tw_reset_sequence() */
> @@ -2381,6 +2539,9 @@
>  	capacity = (param_data[3] << 24) | (param_data[2] << 16) |
>  		   (param_data[1] << 8) | param_data[0];
> 
> +	/* Subtract one sector to fix get last sector ioctl */
> +	capacity -= 1;
> +
>  	dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_read_capacity_complete(): Capacity = 0x%x.\n", capacity);
> 
>  	/* Number of LBA's */
> @@ -2403,8 +2564,8 @@
>  {
>  	TW_Command *command_packet;
>  	u32 command_que_addr, command_que_value = 0;
> -	u32 lba = 0x0, num_sectors = 0x0;
> -	int i, count = 0;
> +	u32 lba = 0x0, num_sectors = 0x0, buffaddr = 0x0;
> +	int i, use_sg;
>  	Scsi_Cmnd *srb;
>  	struct scatterlist *sglist;
> 
> @@ -2461,45 +2622,25 @@
>  	command_packet->byte8.io.lba = lba;
>  	command_packet->byte6.block_count = num_sectors;
> 
> -	if ((tw_dev->is_raid_five[tw_dev->srb[request_id]->target] == 0) || (srb->cmnd[0] == READ_6) || (srb->cmnd[0] == READ_10) || (tw_dev->tw_pci_dev->device == TW_DEVICE_ID2)) {
> -		/* Do this if there are no sg list entries */
> -		if (tw_dev->srb[request_id]->use_sg == 0) {
> -			dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_read_write(): SG = 0\n");
> -			command_packet->byte8.io.sgl[0].address = virt_to_bus(tw_dev->srb[request_id]->request_buffer);
> -			command_packet->byte8.io.sgl[0].length = tw_dev->srb[request_id]->request_bufflen;
> -		}
> -
> -		/* Do this if we have multiple sg list entries */
> -		if (tw_dev->srb[request_id]->use_sg > 0) {
> -			for (i=0;i<tw_dev->srb[request_id]->use_sg; i++) {
> -				command_packet->byte8.io.sgl[i].address = virt_to_bus(sglist[i].address);
> -				command_packet->byte8.io.sgl[i].length = sglist[i].length;
> -				command_packet->size+=2;
> -			}
> -			if (tw_dev->srb[request_id]->use_sg >= 1)
> -				command_packet->size-=2;
> +	/* Do this if there are no sg list entries */
> +	if (tw_dev->srb[request_id]->use_sg == 0) {
> +		dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_read_write(): SG = 0\n");
> +		buffaddr = tw_map_scsi_single_data(tw_dev->tw_pci_dev, tw_dev->srb[request_id]);
> +		command_packet->byte8.io.sgl[0].address = buffaddr;
> +		command_packet->byte8.io.sgl[0].length = tw_dev->srb[request_id]->request_bufflen;
> +	}
> +
> +	/* Do this if we have multiple sg list entries */
> +	if (tw_dev->srb[request_id]->use_sg > 0) {
> +		use_sg = tw_map_scsi_sg_data(tw_dev->tw_pci_dev, tw_dev->srb[request_id]);;
> +		for (i=0;i<use_sg; i++) {
> +			command_packet->byte8.io.sgl[i].address = sg_dma_address(&sglist[i]);
> +			command_packet->byte8.io.sgl[i].length = sg_dma_len(&sglist[i]);
> +			command_packet->size+=2;
>  		}
> -	} else {
> -                /* Do this if there are no sg list entries for raid 5 */
> -                if (tw_dev->srb[request_id]->use_sg == 0) {
> -			dprintk(KERN_WARNING "doing raid 5 write use_sg = 0, bounce_buffer[%d] = 0x%p\n", request_id, tw_dev->bounce_buffer[request_id]);
> -			memcpy(tw_dev->bounce_buffer[request_id], tw_dev->srb[request_id]->request_buffer, tw_dev->srb[request_id]->request_bufflen);
> -			command_packet->byte8.io.sgl[0].address = virt_to_bus(tw_dev->bounce_buffer[request_id]);
> -			command_packet->byte8.io.sgl[0].length = tw_dev->srb[request_id]->request_bufflen;
> -                }
> -
> -                /* Do this if we have multiple sg list entries for raid 5 */
> -                if (tw_dev->srb[request_id]->use_sg > 0) {
> -                        dprintk(KERN_WARNING "doing raid 5 write use_sg = %d, sglist[0].length = %d\n", tw_dev->srb[request_id]->use_sg, sglist[0].length);
> -                        for (i=0;i<tw_dev->srb[request_id]->use_sg; i++) {
> -                                memcpy((char *)(tw_dev->bounce_buffer[request_id])+count, sglist[i].address, sglist[i].length);
> -				count+=sglist[i].length;
> -                        }
> -                        command_packet->byte8.io.sgl[0].address = virt_to_bus(tw_dev->bounce_buffer[request_id]);
> -                        command_packet->byte8.io.sgl[0].length = count;
> -                        command_packet->size = 5; /* single sgl */
> -                }
> -        }
> +		if (tw_dev->srb[request_id]->use_sg >= 1)
> +			command_packet->size-=2;
> +	}
> 
>  	/* Update SG statistics */
>  	tw_dev->sgl_entries = tw_dev->srb[request_id]->use_sg;
> @@ -2521,18 +2662,18 @@
>  /* This function will handle the request sense scsi command */
>  int tw_scsiop_request_sense(TW_Device_Extension *tw_dev, int request_id)
>  {
> -       dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_request_sense()\n");
> -
> -       /* For now we just zero the sense buffer */
> -       memset(tw_dev->srb[request_id]->request_buffer, 0, tw_dev->srb[request_id]->request_bufflen);
> -       tw_dev->state[request_id] = TW_S_COMPLETED;
> -       tw_state_request_finish(tw_dev, request_id);
> -
> -       /* If we got a request_sense, we probably want a reset, return error */
> -       tw_dev->srb[request_id]->result = (DID_ERROR << 16);
> -       tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]);
> -
> -       return 0;
> +	dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_request_sense()\n");
> +
> +	/* For now we just zero the request buffer */
> +	memset(tw_dev->srb[request_id]->request_buffer, 0, tw_dev->srb[request_id]->request_bufflen);
> +	tw_dev->state[request_id] = TW_S_COMPLETED;
> +	tw_state_request_finish(tw_dev, request_id);
> +
> +	/* If we got a request_sense, we probably want a reset, return error */
> +	tw_dev->srb[request_id]->result = (DID_ERROR << 16);
> +	tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]);
> +
> +	return 0;
>  } /* End tw_scsiop_request_sense() */
> 
>  /* This function will handle test unit ready scsi command */
> @@ -2626,8 +2767,7 @@
>  			}
>  			if (command_packet->status != 0) {
>  				/* bad response */
> -				dprintk(KERN_WARNING "3w-xxxx: tw_setfeature(): Bad response, status = 0x%x, flags = 0x%x.\n", command_packet->status, command_packet->flags);
> -				tw_decode_error(tw_dev, command_packet->status, command_packet->flags, command_packet->byte3.unit);
> +				tw_decode_sense(tw_dev, request_id, 0);
>  				return 1;
>  			}
>  			break; /* Response was okay, so we exit */
> @@ -2671,7 +2811,7 @@
>  	}
> 
>  	/* Re-enable interrupts */
> -	tw_enable_interrupts(tw_dev);
> +	tw_enable_and_clear_interrupts(tw_dev);
> 
>  	return 0;
>  } /* End tw_shutdown_device() */
> @@ -2719,7 +2859,7 @@
>  	int id = 0;
> 
>  	dprintk(KERN_NOTICE "3w-xxxx: tw_state_request_start()\n");
> -
> +
>  	/* Obtain next free request_id */
>  	do {
>  		if (tw_dev->free_head == tw_dev->free_wrap) {
> @@ -2738,6 +2878,19 @@
>  	return 0;
>  } /* End tw_state_request_start() */
> 
> +static void tw_unmap_scsi_data(struct pci_dev *pdev, Scsi_Cmnd *cmd)
> +{
> +	int dma_dir = scsi_to_pci_dma_dir(cmd->sc_data_direction);
> +
> +	dprintk(KERN_WARNING "3w-xxxx: tw_unmap_scsi_data()\n");
> +
> +	if (cmd->use_sg) {
> +		pci_unmap_sg(pdev, cmd->request_buffer, cmd->use_sg, dma_dir);
> +	} else {
> +		pci_unmap_single(pdev, cmd->SCp.have_data_in, cmd->request_bufflen, dma_dir);
> +	}
> +} /* End tw_unmap_scsi_data() */
> +
>  /* This function will unmask the command interrupt on the controller */
>  void tw_unmask_command_interrupt(TW_Device_Extension *tw_dev)
>  {
> @@ -2749,7 +2902,6 @@
>  } /* End tw_unmask_command_interrupt() */
> 
>  /* Now get things going */
> -
>  static Scsi_Host_Template driver_template = TWXXXX;
>  #include "scsi_module.c"
> 
> diff -Naur linux-2.5.6-pre1/drivers/scsi/3w-xxxx.h linux-2.5.6-pre2/drivers/scsi/3w-xxxx.h
> --- linux-2.5.6-pre1/drivers/scsi/3w-xxxx.h	Tue Feb 19 18:10:58 2002
> +++ linux-2.5.6-pre2/drivers/scsi/3w-xxxx.h	Wed Feb 27 11:53:52 2002
> @@ -6,7 +6,7 @@
>     		     Arnaldo Carvalho de Melo <acme@conectiva.com.br>
>                       Brad Strand <linux@3ware.com>
> 
> -   Copyright (C) 1999-2001 3ware Inc.
> +   Copyright (C) 1999-2002 3ware Inc.
> 
>     Kernel compatablity By:	Andre Hedrick <andre@suse.com>
>     Non-Copyright (C) 2000	Andre Hedrick <andre@suse.com>
> @@ -62,7 +62,7 @@
>  static char *tw_aen_string[] = {
>  	"AEN queue empty",                      // 0x000
>  	"Soft reset occurred",                  // 0x001
> -	"Mirorr degraded: Unit #",              // 0x002
> +	"Unit degraded: Unit #",                // 0x002
>  	"Controller error",                     // 0x003
>  	"Rebuild failed: Unit #",               // 0x004
>  	"Rebuild complete: Unit #",             // 0x005
> @@ -90,10 +90,36 @@
>  	"DCB unsupported version: Port #",      // 0x028
>  	"Verify started: Unit #",               // 0x029
>  	"Verify failed: Port #",                // 0x02A
> -	"Verify complete: Unit #"               // 0x02B
> +	"Verify complete: Unit #",              // 0x02B
> +	"Overwrote bad sector during rebuild: Port #",  //0x2C
> +	"Encountered bad sector during rebuild: Port #" //0x2D
>  };
> 
> -#define TW_AEN_STRING_MAX                      0x02C
> +#define TW_AEN_STRING_MAX                      0x02E
> +
> +/*
> +   Sense key lookup table
> +   Format: ESDC/flags,SenseKey,AdditionalSenseCode,AdditionalSenseCodeQualifier
> +*/
> +static unsigned char tw_sense_table[][4] =
> +{
> +  /* Codes for newer firmware */
> +                            // ATA Error                    SCSI Error
> +  {0x01, 0x03, 0x13, 0x00}, // Address mark not found       Address mark not found for data field
> +  {0x04, 0x0b, 0x00, 0x00}, // Aborted command              Aborted command
> +  {0x10, 0x0b, 0x14, 0x00}, // ID not found                 Recorded entity not found
> +  {0x40, 0x03, 0x11, 0x00}, // Uncorrectable ECC error      Unrecovered read error
> +  {0x61, 0x04, 0x00, 0x00}, // Device fault                 Hardware error
> +  {0x84, 0x0b, 0x47, 0x00}, // Data CRC error               SCSI parity error
> +  {0xd0, 0x0b, 0x00, 0x00}, // Device busy                  Aborted command
> +  {0xd1, 0x0b, 0x00, 0x00}, // Device busy                  Aborted command
> +
> +  /* Codes for older firmware */
> +                            // 3ware Error                  SCSI Error
> +  {0x09, 0x0b, 0x00, 0x00}, // Unrecovered disk error       Aborted command
> +  {0x37, 0x0b, 0x04, 0x00}, // Unit offline                 Logical unit not ready
> +  {0x51, 0x0b, 0x00, 0x00}  // Unspecified                  Aborted command
> +};
> 
>  /* Control register bit definitions */
>  #define TW_CONTROL_CLEAR_HOST_INTERRUPT	       0x00080000
> @@ -108,6 +134,7 @@
>  #define TW_CONTROL_DISABLE_INTERRUPTS	       0x00000040
>  #define TW_CONTROL_ISSUE_HOST_INTERRUPT	       0x00000020
>  #define TW_CONTROL_CLEAR_PARITY_ERROR          0x00800000
> +#define TW_CONTROL_CLEAR_PCI_ABORT             0x00100000
> 
>  /* Status register bit definitions */
>  #define TW_STATUS_MAJOR_VERSION_MASK	       0xF0000000
> @@ -140,6 +167,7 @@
>  #define TW_DEVICE_ID2 (0x1001)  /* 7000 series controller */
>  #define TW_NUMDEVICES 2
>  #define TW_PCI_CLEAR_PARITY_ERRORS 0xc100
> +#define TW_PCI_CLEAR_PCI_ABORT     0x2000
> 
>  /* Command packet opcodes */
>  #define TW_OP_NOP	      0x0
> @@ -153,6 +181,7 @@
>  #define TW_OP_AEN_LISTEN      0x1c
>  #define TW_CMD_PACKET         0x1d
>  #define TW_ATA_PASSTHRU       0x1e
> +#define TW_CMD_PACKET_WITH_DATA 0x1f
> 
>  /* Asynchronous Event Notification (AEN) Codes */
>  #define TW_AEN_QUEUE_EMPTY       0x0000
> @@ -169,7 +198,8 @@
>  #define TW_AEN_SBUF_FAIL         0x0024
> 
>  /* Misc defines */
> -#define TW_ALIGNMENT			      0x200 /* 16 D-WORDS */
> +#define TW_ALIGNMENT_6000		      64 /* 64 bytes */
> +#define TW_ALIGNMENT_7000                     4  /* 4 bytes */
>  #define TW_MAX_UNITS			      16
>  #define TW_COMMAND_ALIGNMENT_MASK	      0x1ff
>  #define TW_INIT_MESSAGE_CREDITS		      0x100
> @@ -179,7 +209,6 @@
>  #define TW_ATA_PASS_SGL_MAX                   60
>  #define TW_MAX_PASSTHRU_BYTES                 4096
>  #define TW_Q_LENGTH			      256
> -#define TW_MAX_BOUNCEBUF                      16
>  #define TW_Q_START			      0
>  #define TW_MAX_SLOT			      32
>  #define TW_MAX_PCI_BUSES		      255
> @@ -191,12 +220,9 @@
>  #define TW_MAX_AEN_TRIES                      100
>  #define TW_UNIT_ONLINE                        1
>  #define TW_IN_INTR                            1
> -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,7)
>  #define TW_MAX_SECTORS                        256
> -#else
> -#define TW_MAX_SECTORS                        128
> -#endif
>  #define TW_AEN_WAIT_TIME                      1000
> +#define TW_IOCTL_WAIT_TIME                    (1 * HZ) /* 1 second */
> 
>  /* Macros */
>  #define TW_STATUS_ERRORS(x) \
> @@ -262,7 +288,6 @@
>  } TW_Command;
> 
>  typedef struct TAG_TW_Ioctl {
> -	int buffer;
>  	unsigned char opcode;
>  	unsigned short table_id;
>  	unsigned char parameter_id;
> @@ -345,11 +370,8 @@
>  	TW_Registers		registers;
>  	u32			*alignment_virtual_address[TW_Q_LENGTH];
>  	u32			alignment_physical_address[TW_Q_LENGTH];
> -	u32			*bounce_buffer[TW_Q_LENGTH];
>  	int			is_unit_present[TW_MAX_UNITS];
> -	int			is_raid_five[TW_MAX_UNITS];
>  	int			num_units;
> -	int			num_raid_five;
>  	u32			*command_packet_virtual_address[TW_Q_LENGTH];
>  	u32			command_packet_physical_address[TW_Q_LENGTH];
>  	struct pci_dev		*tw_pci_dev;
> @@ -381,22 +403,24 @@
>  	unsigned char		aen_head;
>  	unsigned char		aen_tail;
>  	long			flags; /* long req'd for set_bit --RR */
> +	char			*ioctl_data[TW_Q_LENGTH];
>  } TW_Device_Extension;
> 
>  /* Function prototypes */
>  int tw_aen_complete(TW_Device_Extension *tw_dev, int request_id);
>  int tw_aen_drain_queue(TW_Device_Extension *tw_dev);
>  int tw_aen_read_queue(TW_Device_Extension *tw_dev, int request_id);
> -int tw_allocate_memory(TW_Device_Extension *tw_dev, int request_id, int size, int which);
> +int tw_allocate_memory(TW_Device_Extension *tw_dev, int size, int which);
>  int tw_check_bits(u32 status_reg_value);
>  int tw_check_errors(TW_Device_Extension *tw_dev);
>  void tw_clear_attention_interrupt(TW_Device_Extension *tw_dev);
>  void tw_clear_host_interrupt(TW_Device_Extension *tw_dev);
>  void tw_decode_bits(TW_Device_Extension *tw_dev, u32 status_reg_value);
> -void tw_decode_error(TW_Device_Extension *tw_dev, unsigned char status, unsigned char flags, unsigned char unit);
> +void tw_decode_sense(TW_Device_Extension *tw_dev, int request_id, int fill_sense);
>  void tw_disable_interrupts(TW_Device_Extension *tw_dev);
>  int tw_empty_response_que(TW_Device_Extension *tw_dev);
>  void tw_enable_interrupts(TW_Device_Extension *tw_dev);
> +void tw_enable_and_clear_interrupts(TW_Device_Extension *tw_dev);
>  int tw_findcards(Scsi_Host_Template *tw_host);
>  void tw_free_device_extension(TW_Device_Extension *tw_dev);
>  int tw_initconnection(TW_Device_Extension *tw_dev, int message_credits);
> 
> 
> -
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: 3ware driver update for 2.5.6-pre2 (new DMA mapping)
  2002-02-27 22:58 ` Jeff V. Merkey
@ 2002-02-27 23:28   ` Jeff V. Merkey
  0 siblings, 0 replies; 4+ messages in thread
From: Jeff V. Merkey @ 2002-02-27 23:28 UTC (permalink / raw)
  To: adam@mailhost.nmt.edu; +Cc: linux-kernel

On Wed, Feb 27, 2002 at 03:58:19PM -0700, Jeff V. Merkey wrote:

Adam,

FYI.  We are on a production 2.4.X tree with your drivers, so this is the
tree we need to test with.  Having the patch on 2.5.X is great but 
not a production kernel.  we need these bugs fixed on 2.4.18 also.  I 
have seen the AEN drain bug on 2.4.18 as well.

Please advise,

Thanks

Jeff

> 
> 
> HELLO ADAM,
> 
> The fixes you posted for the 3Ware drivers (AEN drain).  Would they affect 
> the problems I reported this morning.
> 
> Thanks
> 
> Jeff
> 
> 
> 
> On Wed, Feb 27, 2002 at 02:45:04PM -0700, adam@mailhost.nmt.edu wrote:
> > Alan,
> > 
> > Please apply this patch for kernel 2.5.6-pre2 for the 3ware driver to
> > support the new DMA mapping code, and several other fixes.
> > 
> > Thanks.
> > 
> > --
> > Adam Radford
> > Software Engineer
> > 3ware, Inc.
> > 
> > diff -Naur linux-2.5.6-pre1/drivers/scsi/3w-xxxx.c linux-2.5.6-pre2/drivers/scsi/3w-xxxx.c
> > --- linux-2.5.6-pre1/drivers/scsi/3w-xxxx.c	Tue Feb 19 18:11:00 2002
> > +++ linux-2.5.6-pre2/drivers/scsi/3w-xxxx.c	Wed Feb 27 11:53:49 2002
> > @@ -6,7 +6,7 @@
> >     		     Arnaldo Carvalho de Melo <acme@conectiva.com.br>
> >                       Brad Strand <linux@3ware.com>
> > 
> > -   Copyright (C) 1999-2001 3ware Inc.
> > +   Copyright (C) 1999-2002 3ware Inc.
> > 
> >     Kernel compatablity By: 	Andre Hedrick <andre@suse.com>
> >     Non-Copyright (C) 2000	Andre Hedrick <andre@suse.com>
> > @@ -106,17 +106,41 @@
> >                   Add entire aen code string list.
> >     1.02.00.010 - Cleanup queueing code, fix jbod thoughput.
> >                   Fix get_param for specific units.
> > +   1.02.00.011 - Fix bug in tw_aen_complete() where aen's could be lost.
> > +                 Fix tw_aen_drain_queue() to display useful info at init.
> > +                 Set tw_host->max_id for 12 port cards.
> > +                 Add ioctl support for raw command packet post from userspace
> > +                 with sglist fragments (parameter and io).
> > +   1.02.00.012 - Fix read capacity to under report by 1 sector to fix get
> > +                 last sector ioctl.
> > +   1.02.00.013 - Fix bug where more AEN codes weren't coming out during
> > +                 driver initialization.
> > +                 Improved handling of PCI aborts.
> > +   1.02.00.014 - Fix bug in tw_findcards() where AEN code could be lost.
> > +                 Increase timeout in tw_aen_drain_queue() to 30 seconds.
> > +   1.02.00.015 - Re-write raw command post with data ioctl method.
> > +                 Remove raid5 bounce buffers for raid5 for 6XXX for kernel 2.5
> > +                 Add tw_map/unmap_scsi_sg/single_data() for kernel 2.5
> > +                 Replace io_request_lock with host_lock for kernel 2.5
> > +                 Set max_cmd_len to 16 for 3dm for kernel 2.5
> > +   1.02.00.016 - Set host->max_sectors back up to 256.
> > +   1.02.00.017 - Modified pci parity error handling/clearing from config space
> > +                 during initialization.
> > +   1.02.00.018 - Better handling of request sense opcode and sense information
> > +                 for failed commands.  Add tw_decode_sense().
> > +                 Replace all mdelay()'s with scsi_sleep().
> > +   1.02.00.019 - Revert mdelay's and scsi_sleep's, this caused problems on
> > +                 some SMP systems.
> > +   1.02.00.020 - Add pci_set_dma_mask(), rewrite kmalloc()/virt_to_bus() to
> > +                 pci_alloc/free_consistent().
> >  */
> > 
> > -#error Please convert me to Documentation/DMA-mapping.txt
> > -
> >  #include <linux/module.h>
> > 
> >  MODULE_AUTHOR ("3ware Inc.");
> >  MODULE_DESCRIPTION ("3ware Storage Controller Linux Driver");
> >  MODULE_LICENSE("GPL");
> > 
> > -
> >  #include <linux/kernel.h>
> >  #include <linux/pci.h>
> >  #include <linux/time.h>
> > @@ -148,14 +172,17 @@
> >  static void tw_copy_mem_info(TW_Info *info, char *data, int len);
> >  static void tw_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
> >  static int tw_halt(struct notifier_block *nb, ulong event, void *buf);
> > +static int tw_map_scsi_sg_data(struct pci_dev *pdev, Scsi_Cmnd *cmd);
> > +static u32 tw_map_scsi_single_data(struct pci_dev *pdev, Scsi_Cmnd *cmd);
> > +static void tw_unmap_scsi_data(struct pci_dev *pdev, Scsi_Cmnd *cmd);
> > 
> >  /* Notifier block to get a notify on system shutdown/halt/reboot */
> >  static struct notifier_block tw_notifier = {
> > -  tw_halt, NULL, 0
> > +	tw_halt, NULL, 0
> >  };
> > 
> >  /* Globals */
> > -char *tw_driver_version="1.02.00.010";
> > +char *tw_driver_version="1.02.00.020";
> >  TW_Device_Extension *tw_device_extension_list[TW_MAX_SLOT];
> >  int tw_device_extension_count = 0;
> > 
> > @@ -166,6 +193,7 @@
> >  {
> >  	TW_Param *param;
> >  	unsigned short aen;
> > +	int error = 0;
> > 
> >  	dprintk(KERN_WARNING "3w-xxxx: tw_aen_complete()\n");
> >  	if (tw_dev->alignment_virtual_address[request_id] == NULL) {
> > @@ -184,12 +212,15 @@
> >  			if ((tw_aen_string[aen & 0xff][strlen(tw_aen_string[aen & 0xff])-1]) == '#') {
> >  				printk(KERN_WARNING "3w-xxxx: scsi%d: AEN: %s%d.\n", tw_dev->host->host_no, tw_aen_string[aen & 0xff], aen >> 8);
> >  			} else {
> > -				printk(KERN_WARNING "3w-xxxx: scsi%d: AEN: %s.\n", tw_dev->host->host_no, tw_aen_string[aen & 0xff]);
> > +				if (aen != 0x0)
> > +					printk(KERN_WARNING "3w-xxxx: scsi%d: AEN: %s.\n", tw_dev->host->host_no, tw_aen_string[aen & 0xff]);
> >  			}
> > -		} else
> > +		} else {
> >  			printk(KERN_WARNING "3w-xxxx: scsi%d: Received AEN %d.\n", tw_dev->host->host_no, aen);
> > +		}
> >  	}
> > -	tw_dev->aen_count++;
> > +	if (aen != 0x0)
> > +		tw_dev->aen_count++;
> > 
> >  	/* Now queue the code */
> >  	tw_dev->aen_queue[tw_dev->aen_tail] = aen;
> > @@ -205,8 +236,18 @@
> >  			tw_dev->aen_head = tw_dev->aen_head + 1;
> >  		}
> >  	}
> > -	tw_dev->state[request_id] = TW_S_COMPLETED;
> > -	tw_state_request_finish(tw_dev, request_id);
> > +
> > +	if (aen != TW_AEN_QUEUE_EMPTY) {
> > +		error = tw_aen_read_queue(tw_dev, request_id);
> > +		if (error) {
> > +			printk(KERN_WARNING "3w-xxxx: scsi%d: Error completing AEN.\n", tw_dev->host->host_no);
> > +			tw_dev->state[request_id] = TW_S_COMPLETED;
> > +			tw_state_request_finish(tw_dev, request_id);
> > +		}
> > +	} else {
> > +		tw_dev->state[request_id] = TW_S_COMPLETED;
> > +		tw_state_request_finish(tw_dev, request_id);
> > +	}
> > 
> >  	return 0;
> >  } /* End tw_aen_complete() */
> > @@ -237,10 +278,11 @@
> >  	status_reg_addr = tw_dev->registers.status_reg_addr;
> >  	response_que_addr = tw_dev->registers.response_que_addr;
> > 
> > -	if (tw_poll_status(tw_dev, TW_STATUS_ATTENTION_INTERRUPT, 15)) {
> > +	if (tw_poll_status(tw_dev, TW_STATUS_ATTENTION_INTERRUPT, 30)) {
> >  		dprintk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): No attention interrupt for card %d.\n", tw_device_extension_count);
> >  		return 1;
> >  	}
> > +	tw_clear_attention_interrupt(tw_dev);
> > 
> >  	/* Initialize command packet */
> >  	if (tw_dev->command_packet_virtual_address[request_id] == NULL) {
> > @@ -288,7 +330,7 @@
> >  	do {
> >  		/* Post command packet */
> >  		outl(command_que_value, command_que_addr);
> > -
> > +
> >  		/* Now poll for completion */
> >  		for (i=0;i<imax;i++) {
> >  			mdelay(5);
> > @@ -311,8 +353,7 @@
> >  				if (command_packet->status != 0) {
> >  					if (command_packet->flags != TW_AEN_TABLE_UNDEFINED) {
> >  						/* Bad response */
> > -						dprintk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): Bad response, status = 0x%x, flags = 0x%x.\n", command_packet->status, command_packet->flags);
> > -						tw_decode_error(tw_dev, command_packet->status, command_packet->flags, command_packet->byte3.unit);
> > +						tw_decode_sense(tw_dev, request_id, 0);
> >  						return 1;
> >  					} else {
> >  						/* We know this is a 3w-1x00, and doesn't support aen's */
> > @@ -326,7 +367,7 @@
> >  				queue = 0;
> >  				switch (aen_code) {
> >  					case TW_AEN_QUEUE_EMPTY:
> > -						dprintk(KERN_NOTICE "3w-xxxx: tw_aen_drain_queue(): Found TW_AEN_QUEUE_EMPTY.\n");
> > +						dprintk(KERN_WARNING "3w-xxxx: AEN: %s.\n", tw_aen_string[aen & 0xff]);
> >  						if (first_reset != 1) {
> >  							continue;
> >  						} else {
> > @@ -334,51 +375,28 @@
> >  						}
> >  						break;
> >  					case TW_AEN_SOFT_RESET:
> > -						dprintk(KERN_NOTICE "3w-xxxx: tw_aen_drain_queue(): Found TW_AEN_SOFT_RESET.\n");
> >  						if (first_reset == 0) {
> >  							first_reset = 1;
> >  						} else {
> > +							printk(KERN_WARNING "3w-xxxx: AEN: %s.\n", tw_aen_string[aen & 0xff]);
> > +							tw_dev->aen_count++;
> >  							queue = 1;
> >  						}
> >  						break;
> > -					case TW_AEN_DEGRADED_MIRROR:
> > -						dprintk(KERN_NOTICE "3w-xxxx: tw_aen_drain_queue(): Found TW_AEN_DEGRADED_MIRROR.\n");
> > -						queue = 1;
> > -						break;
> > -					case TW_AEN_CONTROLLER_ERROR:
> > -						dprintk(KERN_NOTICE "3w-xxxx: tw_aen_drain_queue(): Found TW_AEN_CONTROLLER_ERROR.\n");
> > -						queue = 1;
> > -						break;
> > -					case TW_AEN_REBUILD_FAIL:
> > -						dprintk(KERN_NOTICE "3w-xxxx: tw_aen_drain_queue(): Found TW_AEN_REBUILD_FAIL.\n");
> > -						queue = 1;
> > -						break;
> > -					case TW_AEN_REBUILD_DONE:
> > -						dprintk(KERN_NOTICE "3w-xxxx: tw_aen_drain_queue(): Found TW_AEN_REBUILD_DONE.\n");
> > -						queue = 1;
> > -						break;
> > -					case TW_AEN_QUEUE_FULL:
> > -						dprintk(KERN_NOTICE "3w-xxxx: tw_aen_drain_queue(): Found TW_AEN_QUEUE_FULL.\n");
> > -						queue = 1;
> > -						break;
> > -					case TW_AEN_APORT_TIMEOUT:
> > -						printk(KERN_WARNING "3w-xxxx: Received drive timeout AEN on port %d, check drive and drive cables.\n", aen >> 8);
> > -						queue = 1;
> > -						break;
> > -					case TW_AEN_DRIVE_ERROR:
> > -						printk(KERN_WARNING "3w-xxxx: Received drive error AEN on port %d, check/replace cabling, or possible bad drive.\n", aen >> 8);
> > -						queue = 1;
> > -						break;
> > -					case TW_AEN_SMART_FAIL:
> > -						printk(KERN_WARNING "3w-xxxx: Received S.M.A.R.T. threshold AEN on port %d, check drive/cooling, or possible bad drive.\n", aen >> 8);
> > -						queue = 1;
> > -						break;
> > -					case TW_AEN_SBUF_FAIL:
> > -						printk(KERN_WARNING "3w-xxxx: Received SBUF integrity check failure AEN, reseat card or bad card.\n");
> > -						queue = 1;
> > -						break;
> >  					default:
> > -						dprintk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): Unknown AEN code 0x%x.\n", aen_code);
> > +						if (aen == 0x0ff) {
> > +							printk(KERN_WARNING "3w-xxxx: AEN: AEN queue overflow.\n");
> > +						} else {
> > +							if ((aen & 0x0ff) < TW_AEN_STRING_MAX) {
> > +								if ((tw_aen_string[aen & 0xff][strlen(tw_aen_string[aen & 0xff])-1]) == '#') {
> > +									printk(KERN_WARNING "3w-xxxx: AEN: %s%d.\n", tw_aen_string[aen & 0xff], aen >> 8);
> > +								} else {
> > +									printk(KERN_WARNING "3w-xxxx: AEN: %s.\n", tw_aen_string[aen & 0xff]);
> > +								}
> > +							} else
> > +								printk(KERN_WARNING "3w-xxxx: Received AEN %d.\n", aen);
> > +						}
> > +						tw_dev->aen_count++;
> >  						queue = 1;
> >  				}
> > 
> > @@ -488,40 +506,44 @@
> >  	return 0;
> >  } /* End tw_aen_read_queue() */
> > 
> > -/* This function will allocate memory and check if it is 16 d-word aligned */
> > -int tw_allocate_memory(TW_Device_Extension *tw_dev, int request_id, int size, int which)
> > +/* This function will allocate memory */
> > +int tw_allocate_memory(TW_Device_Extension *tw_dev, int size, int which)
> >  {
> > -	u32 *virt_addr = kmalloc(size, GFP_ATOMIC);
> > +	int i;
> > +	dma_addr_t dma_handle;
> > +	u32 *cpu_addr = NULL;
> > 
> >  	dprintk(KERN_NOTICE "3w-xxxx: tw_allocate_memory()\n");
> > 
> > -	if (!virt_addr) {
> > -		printk(KERN_WARNING "3w-xxxx: tw_allocate_memory(): kmalloc() failed.\n");
> > -		return 1;
> > -	}
> > +	for (i=0;i<TW_Q_LENGTH;i++) {
> > +		cpu_addr = pci_alloc_consistent(tw_dev->tw_pci_dev, size, &dma_handle);
> > +		if (cpu_addr == NULL) {
> > +			printk(KERN_WARNING "3w-xxxx: pci_alloc_consistent() failed.\n");
> > +			return 1;
> > +		}
> > 
> > -	if ((u32)virt_addr % TW_ALIGNMENT) {
> > -		kfree(virt_addr);
> > -		printk(KERN_WARNING "3w-xxxx: tw_allocate_memory(): Found unaligned address.\n");
> > -		return 1;
> > -	}
> > +		if ((u32)cpu_addr % (tw_dev->tw_pci_dev->device == TW_DEVICE_ID ? TW_ALIGNMENT_6000 : TW_ALIGNMENT_7000)) {
> > +			printk(KERN_WARNING "3w-xxxx: Couldn't allocate correctly aligned memory.\n");
> > +			return 1;
> > +		}
> > 
> > -	switch(which) {
> > -	case 0:
> > -		tw_dev->command_packet_virtual_address[request_id] = virt_addr;
> > -		tw_dev->command_packet_physical_address[request_id] = virt_to_bus(virt_addr);
> > -		break;
> > -	case 1:
> > -		tw_dev->alignment_virtual_address[request_id] = virt_addr;
> > -		tw_dev->alignment_physical_address[request_id] = virt_to_bus(virt_addr);
> > -		break;
> > -	case 2:
> > -		tw_dev->bounce_buffer[request_id] = virt_addr;
> > -		break;
> > -	default:
> > -		printk(KERN_WARNING "3w-xxxx: tw_allocate_memory(): case slip in tw_allocate_memory()\n");
> > -		return 1;
> > +		switch(which) {
> > +		case 0:
> > +			tw_dev->command_packet_virtual_address[i] = cpu_addr;
> > +			tw_dev->command_packet_physical_address[i] = dma_handle;
> > +			memset(tw_dev->command_packet_virtual_address[i], 0, size);
> > +			break;
> > +		case 1:
> > +			tw_dev->alignment_virtual_address[i] = cpu_addr;
> > +			tw_dev->alignment_physical_address[i] = dma_handle;
> > +			memset(tw_dev->alignment_virtual_address[i], 0, size);
> > +			break;
> > +		default:
> > +			printk(KERN_WARNING "3w-xxxx: tw_allocate_memory(): case slip in tw_allocate_memory()\n");
> > +			return 1;
> > +		}
> >  	}
> > +
> >  	return 0;
> >  } /* End tw_allocate_memory() */
> > 
> > @@ -548,8 +570,10 @@
> >  	status_reg_addr = tw_dev->registers.status_reg_addr;
> >  	status_reg_value = inl(status_reg_addr);
> > 
> > -	if (TW_STATUS_ERRORS(status_reg_value) || tw_check_bits(status_reg_value))
> > +	if (TW_STATUS_ERRORS(status_reg_value) || tw_check_bits(status_reg_value)) {
> > +		tw_decode_bits(tw_dev, status_reg_value);
> >  		return 1;
> > +	}
> > 
> >  	return 0;
> >  } /* End tw_check_errors() */
> > @@ -614,37 +638,62 @@
> >  	dprintk(KERN_WARNING "3w-xxxx: tw_decode_bits()\n");
> >  	switch (status_reg_value & TW_STATUS_UNEXPECTED_BITS) {
> >  	case TW_STATUS_PCI_PARITY_ERROR:
> > -		printk(KERN_WARNING "3w-xxxx: PCI Parity Error: Reseat card, move card, or buggy device on the bus.\n");
> > +		printk(KERN_WARNING "3w-xxxx: PCI Parity Error: clearing.\n");
> >  		outl(TW_CONTROL_CLEAR_PARITY_ERROR, tw_dev->registers.control_reg_addr);
> > -		pci_write_config_word(tw_dev->tw_pci_dev, PCI_STATUS, TW_PCI_CLEAR_PARITY_ERRORS);
> >  		break;
> >  	case TW_STATUS_MICROCONTROLLER_ERROR:
> >  		printk(KERN_WARNING "3w-xxxx: Microcontroller Error.\n");
> >  		break;
> > +	case TW_STATUS_PCI_ABORT:
> > +		printk(KERN_WARNING "3w-xxxx: PCI Abort: clearing.\n");
> > +		outl(TW_CONTROL_CLEAR_PCI_ABORT, tw_dev->registers.control_reg_addr);
> > +		pci_write_config_word(tw_dev->tw_pci_dev, PCI_STATUS, TW_PCI_CLEAR_PCI_ABORT);
> > +		break;
> >    }
> >  } /* End tw_decode_bits() */
> > 
> > -/* This function will print readable messages from flags and status values */
> > -void tw_decode_error(TW_Device_Extension *tw_dev, unsigned char status, unsigned char flags, unsigned char unit)
> > +/* This function will return valid sense buffer information for failed cmds */
> > +void tw_decode_sense(TW_Device_Extension *tw_dev, int request_id, int fill_sense)
> >  {
> > -	dprintk(KERN_WARNING "3w-xxxx: tw_decode_error()\n");
> > -	switch (status) {
> > -	case 0xc7:
> > -		switch (flags) {
> > -		case 0x1b:
> > -			printk(KERN_WARNING "3w-xxxx: scsi%d: Drive timeout on unit %d, check drive and drive cables.\n", tw_dev->host->host_no, unit);
> > -			break;
> > -		case 0x51:
> > -			printk(KERN_WARNING "3w-xxxx: scsi%d: Unrecoverable drive error on unit %d, check/replace cabling, or possible bad drive.\n", tw_dev->host->host_no, unit);
> > -			break;
> > -		default:
> > -			printk(KERN_WARNING "3w-xxxx: scsi%d: Controller error: status = 0x%x, flags = 0x%x, unit #%d.\n", tw_dev->host->host_no, status, flags, unit);
> > +	int i, found=0;
> > +	TW_Command *command;
> > +
> > +        dprintk(KERN_WARNING "3w-xxxx: tw_decode_sense()\n");
> > +	command = (TW_Command *)tw_dev->command_packet_virtual_address[request_id];
> > +
> > +	printk(KERN_WARNING "3w-xxxx: scsi%d: Command failed: status = 0x%x, flags = 0x%x, unit #%d.\n", tw_dev->host->host_no, command->status, command->flags, command->byte3.unit);
> > +
> > +	/* Attempt to return intelligent sense information */
> > +	if (fill_sense) {
> > +		if ((command->status == 0xc7) || (command->status == 0xcb)) {
> > +			for (i=0;i<(sizeof(tw_sense_table)/sizeof(tw_sense_table[0]));i++) {
> > +				if (command->flags == tw_sense_table[i][0]) {
> > +					found=1;
> > +
> > +					/* Valid bit and 'current errors' */
> > +					tw_dev->srb[request_id]->sense_buffer[0] = (0x1 << 7 | 0x70);
> > +
> > +					/* Sense key */
> > +					tw_dev->srb[request_id]->sense_buffer[2] = tw_sense_table[i][1];
> > +
> > +					/* Additional sense length */
> > +					tw_dev->srb[request_id]->sense_buffer[7] = 0xa; /* 10 bytes */
> > +
> > +					/* Additional sense code */
> > +					tw_dev->srb[request_id]->sense_buffer[12] = tw_sense_table[i][2];
> > +
> > +					/* Additional sense code qualifier */
> > +					tw_dev->srb[request_id]->sense_buffer[13] = tw_sense_table[i][3];
> > +
> > +					tw_dev->srb[request_id]->result = (DID_OK << 16) | (CHECK_CONDITION << 1);
> > +				}
> > +			}
> >  		}
> > -		break;
> > -	default:
> > -		printk(KERN_WARNING "3w-xxxx: scsi%d: Controller error: status = 0x%x, flags = 0x%x, unit #%d.\n", tw_dev->host->host_no, status, flags, unit);
> > +		/* If no table match, error so we get a reset */
> > +		if (found == 0)
> > +			tw_dev->srb[request_id]->result = (DID_RESET << 16);
> >  	}
> > -} /* End tw_decode_error() */
> > +} /* End tw_decode_sense() */
> > 
> >  /* This function will disable interrupts on the controller */
> >  void tw_disable_interrupts(TW_Device_Extension *tw_dev)
> > @@ -691,11 +740,22 @@
> >  	u32 control_reg_value, control_reg_addr;
> > 
> >  	control_reg_addr = tw_dev->registers.control_reg_addr;
> > +	control_reg_value = (TW_CONTROL_ENABLE_INTERRUPTS |
> > +			     TW_CONTROL_UNMASK_RESPONSE_INTERRUPT);
> > +	outl(control_reg_value, control_reg_addr);
> > +} /* End tw_enable_interrupts() */
> > +
> > +/* This function will enable interrupts on the controller */
> > +void tw_enable_and_clear_interrupts(TW_Device_Extension *tw_dev)
> > +{
> > +	u32 control_reg_value, control_reg_addr;
> > +
> > +	control_reg_addr = tw_dev->registers.control_reg_addr;
> >  	control_reg_value = (TW_CONTROL_CLEAR_ATTENTION_INTERRUPT |
> >  			     TW_CONTROL_UNMASK_RESPONSE_INTERRUPT |
> >  			     TW_CONTROL_ENABLE_INTERRUPTS);
> >  	outl(control_reg_value, control_reg_addr);
> > -} /* End tw_enable_interrupts() */
> > +} /* End tw_enable_and_clear_interrupts() */
> > 
> >  /* This function will find and initialize all cards */
> >  int tw_findcards(Scsi_Host_Template *tw_host)
> > @@ -716,6 +776,13 @@
> >  		while ((tw_pci_dev = pci_find_device(TW_VENDOR_ID, device[i], tw_pci_dev))) {
> >  			if (pci_enable_device(tw_pci_dev))
> >  				continue;
> > +
> > +			/* We only need 32-bit addressing for 5,6,7xxx cards */
> > +			if (pci_set_dma_mask(tw_pci_dev, 0xffffffff)) {
> > +				printk(KERN_WARNING "3w-xxxx: No suitable DMA available.\n");
> > +				continue;
> > +			}
> > +
> >  			/* Prepare temporary device extension */
> >  			tw_dev=(TW_Device_Extension *)kmalloc(sizeof(TW_Device_Extension), GFP_ATOMIC);
> >  			if (tw_dev == NULL) {
> > @@ -724,6 +791,9 @@
> >  			}
> >  			memset(tw_dev, 0, sizeof(TW_Device_Extension));
> > 
> > +			/* Save pci_dev struct to device extension */
> > +			tw_dev->tw_pci_dev = tw_pci_dev;
> > +
> >  			error = tw_initialize_device_extension(tw_dev);
> >  			if (error) {
> >  				printk(KERN_WARNING "3w-xxxx: tw_findcards(): Couldn't initialize device extension for card %d.\n", numcards);
> > @@ -738,8 +808,6 @@
> >  			tw_dev->registers.status_reg_addr = pci_resource_start(tw_pci_dev, 0) + 0x4;
> >  			tw_dev->registers.command_que_addr = pci_resource_start(tw_pci_dev, 0) + 0x8;
> >  			tw_dev->registers.response_que_addr = pci_resource_start(tw_pci_dev, 0) + 0xC;
> > -			/* Save pci_dev struct to device extension */
> > -			tw_dev->tw_pci_dev = tw_pci_dev;
> > 
> >  			/* Check for errors and clear them */
> >  			status_reg_value = inl(tw_dev->registers.status_reg_addr);
> > @@ -763,14 +831,14 @@
> > 
> >  				error = tw_aen_drain_queue(tw_dev);
> >  				if (error) {
> > -					printk(KERN_WARNING "3w-xxxx: tw_findcards(): No attention interrupt for card %d.\n", numcards);
> > +					printk(KERN_WARNING "3w-xxxx: AEN drain failed for card %d.\n", numcards);
> >  					tries++;
> >  					continue;
> >  				}
> > 
> >  				/* Check for controller errors */
> >  				if (tw_check_errors(tw_dev)) {
> > -					printk(KERN_WARNING "3w-xxxx: tw_findcards(): Controller errors found, soft resetting card %d.\n", numcards);
> > +					printk(KERN_WARNING "3w-xxxx: Controller errors found, retrying for card %d.\n", numcards);
> >  					tries++;
> >  					continue;
> >  				}
> > @@ -778,7 +846,7 @@
> >  				/* Empty the response queue */
> >  				error = tw_empty_response_que(tw_dev);
> >  				if (error) {
> > -					printk(KERN_WARNING "3w-xxxx: tw_findcards(): Couldn't empty response queue for card %d.\n", numcards);
> > +					printk(KERN_WARNING "3w-xxxx: Couldn't empty response queue, retrying for card %d.\n", numcards);
> >  					tries++;
> >  					continue;
> >  				}
> > @@ -788,7 +856,7 @@
> >  			}
> > 
> >  			if (tries >= TW_MAX_RESET_TRIES) {
> > -				printk(KERN_WARNING "3w-xxxx: tw_findcards(): Controller error or no attention interrupt: giving up for card %d.\n", numcards);
> > +				printk(KERN_WARNING "3w-xxxx: Controller errors, card not responding, check all cabling for card %d.\n", numcards);
> >  				tw_free_device_extension(tw_dev);
> >  				kfree(tw_dev);
> >  				continue;
> > @@ -818,7 +886,7 @@
> > 
> >  			error = tw_initconnection(tw_dev, TW_INIT_MESSAGE_CREDITS);
> >  			if (error) {
> > -				printk(KERN_WARNING "3w-xxxx: tw_findcards(): Couldn't initconnection for card %d.\n", numcards);
> > +				printk(KERN_WARNING "3w-xxxx: Connection initialization failed for card %d.\n", numcards);
> >  				release_region((tw_dev->tw_pci_dev->resource[0].start), TW_IO_ADDRESS_RANGE);
> >  				tw_free_device_extension(tw_dev);
> >  				kfree(tw_dev);
> > @@ -827,29 +895,28 @@
> > 
> >  			/* Calculate max cmds per lun, and setup queues */
> >  			if (tw_dev->num_units > 0) {
> > -				if ((tw_dev->num_raid_five > 0) && (tw_dev->tw_pci_dev->device == TW_DEVICE_ID)) {
> > -					tw_host->cmd_per_lun = (TW_MAX_BOUNCEBUF-1)/tw_dev->num_units;
> > -					tw_dev->free_head = TW_Q_START;
> > -					tw_dev->free_tail = TW_MAX_BOUNCEBUF - 1;
> > -					tw_dev->free_wrap = TW_MAX_BOUNCEBUF - 1;
> > -				} else {
> > -					tw_host->cmd_per_lun = (TW_Q_LENGTH-1)/tw_dev->num_units;
> > -					tw_dev->free_head = TW_Q_START;
> > -					tw_dev->free_tail = TW_Q_LENGTH - 1;
> > -					tw_dev->free_wrap = TW_Q_LENGTH - 1;
> > -				}
> > +				tw_host->cmd_per_lun = (TW_Q_LENGTH-1)/tw_dev->num_units;
> > +				tw_dev->free_head = TW_Q_START;
> > +				tw_dev->free_tail = TW_Q_LENGTH - 1;
> > +				tw_dev->free_wrap = TW_Q_LENGTH - 1;
> >  			}
> > 
> > -		/* Register the card with the kernel SCSI layer */
> > +			/* Register the card with the kernel SCSI layer */
> >  			host = scsi_register(tw_host, sizeof(TW_Device_Extension));
> >  			if (host == NULL) {
> > -				printk(KERN_WARNING "3w-xxxx: tw_findcards(): scsi_register() failed for card %d.\n", numcards-1);
> > +				printk(KERN_WARNING "3w-xxxx: tw_findcards(): scsi_register() failed for card %d.\n", numcards);
> >  				release_region((tw_dev->tw_pci_dev->resource[0].start), TW_IO_ADDRESS_RANGE);
> >  				tw_free_device_extension(tw_dev);
> >  				kfree(tw_dev);
> >  				continue;
> >  			}
> > 
> > +			/* Set max target id's */
> > +			host->max_id = TW_MAX_UNITS;
> > +
> > +			/* Set max cdb size in bytes */
> > +			host->max_cmd_len = 16;
> > +
> >  			/* Set max sectors per io */
> >  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,7)
> >  			host->max_sectors = TW_MAX_SECTORS;
> > @@ -874,7 +941,7 @@
> >  				tw_device_extension_count = numcards;
> >  				tw_dev2->host = host;
> >  			} else {
> > -				printk(KERN_WARNING "3w-xxxx: tw_findcards(): Bad scsi host data for card %d.\n", numcards-1);
> > +				printk(KERN_WARNING "3w-xxxx: tw_findcards(): Bad scsi host data for card %d.\n", numcards);
> >  				scsi_unregister(host);
> >  				release_region((tw_dev->tw_pci_dev->resource[0].start), TW_IO_ADDRESS_RANGE);
> >  				tw_free_device_extension(tw_dev);
> > @@ -924,15 +991,10 @@
> >  	/* Free command packet and generic buffer memory */
> >  	for (i=0;i<TW_Q_LENGTH;i++) {
> >  		if (tw_dev->command_packet_virtual_address[i])
> > -			kfree(tw_dev->command_packet_virtual_address[i]);
> > +			pci_free_consistent(tw_dev->tw_pci_dev, sizeof(TW_Sector), tw_dev->command_packet_virtual_address[i], tw_dev->command_packet_physical_address[i]);
> > 
> >  		if (tw_dev->alignment_virtual_address[i])
> > -			kfree(tw_dev->alignment_virtual_address[i]);
> > -
> > -	}
> > -	for (i=0;i<TW_MAX_BOUNCEBUF;i++) {
> > -		if (tw_dev->bounce_buffer[i])
> > -			kfree(tw_dev->bounce_buffer[i]);
> > +			pci_free_consistent(tw_dev->tw_pci_dev, sizeof(TW_Sector), tw_dev->alignment_virtual_address[i], tw_dev->alignment_physical_address[i]);
> >  	}
> >  } /* End tw_free_device_extension() */
> > 
> > @@ -1015,8 +1077,7 @@
> >  			}
> >  			if (command_packet->status != 0) {
> >  				/* bad response */
> > -				dprintk(KERN_WARNING "3w-xxxx: tw_initconnection(): Bad response, status = 0x%x, flags = 0x%x.\n", command_packet->status, command_packet->flags);
> > -				tw_decode_error(tw_dev, command_packet->status, command_packet->flags, command_packet->byte3.unit);
> > +				tw_decode_sense(tw_dev, request_id, 0);
> >  				return 1;
> >  			}
> >  			break;	/* Response was okay, so we exit */
> > @@ -1028,57 +1089,33 @@
> >  /* This function will initialize the fields of a device extension */
> >  int tw_initialize_device_extension(TW_Device_Extension *tw_dev)
> >  {
> > -	int i, imax;
> > +	int i, error=0;
> > 
> >  	dprintk(KERN_NOTICE "3w-xxxx: tw_initialize_device_extension()\n");
> > -	imax = TW_Q_LENGTH;
> > 
> > -	for (i=0; i<imax; i++) {
> > -		/* Initialize command packet buffers */
> > -		tw_allocate_memory(tw_dev, i, sizeof(TW_Sector), 0);
> > -		if (tw_dev->command_packet_virtual_address[i] == NULL) {
> > -			printk(KERN_WARNING "3w-xxxx: tw_initialize_device_extension(): Bad command packet virtual address.\n");
> > -			return 1;
> > -		}
> > -		memset(tw_dev->command_packet_virtual_address[i], 0, sizeof(TW_Sector));
> > -
> > -		/* Initialize generic buffer */
> > -		tw_allocate_memory(tw_dev, i, sizeof(TW_Sector), 1);
> > -		if (tw_dev->alignment_virtual_address[i] == NULL) {
> > -			printk(KERN_WARNING "3w-xxxx: tw_initialize_device_extension(): Bad alignment virtual address.\n");
> > -			return 1;
> > -		}
> > -		memset(tw_dev->alignment_virtual_address[i], 0, sizeof(TW_Sector));
> > +	/* Initialize command packet buffers */
> > +	error = tw_allocate_memory(tw_dev, sizeof(TW_Command), 0);
> > +	if (error) {
> > +		printk(KERN_WARNING "3w-xxxx: Command packet memory allocation failed.\n");
> > +		return 1;
> > +	}
> > 
> > -		tw_dev->free_queue[i] = i;
> > -		tw_dev->state[i] = TW_S_INITIAL;
> > -		tw_dev->ioctl_size[i] = 0;
> > -		tw_dev->aen_queue[i] = 0;
> > +	/* Initialize generic buffer */
> > +	error = tw_allocate_memory(tw_dev, sizeof(TW_Sector), 1);
> > +	if (error) {
> > +		printk(KERN_WARNING "3w-xxxx: Generic memory allocation failed.\n");
> > +		return 1;
> >  	}
> > 
> > -	for (i=0;i<TW_MAX_UNITS;i++) {
> > -		tw_dev->is_unit_present[i] = 0;
> > -		tw_dev->is_raid_five[i] = 0;
> > +	for (i=0;i<TW_Q_LENGTH;i++) {
> > +		tw_dev->free_queue[i] = i;
> > +		tw_dev->state[i] = TW_S_INITIAL;
> >  	}
> > 
> > -	tw_dev->num_units = 0;
> > -	tw_dev->num_aborts = 0;
> > -	tw_dev->num_resets = 0;
> > -	tw_dev->posted_request_count = 0;
> > -	tw_dev->max_posted_request_count = 0;
> > -	tw_dev->max_sgl_entries = 0;
> > -	tw_dev->sgl_entries = 0;
> > -	tw_dev->host = NULL;
> >  	tw_dev->pending_head = TW_Q_START;
> >  	tw_dev->pending_tail = TW_Q_START;
> > -	tw_dev->aen_head = 0;
> > -	tw_dev->aen_tail = 0;
> > -	tw_dev->sector_count = 0;
> > -	tw_dev->max_sector_count = 0;
> > -	tw_dev->aen_count = 0;
> > -	tw_dev->num_raid_five = 0;
> >  	spin_lock_init(&tw_dev->tw_lock);
> > -	tw_dev->flags = 0;
> > +
> >  	return 0;
> >  } /* End tw_initialize_device_extension() */
> > 
> > @@ -1089,14 +1126,13 @@
> >  	unsigned char request_id = 0;
> >  	TW_Command *command_packet;
> >  	TW_Param *param;
> > -	int i, j, imax, num_units = 0, num_raid_five = 0;
> > +	int i, imax, num_units = 0;
> >  	u32 status_reg_addr, status_reg_value;
> >  	u32 command_que_addr, command_que_value;
> >  	u32 response_que_addr;
> >  	TW_Response_Queue response_queue;
> >  	u32 param_value;
> >  	unsigned char *is_unit_present;
> > -	unsigned char *raid_level;
> > 
> >  	dprintk(KERN_NOTICE "3w-xxxx: tw_initialize_units()\n");
> > 
> > @@ -1168,8 +1204,7 @@
> >  			}
> >  			if (command_packet->status != 0) {
> >  				/* bad response */
> > -				dprintk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Bad response, status = 0x%x, flags = 0x%x.\n", command_packet->status, command_packet->flags);
> > -				tw_decode_error(tw_dev, command_packet->status, command_packet->flags, command_packet->byte3.unit);
> > +				tw_decode_sense(tw_dev, request_id, 0);
> >  				return 1;
> >  			}
> >  			found = 1;
> > @@ -1205,109 +1240,6 @@
> >  		return 1;
> >  	}
> > 
> > -	/* Find raid 5 arrays */
> > -	for (j=0;j<TW_MAX_UNITS;j++) {
> > -		if (tw_dev->is_unit_present[j] == 0)
> > -			continue;
> > -		command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id];
> > -		if (command_packet == NULL) {
> > -			printk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Bad command packet virtual address.\n");
> > -			return 1;
> > -		}
> > -		memset(command_packet, 0, sizeof(TW_Sector));
> > -		command_packet->byte0.opcode      = TW_OP_GET_PARAM;
> > -		command_packet->byte0.sgl_offset  = 2;
> > -		command_packet->size              = 4;
> > -		command_packet->request_id        = request_id;
> > -		command_packet->byte3.unit        = 0;
> > -		command_packet->byte3.host_id     = 0;
> > -		command_packet->status            = 0;
> > -		command_packet->flags             = 0;
> > -		command_packet->byte6.block_count = 1;
> > -
> > -		/* Now setup the param */
> > -		if (tw_dev->alignment_virtual_address[request_id] == NULL) {
> > -			printk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Bad alignment virtual address.\n");
> > -			return 1;
> > -		}
> > -		param = (TW_Param *)tw_dev->alignment_virtual_address[request_id];
> > -		memset(param, 0, sizeof(TW_Sector));
> > -		param->table_id = 0x300+j; /* unit summary table */
> > -		param->parameter_id = 0x6; /* unit descriptor */
> > -		param->parameter_size_bytes = 0xc;
> > -		param_value = tw_dev->alignment_physical_address[request_id];
> > -		if (param_value == 0) {
> > -			printk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Bad alignment physical address.\n");
> > -			return 1;
> > -		}
> > -
> > -		command_packet->byte8.param.sgl[0].address = param_value;
> > -		command_packet->byte8.param.sgl[0].length = sizeof(TW_Sector);
> > -
> > -		/* Post the command packet to the board */
> > -		command_que_value = tw_dev->command_packet_physical_address[request_id];
> > -		if (command_que_value == 0) {
> > -			printk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Bad command packet physical address.\n");
> > -			return 1;
> > -		}
> > -		outl(command_que_value, command_que_addr);
> > -
> > -		/* Poll for completion */
> > -		imax = TW_POLL_MAX_RETRIES;
> > -		for(i=0; i<imax; i++) {
> > -			mdelay(5);
> > -			status_reg_value = inl(status_reg_addr);
> > -			if (tw_check_bits(status_reg_value)) {
> > -				dprintk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Unexpected bits.\n");
> > -				tw_decode_bits(tw_dev, status_reg_value);
> > -				return 1;
> > -			}
> > -			if ((status_reg_value & TW_STATUS_RESPONSE_QUEUE_EMPTY) == 0) {
> > -				response_queue.value = inl(response_que_addr);
> > -				request_id = (unsigned char)response_queue.u.response_id;
> > -				if (request_id != 0) {
> > -					/* unexpected request id */
> > -					printk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Unexpected request id.\n");
> > -					return 1;
> > -				}
> > -				if (command_packet->status != 0) {
> > -					/* bad response */
> > -					dprintk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Bad response, status = 0x%x, flags = 0x%x.\n", command_packet->status, command_packet->flags);
> > -					tw_decode_error(tw_dev, command_packet->status, command_packet->flags, command_packet->byte3.unit);
> > -					return 1;
> > -				}
> > -				found = 1;
> > -				break;
> > -			}
> > -		}
> > -		if (found == 0) {
> > -			/* response never received */
> > -			printk(KERN_WARNING "3w-xxxx: tw_initialize_units(): No response.\n");
> > -			return 1;
> > -		}
> > -
> > -		param = (TW_Param *)tw_dev->alignment_virtual_address[request_id];
> > -		raid_level = (unsigned char *)&(param->data[1]);
> > -		if (*raid_level == 5) {
> > -			dprintk(KERN_WARNING "3w-xxxx: Found unit %d to be a raid5 unit.\n", j);
> > -			tw_dev->is_raid_five[j] = 1;
> > -			num_raid_five++;
> > -		}
> > -	}
> > -	tw_dev->num_raid_five = num_raid_five;
> > -
> > -	/* Now allocate raid5 bounce buffers */
> > -	if ((num_raid_five != 0) && (tw_dev->tw_pci_dev->device == TW_DEVICE_ID)) {
> > -		for (i=0;i<TW_MAX_BOUNCEBUF;i++) {
> > -			tw_allocate_memory(tw_dev, i, sizeof(TW_Sector)*TW_MAX_SECTORS, 2);
> > -			if (tw_dev->bounce_buffer[i] == NULL) {
> > -				printk(KERN_WARNING "3w-xxxx: Bounce buffer allocation failed.\n");
> > -				return 1;
> > -			}
> > -			memset(tw_dev->bounce_buffer[i], 0, sizeof(TW_Sector)*TW_MAX_SECTORS);
> > -		}
> > -	}
> > -
> >  	return 0;
> >  } /* End tw_initialize_units() */
> > 
> > @@ -1332,13 +1264,18 @@
> > 
> >  	if (tw_dev->tw_pci_dev->irq == irq) {
> >  		spin_lock(&tw_dev->tw_lock);
> > -		dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt()\n");
> > +		dprintk(KERN_WARNING "3w-xxxx: tw_interrupt()\n");
> > 
> >  		/* Read the registers */
> >  		status_reg_addr = tw_dev->registers.status_reg_addr;
> >  		response_que_addr = tw_dev->registers.response_que_addr;
> >  		status_reg_value = inl(status_reg_addr);
> > 
> > +		if (tw_check_bits(status_reg_value)) {
> > +			dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Unexpected bits.\n");
> > +			tw_decode_bits(tw_dev, status_reg_value);
> > +		}
> > +
> >  		/* Check which interrupt */
> >  		if (status_reg_value & TW_STATUS_HOST_INTERRUPT)
> >  			do_host_interrupt=1;
> > @@ -1403,17 +1340,18 @@
> >  				command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id];
> >  				error = 0;
> >  				if (command_packet->status != 0) {
> > -					dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Bad response, status = 0x%x, flags = 0x%x, unit = 0x%x.\n", command_packet->status, command_packet->flags, command_packet->byte3.unit);
> > -					tw_decode_error(tw_dev, command_packet->status, command_packet->flags, command_packet->byte3.unit);
> > -					error = 1;
> > +					/* Bad response */
> > +					if (tw_dev->srb[request_id] != 0)
> > +						tw_decode_sense(tw_dev, request_id, 1);
> > +					error = 3;
> >  				}
> >  				if (tw_dev->state[request_id] != TW_S_POSTED) {
> >  					printk(KERN_WARNING "3w-xxxx: scsi%d: Received a request id (%d) (opcode = 0x%x) that wasn't posted.\n", tw_dev->host->host_no, request_id, command_packet->byte0.opcode);
> >  					error = 1;
> >  				}
> >  				if (TW_STATUS_ERRORS(status_reg_value)) {
> > -				  tw_decode_bits(tw_dev, status_reg_value);
> > -				  error = 1;
> > +					tw_decode_bits(tw_dev, status_reg_value);
> > +					error = 1;
> >  				}
> >  				dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): Response queue request id: %d.\n", request_id);
> >  				/* Check for internal command */
> > @@ -1428,7 +1366,7 @@
> >  						dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Unexpected bits.\n");
> >  						tw_decode_bits(tw_dev, status_reg_value);
> >  					}
> > -		} else {
> > +				} else {
> >  				switch (tw_dev->srb[request_id]->cmnd[0]) {
> >  					case READ_10:
> >  					case READ_6:
> > @@ -1455,18 +1393,23 @@
> >  						tw_dev->srb[request_id]->result = (DID_BAD_TARGET << 16);
> >  						tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]);
> >  					}
> > -					if (error) {
> > +					if (error == 1) {
> >  						/* Tell scsi layer there was an error */
> >  						dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Scsi Error.\n");
> >  						tw_dev->srb[request_id]->result = (DID_RESET << 16);
> > -					} else {
> > +					}
> > +					if (error == 0) {
> >  						/* Tell scsi layer command was a success */
> >  						tw_dev->srb[request_id]->result = (DID_OK << 16);
> >  					}
> > -					tw_dev->state[request_id] = TW_S_COMPLETED;
> > -					tw_state_request_finish(tw_dev, request_id);
> > -					tw_dev->posted_request_count--;
> > -					tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]);
> > +					if (error != 2) {
> > +						tw_dev->state[request_id] = TW_S_COMPLETED;
> > +						tw_state_request_finish(tw_dev, request_id);
> > +						tw_dev->posted_request_count--;
> > +						tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]);
> > +
> > +						tw_unmap_scsi_data(tw_dev->tw_pci_dev, tw_dev->srb[request_id]);
> > +					}
> >  					status_reg_value = inl(status_reg_addr);
> >  					if (tw_check_bits(status_reg_value)) {
> >  						dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Unexpected bits.\n");
> > @@ -1479,19 +1422,22 @@
> >  	}
> >  	spin_unlock_irqrestore(tw_dev->host->host_lock, flags);
> >  	clear_bit(TW_IN_INTR, &tw_dev->flags);
> > -}	/* End tw_interrupt() */
> > +} /* End tw_interrupt() */
> > 
> >  /* This function handles ioctls from userspace to the driver */
> >  int tw_ioctl(TW_Device_Extension *tw_dev, int request_id)
> >  {
> >  	unsigned char opcode;
> > -	int bufflen;
> > +	int bufflen, error = 0;
> >  	TW_Param *param;
> > -	TW_Command *command_packet;
> > +	TW_Command *command_packet, *command_save;
> >  	u32 param_value;
> >  	TW_Ioctl *ioctl = NULL;
> >  	TW_Passthru *passthru = NULL;
> > -	int tw_aen_code;
> > +	int tw_aen_code, i, use_sg;
> > +	char *data_ptr;
> > +	int total_bytes = 0;
> > +	dma_addr_t dma_handle;
> > 
> >  	ioctl = (TW_Ioctl *)tw_dev->srb[request_id]->request_buffer;
> >  	if (ioctl == NULL) {
> > @@ -1598,7 +1544,7 @@
> >  				printk(KERN_WARNING "3w-xxxx: tw_ioctl(): Passthru size (%ld) too big.\n", passthru->sg_list[0].length);
> >  				return 1;
> >  			}
> > -			passthru->sg_list[0].address = virt_to_bus(tw_dev->alignment_virtual_address[request_id]);
> > +			passthru->sg_list[0].address = tw_dev->alignment_physical_address[request_id];
> >  			tw_post_command_packet(tw_dev, request_id);
> >  			return 0;
> >  		case TW_CMD_PACKET:
> > @@ -1612,6 +1558,161 @@
> >  				printk(KERN_WARNING "3w-xxxx: tw_ioctl(): ioctl->data NULL.\n");
> >  				return 1;
> >  			}
> > +		case TW_CMD_PACKET_WITH_DATA:
> > +			dprintk(KERN_WARNING "3w-xxxx: tw_ioctl(): caught TW_CMD_PACKET_WITH_DATA.\n");
> > +			command_save = (TW_Command *)tw_dev->alignment_virtual_address[request_id];
> > +			if (command_save == NULL) {
> > +				printk(KERN_WARNING "3w-xxxx: scsi%d: tw_ioctl(): Bad alignment virtual address.\n", tw_dev->host->host_no);
> > +				return 1;
> > +			}
> > +			if (ioctl->data != NULL) {
> > +				/* Copy down the command packet */
> > +				memcpy(command_packet, ioctl->data, sizeof(TW_Command));
> > +				memcpy(command_save, ioctl->data, sizeof(TW_Command));
> > +				command_packet->request_id = request_id;
> > +
> > +				/* Now deal with the two possible sglists */
> > +				if (command_packet->byte0.sgl_offset == 2) {
> > +					use_sg = command_packet->size - 3;
> > +					for (i=0;i<use_sg;i++)
> > +						total_bytes+=command_packet->byte8.param.sgl[i].length;
> > +					tw_dev->ioctl_data[request_id] = pci_alloc_consistent(tw_dev->tw_pci_dev, total_bytes, &dma_handle);
> > +
> > +					if (!tw_dev->ioctl_data[request_id]) {
> > +						printk(KERN_WARNING "3w-xxxx: scsi%d: tw_ioctl(): kmalloc failed for request_id %d.\n", tw_dev->host->host_no, request_id);
> > +						return 1;
> > +					}
> > +
> > +					/* Copy param sglist into the kernel */
> > +					data_ptr = tw_dev->ioctl_data[request_id];
> > +					for (i=0;i<use_sg;i++) {
> > +						if ((u32 *)command_packet->byte8.param.sgl[i].address != NULL) {
> > +							error = copy_from_user(data_ptr, (u32 *)command_packet->byte8.param.sgl[i].address, command_packet->byte8.param.sgl[i].length);
> > +							if (error) {
> > +								printk(KERN_WARNING "3w-xxxx: scsi%d: Error copying param sglist from userspace.\n", tw_dev->host->host_no);
> > +								goto tw_ioctl_bail;
> > +							}
> > +						} else {
> > +							printk(KERN_WARNING "3w-xxxx: scsi%d: tw_ioctl(): Bad param sgl address.\n", tw_dev->host->host_no);
> > +							tw_dev->srb[request_id]->result = (DID_RESET << 16);
> > +							goto tw_ioctl_bail;
> > +						}
> > +						data_ptr+=command_packet->byte8.param.sgl[i].length;
> > +					}
> > +					command_packet->size = 4;
> > +					command_packet->byte8.param.sgl[0].address = dma_handle;
> > +					command_packet->byte8.param.sgl[0].length = total_bytes;
> > +				}
> > +				if (command_packet->byte0.sgl_offset == 3) {
> > +					use_sg = command_packet->size - 4;
> > +					for (i=0;i<use_sg;i++)
> > +						total_bytes+=command_packet->byte8.io.sgl[i].length;
> > +					tw_dev->ioctl_data[request_id] = pci_alloc_consistent(tw_dev->tw_pci_dev, total_bytes, &dma_handle);
> > +
> > +					if (!tw_dev->ioctl_data[request_id]) {
> > +						printk(KERN_WARNING "3w-xxxx: scsi%d: tw_ioctl(): pci_alloc_consistent() failed for request_id %d.\n", tw_dev->host->host_no, request_id);
> > +						return 1;
> > +					}
> > +					if (command_packet->byte0.opcode == TW_OP_WRITE) {
> > +						/* Copy io sglist into the kernel */
> > +						data_ptr = tw_dev->ioctl_data[request_id];
> > +						for (i=0;i<use_sg;i++) {
> > +							if ((u32 *)command_packet->byte8.io.sgl[i].address != NULL) {
> > +								error = copy_from_user(data_ptr, (u32 *)command_packet->byte8.io.sgl[i].address, command_packet->byte8.io.sgl[i].length);
> > +								if (error) {
> > +									printk(KERN_WARNING "3w-xxxx: scsi%d: Error copying io sglist from userspace.\n", tw_dev->host->host_no);
> > +									goto tw_ioctl_bail;
> > +								}
> > +							} else {
> > +								printk(KERN_WARNING "3w-xxxx: scsi%d: tw_ioctl(): Bad io sgl address.\n", tw_dev->host->host_no);
> > +								tw_dev->srb[request_id]->result = (DID_RESET << 16);
> > +								goto tw_ioctl_bail;
> > +							}
> > +							data_ptr+=command_packet->byte8.io.sgl[i].length;
> > +						}
> > +					}
> > +					command_packet->size = 5;
> > +					command_packet->byte8.io.sgl[0].address = dma_handle;
> > +					command_packet->byte8.io.sgl[0].length = total_bytes;
> > +				}
> > +
> > +				spin_unlock_irq(tw_dev->host->host_lock);
> > +				spin_unlock_irq(&tw_dev->tw_lock);
> > +
> > +				/* Finally post the command packet */
> > +				tw_post_command_packet(tw_dev, request_id);
> > +
> > +				mdelay(TW_IOCTL_WAIT_TIME);
> > +				spin_lock_irq(&tw_dev->tw_lock);
> > +				spin_lock_irq(tw_dev->host->host_lock);
> > +
> > +				if (signal_pending(current)) {
> > +					dprintk(KERN_WARNING "3w-xxxx: scsi%d: tw_ioctl(): Signal pending, aborting ioctl().\n", tw_dev->host->host_no);
> > +					tw_dev->srb[request_id]->result = (DID_OK << 16);
> > +					goto tw_ioctl_bail;
> > +				}
> > +
> > +				tw_dev->srb[request_id]->result = (DID_OK << 16);
> > +				/* Now copy up the param or io sglist to userspace */
> > +				if (command_packet->byte0.sgl_offset == 2) {
> > +					use_sg = command_save->size - 3;
> > +					data_ptr = phys_to_virt(command_packet->byte8.param.sgl[0].address);
> > +					for (i=0;i<use_sg;i++) {
> > +						if ((u32 *)command_save->byte8.param.sgl[i].address != NULL) {
> > +							error = copy_to_user((u32 *)command_save->byte8.param.sgl[i].address, data_ptr, command_save->byte8.param.sgl[i].length);
> > +							if (error) {
> > +								printk(KERN_WARNING "3w-xxxx: scsi%d: Error copying param sglist to userspace.\n", tw_dev->host->host_no);
> > +								goto tw_ioctl_bail;
> > +							}
> > +							dprintk(KERN_WARNING "3w-xxxx: scsi%d: Copied %ld bytes to pid %d.\n", tw_dev->host->host_no, command_save->byte8.param.sgl[i].length, current->pid);
> > +							data_ptr+=command_save->byte8.param.sgl[i].length;
> > +						} else {
> > +							printk(KERN_WARNING "3w-xxxx: scsi%d: tw_ioctl(): Bad param sgl address.\n", tw_dev->host->host_no);
> > +							tw_dev->srb[request_id]->result = (DID_RESET << 16);
> > +							goto tw_ioctl_bail;
> > +						}
> > +					}
> > +				}
> > +				if (command_packet->byte0.sgl_offset == 3) {
> > +					use_sg = command_save->size - 4;
> > +					if (command_packet->byte0.opcode == TW_OP_READ) {
> > +						data_ptr = phys_to_virt(command_packet->byte8.io.sgl[0].address);
> > +						for(i=0;i<use_sg;i++) {
> > +							if ((u32 *)command_save->byte8.io.sgl[i].address != NULL) {
> > +								error = copy_to_user((u32 *)command_save->byte8.io.sgl[i].address, data_ptr, command_save->byte8.io.sgl[i].length);
> > +								if (error) {
> > +									printk(KERN_WARNING "3w-xxxx: scsi%d: Error copying io sglist to userspace.\n", tw_dev->host->host_no);
> > +									goto tw_ioctl_bail;
> > +								}
> > +								dprintk(KERN_WARNING "3w-xxxx: scsi%d: Copied %ld bytes to pid %d.\n", tw_dev->host->host_no, command_save->byte8.io.sgl[i].length, current->pid);
> > +								data_ptr+=command_save->byte8.io.sgl[i].length;
> > +							} else {
> > +								printk(KERN_WARNING "3w-xxxx: scsi%d: tw_ioctl(): Bad io sgl address.\n", tw_dev->host->host_no);
> > +								tw_dev->srb[request_id]->result = (DID_RESET << 16);
> > +								goto tw_ioctl_bail;
> > +							}
> > +						}
> > +					}
> > +				}
> > +
> > +			tw_ioctl_bail:
> > +
> > +				/* Free up sglist memory */
> > +				if (tw_dev->ioctl_data[request_id])
> > +					pci_free_consistent(tw_dev->tw_pci_dev, total_bytes, tw_dev->ioctl_data[request_id], dma_handle);
> > +				else
> > +					printk(KERN_WARNING "3w-xxxx: scsi%d: tw_ioctl(): Error freeing ioctl data.\n", tw_dev->host->host_no);
> > +
> > +				/* Now complete the io */
> > +				tw_dev->state[request_id] = TW_S_COMPLETED;
> > +				tw_state_request_finish(tw_dev, request_id);
> > +				tw_dev->posted_request_count--;
> > +				tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]);
> > +				return 0;
> > +			} else {
> > +				printk(KERN_WARNING "3w-xxxx: tw_ioctl(): ioctl->data NULL.\n");
> > +				return 1;
> > +			}
> >  		default:
> >  			printk(KERN_WARNING "3w-xxxx: Unknown ioctl 0x%x.\n", opcode);
> >  			tw_dev->state[request_id] = TW_S_COMPLETED;
> > @@ -1655,6 +1756,7 @@
> >  	TW_Param *param;
> >  	TW_Ioctl *ioctl = NULL;
> >  	TW_Passthru *passthru = NULL;
> > +	TW_Command *command_packet;
> > 
> >  	ioctl = (TW_Ioctl *)tw_dev->srb[request_id]->request_buffer;
> >  	dprintk(KERN_NOTICE "3w-xxxx: tw_ioctl_complete()\n");
> > @@ -1663,6 +1765,13 @@
> >  		printk(KERN_WARNING "3w-xxxx: tw_ioctl_complete(): Request buffer NULL.\n");
> >  		return 1;
> >  	}
> > +
> > +	command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id];
> > +	if (command_packet == NULL) {
> > +		printk(KERN_WARNING "3w-xxxx: scsi%d: tw_ioctl_complete(): Bad command packet virtual address.\n", tw_dev->host->host_no);
> > +		return 1;
> > +	}
> > +
> >  	dprintk(KERN_NOTICE "3w-xxxx: tw_ioctl_complete(): Request_bufflen = %d\n", tw_dev->srb[request_id]->request_bufflen);
> > 
> >  	ioctl = (TW_Ioctl *)buff;
> > @@ -1671,6 +1780,9 @@
> >  			passthru = (TW_Passthru *)ioctl->data;
> >  			memcpy(buff, tw_dev->alignment_virtual_address[request_id], passthru->sector_count * 512);
> >  			break;
> > +		case TW_CMD_PACKET_WITH_DATA:
> > +			dprintk(KERN_WARNING "3w-xxxx: tw_ioctl_complete(): caught TW_CMD_PACKET_WITH_DATA.\n");
> > +			return 2; /* Special case for isr to not complete io */
> >  		default:
> >  			memset(buff, 0, tw_dev->srb[request_id]->request_bufflen);
> >  			param = (TW_Param *)tw_dev->alignment_virtual_address[request_id];
> > @@ -1684,6 +1796,40 @@
> >  	return 0;
> >  } /* End tw_ioctl_complete() */
> > 
> > +static int tw_map_scsi_sg_data(struct pci_dev *pdev, Scsi_Cmnd *cmd)
> > +{
> > +	int use_sg;
> > +	int dma_dir = scsi_to_pci_dma_dir(cmd->sc_data_direction);
> > +
> > +	dprintk(KERN_WARNING "3w-xxxx: tw_map_scsi_sg_data()\n");
> > +
> > +	if (cmd->use_sg == 0)
> > +		return 0;
> > +
> > +	use_sg = pci_map_sg(pdev, cmd->buffer, cmd->use_sg, dma_dir);
> > +	cmd->SCp.phase = 2;
> > +	cmd->SCp.have_data_in = use_sg;
> > +
> > +	return use_sg;
> > +} /* End tw_map_scsi_sg_data() */
> > +
> > +static u32 tw_map_scsi_single_data(struct pci_dev *pdev, Scsi_Cmnd *cmd)
> > +{
> > +	dma_addr_t mapping;
> > +	int dma_dir = scsi_to_pci_dma_dir(cmd->sc_data_direction);
> > +
> > +	dprintk(KERN_WARNING "3w-xxxx: tw_map_scsi_single_data()\n");
> > +
> > +	if (cmd->request_bufflen == 0)
> > +		return 0;
> > +
> > +	mapping = pci_map_single(pdev, cmd->request_buffer, cmd->request_bufflen, dma_dir);
> > +	cmd->SCp.phase = 2;
> > +	cmd->SCp.have_data_in = mapping;
> > +
> > +	return mapping;
> > +} /* End tw_map_scsi_single_data() */
> > +
> >  /* This function will mask the command interrupt */
> >  void tw_mask_command_interrupt(TW_Device_Extension *tw_dev)
> >  {
> > @@ -1704,14 +1850,25 @@
> >  	do_gettimeofday(&before);
> >  	status_reg_value = inl(status_reg_addr);
> > 
> > +	if (tw_check_bits(status_reg_value)) {
> > +		dprintk(KERN_WARNING "3w-xxxx: tw_poll_status(): Unexpected bits.\n");
> > +		tw_decode_bits(tw_dev, status_reg_value);
> > +	}
> > +
> >  	while ((status_reg_value & flag) != flag) {
> >  		status_reg_value = inl(status_reg_addr);
> > +
> > +		if (tw_check_bits(status_reg_value)) {
> > +			dprintk(KERN_WARNING "3w-xxxx: tw_poll_status(): Unexpected bits.\n");
> > +			tw_decode_bits(tw_dev, status_reg_value);
> > +		}
> > +
> >  		do_gettimeofday(&timeout);
> >  		if (before.tv_sec + seconds < timeout.tv_sec) {
> >  			dprintk(KERN_WARNING "3w-xxxx: tw_poll_status(): Flag 0x%x not found.\n", flag);
> >  			return 1;
> >  		}
> > -		mdelay(1);
> > +		mdelay(5);
> >  	}
> >  	return 0;
> >  } /* End tw_poll_status() */
> > @@ -1787,6 +1944,7 @@
> >  				srb = tw_dev->srb[i];
> >  				srb->result = (DID_RESET << 16);
> >  				tw_dev->srb[i]->scsi_done(tw_dev->srb[i]);
> > +				tw_unmap_scsi_data(tw_dev->tw_pci_dev, tw_dev->srb[i]);
> >  			}
> >  		}
> >  	}
> > @@ -1821,7 +1979,7 @@
> > 
> >  		error = tw_aen_drain_queue(tw_dev);
> >  		if (error) {
> > -			printk(KERN_WARNING "3w-xxxx: scsi%d: Card not responding, retrying.\n", tw_dev->host->host_no);
> > +			printk(KERN_WARNING "3w-xxxx: scsi%d: AEN drain failed, retrying.\n", tw_dev->host->host_no);
> >  			tries++;
> >  			continue;
> >  		}
> > @@ -1857,7 +2015,7 @@
> >  	}
> > 
> >  	/* Re-enable interrupts */
> > -	tw_enable_interrupts(tw_dev);
> > +	tw_enable_and_clear_interrupts(tw_dev);
> > 
> >  	return 0;
> >  } /* End tw_reset_sequence() */
> > @@ -2381,6 +2539,9 @@
> >  	capacity = (param_data[3] << 24) | (param_data[2] << 16) |
> >  		   (param_data[1] << 8) | param_data[0];
> > 
> > +	/* Subtract one sector to fix get last sector ioctl */
> > +	capacity -= 1;
> > +
> >  	dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_read_capacity_complete(): Capacity = 0x%x.\n", capacity);
> > 
> >  	/* Number of LBA's */
> > @@ -2403,8 +2564,8 @@
> >  {
> >  	TW_Command *command_packet;
> >  	u32 command_que_addr, command_que_value = 0;
> > -	u32 lba = 0x0, num_sectors = 0x0;
> > -	int i, count = 0;
> > +	u32 lba = 0x0, num_sectors = 0x0, buffaddr = 0x0;
> > +	int i, use_sg;
> >  	Scsi_Cmnd *srb;
> >  	struct scatterlist *sglist;
> > 
> > @@ -2461,45 +2622,25 @@
> >  	command_packet->byte8.io.lba = lba;
> >  	command_packet->byte6.block_count = num_sectors;
> > 
> > -	if ((tw_dev->is_raid_five[tw_dev->srb[request_id]->target] == 0) || (srb->cmnd[0] == READ_6) || (srb->cmnd[0] == READ_10) || (tw_dev->tw_pci_dev->device == TW_DEVICE_ID2)) {
> > -		/* Do this if there are no sg list entries */
> > -		if (tw_dev->srb[request_id]->use_sg == 0) {
> > -			dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_read_write(): SG = 0\n");
> > -			command_packet->byte8.io.sgl[0].address = virt_to_bus(tw_dev->srb[request_id]->request_buffer);
> > -			command_packet->byte8.io.sgl[0].length = tw_dev->srb[request_id]->request_bufflen;
> > -		}
> > -
> > -		/* Do this if we have multiple sg list entries */
> > -		if (tw_dev->srb[request_id]->use_sg > 0) {
> > -			for (i=0;i<tw_dev->srb[request_id]->use_sg; i++) {
> > -				command_packet->byte8.io.sgl[i].address = virt_to_bus(sglist[i].address);
> > -				command_packet->byte8.io.sgl[i].length = sglist[i].length;
> > -				command_packet->size+=2;
> > -			}
> > -			if (tw_dev->srb[request_id]->use_sg >= 1)
> > -				command_packet->size-=2;
> > +	/* Do this if there are no sg list entries */
> > +	if (tw_dev->srb[request_id]->use_sg == 0) {
> > +		dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_read_write(): SG = 0\n");
> > +		buffaddr = tw_map_scsi_single_data(tw_dev->tw_pci_dev, tw_dev->srb[request_id]);
> > +		command_packet->byte8.io.sgl[0].address = buffaddr;
> > +		command_packet->byte8.io.sgl[0].length = tw_dev->srb[request_id]->request_bufflen;
> > +	}
> > +
> > +	/* Do this if we have multiple sg list entries */
> > +	if (tw_dev->srb[request_id]->use_sg > 0) {
> > +		use_sg = tw_map_scsi_sg_data(tw_dev->tw_pci_dev, tw_dev->srb[request_id]);;
> > +		for (i=0;i<use_sg; i++) {
> > +			command_packet->byte8.io.sgl[i].address = sg_dma_address(&sglist[i]);
> > +			command_packet->byte8.io.sgl[i].length = sg_dma_len(&sglist[i]);
> > +			command_packet->size+=2;
> >  		}
> > -	} else {
> > -                /* Do this if there are no sg list entries for raid 5 */
> > -                if (tw_dev->srb[request_id]->use_sg == 0) {
> > -			dprintk(KERN_WARNING "doing raid 5 write use_sg = 0, bounce_buffer[%d] = 0x%p\n", request_id, tw_dev->bounce_buffer[request_id]);
> > -			memcpy(tw_dev->bounce_buffer[request_id], tw_dev->srb[request_id]->request_buffer, tw_dev->srb[request_id]->request_bufflen);
> > -			command_packet->byte8.io.sgl[0].address = virt_to_bus(tw_dev->bounce_buffer[request_id]);
> > -			command_packet->byte8.io.sgl[0].length = tw_dev->srb[request_id]->request_bufflen;
> > -                }
> > -
> > -                /* Do this if we have multiple sg list entries for raid 5 */
> > -                if (tw_dev->srb[request_id]->use_sg > 0) {
> > -                        dprintk(KERN_WARNING "doing raid 5 write use_sg = %d, sglist[0].length = %d\n", tw_dev->srb[request_id]->use_sg, sglist[0].length);
> > -                        for (i=0;i<tw_dev->srb[request_id]->use_sg; i++) {
> > -                                memcpy((char *)(tw_dev->bounce_buffer[request_id])+count, sglist[i].address, sglist[i].length);
> > -				count+=sglist[i].length;
> > -                        }
> > -                        command_packet->byte8.io.sgl[0].address = virt_to_bus(tw_dev->bounce_buffer[request_id]);
> > -                        command_packet->byte8.io.sgl[0].length = count;
> > -                        command_packet->size = 5; /* single sgl */
> > -                }
> > -        }
> > +		if (tw_dev->srb[request_id]->use_sg >= 1)
> > +			command_packet->size-=2;
> > +	}
> > 
> >  	/* Update SG statistics */
> >  	tw_dev->sgl_entries = tw_dev->srb[request_id]->use_sg;
> > @@ -2521,18 +2662,18 @@
> >  /* This function will handle the request sense scsi command */
> >  int tw_scsiop_request_sense(TW_Device_Extension *tw_dev, int request_id)
> >  {
> > -       dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_request_sense()\n");
> > -
> > -       /* For now we just zero the sense buffer */
> > -       memset(tw_dev->srb[request_id]->request_buffer, 0, tw_dev->srb[request_id]->request_bufflen);
> > -       tw_dev->state[request_id] = TW_S_COMPLETED;
> > -       tw_state_request_finish(tw_dev, request_id);
> > -
> > -       /* If we got a request_sense, we probably want a reset, return error */
> > -       tw_dev->srb[request_id]->result = (DID_ERROR << 16);
> > -       tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]);
> > -
> > -       return 0;
> > +	dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_request_sense()\n");
> > +
> > +	/* For now we just zero the request buffer */
> > +	memset(tw_dev->srb[request_id]->request_buffer, 0, tw_dev->srb[request_id]->request_bufflen);
> > +	tw_dev->state[request_id] = TW_S_COMPLETED;
> > +	tw_state_request_finish(tw_dev, request_id);
> > +
> > +	/* If we got a request_sense, we probably want a reset, return error */
> > +	tw_dev->srb[request_id]->result = (DID_ERROR << 16);
> > +	tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]);
> > +
> > +	return 0;
> >  } /* End tw_scsiop_request_sense() */
> > 
> >  /* This function will handle test unit ready scsi command */
> > @@ -2626,8 +2767,7 @@
> >  			}
> >  			if (command_packet->status != 0) {
> >  				/* bad response */
> > -				dprintk(KERN_WARNING "3w-xxxx: tw_setfeature(): Bad response, status = 0x%x, flags = 0x%x.\n", command_packet->status, command_packet->flags);
> > -				tw_decode_error(tw_dev, command_packet->status, command_packet->flags, command_packet->byte3.unit);
> > +				tw_decode_sense(tw_dev, request_id, 0);
> >  				return 1;
> >  			}
> >  			break; /* Response was okay, so we exit */
> > @@ -2671,7 +2811,7 @@
> >  	}
> > 
> >  	/* Re-enable interrupts */
> > -	tw_enable_interrupts(tw_dev);
> > +	tw_enable_and_clear_interrupts(tw_dev);
> > 
> >  	return 0;
> >  } /* End tw_shutdown_device() */
> > @@ -2719,7 +2859,7 @@
> >  	int id = 0;
> > 
> >  	dprintk(KERN_NOTICE "3w-xxxx: tw_state_request_start()\n");
> > -
> > +
> >  	/* Obtain next free request_id */
> >  	do {
> >  		if (tw_dev->free_head == tw_dev->free_wrap) {
> > @@ -2738,6 +2878,19 @@
> >  	return 0;
> >  } /* End tw_state_request_start() */
> > 
> > +static void tw_unmap_scsi_data(struct pci_dev *pdev, Scsi_Cmnd *cmd)
> > +{
> > +	int dma_dir = scsi_to_pci_dma_dir(cmd->sc_data_direction);
> > +
> > +	dprintk(KERN_WARNING "3w-xxxx: tw_unmap_scsi_data()\n");
> > +
> > +	if (cmd->use_sg) {
> > +		pci_unmap_sg(pdev, cmd->request_buffer, cmd->use_sg, dma_dir);
> > +	} else {
> > +		pci_unmap_single(pdev, cmd->SCp.have_data_in, cmd->request_bufflen, dma_dir);
> > +	}
> > +} /* End tw_unmap_scsi_data() */
> > +
> >  /* This function will unmask the command interrupt on the controller */
> >  void tw_unmask_command_interrupt(TW_Device_Extension *tw_dev)
> >  {
> > @@ -2749,7 +2902,6 @@
> >  } /* End tw_unmask_command_interrupt() */
> > 
> >  /* Now get things going */
> > -
> >  static Scsi_Host_Template driver_template = TWXXXX;
> >  #include "scsi_module.c"
> > 
> > diff -Naur linux-2.5.6-pre1/drivers/scsi/3w-xxxx.h linux-2.5.6-pre2/drivers/scsi/3w-xxxx.h
> > --- linux-2.5.6-pre1/drivers/scsi/3w-xxxx.h	Tue Feb 19 18:10:58 2002
> > +++ linux-2.5.6-pre2/drivers/scsi/3w-xxxx.h	Wed Feb 27 11:53:52 2002
> > @@ -6,7 +6,7 @@
> >     		     Arnaldo Carvalho de Melo <acme@conectiva.com.br>
> >                       Brad Strand <linux@3ware.com>
> > 
> > -   Copyright (C) 1999-2001 3ware Inc.
> > +   Copyright (C) 1999-2002 3ware Inc.
> > 
> >     Kernel compatablity By:	Andre Hedrick <andre@suse.com>
> >     Non-Copyright (C) 2000	Andre Hedrick <andre@suse.com>
> > @@ -62,7 +62,7 @@
> >  static char *tw_aen_string[] = {
> >  	"AEN queue empty",                      // 0x000
> >  	"Soft reset occurred",                  // 0x001
> > -	"Mirorr degraded: Unit #",              // 0x002
> > +	"Unit degraded: Unit #",                // 0x002
> >  	"Controller error",                     // 0x003
> >  	"Rebuild failed: Unit #",               // 0x004
> >  	"Rebuild complete: Unit #",             // 0x005
> > @@ -90,10 +90,36 @@
> >  	"DCB unsupported version: Port #",      // 0x028
> >  	"Verify started: Unit #",               // 0x029
> >  	"Verify failed: Port #",                // 0x02A
> > -	"Verify complete: Unit #"               // 0x02B
> > +	"Verify complete: Unit #",              // 0x02B
> > +	"Overwrote bad sector during rebuild: Port #",  //0x2C
> > +	"Encountered bad sector during rebuild: Port #" //0x2D
> >  };
> > 
> > -#define TW_AEN_STRING_MAX                      0x02C
> > +#define TW_AEN_STRING_MAX                      0x02E
> > +
> > +/*
> > +   Sense key lookup table
> > +   Format: ESDC/flags,SenseKey,AdditionalSenseCode,AdditionalSenseCodeQualifier
> > +*/
> > +static unsigned char tw_sense_table[][4] =
> > +{
> > +  /* Codes for newer firmware */
> > +                            // ATA Error                    SCSI Error
> > +  {0x01, 0x03, 0x13, 0x00}, // Address mark not found       Address mark not found for data field
> > +  {0x04, 0x0b, 0x00, 0x00}, // Aborted command              Aborted command
> > +  {0x10, 0x0b, 0x14, 0x00}, // ID not found                 Recorded entity not found
> > +  {0x40, 0x03, 0x11, 0x00}, // Uncorrectable ECC error      Unrecovered read error
> > +  {0x61, 0x04, 0x00, 0x00}, // Device fault                 Hardware error
> > +  {0x84, 0x0b, 0x47, 0x00}, // Data CRC error               SCSI parity error
> > +  {0xd0, 0x0b, 0x00, 0x00}, // Device busy                  Aborted command
> > +  {0xd1, 0x0b, 0x00, 0x00}, // Device busy                  Aborted command
> > +
> > +  /* Codes for older firmware */
> > +                            // 3ware Error                  SCSI Error
> > +  {0x09, 0x0b, 0x00, 0x00}, // Unrecovered disk error       Aborted command
> > +  {0x37, 0x0b, 0x04, 0x00}, // Unit offline                 Logical unit not ready
> > +  {0x51, 0x0b, 0x00, 0x00}  // Unspecified                  Aborted command
> > +};
> > 
> >  /* Control register bit definitions */
> >  #define TW_CONTROL_CLEAR_HOST_INTERRUPT	       0x00080000
> > @@ -108,6 +134,7 @@
> >  #define TW_CONTROL_DISABLE_INTERRUPTS	       0x00000040
> >  #define TW_CONTROL_ISSUE_HOST_INTERRUPT	       0x00000020
> >  #define TW_CONTROL_CLEAR_PARITY_ERROR          0x00800000
> > +#define TW_CONTROL_CLEAR_PCI_ABORT             0x00100000
> > 
> >  /* Status register bit definitions */
> >  #define TW_STATUS_MAJOR_VERSION_MASK	       0xF0000000
> > @@ -140,6 +167,7 @@
> >  #define TW_DEVICE_ID2 (0x1001)  /* 7000 series controller */
> >  #define TW_NUMDEVICES 2
> >  #define TW_PCI_CLEAR_PARITY_ERRORS 0xc100
> > +#define TW_PCI_CLEAR_PCI_ABORT     0x2000
> > 
> >  /* Command packet opcodes */
> >  #define TW_OP_NOP	      0x0
> > @@ -153,6 +181,7 @@
> >  #define TW_OP_AEN_LISTEN      0x1c
> >  #define TW_CMD_PACKET         0x1d
> >  #define TW_ATA_PASSTHRU       0x1e
> > +#define TW_CMD_PACKET_WITH_DATA 0x1f
> > 
> >  /* Asynchronous Event Notification (AEN) Codes */
> >  #define TW_AEN_QUEUE_EMPTY       0x0000
> > @@ -169,7 +198,8 @@
> >  #define TW_AEN_SBUF_FAIL         0x0024
> > 
> >  /* Misc defines */
> > -#define TW_ALIGNMENT			      0x200 /* 16 D-WORDS */
> > +#define TW_ALIGNMENT_6000		      64 /* 64 bytes */
> > +#define TW_ALIGNMENT_7000                     4  /* 4 bytes */
> >  #define TW_MAX_UNITS			      16
> >  #define TW_COMMAND_ALIGNMENT_MASK	      0x1ff
> >  #define TW_INIT_MESSAGE_CREDITS		      0x100
> > @@ -179,7 +209,6 @@
> >  #define TW_ATA_PASS_SGL_MAX                   60
> >  #define TW_MAX_PASSTHRU_BYTES                 4096
> >  #define TW_Q_LENGTH			      256
> > -#define TW_MAX_BOUNCEBUF                      16
> >  #define TW_Q_START			      0
> >  #define TW_MAX_SLOT			      32
> >  #define TW_MAX_PCI_BUSES		      255
> > @@ -191,12 +220,9 @@
> >  #define TW_MAX_AEN_TRIES                      100
> >  #define TW_UNIT_ONLINE                        1
> >  #define TW_IN_INTR                            1
> > -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,7)
> >  #define TW_MAX_SECTORS                        256
> > -#else
> > -#define TW_MAX_SECTORS                        128
> > -#endif
> >  #define TW_AEN_WAIT_TIME                      1000
> > +#define TW_IOCTL_WAIT_TIME                    (1 * HZ) /* 1 second */
> > 
> >  /* Macros */
> >  #define TW_STATUS_ERRORS(x) \
> > @@ -262,7 +288,6 @@
> >  } TW_Command;
> > 
> >  typedef struct TAG_TW_Ioctl {
> > -	int buffer;
> >  	unsigned char opcode;
> >  	unsigned short table_id;
> >  	unsigned char parameter_id;
> > @@ -345,11 +370,8 @@
> >  	TW_Registers		registers;
> >  	u32			*alignment_virtual_address[TW_Q_LENGTH];
> >  	u32			alignment_physical_address[TW_Q_LENGTH];
> > -	u32			*bounce_buffer[TW_Q_LENGTH];
> >  	int			is_unit_present[TW_MAX_UNITS];
> > -	int			is_raid_five[TW_MAX_UNITS];
> >  	int			num_units;
> > -	int			num_raid_five;
> >  	u32			*command_packet_virtual_address[TW_Q_LENGTH];
> >  	u32			command_packet_physical_address[TW_Q_LENGTH];
> >  	struct pci_dev		*tw_pci_dev;
> > @@ -381,22 +403,24 @@
> >  	unsigned char		aen_head;
> >  	unsigned char		aen_tail;
> >  	long			flags; /* long req'd for set_bit --RR */
> > +	char			*ioctl_data[TW_Q_LENGTH];
> >  } TW_Device_Extension;
> > 
> >  /* Function prototypes */
> >  int tw_aen_complete(TW_Device_Extension *tw_dev, int request_id);
> >  int tw_aen_drain_queue(TW_Device_Extension *tw_dev);
> >  int tw_aen_read_queue(TW_Device_Extension *tw_dev, int request_id);
> > -int tw_allocate_memory(TW_Device_Extension *tw_dev, int request_id, int size, int which);
> > +int tw_allocate_memory(TW_Device_Extension *tw_dev, int size, int which);
> >  int tw_check_bits(u32 status_reg_value);
> >  int tw_check_errors(TW_Device_Extension *tw_dev);
> >  void tw_clear_attention_interrupt(TW_Device_Extension *tw_dev);
> >  void tw_clear_host_interrupt(TW_Device_Extension *tw_dev);
> >  void tw_decode_bits(TW_Device_Extension *tw_dev, u32 status_reg_value);
> > -void tw_decode_error(TW_Device_Extension *tw_dev, unsigned char status, unsigned char flags, unsigned char unit);
> > +void tw_decode_sense(TW_Device_Extension *tw_dev, int request_id, int fill_sense);
> >  void tw_disable_interrupts(TW_Device_Extension *tw_dev);
> >  int tw_empty_response_que(TW_Device_Extension *tw_dev);
> >  void tw_enable_interrupts(TW_Device_Extension *tw_dev);
> > +void tw_enable_and_clear_interrupts(TW_Device_Extension *tw_dev);
> >  int tw_findcards(Scsi_Host_Template *tw_host);
> >  void tw_free_device_extension(TW_Device_Extension *tw_dev);
> >  int tw_initconnection(TW_Device_Extension *tw_dev, int message_credits);
> > 
> > 
> > -
> > To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> > the body of a message to majordomo@vger.kernel.org
> > More majordomo info at  http://vger.kernel.org/majordomo-info.html
> > Please read the FAQ at  http://www.tux.org/lkml/
> -
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2002-02-27 23:15 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2002-02-27 21:45 3ware driver update for 2.5.6-pre2 (new DMA mapping) adam@mailhost.nmt.edu
2002-02-27 22:46 ` Jeff V. Merkey
2002-02-27 22:58 ` Jeff V. Merkey
2002-02-27 23:28   ` Jeff V. Merkey

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®