vserver 1.9.5.x5
[linux-2.6.git] / drivers / scsi / 3w-xxxx.c
index 68ca37d..9073638 100644 (file)
    1.26.00.039 - Fix bug in tw_chrdev_ioctl() polling code.
                  Fix data_buffer_length usage in tw_chrdev_ioctl().
                  Update contact information.
+   1.26.02.000 - Convert driver to pci_driver format.
 */
 
 #include <linux/module.h>
-
-MODULE_AUTHOR ("3ware Inc.");
-#ifdef CONFIG_SMP
-MODULE_DESCRIPTION ("3ware Storage Controller Linux Driver (SMP)");
-#else
-MODULE_DESCRIPTION ("3ware Storage Controller Linux Driver");
-#endif
-MODULE_LICENSE("GPL");
-
-#include <linux/kernel.h>
-#include <linux/pci.h>
-#include <linux/time.h>
-#include <linux/proc_fs.h>
-#include <linux/sched.h>
-#include <linux/ioport.h>
-#include <linux/blkdev.h>
-#include <linux/hdreg.h>
-#include <linux/string.h>
-#include <linux/delay.h>
-#include <linux/smp.h>
 #include <linux/reboot.h>
 #include <linux/spinlock.h>
 #include <linux/interrupt.h>
 #include <linux/moduleparam.h>
-
-#include <asm/errno.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/time.h>
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/uaccess.h>
-
-#define __3W_C                 /* let 3w-xxxx.h know it is use */
-
-#include "scsi.h"
+#include <scsi/scsi.h>
 #include <scsi/scsi_host.h>
-
+#include <scsi/scsi_tcq.h>
+#include <scsi/scsi_cmnd.h>
 #include "3w-xxxx.h"
 
-static int tw_chrdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
-static int tw_chrdev_open(struct inode *inode, struct file *file);
-static int tw_chrdev_release(struct inode *inode, struct file *file);
-static int tw_copy_info(TW_Info *info, char *fmt, ...);
-static void tw_copy_mem_info(TW_Info *info, char *data, int len);
-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
-};
-
-/* File operations struct for character device */
-static struct file_operations tw_fops = {
-       .owner          = THIS_MODULE,
-       .ioctl          = tw_chrdev_ioctl,
-       .open           = tw_chrdev_open,
-       .release        = tw_chrdev_release
-};
-
 /* Globals */
-char *tw_driver_version="1.26.00.039";
-TW_Device_Extension *tw_device_extension_list[TW_MAX_SLOT];
-int tw_device_extension_count = 0;
+#define TW_DRIVER_VERSION "1.26.02.000"
+static TW_Device_Extension *tw_device_extension_list[TW_MAX_SLOT];
+static int tw_device_extension_count = 0;
 static int twe_major = -1;
-static int cmds_per_lun;
 
 /* Module parameters */
-module_param(cmds_per_lun, int, 0);
-MODULE_PARM_DESC(cmds_per_lun, "Maximum commands per LUN");
+MODULE_AUTHOR("AMCC");
+MODULE_DESCRIPTION("3ware Storage Controller Linux Driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(TW_DRIVER_VERSION);
+
+/* Function prototypes */
+static int tw_reset_device_extension(TW_Device_Extension *tw_dev, int ioctl_reset);
 
 /* Functions */
 
-/* This function will complete an aen request from the isr */
-int tw_aen_complete(TW_Device_Extension *tw_dev, int request_id) 
+/* This function will check the status register for unexpected bits */
+static int tw_check_bits(u32 status_reg_value)
 {
-       TW_Param *param;
-       unsigned short aen;
-       int error = 0, table_max = 0;
-
-       dprintk(KERN_WARNING "3w-xxxx: tw_aen_complete()\n");
-       if (tw_dev->alignment_virtual_address[request_id] == NULL) {
-               printk(KERN_WARNING "3w-xxxx: tw_aen_complete(): Bad alignment virtual address.\n");
+       if ((status_reg_value & TW_STATUS_EXPECTED_BITS) != TW_STATUS_EXPECTED_BITS) {  
+               dprintk(KERN_WARNING "3w-xxxx: tw_check_bits(): No expected bits (0x%x).\n", status_reg_value);
+               return 1;
+       }
+       if ((status_reg_value & TW_STATUS_UNEXPECTED_BITS) != 0) {
+               dprintk(KERN_WARNING "3w-xxxx: tw_check_bits(): Found unexpected bits (0x%x).\n", status_reg_value);
                return 1;
        }
-       param = (TW_Param *)tw_dev->alignment_virtual_address[request_id];
-       aen = *(unsigned short *)(param->data);
-       dprintk(KERN_NOTICE "3w-xxxx: tw_aen_complete(): Queue'd code 0x%x\n", aen);
 
-       /* Print some useful info when certain aen codes come out */
-       if (aen == 0x0ff) {
-               printk(KERN_WARNING "3w-xxxx: scsi%d: AEN: INFO: AEN queue overflow.\n", tw_dev->host->host_no);
-       } else {
-               table_max = sizeof(tw_aen_string)/sizeof(char *);
-               if ((aen & 0x0ff) < table_max) {
-                       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 {
-                               if (aen != 0x0) 
-                                       printk(KERN_WARNING "3w-xxxx: scsi%d: AEN: %s.\n", tw_dev->host->host_no, tw_aen_string[aen & 0xff]);
-                       }
-               } else {
-                       printk(KERN_WARNING "3w-xxxx: scsi%d: Received AEN %d.\n", tw_dev->host->host_no, aen);
-               }
+       return 0;
+} /* End tw_check_bits() */
+
+/* This function will print readable messages from status register errors */
+static int tw_decode_bits(TW_Device_Extension *tw_dev, u32 status_reg_value, int print_host)
+{
+       char host[16];
+
+       dprintk(KERN_WARNING "3w-xxxx: tw_decode_bits()\n");
+
+       if (print_host)
+               sprintf(host, " scsi%d:", tw_dev->host->host_no);
+       else
+               host[0] = '\0';
+
+       if (status_reg_value & TW_STATUS_PCI_PARITY_ERROR) {
+               printk(KERN_WARNING "3w-xxxx:%s PCI Parity Error: clearing.\n", host);
+               outl(TW_CONTROL_CLEAR_PARITY_ERROR, TW_CONTROL_REG_ADDR(tw_dev));
        }
-       if (aen != TW_AEN_QUEUE_EMPTY) {
-               tw_dev->aen_count++;
 
-               /* Now queue the code */
-               tw_dev->aen_queue[tw_dev->aen_tail] = aen;
-               if (tw_dev->aen_tail == TW_Q_LENGTH - 1) {
-                       tw_dev->aen_tail = TW_Q_START;
-               } else {
-                       tw_dev->aen_tail = tw_dev->aen_tail + 1;
-               }
-               if (tw_dev->aen_head == tw_dev->aen_tail) {
-                       if (tw_dev->aen_head == TW_Q_LENGTH - 1) {
-                               tw_dev->aen_head = TW_Q_START;
-                       } else {
-                               tw_dev->aen_head = tw_dev->aen_head + 1;
-                       }
-               }
+       if (status_reg_value & TW_STATUS_PCI_ABORT) {
+               printk(KERN_WARNING "3w-xxxx:%s PCI Abort: clearing.\n", host);
+               outl(TW_CONTROL_CLEAR_PCI_ABORT, TW_CONTROL_REG_ADDR(tw_dev));
+               pci_write_config_word(tw_dev->tw_pci_dev, PCI_STATUS, TW_PCI_CLEAR_PCI_ABORT);
+       }
 
-               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);
+       if (status_reg_value & TW_STATUS_QUEUE_ERROR) {
+               printk(KERN_WARNING "3w-xxxx:%s Controller Queue Error: clearing.\n", host);
+               outl(TW_CONTROL_CLEAR_QUEUE_ERROR, TW_CONTROL_REG_ADDR(tw_dev));
        }
 
+       if (status_reg_value & TW_STATUS_SBUF_WRITE_ERROR) {
+               printk(KERN_WARNING "3w-xxxx:%s SBUF Write Error: clearing.\n", host);
+               outl(TW_CONTROL_CLEAR_SBUF_WRITE_ERROR, TW_CONTROL_REG_ADDR(tw_dev));
+       }
+
+       if (status_reg_value & TW_STATUS_MICROCONTROLLER_ERROR) {
+               if (tw_dev->reset_print == 0) {
+                       printk(KERN_WARNING "3w-xxxx:%s Microcontroller Error: clearing.\n", host);
+                       tw_dev->reset_print = 1;
+               }
+               return 1;
+       }
+       
        return 0;
-} /* End tw_aen_complete() */
+} /* End tw_decode_bits() */
 
-/* This function will drain the aen queue after a soft reset */
-int tw_aen_drain_queue(TW_Device_Extension *tw_dev)
+/* This function will poll the status register for a flag */
+static int tw_poll_status(TW_Device_Extension *tw_dev, u32 flag, int seconds)
 {
-       TW_Command *command_packet;
-       TW_Param *param;
-       int request_id = 0;
-       u32 command_que_addr;
-       unsigned long command_que_value;
-       unsigned long param_value;
-       TW_Response_Queue response_queue;
-       u32 response_que_addr;
-       unsigned short aen;
-       unsigned short aen_code;
-       int finished = 0;
-       int first_reset = 0;
-       int queue = 0;
-       int found = 0, table_max = 0;
+       u32 status_reg_value;
+       unsigned long before;
+       int retval = 1;
 
-       dprintk(KERN_NOTICE "3w-xxxx: tw_aen_drain_queue()\n");
+       status_reg_value = inl(TW_STATUS_REG_ADDR(tw_dev));
+       before = jiffies;
 
-       command_que_addr = tw_dev->registers.command_que_addr;
-       response_que_addr = tw_dev->registers.response_que_addr;
+       if (tw_check_bits(status_reg_value))
+               tw_decode_bits(tw_dev, status_reg_value, 0);
 
-       if (tw_poll_status(tw_dev, TW_STATUS_ATTENTION_INTERRUPT | TW_STATUS_MICROCONTROLLER_READY, 30)) {
-               dprintk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): No attention interrupt for card %d.\n", tw_device_extension_count);
-               return 1;
+       while ((status_reg_value & flag) != flag) {
+               status_reg_value = inl(TW_STATUS_REG_ADDR(tw_dev));
+
+               if (tw_check_bits(status_reg_value))
+                       tw_decode_bits(tw_dev, status_reg_value, 0);
+
+               if (time_after(jiffies, before + HZ * seconds))
+                       goto out;
+
+               msleep(50);
        }
-       tw_clear_attention_interrupt(tw_dev);
+       retval = 0;
+out:
+       return retval;
+} /* End tw_poll_status() */
 
-       /* Empty response queue */
-       tw_empty_response_que(tw_dev);
+/* This function will poll the status register for disappearance of a flag */
+static int tw_poll_status_gone(TW_Device_Extension *tw_dev, u32 flag, int seconds)
+{
+       u32 status_reg_value;
+       unsigned long before;
+       int retval = 1;
 
-       /* Initialize command packet */
-       if (tw_dev->command_packet_virtual_address[request_id] == NULL) {
-               printk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): Bad command packet virtual address.\n");
-               return 1;
+       status_reg_value = inl(TW_STATUS_REG_ADDR(tw_dev));
+       before = jiffies;
+
+       if (tw_check_bits(status_reg_value))
+               tw_decode_bits(tw_dev, status_reg_value, 0);
+
+       while ((status_reg_value & flag) != 0) {
+               status_reg_value = inl(TW_STATUS_REG_ADDR(tw_dev));
+
+               if (tw_check_bits(status_reg_value))
+                       tw_decode_bits(tw_dev, status_reg_value, 0);
+
+               if (time_after(jiffies, before + HZ * seconds))
+                       goto out;
+
+               msleep(50);
        }
-       command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id];
-       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.parameter_count = 1;
+       retval = 0;
+out:
+       return retval;
+} /* End tw_poll_status_gone() */
+
+/* This function will attempt to post a command packet to the board */
+static int tw_post_command_packet(TW_Device_Extension *tw_dev, int request_id)
+{
+       u32 status_reg_value;
+       unsigned long command_que_value;
+
+       dprintk(KERN_NOTICE "3w-xxxx: tw_post_command_packet()\n");
        command_que_value = tw_dev->command_packet_physical_address[request_id];
-       if (command_que_value == 0) {
-               printk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): Bad command packet physical address.\n");
-               return 1;
-       }
+       status_reg_value = inl(TW_STATUS_REG_ADDR(tw_dev));
 
-       /* Now setup the param */
-       if (tw_dev->alignment_virtual_address[request_id] == NULL) {
-               printk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): Bad alignment virtual address.\n");
-               return 1;
+       if (tw_check_bits(status_reg_value)) {
+               dprintk(KERN_WARNING "3w-xxxx: tw_post_command_packet(): Unexpected bits.\n");
+               tw_decode_bits(tw_dev, status_reg_value, 1);
        }
-       param = (TW_Param *)tw_dev->alignment_virtual_address[request_id];
-       memset(param, 0, sizeof(TW_Sector));
-       param->table_id = 0x401; /* AEN table */
-       param->parameter_id = 2; /* Unit code */
-       param->parameter_size_bytes = 2;
-       param_value = tw_dev->alignment_physical_address[request_id];
-       if (param_value == 0) {
-               printk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): Bad alignment physical address.\n");
+
+       if ((status_reg_value & TW_STATUS_COMMAND_QUEUE_FULL) == 0) {
+               /* We successfully posted the command packet */
+               outl(command_que_value, TW_COMMAND_QUEUE_REG_ADDR(tw_dev));
+               tw_dev->state[request_id] = TW_S_POSTED;
+               tw_dev->posted_request_count++;
+               if (tw_dev->posted_request_count > tw_dev->max_posted_request_count) {
+                       tw_dev->max_posted_request_count = tw_dev->posted_request_count;
+               }
+       } else {
+               /* Couldn't post the command packet, so we do it in the isr */
+               if (tw_dev->state[request_id] != TW_S_PENDING) {
+                       tw_dev->state[request_id] = TW_S_PENDING;
+                       tw_dev->pending_request_count++;
+                       if (tw_dev->pending_request_count > tw_dev->max_pending_request_count) {
+                               tw_dev->max_pending_request_count = tw_dev->pending_request_count;
+                       }
+                       tw_dev->pending_queue[tw_dev->pending_tail] = request_id;
+                       if (tw_dev->pending_tail == TW_Q_LENGTH-1) {
+                               tw_dev->pending_tail = TW_Q_START;
+                       } else {
+                               tw_dev->pending_tail = tw_dev->pending_tail + 1;
+                       }
+               } 
+               TW_UNMASK_COMMAND_INTERRUPT(tw_dev);
                return 1;
        }
-       command_packet->byte8.param.sgl[0].address = param_value;
-       command_packet->byte8.param.sgl[0].length = sizeof(TW_Sector);
+       return 0;
+} /* End tw_post_command_packet() */
 
-       /* Now drain the controller's aen queue */
-       do {
-               /* Post command packet */
-               outl(command_que_value, command_que_addr);
+/* This function will return valid sense buffer information for failed cmds */
+static int tw_decode_sense(TW_Device_Extension *tw_dev, int request_id, int fill_sense)
+{
+       int i;
+       TW_Command *command;
 
-               /* Now poll for completion */
-               if (tw_poll_status_gone(tw_dev, TW_STATUS_RESPONSE_QUEUE_EMPTY, 30) == 0) {
-                       response_queue.value = inl(response_que_addr);
-                       request_id = (unsigned char)response_queue.u.response_id;
+        dprintk(KERN_WARNING "3w-xxxx: tw_decode_sense()\n");
+       command = (TW_Command *)tw_dev->command_packet_virtual_address[request_id];
 
-                       if (request_id != 0) {
-                               /* Unexpected request id */
-                               printk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): Unexpected request id.\n");
-                               return 1;
-                       }
-                       
-                       if (command_packet->status != 0) {
-                               if (command_packet->flags != TW_AEN_TABLE_UNDEFINED) {
-                                       /* Bad response */
-                                       tw_decode_sense(tw_dev, request_id, 0);
-                                       return 1;
-                               } else {
-                                       /* We know this is a 3w-1x00, and doesn't support aen's */
-                                       return 0;
-                               }
-                       }
+       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, TW_UNIT_OUT(command->unit__hostid));
 
-                       /* Now check the aen */
-                       aen = *(unsigned short *)(param->data);
-                       aen_code = (aen & 0x0ff);
-                       queue = 0;
-                       switch (aen_code) {
-                               case TW_AEN_QUEUE_EMPTY:
-                                       dprintk(KERN_WARNING "3w-xxxx: AEN: %s.\n", tw_aen_string[aen & 0xff]);
-                                       if (first_reset != 1) {
-                                               return 1;
-                                       } else {
-                                               finished = 1;
-                                       }
-                                       break;
-                               case TW_AEN_SOFT_RESET:
-                                       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;
-                               default:
-                                       if (aen == 0x0ff) {
-                                               printk(KERN_WARNING "3w-xxxx: AEN: INFO: AEN queue overflow.\n");
-                                       } else {
-                                               table_max = sizeof(tw_aen_string)/sizeof(char *);
-                                               if ((aen & 0x0ff) < table_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;
-                       }
+       /* 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]) {
 
-                       /* Now put the aen on the aen_queue */
-                       if (queue == 1) {
-                               tw_dev->aen_queue[tw_dev->aen_tail] = aen;
-                               if (tw_dev->aen_tail == TW_Q_LENGTH - 1) {
-                                       tw_dev->aen_tail = TW_Q_START;
-                               } else {
-                                       tw_dev->aen_tail = tw_dev->aen_tail + 1;
-                               }
-                               if (tw_dev->aen_head == tw_dev->aen_tail) {
-                                       if (tw_dev->aen_head == TW_Q_LENGTH - 1) {
-                                               tw_dev->aen_head = TW_Q_START;
-                                       } else {
-                                               tw_dev->aen_head = tw_dev->aen_head + 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);
+                                       return TW_ISR_DONT_RESULT; /* Special case for isr to not over-write result */
                                }
                        }
-                       found = 1;
-               }
-               if (found == 0) {
-                       printk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): Response never received.\n");
-                       return 1;
                }
-       } while (finished == 0);
+
+               /* If no table match, error so we get a reset */
+               return 1;
+       }
 
        return 0;
-} /* End tw_aen_drain_queue() */
+} /* End tw_decode_sense() */
+
+/* This function will report controller error status */
+static int tw_check_errors(TW_Device_Extension *tw_dev) 
+{
+       u32 status_reg_value;
+  
+       status_reg_value = inl(TW_STATUS_REG_ADDR(tw_dev));
+
+       if (TW_STATUS_ERRORS(status_reg_value) || tw_check_bits(status_reg_value)) {
+               tw_decode_bits(tw_dev, status_reg_value, 0);
+               return 1;
+       }
+
+       return 0;
+} /* End tw_check_errors() */
+
+/* This function will empty the response que */
+static void tw_empty_response_que(TW_Device_Extension *tw_dev) 
+{
+       u32 status_reg_value, response_que_value;
+
+       status_reg_value = inl(TW_STATUS_REG_ADDR(tw_dev));
+
+       while ((status_reg_value & TW_STATUS_RESPONSE_QUEUE_EMPTY) == 0) {
+               response_que_value = inl(TW_RESPONSE_QUEUE_REG_ADDR(tw_dev));
+               status_reg_value = inl(TW_STATUS_REG_ADDR(tw_dev));
+       }
+} /* End tw_empty_response_que() */
+
+/* This function will free a request_id */
+static void tw_state_request_finish(TW_Device_Extension *tw_dev, int request_id)
+{
+       tw_dev->free_queue[tw_dev->free_tail] = request_id;
+       tw_dev->state[request_id] = TW_S_FINISHED;
+       tw_dev->free_tail = (tw_dev->free_tail + 1) % TW_Q_LENGTH;
+} /* End tw_state_request_finish() */
+
+/* This function will assign an available request_id */
+static void tw_state_request_start(TW_Device_Extension *tw_dev, int *request_id)
+{
+       *request_id = tw_dev->free_queue[tw_dev->free_head];
+       tw_dev->free_head = (tw_dev->free_head + 1) % TW_Q_LENGTH;
+       tw_dev->state[*request_id] = TW_S_STARTED;
+} /* End tw_state_request_start() */
+
+/* Show some statistics about the card */
+static ssize_t tw_show_stats(struct class_device *class_dev, char *buf)
+{
+       struct Scsi_Host *host = class_to_shost(class_dev);
+       TW_Device_Extension *tw_dev = (TW_Device_Extension *)host->hostdata;
+       unsigned long flags = 0;
+       ssize_t len;
+
+       spin_lock_irqsave(tw_dev->host->host_lock, flags);
+       len = snprintf(buf, PAGE_SIZE, "3w-xxxx Driver version: %s\n"
+                      "Current commands posted:   %4d\n"
+                      "Max commands posted:       %4d\n"
+                      "Current pending commands:  %4d\n"
+                      "Max pending commands:      %4d\n"
+                      "Last sgl length:           %4d\n"
+                      "Max sgl length:            %4d\n"
+                      "Last sector count:         %4d\n"
+                      "Max sector count:          %4d\n"
+                      "SCSI Host Resets:          %4d\n"
+                      "AEN's:                     %4d\n", 
+                      TW_DRIVER_VERSION,
+                      tw_dev->posted_request_count,
+                      tw_dev->max_posted_request_count,
+                      tw_dev->pending_request_count,
+                      tw_dev->max_pending_request_count,
+                      tw_dev->sgl_entries,
+                      tw_dev->max_sgl_entries,
+                      tw_dev->sector_count,
+                      tw_dev->max_sector_count,
+                      tw_dev->num_resets,
+                      tw_dev->aen_count);
+       spin_unlock_irqrestore(tw_dev->host->host_lock, flags);
+       return len;
+} /* End tw_show_stats() */
+
+/* This function will set a devices queue depth */
+static ssize_t tw_store_queue_depth(struct device *dev, const char *buf, size_t count)
+{
+       int queue_depth;
+       struct scsi_device *sdev = to_scsi_device(dev);
+
+       queue_depth = simple_strtoul(buf, NULL, 0);
+       if (queue_depth > TW_Q_LENGTH-2)
+               return -EINVAL;
+       scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG, queue_depth);
+
+       return count;
+} /* End tw_store_queue_depth() */
+
+/* Create sysfs 'queue_depth' entry */
+static struct device_attribute tw_queue_depth_attr = {
+       .attr = {
+               .name =         "queue_depth",
+               .mode =         S_IRUSR | S_IWUSR,
+       },
+       .store = tw_store_queue_depth
+};
+
+/* Device attributes initializer */
+static struct device_attribute *tw_dev_attrs[] = {
+       &tw_queue_depth_attr,
+       NULL,
+};
+
+/* Create sysfs 'stats' entry */
+static struct class_device_attribute tw_host_stats_attr = {
+       .attr = {
+               .name =         "stats",
+               .mode =         S_IRUGO,
+       },
+       .show = tw_show_stats
+};
+
+/* Host attributes initializer */
+static struct class_device_attribute *tw_host_attrs[] = {
+       &tw_host_stats_attr,
+       NULL,
+};
 
 /* This function will read the aen queue from the isr */
-int tw_aen_read_queue(TW_Device_Extension *tw_dev, int request_id) 
+static int tw_aen_read_queue(TW_Device_Extension *tw_dev, int request_id) 
 {
        TW_Command *command_packet;
        TW_Param *param;
-       u32 command_que_addr;
        unsigned long command_que_value;
-       u32 status_reg_value = 0, status_reg_addr;
+       u32 status_reg_value;
        unsigned long param_value = 0;
 
        dprintk(KERN_NOTICE "3w-xxxx: tw_aen_read_queue()\n");
-       command_que_addr = tw_dev->registers.command_que_addr;
-       status_reg_addr = tw_dev->registers.status_reg_addr;
 
-       status_reg_value = inl(status_reg_addr);
+       status_reg_value = inl(TW_STATUS_REG_ADDR(tw_dev));
        if (tw_check_bits(status_reg_value)) {
                dprintk(KERN_WARNING "3w-xxxx: tw_aen_read_queue(): Unexpected bits.\n");
                tw_decode_bits(tw_dev, status_reg_value, 1);
@@ -516,12 +575,9 @@ int tw_aen_read_queue(TW_Device_Extension *tw_dev, int request_id)
        }
        command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id];
        memset(command_packet, 0, sizeof(TW_Sector));
