]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - drivers/scsi/hpsa.c
Merge branch 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mjg59/platf...
[mv-sheeva.git] / drivers / scsi / hpsa.c
index 9017e640e799769132faadf0fd33094ca27b9fc9..03697ba942510243de25b4f4d093605ac3c16366 100644 (file)
@@ -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.1-3"
 #define DRIVER_NAME "HP HPSA Driver (v " HPSA_DRIVER_VERSION ")"
 
 /* How long to wait (in milliseconds) for board to go into simple mode */
@@ -77,9 +77,6 @@ MODULE_PARM_DESC(hpsa_allow_any,
 
 /* 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,6 +84,9 @@ 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_DEVICE_ID_HP_CISSE,     0x103C, 0x3233},
+#define PCI_DEVICE_ID_HP_CISSF 0x333f
+       {PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSF,     0x103C, 0x333F},
        {PCI_VENDOR_ID_HP,     PCI_ANY_ID,             PCI_ANY_ID, PCI_ANY_ID,
                PCI_CLASS_STORAGE_RAID << 8, 0xffff << 8, 0},
        {0,}
@@ -99,9 +99,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,6 +106,8 @@ static struct board_type products[] = {
        {0x3249103C, "Smart Array P812", &SA5_access},
        {0x324a103C, "Smart Array P712m", &SA5_access},
        {0x324b103C, "Smart Array P711m", &SA5_access},
+       {0x3233103C, "StorageWorks P1210m", &SA5_access},
+       {0x333F103C, "StorageWorks P1210m", &SA5_access},
        {0xFFFF103C, "Unknown Smart Array", &SA5_access},
 };
 
@@ -132,6 +131,9 @@ static void fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h,
 
 static int hpsa_scsi_queue_command(struct scsi_cmnd *cmd,
                void (*done)(struct scsi_cmnd *));
+static void hpsa_scan_start(struct Scsi_Host *);
+static int hpsa_scan_finished(struct Scsi_Host *sh,
+       unsigned long elapsed_time);
 
 static int hpsa_eh_device_reset_handler(struct scsi_cmnd *scsicmd);
 static int hpsa_slave_alloc(struct scsi_device *sdev);
@@ -150,6 +152,11 @@ static int check_for_unit_attention(struct ctlr_info *h,
        struct CommandList *c);
 static void check_ioctl_unit_attention(struct ctlr_info *h,
        struct CommandList *c);
+/* 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 inline u32 next_command(struct ctlr_info *h);
 
 static DEVICE_ATTR(raid_level, S_IRUGO, raid_level_show, NULL);
 static DEVICE_ATTR(lunid, S_IRUGO, lunid_show, NULL);
@@ -173,10 +180,10 @@ static struct scsi_host_template hpsa_driver_template = {
        .name                   = "hpsa",
        .proc_name              = "hpsa",
        .queuecommand           = hpsa_scsi_queue_command,
-       .can_queue              = 512,
+       .scan_start             = hpsa_scan_start,
+       .scan_finished          = hpsa_scan_finished,
        .this_id                = -1,
        .sg_tablesize           = MAXSGENTRIES,
-       .cmd_per_lun            = 512,
        .use_clustering         = ENABLE_CLUSTERING,
        .eh_device_reset_handler = hpsa_eh_device_reset_handler,
        .ioctl                  = hpsa_ioctl,
@@ -195,6 +202,12 @@ static inline struct ctlr_info *sdev_to_hba(struct scsi_device *sdev)
        return (struct ctlr_info *) *priv;
 }
 
+static inline struct ctlr_info *shost_to_hba(struct Scsi_Host *sh)
+{
+       unsigned long *priv = shost_priv(sh);
+       return (struct ctlr_info *) *priv;
+}
+
 static struct task_struct *hpsa_scan_thread;
 static DEFINE_MUTEX(hpsa_scan_mutex);
 static LIST_HEAD(hpsa_scan_q);
@@ -312,7 +325,7 @@ static int hpsa_scan_func(__attribute__((unused)) void *data)
                        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);
+                       hpsa_scan_start(h->scsi_host);
                        complete_all(&h->scan_wait);
                        mutex_lock(&hpsa_scan_mutex);
                        h->busy_scanning = 0;
@@ -379,8 +392,7 @@ 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;
+       h = shost_to_hba(shost);
        if (add_to_scan_list(h)) {
                wake_up_process(hpsa_scan_thread);
                wait_for_completion_interruptible(&h->scan_wait);
@@ -394,10 +406,44 @@ static inline void addQ(struct hlist_head *list, struct CommandList *c)
        hlist_add_head(&c->list, list);
 }
 
+static inline u32 next_command(struct ctlr_info *h)
+{
+       u32 a;
+
+       if (unlikely(h->transMethod != CFGTBL_Trans_Performant))
+               return h->access.command_completed(h);
+
+       if ((*(h->reply_pool_head) & 1) == (h->reply_pool_wraparound)) {
+               a = *(h->reply_pool_head); /* Next cmd in ring buffer */
+               (h->reply_pool_head)++;
+               h->commands_outstanding--;
+       } else {
+               a = FIFO_EMPTY;
+       }
+       /* Check for wraparound */
+       if (h->reply_pool_head == (h->reply_pool + h->max_commands)) {
+               h->reply_pool_head = h->reply_pool;
+               h->reply_pool_wraparound ^= 1;
+       }
+       return a;
+}
+
+/* set_performant_mode: Modify the tag for cciss performant
+ * set bit 0 for pull model, bits 3-1 for block fetch
+ * register number
+ */
+static void set_performant_mode(struct ctlr_info *h, struct CommandList *c)
+{
+       if (likely(h->transMethod == CFGTBL_Trans_Performant))
+               c->busaddr |= 1 | (h->blockFetchTable[c->Header.SGList] << 1);
+}
+
 static void enqueue_cmd_and_start_io(struct ctlr_info *h,
        struct CommandList *c)
 {
        unsigned long flags;
+
+       set_performant_mode(h, c);
        spin_lock_irqsave(&h->lock, flags);
        addQ(&h->reqQ, c);
        h->Qdepth++;
@@ -422,6 +468,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"
 };
