[SCSI] bnx2fc: Broadcom FCoE offload driver
[linux-2.6.git] / drivers / scsi / hpsa.c
index e4b5f3c..c30591f 100644 (file)
@@ -74,6 +74,10 @@ 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[] = {
@@ -155,6 +159,10 @@ 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);
@@ -173,6 +181,10 @@ static int __devinit hpsa_find_cfg_addrs(struct pci_dev *pdev,
 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);
@@ -180,6 +192,10 @@ 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,
@@ -191,6 +207,8 @@ 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,
 };
 
@@ -291,17 +309,38 @@ static ssize_t host_show_firmware_revision(struct device *dev,
                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)) {
@@ -325,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);
 }
 
@@ -344,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[])
@@ -1130,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",
@@ -1160,7 +1203,7 @@ static int hpsa_scsi_detect(struct ctlr_info *h)
        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)
@@ -1295,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);
@@ -1595,6 +1641,8 @@ 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. */
 
@@ -1609,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)++;
@@ -2199,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;
@@ -2237,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;
@@ -2267,7 +2313,7 @@ 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
@@ -2281,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));
@@ -2317,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));
@@ -2806,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");
@@ -2863,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 */
@@ -2900,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);
@@ -2953,7 +3002,10 @@ static irqreturn_t do_hpsa_intr_msi(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-/* Send a message CDB to the firmware. */
+/* 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)
 {
@@ -3019,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);
        }
@@ -3051,38 +3103,6 @@ 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)
-{
-/* 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)
-
-       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);
-               }
-       }
-
-       return 0;
-}
-
 static int hpsa_controller_hard_reset(struct pci_dev *pdev,
        void * __iomem vaddr, bool use_doorbell)
 {
@@ -3138,17 +3158,17 @@ static int hpsa_controller_hard_reset(struct pci_dev *pdev,
  */
 static __devinit int hpsa_kdump_hard_reset_controller(struct pci_dev *pdev)
 {
-       u16 saved_config_space[32];
        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, i;
+       int rc;
        struct CfgTable __iomem *cfgtable;
        bool use_doorbell;
        u32 board_id;
+       u16 command_register;
 
        /* For controllers as old as the P600, this is very nearly
         * the same thing as
@@ -3158,14 +3178,6 @@ static __devinit int hpsa_kdump_hard_reset_controller(struct pci_dev *pdev)
         * 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.
@@ -3178,13 +3190,21 @@ static __devinit int hpsa_kdump_hard_reset_controller(struct pci_dev *pdev)
         * likely not be happy.  Just forbid resetting this conjoined mess.
         * The 640x isn't really supported by hpsa anyway.
         */
-       hpsa_lookup_board_id(pdev, &board_id);
+       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;
 
-       for (i = 0; i < 32; i++)
-               pci_read_config_word(pdev, 2*i, &saved_config_space[i]);
-
+       /* 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);
@@ -3210,46 +3230,47 @@ static __devinit int hpsa_kdump_hard_reset_controller(struct pci_dev *pdev)
        misc_fw_support = readl(&cfgtable->misc_fw_support);
        use_doorbell = misc_fw_support & MISC_FW_DOORBELL_RESET;
 
-       /* The doorbell reset seems to cause lockups on some Smart
-        * Arrays (e.g. P410, P410i, maybe others).  Until this is
-        * fixed or at least isolated, avoid the doorbell reset.
-        */
-       use_doorbell = 0;
-
        rc = hpsa_controller_hard_reset(pdev, vaddr, use_doorbell);
        if (rc)
                goto unmap_cfgtable;
 
-       /* 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.
-        */
-       for (i = 0; i < 32; i++) {
-               if (i == 2 || i == 3)
-                       continue;
-               pci_write_config_word(pdev, 2*i, saved_config_space[i]);
+       pci_restore_state(pdev);
+       rc = pci_enable_device(pdev);
+       if (rc) {
+               dev_warn(&pdev->dev, "failed to enable device.\n");
+               goto unmap_cfgtable;
        }
-       wmb();
-       pci_write_config_word(pdev, 4, saved_config_space[2]);
+       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");
+
        /* 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, pretend the reset worked and hope for the best.
+        * In those cases, don't try to proceed, as it generally doesn't work.
         */
        active_transport = readl(&cfgtable->TransportActive);
        if (active_transport & PERFORMANT_MODE) {
                dev_warn(&pdev->dev, "Unable to successfully reset controller,"
-                       " proceeding anyway.\n");
-               rc = -ENOTSUPP;
+                       " Ignoring controller.\n");
+               rc = -ENODEV;
        }
 
 unmap_cfgtable:
@@ -3382,7 +3403,7 @@ static void __devinit hpsa_interrupt_mode(struct ctlr_info *h)
 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] = h->pdev->irq;
+       h->intr[h->intr_mode] = h->pdev->irq;
 }
 
 static int __devinit hpsa_lookup_board_id(struct pci_dev *pdev, u32 *board_id)
@@ -3434,18 +3455,28 @@ static int __devinit hpsa_pci_find_memory_BAR(struct pci_dev *pdev,
        return -ENODEV;
 }
 