-       command_packet->byte0.opcode = TW_OP_GET_PARAM;
-       command_packet->byte0.sgl_offset = 2;
+       command_packet->opcode__sgloffset = TW_OPSGL_IN(2, TW_OP_GET_PARAM);
        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.parameter_count = 1;
@@ -553,7 +609,7 @@ int tw_aen_read_queue(TW_Device_Extension *tw_dev, int request_id)
                dprintk(KERN_WARNING "3w-xxxx: tw_aen_read_queue(): Post succeeded.\n");
                tw_dev->srb[request_id] = NULL; /* Flag internal command */
                tw_dev->state[request_id] = TW_S_POSTED;
-               outl(command_que_value, command_que_addr);
+               outl(command_que_value, TW_COMMAND_QUEUE_REG_ADDR(tw_dev));
        } else {
                printk(KERN_WARNING "3w-xxxx: tw_aen_read_queue(): Post failed, will retry.\n");
                return 1;
@@ -562,86 +618,277 @@ int tw_aen_read_queue(TW_Device_Extension *tw_dev, int request_id)
        return 0;
 } /* End tw_aen_read_queue() */
 
-/* This function will allocate memory */
-int tw_allocate_memory(TW_Device_Extension *tw_dev, int size, int which)
+/* This function will complete an aen request from the isr */
+static int tw_aen_complete(TW_Device_Extension *tw_dev, int request_id) 
 {
-       int i;
-       dma_addr_t dma_handle;
-       unsigned long *cpu_addr = NULL;
-
-       dprintk(KERN_NOTICE "3w-xxxx: tw_allocate_memory()\n");
+       TW_Param *param;
+       unsigned short aen;
+       int error = 0, table_max = 0;
 
-       cpu_addr = pci_alloc_consistent(tw_dev->tw_pci_dev, size*TW_Q_LENGTH, &dma_handle);
-       if (cpu_addr == NULL) {
-               printk(KERN_WARNING "3w-xxxx: pci_alloc_consistent() failed.\n");
+       dprintk(KERN_WARNING "3w-xxxx: tw_aen_complete()\n");
+       if (tw_dev->alignment_virtual_address[request_id] == NULL) {
+               printk(KERN_WARNING "3w-xxxx: tw_aen_complete(): Bad alignment virtual address.\n");
                return 1;
        }
+       param = (TW_Param *)tw_dev->alignment_virtual_address[request_id];
+       aen = *(unsigned short *)(param->data);
+       dprintk(KERN_NOTICE "3w-xxxx: tw_aen_complete(): Queue'd code 0x%x\n", aen);
 
-       if ((unsigned long)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");
-               pci_free_consistent(tw_dev->tw_pci_dev, size*TW_Q_LENGTH, cpu_addr, dma_handle);
-               return 1;
+       /* Print some useful info when certain aen codes come out */
+       if (aen == 0x0ff) {
+               printk(KERN_WARNING "3w-xxxx: scsi%d: AEN: INFO: AEN queue overflow.\n", tw_dev->host->host_no);
+       } else {
+               table_max = sizeof(tw_aen_string)/sizeof(char *);
+               if ((aen & 0x0ff) < table_max) {
+                       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 {
+                               if (aen != 0x0) 
+                                       printk(KERN_WARNING "3w-xxxx: scsi%d: AEN: %s.\n", tw_dev->host->host_no, tw_aen_string[aen & 0xff]);
+                       }
+               } else {
+                       printk(KERN_WARNING "3w-xxxx: scsi%d: Received AEN %d.\n", tw_dev->host->host_no, aen);
+               }
        }
+       if (aen != TW_AEN_QUEUE_EMPTY) {
+               tw_dev->aen_count++;
 
-       memset(cpu_addr, 0, size*TW_Q_LENGTH);
+               /* Now queue the code */
+               tw_dev->aen_queue[tw_dev->aen_tail] = aen;
+               if (tw_dev->aen_tail == TW_Q_LENGTH - 1) {
+                       tw_dev->aen_tail = TW_Q_START;
+               } else {
+                       tw_dev->aen_tail = tw_dev->aen_tail + 1;
+               }
+               if (tw_dev->aen_head == tw_dev->aen_tail) {
+                       if (tw_dev->aen_head == TW_Q_LENGTH - 1) {
+                               tw_dev->aen_head = TW_Q_START;
+                       } else {
+                               tw_dev->aen_head = tw_dev->aen_head + 1;
+                       }
+               }
 
-       for (i=0;i<TW_Q_LENGTH;i++) {
-               switch(which) {
-               case 0:
-                       tw_dev->command_packet_physical_address[i] = dma_handle+(i*size);
-                       tw_dev->command_packet_virtual_address[i] = (unsigned long *)((unsigned char *)cpu_addr + (i*size));
-                       break;
-               case 1:
-                       tw_dev->alignment_physical_address[i] = dma_handle+(i*size);
-                       tw_dev->alignment_virtual_address[i] = (unsigned long *)((unsigned char *)cpu_addr + (i*size));
-                       break;
-               default:
-                       printk(KERN_WARNING "3w-xxxx: tw_allocate_memory(): case slip in tw_allocate_memory()\n");
-                       return 1;
+               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_allocate_memory() */
+} /* End tw_aen_complete() */
 
-/* This function will check the status register for unexpected bits */
-int tw_check_bits(u32 status_reg_value)
+/* This function will drain the aen queue after a soft reset */
+static int tw_aen_drain_queue(TW_Device_Extension *tw_dev)
 {
-       if ((status_reg_value & TW_STATUS_EXPECTED_BITS) != TW_STATUS_EXPECTED_BITS) {  
-               dprintk(KERN_WARNING "3w-xxxx: tw_check_bits(): No expected bits (0x%x).\n", status_reg_value);
-               return 1;
-       }
-       if ((status_reg_value & TW_STATUS_UNEXPECTED_BITS) != 0) {
-               dprintk(KERN_WARNING "3w-xxxx: tw_check_bits(): Found unexpected bits (0x%x).\n", status_reg_value);
-               return 1;
-       }
-
-       return 0;
-} /* End tw_check_bits() */
+       TW_Command *command_packet;
+       TW_Param *param;
+       int request_id = 0;
+       unsigned long command_que_value;
+       unsigned long param_value;
+       TW_Response_Queue response_queue;
+       unsigned short aen;
+       unsigned short aen_code;
+       int finished = 0;
+       int first_reset = 0;
+       int queue = 0;
+       int found = 0, table_max = 0;
 
-/* This function will report controller error status */
-int tw_check_errors(TW_Device_Extension *tw_dev) 
-{
-       u32 status_reg_addr, status_reg_value;
-  
-       status_reg_addr = tw_dev->registers.status_reg_addr;
-       status_reg_value = inl(status_reg_addr);
+       dprintk(KERN_NOTICE "3w-xxxx: tw_aen_drain_queue()\n");
 
-       if (TW_STATUS_ERRORS(status_reg_value) || tw_check_bits(status_reg_value)) {
-               tw_decode_bits(tw_dev, status_reg_value, 0);
+       if (tw_poll_status(tw_dev, TW_STATUS_ATTENTION_INTERRUPT | TW_STATUS_MICROCONTROLLER_READY, 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);
 
-       return 0;
-} /* End tw_check_errors() */
+       /* Empty response queue */
+       tw_empty_response_que(tw_dev);
 
-/* This function handles ioctl for the character device */
-static int tw_chrdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
-{
-       int error, request_id;
-       dma_addr_t dma_handle;
-       unsigned short tw_aen_code;
-       unsigned long flags;
+       /* Initialize command packet */
+       if (tw_dev->command_packet_virtual_address[request_id] == NULL) {
+               printk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): Bad command packet virtual address.\n");
+               return 1;
+       }
+       command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id];
+       memset(command_packet, 0, sizeof(TW_Sector));
+       command_packet->opcode__sgloffset = TW_OPSGL_IN(2, TW_OP_GET_PARAM);
+       command_packet->size = 4;
+       command_packet->request_id = request_id;
+       command_packet->status = 0;
+       command_packet->flags = 0;
+       command_packet->byte6.parameter_count = 1;
+       command_que_value = tw_dev->command_packet_physical_address[request_id];
+       if (command_que_value == 0) {
+               printk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): Bad command packet physical address.\n");
+               return 1;
+       }
+
+       /* Now setup the param */
+       if (tw_dev->alignment_virtual_address[request_id] == NULL) {
+               printk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): 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 = 0x401; /* AEN table */
+       param->parameter_id = 2; /* Unit code */
+       param->parameter_size_bytes = 2;
+       param_value = tw_dev->alignment_physical_address[request_id];
+       if (param_value == 0) {
+               printk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): 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);
+
+       /* Now drain the controller's aen queue */
+       do {
+               /* Post command packet */
+               outl(command_que_value, TW_COMMAND_QUEUE_REG_ADDR(tw_dev));
+
+               /* Now poll for completion */
+               if (tw_poll_status_gone(tw_dev, TW_STATUS_RESPONSE_QUEUE_EMPTY, 30) == 0) {
+                       response_queue.value = inl(TW_RESPONSE_QUEUE_REG_ADDR(tw_dev));
+                       request_id = TW_RESID_OUT(response_queue.response_id);
+
+                       if (request_id != 0) {
+                               /* Unexpected request id */
+                               printk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): Unexpected request id.\n");
+                               return 1;
+                       }
+                       
+                       if (command_packet->status != 0) {
+                               if (command_packet->flags != TW_AEN_TABLE_UNDEFINED) {
+                                       /* Bad response */
+                                       tw_decode_sense(tw_dev, request_id, 0);
+                                       return 1;
+                               } else {
+                                       /* We know this is a 3w-1x00, and doesn't support aen's */
+                                       return 0;
+                               }
+                       }
+
+                       /* Now check the aen */
+                       aen = *(unsigned short *)(param->data);
+                       aen_code = (aen & 0x0ff);
+                       queue = 0;
+                       switch (aen_code) {
+                               case TW_AEN_QUEUE_EMPTY:
+                                       dprintk(KERN_WARNING "3w-xxxx: AEN: %s.\n", tw_aen_string[aen & 0xff]);
+                                       if (first_reset != 1) {
+                                               return 1;
+                                       } else {
+                                               finished = 1;
+                                       }
+                                       break;
+                               case TW_AEN_SOFT_RESET:
+                                       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;
+                               default:
+                                       if (aen == 0x0ff) {
+                                               printk(KERN_WARNING "3w-xxxx: AEN: INFO: AEN queue overflow.\n");
+                                       } else {
+                                               table_max = sizeof(tw_aen_string)/sizeof(char *);
+                                               if ((aen & 0x0ff) < table_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;
+                       }
+
+                       /* Now put the aen on the aen_queue */
+                       if (queue == 1) {
+                               tw_dev->aen_queue[tw_dev->aen_tail] = aen;
+                               if (tw_dev->aen_tail == TW_Q_LENGTH - 1) {
+                                       tw_dev->aen_tail = TW_Q_START;
+                               } else {
+                                       tw_dev->aen_tail = tw_dev->aen_tail + 1;
+                               }
+                               if (tw_dev->aen_head == tw_dev->aen_tail) {
+                                       if (tw_dev->aen_head == TW_Q_LENGTH - 1) {
+                                               tw_dev->aen_head = TW_Q_START;
+                                       } else {
+                                               tw_dev->aen_head = tw_dev->aen_head + 1;
+                                       }
+                               }
+                       }
+                       found = 1;
+               }
+               if (found == 0) {
+                       printk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): Response never received.\n");
+                       return 1;
+               }
+       } while (finished == 0);
+
+       return 0;
+} /* End tw_aen_drain_queue() */
+
+/* This function will allocate memory */
+static int tw_allocate_memory(TW_Device_Extension *tw_dev, int size, int which)
+{
+       int i;
+       dma_addr_t dma_handle;
+       unsigned long *cpu_addr = NULL;
+
+       dprintk(KERN_NOTICE "3w-xxxx: tw_allocate_memory()\n");
+
+       cpu_addr = pci_alloc_consistent(tw_dev->tw_pci_dev, size*TW_Q_LENGTH, &dma_handle);
+       if (cpu_addr == NULL) {
+               printk(KERN_WARNING "3w-xxxx: pci_alloc_consistent() failed.\n");
+               return 1;
+       }
+
+       if ((unsigned long)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");
+               pci_free_consistent(tw_dev->tw_pci_dev, size*TW_Q_LENGTH, cpu_addr, dma_handle);
+               return 1;
+       }
+
+       memset(cpu_addr, 0, size*TW_Q_LENGTH);
+
+       for (i=0;i<TW_Q_LENGTH;i++) {
+               switch(which) {
+               case 0:
+                       tw_dev->command_packet_physical_address[i] = dma_handle+(i*size);
+                       tw_dev->command_packet_virtual_address[i] = (unsigned long *)((unsigned char *)cpu_addr + (i*size));
+                       break;
+               case 1:
+                       tw_dev->alignment_physical_address[i] = dma_handle+(i*size);
+                       tw_dev->alignment_virtual_address[i] = (unsigned long *)((unsigned char *)cpu_addr + (i*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() */
+
+/* This function handles ioctl for the character device */
+static int tw_chrdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+       int request_id;
+       dma_addr_t dma_handle;
+       unsigned short tw_aen_code;
+       unsigned long flags;
        unsigned int data_buffer_length = 0;
        unsigned long data_buffer_length_adjusted = 0;
        unsigned long *cpu_addr;
@@ -659,8 +906,7 @@ static int tw_chrdev_ioctl(struct inode *inode, struct file *file, unsigned int
                return -EINTR;
 
        /* First copy down the buffer length */
-       error = copy_from_user(&data_buffer_length, argp, sizeof(unsigned int));
-       if (error)
+       if (copy_from_user(&data_buffer_length, argp, sizeof(unsigned int)))
                goto out;
 
        /* Check size */
@@ -673,7 +919,7 @@ static int tw_chrdev_ioctl(struct inode *inode, struct file *file, unsigned int
        data_buffer_length_adjusted = (data_buffer_length + 511) & ~511;
        
        /* Now allocate ioctl buf memory */
-       cpu_addr = pci_alloc_consistent(tw_dev->tw_pci_dev, data_buffer_length_adjusted+sizeof(TW_New_Ioctl) - 1, &dma_handle);
+       cpu_addr = dma_alloc_coherent(&tw_dev->tw_pci_dev->dev, data_buffer_length_adjusted+sizeof(TW_New_Ioctl) - 1, &dma_handle, GFP_KERNEL);
        if (cpu_addr == NULL) {
                retval = -ENOMEM;
                goto out;
@@ -682,8 +928,7 @@ static int tw_chrdev_ioctl(struct inode *inode, struct file *file, unsigned int
        tw_ioctl = (TW_New_Ioctl *)cpu_addr;
 
        /* Now copy down the entire ioctl */
-       error = copy_from_user(tw_ioctl, argp, data_buffer_length + sizeof(TW_New_Ioctl) - 1);
-       if (error)
+       if (copy_from_user(tw_ioctl, argp, data_buffer_length + sizeof(TW_New_Ioctl) - 1))
                goto out2;
 
        passthru = (TW_Passthru *)&tw_ioctl->firmware_command;
@@ -713,7 +958,7 @@ static int tw_chrdev_ioctl(struct inode *inode, struct file *file, unsigned int
                        break;
                case TW_CMD_PACKET_WITH_DATA:
                        dprintk(KERN_WARNING "3w-xxxx: tw_chrdev_ioctl(): caught TW_CMD_PACKET_WITH_DATA.\n");
-                       spin_lock_irqsave(&tw_dev->tw_lock, flags);
+                       spin_lock_irqsave(tw_dev->host->host_lock, flags);
 
                        tw_state_request_start(tw_dev, &request_id);
 
@@ -726,7 +971,7 @@ static int tw_chrdev_ioctl(struct inode *inode, struct file *file, unsigned int
                        tw_ioctl->firmware_command.request_id = request_id;
 
                        /* Load the sg list */
-                       switch (tw_ioctl->firmware_command.byte0.sgl_offset) {
+                       switch (TW_SGL_OUT(tw_ioctl->firmware_command.opcode__sgloffset)) {
                        case 2:
                                tw_ioctl->firmware_command.byte8.param.sgl[0].address = dma_handle + sizeof(TW_New_Ioctl) - 1;
                                tw_ioctl->firmware_command.byte8.param.sgl[0].length = data_buffer_length_adjusted;
@@ -745,13 +990,20 @@ static int tw_chrdev_ioctl(struct inode *inode, struct file *file, unsigned int
 
                        /* Now post the command packet to the controller */
                        tw_post_command_packet(tw_dev, request_id);
-                       spin_unlock_irqrestore(&tw_dev->tw_lock, flags);
+                       spin_unlock_irqrestore(tw_dev->host->host_lock, flags);
 
                        timeout = TW_IOCTL_CHRDEV_TIMEOUT*HZ;
 
                        /* Now wait for the command to complete */
                        timeout = wait_event_interruptible_timeout(tw_dev->ioctl_wqueue, tw_dev->chrdev_request_id == TW_IOCTL_CHRDEV_FREE, timeout);
 
+                       /* See if we reset while waiting for the ioctl to complete */
+                       if (test_bit(TW_IN_RESET, &tw_dev->flags)) {
+                               clear_bit(TW_IN_RESET, &tw_dev->flags);
+                               retval = -ERESTARTSYS;
+                               goto out2;
+                       }
+
                        /* Check if we timed out, got a signal, or didn't get
                           an interrupt */
                        if ((timeout <= 0) && (tw_dev->chrdev_request_id != TW_IOCTL_CHRDEV_FREE)) {
@@ -762,14 +1014,14 @@ static int tw_chrdev_ioctl(struct inode *inode, struct file *file, unsigned int
                                        printk(KERN_WARNING "3w-xxxx: scsi%d: Character ioctl (0x%x) timed out, resetting card.\n", tw_dev->host->host_no, cmd);
                                        retval = -EIO;
                                }
-                               spin_lock_irqsave(&tw_dev->tw_lock, flags);
+                               spin_lock_irqsave(tw_dev->host->host_lock, flags);
                                tw_dev->state[request_id] = TW_S_COMPLETED;
                                tw_state_request_finish(tw_dev, request_id);
                                tw_dev->posted_request_count--;
-                               if (tw_reset_device_extension(tw_dev)) {
+                               spin_unlock_irqrestore(tw_dev->host->host_lock, flags);
+                               if (tw_reset_device_extension(tw_dev, 1)) {
                                        printk(KERN_WARNING "3w-xxxx: tw_chrdev_ioctl(): Reset failed for card %d.\n", tw_dev->host->host_no);
                                }
-                               spin_unlock_irqrestore(&tw_dev->tw_lock, flags);
                                goto out2;
                        }
 
@@ -777,11 +1029,11 @@ static int tw_chrdev_ioctl(struct inode *inode, struct file *file, unsigned int
                        memcpy(&(tw_ioctl->firmware_command), tw_dev->command_packet_virtual_address[request_id], sizeof(TW_Command));
 
                        /* Now complete the io */
-                       spin_lock_irqsave(&tw_dev->tw_lock, flags);
+                       spin_lock_irqsave(tw_dev->host->host_lock, flags);
                        tw_dev->posted_request_count--;
                        tw_dev->state[request_id] = TW_S_COMPLETED;
                        tw_state_request_finish(tw_dev, request_id);
-                       spin_unlock_irqrestore(&tw_dev->tw_lock, flags);
+                       spin_unlock_irqrestore(tw_dev->host->host_lock, flags);
                        break;
                default:
                        retval = -ENOTTY;
@@ -789,12 +1041,12 @@ static int tw_chrdev_ioctl(struct inode *inode, struct file *file, unsigned int
        }
 
        /* Now copy the response to userspace */
-       error = copy_to_user(argp, tw_ioctl, sizeof(TW_New_Ioctl) + data_buffer_length - 1);
-       if (error == 0)
-               retval = 0;
+       if (copy_to_user(argp, tw_ioctl, sizeof(TW_New_Ioctl) + data_buffer_length - 1))
+               goto out2;
+       retval = 0;
 out2:
        /* Now free ioctl buf memory */
-       pci_free_consistent(tw_dev->tw_pci_dev, data_buffer_length_adjusted+sizeof(TW_New_Ioctl) - 1, cpu_addr, dma_handle);
+       dma_free_coherent(&tw_dev->tw_pci_dev->dev, data_buffer_length_adjusted+sizeof(TW_New_Ioctl) - 1, cpu_addr, dma_handle);
 out:
        up(&tw_dev->ioctl_sem);
        return retval;
@@ -814,535 +1066,201 @@ static int tw_chrdev_open(struct inode *inode, struct file *file)
        return 0;
 } /* End tw_chrdev_open() */
 
-/* This function handles close for the character device */
-static int tw_chrdev_release(struct inode *inode, struct file *file)
-{
-       dprintk(KERN_WARNING "3w-xxxx: tw_ioctl_release()\n");
-
-       return 0;
-} /* End tw_chrdev_release() */
+/* File operations struct for character device */
+static struct file_operations tw_fops = {
+       .owner          = THIS_MODULE,
+       .ioctl          = tw_chrdev_ioctl,
+       .open           = tw_chrdev_open,
+       .release        = NULL
+};
 
-/* This function will clear all interrupts on the controller */
-void tw_clear_all_interrupts(TW_Device_Extension *tw_dev)
+/* This function will free up device extension resources */
+static void tw_free_device_extension(TW_Device_Extension *tw_dev)
 {
-       u32 control_reg_addr, control_reg_value;
+       dprintk(KERN_NOTICE "3w-xxxx: tw_free_device_extension()\n");
 
-       control_reg_addr = tw_dev->registers.control_reg_addr;
-       control_reg_value = TW_STATUS_VALID_INTERRUPT;
-       outl(control_reg_value, control_reg_addr);
-} /* End tw_clear_all_interrupts() */
+       /* Free command packet and generic buffer memory */
+       if (tw_dev->command_packet_virtual_address[0])
+               pci_free_consistent(tw_dev->tw_pci_dev, sizeof(TW_Command)*TW_Q_LENGTH, tw_dev->command_packet_virtual_address[0], tw_dev->command_packet_physical_address[0]);
 
-/* This function will clear the attention interrupt */
-void tw_clear_attention_interrupt(TW_Device_Extension *tw_dev)
-{
-       u32 control_reg_addr, control_reg_value;
-  
-       control_reg_addr = tw_dev->registers.control_reg_addr;
-       control_reg_value = TW_CONTROL_CLEAR_ATTENTION_INTERRUPT;
-       outl(control_reg_value, control_reg_addr);
-} /* End tw_clear_attention_interrupt() */
+       if (tw_dev->alignment_virtual_address[0])
+               pci_free_consistent(tw_dev->tw_pci_dev, sizeof(TW_Sector)*TW_Q_LENGTH, tw_dev->alignment_virtual_address[0], tw_dev->alignment_physical_address[0]);
+} /* End tw_free_device_extension() */
 
-/* This function will clear the host interrupt */
-void tw_clear_host_interrupt(TW_Device_Extension *tw_dev)
+/* This function will send an initconnection command to controller */
+static int tw_initconnection(TW_Device_Extension *tw_dev, int message_credits) 
 {
-       u32 control_reg_addr, control_reg_value;
+       unsigned long command_que_value;
+       TW_Command  *command_packet;
+       TW_Response_Queue response_queue;
+       int request_id = 0;
 
-       control_reg_addr = tw_dev->registers.control_reg_addr;
-       control_reg_value = TW_CONTROL_CLEAR_HOST_INTERRUPT;
-       outl(control_reg_value, control_reg_addr);
-} /* End tw_clear_host_interrupt() */
+       dprintk(KERN_NOTICE "3w-xxxx: tw_initconnection()\n");
 
-/* This function is called by tw_scsi_proc_info */
-static int tw_copy_info(TW_Info *info, char *fmt, ...) 
-{
-       va_list args;
-       char buf[81];
-       int len;
-  
-       va_start(args, fmt);
-       len = vsprintf(buf, fmt, args);
-       va_end(args);
-       tw_copy_mem_info(info, buf, len);
-       return len;
-} /* End tw_copy_info() */
+       /* Initialize InitConnection command packet */
+       if (tw_dev->command_packet_virtual_address[request_id] == NULL) {
+               printk(KERN_WARNING "3w-xxxx: tw_initconnection(): Bad command packet virtual address.\n");
+               return 1;
+       }
 
-/* This function is called by tw_scsi_proc_info */
-static void tw_copy_mem_info(TW_Info *info, char *data, int len)
-{
-       if (info->position + len > info->length)
-               len = info->length - info->position;
+       command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id];
+       memset(command_packet, 0, sizeof(TW_Sector));
+       command_packet->opcode__sgloffset = TW_OPSGL_IN(0, TW_OP_INIT_CONNECTION);
+       command_packet->size = TW_INIT_COMMAND_PACKET_SIZE;
+       command_packet->request_id = request_id;
+       command_packet->status = 0x0;
+       command_packet->flags = 0x0;
+       command_packet->byte6.message_credits = message_credits; 
+       command_packet->byte8.init_connection.response_queue_pointer = 0x0;
+       command_que_value = tw_dev->command_packet_physical_address[request_id];
 
-       if (info->position + len < info->offset) {
-               info->position += len;
-               return;
-       }
-       if (info->position < info->offset) {
-               data += (info->offset - info->position);
-               len  -= (info->offset - info->position);
+       if (command_que_value == 0) {
+               printk(KERN_WARNING "3w-xxxx: tw_initconnection(): Bad command packet physical address.\n");
+               return 1;
        }
-       if (len > 0) {
-               memcpy(info->buffer + info->position, data, len);
-               info->position += len;
+  
+       /* Send command packet to the board */
+       outl(command_que_value, TW_COMMAND_QUEUE_REG_ADDR(tw_dev));
+    
+       /* Poll for completion */
+       if (tw_poll_status_gone(tw_dev, TW_STATUS_RESPONSE_QUEUE_EMPTY, 30) == 0) {
+               response_queue.value = inl(TW_RESPONSE_QUEUE_REG_ADDR(tw_dev));
+               request_id = TW_RESID_OUT(response_queue.response_id);
+
+               if (request_id != 0) {
+                       /* unexpected request id */
+                       printk(KERN_WARNING "3w-xxxx: tw_initconnection(): Unexpected request id.\n");
+                       return 1;
+               }
+               if (command_packet->status != 0) {
+                       /* bad response */
+                       tw_decode_sense(tw_dev, request_id, 0);
+                       return 1;
+               }
        }
-} /* End tw_copy_mem_info() */
+       return 0;
+} /* End tw_initconnection() */
 
-/* This function will print readable messages from status register errors */
-int tw_decode_bits(TW_Device_Extension *tw_dev, u32 status_reg_value, int print_host)
+/* Set a value in the features table */
+static int tw_setfeature(TW_Device_Extension *tw_dev, int parm, int param_size,
+                  unsigned char *val)
 {
-       char host[16];
-
-       dprintk(KERN_WARNING "3w-xxxx: tw_decode_bits()\n");
-
-       if (print_host)
-               sprintf(host, " scsi%d:", tw_dev->host->host_no);
-       else
-               host[0] = '\0';
+       TW_Param *param;
+       TW_Command  *command_packet;
+       TW_Response_Queue response_queue;
+       int request_id = 0;
+       unsigned long command_que_value;
+       unsigned long param_value;
 
-       if (status_reg_value & TW_STATUS_PCI_PARITY_ERROR) {
-               printk(KERN_WARNING "3w-xxxx:%s PCI Parity Error: clearing.\n", host);
-               outl(TW_CONTROL_CLEAR_PARITY_ERROR, tw_dev->registers.control_reg_addr);
+       /* Initialize SetParam command packet */
+       if (tw_dev->command_packet_virtual_address[request_id] == NULL) {
+               printk(KERN_WARNING "3w-xxxx: tw_setfeature(): Bad command packet virtual address.\n");
+               return 1;
        }
+       command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id];
+       memset(command_packet, 0, sizeof(TW_Sector));
+       param = (TW_Param *)tw_dev->alignment_virtual_address[request_id];
 
-       if (status_reg_value & TW_STATUS_PCI_ABORT) {
-               printk(KERN_WARNING "3w-xxxx:%s PCI Abort: clearing.\n", host);
-               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);
-       }
+       command_packet->opcode__sgloffset = TW_OPSGL_IN(2, TW_OP_SET_PARAM);
+       param->table_id = 0x404;  /* Features table */
+       param->parameter_id = parm;
+       param->parameter_size_bytes = param_size;
+       memcpy(param->data, val, param_size);
 
-       if (status_reg_value & TW_STATUS_QUEUE_ERROR) {
-               printk(KERN_WARNING "3w-xxxx:%s Controller Queue Error: clearing.\n", host);
-               outl(TW_CONTROL_CLEAR_QUEUE_ERROR, tw_dev->registers.control_reg_addr);
+       param_value = tw_dev->alignment_physical_address[request_id];
+       if (param_value == 0) {
+               printk(KERN_WARNING "3w-xxxx: tw_setfeature(): Bad alignment physical address.\n");
+               tw_dev->state[request_id] = TW_S_COMPLETED;
+               tw_state_request_finish(tw_dev, request_id);
+               tw_dev->srb[request_id]->result = (DID_OK << 16);
+               tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]);
        }
+       command_packet->byte8.param.sgl[0].address = param_value;
+       command_packet->byte8.param.sgl[0].length = sizeof(TW_Sector);
 
-       if (status_reg_value & TW_STATUS_SBUF_WRITE_ERROR) {
-               printk(KERN_WARNING "3w-xxxx:%s SBUF Write Error: clearing.\n", host);
-               outl(TW_CONTROL_CLEAR_SBUF_WRITE_ERROR, tw_dev->registers.control_reg_addr);
-       }
+       command_packet->size = 4;
+       command_packet->request_id = request_id;
+       command_packet->byte6.parameter_count = 1;
 
-       if (status_reg_value & TW_STATUS_MICROCONTROLLER_ERROR) {
-               if (tw_dev->reset_print == 0) {
-                       printk(KERN_WARNING "3w-xxxx:%s Microcontroller Error: clearing.\n", host);
-                       tw_dev->reset_print = 1;
-               }
-               return 1;
+       command_que_value = tw_dev->command_packet_physical_address[request_id];
+       if (command_que_value == 0) {
+               printk(KERN_WARNING "3w-xxxx: tw_setfeature(): Bad command packet physical address.\n");
+       return 1;
        }
-       
-       return 0;
-} /* End tw_decode_bits() */
-
-/* This function will return valid sense buffer information for failed cmds */
-int tw_decode_sense(TW_Device_Extension *tw_dev, int request_id, int fill_sense)
-{
-       int i;
-       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]) {
-
-                                       /* 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];
+       /* Send command packet to the board */
+       outl(command_que_value, TW_COMMAND_QUEUE_REG_ADDR(tw_dev));
 
-                                       /* Additional sense code qualifier */
-                                       tw_dev->srb[request_id]->sense_buffer[13] = tw_sense_table[i][3];
+       /* Poll for completion */
+       if (tw_poll_status_gone(tw_dev, TW_STATUS_RESPONSE_QUEUE_EMPTY, 30) == 0) {
+               response_queue.value = inl(TW_RESPONSE_QUEUE_REG_ADDR(tw_dev));
+               request_id = TW_RESID_OUT(response_queue.response_id);
 
-                                       tw_dev->srb[request_id]->result = (DID_OK << 16) | (CHECK_CONDITION << 1);
-                                       return TW_ISR_DONT_RESULT; /* Special case for isr to not over-write result */
-                               }
-                       }
+               if (request_id != 0) {
+                       /* unexpected request id */
+                       printk(KERN_WARNING "3w-xxxx: tw_setfeature(): Unexpected request id.\n");
+                       return 1;
+               }
+               if (command_packet->status != 0) {
+                       /* bad response */
+                       tw_decode_sense(tw_dev, request_id, 0);
+                       return 1;
                }
-
-               /* If no table match, error so we get a reset */
-               return 1;
        }
 
        return 0;
-} /* End tw_decode_sense() */
-
-/* This function will disable interrupts on the controller */  
-void tw_disable_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_DISABLE_INTERRUPTS;
-       outl(control_reg_value, control_reg_addr);
-} /* End tw_disable_interrupts() */
-
-/* This function will empty the response que */
-void tw_empty_response_que(TW_Device_Extension *tw_dev) 
-{
-       u32 status_reg_addr, status_reg_value;
-       u32 response_que_addr, response_que_value;
-
-       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);
-
-       while ((status_reg_value & TW_STATUS_RESPONSE_QUEUE_EMPTY) == 0) {
-               response_que_value = inl(response_que_addr);
-               status_reg_value = inl(status_reg_addr);
-       }
-} /* End tw_empty_response_que() */
-
-/* This function will enable interrupts on the controller */
-void tw_enable_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_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_and_clear_interrupts() */
+} /* End tw_setfeature() */
 
-/* This function will find and initialize all cards */
-int tw_findcards(Scsi_Host_Template *tw_host
+/* This function will reset a controller */
+static int tw_reset_sequence(TW_Device_Extension *tw_dev
 {
-       int numcards = 0, tries = 0, error = 0;
-       struct Scsi_Host *host;
-       TW_Device_Extension *tw_dev;
-       TW_Device_Extension *tw_dev2;
-       struct pci_dev *tw_pci_dev = NULL;
-       u32 status_reg_value;
+       int error = 0;
+       int tries = 0;
        unsigned char c = 1;
-       int i, j = -1;
-       u16 device[TW_NUMDEVICES] = { TW_DEVICE_ID, TW_DEVICE_ID2 };
 
-       dprintk(KERN_NOTICE "3w-xxxx: tw_findcards()\n");
-
-       for (i=0;i<TW_NUMDEVICES;i++) {
-               while ((tw_pci_dev = pci_find_device(TW_VENDOR_ID, device[i], tw_pci_dev))) {
-                       j++;
-                       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) {
-                               printk(KERN_WARNING "3w-xxxx: tw_findcards(): kmalloc() failed for card %d.\n", j);
-                               continue;
-                       }
-                       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", j);
-                               tw_free_device_extension(tw_dev);
-                               kfree(tw_dev);
-                               continue;
-                       }
-
-                       /* Calculate the cards register addresses */
-                       tw_dev->registers.base_addr = pci_resource_start(tw_pci_dev, 0);
-                       tw_dev->registers.control_reg_addr = pci_resource_start(tw_pci_dev, 0);
-                       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;
-
-                       /* Check for errors and clear them */
-                       status_reg_value = inl(tw_dev->registers.status_reg_addr);
-                       if (TW_STATUS_ERRORS(status_reg_value))
-                               tw_decode_bits(tw_dev, status_reg_value, 0);
-                       
-                       /* Poll status register for 60 secs for 'Controller Ready' flag */
-                       if (tw_poll_status(tw_dev, TW_STATUS_MICROCONTROLLER_READY, 60)) {
-                               printk(KERN_WARNING "3w-xxxx: tw_findcards(): Microcontroller not ready for card %d.\n", j);
-                               tw_free_device_extension(tw_dev);
-                               kfree(tw_dev);
-                               continue;
-                       }
-
-                       /* Disable interrupts on the card */
-                       tw_disable_interrupts(tw_dev);
-
-                       tries = 0;
-
-                       while (tries < TW_MAX_RESET_TRIES) {
-                               /* Do soft reset */
-                               tw_soft_reset(tw_dev);
-                         
-                               error = tw_aen_drain_queue(tw_dev);
-                               if (error) {
-                                       printk(KERN_WARNING "3w-xxxx: AEN drain failed for card %d.\n", j);
-                                       tries++;
-                                       continue;
-                               }
-
-                               /* Check for controller errors */
-                               if (tw_check_errors(tw_dev)) {
-                                       printk(KERN_WARNING "3w-xxxx: Controller errors found, retrying for card %d.\n", j);
-                                       tries++;
-                                       continue;
-                               }
-
-                               /* Now the controller is in a good state */
-                               break;
-                       }
-
-                       if (tries >= TW_MAX_RESET_TRIES) {
-                               printk(KERN_WARNING "3w-xxxx: Controller errors, card not responding, check all cabling for card %d.\n", j);
-                               tw_free_device_extension(tw_dev);
-                               kfree(tw_dev);
-                               continue;
-                       }
-
-                       /* Reserve the io address space */
-                       if (!request_region((tw_dev->tw_pci_dev->resource[0].start), TW_IO_ADDRESS_RANGE, TW_DEVICE_NAME)) {
-                               printk(KERN_WARNING "3w-xxxx: tw_findcards(): Couldn't get io range 0x%lx-0x%lx for card %d.\n", 
-                                      (tw_dev->tw_pci_dev->resource[0].start), 
-                                      (tw_dev->tw_pci_dev->resource[0].start) + 
-                                      TW_IO_ADDRESS_RANGE, j);
-                               tw_free_device_extension(tw_dev);
-                               kfree(tw_dev);
-                               continue;
-                       }
-
-                       error = tw_initialize_units(tw_dev);
-                       if (error) {
-                               printk(KERN_WARNING "3w-xxxx: No valid units for for card %d.\n", j);
-                       }
-
-                       error = tw_initconnection(tw_dev, TW_INIT_MESSAGE_CREDITS);
-                       if (error) {
-                               printk(KERN_WARNING "3w-xxxx: Connection initialization failed for card %d.\n", j);
-                               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 card status as online */
-                       tw_dev->online = 1;
-
-                       tw_dev->free_head = TW_Q_START;
-                       tw_dev->free_tail = TW_Q_START;
-                       tw_dev->free_wrap = TW_Q_LENGTH - 1;
-
-                       /* 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", j);
-                               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;
-#endif
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
-                       scsi_set_device(host, &tw_pci_dev->dev);
-#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,4)
-                       scsi_set_pci_device(host, tw_pci_dev);
-#endif
-
-                       status_reg_value = inl(tw_dev->registers.status_reg_addr);
-
-                       printk(KERN_NOTICE "scsi%d : Found a 3ware Storage Controller at 0x%x, IRQ: %d, P-chip: %d.%d\n", host->host_no,
-                               (u32)(tw_pci_dev->resource[0].start), tw_pci_dev->irq, 
-                               (status_reg_value & TW_STATUS_MAJOR_VERSION_MASK) >> 28, 
-                               (status_reg_value & TW_STATUS_MINOR_VERSION_MASK) >> 24);
-
-                       if (host->hostdata) {
-                               tw_dev2 = (TW_Device_Extension *)host->hostdata;
-                               memcpy(tw_dev2, tw_dev, sizeof(TW_Device_Extension));
-                               /* Need to init the sem/wqueue after the copy */
-                               init_MUTEX(&tw_dev2->ioctl_sem);
-                               init_waitqueue_head(&tw_dev2->ioctl_wqueue);
-
-                               tw_device_extension_list[tw_device_extension_count] = tw_dev2;
-                               numcards++;
-                               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", j);
-                               scsi_unregister(host);
-                               release_region((tw_dev->tw_pci_dev->resource[0].start), TW_IO_ADDRESS_RANGE);
-                               tw_free_device_extension(tw_dev);
-                               kfree(tw_dev);
-                               continue;
-                       }
-
-                       /* Tell the firmware we support shutdown notification*/
-                       error = tw_setfeature(tw_dev2, 2, 1, &c);
-                       if (error) {
-                               printk(KERN_WARNING "3w-xxxx: Unable to set features for card %d, old firmware or card.\n", j);
-                       }
-
-                       /* Now setup the interrupt handler */
-                       error = tw_setup_irq(tw_dev2);
-                       if (error) {
-                               printk(KERN_WARNING "3w-xxxx: tw_findcards(): Error requesting irq for card %d.\n", j);
-                               scsi_unregister(host);
-                               release_region((tw_dev->tw_pci_dev->resource[0].start), TW_IO_ADDRESS_RANGE);
-
-                               tw_free_device_extension(tw_dev);
-                               kfree(tw_dev);
-                               numcards--;
-                               continue;
-                       }
-
-                       /* Re-enable interrupts on the card */
-                       tw_enable_interrupts(tw_dev2);
+       /* Reset the board */
+       while (tries < TW_MAX_RESET_TRIES) {
+               TW_SOFT_RESET(tw_dev);
 
-                       /* Free the temporary device extension */
-                       if (tw_dev)
-                               kfree(tw_dev);
+               error = tw_aen_drain_queue(tw_dev);
+               if (error) {
+                       printk(KERN_WARNING "3w-xxxx: scsi%d: AEN drain failed, retrying.\n", tw_dev->host->host_no);
+                       tries++;
+                       continue;
                }
-       }
 
-       if (numcards == 0) {
-               printk(KERN_WARNING "3w-xxxx: No cards found.\n");
-       } else {
-               register_reboot_notifier(&tw_notifier);
-               if ((twe_major = register_chrdev (0, "twe", &tw_fops)) < 0) {
-                       printk(KERN_WARNING "3w-xxxx: Unable to register \"twe\" character device, error = %d.\n", twe_major);
+               /* Check for controller errors */
+               if (tw_check_errors(tw_dev)) {
+                       printk(KERN_WARNING "3w-xxxx: scsi%d: Controller errors found, retrying.\n", tw_dev->host->host_no);
+                       tries++;
+                       continue;
                }
-       }
-
-       return numcards;
-} /* End tw_findcards() */
-
-/* This function will free up device extension resources */
-void tw_free_device_extension(TW_Device_Extension *tw_dev)
-{
-       dprintk(KERN_NOTICE "3w-xxxx: tw_free_device_extension()\n");
-
-       /* Free command packet and generic buffer memory */
-       if (tw_dev->command_packet_virtual_address[0])
-               pci_free_consistent(tw_dev->tw_pci_dev, sizeof(TW_Command)*TW_Q_LENGTH, tw_dev->command_packet_virtual_address[0], tw_dev->command_packet_physical_address[0]);
-
-       if (tw_dev->alignment_virtual_address[0])
-               pci_free_consistent(tw_dev->tw_pci_dev, sizeof(TW_Sector)*TW_Q_LENGTH, tw_dev->alignment_virtual_address[0], tw_dev->alignment_physical_address[0]);
-} /* End tw_free_device_extension() */
-
-/* Clean shutdown routine */
-static int tw_halt(struct notifier_block *nb, ulong event, void *buf)
-{
-       int i;
 
-       for (i=0;i<tw_device_extension_count;i++) {
-               if (tw_device_extension_list[i]->online == 1) {
-                       printk(KERN_NOTICE "3w-xxxx: Shutting down card %d.\n", i);
-                       tw_shutdown_device(tw_device_extension_list[i]);
-                       tw_device_extension_list[i]->online = 0;
-               }
+               /* Now the controller is in a good state */
+               break;
        }
-       unregister_reboot_notifier(&tw_notifier);
-
-       return NOTIFY_OK;
-} /* End tw_halt() */
-
-/* This function will send an initconnection command to controller */
-int tw_initconnection(TW_Device_Extension *tw_dev, int message_credits) 
-{
-       unsigned long command_que_value;
-       u32 command_que_addr;
-       u32 response_que_addr;
-       TW_Command  *command_packet;
-       TW_Response_Queue response_queue;
-       int request_id = 0;
 
-       dprintk(KERN_NOTICE "3w-xxxx: tw_initconnection()\n");
-       command_que_addr = tw_dev->registers.command_que_addr;
-       response_que_addr = tw_dev->registers.response_que_addr;
-
-       /* Initialize InitConnection command packet */
-       if (tw_dev->command_packet_virtual_address[request_id] == NULL) {
-               printk(KERN_WARNING "3w-xxxx: tw_initconnection(): Bad command packet virtual address.\n");
+       if (tries >= TW_MAX_RESET_TRIES) {
+               printk(KERN_WARNING "3w-xxxx: scsi%d: Controller errors, card not responding, check all cabling.\n", tw_dev->host->host_no);
                return 1;
        }
 
-       command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id];
-       memset(command_packet, 0, sizeof(TW_Sector));
-       command_packet->byte0.opcode = TW_OP_INIT_CONNECTION;
-       command_packet->byte0.sgl_offset = 0x0;
-       command_packet->size = TW_INIT_COMMAND_PACKET_SIZE;
-       command_packet->request_id = request_id;
-       command_packet->byte3.unit = 0x0;
-       command_packet->byte3.host_id = 0x0;
-       command_packet->status = 0x0;
-       command_packet->flags = 0x0;
-       command_packet->byte6.message_credits = message_credits; 
-       command_packet->byte8.init_connection.response_queue_pointer = 0x0;
-       command_que_value = tw_dev->command_packet_physical_address[request_id];
-
-       if (command_que_value == 0) {
-               printk(KERN_WARNING "3w-xxxx: tw_initconnection(): Bad command packet physical address.\n");
+       error = tw_initconnection(tw_dev, TW_INIT_MESSAGE_CREDITS);
+       if (error) {
+               printk(KERN_WARNING "3w-xxxx: scsi%d: Connection initialization failed.\n", tw_dev->host->host_no);
                return 1;
        }
-  
-       /* Send command packet to the board */
-       outl(command_que_value, command_que_addr);
-    
-       /* Poll for completion */
-       if (tw_poll_status_gone(tw_dev, TW_STATUS_RESPONSE_QUEUE_EMPTY, 30) == 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_initconnection(): Unexpected request id.\n");
-                       return 1;
-               }
-               if (command_packet->status != 0) {
-                       /* bad response */
-                       tw_decode_sense(tw_dev, request_id, 0);
-                       return 1;
-               }
+
+       error = tw_setfeature(tw_dev, 2, 1, &c);
+       if (error) {
+               printk(KERN_WARNING "3w-xxxx: Unable to set features for card, probable old firmware or card.\n");
        }
+
        return 0;
-} /* End tw_initconnection() */
+} /* End tw_reset_sequence() */
 
 /* This function will initialize the fields of a device extension */
-int tw_initialize_device_extension(TW_Device_Extension *tw_dev)
+static int tw_initialize_device_extension(TW_Device_Extension *tw_dev)
 {
        int i, error=0;
 
@@ -1369,1263 +1287,737 @@ int tw_initialize_device_extension(TW_Device_Extension *tw_dev)
 
        tw_dev->pending_head = TW_Q_START;
        tw_dev->pending_tail = TW_Q_START;
-       spin_lock_init(&tw_dev->tw_lock);
        tw_dev->chrdev_request_id = TW_IOCTL_CHRDEV_FREE;
 
+       init_MUTEX(&tw_dev->ioctl_sem);
+       init_waitqueue_head(&tw_dev->ioctl_wqueue);
+
        return 0;
 } /* End tw_initialize_device_extension() */
 
-/* This function will get unit info from the controller */
-int tw_initialize_units(TW_Device_Extension *tw_dev) 
+static int tw_map_scsi_sg_data(struct pci_dev *pdev, struct scsi_cmnd *cmd)
+{
+       int use_sg;
+
+       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_BIDIRECTIONAL);
+       
+       if (use_sg == 0) {
+               printk(KERN_WARNING "3w-xxxx: tw_map_scsi_sg_data(): pci_map_sg() failed.\n");
+               return 0;
+       }
+
+       cmd->SCp.phase = TW_PHASE_SGLIST;
+       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, struct scsi_cmnd *cmd)
+{
+       dma_addr_t mapping;
+
+       dprintk(KERN_WARNING "3w-xxxx: tw_map_scsi_single_data()\n");
+
+       if (cmd->request_bufflen == 0)
+               return 0;
+
+       mapping = pci_map_page(pdev, virt_to_page(cmd->request_buffer), offset_in_page(cmd->request_buffer), cmd->request_bufflen, DMA_BIDIRECTIONAL);
+
+       if (mapping == 0) {
+               printk(KERN_WARNING "3w-xxxx: tw_map_scsi_single_data(): pci_map_page() failed.\n");
+               return 0;
+       }
+
+       cmd->SCp.phase = TW_PHASE_SINGLE;
+       cmd->SCp.have_data_in = mapping;
+
+       return mapping;
+} /* End tw_map_scsi_single_data() */
+
+static void tw_unmap_scsi_data(struct pci_dev *pdev, struct scsi_cmnd *cmd)
+{
+       dprintk(KERN_WARNING "3w-xxxx: tw_unmap_scsi_data()\n");
+
+       switch(cmd->SCp.phase) {
+               case TW_PHASE_SINGLE:
+                       pci_unmap_page(pdev, cmd->SCp.have_data_in, cmd->request_bufflen, DMA_BIDIRECTIONAL);
+                       break;
+               case TW_PHASE_SGLIST:
+                       pci_unmap_sg(pdev, cmd->request_buffer, cmd->use_sg, DMA_BIDIRECTIONAL);
+                       break;
+       }
+} /* End tw_unmap_scsi_data() */
+
+/* This function will reset a device extension */
+static int tw_reset_device_extension(TW_Device_Extension *tw_dev, int ioctl_reset) 
+{
+       int i = 0;
+       struct scsi_cmnd *srb;
+       unsigned long flags = 0;
+
+       dprintk(KERN_NOTICE "3w-xxxx: tw_reset_device_extension()\n");
+
+       set_bit(TW_IN_RESET, &tw_dev->flags);
+       TW_DISABLE_INTERRUPTS(tw_dev);
+       TW_MASK_COMMAND_INTERRUPT(tw_dev);
+       spin_lock_irqsave(tw_dev->host->host_lock, flags);
+
+       /* Abort all requests that are in progress */
+       for (i=0;i<TW_Q_LENGTH;i++) {
+               if ((tw_dev->state[i] != TW_S_FINISHED) && 
+                   (tw_dev->state[i] != TW_S_INITIAL) &&
+                   (tw_dev->state[i] != TW_S_COMPLETED)) {
+                       srb = tw_dev->srb[i];
+                       if (srb != NULL) {
+                               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]);
+                       }
+               }
+       }
+
+       /* Reset queues and counts */
+       for (i=0;i<TW_Q_LENGTH;i++) {
+               tw_dev->free_queue[i] = i;
+               tw_dev->state[i] = TW_S_INITIAL;
+       }
+       tw_dev->free_head = TW_Q_START;
+       tw_dev->free_tail = TW_Q_START;
+       tw_dev->posted_request_count = 0;
+       tw_dev->pending_request_count = 0;
+       tw_dev->pending_head = TW_Q_START;
+       tw_dev->pending_tail = TW_Q_START;
+       tw_dev->reset_print = 0;
+
+       spin_unlock_irqrestore(tw_dev->host->host_lock, flags);
+
+       if (tw_reset_sequence(tw_dev)) {
+               printk(KERN_WARNING "3w-xxxx: scsi%d: Reset sequence failed.\n", tw_dev->host->host_no);
+               return 1;
+       }
+       TW_ENABLE_AND_CLEAR_INTERRUPTS(tw_dev);
+
+       /* Wake up any ioctl that was pending before the reset */
+       if ((tw_dev->chrdev_request_id == TW_IOCTL_CHRDEV_FREE) || (ioctl_reset)) {
+               clear_bit(TW_IN_RESET, &tw_dev->flags);
+       } else {
+               tw_dev->chrdev_request_id = TW_IOCTL_CHRDEV_FREE;
+               wake_up(&tw_dev->ioctl_wqueue);
+       }
+
+       return 0;
+} /* End tw_reset_device_extension() */
+
+/* This funciton returns unit geometry in cylinders/heads/sectors */
+static int tw_scsi_biosparam(struct scsi_device *sdev, struct block_device *bdev,
+               sector_t capacity, int geom[]) 
+{
+       int heads, sectors, cylinders;
+       TW_Device_Extension *tw_dev;
+       
+       dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_biosparam()\n");
+       tw_dev = (TW_Device_Extension *)sdev->host->hostdata;
+
+       heads = 64;
+       sectors = 32;
+       cylinders = sector_div(capacity, heads * sectors);
+
+       if (capacity >= 0x200000) {
+               heads = 255;
+               sectors = 63;
+               cylinders = sector_div(capacity, heads * sectors);
+       }
+
+       dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_biosparam(): heads = %d, sectors = %d, cylinders = %d\n", heads, sectors, cylinders);
+       geom[0] = heads;                         
+       geom[1] = sectors;
+       geom[2] = cylinders;
+
+       return 0;
+} /* End tw_scsi_biosparam() */
+
+/* This is the new scsi eh reset function */
+static int tw_scsi_eh_reset(struct scsi_cmnd *SCpnt) 
+{
+       TW_Device_Extension *tw_dev=NULL;
+       int retval = FAILED;
+
+       tw_dev = (TW_Device_Extension *)SCpnt->device->host->hostdata;
+
+       spin_unlock_irq(tw_dev->host->host_lock);
+
+       tw_dev->num_resets++;
+
+       printk(KERN_WARNING "3w-xxxx: scsi%d: WARNING: Unit #%d: Command (0x%x) timed out, resetting card.\n", tw_dev->host->host_no, SCpnt->device->id, SCpnt->cmnd[0]);
+
+       /* Now reset the card and some of the device extension data */
+       if (tw_reset_device_extension(tw_dev, 0)) {
+               printk(KERN_WARNING "3w-xxxx: scsi%d: Reset failed.\n", tw_dev->host->host_no);
+               goto out;
+       }
+
+       retval = SUCCESS;
+out:
+       spin_lock_irq(tw_dev->host->host_lock);
+       return retval;
+} /* End tw_scsi_eh_reset() */
+
+/* This function handles scsi inquiry commands */
+static int tw_scsiop_inquiry(TW_Device_Extension *tw_dev, int request_id)
 {
-       int found = 0;
-       unsigned char request_id = 0;
-       TW_Command *command_packet;
        TW_Param *param;
-       int i, imax, num_units = 0;
+       TW_Command *command_packet;
        unsigned long command_que_value;
-       u32 command_que_addr;
-       u32 response_que_addr;
-       TW_Response_Queue response_queue;
        unsigned long param_value;
-       unsigned char *is_unit_present;
 
-       dprintk(KERN_NOTICE "3w-xxxx: tw_initialize_units()\n");
+       dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_inquiry()\n");
 
-       command_que_addr = tw_dev->registers.command_que_addr;
-       response_que_addr = tw_dev->registers.response_que_addr;
-  
-       /* Setup the command packet */
+       /* Initialize command packet */
        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");
+               printk(KERN_WARNING "3w-xxxx: tw_scsiop_inquiry(): 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;
+       command_packet->opcode__sgloffset = TW_OPSGL_IN(2, TW_OP_GET_PARAM);
+       command_packet->size = 4;
+       command_packet->request_id = request_id;
+       command_packet->status = 0;
+       command_packet->flags = 0;
+       command_packet->byte6.parameter_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");
+               printk(KERN_WARNING "3w-xxxx: tw_scsiop_inquiry(): 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 = 3;       /* unit summary table */
-       param->parameter_id = 3;   /* unitstatus parameter */
+       param->table_id = 3;     /* unit summary table */
+       param->parameter_id = 3; /* unitsstatus parameter */
        param->parameter_size_bytes = TW_MAX_UNITS;
        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");
+               printk(KERN_WARNING "3w-xxxx: tw_scsiop_inquiry(): 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");
+               printk(KERN_WARNING "3w-xxxx: tw_scsiop_inquiry(): Bad command packet physical address.\n");
                return 1;
        }
-       outl(command_que_value, command_que_addr);
 
-       /* Poll for completion */
-       if (tw_poll_status_gone(tw_dev, TW_STATUS_RESPONSE_QUEUE_EMPTY, 30) == 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 */
-                       tw_decode_sense(tw_dev, request_id, 0);
-                       return 1;
-               }
-               found = 1;
-       }
-       if (found == 0) {
-               /* response never received */
-               printk(KERN_WARNING "3w-xxxx: tw_initialize_units(): No response.\n");
+       /* Now try to post the command packet */
+       tw_post_command_packet(tw_dev, request_id);
+
+       return 0;
+} /* End tw_scsiop_inquiry() */
+
+/* This function is called by the isr to complete an inquiry command */
+static int tw_scsiop_inquiry_complete(TW_Device_Extension *tw_dev, int request_id)
+{
+       unsigned char *is_unit_present;
+       unsigned char *request_buffer;
+       TW_Param *param;
+
+       dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_inquiry_complete()\n");
+
+       /* Fill request buffer */
+       if (tw_dev->srb[request_id]->request_buffer == NULL) {
+               printk(KERN_WARNING "3w-xxxx: tw_scsiop_inquiry_complete(): Request buffer NULL.\n");
                return 1;
        }
+       request_buffer = tw_dev->srb[request_id]->request_buffer;
+       memset(request_buffer, 0, tw_dev->srb[request_id]->request_bufflen);
+       request_buffer[0] = TYPE_DISK; /* Peripheral device type */
+       request_buffer[1] = 0;         /* Device type modifier */
+       request_buffer[2] = 0;         /* No ansi/iso compliance */
+       request_buffer[4] = 31;        /* Additional length */
+       memcpy(&request_buffer[8], "3ware   ", 8);       /* Vendor ID */
+       sprintf(&request_buffer[16], "Logical Disk %-2d ", tw_dev->srb[request_id]->device->id);
+       memcpy(&request_buffer[32], TW_DRIVER_VERSION, 3);
 
        param = (TW_Param *)tw_dev->alignment_virtual_address[request_id];
-       is_unit_present = (unsigned char *)&(param->data[0]);
-  
-       /* Show all units present */
-       imax = TW_MAX_UNITS;
-       for(i=0; i<imax; i++) {
-               if (is_unit_present[i] == 0) {
-                       tw_dev->is_unit_present[i] = FALSE;
-               } else {
-                 if (is_unit_present[i] & TW_UNIT_ONLINE) {
-                       dprintk(KERN_NOTICE "3w-xxxx: tw_initialize_units(): Unit %d found.\n", i);
-                       tw_dev->is_unit_present[i] = TRUE;
-                       num_units++;
-                 }
-               }
+       if (param == NULL) {
+               printk(KERN_WARNING "3w-xxxx: tw_scsiop_inquiry_complete(): Bad alignment virtual address.\n");
+               return 1;
        }
-       tw_dev->num_units = num_units;
+       is_unit_present = &(param->data[0]);
 
-       if (num_units == 0) {
-               dprintk(KERN_NOTICE "3w-xxxx: tw_initialize_units(): No units found.\n");
-               return 1;
+       if (is_unit_present[tw_dev->srb[request_id]->device->id] & TW_UNIT_ONLINE) {
+               tw_dev->is_unit_present[tw_dev->srb[request_id]->device->id] = 1;
+       } else {
+               tw_dev->is_unit_present[tw_dev->srb[request_id]->device->id] = 0;
+               tw_dev->srb[request_id]->result = (DID_BAD_TARGET << 16);
+               return TW_ISR_DONT_RESULT;
        }
 
        return 0;
-} /* End tw_initialize_units() */
+} /* End tw_scsiop_inquiry_complete() */
 
-/* This function is the interrupt service routine */
-static irqreturn_t tw_interrupt(int irq, void *dev_instance,
-                                       struct pt_regs *regs) 
+/* This function handles scsi mode_sense commands */
+static int tw_scsiop_mode_sense(TW_Device_Extension *tw_dev, int request_id)
 {
-       int request_id;
-       u32 status_reg_addr, status_reg_value;
-       u32 response_que_addr;
-       TW_Device_Extension *tw_dev = (TW_Device_Extension *)dev_instance;
-       TW_Response_Queue response_que;
-       int error = 0, retval = 0;
-       unsigned long flags = 0;
+       TW_Param *param;
        TW_Command *command_packet;
-       int handled = 0;
+       unsigned long command_que_value;
+       unsigned long param_value;
 
-       dprintk(KERN_WARNING "3w-xxxx: tw_interrupt()\n");
+       dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_mode_sense()\n");
 
-       /* See if we are already running on another processor */
-       if (test_and_set_bit(TW_IN_INTR, &tw_dev->flags))
-               return IRQ_NONE;
+       /* Only page control = 0, page code = 0x8 (cache page) supported */
+       if (tw_dev->srb[request_id]->cmnd[2] != 0x8) {
+               tw_dev->state[request_id] = TW_S_COMPLETED;
+               tw_state_request_finish(tw_dev, request_id);
+               tw_dev->srb[request_id]->result = (DID_OK << 16);
+               tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]);
+               return 0;
+       }
 
-       /* Get the host lock for io completions */
-       spin_lock_irqsave(tw_dev->host->host_lock, flags);
+       /* Now read firmware cache setting for this unit */
+       command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id];
+       if (command_packet == NULL) {
+               printk(KERN_WARNING "3w-xxxx: tw_scsiop_mode_sense(): Bad command packet virtual address.\n");
+               return 1;
+       }
 
-       /* See if the interrupt matches this instance */
-       if (tw_dev->tw_pci_dev->irq == irq) {
+       /* Setup the command packet */
+       memset(command_packet, 0, sizeof(TW_Sector));
+       command_packet->opcode__sgloffset = TW_OPSGL_IN(2, TW_OP_GET_PARAM);
+       command_packet->size = 4;
+       command_packet->request_id = request_id;
+       command_packet->status = 0;
+       command_packet->flags = 0;
+       command_packet->byte6.parameter_count = 1;
 
-               handled = 1;
-               /* Make sure io isn't queueing */
-               spin_lock(&tw_dev->tw_lock);
+       /* Setup the param */
+       if (tw_dev->alignment_virtual_address[request_id] == NULL) {
+               printk(KERN_WARNING "3w-xxxx: tw_scsiop_mode_sense(): Bad alignment virtual address.\n");
+               return 1;
+       }
 
-               /* 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);
-
-               /* Check if this is our interrupt, otherwise bail */
-               if (!(status_reg_value & TW_STATUS_VALID_INTERRUPT))
-                       goto tw_interrupt_bail;
-
-               /* Check controller for errors */
-               if (tw_check_bits(status_reg_value)) {
-                       dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Unexpected bits.\n");
-                       if (tw_decode_bits(tw_dev, status_reg_value, 1)) {
-                               tw_clear_all_interrupts(tw_dev);
-                               goto tw_interrupt_bail;
-                       }
-               }
-
-               /* Handle host interrupt */
-               if (status_reg_value & TW_STATUS_HOST_INTERRUPT) {
-                       dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): Received host interrupt.\n");
-                       tw_clear_host_interrupt(tw_dev);
-               }
-
-               /* Handle attention interrupt */
-               if (status_reg_value & TW_STATUS_ATTENTION_INTERRUPT) {
-                       dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): Received attention interrupt.\n");
-                       tw_clear_attention_interrupt(tw_dev);
-                       tw_state_request_start(tw_dev, &request_id);
-                       error = tw_aen_read_queue(tw_dev, request_id);
-                       if (error) {
-                               printk(KERN_WARNING "3w-xxxx: scsi%d: Error reading aen queue.\n", tw_dev->host->host_no);
-                               tw_dev->state[request_id] = TW_S_COMPLETED;
-                               tw_state_request_finish(tw_dev, request_id);
-                       }
-               }
-
-               /* Handle command interrupt */
-               if (status_reg_value & TW_STATUS_COMMAND_INTERRUPT) {
-                       /* Drain as many pending commands as we can */
-                       while (tw_dev->pending_request_count > 0) {
-                               request_id = tw_dev->pending_queue[tw_dev->pending_head];
-                               if (tw_dev->state[request_id] != TW_S_PENDING) {
-                                       printk(KERN_WARNING "3w-xxxx: scsi%d: Found request id that wasn't pending.\n", tw_dev->host->host_no);
-                                       break;
-                               }
-                               if (tw_post_command_packet(tw_dev, request_id)==0) {
-                                       if (tw_dev->pending_head == TW_Q_LENGTH-1) {
-                                               tw_dev->pending_head = TW_Q_START;
-                                       } else {
-                                               tw_dev->pending_head = tw_dev->pending_head + 1;
-                                       }
-                                       tw_dev->pending_request_count--;
-                               } else {
-                                       /* If we get here, we will continue re-posting on the next command interrupt */
-                                       break;
-                               }
-                       }
-                       /* If there are no more pending requests, we mask command interrupt */
-                       if (tw_dev->pending_request_count == 0) 
-                               tw_mask_command_interrupt(tw_dev);
-               }
-
-               /* Handle response interrupt */
-               if (status_reg_value & TW_STATUS_RESPONSE_INTERRUPT) {
-                       /* Drain the response queue from the board */
-                       while ((status_reg_value & TW_STATUS_RESPONSE_QUEUE_EMPTY) == 0) {
-                               /* Read response queue register */
-                               response_que.value = inl(response_que_addr);
-                               request_id = response_que.u.response_id;
-                               command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id];
-                               error = 0;
-
-                               /* Check for bad response */
-                               if (command_packet->status != 0) {
-                                       /* If internal command, don't error, don't fill sense */
-                                       if (tw_dev->srb[request_id] == 0) {
-                                               tw_decode_sense(tw_dev, request_id, 0);
-                                       } else {
-                                               error = tw_decode_sense(tw_dev, request_id, 1);
-                                       }
-                               }
-
-                               /* Check for correct state */
-                               if (tw_dev->state[request_id] != TW_S_POSTED) {
-                                       /* Handle timed out ioctl's */
-                                       if (tw_dev->srb[request_id] != 0) {
-                                               if (tw_dev->srb[request_id]->cmnd[0] != TW_IOCTL) {
-                                                       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;
-                                               }
-                                       }
-                               }
+       param = (TW_Param *)tw_dev->alignment_virtual_address[request_id];
+       memset(param, 0, sizeof(TW_Sector));
+       param->table_id = TW_UNIT_INFORMATION_TABLE_BASE + tw_dev->srb[request_id]->device->id;
+       param->parameter_id = 7; /* unit flags */
+       param->parameter_size_bytes = 1;
+       param_value = tw_dev->alignment_physical_address[request_id];
+       if (param_value == 0) {
+               printk(KERN_WARNING "3w-xxxx: tw_scsiop_mode_sense(): Bad alignment physical address.\n");
+               return 1;
+       }
 
-                               dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): Response queue request id: %d.\n", request_id);
+       command_packet->byte8.param.sgl[0].address = param_value;
+       command_packet->byte8.param.sgl[0].length = sizeof(TW_Sector);
+       command_que_value = tw_dev->command_packet_physical_address[request_id];
+       if (command_que_value == 0) {
+               printk(KERN_WARNING "3w-xxxx: tw_scsiop_mode_sense(): Bad command packet physical address.\n");
+               return 1;
+       }
 
-                               /* Check for internal command completion */
-                               if (tw_dev->srb[request_id] == 0) {
-                                       dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Found internally posted command.\n");
-                                       /* Check for chrdev ioctl completion */
-                                       if (request_id != tw_dev->chrdev_request_id) {
-                                               retval = tw_aen_complete(tw_dev, request_id);
-                                               if (retval) {
-                                                       printk(KERN_WARNING "3w-xxxx: scsi%d: Error completing aen.\n", tw_dev->host->host_no);
-                                               }
-                                       } else {
-                                               tw_dev->chrdev_request_id = TW_IOCTL_CHRDEV_FREE;
-                                               wake_up(&tw_dev->ioctl_wqueue);
-                                       }
-                               } else {
-                               switch (tw_dev->srb[request_id]->cmnd[0]) {
-                                       case READ_10:
-                                       case READ_6:
-                                               dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): caught READ_10/READ_6\n");
-                                               break;
-                                       case WRITE_10:
-                                       case WRITE_6:
-                                               dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): caught WRITE_10/WRITE_6\n");
-                                               break;
-                                       case TEST_UNIT_READY:
-                                               dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): caught TEST_UNIT_READY\n");
-                                               error = tw_scsiop_test_unit_ready_complete(tw_dev, request_id);
-                                               break;
-                                       case INQUIRY:
-                                               dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): caught INQUIRY\n");
-                                               error = tw_scsiop_inquiry_complete(tw_dev, request_id);
-                                               break;
-                                       case READ_CAPACITY:
-                                               dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): caught READ_CAPACITY\n");
-                                               error = tw_scsiop_read_capacity_complete(tw_dev, request_id);
-                                               break;
-                                       case MODE_SENSE:
-                                               dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): caught MODE_SENSE\n");
-                                               error = tw_scsiop_mode_sense_complete(tw_dev, request_id);
-                                               break;
-                                       case SYNCHRONIZE_CACHE:
-                                               dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): caught SYNCHRONIZE_CACHE\n");
-                                               break;
-                                       case TW_IOCTL:
-                                               dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): caught TW_IOCTL\n");
-                                               error = tw_ioctl_complete(tw_dev, request_id);
-                                               break;
-                                       default:
-                                               printk(KERN_WARNING "3w-xxxx: case slip in tw_interrupt()\n");
-                                               error = 1;
-                                       }
+       /* Now try to post the command packet */
+       tw_post_command_packet(tw_dev, request_id);
+       
+       return 0;
+} /* End tw_scsiop_mode_sense() */
 
-                                       /* If no error command was a success */
-                                       if (error == 0) {
-                                               tw_dev->srb[request_id]->result = (DID_OK << 16);
-                                       }
+/* This function is called by the isr to complete a mode sense command */
+static int tw_scsiop_mode_sense_complete(TW_Device_Extension *tw_dev, int request_id)
+{
+       TW_Param *param;
+       unsigned char *flags;
+       unsigned char *request_buffer;
 
-                                       /* If error, command failed */
-                                       if (error == 1) {
-                                               /* Ask for a host reset */
-                                               tw_dev->srb[request_id]->result = (DID_OK << 16) | (CHECK_CONDITION << 1);
-                                       }
+       dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_mode_sense_complete()\n");
 
-                                       /* Now complete the io */
-                                       if ((error != TW_ISR_DONT_COMPLETE)) {
-                                               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]);
+       param = (TW_Param *)tw_dev->alignment_virtual_address[request_id];
+       if (param == NULL) {
+               printk(KERN_WARNING "3w-xxxx: tw_scsiop_mode_sense_complete(): Bad alignment virtual address.\n");
+               return 1;
+       }
+       flags = (char *)&(param->data[0]);
+       request_buffer = tw_dev->srb[request_id]->buffer;
+       memset(request_buffer, 0, tw_dev->srb[request_id]->request_bufflen);
 
-                                               tw_unmap_scsi_data(tw_dev->tw_pci_dev, tw_dev->srb[request_id]);
-                                       }
-                               }
-                               
-                               /* Check for valid status after each drain */
-                               status_reg_value = inl(status_reg_addr);
-                               if (tw_check_bits(status_reg_value)) {
-                                       dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Unexpected bits.\n");
-                                       if (tw_decode_bits(tw_dev, status_reg_value, 1)) {
-                                               tw_clear_all_interrupts(tw_dev);
-                                               goto tw_interrupt_bail;
-                                       }
-                               }
-                       }
-               }
-tw_interrupt_bail:
-               spin_unlock(&tw_dev->tw_lock);
-       } else
-               dprintk(KERN_WARNING "3w-xxxx: tw_interrupt() called for wrong instance.\n");
+       request_buffer[0] = 0xf;        /* mode data length */
+       request_buffer[1] = 0;          /* default medium type */
+       request_buffer[2] = 0x10;       /* dpo/fua support on */
+       request_buffer[3] = 0;          /* no block descriptors */
+       request_buffer[4] = 0x8;        /* caching page */
+       request_buffer[5] = 0xa;        /* page length */
+       if (*flags & 0x1)
+               request_buffer[6] = 0x4;        /* WCE on */
+       else
+               request_buffer[6] = 0x0;        /* WCE off */
 