@@ -620,6 +675,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)
@@ -721,6 +794,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]))
@@ -778,12 +853,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++;
        }
@@ -984,7 +1059,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 "
@@ -992,14 +1066,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,
@@ -1007,7 +1089,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;
                }
 
@@ -1083,7 +1168,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;
@@ -1116,9 +1201,11 @@ static int hpsa_scsi_detect(struct ctlr_info *h)
        sh->max_cmd_len = MAX_COMMAND_SIZE;
        sh->max_lun = HPSA_MAX_LUN;
        sh->max_id = HPSA_MAX_LUN;
+       sh->can_queue = h->nr_cmds;
+       sh->cmd_per_lun = h->nr_cmds;
        h->scsi_host = sh;
        sh->hostdata[0] = (unsigned long) h;
-       sh->irq = h->intr[SIMPLE_MODE_INT];
+       sh->irq = h->intr[PERF_MODE_INT];
        sh->unique_id = sh->irq;
        error = scsi_add_host(sh, &h->pdev->dev);
        if (error)
@@ -1130,11 +1217,11 @@ static int hpsa_scsi_detect(struct ctlr_info *h)
        dev_err(&h->pdev->dev, "hpsa_scsi_detect: scsi_add_host"
                " failed for controller %d\n", h->ctlr);
        scsi_host_put(sh);
-       return -1;
+       return error;
  fail:
        dev_err(&h->pdev->dev, "hpsa_scsi_detect: scsi_host_alloc"
                " failed for controller %d\n", h->ctlr);
