[SCSI] bnx2fc: Broadcom FCoE offload driver
[linux-2.6.git] / drivers / scsi / hpsa.c
index e518766..c30591f 100644 (file)
@@ -31,7 +31,6 @@
 #include <linux/seq_file.h>
 #include <linux/init.h>
 #include <linux/spinlock.h>
-#include <linux/smp_lock.h>
 #include <linux/compat.h>
 #include <linux/blktrace_api.h>
 #include <linux/uaccess.h>
@@ -43,6 +42,7 @@
 #include <scsi/scsi_cmnd.h>
 #include <scsi/scsi_device.h>
 #include <scsi/scsi_host.h>
+#include <scsi/scsi_tcq.h>
 #include <linux/cciss_ioctl.h>
 #include <linux/string.h>
 #include <linux/bitmap.h>
@@ -52,7 +52,7 @@
 #include "hpsa.h"
 
 /* HPSA_DRIVER_VERSION must be 3 byte values (0-255) separated by '.' */
-#define HPSA_DRIVER_VERSION "1.0.0"
+#define HPSA_DRIVER_VERSION "2.0.2-1"
 #define DRIVER_NAME "HP HPSA Driver (v " HPSA_DRIVER_VERSION ")"
 
 /* How long to wait (in milliseconds) for board to go into simple mode */
@@ -74,12 +74,13 @@ static int hpsa_allow_any;
 module_param(hpsa_allow_any, int, S_IRUGO|S_IWUSR);
 MODULE_PARM_DESC(hpsa_allow_any,
                "Allow hpsa driver to access unknown HP Smart Array hardware");