-       spin_unlock_irqrestore(tw_dev->host->host_lock, flags);
-       clear_bit(TW_IN_INTR, &tw_dev->flags);
-       return IRQ_RETVAL(handled);
-} /* End tw_interrupt() */
+       return 0;
+} /* End tw_scsiop_mode_sense_complete() */
 
-/* This function handles ioctls from userspace to the driver */
-int tw_ioctl(TW_Device_Extension *tw_dev, int request_id)
+/* This function handles scsi read_capacity commands */
+static int tw_scsiop_read_capacity(TW_Device_Extension *tw_dev, int request_id) 
 {
-       unsigned char opcode;
-       int bufflen, error = 0;
        TW_Param *param;
-       TW_Command *command_packet, *command_save;
+       TW_Command *command_packet;
+       unsigned long command_que_value;
        unsigned long param_value;
-       TW_Ioctl *ioctl = NULL;
-       TW_Passthru *passthru = NULL;
-       int tw_aen_code, i, use_sg;
-       unsigned long *data_ptr;
-       int total_bytes = 0, posted = 0;
-       dma_addr_t dma_handle;
-       struct timeval before, timeout;
 
-       ioctl = (TW_Ioctl *)tw_dev->srb[request_id]->request_buffer;
-       if (ioctl == NULL) {
-               printk(KERN_WARNING "3w-xxxx: tw_ioctl(): Request buffer NULL.\n");
-               tw_dev->state[request_id] = TW_S_COMPLETED;
-               tw_state_request_finish(tw_dev, request_id);
-               tw_dev->srb[request_id]->result = (DID_OK << 16);
-               tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]);
-               return 0;
-       }
-       bufflen = tw_dev->srb[request_id]->request_bufflen;
+       dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_read_capacity()\n");
 
        /* Initialize command packet */
        command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id];