-       return -1;
+       return -ENOMEM;
 }
 
 static void hpsa_pci_unmap(struct pci_dev *pdev,
@@ -1271,7 +1358,7 @@ static int hpsa_scsi_do_inquiry(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_INQUIRY, h, buf, bufsize, page, scsi3addr, TYPE_CMD);
@@ -1363,9 +1450,8 @@ static int hpsa_scsi_do_report_luns(struct ctlr_info *h, int logical,
                dev_err(&h->pdev->dev, "cmd_special_alloc returned NULL!\n");
                return -1;
        }
-
-       memset(&scsi3addr[0], 0, 8); /* address the controller */
-
+       /* address the controller */
+       memset(scsi3addr, 0, sizeof(scsi3addr));
        fill_cmd(c, logical ? HPSA_REPORT_LOG : HPSA_REPORT_PHYS, h,
                buf, bufsize, 0, scsi3addr, TYPE_CMD);
        if (extended_response)
@@ -1406,13 +1492,12 @@ static int hpsa_update_device_info(struct ctlr_info *h,
        unsigned char scsi3addr[], struct hpsa_scsi_dev_t *this_device)
 {
 #define OBDR_TAPE_INQ_SIZE 49
-       unsigned char *inq_buff = NULL;
+       unsigned char *inq_buff;
 
-       inq_buff = kmalloc(OBDR_TAPE_INQ_SIZE, GFP_KERNEL);
+       inq_buff = kzalloc(OBDR_TAPE_INQ_SIZE, GFP_KERNEL);
        if (!inq_buff)
                goto bail_out;
 
-       memset(inq_buff, 0, OBDR_TAPE_INQ_SIZE);
        /* Do an inquiry to the device to see what it is. */
        if (hpsa_scsi_do_inquiry(h, scsi3addr, 0, inq_buff,
                (unsigned char) OBDR_TAPE_INQ_SIZE) != 0) {
@@ -1485,29 +1570,48 @@ static void figure_bus_target_lun(struct ctlr_info *h,
        u8 *lunaddrbytes, int *bus, int *target, int *lun,
        struct hpsa_scsi_dev_t *device)
 {
-
        u32 lunid;
 
        if (is_logical_dev_addr_mode(lunaddrbytes)) {
                /* logical device */
-               memcpy(&lunid, lunaddrbytes, sizeof(lunid));
-               lunid = le32_to_cpu(lunid);
-
-               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. */
        }
@@ -1547,6 +1651,9 @@ static int add_msa2xxx_enclosure_device(struct ctlr_info *h,
        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 "
@@ -1580,11 +1687,7 @@ static int hpsa_gather_lun_info(struct ctlr_info *h,
                dev_err(&h->pdev->dev, "report physical LUNs failed.\n");
                return -1;
        }
-       memcpy(nphysicals, &physdev->LUNListLength[0], sizeof(*nphysicals));
-       *nphysicals = be32_to_cpu(*nphysicals) / 8;
-#ifdef DEBUG
-       dev_info(&h->pdev->dev, "number of physical luns is %d\n", *nphysicals);
-#endif
+       *nphysicals = be32_to_cpu(*((__be32 *)physdev->LUNListLength)) / 8;
        if (*nphysicals > HPSA_MAX_PHYS_LUN) {
                dev_warn(&h->pdev->dev, "maximum physical LUNs (%d) exceeded."
                        "  %d LUNs ignored.\n", HPSA_MAX_PHYS_LUN,
@@ -1595,11 +1698,7 @@ static int hpsa_gather_lun_info(struct ctlr_info *h,
                dev_err(&h->pdev->dev, "report logical LUNs failed.\n");
                return -1;
        }
-       memcpy(nlogicals, &logdev->LUNListLength[0], sizeof(*nlogicals));
-       *nlogicals = be32_to_cpu(*nlogicals) / 8;
-#ifdef DEBUG
-       dev_info(&h->pdev->dev, "number of logical luns is %d\n", *nlogicals);
-#endif
+       *nlogicals = be32_to_cpu(*((__be32 *) logdev->LUNListLength)) / 8;
        /* Reject Logicals in excess of our max capability. */
        if (*nlogicals > HPSA_MAX_LUN) {
                dev_warn(&h->pdev->dev,
@@ -1618,6 +1717,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
@@ -1641,6 +1765,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,
@@ -1678,23 +1803,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 */
@@ -1856,7 +1980,8 @@ static int hpsa_scsi_queue_command(struct scsi_cmnd *cmd,
        c->scsi_cmd = cmd;
        c->Header.ReplyQueue = 0;  /* unused in simple mode */
        memcpy(&c->Header.LUN.LunAddrBytes[0], &scsi3addr[0], 8);
-       c->Header.Tag.lower = c->busaddr;  /* Use k. address of cmd as tag */
+       c->Header.Tag.lower = (c->cmdindex << DIRECT_LOOKUP_SHIFT);
+       c->Header.Tag.lower |= DIRECT_LOOKUP_BIT;
 
        /* Fill in the request block... */
 
@@ -1910,6 +2035,48 @@ static int hpsa_scsi_queue_command(struct scsi_cmnd *cmd,
        return 0;
 }
 
+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 void hpsa_unregister_scsi(struct ctlr_info *h)
 {
        /* we are being forcibly unloaded, and may not refuse. */
@@ -1922,7 +2089,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"
@@ -1999,14 +2165,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)
@@ -2121,50 +2287,6 @@ static void cmd_special_free(struct ctlr_info *h, struct CommandList *c)
 
 #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 =
@@ -2189,7 +2311,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,
@@ -2226,7 +2348,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,
@@ -2235,6 +2357,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)
@@ -2523,7 +2675,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);
@@ -2706,15 +2858,16 @@ static inline unsigned long get_next_completion(struct ctlr_info *h)
        return h->access.command_completed(h);
 }
 
-static inline int interrupt_pending(struct ctlr_info *h)
+static inline bool interrupt_pending(struct ctlr_info *h)
 {
        return h->access.intr_pending(h);
 }
 
 static inline long interrupt_not_for_us(struct ctlr_info *h)
 {
-       return ((h->access.intr_pending(h) == 0) ||
-                (h->interrupts_enabled == 0));
+       return !(h->msi_vector || h->msix_vector) &&
+               ((h->access.intr_pending(h) == 0) ||
+               (h->interrupts_enabled == 0));
 }
 
 static inline int bad_tag(struct ctlr_info *h, u32 tag_index,
@@ -2736,42 +2889,79 @@ static inline void finish_cmd(struct CommandList *c, u32 raw_tag)
                complete(c->waiting);
 }
 
+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)
+{
+#define HPSA_ERROR_BITS 0x03
+       return tag & ~HPSA_ERROR_BITS;
+}
+
+/* process completion of an indexed ("direct lookup") command */
+static inline u32 process_indexed_cmd(struct ctlr_info *h,
+       u32 raw_tag)
+{
+       u32 tag_index;
+       struct CommandList *c;
+
+       tag_index = hpsa_tag_to_index(raw_tag);
+       if (bad_tag(h, tag_index, raw_tag))
+               return next_command(h);
+       c = h->cmd_pool + tag_index;
+       finish_cmd(c, raw_tag);
+       return next_command(h);
+}
+
+/* process completion of a non-indexed command */
+static inline u32 process_nonindexed_cmd(struct ctlr_info *h,
+       u32 raw_tag)
+{
+       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) {
+               if ((c->busaddr & 0xFFFFFFE0) == (tag & 0xFFFFFFE0)) {
+                       finish_cmd(c, raw_tag);
+                       return next_command(h);
+               }
+       }
+       bad_tag(h, h->nr_cmds + 1, raw_tag);
+       return next_command(h);
+}
+
 static irqreturn_t do_hpsa_intr(int irq, void *dev_id)
 {
        struct ctlr_info *h = dev_id;
-       struct CommandList *c;
        unsigned long flags;
-       u32 raw_tag, tag, tag_index;
-       struct hlist_node *tmp;
+       u32 raw_tag;
 
        if (interrupt_not_for_us(h))
                return IRQ_NONE;
        spin_lock_irqsave(&h->lock, flags);
-       while (interrupt_pending(h)) {
-               while ((raw_tag = get_next_completion(h)) != FIFO_EMPTY) {
-                       if (likely(HPSA_TAG_CONTAINS_INDEX(raw_tag))) {
-                               tag_index = HPSA_TAG_TO_INDEX(raw_tag);
-                               if (bad_tag(h, tag_index, raw_tag))
-                                       return IRQ_HANDLED;
-                               c = h->cmd_pool + tag_index;
-                               finish_cmd(c, raw_tag);
-                               continue;
-                       }
-                       tag = HPSA_TAG_DISCARD_ERROR_BITS(raw_tag);
-                       c = NULL;
-                       hlist_for_each_entry(c, tmp, &h->cmpQ, list) {
-                               if (c->busaddr == tag) {
-                                       finish_cmd(c, raw_tag);
-                                       break;
-                               }
-                       }
-               }
+       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;
 }
 
-/* Send a message CDB to the firmware. */
+/* Send a message CDB to the firmwart. */
 static __devinit int hpsa_message(struct pci_dev *pdev, unsigned char opcode,
                                                unsigned char type)
 {
@@ -2837,7 +3027,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 (hpsa_tag_discard_error_bits(tag) == paddr32)
                        break;
                msleep(HPSA_MSG_SEND_RETRY_INTERVAL_MSECS);
        }
@@ -3103,7 +3293,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[SIMPLE_MODE_INT] = pdev->irq;
+       h->intr[PERF_MODE_INT] = pdev->irq;
 }
 
 static int hpsa_pci_init(struct ctlr_info *h, struct pci_dev *pdev)
@@ -3113,6 +3303,7 @@ static int hpsa_pci_init(struct ctlr_info *h, struct pci_dev *pdev)
        u64 cfg_offset;
        u32 cfg_base_addr;
        u64 cfg_base_addr_index;
+       u32 trans_offset;
        int i, prod_index, err;
 
        subsystem_vendor_id = pdev->subsystem_vendor;
@@ -3206,11 +3397,14 @@ static int hpsa_pci_init(struct ctlr_info *h, struct pci_dev *pdev)
        h->cfgtable = remap_pci_mem(pci_resource_start(pdev,
                               cfg_base_addr_index) + cfg_offset,
                                sizeof(h->cfgtable));
-       h->board_id = board_id;
-
-       /* Query controller for max supported commands: */
-       h->max_commands = readl(&(h->cfgtable->CmdsOutMax));
+       /* Find performant mode table. */
+       trans_offset = readl(&(h->cfgtable->TransMethodOffset));
+       h->transtable = remap_pci_mem(pci_resource_start(pdev,
+                               cfg_base_addr_index)+cfg_offset+trans_offset,
+                               sizeof(*h->transtable));
 
+       h->board_id = board_id;
+       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 */
@@ -3281,10 +3475,26 @@ err_out_free_res:
        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 int __devinit hpsa_init_one(struct pci_dev *pdev,
                                    const struct pci_device_id *ent)
 {
-       int i;
+       int i, rc;
        int dac;
        struct ctlr_info *h;
 
@@ -3309,17 +3519,23 @@ static int __devinit hpsa_init_one(struct pci_dev *pdev,
                }
        }
 
-       BUILD_BUG_ON(sizeof(struct CommandList) % 8);
+       /* 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
+        * the driver.  See comments in hpsa.h for more info.
+        */
+#define COMMANDLIST_ALIGNMENT 32
+       BUILD_BUG_ON(sizeof(struct CommandList) % COMMANDLIST_ALIGNMENT);
        h = kzalloc(sizeof(*h), GFP_KERNEL);
        if (!h)
-               return -1;
+               return -ENOMEM;
 
        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);
-       if (hpsa_pci_init(h, pdev) != 0)
+       rc = hpsa_pci_init(h, pdev);
+       if (rc != 0)
                goto clean1;
 
        sprintf(h->devname, "hpsa%d", number_of_controllers);
@@ -3328,27 +3544,32 @@ static int __devinit hpsa_init_one(struct pci_dev *pdev,
        h->pdev = pdev;
 
        /* configure PCI DMA stuff */
-       if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(64)))
+       rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(64));
+       if (rc == 0) {
                dac = 1;
-       else if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32)))
-               dac = 0;
-       else {
-               dev_err(&pdev->dev, "no suitable DMA available\n");
-               goto clean1;
+       } else {
+               rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
+               if (rc == 0) {
+                       dac = 0;
+               } else {
+                       dev_err(&pdev->dev, "no suitable DMA available\n");
+                       goto clean1;
+               }
        }
 
        /* make sure the board interrupts are off */
        h->access.set_intr_mask(h, HPSA_INTR_OFF);