-static int __devinit hpsa_wait_for_board_ready(struct ctlr_info *h)
+static int __devinit hpsa_wait_for_board_state(struct pci_dev *pdev,
+       void __iomem *vaddr, int wait_for_ready)
 {
-       int i;
+       int i, iterations;
        u32 scratchpad;
+       if (wait_for_ready)
+               iterations = HPSA_BOARD_READY_ITERATIONS;
+       else
+               iterations = HPSA_BOARD_NOT_READY_ITERATIONS;
 
-       for (i = 0; i < HPSA_BOARD_READY_ITERATIONS; i++) {
-               scratchpad = readl(h->vaddr + SA5_SCRATCHPAD_OFFSET);
-               if (scratchpad == HPSA_FIRMWARE_READY)
-                       return 0;
+       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);
        }
-       dev_warn(&h->pdev->dev, "board not ready, timed out.\n");
+       dev_warn(&pdev->dev, "board not ready, timed out.\n");
        return -ENODEV;
 }
 
@@ -3493,6 +3524,11 @@ static int __devinit hpsa_find_cfgtables(struct ctlr_info *h)
 static void __devinit hpsa_get_max_perf_mode_cmds(struct ctlr_info *h)
 {
        h->max_commands = readl(&(h->cfgtable->MaxPerformantModeCommands));
+
+       /* 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. "
@@ -3567,16 +3603,21 @@ static inline void hpsa_p600_dma_prefetch_quirk(struct ctlr_info *h)
 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);
        }
 }
 
@@ -3599,6 +3640,7 @@ static int __devinit hpsa_enter_simple_mode(struct ctlr_info *h)
                        "unable to get board into simple mode\n");
                return -ENODEV;
        }
+       h->transMethod = CFGTBL_Trans_Simple;
        return 0;
 }
 
@@ -3637,7 +3679,7 @@ static int __devinit hpsa_pci_init(struct ctlr_info *h)
                err = -ENOMEM;
                goto err_out_free_res;
        }
-       err = hpsa_wait_for_board_ready(h);
+       err = hpsa_wait_for_board_state(h->pdev, h->vaddr, BOARD_READY);
        if (err)
                goto err_out_free_res;
        err = hpsa_find_cfgtables(h);
@@ -3706,8 +3748,6 @@ static __devinit int hpsa_init_reset_devices(struct pci_dev *pdev)
                return 0; /* just try to do the kdump anyhow. */
        if (rc)
                return -ENODEV;
-       if (hpsa_reset_msi(pdev))
-               return -ENODEV;
 
        /* Now try to get the controller to respond to a no-op */
        for (i = 0; i < HPSA_POST_RESET_NOOP_RETRIES; i++) {
@@ -3745,8 +3785,11 @@ static int __devinit hpsa_init_one(struct pci_dev *pdev,
 
        h->pdev = pdev;
        h->busy_initializing = 1;
-       INIT_HLIST_HEAD(&h->cmpQ);
-       INIT_HLIST_HEAD(&h->reqQ);
+       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;
@@ -3773,20 +3816,20 @@ static int __devinit hpsa_init_one(struct pci_dev *pdev,
        h->access.set_intr_mask(h, HPSA_INTR_OFF);
 
        if (h->msix_vector || h->msi_vector)
-               rc = request_irq(h->intr[PERF_MODE_INT], do_hpsa_intr_msi,
+               rc = request_irq(h->intr[h->intr_mode], do_hpsa_intr_msi,
                                IRQF_DISABLED, h->devname, h);
        else
-               rc = request_irq(h->intr[PERF_MODE_INT], do_hpsa_intr_intx,
+               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 -
@@ -3806,8 +3849,6 @@ static int __devinit hpsa_init_one(struct pci_dev *pdev,
        }
        if (hpsa_allocate_sg_chain_blocks(h))
                goto clean4;
-       spin_lock_init(&h->lock);
-       spin_lock_init(&h->scan_lock);
        init_waitqueue_head(&h->scan_wait_queue);
        h->scan_finished = 1; /* no scan currently in progress */
 
@@ -3839,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;
@@ -3883,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);
@@ -3985,7 +4026,8 @@ static void  calc_bucket_map(int bucket[], int num_buckets,
        }
 }
 
-static __devinit void hpsa_enter_performant_mode(struct ctlr_info *h)
+static __devinit void hpsa_enter_performant_mode(struct ctlr_info *h,
+       u32 use_short_tags)
 {
        int i;
        unsigned long register_value;
@@ -4033,7 +4075,7 @@ static __devinit void hpsa_enter_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);
        hpsa_wait_for_mode_change_ack(h);
@@ -4043,12 +4085,18 @@ static __devinit void hpsa_enter_performant_mode(struct ctlr_info *h)
                                        " 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;
@@ -4068,11 +4116,8 @@ static __devinit void hpsa_put_ctlr_into_performant_mode(struct ctlr_info *h)
                || (h->blockFetchTable == NULL))
                goto clean_up;
 
-       hpsa_enter_performant_mode(h);
-
-       /* Change the access methods to the performant access methods */
-       h->access = SA5_performant_access;
-       h->transMethod = CFGTBL_Trans_Performant;
+       hpsa_enter_performant_mode(h,
+               trans_support & CFGTBL_Trans_use_short_tags);
 
        return;