+
        if (command_packet == NULL) {
-               printk(KERN_WARNING "3w-xxxx: tw_ioctl(): Bad command packet virtual address.\n");
-               tw_dev->state[request_id] = TW_S_COMPLETED;
-               tw_state_request_finish(tw_dev, request_id);
-               tw_dev->srb[request_id]->result = (DID_OK << 16);
-               tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]);
-               return 0;
+               dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_read_capacity(): Bad command packet virtual address.\n");
+               return 1;
        }
        memset(command_packet, 0, sizeof(TW_Sector));
+       command_packet->opcode__sgloffset = TW_OPSGL_IN(2, TW_OP_GET_PARAM);
+       command_packet->size = 4;
+       command_packet->request_id = request_id;
+       command_packet->unit__hostid = TW_UNITHOST_IN(0, tw_dev->srb[request_id]->device->id);
+       command_packet->status = 0;
+       command_packet->flags = 0;
+       command_packet->byte6.block_count = 1;
 
-       /* Initialize param */
+       /* Now setup the param */
        if (tw_dev->alignment_virtual_address[request_id] == NULL) {
-               printk(KERN_WARNING "3w-xxxx: tw_ioctl(): Bad alignment virtual address.\n");
-               tw_dev->state[request_id] = TW_S_COMPLETED;
-               tw_state_request_finish(tw_dev, request_id);
-               tw_dev->srb[request_id]->result = (DID_OK << 16);
-               tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]);
-               return 0;
+               dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_read_capacity(): Bad alignment virtual address.\n");
+               return 1;
        }
        param = (TW_Param *)tw_dev->alignment_virtual_address[request_id];
        memset(param, 0, sizeof(TW_Sector));