-       if (request_irq(h->intr[SIMPLE_MODE_INT], do_hpsa_intr,
-                       IRQF_DISABLED | IRQF_SHARED, h->devname, h)) {
+       rc = request_irq(h->intr[PERF_MODE_INT], do_hpsa_intr,
+                       IRQF_DISABLED, h->devname, h);
+       if (rc) {
                dev_err(&pdev->dev, "unable to get irq %d for %s\n",
-                      h->intr[SIMPLE_MODE_INT], h->devname);
+                      h->intr[PERF_MODE_INT], h->devname);
                goto clean2;
        }
 
-       dev_info(&pdev->dev, "%s: <0x%x> at PCI %s IRQ %d%s using DAC\n",
-              h->devname, pdev->device, pci_name(pdev),
-              h->intr[SIMPLE_MODE_INT], dac ? "" : " not");
+       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->cmd_pool_bits =
            kmalloc(((h->nr_cmds + BITS_PER_LONG -
@@ -3363,9 +3584,13 @@ static int __devinit hpsa_init_one(struct pci_dev *pdev,
            || (h->cmd_pool == NULL)
            || (h->errinfo_pool == NULL)) {
                dev_err(&pdev->dev, "out of memory");
+               rc = -ENOMEM;
                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 */
 
        pci_set_drvdata(pdev, h);
        memset(h->cmd_pool_bits, 0,
@@ -3377,6 +3602,8 @@ static int __devinit hpsa_init_one(struct pci_dev *pdev,
        /* Turn the interrupts on so we can service requests */
        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;
@@ -3392,12 +3619,12 @@ clean4:
                            h->nr_cmds * sizeof(struct ErrorInfo),
                            h->errinfo_pool,
                            h->errinfo_pool_dhandle);
-       free_irq(h->intr[SIMPLE_MODE_INT], h);
+       free_irq(h->intr[PERF_MODE_INT], h);
 clean2:
 clean1:
        h->busy_initializing = 0;
        kfree(h);
-       return -1;
+       return rc;
 }
 
 static void hpsa_flush_cache(struct ctlr_info *h)
@@ -3436,7 +3663,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[2], h);
+       free_irq(h->intr[PERF_MODE_INT], h);
 #ifdef CONFIG_PCI_MSI
        if (h->msix_vector)
                pci_disable_msix(h->pdev);
@@ -3465,7 +3692,11 @@ static void __devexit hpsa_remove_one(struct pci_dev *pdev)
        pci_free_consistent(h->pdev,
                h->nr_cmds * sizeof(struct ErrorInfo),
                h->errinfo_pool, h->errinfo_pool_dhandle);
+       pci_free_consistent(h->pdev, h->reply_pool_size,
+               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
@@ -3497,6 +3728,129 @@ static struct pci_driver hpsa_pci_driver = {
        .resume = hpsa_resume,
 };
 
+/* Fill in bucket_map[], given nsgs (the max number of
+ * scatter gather elements supported) and bucket[],
+ * which is an array of 8 integers.  The bucket[] array
+ * contains 8 different DMA transfer sizes (in 16
+ * byte increments) which the controller uses to fetch
+ * commands.  This function fills in bucket_map[], which
+ * maps a given number of scatter gather elements to one of
+ * the 8 DMA transfer sizes.  The point of it is to allow the
+ * controller to only do as much DMA as needed to fetch the
+ * command, with the DMA transfer size encoded in the lower
+ * bits of the command address.
+ */
+static void  calc_bucket_map(int bucket[], int num_buckets,
+       int nsgs, int *bucket_map)
+{
+       int i, j, b, size;
+
+       /* even a command with 0 SGs requires 4 blocks */
+#define MINIMUM_TRANSFER_BLOCKS 4
+#define NUM_BUCKETS 8
+       /* Note, bucket_map must have nsgs+1 entries. */
+       for (i = 0; i <= nsgs; i++) {
+               /* Compute size of a command with i SG entries */
+               size = i + MINIMUM_TRANSFER_BLOCKS;
+               b = num_buckets; /* Assume the biggest bucket */
+               /* Find the bucket that is just big enough */
+               for (j = 0; j < 8; j++) {
+                       if (bucket[j] >= size) {
+                               b = j;
+                               break;
+                       }
+               }
+               /* for a command with i SG entries, use bucket b. */
+               bucket_map[i] = b;
+       }
+}
+
+static void hpsa_put_ctlr_into_performant_mode(struct ctlr_info *h)
+{
+       u32 trans_support;
+       u64 trans_offset;
+       /*  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 */
+
+       /* Controller spec: zero out this buffer. */
+       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++)
+               writel(bft[i], &h->transtable->BlockFetch[i]);
+
+       /* size of controller ring buffer */
+       writel(h->max_commands, &h->transtable->RepQSize);
+       writel(1, &h->transtable->RepQCount);
+       writel(0, &h->transtable->RepQCtrAddrLow32);
+       writel(0, &h->transtable->RepQCtrAddrHigh32);
+       writel(h->reply_pool_dhandle, &h->transtable->RepQAddr0Low32);
+       writel(0, &h->transtable->RepQAddr0High32);
+       writel(CFGTBL_Trans_Performant,
+               &(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);
+       }
+       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;
+
+       return;
+
+clean_up:
+       if (h->reply_pool)
+               pci_free_consistent(h->pdev, h->reply_pool_size,
+                       h->reply_pool, h->reply_pool_dhandle);
+       kfree(h->blockFetchTable);
+}
+
 /*
  *  This is it.  Register the PCI driver information for the cards we control
  *  the OS will call our registered routines when it finds one of our cards.