+static int hpsa_simple_mode;
+module_param(hpsa_simple_mode, int, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(hpsa_simple_mode,
+       "Use 'simple mode' rather than 'performant mode'");
 
 /* define the PCI info for the cards we can control */
 static const struct pci_device_id hpsa_pci_device_id[] = {
-       {PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSC,     0x103C, 0x3223},
-       {PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSC,     0x103C, 0x3234},
-       {PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSC,     0x103C, 0x323D},
        {PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSE,     0x103C, 0x3241},
        {PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSE,     0x103C, 0x3243},
        {PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSE,     0x103C, 0x3245},
@@ -87,7 +88,13 @@ static const struct pci_device_id hpsa_pci_device_id[] = {
        {PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSE,     0x103C, 0x3249},
        {PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSE,     0x103C, 0x324a},
        {PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSE,     0x103C, 0x324b},
-       {PCI_VENDOR_ID_HP,     PCI_ANY_ID,             PCI_ANY_ID, PCI_ANY_ID,
+       {PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSE,     0x103C, 0x3233},
+       {PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSE,     0x103C, 0x3250},
+       {PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSE,     0x103C, 0x3251},
+       {PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSE,     0x103C, 0x3252},
+       {PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSE,     0x103C, 0x3253},
+       {PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSE,     0x103C, 0x3254},
+       {PCI_VENDOR_ID_HP,     PCI_ANY_ID,      PCI_ANY_ID, PCI_ANY_ID,
                PCI_CLASS_STORAGE_RAID << 8, 0xffff << 8, 0},
        {0,}
 };
@@ -99,9 +106,6 @@ MODULE_DEVICE_TABLE(pci, hpsa_pci_device_id);
  *  access = Address of the struct of function pointers
  */
 static struct board_type products[] = {
-       {0x3223103C, "Smart Array P800", &SA5_access},
-       {0x3234103C, "Smart Array P400", &SA5_access},
-       {0x323d103c, "Smart Array P700M", &SA5_access},
        {0x3241103C, "Smart Array P212", &SA5_access},
        {0x3243103C, "Smart Array P410", &SA5_access},
        {0x3245103C, "Smart Array P410i", &SA5_access},
@@ -109,12 +113,18 @@ static struct board_type products[] = {
        {0x3249103C, "Smart Array P812", &SA5_access},
        {0x324a103C, "Smart Array P712m", &SA5_access},
        {0x324b103C, "Smart Array P711m", &SA5_access},
+       {0x3250103C, "Smart Array", &SA5_access},
+       {0x3250113C, "Smart Array", &SA5_access},
+       {0x3250123C, "Smart Array", &SA5_access},
+       {0x3250133C, "Smart Array", &SA5_access},
+       {0x3250143C, "Smart Array", &SA5_access},
        {0xFFFF103C, "Unknown Smart Array", &SA5_access},
 };
 
 static int number_of_controllers;
 
-static irqreturn_t do_hpsa_intr(int irq, void *dev_id);
+static irqreturn_t do_hpsa_intr_intx(int irq, void *dev_id);
+static irqreturn_t do_hpsa_intr_msi(int irq, void *dev_id);
 static int hpsa_ioctl(struct scsi_device *dev, int cmd, void *arg);
 static void start_io(struct ctlr_info *h);
 
@@ -130,8 +140,12 @@ static void fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h,
        void *buff, size_t size, u8 page_code, unsigned char *scsi3addr,
        int cmd_type);
 
-static int hpsa_scsi_queue_command(struct scsi_cmnd *cmd,
-               void (*done)(struct scsi_cmnd *));
+static int hpsa_scsi_queue_command(struct Scsi_Host *h, struct scsi_cmnd *cmd);
+static void hpsa_scan_start(struct Scsi_Host *);
+static int hpsa_scan_finished(struct Scsi_Host *sh,
+       unsigned long elapsed_time);
+static int hpsa_change_queue_depth(struct scsi_device *sdev,
+       int qdepth, int reason);
 
 static int hpsa_eh_device_reset_handler(struct scsi_cmnd *scsicmd);
 static int hpsa_slave_alloc(struct scsi_device *sdev);
@@ -143,6 +157,12 @@ static ssize_t lunid_show(struct device *dev,
        struct device_attribute *attr, char *buf);
 static ssize_t unique_id_show(struct device *dev,
        struct device_attribute *attr, char *buf);
+static ssize_t host_show_firmware_revision(struct device *dev,
+            struct device_attribute *attr, char *buf);
+static ssize_t host_show_commands_outstanding(struct device *dev,
+            struct device_attribute *attr, char *buf);
+static ssize_t host_show_transport_mode(struct device *dev,
+       struct device_attribute *attr, char *buf);
 static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno);
 static ssize_t host_store_rescan(struct device *dev,
         struct device_attribute *attr, const char *buf, size_t count);
@@ -153,13 +173,29 @@ static void check_ioctl_unit_attention(struct ctlr_info *h,
 /* performant mode helper functions */
 static void calc_bucket_map(int *bucket, int num_buckets,
        int nsgs, int *bucket_map);
-static void hpsa_put_ctlr_into_performant_mode(struct ctlr_info *h);
+static __devinit void hpsa_put_ctlr_into_performant_mode(struct ctlr_info *h);
 static inline u32 next_command(struct ctlr_info *h);
+static int __devinit hpsa_find_cfg_addrs(struct pci_dev *pdev,
+       void __iomem *vaddr, u32 *cfg_base_addr, u64 *cfg_base_addr_index,
+       u64 *cfg_offset);
+static int __devinit hpsa_pci_find_memory_BAR(struct pci_dev *pdev,
+       unsigned long *memory_bar);
+static int __devinit hpsa_lookup_board_id(struct pci_dev *pdev, u32 *board_id);
+static int __devinit hpsa_wait_for_board_state(struct pci_dev *pdev,
+       void __iomem *vaddr, int wait_for_ready);
+#define BOARD_NOT_READY 0
+#define BOARD_READY 1
 
 static DEVICE_ATTR(raid_level, S_IRUGO, raid_level_show, NULL);
 static DEVICE_ATTR(lunid, S_IRUGO, lunid_show, NULL);
 static DEVICE_ATTR(unique_id, S_IRUGO, unique_id_show, NULL);
 static DEVICE_ATTR(rescan, S_IWUSR, NULL, host_store_rescan);
+static DEVICE_ATTR(firmware_revision, S_IRUGO,
+       host_show_firmware_revision, NULL);
+static DEVICE_ATTR(commands_outstanding, S_IRUGO,
+       host_show_commands_outstanding, NULL);
+static DEVICE_ATTR(transport_mode, S_IRUGO,
+       host_show_transport_mode, NULL);
 
 static struct device_attribute *hpsa_sdev_attrs[] = {
        &dev_attr_raid_level,
@@ -170,6 +206,9 @@ static struct device_attribute *hpsa_sdev_attrs[] = {
 
 static struct device_attribute *hpsa_shost_attrs[] = {
        &dev_attr_rescan,
+       &dev_attr_firmware_revision,
+       &dev_attr_commands_outstanding,
+       &dev_attr_transport_mode,
        NULL,
 };
 
@@ -178,8 +217,10 @@ static struct scsi_host_template hpsa_driver_template = {
        .name                   = "hpsa",
        .proc_name              = "hpsa",
        .queuecommand           = hpsa_scsi_queue_command,
+       .scan_start             = hpsa_scan_start,
+       .scan_finished          = hpsa_scan_finished,
+       .change_queue_depth     = hpsa_change_queue_depth,
        .this_id                = -1,
-       .sg_tablesize           = MAXSGENTRIES,
        .use_clustering         = ENABLE_CLUSTERING,
        .eh_device_reset_handler = hpsa_eh_device_reset_handler,
        .ioctl                  = hpsa_ioctl,
@@ -198,131 +239,10 @@ static inline struct ctlr_info *sdev_to_hba(struct scsi_device *sdev)
        return (struct ctlr_info *) *priv;
 }
 
-static struct task_struct *hpsa_scan_thread;
-static DEFINE_MUTEX(hpsa_scan_mutex);
-static LIST_HEAD(hpsa_scan_q);
-static int hpsa_scan_func(void *data);
-
-/**
- * add_to_scan_list() - add controller to rescan queue
- * @h:               Pointer to the controller.
- *
- * Adds the controller to the rescan queue if not already on the queue.
- *
- * returns 1 if added to the queue, 0 if skipped (could be on the
- * queue already, or the controller could be initializing or shutting
- * down).
- **/
-static int add_to_scan_list(struct ctlr_info *h)
-{
-       struct ctlr_info *test_h;
-       int found = 0;
-       int ret = 0;
-
-       if (h->busy_initializing)
-               return 0;
-
-       /*
-        * If we don't get the lock, it means the driver is unloading
-        * and there's no point in scheduling a new scan.
-        */
-       if (!mutex_trylock(&h->busy_shutting_down))
-               return 0;
-
-       mutex_lock(&hpsa_scan_mutex);
-       list_for_each_entry(test_h, &hpsa_scan_q, scan_list) {
-               if (test_h == h) {
-                       found = 1;
-                       break;
-               }
-       }
-       if (!found && !h->busy_scanning) {
-               INIT_COMPLETION(h->scan_wait);
-               list_add_tail(&h->scan_list, &hpsa_scan_q);
-               ret = 1;
-       }
-       mutex_unlock(&hpsa_scan_mutex);
-       mutex_unlock(&h->busy_shutting_down);
-
-       return ret;
-}
-
-/**
- * remove_from_scan_list() - remove controller from rescan queue
- * @h:                    Pointer to the controller.
- *
- * Removes the controller from the rescan queue if present. Blocks if
- * the controller is currently conducting a rescan.  The controller
- * can be in one of three states:
- * 1. Doesn't need a scan
- * 2. On the scan list, but not scanning yet (we remove it)
- * 3. Busy scanning (and not on the list). In this case we want to wait for
- *    the scan to complete to make sure the scanning thread for this
- *    controller is completely idle.
- **/
-static void remove_from_scan_list(struct ctlr_info *h)
-{
-       struct ctlr_info *test_h, *tmp_h;
-
-       mutex_lock(&hpsa_scan_mutex);
-       list_for_each_entry_safe(test_h, tmp_h, &hpsa_scan_q, scan_list) {
-               if (test_h == h) { /* state 2. */
-                       list_del(&h->scan_list);
-                       complete_all(&h->scan_wait);
-                       mutex_unlock(&hpsa_scan_mutex);
-                       return;
-               }
-       }
-       if (h->busy_scanning) { /* state 3. */
-               mutex_unlock(&hpsa_scan_mutex);
-               wait_for_completion(&h->scan_wait);
-       } else { /* state 1, nothing to do. */
-               mutex_unlock(&hpsa_scan_mutex);
-       }
-}
-
-/* hpsa_scan_func() - kernel thread used to rescan controllers
- * @data:       Ignored.
- *
- * A kernel thread used scan for drive topology changes on
- * controllers. The thread processes only one controller at a time
- * using a queue.  Controllers are added to the queue using
- * add_to_scan_list() and removed from the queue either after done
- * processing or using remove_from_scan_list().
- *
- * returns 0.
- **/
-static int hpsa_scan_func(__attribute__((unused)) void *data)
+static inline struct ctlr_info *shost_to_hba(struct Scsi_Host *sh)
 {
-       struct ctlr_info *h;
-       int host_no;
-
-       while (1) {
-               set_current_state(TASK_INTERRUPTIBLE);
-               schedule();
-               if (kthread_should_stop())
-                       break;
-
-               while (1) {
-                       mutex_lock(&hpsa_scan_mutex);
-                       if (list_empty(&hpsa_scan_q)) {
-                               mutex_unlock(&hpsa_scan_mutex);
-                               break;
-                       }
-                       h = list_entry(hpsa_scan_q.next, struct ctlr_info,
-                                       scan_list);
-                       list_del(&h->scan_list);
-                       h->busy_scanning = 1;
-                       mutex_unlock(&hpsa_scan_mutex);
-                       host_no = h->scsi_host ?  h->scsi_host->host_no : -1;
-                       hpsa_update_scsi_devices(h, host_no);
-                       complete_all(&h->scan_wait);
-                       mutex_lock(&hpsa_scan_mutex);
-                       h->busy_scanning = 0;
-                       mutex_unlock(&hpsa_scan_mutex);
-               }
-       }
-       return 0;
+       unsigned long *priv = shost_priv(sh);
+       return (struct ctlr_info *) *priv;
 }
 
 static int check_for_unit_attention(struct ctlr_info *h,
@@ -342,21 +262,8 @@ static int check_for_unit_attention(struct ctlr_info *h,
                break;
        case REPORT_LUNS_CHANGED:
                dev_warn(&h->pdev->dev, "hpsa%d: report LUN data "
-                       "changed\n", h->ctlr);
+                       "changed, action required\n", h->ctlr);
        /*
-        * Here, we could call add_to_scan_list and wake up the scan thread,
-        * except that it's quite likely that we will get more than one
-        * REPORT_LUNS_CHANGED condition in quick succession, which means
-        * that those which occur after the first one will likely happen
-        * *during* the hpsa_scan_thread's rescan.  And the rescan code is not
-        * robust enough to restart in the middle, undoing what it has already
-        * done, and it's not clear that it's even possible to do this, since
-        * part of what it does is notify the SCSI mid layer, which starts
-        * doing it's own i/o to read partition tables and so on, and the
-        * driver doesn't have visibility to know what might need undoing.
-        * In any event, if possible, it is horribly complicated to get right
-        * so we just don't do it for now.
-        *
         * Note: this REPORT_LUNS_CHANGED condition only occurs on the MSA2012.
         */
                break;
@@ -382,26 +289,58 @@ static ssize_t host_store_rescan(struct device *dev,
 {
        struct ctlr_info *h;
        struct Scsi_Host *shost = class_to_shost(dev);
-       unsigned long *priv = shost_priv(shost);
-       h = (struct ctlr_info *) *priv;
-       if (add_to_scan_list(h)) {
-               wake_up_process(hpsa_scan_thread);
-               wait_for_completion_interruptible(&h->scan_wait);
-       }
+       h = shost_to_hba(shost);
+       hpsa_scan_start(h->scsi_host);
        return count;
 }
 
+static ssize_t host_show_firmware_revision(struct device *dev,
+            struct device_attribute *attr, char *buf)
+{
+       struct ctlr_info *h;
+       struct Scsi_Host *shost = class_to_shost(dev);
+       unsigned char *fwrev;
+
+       h = shost_to_hba(shost);
+       if (!h->hba_inquiry_data)
+               return 0;
+       fwrev = &h->hba_inquiry_data[32];
+       return snprintf(buf, 20, "%c%c%c%c\n",
+               fwrev[0], fwrev[1], fwrev[2], fwrev[3]);
+}
+
+static ssize_t host_show_commands_outstanding(struct device *dev,
+            struct device_attribute *attr, char *buf)
+{
+       struct Scsi_Host *shost = class_to_shost(dev);
+       struct ctlr_info *h = shost_to_hba(shost);
+
+       return snprintf(buf, 20, "%d\n", h->commands_outstanding);
+}
+
+static ssize_t host_show_transport_mode(struct device *dev,
+       struct device_attribute *attr, char *buf)
+{
+       struct ctlr_info *h;
+       struct Scsi_Host *shost = class_to_shost(dev);
+
+       h = shost_to_hba(shost);
+       return snprintf(buf, 20, "%s\n",
+               h->transMethod & CFGTBL_Trans_Performant ?
+                       "performant" : "simple");
+}
+
 /* Enqueuing and dequeuing functions for cmdlists. */
-static inline void addQ(struct hlist_head *list, struct CommandList *c)
+static inline void addQ(struct list_head *list, struct CommandList *c)
 {
-       hlist_add_head(&c->list, list);
+       list_add_tail(&c->list, list);
 }
 
 static inline u32 next_command(struct ctlr_info *h)
 {
        u32 a;
 
-       if (unlikely(h->transMethod != CFGTBL_Trans_Performant))
+       if (unlikely(!(h->transMethod & CFGTBL_Trans_Performant)))
                return h->access.command_completed(h);
 
        if ((*(h->reply_pool_head) & 1) == (h->reply_pool_wraparound)) {
@@ -425,7 +364,7 @@ static inline u32 next_command(struct ctlr_info *h)
  */
 static void set_performant_mode(struct ctlr_info *h, struct CommandList *c)
 {
-       if (likely(h->transMethod == CFGTBL_Trans_Performant))
+       if (likely(h->transMethod & CFGTBL_Trans_Performant))
                c->busaddr |= 1 | (h->blockFetchTable[c->Header.SGList] << 1);
 }
 
@@ -444,9 +383,9 @@ static void enqueue_cmd_and_start_io(struct ctlr_info *h,
 
 static inline void removeQ(struct CommandList *c)
 {
-       if (WARN_ON(hlist_unhashed(&c->list)))
+       if (WARN_ON(list_empty(&c->list)))
                return;
-       hlist_del_init(&c->list);
+       list_del_init(&c->list);
 }
 
 static inline int is_hba_lunid(unsigned char scsi3addr[])
@@ -459,6 +398,15 @@ static inline int is_logical_dev_addr_mode(unsigned char scsi3addr[])
        return (scsi3addr[3] & 0xC0) == 0x40;
 }
 
+static inline int is_scsi_rev_5(struct ctlr_info *h)
+{
+       if (!h->hba_inquiry_data)
+               return 0;
+       if ((h->hba_inquiry_data[2] & 0x07) == 5)
+               return 1;
+       return 0;
+}
+
 static const char *raid_label[] = { "0", "4", "1(1+0)", "5", "5+1", "ADG",
        "UNKNOWN"
 };
@@ -657,6 +605,24 @@ lun_assigned:
        return 0;
 }
 
+/* Replace an entry from h->dev[] array. */
+static void hpsa_scsi_replace_entry(struct ctlr_info *h, int hostno,
+       int entry, struct hpsa_scsi_dev_t *new_entry,
+       struct hpsa_scsi_dev_t *added[], int *nadded,
+       struct hpsa_scsi_dev_t *removed[], int *nremoved)
+{
+       /* assumes h->devlock is held */
+       BUG_ON(entry < 0 || entry >= HPSA_MAX_SCSI_DEVS_PER_HBA);
+       removed[*nremoved] = h->dev[entry];
+       (*nremoved)++;
+       h->dev[entry] = new_entry;
+       added[*nadded] = new_entry;
+       (*nadded)++;
+       dev_info(&h->pdev->dev, "%s device c%db%dt%dl%d changed.\n",
+               scsi_device_type(new_entry->devtype), hostno, new_entry->bus,
+                       new_entry->target, new_entry->lun);
+}
+
 /* Remove an entry from h->dev[] array. */
 static void hpsa_scsi_remove_entry(struct ctlr_info *h, int hostno, int entry,
        struct hpsa_scsi_dev_t *removed[], int *nremoved)
@@ -714,11 +680,6 @@ static void fixup_botched_add(struct ctlr_info *h,
 static inline int device_is_the_same(struct hpsa_scsi_dev_t *dev1,
        struct hpsa_scsi_dev_t *dev2)
 {
-       if ((is_logical_dev_addr_mode(dev1->scsi3addr) ||
-               (dev1->lun != -1 && dev2->lun != -1)) &&
-               dev1->devtype != 0x0C)
-               return (memcmp(dev1, dev2, sizeof(*dev1)) == 0);
-
        /* we compare everything except lun and target as these
         * are not yet assigned.  Compare parts likely
         * to differ first
@@ -733,12 +694,8 @@ static inline int device_is_the_same(struct hpsa_scsi_dev_t *dev1,
                return 0;
        if (memcmp(dev1->vendor, dev2->vendor, sizeof(dev1->vendor)) != 0)
                return 0;
-       if (memcmp(dev1->revision, dev2->revision, sizeof(dev1->revision)) != 0)
-               return 0;
        if (dev1->devtype != dev2->devtype)
                return 0;
-       if (dev1->raid_level != dev2->raid_level)
-               return 0;
        if (dev1->bus != dev2->bus)
                return 0;
        return 1;
@@ -758,6 +715,8 @@ static int hpsa_scsi_find_entry(struct hpsa_scsi_dev_t *needle,
 #define DEVICE_CHANGED 1
 #define DEVICE_SAME 2
        for (i = 0; i < haystack_size; i++) {
+               if (haystack[i] == NULL) /* previously removed. */
+                       continue;
                if (SCSI3ADDR_EQ(needle->scsi3addr, haystack[i]->scsi3addr)) {
                        *index = i;
                        if (device_is_the_same(needle, haystack[i]))
@@ -815,12 +774,12 @@ static void adjust_hpsa_scsi_table(struct ctlr_info *h, int hostno,
                        continue; /* remove ^^^, hence i not incremented */
                } else if (device_change == DEVICE_CHANGED) {
                        changes++;
-                       hpsa_scsi_remove_entry(h, hostno, i,
-                               removed, &nremoved);
-                       (void) hpsa_scsi_add_entry(h, hostno, sd[entry],
-                               added, &nadded);
-                       /* add can't fail, we just removed one. */
-                       sd[entry] = NULL; /* prevent it from being freed */
+                       hpsa_scsi_replace_entry(h, hostno, i, sd[entry],
+                               added, &nadded, removed, &nremoved);
+                       /* Set it to NULL to prevent it from being freed
+                        * at the bottom of hpsa_update_scsi_devices()
+                        */
+                       sd[entry] = NULL;
                }
                i++;
        }
@@ -945,6 +904,76 @@ static void hpsa_scsi_setup(struct ctlr_info *h)
        spin_lock_init(&h->devlock);
 }
 
+static void hpsa_free_sg_chain_blocks(struct ctlr_info *h)
+{
+       int i;
+
+       if (!h->cmd_sg_list)
+               return;
+       for (i = 0; i < h->nr_cmds; i++) {
+               kfree(h->cmd_sg_list[i]);
+               h->cmd_sg_list[i] = NULL;
+       }
+       kfree(h->cmd_sg_list);
+       h->cmd_sg_list = NULL;
+}
+
+static int hpsa_allocate_sg_chain_blocks(struct ctlr_info *h)
+{
+       int i;
+
+       if (h->chainsize <= 0)
+               return 0;
+
+       h->cmd_sg_list = kzalloc(sizeof(*h->cmd_sg_list) * h->nr_cmds,
+                               GFP_KERNEL);
+       if (!h->cmd_sg_list)
+               return -ENOMEM;
+       for (i = 0; i < h->nr_cmds; i++) {
+               h->cmd_sg_list[i] = kmalloc(sizeof(*h->cmd_sg_list[i]) *
+                                               h->chainsize, GFP_KERNEL);
+               if (!h->cmd_sg_list[i])
+                       goto clean;
+       }
+       return 0;
+
+clean:
+       hpsa_free_sg_chain_blocks(h);
+       return -ENOMEM;
+}
+
+static void hpsa_map_sg_chain_block(struct ctlr_info *h,
+       struct CommandList *c)
+{
+       struct SGDescriptor *chain_sg, *chain_block;
+       u64 temp64;
+
+       chain_sg = &c->SG[h->max_cmd_sg_entries - 1];
+       chain_block = h->cmd_sg_list[c->cmdindex];
+       chain_sg->Ext = HPSA_SG_CHAIN;
+       chain_sg->Len = sizeof(*chain_sg) *
+               (c->Header.SGTotal - h->max_cmd_sg_entries);
+       temp64 = pci_map_single(h->pdev, chain_block, chain_sg->Len,
+                               PCI_DMA_TODEVICE);
+       chain_sg->Addr.lower = (u32) (temp64 & 0x0FFFFFFFFULL);
+       chain_sg->Addr.upper = (u32) ((temp64 >> 32) & 0x0FFFFFFFFULL);
+}
+
+static void hpsa_unmap_sg_chain_block(struct ctlr_info *h,
+       struct CommandList *c)
+{
+       struct SGDescriptor *chain_sg;
+       union u64bit temp64;
+
+       if (c->Header.SGTotal <= h->max_cmd_sg_entries)
+               return;
+
+       chain_sg = &c->SG[h->max_cmd_sg_entries - 1];
+       temp64.val32.lower = chain_sg->Addr.lower;
+       temp64.val32.upper = chain_sg->Addr.upper;
+       pci_unmap_single(h->pdev, temp64.val, chain_sg->Len, PCI_DMA_TODEVICE);
+}
+
 static void complete_scsi_command(struct CommandList *cp,
        int timeout, u32 tag)
 {
@@ -961,10 +990,12 @@ static void complete_scsi_command(struct CommandList *cp,
        h = cp->h;
 
        scsi_dma_unmap(cmd); /* undo the DMA mappings */
+       if (cp->Header.SGTotal > h->max_cmd_sg_entries)
+               hpsa_unmap_sg_chain_block(h, cp);
 
        cmd->result = (DID_OK << 16);           /* host byte */
        cmd->result |= (COMMAND_COMPLETE << 8); /* msg byte */
-       cmd->result |= (ei->ScsiStatus << 1);
+       cmd->result |= ei->ScsiStatus;
 
        /* copy the sense data whether we need to or not. */
        memcpy(cmd->sense_buffer, ei->SenseInfo,
@@ -1021,7 +1052,6 @@ static void complete_scsi_command(struct CommandList *cp,
                                 * required
                                 */
                                if ((asc == 0x04) && (ascq == 0x03)) {
-                                       cmd->result = DID_NO_CONNECT << 16;
                                        dev_warn(&h->pdev->dev, "cp %p "
                                                "has check condition: unit "
                                                "not ready, manual "
@@ -1029,14 +1059,22 @@ static void complete_scsi_command(struct CommandList *cp,
                                        break;
                                }
                        }
-
-
+                       if (sense_key == ABORTED_COMMAND) {
+                               /* Aborted command is retryable */
+                               dev_warn(&h->pdev->dev, "cp %p "
+                                       "has check condition: aborted command: "
+                                       "ASC: 0x%x, ASCQ: 0x%x\n",
+                                       cp, asc, ascq);
+                               cmd->result = DID_SOFT_ERROR << 16;
+                               break;
+                       }
                        /* Must be some other type of check condition */
                        dev_warn(&h->pdev->dev, "cp %p has check condition: "
                                        "unknown type: "
                                        "Sense: 0x%x, ASC: 0x%x, ASCQ: 0x%x, "
                                        "Returning result: 0x%x, "
                                        "cmd=[%02x %02x %02x %02x %02x "
+                                       "%02x %02x %02x %02x %02x %02x "
                                        "%02x %02x %02x %02x %02x]\n",
                                        cp, sense_key, asc, ascq,
                                        cmd->result,
@@ -1044,7 +1082,10 @@ static void complete_scsi_command(struct CommandList *cp,
                                        cmd->cmnd[2], cmd->cmnd[3],
                                        cmd->cmnd[4], cmd->cmnd[5],
                                        cmd->cmnd[6], cmd->cmnd[7],
-                                       cmd->cmnd[8], cmd->cmnd[9]);
+                                       cmd->cmnd[8], cmd->cmnd[9],
+                                       cmd->cmnd[10], cmd->cmnd[11],
+                                       cmd->cmnd[12], cmd->cmnd[13],
+                                       cmd->cmnd[14], cmd->cmnd[15]);
                        break;
                }
 
@@ -1120,7 +1161,7 @@ static void complete_scsi_command(struct CommandList *cp,
                dev_warn(&h->pdev->dev, "cp %p reports abort failed\n", cp);
                break;
        case CMD_UNSOLICITED_ABORT:
-               cmd->result = DID_ABORT << 16;
+               cmd->result = DID_RESET << 16;
                dev_warn(&h->pdev->dev, "cp %p aborted do to an unsolicited "
                        "abort\n", cp);
                break;
@@ -1128,6 +1169,10 @@ static void complete_scsi_command(struct CommandList *cp,
                cmd->result = DID_TIME_OUT << 16;
                dev_warn(&h->pdev->dev, "cp %p timedout\n", cp);
                break;
+       case CMD_UNABORTABLE:
+               cmd->result = DID_ERROR << 16;
+               dev_warn(&h->pdev->dev, "Command unabortable\n");
+               break;
        default:
                cmd->result = DID_ERROR << 16;
                dev_warn(&h->pdev->dev, "cp %p returned unknown status %x\n",
@@ -1155,9 +1200,10 @@ static int hpsa_scsi_detect(struct ctlr_info *h)
        sh->max_id = HPSA_MAX_LUN;
        sh->can_queue = h->nr_cmds;
        sh->cmd_per_lun = h->nr_cmds;
+       sh->sg_tablesize = h->maxsgentries;
        h->scsi_host = sh;
        sh->hostdata[0] = (unsigned long) h;
-       sh->irq = h->intr[PERF_MODE_INT];
+       sh->irq = h->intr[h->intr_mode];
        sh->unique_id = sh->irq;
        error = scsi_add_host(sh, &h->pdev->dev);
        if (error)
@@ -1292,6 +1338,9 @@ static void hpsa_scsi_interpret_error(struct CommandList *cp)
        case CMD_TIMEOUT:
                dev_warn(d, "cp %p timed out\n", cp);
                break;
+       case CMD_UNABORTABLE:
+               dev_warn(d, "Command unabortable\n");
+               break;
        default:
                dev_warn(d, "cp %p returned unknown status %x\n", cp,
                                ei->CommandStatus);
@@ -1334,7 +1383,7 @@ static int hpsa_send_reset(struct ctlr_info *h, unsigned char *scsi3addr)
 
        if (c == NULL) {                        /* trouble... */
                dev_warn(&h->pdev->dev, "cmd_special_alloc returned NULL!\n");
-               return -1;
+               return -ENOMEM;
        }
 
        fill_cmd(c, HPSA_DEVICE_RESET_MSG, h, NULL, 0, 0, scsi3addr, TYPE_MSG);
@@ -1459,20 +1508,12 @@ static int hpsa_update_device_info(struct ctlr_info *h,
                goto bail_out;
        }
 
-       /* As a side effect, record the firmware version number
-        * if we happen to be talking to the RAID controller.
-        */
-       if (is_hba_lunid(scsi3addr))
-               memcpy(h->firm_ver, &inq_buff[32], 4);
-
        this_device->devtype = (inq_buff[0] & 0x1f);
        memcpy(this_device->scsi3addr, scsi3addr, 8);
        memcpy(this_device->vendor, &inq_buff[8],
                sizeof(this_device->vendor));
        memcpy(this_device->model, &inq_buff[16],
                sizeof(this_device->model));
-       memcpy(this_device->revision, &inq_buff[32],
-               sizeof(this_device->revision));
        memset(this_device->device_id, 0,
                sizeof(this_device->device_id));
        hpsa_get_device_id(h, scsi3addr, this_device->device_id,
@@ -1526,22 +1567,44 @@ static void figure_bus_target_lun(struct ctlr_info *h,
 
        if (is_logical_dev_addr_mode(lunaddrbytes)) {
                /* logical device */
-               lunid = le32_to_cpu(*((__le32 *) lunaddrbytes));
-               if (is_msa2xxx(h, device)) {
-                       *bus = 1;
-                       *target = (lunid >> 16) & 0x3fff;
-                       *lun = lunid & 0x00ff;
-               } else {
+               if (unlikely(is_scsi_rev_5(h))) {
+                       /* p1210m, logical drives lun assignments
+                        * match SCSI REPORT LUNS data.
+                        */
+                       lunid = le32_to_cpu(*((__le32 *) lunaddrbytes));
                        *bus = 0;
-                       *lun = 0;
-                       *target = lunid & 0x3fff;
+                       *target = 0;
+                       *lun = (lunid & 0x3fff) + 1;
+               } else {
+                       /* not p1210m... */
+                       lunid = le32_to_cpu(*((__le32 *) lunaddrbytes));
+                       if (is_msa2xxx(h, device)) {
+                               /* msa2xxx way, put logicals on bus 1
+                                * and match target/lun numbers box
+                                * reports.
+                                */
+                               *bus = 1;
+                               *target = (lunid >> 16) & 0x3fff;
+                               *lun = lunid & 0x00ff;
+                       } else {
+                               /* Traditional smart array way. */
+                               *bus = 0;
+                               *lun = 0;
+                               *target = lunid & 0x3fff;
+                       }
                }
        } else {
                /* physical device */
                if (is_hba_lunid(lunaddrbytes))
-                       *bus = 3;
+                       if (unlikely(is_scsi_rev_5(h))) {
+                               *bus = 0; /* put p1210m ctlr at 0,0,0 */
+                               *target = 0;
+                               *lun = 0;
+                               return;
+                       } else
+                               *bus = 3; /* traditional smartarray */
                else
-                       *bus = 2;
+                       *bus = 2; /* physical disk */
                *target = -1;
                *lun = -1; /* we will fill these in later. */
        }
@@ -1578,9 +1641,14 @@ static int add_msa2xxx_enclosure_device(struct ctlr_info *h,
        if (lun == 0) /* if lun is 0, then obviously we have a lun 0. */
                return 0;
 
+       memset(scsi3addr, 0, 8);
+       scsi3addr[3] = target;
        if (is_hba_lunid(scsi3addr))
                return 0; /* Don't add the RAID controller here. */
 
+       if (is_scsi_rev_5(h))
+               return 0; /* p1210m doesn't need to do this. */
+
 #define MAX_MSA2XXX_ENCLOSURES 32
        if (*nmsa2xxx_enclosures >= MAX_MSA2XXX_ENCLOSURES) {
                dev_warn(&h->pdev->dev, "Maximum number of MSA2XXX "
@@ -1589,8 +1657,6 @@ static int add_msa2xxx_enclosure_device(struct ctlr_info *h,
                return 0;
        }
 
-       memset(scsi3addr, 0, 8);
-       scsi3addr[3] = target;
        if (hpsa_update_device_info(h, scsi3addr, this_device))
                return 0;
        (*nmsa2xxx_enclosures)++;
@@ -1644,6 +1710,31 @@ static int hpsa_gather_lun_info(struct ctlr_info *h,
        return 0;
 }
 
+u8 *figure_lunaddrbytes(struct ctlr_info *h, int raid_ctlr_position, int i,
+       int nphysicals, int nlogicals, struct ReportLUNdata *physdev_list,
+       struct ReportLUNdata *logdev_list)
+{
+       /* Helper function, figure out where the LUN ID info is coming from
+        * given index i, lists of physical and logical devices, where in
+        * the list the raid controller is supposed to appear (first or last)
+        */
+
+       int logicals_start = nphysicals + (raid_ctlr_position == 0);
+       int last_device = nphysicals + nlogicals + (raid_ctlr_position == 0);
+
+       if (i == raid_ctlr_position)
+               return RAID_CTLR_LUNID;
+
+       if (i < logicals_start)
+               return &physdev_list->LUN[i - (raid_ctlr_position == 0)][0];
+
+       if (i < last_device)
+               return &logdev_list->LUN[i - nphysicals -
+                       (raid_ctlr_position == 0)][0];
+       BUG();
+       return NULL;
+}
+
 static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno)
 {
        /* the idea here is we could get notified
@@ -1667,6 +1758,7 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno)
        int reportlunsize = sizeof(*physdev_list) + HPSA_MAX_PHYS_LUN * 8;
        int i, nmsa2xxx_enclosures, ndevs_to_allocate;
        int bus, target, lun;
+       int raid_ctlr_position;
        DECLARE_BITMAP(lunzerobits, HPSA_MAX_TARGETS_PER_CTLR);
 
        currentsd = kzalloc(sizeof(*currentsd) * HPSA_MAX_SCSI_DEVS_PER_HBA,
@@ -1704,23 +1796,22 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno)
                ndev_allocated++;
        }
 
+       if (unlikely(is_scsi_rev_5(h)))
+               raid_ctlr_position = 0;
+       else
+               raid_ctlr_position = nphysicals + nlogicals;
+
        /* adjust our table of devices */
        nmsa2xxx_enclosures = 0;
        for (i = 0; i < nphysicals + nlogicals + 1; i++) {
                u8 *lunaddrbytes;
 
                /* Figure out where the LUN ID info is coming from */
-               if (i < nphysicals)
-                       lunaddrbytes = &physdev_list->LUN[i][0];
-               else
-                       if (i < nphysicals + nlogicals)
-                               lunaddrbytes =
-                                       &logdev_list->LUN[i-nphysicals][0];
-                       else /* jam in the RAID controller at the end */
-                               lunaddrbytes = RAID_CTLR_LUNID;
-
+               lunaddrbytes = figure_lunaddrbytes(h, raid_ctlr_position,
+                       i, nphysicals, nlogicals, physdev_list, logdev_list);
                /* skip masked physical devices. */
-               if (lunaddrbytes[3] & 0xC0 && i < nphysicals)
+               if (lunaddrbytes[3] & 0xC0 &&
+                       i < nphysicals + (raid_ctlr_position == 0))
                        continue;
 
                /* Get device type, vendor, model, device id */
@@ -1806,16 +1897,17 @@ out:
  * dma mapping  and fills in the scatter gather entries of the
  * hpsa command, cp.
  */
-static int hpsa_scatter_gather(struct pci_dev *pdev,
+static int hpsa_scatter_gather(struct ctlr_info *h,
                struct CommandList *cp,
                struct scsi_cmnd *cmd)
 {
        unsigned int len;
        struct scatterlist *sg;
        u64 addr64;
-       int use_sg, i;
+       int use_sg, i, sg_index, chained;
+       struct SGDescriptor *curr_sg;
 
-       BUG_ON(scsi_sg_count(cmd) > MAXSGENTRIES);
+       BUG_ON(scsi_sg_count(cmd) > h->maxsgentries);
 
        use_sg = scsi_dma_map(cmd);
        if (use_sg < 0)
@@ -1824,15 +1916,33 @@ static int hpsa_scatter_gather(struct pci_dev *pdev,
        if (!use_sg)
                goto sglist_finished;
 
+       curr_sg = cp->SG;
+       chained = 0;
+       sg_index = 0;
        scsi_for_each_sg(cmd, sg, use_sg, i) {
+               if (i == h->max_cmd_sg_entries - 1 &&
+                       use_sg > h->max_cmd_sg_entries) {
+                       chained = 1;
+                       curr_sg = h->cmd_sg_list[cp->cmdindex];
+                       sg_index = 0;
+               }
                addr64 = (u64) sg_dma_address(sg);
                len  = sg_dma_len(sg);
-               cp->SG[i].Addr.lower =
-                       (u32) (addr64 & (u64) 0x00000000FFFFFFFF);
-               cp->SG[i].Addr.upper =
-                       (u32) ((addr64 >> 32) & (u64) 0x00000000FFFFFFFF);
-               cp->SG[i].Len = len;
-               cp->SG[i].Ext = 0;  /* we are not chaining */
+               curr_sg->Addr.lower = (u32) (addr64 & 0x0FFFFFFFFULL);
+               curr_sg->Addr.upper = (u32) ((addr64 >> 32) & 0x0FFFFFFFFULL);
+               curr_sg->Len = len;
+               curr_sg->Ext = 0;  /* we are not chaining */
+               curr_sg++;
+       }
+
+       if (use_sg + chained > h->maxSG)
+               h->maxSG = use_sg + chained;
+
+       if (chained) {
+               cp->Header.SGList = h->max_cmd_sg_entries;
+               cp->Header.SGTotal = (u16) (use_sg + 1);
+               hpsa_map_sg_chain_block(h, cp);
+               return 0;
        }
 
 sglist_finished:
@@ -1843,7 +1953,7 @@ sglist_finished:
 }
 
 
-static int hpsa_scsi_queue_command(struct scsi_cmnd *cmd,
+static int hpsa_scsi_queue_command_lck(struct scsi_cmnd *cmd,
        void (*done)(struct scsi_cmnd *))
 {
        struct ctlr_info *h;
@@ -1928,7 +2038,7 @@ static int hpsa_scsi_queue_command(struct scsi_cmnd *cmd,
                break;
        }
 
-       if (hpsa_scatter_gather(h->pdev, c, cmd) < 0) { /* Fill SG list */
+       if (hpsa_scatter_gather(h, c, cmd) < 0) { /* Fill SG list */
                cmd_free(h, c);
                return SCSI_MLQUEUE_HOST_BUSY;
        }
@@ -1937,6 +2047,67 @@ static int hpsa_scsi_queue_command(struct scsi_cmnd *cmd,
        return 0;
 }
 
+static DEF_SCSI_QCMD(hpsa_scsi_queue_command)
+
+static void hpsa_scan_start(struct Scsi_Host *sh)
+{
+       struct ctlr_info *h = shost_to_hba(sh);
+       unsigned long flags;
+
+       /* wait until any scan already in progress is finished. */
+       while (1) {
+               spin_lock_irqsave(&h->scan_lock, flags);
+               if (h->scan_finished)
+                       break;
+               spin_unlock_irqrestore(&h->scan_lock, flags);
+               wait_event(h->scan_wait_queue, h->scan_finished);
+               /* Note: We don't need to worry about a race between this
+                * thread and driver unload because the midlayer will
+                * have incremented the reference count, so unload won't
+                * happen if we're in here.
+                */
+       }
+       h->scan_finished = 0; /* mark scan as in progress */
+       spin_unlock_irqrestore(&h->scan_lock, flags);
+
+       hpsa_update_scsi_devices(h, h->scsi_host->host_no);
+
+       spin_lock_irqsave(&h->scan_lock, flags);
+       h->scan_finished = 1; /* mark scan as finished. */
+       wake_up_all(&h->scan_wait_queue);
+       spin_unlock_irqrestore(&h->scan_lock, flags);
+}
+
+static int hpsa_scan_finished(struct Scsi_Host *sh,
+       unsigned long elapsed_time)
+{
+       struct ctlr_info *h = shost_to_hba(sh);
+       unsigned long flags;
+       int finished;
+
+       spin_lock_irqsave(&h->scan_lock, flags);
+       finished = h->scan_finished;
+       spin_unlock_irqrestore(&h->scan_lock, flags);
+       return finished;
+}
+
+static int hpsa_change_queue_depth(struct scsi_device *sdev,
+       int qdepth, int reason)
+{
+       struct ctlr_info *h = sdev_to_hba(sdev);
+
+       if (reason != SCSI_QDEPTH_DEFAULT)
+               return -ENOTSUPP;
+
+       if (qdepth < 1)
+               qdepth = 1;
+       else
+               if (qdepth > h->nr_cmds)
+                       qdepth = h->nr_cmds;
+       scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), qdepth);
+       return sdev->queue_depth;
+}
+
 static void hpsa_unregister_scsi(struct ctlr_info *h)
 {
        /* we are being forcibly unloaded, and may not refuse. */
@@ -1949,7 +2120,6 @@ static int hpsa_register_scsi(struct ctlr_info *h)
 {
        int rc;
 
-       hpsa_update_scsi_devices(h, -1);
        rc = hpsa_scsi_detect(h);
        if (rc != 0)
                dev_err(&h->pdev->dev, "hpsa_register_scsi: failed"
@@ -2026,14 +2196,14 @@ static int hpsa_eh_device_reset_handler(struct scsi_cmnd *scsicmd)
        h = sdev_to_hba(scsicmd->device);
        if (h == NULL) /* paranoia */
                return FAILED;
-       dev_warn(&h->pdev->dev, "resetting drive\n");
-
        dev = scsicmd->device->hostdata;
        if (!dev) {
                dev_err(&h->pdev->dev, "hpsa_eh_device_reset_handler: "
                        "device lookup failed.\n");
                return FAILED;
        }
+       dev_warn(&h->pdev->dev, "resetting device %d:%d:%d:%d\n",
+               h->scsi_host->host_no, dev->bus, dev->target, dev->lun);
        /* send a reset to the SCSI LUN which the command was sent to */
        rc = hpsa_send_reset(h, dev->scsi3addr);
        if (rc == 0 && wait_for_device_to_become_ready(h, dev->scsi3addr) == 0)
@@ -2075,7 +2245,7 @@ static struct CommandList *cmd_alloc(struct ctlr_info *h)
 
        c->cmdindex = i;
 
-       INIT_HLIST_NODE(&c->list);
+       INIT_LIST_HEAD(&c->list);
        c->busaddr = (u32) cmd_dma_handle;
        temp64.val = (u64) err_dma_handle;
        c->ErrDesc.Addr.lower = temp64.val32.lower;
@@ -2113,7 +2283,7 @@ static struct CommandList *cmd_special_alloc(struct ctlr_info *h)
        }
        memset(c->err_info, 0, sizeof(*c->err_info));
 
-       INIT_HLIST_NODE(&c->list);
+       INIT_LIST_HEAD(&c->list);
        c->busaddr = (u32) cmd_dma_handle;
        temp64.val = (u64) err_dma_handle;
        c->ErrDesc.Addr.lower = temp64.val32.lower;
@@ -2143,55 +2313,11 @@ static void cmd_special_free(struct ctlr_info *h, struct CommandList *c)
        pci_free_consistent(h->pdev, sizeof(*c->err_info),
                            c->err_info, (dma_addr_t) temp64.val);
        pci_free_consistent(h->pdev, sizeof(*c),
-                           c, (dma_addr_t) c->busaddr);
+                           c, (dma_addr_t) (c->busaddr & DIRECT_LOOKUP_MASK));
 }
 
 #ifdef CONFIG_COMPAT
 
-static int do_ioctl(struct scsi_device *dev, int cmd, void *arg)
-{
-       int ret;
-
-       lock_kernel();
-       ret = hpsa_ioctl(dev, cmd, arg);
-       unlock_kernel();
-       return ret;
-}
-
-static int hpsa_ioctl32_passthru(struct scsi_device *dev, int cmd, void *arg);
-static int hpsa_ioctl32_big_passthru(struct scsi_device *dev,
-       int cmd, void *arg);
-
-static int hpsa_compat_ioctl(struct scsi_device *dev, int cmd, void *arg)
-{
-       switch (cmd) {
-       case CCISS_GETPCIINFO:
-       case CCISS_GETINTINFO:
-       case CCISS_SETINTINFO:
-       case CCISS_GETNODENAME:
-       case CCISS_SETNODENAME:
-       case CCISS_GETHEARTBEAT:
-       case CCISS_GETBUSTYPES:
-       case CCISS_GETFIRMVER:
-       case CCISS_GETDRIVVER:
-       case CCISS_REVALIDVOLS:
-       case CCISS_DEREGDISK:
-       case CCISS_REGNEWDISK:
-       case CCISS_REGNEWD:
-       case CCISS_RESCANDISK:
-       case CCISS_GETLUNINFO:
-               return do_ioctl(dev, cmd, arg);
-
-       case CCISS_PASSTHRU32:
-               return hpsa_ioctl32_passthru(dev, cmd, arg);
-       case CCISS_BIG_PASSTHRU32:
-               return hpsa_ioctl32_big_passthru(dev, cmd, arg);
-
-       default:
-               return -ENOIOCTLCMD;
-       }
-}
-
 static int hpsa_ioctl32_passthru(struct scsi_device *dev, int cmd, void *arg)
 {
        IOCTL32_Command_struct __user *arg32 =
@@ -2201,6 +2327,7 @@ static int hpsa_ioctl32_passthru(struct scsi_device *dev, int cmd, void *arg)
        int err;
        u32 cp;
 
+       memset(&arg64, 0, sizeof(arg64));
        err = 0;
        err |= copy_from_user(&arg64.LUN_info, &arg32->LUN_info,
                           sizeof(arg64.LUN_info));
@@ -2216,7 +2343,7 @@ static int hpsa_ioctl32_passthru(struct scsi_device *dev, int cmd, void *arg)
        if (err)
                return -EFAULT;
 
-       err = do_ioctl(dev, CCISS_PASSTHRU, (void *)p);
+       err = hpsa_ioctl(dev, CCISS_PASSTHRU, (void *)p);
        if (err)
                return err;
        err |= copy_in_user(&arg32->error_info, &p->error_info,
@@ -2237,6 +2364,7 @@ static int hpsa_ioctl32_big_passthru(struct scsi_device *dev,
        int err;
        u32 cp;
 
+       memset(&arg64, 0, sizeof(arg64));
        err = 0;
        err |= copy_from_user(&arg64.LUN_info, &arg32->LUN_info,
                           sizeof(arg64.LUN_info));
@@ -2253,7 +2381,7 @@ static int hpsa_ioctl32_big_passthru(struct scsi_device *dev,
        if (err)
                return -EFAULT;
 
-       err = do_ioctl(dev, CCISS_BIG_PASSTHRU, (void *)p);
+       err = hpsa_ioctl(dev, CCISS_BIG_PASSTHRU, (void *)p);
        if (err)
                return err;
        err |= copy_in_user(&arg32->error_info, &p->error_info,
@@ -2262,6 +2390,36 @@ static int hpsa_ioctl32_big_passthru(struct scsi_device *dev,
                return -EFAULT;
        return err;
 }
+
+static int hpsa_compat_ioctl(struct scsi_device *dev, int cmd, void *arg)
+{
+       switch (cmd) {
+       case CCISS_GETPCIINFO:
+       case CCISS_GETINTINFO:
+       case CCISS_SETINTINFO:
+       case CCISS_GETNODENAME:
+       case CCISS_SETNODENAME:
+       case CCISS_GETHEARTBEAT:
+       case CCISS_GETBUSTYPES:
+       case CCISS_GETFIRMVER:
+       case CCISS_GETDRIVVER:
+       case CCISS_REVALIDVOLS:
+       case CCISS_DEREGDISK:
+       case CCISS_REGNEWDISK:
+       case CCISS_REGNEWD:
+       case CCISS_RESCANDISK:
+       case CCISS_GETLUNINFO:
+               return hpsa_ioctl(dev, cmd, arg);
+
+       case CCISS_PASSTHRU32:
+               return hpsa_ioctl32_passthru(dev, cmd, arg);
+       case CCISS_BIG_PASSTHRU32:
+               return hpsa_ioctl32_big_passthru(dev, cmd, arg);
+
+       default:
+               return -ENOIOCTLCMD;
+       }
+}
 #endif
 
 static int hpsa_getpciinfo_ioctl(struct ctlr_info *h, void __user *argp)
@@ -2323,15 +2481,17 @@ static int hpsa_passthru_ioctl(struct ctlr_info *h, void __user *argp)
                buff = kmalloc(iocommand.buf_size, GFP_KERNEL);
                if (buff == NULL)
                        return -EFAULT;
-       }
-       if (iocommand.Request.Type.Direction == XFER_WRITE) {
-               /* Copy the data into the buffer we created */
-               if (copy_from_user(buff, iocommand.buf, iocommand.buf_size)) {
-                       kfree(buff);
-                       return -EFAULT;
+               if (iocommand.Request.Type.Direction == XFER_WRITE) {
+                       /* Copy the data into the buffer we created */
+                       if (copy_from_user(buff, iocommand.buf,
+                               iocommand.buf_size)) {
+                               kfree(buff);
+                               return -EFAULT;
+                       }
+               } else {
+                       memset(buff, 0, iocommand.buf_size);
                }
-       } else
-               memset(buff, 0, iocommand.buf_size);
+       }
        c = cmd_special_alloc(h);
        if (c == NULL) {
                kfree(buff);
@@ -2377,8 +2537,8 @@ static int hpsa_passthru_ioctl(struct ctlr_info *h, void __user *argp)
                cmd_special_free(h, c);
                return -EFAULT;
        }
-
-       if (iocommand.Request.Type.Direction == XFER_READ) {
+       if (iocommand.Request.Type.Direction == XFER_READ &&
+               iocommand.buf_size > 0) {
                /* Copy the data out of the buffer we created */
                if (copy_to_user(iocommand.buf, buff, iocommand.buf_size)) {
                        kfree(buff);
@@ -2471,14 +2631,7 @@ static int hpsa_big_passthru_ioctl(struct ctlr_info *h, void __user *argp)
        }
        c->cmd_type = CMD_IOCTL_PEND;
        c->Header.ReplyQueue = 0;
-
-       if (ioc->buf_size > 0) {
-               c->Header.SGList = sg_used;
-               c->Header.SGTotal = sg_used;
-       } else {
-               c->Header.SGList = 0;
-               c->Header.SGTotal = 0;
-       }
+       c->Header.SGList = c->Header.SGTotal = sg_used;
        memcpy(&c->Header.LUN, &ioc->LUN_info, sizeof(c->Header.LUN));
        c->Header.Tag.lower = c->busaddr;
        memcpy(&c->Request, &ioc->Request, sizeof(c->Request));
@@ -2495,7 +2648,8 @@ static int hpsa_big_passthru_ioctl(struct ctlr_info *h, void __user *argp)
                }
        }
        hpsa_scsi_do_simple_cmd_core(h, c);
-       hpsa_pci_unmap(h->pdev, c, sg_used, PCI_DMA_BIDIRECTIONAL);
+       if (sg_used)
+               hpsa_pci_unmap(h->pdev, c, sg_used, PCI_DMA_BIDIRECTIONAL);
        check_ioctl_unit_attention(h, c);
        /* Copy the error information out */
        memcpy(&ioc->error_info, c->err_info, sizeof(ioc->error_info));
@@ -2504,7 +2658,7 @@ static int hpsa_big_passthru_ioctl(struct ctlr_info *h, void __user *argp)
                status = -EFAULT;
                goto cleanup1;
        }
-       if (ioc->Request.Type.Direction == XFER_READ) {
+       if (ioc->Request.Type.Direction == XFER_READ && ioc->buf_size > 0) {
                /* Copy the data out of the buffer we created */
                BYTE __user *ptr = ioc->buf;
                for (i = 0; i < sg_used; i++) {
@@ -2550,7 +2704,7 @@ static int hpsa_ioctl(struct scsi_device *dev, int cmd, void *arg)
        case CCISS_DEREGDISK:
        case CCISS_REGNEWDISK:
        case CCISS_REGNEWD:
-               hpsa_update_scsi_devices(h, dev->host->host_no);
+               hpsa_scan_start(h->scsi_host);
                return 0;
        case CCISS_GETPCIINFO:
                return hpsa_getpciinfo_ioctl(h, argp);
@@ -2614,14 +2768,6 @@ static void fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h,
                        c->Request.CDB[8] = (size >> 8) & 0xFF;
                        c->Request.CDB[9] = size & 0xFF;
                        break;
-
-               case HPSA_READ_CAPACITY:
-                       c->Request.CDBLen = 10;
-                       c->Request.Type.Attribute = ATTR_SIMPLE;
-                       c->Request.Type.Direction = XFER_READ;
-                       c->Request.Timeout = 0;
-                       c->Request.CDB[0] = cmd;
-                       break;
                case HPSA_CACHE_FLUSH:
                        c->Request.CDBLen = 12;
                        c->Request.Type.Attribute = ATTR_SIMPLE;
@@ -2708,8 +2854,8 @@ static void start_io(struct ctlr_info *h)
 {
        struct CommandList *c;
 
-       while (!hlist_empty(&h->reqQ)) {
-               c = hlist_entry(h->reqQ.first, struct CommandList, list);
+       while (!list_empty(&h->reqQ)) {
+               c = list_entry(h->reqQ.next, struct CommandList, list);
                /* can't do anything if fifo is full */
                if ((h->access.fifo_full(h))) {
                        dev_warn(&h->pdev->dev, "fifo full\n");
@@ -2740,9 +2886,8 @@ static inline bool interrupt_pending(struct ctlr_info *h)
 
 static inline long interrupt_not_for_us(struct ctlr_info *h)
 {
-       return !(h->msi_vector || h->msix_vector) &&
-               ((h->access.intr_pending(h) == 0) ||
-               (h->interrupts_enabled == 0));
+       return (h->access.intr_pending(h) == 0) ||
+               (h->interrupts_enabled == 0);
 }
 
 static inline int bad_tag(struct ctlr_info *h, u32 tag_index,
@@ -2766,20 +2911,22 @@ static inline void finish_cmd(struct CommandList *c, u32 raw_tag)
 
 static inline u32 hpsa_tag_contains_index(u32 tag)
 {
-#define DIRECT_LOOKUP_BIT 0x10
        return tag & DIRECT_LOOKUP_BIT;
 }
 
 static inline u32 hpsa_tag_to_index(u32 tag)
 {
-#define DIRECT_LOOKUP_SHIFT 5
        return tag >> DIRECT_LOOKUP_SHIFT;
 }
 
-static inline u32 hpsa_tag_discard_error_bits(u32 tag)
+
+static inline u32 hpsa_tag_discard_error_bits(struct ctlr_info *h, u32 tag)
 {
-#define HPSA_ERROR_BITS 0x03
-       return tag & ~HPSA_ERROR_BITS;
+#define HPSA_PERF_ERROR_BITS ((1 << DIRECT_LOOKUP_SHIFT) - 1)
+#define HPSA_SIMPLE_ERROR_BITS 0x03
+       if (unlikely(!(h->transMethod & CFGTBL_Trans_Performant)))
+               return tag & ~HPSA_SIMPLE_ERROR_BITS;
+       return tag & ~HPSA_PERF_ERROR_BITS;
 }
 
 /* process completion of an indexed ("direct lookup") command */
@@ -2803,10 +2950,9 @@ static inline u32 process_nonindexed_cmd(struct ctlr_info *h,
 {
        u32 tag;
        struct CommandList *c = NULL;
-       struct hlist_node *tmp;
 
-       tag = hpsa_tag_discard_error_bits(raw_tag);
-       hlist_for_each_entry(c, tmp, &h->cmpQ, list) {
+       tag = hpsa_tag_discard_error_bits(h, raw_tag);
+       list_for_each_entry(c, &h->cmpQ, list) {
                if ((c->busaddr & 0xFFFFFFE0) == (tag & 0xFFFFFFE0)) {
                        finish_cmd(c, raw_tag);
                        return next_command(h);
@@ -2816,7 +2962,7 @@ static inline u32 process_nonindexed_cmd(struct ctlr_info *h,
        return next_command(h);
 }
 
-static irqreturn_t do_hpsa_intr(int irq, void *dev_id)
+static irqreturn_t do_hpsa_intr_intx(int irq, void *dev_id)
 {
        struct ctlr_info *h = dev_id;
        unsigned long flags;
@@ -2825,6 +2971,26 @@ static irqreturn_t do_hpsa_intr(int irq, void *dev_id)
        if (interrupt_not_for_us(h))
                return IRQ_NONE;
        spin_lock_irqsave(&h->lock, flags);
+       while (interrupt_pending(h)) {
+               raw_tag = get_next_completion(h);
+               while (raw_tag != FIFO_EMPTY) {
+                       if (hpsa_tag_contains_index(raw_tag))
+                               raw_tag = process_indexed_cmd(h, raw_tag);
+                       else
+                               raw_tag = process_nonindexed_cmd(h, raw_tag);
+               }
+       }
+       spin_unlock_irqrestore(&h->lock, flags);
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t do_hpsa_intr_msi(int irq, void *dev_id)
+{
+       struct ctlr_info *h = dev_id;
+       unsigned long flags;
+       u32 raw_tag;
+
+       spin_lock_irqsave(&h->lock, flags);
        raw_tag = get_next_completion(h);
        while (raw_tag != FIFO_EMPTY) {
                if (hpsa_tag_contains_index(raw_tag))
@@ -2836,7 +3002,10 @@ static irqreturn_t do_hpsa_intr(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-/* Send a message CDB to the firmwart. */
+/* Send a message CDB to the firmware. Careful, this only works
+ * in simple mode, not performant mode due to the tag lookup.
+ * We only ever use this immediately after a controller reset.
+ */
 static __devinit int hpsa_message(struct pci_dev *pdev, unsigned char opcode,
                                                unsigned char type)
 {
@@ -2902,7 +3071,7 @@ static __devinit int hpsa_message(struct pci_dev *pdev, unsigned char opcode,
 
        for (i = 0; i < HPSA_MSG_SEND_RETRY_LIMIT; i++) {
                tag = readl(vaddr + SA5_REPLY_PORT_OFFSET);
-               if (hpsa_tag_discard_error_bits(tag) == paddr32)
+               if ((tag & ~HPSA_SIMPLE_ERROR_BITS) == paddr32)
                        break;
                msleep(HPSA_MSG_SEND_RETRY_INTERVAL_MSECS);
        }
@@ -2934,114 +3103,182 @@ static __devinit int hpsa_message(struct pci_dev *pdev, unsigned char opcode,
 #define hpsa_soft_reset_controller(p) hpsa_message(p, 1, 0)
 #define hpsa_noop(p) hpsa_message(p, 3, 0)
 
-static __devinit int hpsa_reset_msi(struct pci_dev *pdev)
+static int hpsa_controller_hard_reset(struct pci_dev *pdev,
+       void * __iomem vaddr, bool use_doorbell)
 {
-/* the #defines are stolen from drivers/pci/msi.h. */
-#define msi_control_reg(base)          (base + PCI_MSI_FLAGS)
-#define PCI_MSIX_FLAGS_ENABLE          (1 << 15)
-
+       u16 pmcsr;
        int pos;
-       u16 control = 0;
-
-       pos = pci_find_capability(pdev, PCI_CAP_ID_MSI);
-       if (pos) {
-               pci_read_config_word(pdev, msi_control_reg(pos), &control);
-               if (control & PCI_MSI_FLAGS_ENABLE) {
-                       dev_info(&pdev->dev, "resetting MSI\n");
-                       pci_write_config_word(pdev, msi_control_reg(pos),
-                                       control & ~PCI_MSI_FLAGS_ENABLE);
-               }
-       }
 
-       pos = pci_find_capability(pdev, PCI_CAP_ID_MSIX);
-       if (pos) {
-               pci_read_config_word(pdev, msi_control_reg(pos), &control);
-               if (control & PCI_MSIX_FLAGS_ENABLE) {
-                       dev_info(&pdev->dev, "resetting MSI-X\n");
-                       pci_write_config_word(pdev, msi_control_reg(pos),
-                                       control & ~PCI_MSIX_FLAGS_ENABLE);
+       if (use_doorbell) {
+               /* For everything after the P600, the PCI power state method
+                * of resetting the controller doesn't work, so we have this
+                * other way using the doorbell register.
+                */
+               dev_info(&pdev->dev, "using doorbell to reset controller\n");
+               writel(DOORBELL_CTLR_RESET, vaddr + SA5_DOORBELL);
+               msleep(1000);
+       } else { /* Try to do it the PCI power state way */
+
+               /* Quoting from the Open CISS Specification: "The Power
+                * Management Control/Status Register (CSR) controls the power
+                * state of the device.  The normal operating state is D0,
+                * CSR=00h.  The software off state is D3, CSR=03h.  To reset
+                * the controller, place the interface device in D3 then to D0,
+                * this causes a secondary PCI reset which will reset the
+                * controller." */
+
+               pos = pci_find_capability(pdev, PCI_CAP_ID_PM);
+               if (pos == 0) {
+                       dev_err(&pdev->dev,
+                               "hpsa_reset_controller: "
+                               "PCI PM not supported\n");
+                       return -ENODEV;
                }
-       }
+               dev_info(&pdev->dev, "using PCI PM to reset controller\n");
+               /* enter the D3hot power management state */
+               pci_read_config_word(pdev, pos + PCI_PM_CTRL, &pmcsr);
+               pmcsr &= ~PCI_PM_CTRL_STATE_MASK;
+               pmcsr |= PCI_D3hot;
+               pci_write_config_word(pdev, pos + PCI_PM_CTRL, pmcsr);
+
+               msleep(500);
 
+               /* enter the D0 power management state */
+               pmcsr &= ~PCI_PM_CTRL_STATE_MASK;
+               pmcsr |= PCI_D0;
+               pci_write_config_word(pdev, pos + PCI_PM_CTRL, pmcsr);
+
+               msleep(500);
+       }
        return 0;
 }
 
 /* This does a hard reset of the controller using PCI power management
- * states.
+ * states or the using the doorbell register.
  */
-static __devinit int hpsa_hard_reset_controller(struct pci_dev *pdev)
+static __devinit int hpsa_kdump_hard_reset_controller(struct pci_dev *pdev)
 {
-       u16 pmcsr, saved_config_space[32];
-       int i, pos;
-
-       dev_info(&pdev->dev, "using PCI PM to reset controller\n");
+       u64 cfg_offset;
+       u32 cfg_base_addr;
+       u64 cfg_base_addr_index;
+       void __iomem *vaddr;
+       unsigned long paddr;
+       u32 misc_fw_support, active_transport;
+       int rc;
+       struct CfgTable __iomem *cfgtable;
+       bool use_doorbell;
+       u32 board_id;
+       u16 command_register;
 
-       /* This is very nearly the same thing as
+       /* For controllers as old as the P600, this is very nearly
+        * the same thing as
         *
         * pci_save_state(pci_dev);
         * pci_set_power_state(pci_dev, PCI_D3hot);
         * pci_set_power_state(pci_dev, PCI_D0);
         * pci_restore_state(pci_dev);
         *
-        * but we can't use these nice canned kernel routines on
-        * kexec, because they also check the MSI/MSI-X state in PCI
-        * configuration space and do the wrong thing when it is
-        * set/cleared.  Also, the pci_save/restore_state functions
-        * violate the ordering requirements for restoring the
-        * configuration space from the CCISS document (see the
-        * comment below).  So we roll our own ....
+        * For controllers newer than the P600, the pci power state
+        * method of resetting doesn't work so we have another way
+        * using the doorbell register.
         */
 
-       for (i = 0; i < 32; i++)
-               pci_read_config_word(pdev, 2*i, &saved_config_space[i]);
-
-       pos = pci_find_capability(pdev, PCI_CAP_ID_PM);
-       if (pos == 0) {
-               dev_err(&pdev->dev,
-                       "hpsa_reset_controller: PCI PM not supported\n");
+       /* Exclude 640x boards.  These are two pci devices in one slot
+        * which share a battery backed cache module.  One controls the
+        * cache, the other accesses the cache through the one that controls
+        * it.  If we reset the one controlling the cache, the other will
+        * likely not be happy.  Just forbid resetting this conjoined mess.
+        * The 640x isn't really supported by hpsa anyway.
+        */
+       rc = hpsa_lookup_board_id(pdev, &board_id);
+       if (rc < 0) {
+               dev_warn(&pdev->dev, "Not resetting device.\n");
                return -ENODEV;
        }
+       if (board_id == 0x409C0E11 || board_id == 0x409D0E11)
+               return -ENOTSUPP;
 
-       /* Quoting from the Open CISS Specification: "The Power
-        * Management Control/Status Register (CSR) controls the power
-        * state of the device.  The normal operating state is D0,
-        * CSR=00h.  The software off state is D3, CSR=03h.  To reset
-        * the controller, place the interface device in D3 then to
-        * D0, this causes a secondary PCI reset which will reset the
-        * controller."
+       /* Save the PCI command register */
+       pci_read_config_word(pdev, 4, &command_register);
+       /* Turn the board off.  This is so that later pci_restore_state()
+        * won't turn the board on before the rest of config space is ready.
         */
+       pci_disable_device(pdev);
+       pci_save_state(pdev);
+
+       /* find the first memory BAR, so we can find the cfg table */
+       rc = hpsa_pci_find_memory_BAR(pdev, &paddr);
+       if (rc)
+               return rc;
+       vaddr = remap_pci_mem(paddr, 0x250);
+       if (!vaddr)
+               return -ENOMEM;
 
-       /* enter the D3hot power management state */
-       pci_read_config_word(pdev, pos + PCI_PM_CTRL, &pmcsr);
-       pmcsr &= ~PCI_PM_CTRL_STATE_MASK;
-       pmcsr |= PCI_D3hot;
-       pci_write_config_word(pdev, pos + PCI_PM_CTRL, pmcsr);
+       /* find cfgtable in order to check if reset via doorbell is supported */
+       rc = hpsa_find_cfg_addrs(pdev, vaddr, &cfg_base_addr,
+                                       &cfg_base_addr_index, &cfg_offset);
+       if (rc)
+               goto unmap_vaddr;
+       cfgtable = remap_pci_mem(pci_resource_start(pdev,
+                      cfg_base_addr_index) + cfg_offset, sizeof(*cfgtable));
+       if (!cfgtable) {
+               rc = -ENOMEM;
+               goto unmap_vaddr;
+       }
 
-       msleep(500);
+       /* If reset via doorbell register is supported, use that. */
+       misc_fw_support = readl(&cfgtable->misc_fw_support);
+       use_doorbell = misc_fw_support & MISC_FW_DOORBELL_RESET;
 
-       /* enter the D0 power management state */
-       pmcsr &= ~PCI_PM_CTRL_STATE_MASK;
-       pmcsr |= PCI_D0;
-       pci_write_config_word(pdev, pos + PCI_PM_CTRL, pmcsr);
+       rc = hpsa_controller_hard_reset(pdev, vaddr, use_doorbell);
+       if (rc)
+               goto unmap_cfgtable;
 
-       msleep(500);
+       pci_restore_state(pdev);
+       rc = pci_enable_device(pdev);
+       if (rc) {
+               dev_warn(&pdev->dev, "failed to enable device.\n");
+               goto unmap_cfgtable;
+       }
+       pci_write_config_word(pdev, 4, command_register);
+
+       /* Some devices (notably the HP Smart Array 5i Controller)
+          need a little pause here */
+       msleep(HPSA_POST_RESET_PAUSE_MSECS);
+
+       /* Wait for board to become not ready, then ready. */
+       dev_info(&pdev->dev, "Waiting for board to become ready.\n");
+       rc = hpsa_wait_for_board_state(pdev, vaddr, BOARD_NOT_READY);
+       if (rc)
+               dev_warn(&pdev->dev,
+                       "failed waiting for board to become not ready\n");
+       rc = hpsa_wait_for_board_state(pdev, vaddr, BOARD_READY);
+       if (rc) {
+               dev_warn(&pdev->dev,
+                       "failed waiting for board to become ready\n");
+               goto unmap_cfgtable;
+       }
+       dev_info(&pdev->dev, "board ready.\n");
 
-       /* Restore the PCI configuration space.  The Open CISS
-        * Specification says, "Restore the PCI Configuration
-        * Registers, offsets 00h through 60h. It is important to
-        * restore the command register, 16-bits at offset 04h,
-        * last. Do not restore the configuration status register,
-        * 16-bits at offset 06h."  Note that the offset is 2*i.
+       /* Controller should be in simple mode at this point.  If it's not,
+        * It means we're on one of those controllers which doesn't support
+        * the doorbell reset method and on which the PCI power management reset
+        * method doesn't work (P800, for example.)
+        * In those cases, don't try to proceed, as it generally doesn't work.
         */
-       for (i = 0; i < 32; i++) {
-               if (i == 2 || i == 3)
-                       continue;
-               pci_write_config_word(pdev, 2*i, saved_config_space[i]);
+       active_transport = readl(&cfgtable->TransportActive);
+       if (active_transport & PERFORMANT_MODE) {
+               dev_warn(&pdev->dev, "Unable to successfully reset controller,"
+                       " Ignoring controller.\n");
+               rc = -ENODEV;
        }
-       wmb();
-       pci_write_config_word(pdev, 4, saved_config_space[2]);
 
-       return 0;
+unmap_cfgtable:
+       iounmap(cfgtable);
+
+unmap_vaddr:
+       iounmap(vaddr);
+       return rc;
 }
 
 /*
@@ -3049,9 +3286,9 @@ static __devinit int hpsa_hard_reset_controller(struct pci_dev *pdev)
  *   the io functions.
  *   This is for debug only.
  */
-#ifdef HPSA_DEBUG
 static void print_cfg_table(struct device *dev, struct CfgTable *tb)
 {
+#ifdef HPSA_DEBUG
        int i;
        char temp_name[17];
 
@@ -3081,8 +3318,8 @@ static void print_cfg_table(struct device *dev, struct CfgTable *tb)
        dev_info(dev, "   Server Name = %s\n", temp_name);
        dev_info(dev, "   Heartbeat Counter = 0x%x\n\n\n",
                readl(&(tb->HeartBeat)));
-}
 #endif                         /* HPSA_DEBUG */
+}
 
 static int find_PCI_BAR_index(struct pci_dev *pdev, unsigned long pci_bar_addr)
 {
@@ -3123,8 +3360,7 @@ static int find_PCI_BAR_index(struct pci_dev *pdev, unsigned long pci_bar_addr)
  * controllers that are capable. If not, we use IO-APIC mode.
  */
 
-static void __devinit hpsa_interrupt_mode(struct ctlr_info *h,
-                                          struct pci_dev *pdev, u32 board_id)
+static void __devinit hpsa_interrupt_mode(struct ctlr_info *h)
 {
 #ifdef CONFIG_PCI_MSI
        int err;
@@ -3133,13 +3369,12 @@ static void __devinit hpsa_interrupt_mode(struct ctlr_info *h,
        };
 
        /* Some boards advertise MSI but don't really support it */
-       if ((board_id == 0x40700E11) ||
-           (board_id == 0x40800E11) ||
-           (board_id == 0x40820E11) || (board_id == 0x40830E11))
+       if ((h->board_id == 0x40700E11) || (h->board_id == 0x40800E11) ||
+           (h->board_id == 0x40820E11) || (h->board_id == 0x40830E11))
                goto default_int_mode;
-       if (pci_find_capability(pdev, PCI_CAP_ID_MSIX)) {
-               dev_info(&pdev->dev, "MSIX\n");
-               err = pci_enable_msix(pdev, hpsa_msix_entries, 4);
+       if (pci_find_capability(h->pdev, PCI_CAP_ID_MSIX)) {
+               dev_info(&h->pdev->dev, "MSIX\n");
+               err = pci_enable_msix(h->pdev, hpsa_msix_entries, 4);
                if (!err) {
                        h->intr[0] = hpsa_msix_entries[0].vector;
                        h->intr[1] = hpsa_msix_entries[1].vector;
@@ -3149,234 +3384,394 @@ static void __devinit hpsa_interrupt_mode(struct ctlr_info *h,
                        return;
                }
                if (err > 0) {
-                       dev_warn(&pdev->dev, "only %d MSI-X vectors "
+                       dev_warn(&h->pdev->dev, "only %d MSI-X vectors "
                               "available\n", err);
                        goto default_int_mode;
                } else {
-                       dev_warn(&pdev->dev, "MSI-X init failed %d\n",
+                       dev_warn(&h->pdev->dev, "MSI-X init failed %d\n",
                               err);
                        goto default_int_mode;
                }
        }
-       if (pci_find_capability(pdev, PCI_CAP_ID_MSI)) {
-               dev_info(&pdev->dev, "MSI\n");
-               if (!pci_enable_msi(pdev))
+       if (pci_find_capability(h->pdev, PCI_CAP_ID_MSI)) {
+               dev_info(&h->pdev->dev, "MSI\n");
+               if (!pci_enable_msi(h->pdev))
                        h->msi_vector = 1;
                else
-                       dev_warn(&pdev->dev, "MSI init failed\n");
+                       dev_warn(&h->pdev->dev, "MSI init failed\n");
        }
 default_int_mode:
 #endif                         /* CONFIG_PCI_MSI */
        /* if we get here we're going to use the default interrupt mode */
-       h->intr[PERF_MODE_INT] = pdev->irq;
+       h->intr[h->intr_mode] = h->pdev->irq;
 }
 
-static int hpsa_pci_init(struct ctlr_info *h, struct pci_dev *pdev)
+static int __devinit hpsa_lookup_board_id(struct pci_dev *pdev, u32 *board_id)
 {
-       ushort subsystem_vendor_id, subsystem_device_id, command;
-       u32 board_id, scratchpad = 0;
-       u64 cfg_offset;
-       u32 cfg_base_addr;
-       u64 cfg_base_addr_index;
-       u32 trans_offset;
-       int i, prod_index, err;
+       int i;
+       u32 subsystem_vendor_id, subsystem_device_id;
 
        subsystem_vendor_id = pdev->subsystem_vendor;
        subsystem_device_id = pdev->subsystem_device;
-       board_id = (((u32) (subsystem_device_id << 16) & 0xffff0000) |
-                   subsystem_vendor_id);
+       *board_id = ((subsystem_device_id << 16) & 0xffff0000) |
+                   subsystem_vendor_id;
 
        for (i = 0; i < ARRAY_SIZE(products); i++)
-               if (board_id == products[i].board_id)
-                       break;
-
-       prod_index = i;
-
-       if (prod_index == ARRAY_SIZE(products)) {
-               prod_index--;
-               if (subsystem_vendor_id != PCI_VENDOR_ID_HP ||
-                               !hpsa_allow_any) {
-                       dev_warn(&pdev->dev, "unrecognized board ID:"
-                               " 0x%08lx, ignoring.\n",
-                               (unsigned long) board_id);
+               if (*board_id == products[i].board_id)
+                       return i;
+
+       if ((subsystem_vendor_id != PCI_VENDOR_ID_HP &&
+               subsystem_vendor_id != PCI_VENDOR_ID_COMPAQ) ||
+               !hpsa_allow_any) {
+               dev_warn(&pdev->dev, "unrecognized board ID: "
+                       "0x%08x, ignoring.\n", *board_id);
                        return -ENODEV;
-               }
-       }
-       /* check to see if controller has been disabled
-        * BEFORE trying to enable it
-        */
-       (void)pci_read_config_word(pdev, PCI_COMMAND, &command);
-       if (!(command & 0x02)) {
-               dev_warn(&pdev->dev, "controller appears to be disabled\n");
-               return -ENODEV;
-       }
-
-       err = pci_enable_device(pdev);
-       if (err) {
-               dev_warn(&pdev->dev, "unable to enable PCI device\n");
-               return err;
        }
+       return ARRAY_SIZE(products) - 1; /* generic unknown smart array */
+}
 
-       err = pci_request_regions(pdev, "hpsa");
-       if (err) {
-               dev_err(&pdev->dev, "cannot obtain PCI resources, aborting\n");
-               return err;
-       }
+static inline bool hpsa_board_disabled(struct pci_dev *pdev)
+{
+       u16 command;
 
-       /* If the kernel supports MSI/MSI-X we will try to enable that,
-        * else we use the IO-APIC interrupt assigned to us by system ROM.
-        */
-       hpsa_interrupt_mode(h, pdev, board_id);
+       (void) pci_read_config_word(pdev, PCI_COMMAND, &command);
+       return ((command & PCI_COMMAND_MEMORY) == 0);
+}
 
-       /* find the memory BAR */
-       for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
-               if (pci_resource_flags(pdev, i) & IORESOURCE_MEM)
-                       break;
-       }
-       if (i == DEVICE_COUNT_RESOURCE) {
-               dev_warn(&pdev->dev, "no memory BAR found\n");
-               err = -ENODEV;
-               goto err_out_free_res;
-       }
+static int __devinit hpsa_pci_find_memory_BAR(struct pci_dev *pdev,
+       unsigned long *memory_bar)
+{
+       int i;
 
-       h->paddr = pci_resource_start(pdev, i); /* addressing mode bits
-                                                * already removed
-                                                */
+       for (i = 0; i < DEVICE_COUNT_RESOURCE; i++)
+               if (pci_resource_flags(pdev, i) & IORESOURCE_MEM) {
+                       /* addressing mode bits already removed */
+                       *memory_bar = pci_resource_start(pdev, i);
+                       dev_dbg(&pdev->dev, "memory BAR = %lx\n",
+                               *memory_bar);
+                       return 0;
+               }
+       dev_warn(&pdev->dev, "no memory BAR found\n");
+       return -ENODEV;
+}
 
-       h->vaddr = remap_pci_mem(h->paddr, 0x250);
+static int __devinit hpsa_wait_for_board_state(struct pci_dev *pdev,
+       void __iomem *vaddr, int wait_for_ready)
+{
+       int i, iterations;
+       u32 scratchpad;
+       if (wait_for_ready)
+               iterations = HPSA_BOARD_READY_ITERATIONS;
+       else
+               iterations = HPSA_BOARD_NOT_READY_ITERATIONS;
 
-       /* Wait for the board to become ready.  */
-       for (i = 0; i < HPSA_BOARD_READY_ITERATIONS; i++) {
-               scratchpad = readl(h->vaddr + SA5_SCRATCHPAD_OFFSET);
-               if (scratchpad == HPSA_FIRMWARE_READY)
-                       break;
+       for (i = 0; i < iterations; i++) {
+               scratchpad = readl(vaddr + SA5_SCRATCHPAD_OFFSET);
+               if (wait_for_ready) {
+                       if (scratchpad == HPSA_FIRMWARE_READY)
+                               return 0;
+               } else {
+                       if (scratchpad != HPSA_FIRMWARE_READY)
+                               return 0;
+               }
                msleep(HPSA_BOARD_READY_POLL_INTERVAL_MSECS);
        }
-       if (scratchpad != HPSA_FIRMWARE_READY) {
-               dev_warn(&pdev->dev, "board not ready, timed out.\n");
-               err = -ENODEV;
-               goto err_out_free_res;
-       }
+       dev_warn(&pdev->dev, "board not ready, timed out.\n");
+       return -ENODEV;
+}
 
-       /* get the address index number */
-       cfg_base_addr = readl(h->vaddr + SA5_CTCFG_OFFSET);
-       cfg_base_addr &= (u32) 0x0000ffff;
-       cfg_base_addr_index = find_PCI_BAR_index(pdev, cfg_base_addr);
-       if (cfg_base_addr_index == -1) {
+static int __devinit hpsa_find_cfg_addrs(struct pci_dev *pdev,
+       void __iomem *vaddr, u32 *cfg_base_addr, u64 *cfg_base_addr_index,
+       u64 *cfg_offset)
+{
+       *cfg_base_addr = readl(vaddr + SA5_CTCFG_OFFSET);
+       *cfg_offset = readl(vaddr + SA5_CTMEM_OFFSET);
+       *cfg_base_addr &= (u32) 0x0000ffff;
+       *cfg_base_addr_index = find_PCI_BAR_index(pdev, *cfg_base_addr);
+       if (*cfg_base_addr_index == -1) {
                dev_warn(&pdev->dev, "cannot find cfg_base_addr_index\n");
-               err = -ENODEV;
-               goto err_out_free_res;
+               return -ENODEV;
        }
+       return 0;
+}
 
-       cfg_offset = readl(h->vaddr + SA5_CTMEM_OFFSET);
-       h->cfgtable = remap_pci_mem(pci_resource_start(pdev,
-                              cfg_base_addr_index) + cfg_offset,
-                               sizeof(h->cfgtable));
+static int __devinit hpsa_find_cfgtables(struct ctlr_info *h)
+{
+       u64 cfg_offset;
+       u32 cfg_base_addr;
+       u64 cfg_base_addr_index;
+       u32 trans_offset;
+       int rc;
+
+       rc = hpsa_find_cfg_addrs(h->pdev, h->vaddr, &cfg_base_addr,
+               &cfg_base_addr_index, &cfg_offset);
+       if (rc)
+               return rc;
+       h->cfgtable = remap_pci_mem(pci_resource_start(h->pdev,
+                      cfg_base_addr_index) + cfg_offset, sizeof(*h->cfgtable));
+       if (!h->cfgtable)
+               return -ENOMEM;
        /* Find performant mode table. */
-       trans_offset = readl(&(h->cfgtable->TransMethodOffset));
-       h->transtable = remap_pci_mem(pci_resource_start(pdev,
+       trans_offset = readl(&h->cfgtable->TransMethodOffset);
+       h->transtable = remap_pci_mem(pci_resource_start(h->pdev,
                                cfg_base_addr_index)+cfg_offset+trans_offset,
                                sizeof(*h->transtable));
+       if (!h->transtable)
+               return -ENOMEM;
+       return 0;
+}
 
-       h->board_id = board_id;
+static void __devinit hpsa_get_max_perf_mode_cmds(struct ctlr_info *h)
+{
        h->max_commands = readl(&(h->cfgtable->MaxPerformantModeCommands));
-       h->product_name = products[prod_index].product_name;
-       h->access = *(products[prod_index].access);
-       /* Allow room for some ioctls */
-       h->nr_cmds = h->max_commands - 4;
 
+       /* Limit commands in memory limited kdump scenario. */
+       if (reset_devices && h->max_commands > 32)
+               h->max_commands = 32;
+
+       if (h->max_commands < 16) {
+               dev_warn(&h->pdev->dev, "Controller reports "
+                       "max supported commands of %d, an obvious lie. "
+                       "Using 16.  Ensure that firmware is up to date.\n",
+                       h->max_commands);
+               h->max_commands = 16;
+       }
+}
+
+/* Interrogate the hardware for some limits:
+ * max commands, max SG elements without chaining, and with chaining,
+ * SG chain block size, etc.
+ */
+static void __devinit hpsa_find_board_params(struct ctlr_info *h)
+{
+       hpsa_get_max_perf_mode_cmds(h);
+       h->nr_cmds = h->max_commands - 4; /* Allow room for some ioctls */
+       h->maxsgentries = readl(&(h->cfgtable->MaxScatterGatherElements));
+       /*
+        * Limit in-command s/g elements to 32 save dma'able memory.
+        * Howvever spec says if 0, use 31
+        */
+       h->max_cmd_sg_entries = 31;
+       if (h->maxsgentries > 512) {
+               h->max_cmd_sg_entries = 32;
+               h->chainsize = h->maxsgentries - h->max_cmd_sg_entries + 1;
+               h->maxsgentries--; /* save one for chain pointer */
+       } else {
+               h->maxsgentries = 31; /* default to traditional values */
+               h->chainsize = 0;
+       }
+}
+
+static inline bool hpsa_CISS_signature_present(struct ctlr_info *h)
+{
        if ((readb(&h->cfgtable->Signature[0]) != 'C') ||
            (readb(&h->cfgtable->Signature[1]) != 'I') ||
            (readb(&h->cfgtable->Signature[2]) != 'S') ||
            (readb(&h->cfgtable->Signature[3]) != 'S')) {
-               dev_warn(&pdev->dev, "not a valid CISS config table\n");
-               err = -ENODEV;
-               goto err_out_free_res;
+               dev_warn(&h->pdev->dev, "not a valid CISS config table\n");
+               return false;
        }
+       return true;
+}
+
+/* Need to enable prefetch in the SCSI core for 6400 in x86 */
+static inline void hpsa_enable_scsi_prefetch(struct ctlr_info *h)
+{
 #ifdef CONFIG_X86
-       {
-               /* Need to enable prefetch in the SCSI core for 6400 in x86 */
-               u32 prefetch;
-               prefetch = readl(&(h->cfgtable->SCSI_Prefetch));
-               prefetch |= 0x100;
-               writel(prefetch, &(h->cfgtable->SCSI_Prefetch));
-       }
+       u32 prefetch;
+
+       prefetch = readl(&(h->cfgtable->SCSI_Prefetch));
+       prefetch |= 0x100;
+       writel(prefetch, &(h->cfgtable->SCSI_Prefetch));
 #endif
+}
 
-       /* Disabling DMA prefetch for the P600
-        * An ASIC bug may result in a prefetch beyond
-        * physical memory.
-        */
-       if (board_id == 0x3225103C) {
-               u32 dma_prefetch;
-               dma_prefetch = readl(h->vaddr + I2O_DMA1_CFG);
-               dma_prefetch |= 0x8000;
-               writel(dma_prefetch, h->vaddr + I2O_DMA1_CFG);
-       }
+/* Disable DMA prefetch for the P600.  Otherwise an ASIC bug may result
+ * in a prefetch beyond physical memory.
+ */
+static inline void hpsa_p600_dma_prefetch_quirk(struct ctlr_info *h)
+{
+       u32 dma_prefetch;
 
-       h->max_commands = readl(&(h->cfgtable->CmdsOutMax));
-       /* Update the field, and then ring the doorbell */
-       writel(CFGTBL_Trans_Simple, &(h->cfgtable->HostWrite.TransportRequest));
-       writel(CFGTBL_ChangeReq, h->vaddr + SA5_DOORBELL);
+       if (h->board_id != 0x3225103C)
+               return;
+       dma_prefetch = readl(h->vaddr + I2O_DMA1_CFG);
+       dma_prefetch |= 0x8000;
+       writel(dma_prefetch, h->vaddr + I2O_DMA1_CFG);
+}
+
+static void __devinit hpsa_wait_for_mode_change_ack(struct ctlr_info *h)
+{
+       int i;
+       u32 doorbell_value;
+       unsigned long flags;
 
        /* under certain very rare conditions, this can take awhile.
         * (e.g.: hot replace a failed 144GB drive in a RAID 5 set right
         * as we enter this code.)
         */
        for (i = 0; i < MAX_CONFIG_WAIT; i++) {
-               if (!(readl(h->vaddr + SA5_DOORBELL) & CFGTBL_ChangeReq))
+               spin_lock_irqsave(&h->lock, flags);
+               doorbell_value = readl(h->vaddr + SA5_DOORBELL);
+               spin_unlock_irqrestore(&h->lock, flags);
+               if (!(doorbell_value & CFGTBL_ChangeReq))
                        break;
                /* delay and try again */
-               msleep(10);
+               usleep_range(10000, 20000);
        }
+}
 
-#ifdef HPSA_DEBUG
-       print_cfg_table(&pdev->dev, h->cfgtable);
-#endif                         /* HPSA_DEBUG */
+static int __devinit hpsa_enter_simple_mode(struct ctlr_info *h)
+{
+       u32 trans_support;
 
+       trans_support = readl(&(h->cfgtable->TransportSupport));
+       if (!(trans_support & SIMPLE_MODE))
+               return -ENOTSUPP;
+
+       h->max_commands = readl(&(h->cfgtable->CmdsOutMax));
+       /* Update the field, and then ring the doorbell */
+       writel(CFGTBL_Trans_Simple, &(h->cfgtable->HostWrite.TransportRequest));
+       writel(CFGTBL_ChangeReq, h->vaddr + SA5_DOORBELL);
+       hpsa_wait_for_mode_change_ack(h);
+       print_cfg_table(&h->pdev->dev, h->cfgtable);
        if (!(readl(&(h->cfgtable->TransportActive)) & CFGTBL_Trans_Simple)) {
-               dev_warn(&pdev->dev, "unable to get board into simple mode\n");
+               dev_warn(&h->pdev->dev,
+                       "unable to get board into simple mode\n");
+               return -ENODEV;
+       }
+       h->transMethod = CFGTBL_Trans_Simple;
+       return 0;
+}
+
+static int __devinit hpsa_pci_init(struct ctlr_info *h)
+{
+       int prod_index, err;
+
+       prod_index = hpsa_lookup_board_id(h->pdev, &h->board_id);
+       if (prod_index < 0)
+               return -ENODEV;
+       h->product_name = products[prod_index].product_name;
+       h->access = *(products[prod_index].access);
+
+       if (hpsa_board_disabled(h->pdev)) {
+               dev_warn(&h->pdev->dev, "controller appears to be disabled\n");
+               return -ENODEV;
+       }
+       err = pci_enable_device(h->pdev);
+       if (err) {
+               dev_warn(&h->pdev->dev, "unable to enable PCI device\n");
+               return err;
+       }
+
+       err = pci_request_regions(h->pdev, "hpsa");
+       if (err) {
+               dev_err(&h->pdev->dev,
+                       "cannot obtain PCI resources, aborting\n");
+               return err;
+       }
+       hpsa_interrupt_mode(h);
+       err = hpsa_pci_find_memory_BAR(h->pdev, &h->paddr);
+       if (err)
+               goto err_out_free_res;
+       h->vaddr = remap_pci_mem(h->paddr, 0x250);
+       if (!h->vaddr) {
+               err = -ENOMEM;
+               goto err_out_free_res;
+       }
+       err = hpsa_wait_for_board_state(h->pdev, h->vaddr, BOARD_READY);
+       if (err)
+               goto err_out_free_res;
+       err = hpsa_find_cfgtables(h);
+       if (err)
+               goto err_out_free_res;
+       hpsa_find_board_params(h);
+
+       if (!hpsa_CISS_signature_present(h)) {
                err = -ENODEV;
                goto err_out_free_res;
        }
+       hpsa_enable_scsi_prefetch(h);
+       hpsa_p600_dma_prefetch_quirk(h);
+       err = hpsa_enter_simple_mode(h);
+       if (err)
+               goto err_out_free_res;
        return 0;
 
 err_out_free_res:
+       if (h->transtable)
+               iounmap(h->transtable);
+       if (h->cfgtable)
+               iounmap(h->cfgtable);
+       if (h->vaddr)
+               iounmap(h->vaddr);
        /*
         * Deliberately omit pci_disable_device(): it does something nasty to
         * Smart Array controllers that pci_enable_device does not undo
         */
-       pci_release_regions(pdev);
+       pci_release_regions(h->pdev);
        return err;
 }
 
+static void __devinit hpsa_hba_inquiry(struct ctlr_info *h)
+{
+       int rc;
+
+#define HBA_INQUIRY_BYTE_COUNT 64
+       h->hba_inquiry_data = kmalloc(HBA_INQUIRY_BYTE_COUNT, GFP_KERNEL);
+       if (!h->hba_inquiry_data)
+               return;
+       rc = hpsa_scsi_do_inquiry(h, RAID_CTLR_LUNID, 0,
+               h->hba_inquiry_data, HBA_INQUIRY_BYTE_COUNT);
+       if (rc != 0) {
+               kfree(h->hba_inquiry_data);
+               h->hba_inquiry_data = NULL;
+       }
+}
+
+static __devinit int hpsa_init_reset_devices(struct pci_dev *pdev)
+{
+       int rc, i;
+
+       if (!reset_devices)
+               return 0;
+
+       /* Reset the controller with a PCI power-cycle or via doorbell */
+       rc = hpsa_kdump_hard_reset_controller(pdev);
+
+       /* -ENOTSUPP here means we cannot reset the controller
+        * but it's already (and still) up and running in
+        * "performant mode".  Or, it might be 640x, which can't reset
+        * due to concerns about shared bbwc between 6402/6404 pair.
+        */
+       if (rc == -ENOTSUPP)
+               return 0; /* just try to do the kdump anyhow. */
+       if (rc)
+               return -ENODEV;
+
+       /* Now try to get the controller to respond to a no-op */
+       for (i = 0; i < HPSA_POST_RESET_NOOP_RETRIES; i++) {
+               if (hpsa_noop(pdev) == 0)
+                       break;
+               else
+                       dev_warn(&pdev->dev, "no-op failed%s\n",
+                                       (i < 11 ? "; re-trying" : ""));
+       }
+       return 0;
+}
+
 static int __devinit hpsa_init_one(struct pci_dev *pdev,
                                    const struct pci_device_id *ent)
 {
-       int i, rc;
-       int dac;
+       int dac, rc;
        struct ctlr_info *h;
 
        if (number_of_controllers == 0)
                printk(KERN_INFO DRIVER_NAME "\n");
-       if (reset_devices) {
-               /* Reset the controller with a PCI power-cycle */
-               if (hpsa_hard_reset_controller(pdev) || hpsa_reset_msi(pdev))
-                       return -ENODEV;
 
-               /* Some devices (notably the HP Smart Array 5i Controller)
-                  need a little pause here */
-               msleep(HPSA_POST_RESET_PAUSE_MSECS);
-
-               /* Now try to get the controller to respond to a no-op */
-               for (i = 0; i < HPSA_POST_RESET_NOOP_RETRIES; i++) {
-                       if (hpsa_noop(pdev) == 0)
-                               break;
-                       else
-                               dev_warn(&pdev->dev, "no-op failed%s\n",
-                                               (i < 11 ? "; re-trying" : ""));
-               }
-       }
+       rc = hpsa_init_reset_devices(pdev);
+       if (rc)
+               return rc;
 
        /* Command structures must be aligned on a 32-byte boundary because
         * the 5 lower bits of the address are used by the hardware. and by
@@ -3388,19 +3783,20 @@ static int __devinit hpsa_init_one(struct pci_dev *pdev,
        if (!h)
                return -ENOMEM;
 
+       h->pdev = pdev;
        h->busy_initializing = 1;
-       INIT_HLIST_HEAD(&h->cmpQ);
-       INIT_HLIST_HEAD(&h->reqQ);
-       mutex_init(&h->busy_shutting_down);
-       init_completion(&h->scan_wait);
-       rc = hpsa_pci_init(h, pdev);
+       h->intr_mode = hpsa_simple_mode ? SIMPLE_MODE_INT : PERF_MODE_INT;
+       INIT_LIST_HEAD(&h->cmpQ);
+       INIT_LIST_HEAD(&h->reqQ);
+       spin_lock_init(&h->lock);
+       spin_lock_init(&h->scan_lock);
+       rc = hpsa_pci_init(h);
        if (rc != 0)
                goto clean1;
 
        sprintf(h->devname, "hpsa%d", number_of_controllers);
        h->ctlr = number_of_controllers;
        number_of_controllers++;
-       h->pdev = pdev;
 
        /* configure PCI DMA stuff */
        rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(64));
@@ -3418,17 +3814,22 @@ static int __devinit hpsa_init_one(struct pci_dev *pdev,
 
        /* make sure the board interrupts are off */
        h->access.set_intr_mask(h, HPSA_INTR_OFF);
-       rc = request_irq(h->intr[PERF_MODE_INT], do_hpsa_intr,
-                       IRQF_DISABLED, h->devname, h);
+
+       if (h->msix_vector || h->msi_vector)
+               rc = request_irq(h->intr[h->intr_mode], do_hpsa_intr_msi,
+                               IRQF_DISABLED, h->devname, h);
+       else
+               rc = request_irq(h->intr[h->intr_mode], do_hpsa_intr_intx,
+                               IRQF_DISABLED, h->devname, h);
        if (rc) {
                dev_err(&pdev->dev, "unable to get irq %d for %s\n",
-                      h->intr[PERF_MODE_INT], h->devname);
+                      h->intr[h->intr_mode], h->devname);
                goto clean2;
        }
 
        dev_info(&pdev->dev, "%s: <0x%x> at IRQ %d%s using DAC\n",
               h->devname, pdev->device,
-              h->intr[PERF_MODE_INT], dac ? "" : " not");
+              h->intr[h->intr_mode], dac ? "" : " not");
 
        h->cmd_pool_bits =
            kmalloc(((h->nr_cmds + BITS_PER_LONG -
@@ -3446,7 +3847,10 @@ static int __devinit hpsa_init_one(struct pci_dev *pdev,
                rc = -ENOMEM;
                goto clean4;
        }
-       spin_lock_init(&h->lock);
+       if (hpsa_allocate_sg_chain_blocks(h))
+               goto clean4;
+       init_waitqueue_head(&h->scan_wait_queue);
+       h->scan_finished = 1; /* no scan currently in progress */
 
        pci_set_drvdata(pdev, h);
        memset(h->cmd_pool_bits, 0,
@@ -3459,11 +3863,13 @@ static int __devinit hpsa_init_one(struct pci_dev *pdev,
        h->access.set_intr_mask(h, HPSA_INTR_ON);
 
        hpsa_put_ctlr_into_performant_mode(h);
+       hpsa_hba_inquiry(h);
        hpsa_register_scsi(h);  /* hook ourselves into SCSI subsystem */
        h->busy_initializing = 0;
        return 1;
 
 clean4:
+       hpsa_free_sg_chain_blocks(h);
        kfree(h->cmd_pool_bits);
        if (h->cmd_pool)
                pci_free_consistent(h->pdev,
@@ -3474,7 +3880,7 @@ clean4:
                            h->nr_cmds * sizeof(struct ErrorInfo),
                            h->errinfo_pool,
                            h->errinfo_pool_dhandle);
-       free_irq(h->intr[PERF_MODE_INT], h);
+       free_irq(h->intr[h->intr_mode], h);
 clean2:
 clean1:
        h->busy_initializing = 0;
@@ -3518,7 +3924,7 @@ static void hpsa_shutdown(struct pci_dev *pdev)
         */
        hpsa_flush_cache(h);
        h->access.set_intr_mask(h, HPSA_INTR_OFF);
-       free_irq(h->intr[PERF_MODE_INT], h);
+       free_irq(h->intr[h->intr_mode], h);
 #ifdef CONFIG_PCI_MSI
        if (h->msix_vector)
                pci_disable_msix(h->pdev);
@@ -3536,11 +3942,12 @@ static void __devexit hpsa_remove_one(struct pci_dev *pdev)
                return;
        }
        h = pci_get_drvdata(pdev);
-       mutex_lock(&h->busy_shutting_down);
-       remove_from_scan_list(h);
        hpsa_unregister_scsi(h);        /* unhook from SCSI subsystem */
        hpsa_shutdown(pdev);
        iounmap(h->vaddr);
+       iounmap(h->transtable);
+       iounmap(h->cfgtable);
+       hpsa_free_sg_chain_blocks(h);
        pci_free_consistent(h->pdev,
                h->nr_cmds * sizeof(struct CommandList),
                h->cmd_pool, h->cmd_pool_dhandle);
@@ -3551,13 +3958,13 @@ static void __devexit hpsa_remove_one(struct pci_dev *pdev)
                h->reply_pool, h->reply_pool_dhandle);
        kfree(h->cmd_pool_bits);
        kfree(h->blockFetchTable);
+       kfree(h->hba_inquiry_data);
        /*
         * Deliberately omit pci_disable_device(): it does something nasty to
         * Smart Array controllers that pci_enable_device does not undo
         */
        pci_release_regions(pdev);
        pci_set_drvdata(pdev, NULL);
-       mutex_unlock(&h->busy_shutting_down);
        kfree(h);
 }
 
@@ -3619,38 +4026,36 @@ static void  calc_bucket_map(int bucket[], int num_buckets,
        }
 }
 
-static void hpsa_put_ctlr_into_performant_mode(struct ctlr_info *h)
+static __devinit void hpsa_enter_performant_mode(struct ctlr_info *h,
+       u32 use_short_tags)
 {
-       u32 trans_support;
-       u64 trans_offset;
+       int i;
+       unsigned long register_value;
+
+       /* This is a bit complicated.  There are 8 registers on
+        * the controller which we write to to tell it 8 different
+        * sizes of commands which there may be.  It's a way of
+        * reducing the DMA done to fetch each command.  Encoded into
+        * each command's tag are 3 bits which communicate to the controller
+        * which of the eight sizes that command fits within.  The size of
+        * each command depends on how many scatter gather entries there are.
+        * Each SG entry requires 16 bytes.  The eight registers are programmed
+        * with the number of 16-byte blocks a command of that size requires.
+        * The smallest command possible requires 5 such 16 byte blocks.
+        * the largest command possible requires MAXSGENTRIES + 4 16-byte
+        * blocks.  Note, this only extends to the SG entries contained
+        * within the command block, and does not extend to chained blocks
+        * of SG elements.   bft[] contains the eight values we write to
+        * the registers.  They are not evenly distributed, but have more
+        * sizes for small commands, and fewer sizes for larger commands.
+        */
+       int bft[8] = {5, 6, 8, 10, 12, 20, 28, MAXSGENTRIES + 4};
+       BUILD_BUG_ON(28 > MAXSGENTRIES + 4);
        /*  5 = 1 s/g entry or 4k
         *  6 = 2 s/g entry or 8k
         *  8 = 4 s/g entry or 16k
         * 10 = 6 s/g entry or 24k
         */
-       int bft[8] = {5, 6, 8, 10, 12, 20, 28, 35}; /* for scatter/gathers */
-       int i = 0;
-       int l = 0;
-       unsigned long register_value;
-
-       trans_support = readl(&(h->cfgtable->TransportSupport));
-       if (!(trans_support & PERFORMANT_MODE))
-               return;
-
-       h->max_commands = readl(&(h->cfgtable->MaxPerformantModeCommands));
-       h->max_sg_entries = 32;
-       /* Performant mode ring buffer and supporting data structures */
-       h->reply_pool_size = h->max_commands * sizeof(u64);
-       h->reply_pool = pci_alloc_consistent(h->pdev, h->reply_pool_size,
-                               &(h->reply_pool_dhandle));
-
-       /* Need a block fetch table for performant mode */
-       h->blockFetchTable = kmalloc(((h->max_sg_entries+1) *
-                               sizeof(u32)), GFP_KERNEL);
-
-       if ((h->reply_pool == NULL)
-               || (h->blockFetchTable == NULL))
-               goto clean_up;
 
        h->reply_pool_wraparound = 1; /* spec: init to 1 */
 
@@ -3658,7 +4063,6 @@ static void hpsa_put_ctlr_into_performant_mode(struct ctlr_info *h)
        memset(h->reply_pool, 0, h->reply_pool_size);
        h->reply_pool_head = h->reply_pool;
 
-       trans_offset = readl(&(h->cfgtable->TransMethodOffset));
        bft[7] = h->max_sg_entries + 4;
        calc_bucket_map(bft, ARRAY_SIZE(bft), 32, h->blockFetchTable);
        for (i = 0; i < 8; i++)
@@ -3671,30 +4075,49 @@ static void hpsa_put_ctlr_into_performant_mode(struct ctlr_info *h)
        writel(0, &h->transtable->RepQCtrAddrHigh32);
        writel(h->reply_pool_dhandle, &h->transtable->RepQAddr0Low32);
        writel(0, &h->transtable->RepQAddr0High32);
-       writel(CFGTBL_Trans_Performant,
+       writel(CFGTBL_Trans_Performant | use_short_tags,
                &(h->cfgtable->HostWrite.TransportRequest));
        writel(CFGTBL_ChangeReq, h->vaddr + SA5_DOORBELL);
-       /* under certain very rare conditions, this can take awhile.
-        * (e.g.: hot replace a failed 144GB drive in a RAID 5 set right
-        * as we enter this code.) */
-       for (l = 0; l < MAX_CONFIG_WAIT; l++) {
-               register_value = readl(h->vaddr + SA5_DOORBELL);
-               if (!(register_value & CFGTBL_ChangeReq))
-                       break;
-               /* delay and try again */
-               set_current_state(TASK_INTERRUPTIBLE);
-               schedule_timeout(10);
-       }
+       hpsa_wait_for_mode_change_ack(h);
        register_value = readl(&(h->cfgtable->TransportActive));
        if (!(register_value & CFGTBL_Trans_Performant)) {
                dev_warn(&h->pdev->dev, "unable to get board into"
                                        " performant mode\n");
                return;
        }
-
        /* Change the access methods to the performant access methods */
        h->access = SA5_performant_access;
        h->transMethod = CFGTBL_Trans_Performant;
+}
+
+static __devinit void hpsa_put_ctlr_into_performant_mode(struct ctlr_info *h)
+{
+       u32 trans_support;
+
+       if (hpsa_simple_mode)
+               return;
+
+       trans_support = readl(&(h->cfgtable->TransportSupport));
+       if (!(trans_support & PERFORMANT_MODE))
+               return;
+
+       hpsa_get_max_perf_mode_cmds(h);
+       h->max_sg_entries = 32;
+       /* Performant mode ring buffer and supporting data structures */
+       h->reply_pool_size = h->max_commands * sizeof(u64);
+       h->reply_pool = pci_alloc_consistent(h->pdev, h->reply_pool_size,
+                               &(h->reply_pool_dhandle));
+
+       /* Need a block fetch table for performant mode */
+       h->blockFetchTable = kmalloc(((h->max_sg_entries+1) *
+                               sizeof(u32)), GFP_KERNEL);
+
+       if ((h->reply_pool == NULL)
+               || (h->blockFetchTable == NULL))
+               goto clean_up;
+
+       hpsa_enter_performant_mode(h,
+               trans_support & CFGTBL_Trans_use_short_tags);
 
        return;
 
@@ -3711,23 +4134,12 @@ clean_up:
  */
 static int __init hpsa_init(void)
 {
-       int err;
-       /* Start the scan thread */
-       hpsa_scan_thread = kthread_run(hpsa_scan_func, NULL, "hpsa_scan");
-       if (IS_ERR(hpsa_scan_thread)) {
-               err = PTR_ERR(hpsa_scan_thread);
-               return -ENODEV;
-       }
-       err = pci_register_driver(&hpsa_pci_driver);
-       if (err)
-               kthread_stop(hpsa_scan_thread);
-       return err;
+       return pci_register_driver(&hpsa_pci_driver);
 }
 
 static void __exit hpsa_cleanup(void)
 {
        pci_unregister_driver(&hpsa_pci_driver);
-       kthread_stop(hpsa_scan_thread);
 }
 
 module_init(hpsa_init);