-
-       dprintk(KERN_NOTICE "opcode = %d table_id = %d parameter_id = %d parameter_size_bytes = %d\n", ioctl->opcode, ioctl->table_id, ioctl->parameter_id, ioctl->parameter_size_bytes);
-       opcode = ioctl->opcode;
-
-       switch (opcode) {
-               case TW_OP_NOP:
-                       dprintk(KERN_NOTICE "3w-xxxx: tw_ioctl(): caught TW_OP_NOP.\n");
-                       command_packet->byte0.opcode = TW_OP_NOP;
-                       break;
-               case TW_OP_GET_PARAM:
-                       dprintk(KERN_NOTICE "3w-xxxx: tw_ioctl(): caught TW_OP_GET_PARAM.\n");
-                       command_packet->byte0.opcode = TW_OP_GET_PARAM;
-                       command_packet->byte3.unit = ioctl->unit_index;
-                       param->table_id = ioctl->table_id;
-                       param->parameter_id = ioctl->parameter_id;
-                       param->parameter_size_bytes = ioctl->parameter_size_bytes;
-                       tw_dev->ioctl_size[request_id] = ioctl->parameter_size_bytes;
-                       dprintk(KERN_NOTICE "table_id = %d parameter_id = %d parameter_size_bytes %d\n", param->table_id, param->parameter_id, param->parameter_size_bytes);
-                       break;
-               case TW_OP_SET_PARAM:
-                       dprintk(KERN_NOTICE "3w-xxxx: tw_ioctl(): caught TW_OP_SET_PARAM: table_id = %d, parameter_id = %d, parameter_size_bytes = %d.\n",
-                       ioctl->table_id, ioctl->parameter_id, ioctl->parameter_size_bytes);
-                       if (ioctl->data != NULL) {
-                               command_packet->byte0.opcode = TW_OP_SET_PARAM;
-                               param->table_id = ioctl->table_id;
-                               param->parameter_id = ioctl->parameter_id;
-                               param->parameter_size_bytes = ioctl->parameter_size_bytes;
-                               memcpy(param->data, ioctl->data, ioctl->parameter_size_bytes);
-                               break;
-                       } else {
-                               printk(KERN_WARNING "3w-xxxx: tw_ioctl(): ioctl->data NULL.\n");
-                               return 1;
-                       }
-               case TW_OP_AEN_LISTEN:
-                       dprintk(KERN_NOTICE "3w-xxxx: tw_ioctl(): caught TW_OP_AEN_LISTEN.\n");
-                       if (tw_dev->aen_head == tw_dev->aen_tail) {
-                               /* aen queue empty */
-                               dprintk(KERN_NOTICE "3w-xxxx: tw_ioctl(): Aen queue empty.\n");
-                               tw_aen_code = TW_AEN_QUEUE_EMPTY;
-                               memcpy(tw_dev->srb[request_id]->request_buffer, &tw_aen_code, ioctl->parameter_size_bytes);
-                       } else {
-                               /* Copy aen queue entry to request buffer */
-                               dprintk(KERN_NOTICE "3w-xxxx: tw_ioctl(): Returning aen 0x%x\n", tw_dev->aen_queue[tw_dev->aen_head]);
-                               tw_aen_code = tw_dev->aen_queue[tw_dev->aen_head];
-                               memcpy(tw_dev->srb[request_id]->request_buffer, &tw_aen_code, ioctl->parameter_size_bytes);
-                               if (tw_dev->aen_head == TW_Q_LENGTH - 1) {
-                                       tw_dev->aen_head = TW_Q_START;
-                               } else {
-                                       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);
-                       tw_dev->srb[request_id]->result = (DID_OK << 16);
-                       tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]);
-                       return 0;
-               case TW_ATA_PASSTHRU:
-                       if (ioctl->data != NULL) {
-                               memcpy(command_packet, ioctl->data, sizeof(TW_Command));
-                               command_packet->request_id = request_id;
-                       } else {
-                               printk(KERN_WARNING "3w-xxxx: tw_ioctl(): ioctl->data NULL.\n");
-                               return 1;
-                       }
-
-                       passthru = (TW_Passthru *)tw_dev->command_packet_virtual_address[request_id];
-                       /* Don't load sg_list for non-data ATA cmds */
-                       if ((passthru->param != 0) && (passthru->param != 0x8)) {
-                               passthru->sg_list[0].length = passthru->sector_count*512;
-                               if (passthru->sg_list[0].length > TW_MAX_PASSTHRU_BYTES) {
-                                       printk(KERN_WARNING "3w-xxxx: tw_ioctl(): Passthru size (%d) too big.\n", passthru->sg_list[0].length);
-                                       return 1;
-                               }
-                               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:
-                       dprintk(KERN_WARNING "3w-xxxx: tw_ioctl(): caught TW_CMD_PACKET.\n");
-                       if (ioctl->data != NULL) {
-                               memcpy(command_packet, ioctl->data, sizeof(TW_Command));
-                               command_packet->request_id = request_id;
-                               tw_post_command_packet(tw_dev, request_id);
-                               return 0;
-                       } else {
-                               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(): pci_alloc_consistent() 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 (command_packet->byte8.param.sgl[i].address != 0) {
-                                                       error = copy_from_user(data_ptr, (void *)(unsigned long)command_packet->byte8.param.sgl[i].address, command_packet->byte8.param.sgl[i].length);
-                                                       if (error) {
-                                                               dprintk(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 (command_packet->byte8.io.sgl[i].address != 0) {
-                                                               error = copy_from_user(data_ptr, (void *)(unsigned long)command_packet->byte8.io.sgl[i].address, command_packet->byte8.io.sgl[i].length);
-                                                               if (error) {
-                                                                       dprintk(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(&tw_dev->tw_lock);
-                               spin_unlock_irq(tw_dev->host->host_lock);
-
-                               set_bit(TW_IN_IOCTL, &tw_dev->flags);
-
-                               /* Finally post the command packet */
-                               tw_post_command_packet(tw_dev, request_id);
-                               posted = 1;
-                               do_gettimeofday(&before);
-
-                       tw_ioctl_retry:
-                               mdelay(TW_IOCTL_WAIT_TIME);
-                               if (test_bit(TW_IN_IOCTL, &tw_dev->flags)) {
-                                       do_gettimeofday(&timeout);
-                                       if (before.tv_sec + TW_IOCTL_TIMEOUT < timeout.tv_sec) {
-                                               spin_lock_irq(tw_dev->host->host_lock);
-                                               spin_lock(&tw_dev->tw_lock);
-                                               goto tw_ioctl_bail;
-                                       } else {
-                                               goto tw_ioctl_retry;
-                                       }
-                               }
-
-                               spin_lock_irq(tw_dev->host->host_lock);
-                               spin_lock(&tw_dev->tw_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 = tw_dev->ioctl_data[request_id];
-                                       for (i=0;i<use_sg;i++) {
-                                               if (command_save->byte8.param.sgl[i].address != 0) {
-                                                       error = copy_to_user((void *)(unsigned long)command_save->byte8.param.sgl[i].address, data_ptr, command_save->byte8.param.sgl[i].length);
-                                                       if (error) {
-                                                               dprintk(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 = tw_dev->ioctl_data[request_id];
-                                               for(i=0;i<use_sg;i++) {
-                                                       if (command_save->byte8.io.sgl[i].address != 0) {
-                                                               error = copy_to_user((void *)(unsigned long)command_save->byte8.io.sgl[i].address, data_ptr, command_save->byte8.io.sgl[i].length);
-                                                               if (error) {
-                                                                       dprintk(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);
-                               if (posted)
-                                       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:
-                       dprintk(KERN_WARNING "3w-xxxx: Unknown ioctl 0x%x.\n", opcode);
-                       tw_dev->state[request_id] = TW_S_COMPLETED;
-                       tw_state_request_finish(tw_dev, request_id);
-                       tw_dev->srb[request_id]->result = (DID_OK << 16);
-                       tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]);
-                       return 0;
-       }
-
-       param_value = tw_dev->alignment_physical_address[request_id];
-       if (param_value == 0) {
-               printk(KERN_WARNING "3w-xxxx: tw_ioctl(): Bad alignment physical address.\n");
-               tw_dev->state[request_id] = TW_S_COMPLETED;
-               tw_state_request_finish(tw_dev, request_id);
-               tw_dev->srb[request_id]->result = (DID_OK << 16);
-               tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]);
-       }
-
-       command_packet->byte8.param.sgl[0].address = param_value;
-       command_packet->byte8.param.sgl[0].length = sizeof(TW_Sector);
-
-       command_packet->byte0.sgl_offset = 2;
-       command_packet->size = 4;
-       command_packet->request_id = request_id;
-       command_packet->byte3.host_id = 0;
-       command_packet->status = 0;
-       command_packet->flags = 0;
-       command_packet->byte6.parameter_count = 1;
+       param->table_id = TW_UNIT_INFORMATION_TABLE_BASE + 
+       tw_dev->srb[request_id]->device->id;
+       param->parameter_id = 4;        /* unitcapacity parameter */
+       param->parameter_size_bytes = 4;
+       param_value = tw_dev->alignment_physical_address[request_id];
+       if (param_value == 0) {
+               dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_read_capacity(): 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);
+       command_que_value = tw_dev->command_packet_physical_address[request_id];
+       if (command_que_value == 0) {
+               dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_read_capacity(): Bad command packet physical address.\n");
+               return 1;
+       }
 
        /* Now try to post the command to the board */
        tw_post_command_packet(tw_dev, request_id);
-
+  
        return 0;
-} /* End tw_ioctl() */
+} /* End tw_scsiop_read_capacity() */
 
-/* This function is called by the isr to complete ioctl requests */
-int tw_ioctl_complete(TW_Device_Extension *tw_dev, int request_id)
+/* This function is called by the isr to complete a readcapacity command */
+static int tw_scsiop_read_capacity_complete(TW_Device_Extension *tw_dev, int request_id)
 {
        unsigned char *param_data;
-       unsigned char *buff;
+       u32 capacity;
+       char *buff;
        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");
+       dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_read_capacity_complete()\n");
+
        buff = tw_dev->srb[request_id]->request_buffer;
        if (buff == NULL) {
-               printk(KERN_WARNING "3w-xxxx: tw_ioctl_complete(): Request buffer NULL.\n");
+               printk(KERN_WARNING "3w-xxxx: tw_scsiop_read_capacity_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);
+       memset(buff, 0, tw_dev->srb[request_id]->request_bufflen);
+       param = (TW_Param *)tw_dev->alignment_virtual_address[request_id];
+       if (param == NULL) {
+               printk(KERN_WARNING "3w-xxxx: tw_scsiop_read_capacity_complete(): Bad alignment virtual address.\n");
                return 1;
        }
+       param_data = &(param->data[0]);
 
-       dprintk(KERN_NOTICE "3w-xxxx: tw_ioctl_complete(): Request_bufflen = %d\n", tw_dev->srb[request_id]->request_bufflen);
+       capacity = (param_data[3] << 24) | (param_data[2] << 16) | 
+                  (param_data[1] << 8) | param_data[0];
 
-       ioctl = (TW_Ioctl *)buff;
-       switch (ioctl->opcode) {
-               case TW_ATA_PASSTHRU:
-                       passthru = (TW_Passthru *)ioctl->data;
-                       /* Don't return data for non-data ATA cmds */
-                       if ((passthru->param != 0) && (passthru->param != 0x8))
-                               memcpy(buff, tw_dev->alignment_virtual_address[request_id], passthru->sector_count * 512);
-                       else {
-                               /* For non-data cmds, return cmd pkt */
-                               if (tw_dev->srb[request_id]->request_bufflen >= sizeof(TW_Command))
-                                       memcpy(buff, tw_dev->command_packet_virtual_address[request_id], sizeof(TW_Command));
-                       }
-                       break;
-               case TW_CMD_PACKET_WITH_DATA:
-                       dprintk(KERN_WARNING "3w-xxxx: tw_ioctl_complete(): caught TW_CMD_PACKET_WITH_DATA.\n");
-                       clear_bit(TW_IN_IOCTL, &tw_dev->flags);
-                       return TW_ISR_DONT_COMPLETE; /* 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];
-                       if (param == NULL) {
-                               printk(KERN_WARNING "3w-xxxx: tw_ioctl_complete(): Bad alignment virtual address.\n");
-                               return 1;
-                       }
-                       param_data = &(param->data[0]);
-                       memcpy(buff, param_data, tw_dev->ioctl_size[request_id]);
-       }
-       return 0;
-} /* End tw_ioctl_complete() */
+       /* Subtract one sector to fix get last sector ioctl */
+       capacity -= 1;
 
-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_NOTICE "3w-xxxx: tw_scsiop_read_capacity_complete(): Capacity = 0x%x.\n", capacity);
 
-       dprintk(KERN_WARNING "3w-xxxx: tw_map_scsi_sg_data()\n");
-       
-       if (cmd->use_sg == 0)
-               return 0;
+       /* Number of LBA's */
+       buff[0] = (capacity >> 24);
+       buff[1] = (capacity >> 16) & 0xff;
+       buff[2] = (capacity >> 8) & 0xff;
+       buff[3] = capacity & 0xff;
 
-       use_sg = pci_map_sg(pdev, cmd->buffer, cmd->use_sg, dma_dir);
-       
-       if (use_sg == 0) {
-               printk(KERN_WARNING "3w-xxxx: tw_map_scsi_sg_data(): pci_map_sg() failed.\n");
-               return 0;
-       }
+       /* Block size in bytes (512) */
+       buff[4] = (TW_BLOCK_SIZE >> 24);
+       buff[5] = (TW_BLOCK_SIZE >> 16) & 0xff;
+       buff[6] = (TW_BLOCK_SIZE >> 8) & 0xff;
+       buff[7] = TW_BLOCK_SIZE & 0xff;
 
-       cmd->SCp.phase = 2;
-       cmd->SCp.have_data_in = use_sg;
-       
-       return use_sg;
-} /* End tw_map_scsi_sg_data() */
+       return 0;
+} /* End tw_scsiop_read_capacity_complete() */
 
-static u32 tw_map_scsi_single_data(struct pci_dev *pdev, Scsi_Cmnd *cmd)
+/* This function handles scsi read or write commands */
+static int tw_scsiop_read_write(TW_Device_Extension *tw_dev, int request_id) 
 {
-       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");
+       TW_Command *command_packet;
+       unsigned long command_que_value;
+       u32 lba = 0x0, num_sectors = 0x0, buffaddr = 0x0;
+       int i, use_sg;
+       struct scsi_cmnd *srb;
+       struct scatterlist *sglist;
 
-       if (cmd->request_bufflen == 0)
-               return 0;
+       dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_read_write()\n");
 
-       mapping = pci_map_page(pdev, virt_to_page(cmd->request_buffer), offset_in_page(cmd->request_buffer), cmd->request_bufflen, dma_dir);
+       if (tw_dev->srb[request_id]->request_buffer == NULL) {
+               printk(KERN_WARNING "3w-xxxx: tw_scsiop_read_write(): Request buffer NULL.\n");
+               return 1;
+       }
+       sglist = (struct scatterlist *)tw_dev->srb[request_id]->request_buffer;
+       srb = tw_dev->srb[request_id];
 
-       if (mapping == 0) {
-               printk(KERN_WARNING "3w-xxxx: tw_map_scsi_single_data(): pci_map_page() failed.\n");
-               return 0;
+       /* Initialize command packet */
+       command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id];
+       if (command_packet == NULL) {
+               dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_read_write(): Bad command packet virtual address.\n");
+               return 1;
        }
 
-       cmd->SCp.phase = 1;
-       cmd->SCp.have_data_in = mapping;
+       if (srb->cmnd[0] == READ_6 || srb->cmnd[0] == READ_10) {
+               command_packet->opcode__sgloffset = TW_OPSGL_IN(3, TW_OP_READ);
+       } else {
+               command_packet->opcode__sgloffset = TW_OPSGL_IN(3, TW_OP_WRITE);
+       }
 
-       return mapping;
-} /* End tw_map_scsi_single_data() */
+       command_packet->size = 3;
+       command_packet->request_id = request_id;
+       command_packet->unit__hostid = TW_UNITHOST_IN(0, srb->device->id);
+       command_packet->status = 0;
+       command_packet->flags = 0;
 
-/* This function will mask the command interrupt */
-void tw_mask_command_interrupt(TW_Device_Extension *tw_dev)
-{
-       u32 control_reg_addr, control_reg_value;
-       
-       control_reg_addr = tw_dev->registers.control_reg_addr;
-       control_reg_value = TW_CONTROL_MASK_COMMAND_INTERRUPT;
-       outl(control_reg_value, control_reg_addr);
-} /* End tw_mask_command_interrupt() */
+       if (srb->cmnd[0] == WRITE_10) {
+               if ((srb->cmnd[1] & 0x8) || (srb->cmnd[1] & 0x10))
+                       command_packet->flags = 1;
+       }
 
-/* This function will poll the status register for a flag */
-int tw_poll_status(TW_Device_Extension *tw_dev, u32 flag, int seconds)
-{
-       u32 status_reg_addr, status_reg_value;
-       struct timeval before, timeout;
+       if (srb->cmnd[0] == READ_6 || srb->cmnd[0] == WRITE_6) {
+               lba = ((u32)srb->cmnd[1] << 16) | ((u32)srb->cmnd[2] << 8) | (u32)srb->cmnd[3];
+               num_sectors = (u32)srb->cmnd[4];
+       } else {
+               lba = ((u32)srb->cmnd[2] << 24) | ((u32)srb->cmnd[3] << 16) | ((u32)srb->cmnd[4] << 8) | (u32)srb->cmnd[5];
+               num_sectors = (u32)srb->cmnd[8] | ((u32)srb->cmnd[7] << 8);
+       }
+  
+       /* Update sector statistic */
+       tw_dev->sector_count = num_sectors;
+       if (tw_dev->sector_count > tw_dev->max_sector_count)
+               tw_dev->max_sector_count = tw_dev->sector_count;
+  
+       dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_read_write(): lba = 0x%x num_sectors = 0x%x\n", lba, num_sectors);
+       command_packet->byte8.io.lba = lba;
+       command_packet->byte6.block_count = num_sectors;
 
-       status_reg_addr = tw_dev->registers.status_reg_addr;
-       do_gettimeofday(&before);
-       status_reg_value = inl(status_reg_addr);
+       /* 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]);
+               if (buffaddr == 0)
+                       return 1;
 
-       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, 0);
+               command_packet->byte8.io.sgl[0].address = buffaddr;
+               command_packet->byte8.io.sgl[0].length = tw_dev->srb[request_id]->request_bufflen;
+               command_packet->size+=2;
        }
-               
-       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, 0);
-               }
 
-               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);
+       /* 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]);
+               if (use_sg == 0)
                        return 1;
+
+               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;
                }
-               mdelay(5);
        }
-       return 0;
-} /* End tw_poll_status() */
-
-/* This function will poll the status register for disappearance of a flag */
-int tw_poll_status_gone(TW_Device_Extension *tw_dev, u32 flag, int seconds)
-{
-       u32 status_reg_addr, status_reg_value;
-       struct timeval before, timeout;
 
-       status_reg_addr = tw_dev->registers.status_reg_addr;
-       do_gettimeofday(&before);
-       status_reg_value = inl(status_reg_addr);
+       /* Update SG statistics */
+       tw_dev->sgl_entries = tw_dev->srb[request_id]->use_sg;
+       if (tw_dev->sgl_entries > tw_dev->max_sgl_entries)
+               tw_dev->max_sgl_entries = tw_dev->sgl_entries;
 
-       if (tw_check_bits(status_reg_value)) {
-               dprintk(KERN_WARNING "3w-xxxx: tw_poll_status_gone(): Unexpected bits.\n");
-               tw_decode_bits(tw_dev, status_reg_value, 0);
+       command_que_value = tw_dev->command_packet_physical_address[request_id];
+       if (command_que_value == 0) {
+               dprintk(KERN_WARNING "3w-xxxx: tw_scsiop_read_write(): Bad command packet physical address.\n");
+               return 1;
        }
+      
+       /* Now try to post the command to the board */
+       tw_post_command_packet(tw_dev, request_id);
 
-       while ((status_reg_value & flag) != 0) {
-               status_reg_value = inl(status_reg_addr);
-
-               if (tw_check_bits(status_reg_value)) {
-                       dprintk(KERN_WARNING "3w-xxxx: tw_poll_status_gone(): Unexpected bits.\n");
-                       tw_decode_bits(tw_dev, status_reg_value, 0);
-               }
-
-               do_gettimeofday(&timeout);
-               if (before.tv_sec + seconds < timeout.tv_sec) {
-                       dprintk(KERN_WARNING "3w-xxxx: tw_poll_status_gone(): Flag 0x%x never disappeared.\n", flag);
-                       return 1;
-               }
-               mdelay(5);
-       }
        return 0;
-} /* End tw_poll_status_gone() */
+} /* End tw_scsiop_read_write() */
 
-/* This function will attempt to post a command packet to the board */
-int tw_post_command_packet(TW_Device_Extension *tw_dev, int request_id)
+/* This function will handle the request sense scsi command */
+static int tw_scsiop_request_sense(TW_Device_Extension *tw_dev, int request_id)
 {
-       u32 status_reg_addr, status_reg_value;
-       unsigned long command_que_value;
-       u32 command_que_addr;
+       dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_request_sense()\n");
 
-       dprintk(KERN_NOTICE "3w-xxxx: tw_post_command_packet()\n");
-       command_que_addr = tw_dev->registers.command_que_addr;
-       command_que_value = tw_dev->command_packet_physical_address[request_id];
-       status_reg_addr = tw_dev->registers.status_reg_addr;
-       status_reg_value = inl(status_reg_addr);
+       /* 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 (tw_check_bits(status_reg_value)) {
-               dprintk(KERN_WARNING "3w-xxxx: tw_post_command_packet(): Unexpected bits.\n");
-               tw_decode_bits(tw_dev, status_reg_value, 1);
-       }
+       /* 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]);
 
-       if ((status_reg_value & TW_STATUS_COMMAND_QUEUE_FULL) == 0) {
-               /* We successfully posted the command packet */
-               outl(command_que_value, command_que_addr);
-               tw_dev->state[request_id] = TW_S_POSTED;
-               tw_dev->posted_request_count++;
-               if (tw_dev->posted_request_count > tw_dev->max_posted_request_count) {
-                       tw_dev->max_posted_request_count = tw_dev->posted_request_count;
-               }
-       } else {
-               /* Couldn't post the command packet, so we do it in the isr */
-               if (tw_dev->state[request_id] != TW_S_PENDING) {
-                       tw_dev->state[request_id] = TW_S_PENDING;
-                       tw_dev->pending_request_count++;
-                       if (tw_dev->pending_request_count > tw_dev->max_pending_request_count) {
-                               tw_dev->max_pending_request_count = tw_dev->pending_request_count;
-                       }
-                       tw_dev->pending_queue[tw_dev->pending_tail] = request_id;
-                       if (tw_dev->pending_tail == TW_Q_LENGTH-1) {
-                               tw_dev->pending_tail = TW_Q_START;
-                       } else {
-                               tw_dev->pending_tail = tw_dev->pending_tail + 1;
-                       }
-               } 
-               tw_unmask_command_interrupt(tw_dev);
-               return 1;
-       }
        return 0;
-} /* End tw_post_command_packet() */
+} /* End tw_scsiop_request_sense() */
 
-/* This function will reset a device extension */
-int tw_reset_device_extension(TW_Device_Extension *tw_dev) 
+/* This function will handle synchronize cache scsi command */
+static int tw_scsiop_synchronize_cache(TW_Device_Extension *tw_dev, int request_id)
 {
-       int imax = 0;
-       int i = 0;
-       Scsi_Cmnd *srb;
+       TW_Command *command_packet;
+       unsigned long command_que_value;
 
-       dprintk(KERN_NOTICE "3w-xxxx: tw_reset_device_extension()\n");
-       imax = TW_Q_LENGTH;
+       dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_synchronize_cache()\n");
 
-       if (tw_reset_sequence(tw_dev)) {
-               printk(KERN_WARNING "3w-xxxx: scsi%d: Reset sequence failed.\n", tw_dev->host->host_no);
+       /* Send firmware flush command for this unit */
+       command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id];
+       if (command_packet == NULL) {
+               printk(KERN_WARNING "3w-xxxx: tw_scsiop_synchronize_cache(): Bad command packet virtual address.\n");
                return 1;
        }
 
-       /* Abort all requests that are in progress */
-       for (i=0;i<imax;i++) {
-               if ((tw_dev->state[i] != TW_S_FINISHED) && 
-                   (tw_dev->state[i] != TW_S_INITIAL) &&
-                   (tw_dev->state[i] != TW_S_COMPLETED)) {
-                       srb = tw_dev->srb[i];
-                       if (srb != NULL) {
-                               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]);
-                       }
-               }
+       /* Setup the command packet */
+       memset(command_packet, 0, sizeof(TW_Sector));
+       command_packet->opcode__sgloffset = TW_OPSGL_IN(0, TW_OP_FLUSH_CACHE);
+       command_packet->size = 2;
+       command_packet->request_id = request_id;
+       command_packet->unit__hostid = TW_UNITHOST_IN(0, tw_dev->srb[request_id]->device->id);
+       command_packet->status = 0;
+       command_packet->flags = 0;
+       command_packet->byte6.parameter_count = 1;
+       command_que_value = tw_dev->command_packet_physical_address[request_id];
+       if (command_que_value == 0) {
+               printk(KERN_WARNING "3w-xxxx: tw_scsiop_synchronize_cache(): Bad command packet physical address.\n");
+               return 1;
        }
 
-       /* Reset queues and counts */
-       for (i=0;i<imax;i++) {
-               tw_dev->free_queue[i] = i;
-               tw_dev->state[i] = TW_S_INITIAL;
-       }
-       tw_dev->free_head = TW_Q_START;
-       tw_dev->free_tail = TW_Q_START;
-       tw_dev->posted_request_count = 0;
-       tw_dev->pending_request_count = 0;
-       tw_dev->pending_head = TW_Q_START;
-       tw_dev->pending_tail = TW_Q_START;
-       tw_dev->reset_print = 0;
-       tw_dev->chrdev_request_id = TW_IOCTL_CHRDEV_FREE;
+       /* Now try to post the command packet */
+       tw_post_command_packet(tw_dev, request_id);
 
        return 0;
-} /* End tw_reset_device_extension() */
+} /* End tw_scsiop_synchronize_cache() */
 
-/* This function will reset a controller */
-int tw_reset_sequence(TW_Device_Extension *tw_dev) 
+/* This function will handle test unit ready scsi command */
+static int tw_scsiop_test_unit_ready(TW_Device_Extension *tw_dev, int request_id)
 {
-       int error = 0;
-       int tries = 0;
-
-       /* Disable interrupts */
-       tw_disable_interrupts(tw_dev);
-
-       /* Reset the board */
-       while (tries < TW_MAX_RESET_TRIES) {
-               tw_soft_reset(tw_dev);
-
-               error = tw_aen_drain_queue(tw_dev);
-               if (error) {
-                       printk(KERN_WARNING "3w-xxxx: scsi%d: AEN drain failed, retrying.\n", tw_dev->host->host_no);
-                       tries++;
-                       continue;
-               }
+       TW_Param *param;
+       TW_Command *command_packet;
+       unsigned long command_que_value;
+       unsigned long param_value;
 
-               /* Check for controller errors */
-               if (tw_check_errors(tw_dev)) {
-                       printk(KERN_WARNING "3w-xxxx: scsi%d: Controller errors found, retrying.\n", tw_dev->host->host_no);
-                       tries++;
-                       continue;
-               }
+       dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_test_unit_ready()\n");
 
-               /* Now the controller is in a good state */
-               break;
+       /* Initialize command packet */
+       command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id];
+       if (command_packet == NULL) {
+               printk(KERN_WARNING "3w-xxxx: tw_scsiop_test_unit_ready(): Bad command packet virtual address.\n");
+               return 1;
        }
+       memset(command_packet, 0, sizeof(TW_Sector));
+       command_packet->opcode__sgloffset = TW_OPSGL_IN(2, TW_OP_GET_PARAM);
+       command_packet->size = 4;
+       command_packet->request_id = request_id;
+       command_packet->status = 0;
+       command_packet->flags = 0;
+       command_packet->byte6.parameter_count = 1;
 
-       if (tries >= TW_MAX_RESET_TRIES) {
-               printk(KERN_WARNING "3w-xxxx: scsi%d: Controller errors, card not responding, check all cabling.\n", tw_dev->host->host_no);
+       /* Now setup the param */
+       if (tw_dev->alignment_virtual_address[request_id] == NULL) {
+               printk(KERN_WARNING "3w-xxxx: tw_scsiop_test_unit_ready(): Bad alignment virtual address.\n");
                return 1;
        }
-
-       error = tw_initconnection(tw_dev, TW_INIT_MESSAGE_CREDITS);
-       if (error) {
-               printk(KERN_WARNING "3w-xxxx: scsi%d: Connection initialization failed.\n", tw_dev->host->host_no);
+       param = (TW_Param *)tw_dev->alignment_virtual_address[request_id];
+       memset(param, 0, sizeof(TW_Sector));
+       param->table_id = 3;     /* unit summary table */
+       param->parameter_id = 3; /* unitsstatus parameter */
+       param->parameter_size_bytes = TW_MAX_UNITS;
+       param_value = tw_dev->alignment_physical_address[request_id];
+       if (param_value == 0) {
+               printk(KERN_WARNING "3w-xxxx: tw_scsiop_test_unit_ready(): Bad alignment physical address.\n");
                return 1;
        }
 
-       /* Re-enable interrupts */
-       tw_enable_and_clear_interrupts(tw_dev);
-
-       return 0;
-} /* End tw_reset_sequence() */
-
-/* This funciton returns unit geometry in cylinders/heads/sectors */
-int tw_scsi_biosparam(struct scsi_device *sdev, struct block_device *bdev,
-               sector_t capacity, int geom[]) 
-{
-       int heads, sectors, cylinders;
-       TW_Device_Extension *tw_dev;
-       
-       dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_biosparam()\n");
-       tw_dev = (TW_Device_Extension *)sdev->host->hostdata;
-
-       heads = 64;
-       sectors = 32;
-       cylinders = (unsigned long)capacity / (heads * sectors);
-
-       if (capacity >= 0x200000) {
-               heads = 255;
-               sectors = 63;
-               cylinders = (unsigned long)capacity / (heads * sectors);
+       command_packet->byte8.param.sgl[0].address = param_value;
+       command_packet->byte8.param.sgl[0].length = sizeof(TW_Sector);
+       command_que_value = tw_dev->command_packet_physical_address[request_id];
+       if (command_que_value == 0) {
+               printk(KERN_WARNING "3w-xxxx: tw_scsiop_test_unit_ready(): Bad command packet physical address.\n");
+               return 1;
        }
 
-       dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_biosparam(): heads = %d, sectors = %d, cylinders = %d\n", heads, sectors, cylinders);
-       geom[0] = heads;                         
-       geom[1] = sectors;
-       geom[2] = cylinders;
+       /* Now try to post the command packet */
+       tw_post_command_packet(tw_dev, request_id);
 
        return 0;
-} /* End tw_scsi_biosparam() */
-
-/* This function will find and initialize any cards */
-int tw_scsi_detect(Scsi_Host_Template *tw_host)
-{
-       int ret;
-       
-       dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_detect()\n");
-
-       printk(KERN_WARNING "3ware Storage Controller device driver for Linux v%s.\n", tw_driver_version);
-
-       ret = tw_findcards(tw_host);
-
-       return ret;
-} /* End tw_scsi_detect() */
+} /* End tw_scsiop_test_unit_ready() */
 
-/* This is the new scsi eh abort function */
-int tw_scsi_eh_abort(Scsi_Cmnd *SCpnt) 
+/* This function is called by the isr to complete a testunitready command */
+static int tw_scsiop_test_unit_ready_complete(TW_Device_Extension *tw_dev, int request_id)
 {
-       TW_Device_Extension *tw_dev=NULL;
-       int i = 0;
-
-       dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_eh_abort()\n");
+       unsigned char *is_unit_present;
+       TW_Param *param;
 
-       if (!SCpnt) {
-               printk(KERN_WARNING "3w-xxxx: tw_scsi_eh_abort(): Invalid Scsi_Cmnd.\n");
-               return (FAILED);
-       }
+       dprintk(KERN_WARNING "3w-xxxx: tw_scsiop_test_unit_ready_complete()\n");
 
-       tw_dev = (TW_Device_Extension *)SCpnt->device->host->hostdata;
-       if (tw_dev == NULL) {
-               printk(KERN_WARNING "3w-xxxx: tw_scsi_eh_abort(): Invalid device extension.\n");
-               return (FAILED);
+       param = (TW_Param *)tw_dev->alignment_virtual_address[request_id];
+       if (param == NULL) {
+               printk(KERN_WARNING "3w-xxxx: tw_scsiop_test_unit_ready_complete(): Bad alignment virtual address.\n");
+               return 1;
        }
+       is_unit_present = &(param->data[0]);
 
-       spin_lock(&tw_dev->tw_lock);
-       tw_dev->num_aborts++;
-
-       /* If the command hasn't been posted yet, we can do the abort */
-       for (i=0;i<TW_Q_LENGTH;i++) {
-               if (tw_dev->srb[i] == SCpnt) {
-                       if (tw_dev->state[i] == TW_S_STARTED) {
-                               printk(KERN_WARNING "3w-xxxx: scsi%d: Unit #%d: Command (%p) timed out.\n", tw_dev->host->host_no, tw_dev->srb[i]==0 ? 0 : tw_dev->srb[i]->device->id, SCpnt);
-                               tw_dev->state[i] = TW_S_COMPLETED;
-                               tw_state_request_finish(tw_dev, i);
-                               spin_unlock(&tw_dev->tw_lock);
-                               return (SUCCESS);
-                       }
-                       if (tw_dev->state[i] == TW_S_PENDING) {
-                               printk(KERN_WARNING "3w-xxxx: scsi%d: Unit #%d: Command (%p) timed out.\n", tw_dev->host->host_no, tw_dev->srb[i]==0 ? 0 : tw_dev->srb[i]->device->id, SCpnt);
-                               if (tw_dev->pending_head == TW_Q_LENGTH-1) {
-                                       tw_dev->pending_head = TW_Q_START;
-                               } else {
-                                       tw_dev->pending_head = tw_dev->pending_head + 1;
-                               }
-                               tw_dev->pending_request_count--;
-                               tw_dev->state[i] = TW_S_COMPLETED;
-                               tw_state_request_finish(tw_dev, i);
-                               spin_unlock(&tw_dev->tw_lock);
-                               return (SUCCESS);
-                       }
-                       if (tw_dev->state[i] == TW_S_POSTED) {
-                               /* If the command has already been posted, we have to reset the card */
-                               printk(KERN_WARNING "3w-xxxx: scsi%d: Unit #%d: Command (%p) timed out, resetting card.\n", tw_dev->host->host_no, tw_dev->srb[i]==0 ? 0 : tw_dev->srb[i]->device->id, SCpnt);
-                               /* We have to let AEN requests through before the reset */
-                               spin_unlock(&tw_dev->tw_lock);
-                               spin_unlock_irq(tw_dev->host->host_lock);
-                               mdelay(TW_AEN_WAIT_TIME);
-                               spin_lock_irq(tw_dev->host->host_lock);
-                               spin_lock(&tw_dev->tw_lock);
-
-                               if (tw_reset_device_extension(tw_dev)) {
-                                       dprintk(KERN_WARNING "3w-xxxx: tw_scsi_eh_abort(): Reset failed for card %d.\n", tw_dev->host->host_no);
-                                       spin_unlock(&tw_dev->tw_lock);
-                                       return (FAILED);
-                               }
-                       }
-               }
+       if (is_unit_present[tw_dev->srb[request_id]->device->id] & TW_UNIT_ONLINE) {
+               tw_dev->is_unit_present[tw_dev->srb[request_id]->device->id] = 1;
+       } else {
+               tw_dev->is_unit_present[tw_dev->srb[request_id]->device->id] = 0;
+               tw_dev->srb[request_id]->result = (DID_BAD_TARGET << 16);
+               return TW_ISR_DONT_RESULT;
        }
 
-       spin_unlock(&tw_dev->tw_lock);
-       return (SUCCESS);
-} /* End tw_scsi_eh_abort() */
+       return 0;
+} /* End tw_scsiop_test_unit_ready_complete() */
 
-/* This is the new scsi eh reset function */
-int tw_scsi_eh_reset(Scsi_Cmnd *SCpnt
+/* This is the main scsi queue function to handle scsi opcodes */
+static int tw_scsi_queue(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)
 {
-       TW_Device_Extension *tw_dev=NULL;
-
-       dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_eh_reset()\n");
-
-       if (!SCpnt) {
-               printk(KERN_WARNING "3w-xxxx: tw_scsi_eh_reset(): Invalid Scsi_Cmnd.\n");
-               return (FAILED);
-       }
+       unsigned char *command = SCpnt->cmnd;
+       int request_id = 0;
+       int retval = 1;
+       TW_Device_Extension *tw_dev = (TW_Device_Extension *)SCpnt->device->host->hostdata;
 
-       tw_dev = (TW_Device_Extension *)SCpnt->device->host->hostdata;
-       if (tw_dev == NULL) {
-               printk(KERN_WARNING "3w-xxxx: tw_scsi_eh_reset(): Invalid device extension.\n");
-               return (FAILED);
-       }
+       /* Save done function into Scsi_Cmnd struct */
+       SCpnt->scsi_done = done;
+                
+       /* Queue the command and get a request id */
+       tw_state_request_start(tw_dev, &request_id);
 
-       /* We have to let AEN requests through before the reset */
-       spin_unlock_irq(tw_dev->host->host_lock);
-       mdelay(TW_AEN_WAIT_TIME);
-       spin_lock_irq(tw_dev->host->host_lock);
+       /* Save the scsi command for use by the ISR */
+       tw_dev->srb[request_id] = SCpnt;
 
-       spin_lock(&tw_dev->tw_lock);
-       tw_dev->num_resets++;
-
-       /* Now reset the card and some of the device extension data */
-       if (tw_reset_device_extension(tw_dev)) {
-               printk(KERN_WARNING "3w-xxxx: scsi%d: Reset failed.\n", tw_dev->host->host_no);
-               spin_unlock(&tw_dev->tw_lock);
-               return (FAILED);
-       }
-       printk(KERN_WARNING "3w-xxxx: scsi%d: Reset succeeded.\n", tw_dev->host->host_no);
-       spin_unlock(&tw_dev->tw_lock);
-
-       return (SUCCESS);
-} /* End tw_scsi_eh_reset() */
-
-/* This function handles input and output from /proc/scsi/3w-xxxx/x */
-int tw_scsi_proc_info(struct Scsi_Host *shost, char *buffer, char **start,
-                     off_t offset, int length, int inout) 
-{
-       TW_Device_Extension *tw_dev = NULL;
-       TW_Info info;
-       int i;
-       int j;
-
-       dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_proc_info()\n");
-
-       /* Find the correct device extension */
-       for (i=0;i<tw_device_extension_count;i++) 
-               if (tw_device_extension_list[i]->host->host_no == shost->host_no) 
-                       tw_dev = tw_device_extension_list[i];
-       if (tw_dev == NULL) {
-               printk(KERN_WARNING "3w-xxxx: tw_scsi_proc_info(): Couldn't locate device extension.\n");
-               return (-EINVAL);
-       }
-
-       info.buffer = buffer;
-       info.length = length;
-       info.offset = offset;
-       info.position = 0;
-       
-       if (inout) {
-               /* Write */
-               if (strncmp(buffer, "debug", 5) == 0) {
-                       printk(KERN_INFO "3w-xxxx: Posted commands:\n");
-                       for (j=0;j<TW_Q_LENGTH;j++) {
-                               if (tw_dev->state[j] == TW_S_POSTED) {
-                                       TW_Command *command = (TW_Command *)tw_dev->command_packet_virtual_address[j];
-                                       printk(KERN_INFO "3w-xxxx: Request_id: %d\n", j);
-                                       printk(KERN_INFO "Opcode: 0x%x\n", command->byte0.opcode);
-                                       printk(KERN_INFO "Block_count: 0x%x\n", command->byte6.block_count);
-                                       printk(KERN_INFO "LBA: 0x%x\n", command->byte8.io.lba);
-                                       printk(KERN_INFO "Physical command packet addr: 0x%lx\n", tw_dev->command_packet_physical_address[j]);
-                                       printk(KERN_INFO "Scsi_Cmnd: %p\n", tw_dev->srb[j]);
-                               }
-                       }
-                       printk(KERN_INFO "3w-xxxx: Free_head: %3d\n", tw_dev->free_head);
-                       printk(KERN_INFO "3w-xxxx: Free_tail: %3d\n", tw_dev->free_tail);
-               } 
-               return length;
-       } else {
-               /* Read */
-               if (start) {
-                       *start = buffer;
-               }
-               tw_copy_info(&info, "scsi%d: 3ware Storage Controller\n", shost->host_no);
-               tw_copy_info(&info, "Driver version: %s\n", tw_driver_version);
-               tw_copy_info(&info, "Current commands posted:       %3d\n", tw_dev->posted_request_count);
-               tw_copy_info(&info, "Max commands posted:           %3d\n", tw_dev->max_posted_request_count);
-               tw_copy_info(&info, "Current pending commands:      %3d\n", tw_dev->pending_request_count);
-               tw_copy_info(&info, "Max pending commands:          %3d\n", tw_dev->max_pending_request_count);
-               tw_copy_info(&info, "Last sgl length:               %3d\n", tw_dev->sgl_entries);
-               tw_copy_info(&info, "Max sgl length:                %3d\n", tw_dev->max_sgl_entries);
-               tw_copy_info(&info, "Last sector count:             %3d\n", tw_dev->sector_count);
-               tw_copy_info(&info, "Max sector count:              %3d\n", tw_dev->max_sector_count);
-               tw_copy_info(&info, "Resets:                        %3d\n", tw_dev->num_resets);
-               tw_copy_info(&info, "Aborts:                        %3d\n", tw_dev->num_aborts);
-               tw_copy_info(&info, "AEN's:                         %3d\n", tw_dev->aen_count);
-       }
-       if (info.position > info.offset) {
-               return (info.position - info.offset);
-       } else { 
-               return 0;
-       }
-} /* End tw_scsi_proc_info() */
-
-/* This is the main scsi queue function to handle scsi opcodes */
-int tw_scsi_queue(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) 
-{
-       unsigned char *command = SCpnt->cmnd;
-       int request_id = 0;
-       int error = 0;
-       TW_Device_Extension *tw_dev = (TW_Device_Extension *)SCpnt->device->host->hostdata;
-
-       if (tw_dev == NULL) {
-               printk(KERN_WARNING "3w-xxxx: tw_scsi_queue(): Invalid device extension.\n");
-               SCpnt->result = (DID_ERROR << 16);
-               done(SCpnt);
-               return 0;
-       }
-
-       spin_lock(&tw_dev->tw_lock);
-       dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_queue()\n");
-
-       /* Skip scsi command if it isn't for us */
-       if ((SCpnt->device->channel != 0) || (SCpnt->device->lun != 0)) {
-               SCpnt->result = (DID_BAD_TARGET << 16);
-               done(SCpnt);
-               spin_unlock(&tw_dev->tw_lock);
-               return 0;
-       }
-       
-       /* Save done function into Scsi_Cmnd struct */
-       SCpnt->scsi_done = done;
-                
-       /* Queue the command and get a request id */
-       tw_state_request_start(tw_dev, &request_id);
-
-       /* Save the scsi command for use by the ISR */
-       tw_dev->srb[request_id] = SCpnt;
-
-       /* Initialize phase to zero */
-       SCpnt->SCp.phase = 0;
+       /* Initialize phase to zero */
+       SCpnt->SCp.phase = TW_PHASE_INITIAL;
 
        switch (*command) {
                case READ_10:
@@ -2633,35 +2025,34 @@ int tw_scsi_queue(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
                case WRITE_10:
                case WRITE_6:
                        dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_queue(): caught READ/WRITE.\n");
-                       error = tw_scsiop_read_write(tw_dev, request_id);
+                       retval = tw_scsiop_read_write(tw_dev, request_id);
                        break;
                case TEST_UNIT_READY:
                        dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_queue(): caught TEST_UNIT_READY.\n");
-                       error = tw_scsiop_test_unit_ready(tw_dev, request_id);
+                       retval = tw_scsiop_test_unit_ready(tw_dev, request_id);
                        break;
                case INQUIRY:
                        dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_queue(): caught INQUIRY.\n");
-                       error = tw_scsiop_inquiry(tw_dev, request_id);
+                       retval = tw_scsiop_inquiry(tw_dev, request_id);
                        break;
                case READ_CAPACITY:
                        dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_queue(): caught READ_CAPACITY.\n");
-                       error = tw_scsiop_read_capacity(tw_dev, request_id);
+                       retval = tw_scsiop_read_capacity(tw_dev, request_id);
                        break;
                case REQUEST_SENSE:
                        dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_queue(): caught REQUEST_SENSE.\n");
-                       error = tw_scsiop_request_sense(tw_dev, request_id);
+                       retval = tw_scsiop_request_sense(tw_dev, request_id);
                        break;
                case MODE_SENSE:
                        dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_queue(): caught MODE_SENSE.\n");
-                       error = tw_scsiop_mode_sense(tw_dev, request_id);
+                       retval = tw_scsiop_mode_sense(tw_dev, request_id);
                        break;
                case SYNCHRONIZE_CACHE:
                        dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_queue(): caught SYNCHRONIZE_CACHE.\n");
-                       error = tw_scsiop_synchronize_cache(tw_dev, request_id);
+                       retval = tw_scsiop_synchronize_cache(tw_dev, request_id);
                        break;
                case TW_IOCTL:
-                       dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_queue(): caught TW_SCSI_IOCTL.\n");
-                       error = tw_ioctl(tw_dev, request_id);
+                       printk(KERN_WARNING "3w-xxxx: SCSI_IOCTL_SEND_COMMAND deprecated, please update your 3ware tools.\n");
                        break;
                default:
                        printk(KERN_NOTICE "3w-xxxx: scsi%d: Unknown scsi opcode: 0x%x\n", tw_dev->host->host_no, *command);
@@ -2669,837 +2060,441 @@ int tw_scsi_queue(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
                        tw_state_request_finish(tw_dev, request_id);
                        SCpnt->result = (DID_BAD_TARGET << 16);
                        done(SCpnt);
+                       goto out;
        }
-       if (error) {
+       if (retval) {
                tw_dev->state[request_id] = TW_S_COMPLETED;
                tw_state_request_finish(tw_dev, request_id);
                SCpnt->result = (DID_ERROR << 16);
                done(SCpnt);
+               retval = 0;
        }
-       spin_unlock(&tw_dev->tw_lock);
-
-       return 0;
+out:
+       return retval;
 } /* End tw_scsi_queue() */
 
-/* This function will release the resources on an rmmod call */
-int tw_scsi_release(struct Scsi_Host *tw_host) 
-{
-       TW_Device_Extension *tw_dev;
-       tw_dev = (TW_Device_Extension *)tw_host->hostdata;
-
-       dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_release()\n");
-
-       /* Fake like we just shut down, so notify the card that
-        * we "shut down cleanly".
-        */
-       tw_halt(NULL, 0, NULL);  // parameters aren't actually used
-
-       /* Free up the IO region */
-       release_region((tw_dev->tw_pci_dev->resource[0].start), TW_IO_ADDRESS_RANGE);
-
-       /* Free up the IRQ */
-       free_irq(tw_dev->tw_pci_dev->irq, tw_dev);
-
-       /* Unregister character device */
-       if (twe_major >= 0) {
-               unregister_chrdev(twe_major, "twe");
-               twe_major = -1;
-       }
-
-       /* Free up device extension resources */
-       tw_free_device_extension(tw_dev);
-
-       /* Tell kernel scsi-layer we are gone */
-       scsi_unregister(tw_host);
-
-       return 0;
-} /* End tw_scsi_release() */
-
-/* This function handles scsi inquiry commands */
-int tw_scsiop_inquiry(TW_Device_Extension *tw_dev, int request_id)
+/* This function is the interrupt service routine */
+static irqreturn_t tw_interrupt(int irq, void *dev_instance,
+                    struct pt_regs *regs) 
 {
-       TW_Param *param;
+       int request_id;
+       u32 status_reg_value;
+       TW_Device_Extension *tw_dev = (TW_Device_Extension *)dev_instance;
+       TW_Response_Queue response_que;
+       int error = 0, retval = 0;
        TW_Command *command_packet;
-       unsigned long command_que_value;
-       u32 command_que_addr;
-       unsigned long param_value;
-
-       dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_inquiry()\n");
-
-       /* Initialize command packet */
-       command_que_addr = tw_dev->registers.command_que_addr;
-       command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id];
-       if (command_packet == NULL) {
-               printk(KERN_WARNING "3w-xxxx: tw_scsiop_inquiry(): 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.parameter_count = 1;
-
-       /* Now setup the param */
-       if (tw_dev->alignment_virtual_address[request_id] == NULL) {
-               printk(KERN_WARNING "3w-xxxx: tw_scsiop_inquiry(): 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 = 3;     /* unit summary table */
-       param->parameter_id = 3; /* unitsstatus parameter */
-       param->parameter_size_bytes = TW_MAX_UNITS;
-       param_value = tw_dev->alignment_physical_address[request_id];
-       if (param_value == 0) {
-               printk(KERN_WARNING "3w-xxxx: tw_scsiop_inquiry(): Bad alignment physical address.\n");
-               return 1;
-       }
+       int handled = 0;
 
-       command_packet->byte8.param.sgl[0].address = param_value;
-       command_packet->byte8.param.sgl[0].length = sizeof(TW_Sector);
-       command_que_value = tw_dev->command_packet_physical_address[request_id];
-       if (command_que_value == 0) {
-               printk(KERN_WARNING "3w-xxxx: tw_scsiop_inquiry(): Bad command packet physical address.\n");
-               return 1;
-       }
+       /* Get the host lock for io completions */
+       spin_lock(tw_dev->host->host_lock);
 
-       /* Now try to post the command packet */
-       tw_post_command_packet(tw_dev, request_id);
+       /* See if the interrupt matches this instance */
+       if (tw_dev->tw_pci_dev->irq == (unsigned int)irq) {
 
-       return 0;
-} /* End tw_scsiop_inquiry() */
+               handled = 1;
 
-/* This function is called by the isr to complete an inquiry command */
-int tw_scsiop_inquiry_complete(TW_Device_Extension *tw_dev, int request_id)
-{
-       unsigned char *is_unit_present;
-       unsigned char *request_buffer;
-       TW_Param *param;
+               /* Read the registers */
+               status_reg_value = inl(TW_STATUS_REG_ADDR(tw_dev));
 
-       dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_inquiry_complete()\n");
+               /* Check if this is our interrupt, otherwise bail */
+               if (!(status_reg_value & TW_STATUS_VALID_INTERRUPT))
+                       goto tw_interrupt_bail;
 
-       /* Fill request buffer */
-       if (tw_dev->srb[request_id]->request_buffer == NULL) {
-               printk(KERN_WARNING "3w-xxxx: tw_scsiop_inquiry_complete(): Request buffer NULL.\n");
-               return 1;
-       }
-       request_buffer = tw_dev->srb[request_id]->request_buffer;
-       memset(request_buffer, 0, tw_dev->srb[request_id]->request_bufflen);
-       request_buffer[0] = TYPE_DISK; /* Peripheral device type */
-       request_buffer[1] = 0;         /* Device type modifier */
-       request_buffer[2] = 0;         /* No ansi/iso compliance */
-       request_buffer[4] = 31;        /* Additional length */
-       memcpy(&request_buffer[8], "3ware   ", 8);       /* Vendor ID */
-       sprintf(&request_buffer[16], "Logical Disk %-2d ", tw_dev->srb[request_id]->device->id);
-       memcpy(&request_buffer[32], tw_driver_version, 3);
+               /* Check controller for errors */
+               if (tw_check_bits(status_reg_value)) {
+                       dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Unexpected bits.\n");
+                       if (tw_decode_bits(tw_dev, status_reg_value, 1)) {
+                               TW_CLEAR_ALL_INTERRUPTS(tw_dev);
+                               goto tw_interrupt_bail;
+                       }
+               }
 
-       param = (TW_Param *)tw_dev->alignment_virtual_address[request_id];
-       if (param == NULL) {
-               printk(KERN_WARNING "3w-xxxx: tw_scsiop_inquiry_complete(): Bad alignment virtual address.\n");
-               return 1;
-       }
-       is_unit_present = &(param->data[0]);
+               /* Handle host interrupt */
+               if (status_reg_value & TW_STATUS_HOST_INTERRUPT) {
+                       dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): Received host interrupt.\n");
+                       TW_CLEAR_HOST_INTERRUPT(tw_dev);
+               }
 
-       if (is_unit_present[tw_dev->srb[request_id]->device->id] & TW_UNIT_ONLINE) {
-               tw_dev->is_unit_present[tw_dev->srb[request_id]->device->id] = TRUE;
-       } else {
-               tw_dev->is_unit_present[tw_dev->srb[request_id]->device->id] = FALSE;
-               tw_dev->srb[request_id]->result = (DID_BAD_TARGET << 16);
-               return TW_ISR_DONT_RESULT;
-       }
+               /* Handle attention interrupt */
+               if (status_reg_value & TW_STATUS_ATTENTION_INTERRUPT) {
+                       dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): Received attention interrupt.\n");
+                       TW_CLEAR_ATTENTION_INTERRUPT(tw_dev);
+                       tw_state_request_start(tw_dev, &request_id);
+                       error = tw_aen_read_queue(tw_dev, request_id);
+                       if (error) {
+                               printk(KERN_WARNING "3w-xxxx: scsi%d: Error reading aen queue.\n", tw_dev->host->host_no);
+                               tw_dev->state[request_id] = TW_S_COMPLETED;
+                               tw_state_request_finish(tw_dev, request_id);
+                       }
+               }
 
-       return 0;
-} /* End tw_scsiop_inquiry_complete() */
+               /* Handle command interrupt */
+               if (status_reg_value & TW_STATUS_COMMAND_INTERRUPT) {
+                       /* Drain as many pending commands as we can */
+                       while (tw_dev->pending_request_count > 0) {
+                               request_id = tw_dev->pending_queue[tw_dev->pending_head];
+                               if (tw_dev->state[request_id] != TW_S_PENDING) {
+                                       printk(KERN_WARNING "3w-xxxx: scsi%d: Found request id that wasn't pending.\n", tw_dev->host->host_no);
+                                       break;
+                               }
+                               if (tw_post_command_packet(tw_dev, request_id)==0) {
+                                       if (tw_dev->pending_head == TW_Q_LENGTH-1) {
+                                               tw_dev->pending_head = TW_Q_START;
+                                       } else {
+                                               tw_dev->pending_head = tw_dev->pending_head + 1;
+                                       }
+                                       tw_dev->pending_request_count--;
+                               } else {
+                                       /* If we get here, we will continue re-posting on the next command interrupt */
+                                       break;
+                               }
+                       }
+                       /* If there are no more pending requests, we mask command interrupt */
+                       if (tw_dev->pending_request_count == 0) 
+                               TW_MASK_COMMAND_INTERRUPT(tw_dev);
+               }
 
-/* This function handles scsi mode_sense commands */
-int tw_scsiop_mode_sense(TW_Device_Extension *tw_dev, int request_id)
-{
-       TW_Param *param;
-       TW_Command *command_packet;
-       unsigned long command_que_value;
-       unsigned long param_value;
+               /* Handle response interrupt */
+               if (status_reg_value & TW_STATUS_RESPONSE_INTERRUPT) {
+                       /* Drain the response queue from the board */
+                       while ((status_reg_value & TW_STATUS_RESPONSE_QUEUE_EMPTY) == 0) {
+                               /* Read response queue register */
+                               response_que.value = inl(TW_RESPONSE_QUEUE_REG_ADDR(tw_dev));
+                               request_id = TW_RESID_OUT(response_que.response_id);
+                               command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id];
+                               error = 0;
 
-       dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_mode_sense()\n");
+                               /* Check for bad response */
+                               if (command_packet->status != 0) {
+                                       /* If internal command, don't error, don't fill sense */
+                                       if (tw_dev->srb[request_id] == NULL) {
+                                               tw_decode_sense(tw_dev, request_id, 0);
+                                       } else {
+                                               error = tw_decode_sense(tw_dev, request_id, 1);
+                                       }
+                               }
 
-       /* Only page control = 0, page code = 0x8 (cache page) supported */
-       if (tw_dev->srb[request_id]->cmnd[2] != 0x8) {
-               tw_dev->state[request_id] = TW_S_COMPLETED;
-               tw_state_request_finish(tw_dev, request_id);
-               tw_dev->srb[request_id]->result = (DID_OK << 16);
-               tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]);
-               return 0;
-       }
+                               /* Check for correct state */
+                               if (tw_dev->state[request_id] != TW_S_POSTED) {
+                                       if (tw_dev->srb[request_id] != NULL) {
+                                               printk(KERN_WARNING "3w-xxxx: scsi%d: Received a request id that wasn't posted.\n", tw_dev->host->host_no);
+                                               error = 1;
+                                       }
+                               }
 
-       /* Now read firmware cache setting for this unit */
-       command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id];
-       if (command_packet == NULL) {
-               printk(KERN_WARNING "3w-xxxx: tw_scsiop_mode_sense(): Bad command packet virtual address.\n");
-               return 1;
-       }
+                               dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): Response queue request id: %d.\n", request_id);
 
-       /* Setup the command packet */
-       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.parameter_count = 1;
-
-       /* Setup the param */
-       if (tw_dev->alignment_virtual_address[request_id] == NULL) {
-               printk(KERN_WARNING "3w-xxxx: tw_scsiop_mode_sense(): 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 = TW_UNIT_INFORMATION_TABLE_BASE + tw_dev->srb[request_id]->device->id;
-       param->parameter_id = 7; /* unit flags */
-       param->parameter_size_bytes = 1;
-       param_value = tw_dev->alignment_physical_address[request_id];
-       if (param_value == 0) {
-               printk(KERN_WARNING "3w-xxxx: tw_scsiop_mode_sense(): 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);
-       command_que_value = tw_dev->command_packet_physical_address[request_id];
-       if (command_que_value == 0) {
-               printk(KERN_WARNING "3w-xxxx: tw_scsiop_mode_sense(): Bad command packet physical address.\n");
-               return 1;
-       }
-
-       /* Now try to post the command packet */
-       tw_post_command_packet(tw_dev, request_id);
-       
-       return 0;
-} /* End tw_scsiop_mode_sense() */
-
-/* This function is called by the isr to complete a mode sense command */
-int tw_scsiop_mode_sense_complete(TW_Device_Extension *tw_dev, int request_id)
-{
-       TW_Param *param;
-       unsigned char *flags;
-       unsigned char *request_buffer;
-
-       dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_mode_sense_complete()\n");
-
-       param = (TW_Param *)tw_dev->alignment_virtual_address[request_id];
-       if (param == NULL) {
-               printk(KERN_WARNING "3w-xxxx: tw_scsiop_mode_sense_complete(): Bad alignment virtual address.\n");
-               return 1;
-       }
-       flags = (char *)&(param->data[0]);
-       request_buffer = tw_dev->srb[request_id]->buffer;
-       memset(request_buffer, 0, tw_dev->srb[request_id]->request_bufflen);
-
-       request_buffer[0] = 0xf;        /* mode data length */
-       request_buffer[1] = 0;          /* default medium type */
-       request_buffer[2] = 0x10;       /* dpo/fua support on */
-       request_buffer[3] = 0;          /* no block descriptors */
-       request_buffer[4] = 0x8;        /* caching page */
-       request_buffer[5] = 0xa;        /* page length */
-       if (*flags & 0x1)
-               request_buffer[6] = 0x4;        /* WCE on */
-       else
-               request_buffer[6] = 0x0;        /* WCE off */
-
-       return 0;
-} /* End tw_scsiop_mode_sense_complete() */
-
-/* This function handles scsi read_capacity commands */
-int tw_scsiop_read_capacity(TW_Device_Extension *tw_dev, int request_id) 
-{
-       TW_Param *param;
-       TW_Command *command_packet;
-       unsigned long command_que_value;
-       u32 command_que_addr;
-       unsigned long param_value;
-
-       dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_read_capacity()\n");
-
-       /* Initialize command packet */
-       command_que_addr = tw_dev->registers.command_que_addr;
-       command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id];
-
-       if (command_packet == NULL) {
-               dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_read_capacity(): 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 = tw_dev->srb[request_id]->device->id;
-       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) {
-               dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_read_capacity(): 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 = TW_UNIT_INFORMATION_TABLE_BASE + 
-       tw_dev->srb[request_id]->device->id;
-       param->parameter_id = 4;        /* unitcapacity parameter */
-       param->parameter_size_bytes = 4;
-       param_value = tw_dev->alignment_physical_address[request_id];
-       if (param_value == 0) {
-               dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_read_capacity(): 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);
-       command_que_value = tw_dev->command_packet_physical_address[request_id];
-       if (command_que_value == 0) {
-               dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_read_capacity(): Bad command packet physical address.\n");
-               return 1;
-       }
-
-       /* Now try to post the command to the board */
-       tw_post_command_packet(tw_dev, request_id);
-  
-       return 0;
-} /* End tw_scsiop_read_capacity() */
-
-/* This function is called by the isr to complete a readcapacity command */
-int tw_scsiop_read_capacity_complete(TW_Device_Extension *tw_dev, int request_id)
-{
-       unsigned char *param_data;
-       u32 capacity;
-       char *buff;
-       TW_Param *param;
-
-       dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_read_capacity_complete()\n");
-
-       buff = tw_dev->srb[request_id]->request_buffer;
-       if (buff == NULL) {
-               printk(KERN_WARNING "3w-xxxx: tw_scsiop_read_capacity_complete(): Request buffer NULL.\n");
-               return 1;
-       }
-       memset(buff, 0, tw_dev->srb[request_id]->request_bufflen);
-       param = (TW_Param *)tw_dev->alignment_virtual_address[request_id];
-       if (param == NULL) {
-               printk(KERN_WARNING "3w-xxxx: tw_scsiop_read_capacity_complete(): Bad alignment virtual address.\n");
-               return 1;
-       }
-       param_data = &(param->data[0]);
-
-       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 */
-       buff[0] = (capacity >> 24);
-       buff[1] = (capacity >> 16) & 0xff;
-       buff[2] = (capacity >> 8) & 0xff;
-       buff[3] = capacity & 0xff;
-
-       /* Block size in bytes (512) */
-       buff[4] = (TW_BLOCK_SIZE >> 24);
-       buff[5] = (TW_BLOCK_SIZE >> 16) & 0xff;
-       buff[6] = (TW_BLOCK_SIZE >> 8) & 0xff;
-       buff[7] = TW_BLOCK_SIZE & 0xff;
-
-       return 0;
-} /* End tw_scsiop_read_capacity_complete() */
-
-/* This function handles scsi read or write commands */
-int tw_scsiop_read_write(TW_Device_Extension *tw_dev, int request_id) 
-{
-       TW_Command *command_packet;
-       unsigned long command_que_value;
-       u32 command_que_addr = 0x0;
-       u32 lba = 0x0, num_sectors = 0x0, buffaddr = 0x0;
-       int i, use_sg;
-       Scsi_Cmnd *srb;
-       struct scatterlist *sglist;
-
-       dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_read_write()\n");
-
-       if (tw_dev->srb[request_id]->request_buffer == NULL) {
-               printk(KERN_WARNING "3w-xxxx: tw_scsiop_read_write(): Request buffer NULL.\n");
-               return 1;
-       }
-       sglist = (struct scatterlist *)tw_dev->srb[request_id]->request_buffer;
-       srb = tw_dev->srb[request_id];
-
-       /* Initialize command packet */
-       command_que_addr = tw_dev->registers.command_que_addr;
-       command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id];
-       if (command_packet == NULL) {
-               dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_read_write(): Bad command packet virtual address.\n");
-               return 1;
-       }
-
-       if (srb->cmnd[0] == READ_6 || srb->cmnd[0] == READ_10) {
-               command_packet->byte0.opcode = TW_OP_READ;
-       } else {
-               command_packet->byte0.opcode = TW_OP_WRITE;
-       }
-
-       command_packet->byte0.sgl_offset = 3;
-       command_packet->size = 3;
-       command_packet->request_id = request_id;
-       command_packet->byte3.unit = srb->device->id;
-       command_packet->byte3.host_id = 0;
-       command_packet->status = 0;
-       command_packet->flags = 0;
-
-       if (srb->cmnd[0] == WRITE_10) {
-               if ((srb->cmnd[1] & 0x8) || (srb->cmnd[1] & 0x10))
-                       command_packet->flags = 1;
-       }
-
-       if (srb->cmnd[0] == READ_6 || srb->cmnd[0] == WRITE_6) {
-               lba = ((u32)srb->cmnd[1] << 16) | ((u32)srb->cmnd[2] << 8) | (u32)srb->cmnd[3];
-               num_sectors = (u32)srb->cmnd[4];
-       } else {
-               lba = ((u32)srb->cmnd[2] << 24) | ((u32)srb->cmnd[3] << 16) | ((u32)srb->cmnd[4] << 8) | (u32)srb->cmnd[5];
-               num_sectors = (u32)srb->cmnd[8] | ((u32)srb->cmnd[7] << 8);
-       }
-  
-       /* Update sector statistic */
-       tw_dev->sector_count = num_sectors;
-       if (tw_dev->sector_count > tw_dev->max_sector_count)
-               tw_dev->max_sector_count = tw_dev->sector_count;
-  
-       dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_read_write(): lba = 0x%x num_sectors = 0x%x\n", lba, num_sectors);
-       command_packet->byte8.io.lba = lba;
-       command_packet->byte6.block_count = num_sectors;
-
-       /* 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]);
-               if (buffaddr == 0)
-                       return 1;
-
-               command_packet->byte8.io.sgl[0].address = buffaddr;
-               command_packet->byte8.io.sgl[0].length = tw_dev->srb[request_id]->request_bufflen;
-               command_packet->size+=2;
-       }
-
-       /* 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]);
-               if (use_sg == 0)
-                       return 1;
-
-               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;
-               }
-       }
-
-       /* Update SG statistics */
-       tw_dev->sgl_entries = tw_dev->srb[request_id]->use_sg;
-       if (tw_dev->sgl_entries > tw_dev->max_sgl_entries)
-               tw_dev->max_sgl_entries = tw_dev->sgl_entries;
-
-       command_que_value = tw_dev->command_packet_physical_address[request_id];
-       if (command_que_value == 0) {
-               dprintk(KERN_WARNING "3w-xxxx: tw_scsiop_read_write(): Bad command packet physical address.\n");
-               return 1;
-       }
-      
-       /* Now try to post the command to the board */
-       tw_post_command_packet(tw_dev, request_id);
-
-       return 0;
-} /* End tw_scsiop_read_write() */
-
-/* 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 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() */
+                               /* Check for internal command completion */
+                               if (tw_dev->srb[request_id] == NULL) {
+                                       dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Found internally posted command.\n");
+                                       /* Check for chrdev ioctl completion */
+                                       if (request_id != tw_dev->chrdev_request_id) {
+                                               retval = tw_aen_complete(tw_dev, request_id);
+                                               if (retval) {
+                                                       printk(KERN_WARNING "3w-xxxx: scsi%d: Error completing aen.\n", tw_dev->host->host_no);
+                                               }
+                                       } else {
+                                               tw_dev->chrdev_request_id = TW_IOCTL_CHRDEV_FREE;
+                                               wake_up(&tw_dev->ioctl_wqueue);
+                                       }
+                               } else {
+                               switch (tw_dev->srb[request_id]->cmnd[0]) {
+                                       case READ_10:
+                                       case READ_6:
+                                               dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): caught READ_10/READ_6\n");
+                                               break;
+                                       case WRITE_10:
+                                       case WRITE_6:
+                                               dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): caught WRITE_10/WRITE_6\n");
+                                               break;
+                                       case TEST_UNIT_READY:
+                                               dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): caught TEST_UNIT_READY\n");
+                                               error = tw_scsiop_test_unit_ready_complete(tw_dev, request_id);
+                                               break;
+                                       case INQUIRY:
+                                               dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): caught INQUIRY\n");
+                                               error = tw_scsiop_inquiry_complete(tw_dev, request_id);
+                                               break;
+                                       case READ_CAPACITY:
+                                               dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): caught READ_CAPACITY\n");
+                                               error = tw_scsiop_read_capacity_complete(tw_dev, request_id);
+                                               break;
+                                       case MODE_SENSE:
+                                               dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): caught MODE_SENSE\n");
+                                               error = tw_scsiop_mode_sense_complete(tw_dev, request_id);
+                                               break;
+                                       case SYNCHRONIZE_CACHE:
+                                               dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): caught SYNCHRONIZE_CACHE\n");
+                                               break;
+                                       default:
+                                               printk(KERN_WARNING "3w-xxxx: case slip in tw_interrupt()\n");
+                                               error = 1;
+                                       }
 
-/* This function will handle synchronize cache scsi command */
-int tw_scsiop_synchronize_cache(TW_Device_Extension *tw_dev, int request_id)
-{
-       TW_Command *command_packet;
-       unsigned long command_que_value;
+                                       /* If no error command was a success */
+                                       if (error == 0) {
+                                               tw_dev->srb[request_id]->result = (DID_OK << 16);
+                                       }
 
-       dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_synchronize_cache()\n");
+                                       /* If error, command failed */
+                                       if (error == 1) {
+                                               /* Ask for a host reset */
+                                               tw_dev->srb[request_id]->result = (DID_OK << 16) | (CHECK_CONDITION << 1);
+                                       }
 
-       /* Send firmware flush command for this unit */
-       command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id];
-       if (command_packet == NULL) {
-               printk(KERN_WARNING "3w-xxxx: tw_scsiop_synchronize_cache(): Bad command packet virtual address.\n");
-               return 1;
-       }
+                                       /* Now complete the io */
+                                       if ((error != TW_ISR_DONT_COMPLETE)) {
+                                               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]);
 
-       /* Setup the command packet */
-       memset(command_packet, 0, sizeof(TW_Sector));
-       command_packet->byte0.opcode = TW_OP_FLUSH_CACHE;
-       command_packet->byte0.sgl_offset = 0;
-       command_packet->size = 2;
-       command_packet->request_id = request_id;
-       command_packet->byte3.unit = tw_dev->srb[request_id]->device->id;
-       command_packet->byte3.host_id = 0;
-       command_packet->status = 0;
-       command_packet->flags = 0;
-       command_packet->byte6.parameter_count = 1;
-       command_que_value = tw_dev->command_packet_physical_address[request_id];
-       if (command_que_value == 0) {
-               printk(KERN_WARNING "3w-xxxx: tw_scsiop_synchronize_cache(): Bad command packet physical address.\n");
-               return 1;
+                                               tw_unmap_scsi_data(tw_dev->tw_pci_dev, tw_dev->srb[request_id]);
+                                       }
+                               }
+                               
+                               /* Check for valid status after each drain */
+                               status_reg_value = inl(TW_STATUS_REG_ADDR(tw_dev));
+                               if (tw_check_bits(status_reg_value)) {
+                                       dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Unexpected bits.\n");
+                                       if (tw_decode_bits(tw_dev, status_reg_value, 1)) {
+                                               TW_CLEAR_ALL_INTERRUPTS(tw_dev);
+                                               goto tw_interrupt_bail;
+                                       }
+                               }
+                       }
+               }
        }
+tw_interrupt_bail:
+       spin_unlock(tw_dev->host->host_lock);
+       return IRQ_RETVAL(handled);
+} /* End tw_interrupt() */
 
-       /* Now try to post the command packet */
-       tw_post_command_packet(tw_dev, request_id);
-
-       return 0;
-} /* End tw_scsiop_synchronize_cache() */
-
-/* This function will handle test unit ready scsi command */
-int tw_scsiop_test_unit_ready(TW_Device_Extension *tw_dev, int request_id)
+/* This function tells the controller to shut down */
+static void __tw_shutdown(TW_Device_Extension *tw_dev)
 {
-       TW_Param *param;
-       TW_Command *command_packet;
-       unsigned long command_que_value;
-       u32 command_que_addr;
-       unsigned long param_value;
+       /* Disable interrupts */
+       TW_DISABLE_INTERRUPTS(tw_dev);
 
-       dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_test_unit_ready()\n");
+       printk(KERN_WARNING "3w-xxxx: Shutting down host %d.\n", tw_dev->host->host_no);
 
-       /* Initialize command packet */
-       command_que_addr = tw_dev->registers.command_que_addr;
-       command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id];
-       if (command_packet == NULL) {
-               printk(KERN_WARNING "3w-xxxx: tw_scsiop_test_unit_ready(): Bad command packet virtual address.\n");
-               return 1;
+       /* Tell the card we are shutting down */
+       if (tw_initconnection(tw_dev, 1)) {
+               printk(KERN_WARNING "3w-xxxx: Connection shutdown failed.\n");
+       } else {
+               printk(KERN_WARNING "3w-xxxx: Shutdown complete.\n");
        }
-       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.parameter_count = 1;
 
-       /* Now setup the param */
-       if (tw_dev->alignment_virtual_address[request_id] == NULL) {
-               printk(KERN_WARNING "3w-xxxx: tw_scsiop_test_unit_ready(): 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 = 3;     /* unit summary table */
-       param->parameter_id = 3; /* unitsstatus parameter */
-       param->parameter_size_bytes = TW_MAX_UNITS;
-       param_value = tw_dev->alignment_physical_address[request_id];
-       if (param_value == 0) {
-               printk(KERN_WARNING "3w-xxxx: tw_scsiop_test_unit_ready(): Bad alignment physical address.\n");
-               return 1;
-       }
+       /* Clear all interrupts just before exit */
+       TW_ENABLE_AND_CLEAR_INTERRUPTS(tw_dev);
+} /* End __tw_shutdown() */
 
-       command_packet->byte8.param.sgl[0].address = param_value;
-       command_packet->byte8.param.sgl[0].length = sizeof(TW_Sector);
-       command_que_value = tw_dev->command_packet_physical_address[request_id];
-       if (command_que_value == 0) {
-               printk(KERN_WARNING "3w-xxxx: tw_scsiop_test_unit_ready(): Bad command packet physical address.\n");
-               return 1;
-       }
+/* Wrapper for __tw_shutdown */
+static void tw_shutdown(struct device *dev)
+{
+       struct Scsi_Host *host = pci_get_drvdata(to_pci_dev(dev));
+       TW_Device_Extension *tw_dev = (TW_Device_Extension *)host->hostdata;
 
-       /* Now try to post the command packet */
-       tw_post_command_packet(tw_dev, request_id);
+       __tw_shutdown(tw_dev);
+} /* End tw_shutdown() */
 
-       return 0;
-} /* End tw_scsiop_test_unit_ready() */
+static struct scsi_host_template driver_template = {
+       .module                 = THIS_MODULE,
+       .name                   = "3ware Storage Controller",
+       .queuecommand           = tw_scsi_queue,
+       .eh_host_reset_handler  = tw_scsi_eh_reset,
+       .bios_param             = tw_scsi_biosparam,
+       .can_queue              = TW_Q_LENGTH-2,
+       .this_id                = -1,
+       .sg_tablesize           = TW_MAX_SGL_LENGTH,
+       .max_sectors            = TW_MAX_SECTORS,
+       .cmd_per_lun            = TW_MAX_CMDS_PER_LUN,  
+       .use_clustering         = ENABLE_CLUSTERING,
+       .shost_attrs            = tw_host_attrs,
+       .sdev_attrs             = tw_dev_attrs,
+       .emulated               = 1
+};
 
-/* This function is called by the isr to complete a testunitready command */
-int tw_scsiop_test_unit_ready_complete(TW_Device_Extension *tw_dev, int request_id)
+/* This function will probe and initialize a card */
+static int __devinit tw_probe(struct pci_dev *pdev, const struct pci_device_id *dev_id)
 {
-       unsigned char *is_unit_present;
-       TW_Param *param;
+       struct Scsi_Host *host = NULL;
+       TW_Device_Extension *tw_dev;
+       int retval = -ENODEV;
 
-       dprintk(KERN_WARNING "3w-xxxx: tw_scsiop_test_unit_ready_complete()\n");
+       retval = pci_enable_device(pdev);
+       if (retval) {
+               printk(KERN_WARNING "3w-xxxx: Failed to enable pci device.");
+               goto out_disable_device;
+       }
 
-       param = (TW_Param *)tw_dev->alignment_virtual_address[request_id];
-       if (param == NULL) {
-               printk(KERN_WARNING "3w-xxxx: tw_scsiop_test_unit_ready_complete(): Bad alignment virtual address.\n");
-               return 1;
+       pci_set_master(pdev);
+
+       retval = pci_set_dma_mask(pdev, TW_DMA_MASK);
+       if (retval) {
+               printk(KERN_WARNING "3w-xxxx: Failed to set dma mask.");
+               goto out_disable_device;
        }
-       is_unit_present = &(param->data[0]);
 
-       if (is_unit_present[tw_dev->srb[request_id]->device->id] & TW_UNIT_ONLINE) {
-               tw_dev->is_unit_present[tw_dev->srb[request_id]->device->id] = TRUE;
-       } else {
-               tw_dev->is_unit_present[tw_dev->srb[request_id]->device->id] = FALSE;
-               tw_dev->srb[request_id]->result = (DID_BAD_TARGET << 16);
-               return TW_ISR_DONT_RESULT;
+       host = scsi_host_alloc(&driver_template, sizeof(TW_Device_Extension));
+       if (!host) {
+               printk(KERN_WARNING "3w-xxxx: Failed to allocate memory for device extension.");
+               retval = -ENOMEM;
+               goto out_disable_device;
        }
+       tw_dev = (TW_Device_Extension *)host->hostdata;
 
-       return 0;
-} /* End tw_scsiop_test_unit_ready_complete() */
+       memset(tw_dev, 0, sizeof(TW_Device_Extension));
 
-/* Set a value in the features table */
-int tw_setfeature(TW_Device_Extension *tw_dev, int parm, int param_size,
-                  unsigned char *val)
-{
-       TW_Param *param;
-       TW_Command  *command_packet;
-       TW_Response_Queue response_queue;
-       int request_id = 0;
-       unsigned long command_que_value;
-       u32 command_que_addr;
-       u32 response_que_addr;
-       unsigned long param_value;
+       /* Save values to device extension */
+       tw_dev->host = host;
+       tw_dev->tw_pci_dev = pdev;
 
-       /* Initialize SetParam command packet */
-       if (tw_dev->command_packet_virtual_address[request_id] == NULL) {
-               printk(KERN_WARNING "3w-xxxx: tw_setfeature(): Bad command packet virtual address.\n");
-               return 1;
+       if (tw_initialize_device_extension(tw_dev)) {
+               printk(KERN_WARNING "3w-xxxx: Failed to initialize device extension.");
+               goto out_free_device_extension;
        }
-       command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id];
-       memset(command_packet, 0, sizeof(TW_Sector));
-       param = (TW_Param *)tw_dev->alignment_virtual_address[request_id];
-
-       command_packet->byte0.opcode = TW_OP_SET_PARAM;
-       command_packet->byte0.sgl_offset  = 2;
-       param->table_id = 0x404;  /* Features table */
-       param->parameter_id = parm;
-       param->parameter_size_bytes = param_size;
-       memcpy(param->data, val, param_size);
 
-       param_value = tw_dev->alignment_physical_address[request_id];
-       if (param_value == 0) {
-               printk(KERN_WARNING "3w-xxxx: tw_ioctl(): Bad alignment physical address.\n");
-               tw_dev->state[request_id] = TW_S_COMPLETED;
-               tw_state_request_finish(tw_dev, request_id);
-               tw_dev->srb[request_id]->result = (DID_OK << 16);
-               tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]);
+       /* Request IO regions */
+       retval = pci_request_regions(pdev, "3w-xxxx");
+       if (retval) {
+               printk(KERN_WARNING "3w-xxxx: Failed to get mem region.");
+               goto out_free_device_extension;
        }
-       command_packet->byte8.param.sgl[0].address = param_value;
-       command_packet->byte8.param.sgl[0].length = sizeof(TW_Sector);
-
-       command_packet->size = 4;
-       command_packet->request_id = request_id;
-       command_packet->byte6.parameter_count = 1;
 
-       command_que_value = tw_dev->command_packet_physical_address[request_id];
-       if (command_que_value == 0) {
-               printk(KERN_WARNING "3w-xxxx: tw_setfeature(): Bad command packet physical address.\n");
-       return 1;
+       /* Save base address */
+       tw_dev->base_addr = pci_resource_start(pdev, 0);
+       if (!tw_dev->base_addr) {
+               printk(KERN_WARNING "3w-xxxx: Failed to get io address.");
+               goto out_release_mem_region;
        }
-       command_que_addr = tw_dev->registers.command_que_addr;
-       response_que_addr = tw_dev->registers.response_que_addr;
-
-       /* Send command packet to the board */
-       outl(command_que_value, command_que_addr);
 
-       /* Poll for completion */
-       if (tw_poll_status_gone(tw_dev, TW_STATUS_RESPONSE_QUEUE_EMPTY, 30) == 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_setfeature(): Unexpected request id.\n");
-                       return 1;
-               }
-               if (command_packet->status != 0) {
-                       /* bad response */
-                       tw_decode_sense(tw_dev, request_id, 0);
-                       return 1;
-               }
-       }
+       /* Disable interrupts on the card */
+       TW_DISABLE_INTERRUPTS(tw_dev);
 
-       return 0;
-} /* End tw_setfeature() */
+       /* Initialize the card */
+       if (tw_reset_sequence(tw_dev))
+               goto out_release_mem_region;
 
-/* This function will setup the interrupt handler */
-int tw_setup_irq(TW_Device_Extension *tw_dev)
-{
-       char *device = TW_DEVICE_NAME;
-       int error;
+       /* Set host specific parameters */
+       host->max_id = TW_MAX_UNITS;
+       host->max_cmd_len = TW_MAX_CDB_LEN;
 
-       dprintk(KERN_NOTICE "3w-xxxx: tw_setup_irq()\n");
-       error = request_irq(tw_dev->tw_pci_dev->irq, tw_interrupt, SA_SHIRQ, device, tw_dev);
+       /* Luns and channels aren't supported by adapter */
+       host->max_lun = 0;
+       host->max_channel = 0;
 
-       if (error < 0) {
-               printk(KERN_WARNING "3w-xxxx: scsi%d: Error requesting IRQ: %d.\n", tw_dev->host->host_no, tw_dev->tw_pci_dev->irq);
-               return 1;
+       /* Register the card with the kernel SCSI layer */
+       retval = scsi_add_host(host, &pdev->dev);
+       if (retval) {
+               printk(KERN_WARNING "3w-xxxx: scsi add host failed");
+               goto out_release_mem_region;
        }
-       return 0;
-} /* End tw_setup_irq() */
 
-/* This function will tell the controller we're shutting down by sending
-   initconnection with a 1 */
-int tw_shutdown_device(TW_Device_Extension *tw_dev)
-{
-       int error;
+       pci_set_drvdata(pdev, host);
 
-       /* Disable interrupts */
-       tw_disable_interrupts(tw_dev);
+       printk(KERN_WARNING "3w-xxxx: scsi%d: Found a 3ware Storage Controller at 0x%x, IRQ: %d.\n", host->host_no, tw_dev->base_addr, pdev->irq);
 
-       /* poke the board */
-       error = tw_initconnection(tw_dev, 1);
-       if (error) {
-               printk(KERN_WARNING "3w-xxxx: scsi%d: Connection shutdown failed.\n", tw_dev->host->host_no);
-       } else {
-               printk(KERN_NOTICE "3w-xxxx: Shutdown complete.\n");
+       /* Now setup the interrupt handler */
+       retval = request_irq(pdev->irq, tw_interrupt, SA_SHIRQ, "3w-xxxx", tw_dev);
+       if (retval) {
+               printk(KERN_WARNING "3w-xxxx: Error requesting IRQ.");
+               goto out_remove_host;
        }
 
-       /* Re-enable interrupts */
-       tw_enable_and_clear_interrupts(tw_dev);
-
-       return 0;
-} /* End tw_shutdown_device() */
+       tw_device_extension_list[tw_device_extension_count] = tw_dev;
+       tw_device_extension_count++;
 
-/* This function will configure individual target parameters */
-int tw_slave_configure(Scsi_Device *SDptr)
-{
-       int max_cmds;
+       /* Re-enable interrupts on the card */
+       TW_ENABLE_AND_CLEAR_INTERRUPTS(tw_dev);
 
-       dprintk(KERN_WARNING "3w-xxxx: tw_slave_configure()\n");
+       /* Finally, scan the host */
+       scsi_scan_host(host);
 
-       if (cmds_per_lun) {
-               max_cmds = cmds_per_lun;
-               if (max_cmds > TW_MAX_CMDS_PER_LUN)
-                       max_cmds = TW_MAX_CMDS_PER_LUN;
-       } else {
-               max_cmds = TW_MAX_CMDS_PER_LUN;
+       if (twe_major == -1) {
+               if ((twe_major = register_chrdev (0, "twe", &tw_fops)) < 0)
+                       printk(KERN_WARNING "3w-xxxx: Failed to register character device.");
        }
-       scsi_adjust_queue_depth(SDptr, MSG_ORDERED_TAG, max_cmds);
-
        return 0;
-} /* End tw_slave_configure() */
 
-/* This function will soft reset the controller */
-void tw_soft_reset(TW_Device_Extension *tw_dev) 
-{
-       u32 control_reg_addr, control_reg_value;
-
-       control_reg_addr = tw_dev->registers.control_reg_addr;
-       control_reg_value = (   TW_CONTROL_ISSUE_SOFT_RESET |
-                               TW_CONTROL_CLEAR_HOST_INTERRUPT |
-                               TW_CONTROL_CLEAR_ATTENTION_INTERRUPT |
-                               TW_CONTROL_MASK_COMMAND_INTERRUPT |
-                               TW_CONTROL_MASK_RESPONSE_INTERRUPT |
-                               TW_CONTROL_CLEAR_ERROR_STATUS | 
-                               TW_CONTROL_DISABLE_INTERRUPTS);
-       outl(control_reg_value, control_reg_addr);
-} /* End tw_soft_reset() */
+out_remove_host:
+       scsi_remove_host(host);
+out_release_mem_region:
+       pci_release_regions(pdev);
+out_free_device_extension:
+       tw_free_device_extension(tw_dev);
+       scsi_host_put(host);
+out_disable_device:
+       pci_disable_device(pdev);
 
-/* This function will free a request_id */
-int tw_state_request_finish(TW_Device_Extension *tw_dev, int request_id)
+       return retval;
+} /* End tw_probe() */
+
+/* This function is called to remove a device */
+static void tw_remove(struct pci_dev *pdev)
 {
-       dprintk(KERN_NOTICE "3w-xxxx: tw_state_request_finish()\n");
-  
-       tw_dev->free_queue[tw_dev->free_tail] = request_id;
-       tw_dev->state[request_id] = TW_S_FINISHED;
-       if (tw_dev->free_tail == tw_dev->free_wrap)
-               tw_dev->free_tail = TW_Q_START;
-       else
-               tw_dev->free_tail++;
+       struct Scsi_Host *host = pci_get_drvdata(pdev);
+       TW_Device_Extension *tw_dev = (TW_Device_Extension *)host->hostdata;
 
-       dprintk(KERN_NOTICE "3w-xxxx: tw_state_request_finish(): Freeing request_id %d\n", request_id);
+       scsi_remove_host(tw_dev->host);
 
-       return 0;
-} /* End tw_state_request_finish() */
+       __tw_shutdown(tw_dev);
 
-/* This function will assign an available request_id */
-int tw_state_request_start(TW_Device_Extension *tw_dev, int *request_id)
-{
-       int id = 0;
+       /* Free up the IRQ */
+       free_irq(tw_dev->tw_pci_dev->irq, tw_dev);
 
-       dprintk(KERN_NOTICE "3w-xxxx: tw_state_request_start()\n");
-       
-       /* Obtain next free request_id */
-       id = tw_dev->free_queue[tw_dev->free_head];
-       if (tw_dev->free_head == tw_dev->free_wrap)
-               tw_dev->free_head = TW_Q_START;
-       else
-               tw_dev->free_head++;
+       /* Free up the mem region */
+       pci_release_regions(pdev);
 
-       *request_id = id;
-       tw_dev->state[id] = TW_S_STARTED;
+       /* Free up device extension resources */
+       tw_free_device_extension(tw_dev);
 
-       dprintk(KERN_NOTICE "3w-xxxx: tw_state_request_start(): id = %d.\n", id);
-       return 0;
-} /* End tw_state_request_start() */
+       /* Unregister character device */
+       if (twe_major >= 0) {
+               unregister_chrdev(twe_major, "twe");
+               twe_major = -1;
+       }
 
-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);
+       scsi_host_put(tw_dev->host);
+       pci_disable_device(pdev);
+       tw_device_extension_count--;
+} /* End tw_remove() */
 
-       dprintk(KERN_WARNING "3w-xxxx: tw_unmap_scsi_data()\n");
+/* PCI Devices supported by this driver */
+static struct pci_device_id tw_pci_tbl[] __devinitdata = {
+       { PCI_VENDOR_ID_3WARE, PCI_DEVICE_ID_3WARE_1000,
+         PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+       { PCI_VENDOR_ID_3WARE, PCI_DEVICE_ID_3WARE_7000,
+         PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+       { }
+};
+MODULE_DEVICE_TABLE(pci, tw_pci_tbl);
 
-       switch(cmd->SCp.phase) {
-               case 1:
-                       pci_unmap_page(pdev, cmd->SCp.have_data_in, cmd->request_bufflen, dma_dir);
-                       break;
-               case 2:
-                       pci_unmap_sg(pdev, cmd->request_buffer, cmd->use_sg, dma_dir);
-                       break;
+/* pci_driver initializer */
+static struct pci_driver tw_driver = {
+       .name           = "3w-xxxx",
+       .id_table       = tw_pci_tbl,
+       .probe          = tw_probe,
+       .remove         = tw_remove,
+       .driver         = {
+               .shutdown = tw_shutdown
        }
-} /* 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)
+/* This function is called on driver initialization */
+static int __init tw_init(void)
 {
-       u32 control_reg_addr, control_reg_value;
+       printk(KERN_WARNING "3ware Storage Controller device driver for Linux v%s.\n", TW_DRIVER_VERSION);
 
-       control_reg_addr = tw_dev->registers.control_reg_addr;
-       control_reg_value = TW_CONTROL_UNMASK_COMMAND_INTERRUPT;
-       outl(control_reg_value, control_reg_addr);
-} /* End tw_unmask_command_interrupt() */
+       return pci_module_init(&tw_driver);
+} /* End tw_init() */
 
-static Scsi_Host_Template driver_template = {
-       .proc_name              = "3w-xxxx",
-       .proc_info              = tw_scsi_proc_info,
-       .name                   = "3ware Storage Controller",
-       .detect                 = tw_scsi_detect,
-       .release                = tw_scsi_release,
-       .queuecommand           = tw_scsi_queue,
-       .eh_abort_handler       = tw_scsi_eh_abort,
-       .eh_host_reset_handler  = tw_scsi_eh_reset,
-       .bios_param             = tw_scsi_biosparam,
-       .slave_configure        = tw_slave_configure,
-       .can_queue              = TW_Q_LENGTH-2,
-       .this_id                = -1,
-       .sg_tablesize           = TW_MAX_SGL_LENGTH,
-       .max_sectors            = TW_MAX_SECTORS,
-       .cmd_per_lun            = TW_MAX_CMDS_PER_LUN,  
-       .use_clustering         = ENABLE_CLUSTERING,
-       .emulated               = 1
-};
-#include "scsi_module.c"
+/* This function is called on driver exit */
+static void __exit tw_exit(void)
+{
+       pci_unregister_driver(&tw_driver);
+} /* End tw_exit() */
+
+module_init(tw_init);
+module_exit(tw_exit);