Merge branch 'for-2.6.36' of git://git.kernel.dk/linux-2.6-block
[pandora-kernel.git] / drivers / block / cciss.c
index e1e7143..31064df 100644 (file)
 #include <linux/kthread.h>
 
 #define CCISS_DRIVER_VERSION(maj,min,submin) ((maj<<16)|(min<<8)|(submin))
 #include <linux/kthread.h>
 
 #define CCISS_DRIVER_VERSION(maj,min,submin) ((maj<<16)|(min<<8)|(submin))
-#define DRIVER_NAME "HP CISS Driver (v 3.6.20)"
-#define DRIVER_VERSION CCISS_DRIVER_VERSION(3, 6, 20)
+#define DRIVER_NAME "HP CISS Driver (v 3.6.26)"
+#define DRIVER_VERSION CCISS_DRIVER_VERSION(3, 6, 26)
 
 /* Embedded module documentation macros - see modules.h */
 MODULE_AUTHOR("Hewlett-Packard Company");
 MODULE_DESCRIPTION("Driver for HP Smart Array Controllers");
 
 /* Embedded module documentation macros - see modules.h */
 MODULE_AUTHOR("Hewlett-Packard Company");
 MODULE_DESCRIPTION("Driver for HP Smart Array Controllers");
-MODULE_SUPPORTED_DEVICE("HP SA5i SA5i+ SA532 SA5300 SA5312 SA641 SA642 SA6400"
-                       " SA6i P600 P800 P400 P400i E200 E200i E500 P700m"
-                       " Smart Array G2 Series SAS/SATA Controllers");
-MODULE_VERSION("3.6.20");
+MODULE_SUPPORTED_DEVICE("HP Smart Array Controllers");
+MODULE_VERSION("3.6.26");
 MODULE_LICENSE("GPL");
 
 static int cciss_allow_hpsa;
 MODULE_LICENSE("GPL");
 
 static int cciss_allow_hpsa;
@@ -107,6 +105,11 @@ static const struct pci_device_id cciss_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, 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, 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},
        {0,}
 };
 
        {0,}
 };
 
@@ -146,6 +149,11 @@ static struct board_type products[] = {
        {0x3249103C, "Smart Array P812", &SA5_access},
        {0x324A103C, "Smart Array P712m", &SA5_access},
        {0x324B103C, "Smart Array P711m", &SA5_access},
        {0x3249103C, "Smart Array P812", &SA5_access},
        {0x324A103C, "Smart Array P712m", &SA5_access},
        {0x324B103C, "Smart Array P711m", &SA5_access},
+       {0x3250103C, "Smart Array", &SA5_access},
+       {0x3251103C, "Smart Array", &SA5_access},
+       {0x3252103C, "Smart Array", &SA5_access},
+       {0x3253103C, "Smart Array", &SA5_access},
+       {0x3254103C, "Smart Array", &SA5_access},
 };
 
 /* How long to wait (in milliseconds) for board to go into simple mode */
 };
 
 /* How long to wait (in milliseconds) for board to go into simple mode */
@@ -167,9 +175,13 @@ static DEFINE_MUTEX(scan_mutex);
 static LIST_HEAD(scan_q);
 
 static void do_cciss_request(struct request_queue *q);
 static LIST_HEAD(scan_q);
 
 static void do_cciss_request(struct request_queue *q);
-static irqreturn_t do_cciss_intr(int irq, void *dev_id);
+static irqreturn_t do_cciss_intx(int irq, void *dev_id);
+static irqreturn_t do_cciss_msix_intr(int irq, void *dev_id);
 static int cciss_open(struct block_device *bdev, fmode_t mode);
 static int cciss_open(struct block_device *bdev, fmode_t mode);
+static int cciss_unlocked_open(struct block_device *bdev, fmode_t mode);
 static int cciss_release(struct gendisk *disk, fmode_t mode);
 static int cciss_release(struct gendisk *disk, fmode_t mode);
+static int do_ioctl(struct block_device *bdev, fmode_t mode,
+                   unsigned int cmd, unsigned long arg);
 static int cciss_ioctl(struct block_device *bdev, fmode_t mode,
                       unsigned int cmd, unsigned long arg);
 static int cciss_getgeo(struct block_device *bdev, struct hd_geometry *geo);
 static int cciss_ioctl(struct block_device *bdev, fmode_t mode,
                       unsigned int cmd, unsigned long arg);
 static int cciss_getgeo(struct block_device *bdev, struct hd_geometry *geo);
@@ -179,25 +191,23 @@ static int rebuild_lun_table(ctlr_info_t *h, int first_time, int via_ioctl);
 static int deregister_disk(ctlr_info_t *h, int drv_index,
                           int clear_all, int via_ioctl);
 
 static int deregister_disk(ctlr_info_t *h, int drv_index,
                           int clear_all, int via_ioctl);
 
-static void cciss_read_capacity(int ctlr, int logvol,
+static void cciss_read_capacity(ctlr_info_t *h, int logvol,
                        sector_t *total_size, unsigned int *block_size);
                        sector_t *total_size, unsigned int *block_size);
-static void cciss_read_capacity_16(int ctlr, int logvol,
+static void cciss_read_capacity_16(ctlr_info_t *h, int logvol,
                        sector_t *total_size, unsigned int *block_size);
                        sector_t *total_size, unsigned int *block_size);
-static void cciss_geometry_inquiry(int ctlr, int logvol,
+static void cciss_geometry_inquiry(ctlr_info_t *h, int logvol,
                        sector_t total_size,
                        unsigned int block_size, InquiryData_struct *inq_buff,
                                   drive_info_struct *drv);
                        sector_t total_size,
                        unsigned int block_size, InquiryData_struct *inq_buff,
                                   drive_info_struct *drv);
-static void __devinit cciss_interrupt_mode(ctlr_info_t *, struct pci_dev *,
-                                          __u32);
+static void __devinit cciss_interrupt_mode(ctlr_info_t *);
 static void start_io(ctlr_info_t *h);
 static void start_io(ctlr_info_t *h);
-static int sendcmd_withirq(__u8 cmd, int ctlr, void *buff, size_t size,
+static int sendcmd_withirq(ctlr_info_t *h, __u8 cmd, void *buff, size_t size,
                        __u8 page_code, unsigned char scsi3addr[],
                        int cmd_type);
 static int sendcmd_withirq_core(ctlr_info_t *h, CommandList_struct *c,
        int attempt_retry);
 static int process_sendcmd_error(ctlr_info_t *h, CommandList_struct *c);
 
                        __u8 page_code, unsigned char scsi3addr[],
                        int cmd_type);
 static int sendcmd_withirq_core(ctlr_info_t *h, CommandList_struct *c,
        int attempt_retry);
 static int process_sendcmd_error(ctlr_info_t *h, CommandList_struct *c);
 
-static void fail_all_cmds(unsigned long ctlr);
 static int add_to_scan_list(struct ctlr_info *h);
 static int scan_thread(void *data);
 static int check_for_unit_attention(ctlr_info_t *h, CommandList_struct *c);
 static int add_to_scan_list(struct ctlr_info *h);
 static int scan_thread(void *data);
 static int check_for_unit_attention(ctlr_info_t *h, CommandList_struct *c);
@@ -205,11 +215,23 @@ static void cciss_hba_release(struct device *dev);
 static void cciss_device_release(struct device *dev);
 static void cciss_free_gendisk(ctlr_info_t *h, int drv_index);
 static void cciss_free_drive_info(ctlr_info_t *h, int drv_index);
 static void cciss_device_release(struct device *dev);
 static void cciss_free_gendisk(ctlr_info_t *h, int drv_index);
 static void cciss_free_drive_info(ctlr_info_t *h, int drv_index);
+static inline u32 next_command(ctlr_info_t *h);
+static int __devinit cciss_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 cciss_pci_find_memory_BAR(struct pci_dev *pdev,
+       unsigned long *memory_bar);
+
+
+/* performant mode helper functions */
+static void  calc_bucket_map(int *bucket, int num_buckets, int nsgs,
+                               int *bucket_map);
+static void cciss_put_controller_into_performant_mode(ctlr_info_t *h);
 
 #ifdef CONFIG_PROC_FS
 
 #ifdef CONFIG_PROC_FS
-static void cciss_procinit(int i);
+static void cciss_procinit(ctlr_info_t *h);
 #else
 #else
-static void cciss_procinit(int i)
+static void cciss_procinit(ctlr_info_t *h)
 {
 }
 #endif                         /* CONFIG_PROC_FS */
 {
 }
 #endif                         /* CONFIG_PROC_FS */
@@ -221,9 +243,9 @@ static int cciss_compat_ioctl(struct block_device *, fmode_t,
 
 static const struct block_device_operations cciss_fops = {
        .owner = THIS_MODULE,
 
 static const struct block_device_operations cciss_fops = {
        .owner = THIS_MODULE,
-       .open = cciss_open,
+       .open = cciss_unlocked_open,
        .release = cciss_release,
        .release = cciss_release,
-       .locked_ioctl = cciss_ioctl,
+       .ioctl = do_ioctl,
        .getgeo = cciss_getgeo,
 #ifdef CONFIG_COMPAT
        .compat_ioctl = cciss_compat_ioctl,
        .getgeo = cciss_getgeo,
 #ifdef CONFIG_COMPAT
        .compat_ioctl = cciss_compat_ioctl,
@@ -231,6 +253,16 @@ static const struct block_device_operations cciss_fops = {
        .revalidate_disk = cciss_revalidate,
 };
 
        .revalidate_disk = cciss_revalidate,
 };
 
+/* 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(ctlr_info_t *h, CommandList_struct *c)
+{
+       if (likely(h->transMethod == CFGTBL_Trans_Performant))
+               c->busaddr |= 1 | (h->blockFetchTable[c->Header.SGList] << 1);
+}
+
 /*
  * Enqueuing and dequeuing functions for cmdlists.
  */
 /*
  * Enqueuing and dequeuing functions for cmdlists.
  */
@@ -257,6 +289,18 @@ static inline void removeQ(CommandList_struct *c)
        hlist_del_init(&c->list);
 }
 
        hlist_del_init(&c->list);
 }
 
+static void enqueue_cmd_and_start_io(ctlr_info_t *h,
+       CommandList_struct *c)
+{
+       unsigned long flags;
+       set_performant_mode(h, c);
+       spin_lock_irqsave(&h->lock, flags);
+       addQ(&h->reqQ, c);
+       h->Qdepth++;
+       start_io(h);
+       spin_unlock_irqrestore(&h->lock, flags);
+}
+
 static void cciss_free_sg_chain_blocks(SGDescriptor_struct **cmd_sg_list,
        int nr_cmds)
 {
 static void cciss_free_sg_chain_blocks(SGDescriptor_struct **cmd_sg_list,
        int nr_cmds)
 {
@@ -366,32 +410,31 @@ static void cciss_seq_show_header(struct seq_file *seq)
                h->product_name,
                (unsigned long)h->board_id,
                h->firm_ver[0], h->firm_ver[1], h->firm_ver[2],
                h->product_name,
                (unsigned long)h->board_id,
                h->firm_ver[0], h->firm_ver[1], h->firm_ver[2],
-               h->firm_ver[3], (unsigned int)h->intr[SIMPLE_MODE_INT],
+               h->firm_ver[3], (unsigned int)h->intr[PERF_MODE_INT],
                h->num_luns,
                h->Qdepth, h->commands_outstanding,
                h->maxQsinceinit, h->max_outstanding, h->maxSG);
 
 #ifdef CONFIG_CISS_SCSI_TAPE
                h->num_luns,
                h->Qdepth, h->commands_outstanding,
                h->maxQsinceinit, h->max_outstanding, h->maxSG);
 
 #ifdef CONFIG_CISS_SCSI_TAPE
-       cciss_seq_tape_report(seq, h->ctlr);
+       cciss_seq_tape_report(seq, h);
 #endif /* CONFIG_CISS_SCSI_TAPE */
 }
 
 static void *cciss_seq_start(struct seq_file *seq, loff_t *pos)
 {
        ctlr_info_t *h = seq->private;
 #endif /* CONFIG_CISS_SCSI_TAPE */
 }
 
 static void *cciss_seq_start(struct seq_file *seq, loff_t *pos)
 {
        ctlr_info_t *h = seq->private;
-       unsigned ctlr = h->ctlr;
        unsigned long flags;
 
        /* prevent displaying bogus info during configuration
         * or deconfiguration of a logical volume
         */
        unsigned long flags;
 
        /* prevent displaying bogus info during configuration
         * or deconfiguration of a logical volume
         */
-       spin_lock_irqsave(CCISS_LOCK(ctlr), flags);
+       spin_lock_irqsave(&h->lock, flags);
        if (h->busy_configuring) {
        if (h->busy_configuring) {
-               spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
+               spin_unlock_irqrestore(&h->lock, flags);
                return ERR_PTR(-EBUSY);
        }
        h->busy_configuring = 1;
                return ERR_PTR(-EBUSY);
        }
        h->busy_configuring = 1;
-       spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
+       spin_unlock_irqrestore(&h->lock, flags);
 
        if (*pos == 0)
                cciss_seq_show_header(seq);
 
        if (*pos == 0)
                cciss_seq_show_header(seq);
@@ -499,7 +542,7 @@ cciss_proc_write(struct file *file, const char __user *buf,
                struct seq_file *seq = file->private_data;
                ctlr_info_t *h = seq->private;
 
                struct seq_file *seq = file->private_data;
                ctlr_info_t *h = seq->private;
 
-               err = cciss_engage_scsi(h->ctlr);
+               err = cciss_engage_scsi(h);
                if (err == 0)
                        err = length;
        } else
                if (err == 0)
                        err = length;
        } else
@@ -522,7 +565,7 @@ static const struct file_operations cciss_proc_fops = {
        .write   = cciss_proc_write,
 };
 
        .write   = cciss_proc_write,
 };
 
-static void __devinit cciss_procinit(int i)
+static void __devinit cciss_procinit(ctlr_info_t *h)
 {
        struct proc_dir_entry *pde;
 
 {
        struct proc_dir_entry *pde;
 
@@ -530,9 +573,9 @@ static void __devinit cciss_procinit(int i)
                proc_cciss = proc_mkdir("driver/cciss", NULL);
        if (!proc_cciss)
                return;
                proc_cciss = proc_mkdir("driver/cciss", NULL);
        if (!proc_cciss)
                return;
-       pde = proc_create_data(hba[i]->devname, S_IWUSR | S_IRUSR | S_IRGRP |
+       pde = proc_create_data(h->devname, S_IWUSR | S_IRUSR | S_IRGRP |
                                        S_IROTH, proc_cciss,
                                        S_IROTH, proc_cciss,
-                                       &cciss_proc_fops, hba[i]);
+                                       &cciss_proc_fops, h);
 }
 #endif                         /* CONFIG_PROC_FS */
 
 }
 #endif                         /* CONFIG_PROC_FS */
 
@@ -565,12 +608,12 @@ static ssize_t dev_show_unique_id(struct device *dev,
        unsigned long flags;
        int ret = 0;
 
        unsigned long flags;
        int ret = 0;
 
-       spin_lock_irqsave(CCISS_LOCK(h->ctlr), flags);
+       spin_lock_irqsave(&h->lock, flags);
        if (h->busy_configuring)
                ret = -EBUSY;
        else
                memcpy(sn, drv->serial_no, sizeof(sn));
        if (h->busy_configuring)
                ret = -EBUSY;
        else
                memcpy(sn, drv->serial_no, sizeof(sn));
-       spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags);
+       spin_unlock_irqrestore(&h->lock, flags);
 
        if (ret)
                return ret;
 
        if (ret)
                return ret;
@@ -595,12 +638,12 @@ static ssize_t dev_show_vendor(struct device *dev,
        unsigned long flags;
        int ret = 0;
 
        unsigned long flags;
        int ret = 0;
 
-       spin_lock_irqsave(CCISS_LOCK(h->ctlr), flags);
+       spin_lock_irqsave(&h->lock, flags);
        if (h->busy_configuring)
                ret = -EBUSY;
        else
                memcpy(vendor, drv->vendor, VENDOR_LEN + 1);
        if (h->busy_configuring)
                ret = -EBUSY;
        else
                memcpy(vendor, drv->vendor, VENDOR_LEN + 1);
-       spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags);
+       spin_unlock_irqrestore(&h->lock, flags);
 
        if (ret)
                return ret;
 
        if (ret)
                return ret;
@@ -619,12 +662,12 @@ static ssize_t dev_show_model(struct device *dev,
        unsigned long flags;
        int ret = 0;
 
        unsigned long flags;
        int ret = 0;
 
-       spin_lock_irqsave(CCISS_LOCK(h->ctlr), flags);
+       spin_lock_irqsave(&h->lock, flags);
        if (h->busy_configuring)
                ret = -EBUSY;
        else
                memcpy(model, drv->model, MODEL_LEN + 1);
        if (h->busy_configuring)
                ret = -EBUSY;
        else
                memcpy(model, drv->model, MODEL_LEN + 1);
-       spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags);
+       spin_unlock_irqrestore(&h->lock, flags);
 
        if (ret)
                return ret;
 
        if (ret)
                return ret;
@@ -643,12 +686,12 @@ static ssize_t dev_show_rev(struct device *dev,
        unsigned long flags;
        int ret = 0;
 
        unsigned long flags;
        int ret = 0;
 
-       spin_lock_irqsave(CCISS_LOCK(h->ctlr), flags);
+       spin_lock_irqsave(&h->lock, flags);
        if (h->busy_configuring)
                ret = -EBUSY;
        else
                memcpy(rev, drv->rev, REV_LEN + 1);
        if (h->busy_configuring)
                ret = -EBUSY;
        else
                memcpy(rev, drv->rev, REV_LEN + 1);
-       spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags);
+       spin_unlock_irqrestore(&h->lock, flags);
 
        if (ret)
                return ret;
 
        if (ret)
                return ret;
@@ -665,17 +708,17 @@ static ssize_t cciss_show_lunid(struct device *dev,
        unsigned long flags;
        unsigned char lunid[8];
 
        unsigned long flags;
        unsigned char lunid[8];
 
-       spin_lock_irqsave(CCISS_LOCK(h->ctlr), flags);
+       spin_lock_irqsave(&h->lock, flags);
        if (h->busy_configuring) {
        if (h->busy_configuring) {
-               spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags);
+               spin_unlock_irqrestore(&h->lock, flags);
                return -EBUSY;
        }
        if (!drv->heads) {
                return -EBUSY;
        }
        if (!drv->heads) {
-               spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags);
+               spin_unlock_irqrestore(&h->lock, flags);
                return -ENOTTY;
        }
        memcpy(lunid, drv->LunID, sizeof(lunid));
                return -ENOTTY;
        }
        memcpy(lunid, drv->LunID, sizeof(lunid));
-       spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags);
+       spin_unlock_irqrestore(&h->lock, flags);
        return snprintf(buf, 20, "0x%02x%02x%02x%02x%02x%02x%02x%02x\n",
                lunid[0], lunid[1], lunid[2], lunid[3],
                lunid[4], lunid[5], lunid[6], lunid[7]);
        return snprintf(buf, 20, "0x%02x%02x%02x%02x%02x%02x%02x%02x\n",
                lunid[0], lunid[1], lunid[2], lunid[3],
                lunid[4], lunid[5], lunid[6], lunid[7]);
@@ -690,13 +733,13 @@ static ssize_t cciss_show_raid_level(struct device *dev,
        int raid;
        unsigned long flags;
 
        int raid;
        unsigned long flags;
 
-       spin_lock_irqsave(CCISS_LOCK(h->ctlr), flags);
+       spin_lock_irqsave(&h->lock, flags);
        if (h->busy_configuring) {
        if (h->busy_configuring) {
-               spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags);
+               spin_unlock_irqrestore(&h->lock, flags);
                return -EBUSY;
        }
        raid = drv->raid_level;
                return -EBUSY;
        }
        raid = drv->raid_level;
-       spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags);
+       spin_unlock_irqrestore(&h->lock, flags);
        if (raid < 0 || raid > RAID_UNKNOWN)
                raid = RAID_UNKNOWN;
 
        if (raid < 0 || raid > RAID_UNKNOWN)
                raid = RAID_UNKNOWN;
 
@@ -713,13 +756,13 @@ static ssize_t cciss_show_usage_count(struct device *dev,
        unsigned long flags;
        int count;
 
        unsigned long flags;
        int count;
 
-       spin_lock_irqsave(CCISS_LOCK(h->ctlr), flags);
+       spin_lock_irqsave(&h->lock, flags);
        if (h->busy_configuring) {
        if (h->busy_configuring) {
-               spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags);
+               spin_unlock_irqrestore(&h->lock, flags);
                return -EBUSY;
        }
        count = drv->usage_count;
                return -EBUSY;
        }
        count = drv->usage_count;
-       spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags);
+       spin_unlock_irqrestore(&h->lock, flags);
        return snprintf(buf, 20, "%d\n", count);
 }
 static DEVICE_ATTR(usage_count, S_IRUGO, cciss_show_usage_count, NULL);
        return snprintf(buf, 20, "%d\n", count);
 }
 static DEVICE_ATTR(usage_count, S_IRUGO, cciss_show_usage_count, NULL);
@@ -864,60 +907,70 @@ static void cciss_destroy_ld_sysfs_entry(struct ctlr_info *h, int drv_index,
 /*
  * For operations that cannot sleep, a command block is allocated at init,
  * and managed by cmd_alloc() and cmd_free() using a simple bitmap to track
 /*
  * For operations that cannot sleep, a command block is allocated at init,
  * and managed by cmd_alloc() and cmd_free() using a simple bitmap to track
- * which ones are free or in use.  For operations that can wait for kmalloc
- * to possible sleep, this routine can be called with get_from_pool set to 0.
- * cmd_free() MUST be called with a got_from_pool set to 0 if cmd_alloc was.
+ * which ones are free or in use.
  */
  */
-static CommandList_struct *cmd_alloc(ctlr_info_t *h, int get_from_pool)
+static CommandList_struct *cmd_alloc(ctlr_info_t *h)
 {
        CommandList_struct *c;
        int i;
        u64bit temp64;
        dma_addr_t cmd_dma_handle, err_dma_handle;
 
 {
        CommandList_struct *c;
        int i;
        u64bit temp64;
        dma_addr_t cmd_dma_handle, err_dma_handle;
 
-       if (!get_from_pool) {
-               c = (CommandList_struct *) pci_alloc_consistent(h->pdev,
-                       sizeof(CommandList_struct), &cmd_dma_handle);
-               if (c == NULL)
+       do {
+               i = find_first_zero_bit(h->cmd_pool_bits, h->nr_cmds);
+               if (i == h->nr_cmds)
                        return NULL;
                        return NULL;
-               memset(c, 0, sizeof(CommandList_struct));
+       } while (test_and_set_bit(i & (BITS_PER_LONG - 1),
+                 h->cmd_pool_bits + (i / BITS_PER_LONG)) != 0);
+       c = h->cmd_pool + i;
+       memset(c, 0, sizeof(CommandList_struct));
+       cmd_dma_handle = h->cmd_pool_dhandle + i * sizeof(CommandList_struct);
+       c->err_info = h->errinfo_pool + i;
+       memset(c->err_info, 0, sizeof(ErrorInfo_struct));
+       err_dma_handle = h->errinfo_pool_dhandle
+           + i * sizeof(ErrorInfo_struct);
+       h->nr_allocs++;
 
 
-               c->cmdindex = -1;
+       c->cmdindex = i;
 
 
-               c->err_info = (ErrorInfo_struct *)
-                   pci_alloc_consistent(h->pdev, sizeof(ErrorInfo_struct),
-                           &err_dma_handle);
+       INIT_HLIST_NODE(&c->list);
+       c->busaddr = (__u32) cmd_dma_handle;
+       temp64.val = (__u64) err_dma_handle;
+       c->ErrDesc.Addr.lower = temp64.val32.lower;
+       c->ErrDesc.Addr.upper = temp64.val32.upper;
+       c->ErrDesc.Len = sizeof(ErrorInfo_struct);
 
 
-               if (c->err_info == NULL) {
-                       pci_free_consistent(h->pdev,
-                               sizeof(CommandList_struct), c, cmd_dma_handle);
-                       return NULL;
-               }
-               memset(c->err_info, 0, sizeof(ErrorInfo_struct));
-       } else {                /* get it out of the controllers pool */
-
-               do {
-                       i = find_first_zero_bit(h->cmd_pool_bits, h->nr_cmds);
-                       if (i == h->nr_cmds)
-                               return NULL;
-               } while (test_and_set_bit
-                        (i & (BITS_PER_LONG - 1),
-                         h->cmd_pool_bits + (i / BITS_PER_LONG)) != 0);
-#ifdef CCISS_DEBUG
-               printk(KERN_DEBUG "cciss: using command buffer %d\n", i);
-#endif
-               c = h->cmd_pool + i;
-               memset(c, 0, sizeof(CommandList_struct));
-               cmd_dma_handle = h->cmd_pool_dhandle
-                   + i * sizeof(CommandList_struct);
-               c->err_info = h->errinfo_pool + i;
-               memset(c->err_info, 0, sizeof(ErrorInfo_struct));
-               err_dma_handle = h->errinfo_pool_dhandle
-                   + i * sizeof(ErrorInfo_struct);
-               h->nr_allocs++;
+       c->ctlr = h->ctlr;
+       return c;
+}
 
 
-               c->cmdindex = i;
+/* allocate a command using pci_alloc_consistent, used for ioctls,
+ * etc., not for the main i/o path.
+ */
+static CommandList_struct *cmd_special_alloc(ctlr_info_t *h)
+{
+       CommandList_struct *c;
+       u64bit temp64;
+       dma_addr_t cmd_dma_handle, err_dma_handle;
+
+       c = (CommandList_struct *) pci_alloc_consistent(h->pdev,
+               sizeof(CommandList_struct), &cmd_dma_handle);
+       if (c == NULL)
+               return NULL;
+       memset(c, 0, sizeof(CommandList_struct));
+
+       c->cmdindex = -1;
+
+       c->err_info = (ErrorInfo_struct *)
+           pci_alloc_consistent(h->pdev, sizeof(ErrorInfo_struct),
+                   &err_dma_handle);
+
+       if (c->err_info == NULL) {
+               pci_free_consistent(h->pdev,
+                       sizeof(CommandList_struct), c, cmd_dma_handle);
+               return NULL;
        }
        }
+       memset(c->err_info, 0, sizeof(ErrorInfo_struct));
 
        INIT_HLIST_NODE(&c->list);
        c->busaddr = (__u32) cmd_dma_handle;
 
        INIT_HLIST_NODE(&c->list);
        c->busaddr = (__u32) cmd_dma_handle;
@@ -930,27 +983,26 @@ static CommandList_struct *cmd_alloc(ctlr_info_t *h, int get_from_pool)
        return c;
 }
 
        return c;
 }
 
-/*
- * Frees a command block that was previously allocated with cmd_alloc().
- */
-static void cmd_free(ctlr_info_t *h, CommandList_struct *c, int got_from_pool)
+static void cmd_free(ctlr_info_t *h, CommandList_struct *c)
 {
        int i;
 {
        int i;
+
+       i = c - h->cmd_pool;
+       clear_bit(i & (BITS_PER_LONG - 1),
+                 h->cmd_pool_bits + (i / BITS_PER_LONG));
+       h->nr_frees++;
+}
+
+static void cmd_special_free(ctlr_info_t *h, CommandList_struct *c)
+{
        u64bit temp64;
 
        u64bit temp64;
 
-       if (!got_from_pool) {
-               temp64.val32.lower = c->ErrDesc.Addr.lower;
-               temp64.val32.upper = c->ErrDesc.Addr.upper;
-               pci_free_consistent(h->pdev, sizeof(ErrorInfo_struct),
-                                   c->err_info, (dma_addr_t) temp64.val);
-               pci_free_consistent(h->pdev, sizeof(CommandList_struct),
-                                   c, (dma_addr_t) c->busaddr);
-       } else {
-               i = c - h->cmd_pool;
-               clear_bit(i & (BITS_PER_LONG - 1),
-                         h->cmd_pool_bits + (i / BITS_PER_LONG));
-               h->nr_frees++;
-       }
+       temp64.val32.lower = c->ErrDesc.Addr.lower;
+       temp64.val32.upper = c->ErrDesc.Addr.upper;
+       pci_free_consistent(h->pdev, sizeof(ErrorInfo_struct),
+                           c->err_info, (dma_addr_t) temp64.val);
+       pci_free_consistent(h->pdev, sizeof(CommandList_struct),
+                           c, (dma_addr_t) c->busaddr);
 }
 
 static inline ctlr_info_t *get_host(struct gendisk *disk)
 }
 
 static inline ctlr_info_t *get_host(struct gendisk *disk)
@@ -968,13 +1020,10 @@ static inline drive_info_struct *get_drv(struct gendisk *disk)
  */
 static int cciss_open(struct block_device *bdev, fmode_t mode)
 {
  */
 static int cciss_open(struct block_device *bdev, fmode_t mode)
 {
-       ctlr_info_t *host = get_host(bdev->bd_disk);
+       ctlr_info_t *h = get_host(bdev->bd_disk);
        drive_info_struct *drv = get_drv(bdev->bd_disk);
 
        drive_info_struct *drv = get_drv(bdev->bd_disk);
 
-#ifdef CCISS_DEBUG
-       printk(KERN_DEBUG "cciss_open %s\n", bdev->bd_disk->disk_name);
-#endif                         /* CCISS_DEBUG */
-
+       dev_dbg(&h->pdev->dev, "cciss_open %s\n", bdev->bd_disk->disk_name);
        if (drv->busy_configuring)
                return -EBUSY;
        /*
        if (drv->busy_configuring)
                return -EBUSY;
        /*
@@ -1000,29 +1049,39 @@ static int cciss_open(struct block_device *bdev, fmode_t mode)
                        return -EPERM;
        }
        drv->usage_count++;
                        return -EPERM;
        }
        drv->usage_count++;
-       host->usage_count++;
+       h->usage_count++;
        return 0;
 }
 
        return 0;
 }
 
+static int cciss_unlocked_open(struct block_device *bdev, fmode_t mode)
+{
+       int ret;
+
+       lock_kernel();
+       ret = cciss_open(bdev, mode);
+       unlock_kernel();
+
+       return ret;
+}
+
 /*
  * Close.  Sync first.
  */
 static int cciss_release(struct gendisk *disk, fmode_t mode)
 {
 /*
  * Close.  Sync first.
  */
 static int cciss_release(struct gendisk *disk, fmode_t mode)
 {
-       ctlr_info_t *host = get_host(disk);
-       drive_info_struct *drv = get_drv(disk);
-
-#ifdef CCISS_DEBUG
-       printk(KERN_DEBUG "cciss_release %s\n", disk->disk_name);
-#endif                         /* CCISS_DEBUG */
+       ctlr_info_t *h;
+       drive_info_struct *drv;
 
 
+       lock_kernel();
+       h = get_host(disk);
+       drv = get_drv(disk);
+       dev_dbg(&h->pdev->dev, "cciss_release %s\n", disk->disk_name);
        drv->usage_count--;
        drv->usage_count--;
-       host->usage_count--;
+       h->usage_count--;
+       unlock_kernel();
        return 0;
 }
 
        return 0;
 }
 
-#ifdef CONFIG_COMPAT
-
 static int do_ioctl(struct block_device *bdev, fmode_t mode,
                    unsigned cmd, unsigned long arg)
 {
 static int do_ioctl(struct block_device *bdev, fmode_t mode,
                    unsigned cmd, unsigned long arg)
 {
@@ -1033,6 +1092,8 @@ static int do_ioctl(struct block_device *bdev, fmode_t mode,
        return ret;
 }
 
        return ret;
 }
 
+#ifdef CONFIG_COMPAT
+
 static int cciss_ioctl32_passthru(struct block_device *bdev, fmode_t mode,
                                  unsigned cmd, unsigned long arg);
 static int cciss_ioctl32_big_passthru(struct block_device *bdev, fmode_t mode,
 static int cciss_ioctl32_passthru(struct block_device *bdev, fmode_t mode,
                                  unsigned cmd, unsigned long arg);
 static int cciss_ioctl32_big_passthru(struct block_device *bdev, fmode_t mode,
@@ -1163,11 +1224,11 @@ static int cciss_getgeo(struct block_device *bdev, struct hd_geometry *geo)
        return 0;
 }
 
        return 0;
 }
 
-static void check_ioctl_unit_attention(ctlr_info_t *host, CommandList_struct *c)
+static void check_ioctl_unit_attention(ctlr_info_t *h, CommandList_struct *c)
 {
        if (c->err_info->CommandStatus == CMD_TARGET_STATUS &&
                        c->err_info->ScsiStatus != SAM_STAT_CHECK_CONDITION)
 {
        if (c->err_info->CommandStatus == CMD_TARGET_STATUS &&
                        c->err_info->ScsiStatus != SAM_STAT_CHECK_CONDITION)
-               (void)check_for_unit_attention(host, c);
+               (void)check_for_unit_attention(h, c);
 }
 /*
  * ioctl
 }
 /*
  * ioctl
@@ -1176,15 +1237,12 @@ static int cciss_ioctl(struct block_device *bdev, fmode_t mode,
                       unsigned int cmd, unsigned long arg)
 {
        struct gendisk *disk = bdev->bd_disk;
                       unsigned int cmd, unsigned long arg)
 {
        struct gendisk *disk = bdev->bd_disk;
-       ctlr_info_t *host = get_host(disk);
+       ctlr_info_t *h = get_host(disk);
        drive_info_struct *drv = get_drv(disk);
        drive_info_struct *drv = get_drv(disk);
-       int ctlr = host->ctlr;
        void __user *argp = (void __user *)arg;
 
        void __user *argp = (void __user *)arg;
 
-#ifdef CCISS_DEBUG
-       printk(KERN_DEBUG "cciss_ioctl: Called with cmd=%x %lx\n", cmd, arg);
-#endif                         /* CCISS_DEBUG */
-
+       dev_dbg(&h->pdev->dev, "cciss_ioctl: Called with cmd=%x %lx\n",
+               cmd, arg);
        switch (cmd) {
        case CCISS_GETPCIINFO:
                {
        switch (cmd) {
        case CCISS_GETPCIINFO:
                {
@@ -1192,10 +1250,10 @@ static int cciss_ioctl(struct block_device *bdev, fmode_t mode,
 
                        if (!arg)
                                return -EINVAL;
 
                        if (!arg)
                                return -EINVAL;
-                       pciinfo.domain = pci_domain_nr(host->pdev->bus);
-                       pciinfo.bus = host->pdev->bus->number;
-                       pciinfo.dev_fn = host->pdev->devfn;
-                       pciinfo.board_id = host->board_id;
+                       pciinfo.domain = pci_domain_nr(h->pdev->bus);
+                       pciinfo.bus = h->pdev->bus->number;
+                       pciinfo.dev_fn = h->pdev->devfn;
+                       pciinfo.board_id = h->board_id;
                        if (copy_to_user
                            (argp, &pciinfo, sizeof(cciss_pci_info_struct)))
                                return -EFAULT;
                        if (copy_to_user
                            (argp, &pciinfo, sizeof(cciss_pci_info_struct)))
                                return -EFAULT;
@@ -1207,9 +1265,9 @@ static int cciss_ioctl(struct block_device *bdev, fmode_t mode,
                        if (!arg)
                                return -EINVAL;
                        intinfo.delay =
                        if (!arg)
                                return -EINVAL;
                        intinfo.delay =
-                           readl(&host->cfgtable->HostWrite.CoalIntDelay);
+                           readl(&h->cfgtable->HostWrite.CoalIntDelay);
                        intinfo.count =
                        intinfo.count =
-                           readl(&host->cfgtable->HostWrite.CoalIntCount);
+                           readl(&h->cfgtable->HostWrite.CoalIntCount);
                        if (copy_to_user
                            (argp, &intinfo, sizeof(cciss_coalint_struct)))
                                return -EFAULT;
                        if (copy_to_user
                            (argp, &intinfo, sizeof(cciss_coalint_struct)))
                                return -EFAULT;
@@ -1229,26 +1287,23 @@ static int cciss_ioctl(struct block_device *bdev, fmode_t mode,
                            (&intinfo, argp, sizeof(cciss_coalint_struct)))
                                return -EFAULT;
                        if ((intinfo.delay == 0) && (intinfo.count == 0))
                            (&intinfo, argp, sizeof(cciss_coalint_struct)))
                                return -EFAULT;
                        if ((intinfo.delay == 0) && (intinfo.count == 0))
-                       {
-//                      printk("cciss_ioctl: delay and count cannot be 0\n");
                                return -EINVAL;
                                return -EINVAL;
-                       }
-                       spin_lock_irqsave(CCISS_LOCK(ctlr), flags);
+                       spin_lock_irqsave(&h->lock, flags);
                        /* Update the field, and then ring the doorbell */
                        writel(intinfo.delay,
                        /* Update the field, and then ring the doorbell */
                        writel(intinfo.delay,
-                              &(host->cfgtable->HostWrite.CoalIntDelay));
+                              &(h->cfgtable->HostWrite.CoalIntDelay));
                        writel(intinfo.count,
                        writel(intinfo.count,
-                              &(host->cfgtable->HostWrite.CoalIntCount));
-                       writel(CFGTBL_ChangeReq, host->vaddr + SA5_DOORBELL);
+                              &(h->cfgtable->HostWrite.CoalIntCount));
+                       writel(CFGTBL_ChangeReq, h->vaddr + SA5_DOORBELL);
 
                        for (i = 0; i < MAX_IOCTL_CONFIG_WAIT; i++) {
 
                        for (i = 0; i < MAX_IOCTL_CONFIG_WAIT; i++) {
-                               if (!(readl(host->vaddr + SA5_DOORBELL)
+                               if (!(readl(h->vaddr + SA5_DOORBELL)
                                      & CFGTBL_ChangeReq))
                                        break;
                                /* delay and try again */
                                udelay(1000);
                        }
                                      & CFGTBL_ChangeReq))
                                        break;
                                /* delay and try again */
                                udelay(1000);
                        }
-                       spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
+                       spin_unlock_irqrestore(&h->lock, flags);
                        if (i >= MAX_IOCTL_CONFIG_WAIT)
                                return -EAGAIN;
                        return 0;
                        if (i >= MAX_IOCTL_CONFIG_WAIT)
                                return -EAGAIN;
                        return 0;
@@ -1262,7 +1317,7 @@ static int cciss_ioctl(struct block_device *bdev, fmode_t mode,
                                return -EINVAL;
                        for (i = 0; i < 16; i++)
                                NodeName[i] =
                                return -EINVAL;
                        for (i = 0; i < 16; i++)
                                NodeName[i] =
-                                   readb(&host->cfgtable->ServerName[i]);
+                                   readb(&h->cfgtable->ServerName[i]);
                        if (copy_to_user(argp, NodeName, sizeof(NodeName_type)))
                                return -EFAULT;
                        return 0;
                        if (copy_to_user(argp, NodeName, sizeof(NodeName_type)))
                                return -EFAULT;
                        return 0;
@@ -1282,23 +1337,23 @@ static int cciss_ioctl(struct block_device *bdev, fmode_t mode,
                            (NodeName, argp, sizeof(NodeName_type)))
                                return -EFAULT;
 
                            (NodeName, argp, sizeof(NodeName_type)))
                                return -EFAULT;
 
-                       spin_lock_irqsave(CCISS_LOCK(ctlr), flags);
+                       spin_lock_irqsave(&h->lock, flags);
 
                        /* Update the field, and then ring the doorbell */
                        for (i = 0; i < 16; i++)
                                writeb(NodeName[i],
 
                        /* Update the field, and then ring the doorbell */
                        for (i = 0; i < 16; i++)
                                writeb(NodeName[i],
-                                      &host->cfgtable->ServerName[i]);
+                                      &h->cfgtable->ServerName[i]);
 
 
-                       writel(CFGTBL_ChangeReq, host->vaddr + SA5_DOORBELL);
+                       writel(CFGTBL_ChangeReq, h->vaddr + SA5_DOORBELL);
 
                        for (i = 0; i < MAX_IOCTL_CONFIG_WAIT; i++) {
 
                        for (i = 0; i < MAX_IOCTL_CONFIG_WAIT; i++) {
-                               if (!(readl(host->vaddr + SA5_DOORBELL)
+                               if (!(readl(h->vaddr + SA5_DOORBELL)
                                      & CFGTBL_ChangeReq))
                                        break;
                                /* delay and try again */
                                udelay(1000);
                        }
                                      & CFGTBL_ChangeReq))
                                        break;
                                /* delay and try again */
                                udelay(1000);
                        }
-                       spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
+                       spin_unlock_irqrestore(&h->lock, flags);
                        if (i >= MAX_IOCTL_CONFIG_WAIT)
                                return -EAGAIN;
                        return 0;
                        if (i >= MAX_IOCTL_CONFIG_WAIT)
                                return -EAGAIN;
                        return 0;
@@ -1310,7 +1365,7 @@ static int cciss_ioctl(struct block_device *bdev, fmode_t mode,
 
                        if (!arg)
                                return -EINVAL;
 
                        if (!arg)
                                return -EINVAL;
-                       heartbeat = readl(&host->cfgtable->HeartBeat);
+                       heartbeat = readl(&h->cfgtable->HeartBeat);
                        if (copy_to_user
                            (argp, &heartbeat, sizeof(Heartbeat_type)))
                                return -EFAULT;
                        if (copy_to_user
                            (argp, &heartbeat, sizeof(Heartbeat_type)))
                                return -EFAULT;
@@ -1322,7 +1377,7 @@ static int cciss_ioctl(struct block_device *bdev, fmode_t mode,
 
                        if (!arg)
                                return -EINVAL;
 
                        if (!arg)
                                return -EINVAL;
-                       BusTypes = readl(&host->cfgtable->BusTypes);
+                       BusTypes = readl(&h->cfgtable->BusTypes);
                        if (copy_to_user
                            (argp, &BusTypes, sizeof(BusTypes_type)))
                                return -EFAULT;
                        if (copy_to_user
                            (argp, &BusTypes, sizeof(BusTypes_type)))
                                return -EFAULT;
@@ -1334,7 +1389,7 @@ static int cciss_ioctl(struct block_device *bdev, fmode_t mode,
 
                        if (!arg)
                                return -EINVAL;
 
                        if (!arg)
                                return -EINVAL;
-                       memcpy(firmware, host->firm_ver, 4);
+                       memcpy(firmware, h->firm_ver, 4);
 
                        if (copy_to_user
                            (argp, firmware, sizeof(FirmwareVer_type)))
 
                        if (copy_to_user
                            (argp, firmware, sizeof(FirmwareVer_type)))
@@ -1357,7 +1412,7 @@ static int cciss_ioctl(struct block_device *bdev, fmode_t mode,
        case CCISS_DEREGDISK:
        case CCISS_REGNEWD:
        case CCISS_REVALIDVOLS:
        case CCISS_DEREGDISK:
        case CCISS_REGNEWD:
        case CCISS_REVALIDVOLS:
-               return rebuild_lun_table(host, 0, 1);
+               return rebuild_lun_table(h, 0, 1);
 
        case CCISS_GETLUNINFO:{
                        LogvolInfo_struct luninfo;
 
        case CCISS_GETLUNINFO:{
                        LogvolInfo_struct luninfo;
@@ -1377,7 +1432,6 @@ static int cciss_ioctl(struct block_device *bdev, fmode_t mode,
                        CommandList_struct *c;
                        char *buff = NULL;
                        u64bit temp64;
                        CommandList_struct *c;
                        char *buff = NULL;
                        u64bit temp64;
-                       unsigned long flags;
                        DECLARE_COMPLETION_ONSTACK(wait);
 
                        if (!arg)
                        DECLARE_COMPLETION_ONSTACK(wait);
 
                        if (!arg)
@@ -1413,7 +1467,8 @@ static int cciss_ioctl(struct block_device *bdev, fmode_t mode,
                        } else {
                                memset(buff, 0, iocommand.buf_size);
                        }
                        } else {
                                memset(buff, 0, iocommand.buf_size);
                        }
-                       if ((c = cmd_alloc(host, 0)) == NULL) {
+                       c = cmd_special_alloc(h);
+                       if (!c) {
                                kfree(buff);
                                return -ENOMEM;
                        }
                                kfree(buff);
                                return -ENOMEM;
                        }
@@ -1439,7 +1494,7 @@ static int cciss_ioctl(struct block_device *bdev, fmode_t mode,
 
                        /* Fill in the scatter gather information */
                        if (iocommand.buf_size > 0) {
 
                        /* Fill in the scatter gather information */
                        if (iocommand.buf_size > 0) {
-                               temp64.val = pci_map_single(host->pdev, buff,
+                               temp64.val = pci_map_single(h->pdev, buff,
                                        iocommand.buf_size,
                                        PCI_DMA_BIDIRECTIONAL);
                                c->SG[0].Addr.lower = temp64.val32.lower;
                                        iocommand.buf_size,
                                        PCI_DMA_BIDIRECTIONAL);
                                c->SG[0].Addr.lower = temp64.val32.lower;
@@ -1449,30 +1504,24 @@ static int cciss_ioctl(struct block_device *bdev, fmode_t mode,
                        }
                        c->waiting = &wait;
 
                        }
                        c->waiting = &wait;
 
-                       /* Put the request on the tail of the request queue */
-                       spin_lock_irqsave(CCISS_LOCK(ctlr), flags);
-                       addQ(&host->reqQ, c);
-                       host->Qdepth++;
-                       start_io(host);
-                       spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
-
+                       enqueue_cmd_and_start_io(h, c);
                        wait_for_completion(&wait);
 
                        /* unlock the buffers from DMA */
                        temp64.val32.lower = c->SG[0].Addr.lower;
                        temp64.val32.upper = c->SG[0].Addr.upper;
                        wait_for_completion(&wait);
 
                        /* unlock the buffers from DMA */
                        temp64.val32.lower = c->SG[0].Addr.lower;
                        temp64.val32.upper = c->SG[0].Addr.upper;
-                       pci_unmap_single(host->pdev, (dma_addr_t) temp64.val,
+                       pci_unmap_single(h->pdev, (dma_addr_t) temp64.val,
                                         iocommand.buf_size,
                                         PCI_DMA_BIDIRECTIONAL);
 
                                         iocommand.buf_size,
                                         PCI_DMA_BIDIRECTIONAL);
 
-                       check_ioctl_unit_attention(host, c);
+                       check_ioctl_unit_attention(h, c);
 
                        /* Copy the error information out */
                        iocommand.error_info = *(c->err_info);
                        if (copy_to_user
                            (argp, &iocommand, sizeof(IOCTL_Command_struct))) {
                                kfree(buff);
 
                        /* Copy the error information out */
                        iocommand.error_info = *(c->err_info);
                        if (copy_to_user
                            (argp, &iocommand, sizeof(IOCTL_Command_struct))) {
                                kfree(buff);
-                               cmd_free(host, c, 0);
+                               cmd_special_free(h, c);
                                return -EFAULT;
                        }
 
                                return -EFAULT;
                        }
 
@@ -1481,12 +1530,12 @@ static int cciss_ioctl(struct block_device *bdev, fmode_t mode,
                                if (copy_to_user
                                    (iocommand.buf, buff, iocommand.buf_size)) {
                                        kfree(buff);
                                if (copy_to_user
                                    (iocommand.buf, buff, iocommand.buf_size)) {
                                        kfree(buff);
-                                       cmd_free(host, c, 0);
+                                       cmd_special_free(h, c);
                                        return -EFAULT;
                                }
                        }
                        kfree(buff);
                                        return -EFAULT;
                                }
                        }
                        kfree(buff);
-                       cmd_free(host, c, 0);
+                       cmd_special_free(h, c);
                        return 0;
                }
        case CCISS_BIG_PASSTHRU:{
                        return 0;
                }
        case CCISS_BIG_PASSTHRU:{
@@ -1495,7 +1544,6 @@ static int cciss_ioctl(struct block_device *bdev, fmode_t mode,
                        unsigned char **buff = NULL;
                        int *buff_size = NULL;
                        u64bit temp64;
                        unsigned char **buff = NULL;
                        int *buff_size = NULL;
                        u64bit temp64;
-                       unsigned long flags;
                        BYTE sg_used = 0;
                        int status = 0;
                        int i;
                        BYTE sg_used = 0;
                        int status = 0;
                        int i;
@@ -1569,7 +1617,8 @@ static int cciss_ioctl(struct block_device *bdev, fmode_t mode,
                                data_ptr += sz;
                                sg_used++;
                        }
                                data_ptr += sz;
                                sg_used++;
                        }
-                       if ((c = cmd_alloc(host, 0)) == NULL) {
+                       c = cmd_special_alloc(h);
+                       if (!c) {
                                status = -ENOMEM;
                                goto cleanup1;
                        }
                                status = -ENOMEM;
                                goto cleanup1;
                        }
@@ -1590,7 +1639,7 @@ static int cciss_ioctl(struct block_device *bdev, fmode_t mode,
                        if (ioc->buf_size > 0) {
                                for (i = 0; i < sg_used; i++) {
                                        temp64.val =
                        if (ioc->buf_size > 0) {
                                for (i = 0; i < sg_used; i++) {
                                        temp64.val =
-                                           pci_map_single(host->pdev, buff[i],
+                                           pci_map_single(h->pdev, buff[i],
                                                    buff_size[i],
                                                    PCI_DMA_BIDIRECTIONAL);
                                        c->SG[i].Addr.lower =
                                                    buff_size[i],
                                                    PCI_DMA_BIDIRECTIONAL);
                                        c->SG[i].Addr.lower =
@@ -1602,26 +1651,21 @@ static int cciss_ioctl(struct block_device *bdev, fmode_t mode,
                                }
                        }
                        c->waiting = &wait;
                                }
                        }
                        c->waiting = &wait;
-                       /* Put the request on the tail of the request queue */
-                       spin_lock_irqsave(CCISS_LOCK(ctlr), flags);
-                       addQ(&host->reqQ, c);
-                       host->Qdepth++;
-                       start_io(host);
-                       spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
+                       enqueue_cmd_and_start_io(h, c);
                        wait_for_completion(&wait);
                        /* unlock the buffers from DMA */
                        for (i = 0; i < sg_used; i++) {
                                temp64.val32.lower = c->SG[i].Addr.lower;
                                temp64.val32.upper = c->SG[i].Addr.upper;
                        wait_for_completion(&wait);
                        /* unlock the buffers from DMA */
                        for (i = 0; i < sg_used; i++) {
                                temp64.val32.lower = c->SG[i].Addr.lower;
                                temp64.val32.upper = c->SG[i].Addr.upper;
-                               pci_unmap_single(host->pdev,
+                               pci_unmap_single(h->pdev,
                                        (dma_addr_t) temp64.val, buff_size[i],
                                        PCI_DMA_BIDIRECTIONAL);
                        }
                                        (dma_addr_t) temp64.val, buff_size[i],
                                        PCI_DMA_BIDIRECTIONAL);
                        }
-                       check_ioctl_unit_attention(host, c);
+                       check_ioctl_unit_attention(h, c);
                        /* Copy the error information out */
                        ioc->error_info = *(c->err_info);
                        if (copy_to_user(argp, ioc, sizeof(*ioc))) {
                        /* Copy the error information out */
                        ioc->error_info = *(c->err_info);
                        if (copy_to_user(argp, ioc, sizeof(*ioc))) {
-                               cmd_free(host, c, 0);
+                               cmd_special_free(h, c);
                                status = -EFAULT;
                                goto cleanup1;
                        }
                                status = -EFAULT;
                                goto cleanup1;
                        }
@@ -1631,14 +1675,14 @@ static int cciss_ioctl(struct block_device *bdev, fmode_t mode,
                                for (i = 0; i < sg_used; i++) {
                                        if (copy_to_user
                                            (ptr, buff[i], buff_size[i])) {
                                for (i = 0; i < sg_used; i++) {
                                        if (copy_to_user
                                            (ptr, buff[i], buff_size[i])) {
-                                               cmd_free(host, c, 0);
+                                               cmd_special_free(h, c);
                                                status = -EFAULT;
                                                goto cleanup1;
                                        }
                                        ptr += buff_size[i];
                                }
                        }
                                                status = -EFAULT;
                                                goto cleanup1;
                                        }
                                        ptr += buff_size[i];
                                }
                        }
-                       cmd_free(host, c, 0);
+                       cmd_special_free(h, c);
                        status = 0;
                      cleanup1:
                        if (buff) {
                        status = 0;
                      cleanup1:
                        if (buff) {
@@ -1726,26 +1770,26 @@ static void cciss_check_queues(ctlr_info_t *h)
 
 static void cciss_softirq_done(struct request *rq)
 {
 
 static void cciss_softirq_done(struct request *rq)
 {
-       CommandList_struct *cmd = rq->completion_data;
-       ctlr_info_t *h = hba[cmd->ctlr];
-       SGDescriptor_struct *curr_sg = cmd->SG;
-       unsigned long flags;
+       CommandList_struct *c = rq->completion_data;
+       ctlr_info_t *h = hba[c->ctlr];
+       SGDescriptor_struct *curr_sg = c->SG;
        u64bit temp64;
        u64bit temp64;
+       unsigned long flags;
        int i, ddir;
        int sg_index = 0;
 
        int i, ddir;
        int sg_index = 0;
 
-       if (cmd->Request.Type.Direction == XFER_READ)
+       if (c->Request.Type.Direction == XFER_READ)
                ddir = PCI_DMA_FROMDEVICE;
        else
                ddir = PCI_DMA_TODEVICE;
 
        /* command did not need to be retried */
        /* unmap the DMA mapping for all the scatter gather elements */
                ddir = PCI_DMA_FROMDEVICE;
        else
                ddir = PCI_DMA_TODEVICE;
 
        /* command did not need to be retried */
        /* unmap the DMA mapping for all the scatter gather elements */
-       for (i = 0; i < cmd->Header.SGList; i++) {
+       for (i = 0; i < c->Header.SGList; i++) {
                if (curr_sg[sg_index].Ext == CCISS_SG_CHAIN) {
                if (curr_sg[sg_index].Ext == CCISS_SG_CHAIN) {
-                       cciss_unmap_sg_chain_block(h, cmd);
+                       cciss_unmap_sg_chain_block(h, c);
                        /* Point to the next block */
                        /* Point to the next block */
-                       curr_sg = h->cmd_sg_list[cmd->cmdindex];
+                       curr_sg = h->cmd_sg_list[c->cmdindex];
                        sg_index = 0;
                }
                temp64.val32.lower = curr_sg[sg_index].Addr.lower;
                        sg_index = 0;
                }
                temp64.val32.lower = curr_sg[sg_index].Addr.lower;
@@ -1755,18 +1799,16 @@ static void cciss_softirq_done(struct request *rq)
                ++sg_index;
        }
 
                ++sg_index;
        }
 
-#ifdef CCISS_DEBUG
-       printk("Done with %p\n", rq);
-#endif                         /* CCISS_DEBUG */
+       dev_dbg(&h->pdev->dev, "Done with %p\n", rq);
 
        /* set the residual count for pc requests */
 
        /* set the residual count for pc requests */
-       if (blk_pc_request(rq))
-               rq->resid_len = cmd->err_info->ResidualCnt;
+       if (rq->cmd_type == REQ_TYPE_BLOCK_PC)
+               rq->resid_len = c->err_info->ResidualCnt;
 
        blk_end_request_all(rq, (rq->errors == 0) ? 0 : -EIO);
 
        spin_lock_irqsave(&h->lock, flags);
 
        blk_end_request_all(rq, (rq->errors == 0) ? 0 : -EIO);
 
        spin_lock_irqsave(&h->lock, flags);
-       cmd_free(h, cmd, 1);
+       cmd_free(h, c);
        cciss_check_queues(h);
        spin_unlock_irqrestore(&h->lock, flags);
 }
        cciss_check_queues(h);
        spin_unlock_irqrestore(&h->lock, flags);
 }
@@ -1782,7 +1824,7 @@ static inline void log_unit_to_scsi3addr(ctlr_info_t *h,
  * via the inquiry page 0.  Model, vendor, and rev are set to empty strings if
  * they cannot be read.
  */
  * via the inquiry page 0.  Model, vendor, and rev are set to empty strings if
  * they cannot be read.
  */
-static void cciss_get_device_descr(int ctlr, int logvol,
+static void cciss_get_device_descr(ctlr_info_t *h, int logvol,
                                   char *vendor, char *model, char *rev)
 {
        int rc;
                                   char *vendor, char *model, char *rev)
 {
        int rc;
@@ -1797,8 +1839,8 @@ static void cciss_get_device_descr(int ctlr, int logvol,
        if (!inq_buf)
                return;
 
        if (!inq_buf)
                return;
 
-       log_unit_to_scsi3addr(hba[ctlr], scsi3addr, logvol);
-       rc = sendcmd_withirq(CISS_INQUIRY, ctlr, inq_buf, sizeof(*inq_buf), 0,
+       log_unit_to_scsi3addr(h, scsi3addr, logvol);
+       rc = sendcmd_withirq(h, CISS_INQUIRY, inq_buf, sizeof(*inq_buf), 0,
                        scsi3addr, TYPE_CMD);
        if (rc == IO_OK) {
                memcpy(vendor, &inq_buf->data_byte[8], VENDOR_LEN);
                        scsi3addr, TYPE_CMD);
        if (rc == IO_OK) {
                memcpy(vendor, &inq_buf->data_byte[8], VENDOR_LEN);
@@ -1818,7 +1860,7 @@ static void cciss_get_device_descr(int ctlr, int logvol,
  * number cannot be had, for whatever reason, 16 bytes of 0xff
  * are returned instead.
  */
  * number cannot be had, for whatever reason, 16 bytes of 0xff
  * are returned instead.
  */
-static void cciss_get_serial_no(int ctlr, int logvol,
+static void cciss_get_serial_no(ctlr_info_t *h, int logvol,
                                unsigned char *serial_no, int buflen)
 {
 #define PAGE_83_INQ_BYTES 64
                                unsigned char *serial_no, int buflen)
 {
 #define PAGE_83_INQ_BYTES 64
@@ -1833,8 +1875,8 @@ static void cciss_get_serial_no(int ctlr, int logvol,
        if (!buf)
                return;
        memset(serial_no, 0, buflen);
        if (!buf)
                return;
        memset(serial_no, 0, buflen);
-       log_unit_to_scsi3addr(hba[ctlr], scsi3addr, logvol);
-       rc = sendcmd_withirq(CISS_INQUIRY, ctlr, buf,
+       log_unit_to_scsi3addr(h, scsi3addr, logvol);
+       rc = sendcmd_withirq(h, CISS_INQUIRY, buf,
                PAGE_83_INQ_BYTES, 0x83, scsi3addr, TYPE_CMD);
        if (rc == IO_OK)
                memcpy(serial_no, &buf[8], buflen);
                PAGE_83_INQ_BYTES, 0x83, scsi3addr, TYPE_CMD);
        if (rc == IO_OK)
                memcpy(serial_no, &buf[8], buflen);
@@ -1900,10 +1942,9 @@ init_queue_failure:
  * is also the controller node.  Any changes to disk 0 will show up on
  * the next reboot.
  */
  * is also the controller node.  Any changes to disk 0 will show up on
  * the next reboot.
  */
-static void cciss_update_drive_info(int ctlr, int drv_index, int first_time,
-       int via_ioctl)
+static void cciss_update_drive_info(ctlr_info_t *h, int drv_index,
+       int first_time, int via_ioctl)
 {
 {
-       ctlr_info_t *h = hba[ctlr];
        struct gendisk *disk;
        InquiryData_struct *inq_buff = NULL;
        unsigned int block_size;
        struct gendisk *disk;
        InquiryData_struct *inq_buff = NULL;
        unsigned int block_size;
@@ -1920,16 +1961,16 @@ static void cciss_update_drive_info(int ctlr, int drv_index, int first_time,
 
        /* testing to see if 16-byte CDBs are already being used */
        if (h->cciss_read == CCISS_READ_16) {
 
        /* testing to see if 16-byte CDBs are already being used */
        if (h->cciss_read == CCISS_READ_16) {
-               cciss_read_capacity_16(h->ctlr, drv_index,
+               cciss_read_capacity_16(h, drv_index,
                        &total_size, &block_size);
 
        } else {
                        &total_size, &block_size);
 
        } else {
-               cciss_read_capacity(ctlr, drv_index, &total_size, &block_size);
+               cciss_read_capacity(h, drv_index, &total_size, &block_size);
                /* if read_capacity returns all F's this volume is >2TB */
                /* in size so we switch to 16-byte CDB's for all */
                /* read/write ops */
                if (total_size == 0xFFFFFFFFULL) {
                /* if read_capacity returns all F's this volume is >2TB */
                /* in size so we switch to 16-byte CDB's for all */
                /* read/write ops */
                if (total_size == 0xFFFFFFFFULL) {
-                       cciss_read_capacity_16(ctlr, drv_index,
+                       cciss_read_capacity_16(h, drv_index,
                        &total_size, &block_size);
                        h->cciss_read = CCISS_READ_16;
                        h->cciss_write = CCISS_WRITE_16;
                        &total_size, &block_size);
                        h->cciss_read = CCISS_READ_16;
                        h->cciss_write = CCISS_WRITE_16;
@@ -1939,14 +1980,14 @@ static void cciss_update_drive_info(int ctlr, int drv_index, int first_time,
                }
        }
 
                }
        }
 
-       cciss_geometry_inquiry(ctlr, drv_index, total_size, block_size,
+       cciss_geometry_inquiry(h, drv_index, total_size, block_size,
                               inq_buff, drvinfo);
        drvinfo->block_size = block_size;
        drvinfo->nr_blocks = total_size + 1;
 
                               inq_buff, drvinfo);
        drvinfo->block_size = block_size;
        drvinfo->nr_blocks = total_size + 1;
 
-       cciss_get_device_descr(ctlr, drv_index, drvinfo->vendor,
+       cciss_get_device_descr(h, drv_index, drvinfo->vendor,
                                drvinfo->model, drvinfo->rev);
                                drvinfo->model, drvinfo->rev);
-       cciss_get_serial_no(ctlr, drv_index, drvinfo->serial_no,
+       cciss_get_serial_no(h, drv_index, drvinfo->serial_no,
                        sizeof(drvinfo->serial_no));
        /* Save the lunid in case we deregister the disk, below. */
        memcpy(drvinfo->LunID, h->drv[drv_index]->LunID,
                        sizeof(drvinfo->serial_no));
        /* Save the lunid in case we deregister the disk, below. */
        memcpy(drvinfo->LunID, h->drv[drv_index]->LunID,
@@ -1971,10 +2012,10 @@ static void cciss_update_drive_info(int ctlr, int drv_index, int first_time,
         * (unless it's the first disk (for the controller node).
         */
        if (h->drv[drv_index]->raid_level != -1 && drv_index != 0) {
         * (unless it's the first disk (for the controller node).
         */
        if (h->drv[drv_index]->raid_level != -1 && drv_index != 0) {
-               printk(KERN_WARNING "disk %d has changed.\n", drv_index);
-               spin_lock_irqsave(CCISS_LOCK(h->ctlr), flags);
+               dev_warn(&h->pdev->dev, "disk %d has changed.\n", drv_index);
+               spin_lock_irqsave(&h->lock, flags);
                h->drv[drv_index]->busy_configuring = 1;
                h->drv[drv_index]->busy_configuring = 1;
-               spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags);
+               spin_unlock_irqrestore(&h->lock, flags);
 
                /* deregister_disk sets h->drv[drv_index]->queue = NULL
                 * which keeps the interrupt handler from starting
 
                /* deregister_disk sets h->drv[drv_index]->queue = NULL
                 * which keeps the interrupt handler from starting
@@ -2024,8 +2065,8 @@ static void cciss_update_drive_info(int ctlr, int drv_index, int first_time,
                if (cciss_add_disk(h, disk, drv_index) != 0) {
                        cciss_free_gendisk(h, drv_index);
                        cciss_free_drive_info(h, drv_index);
                if (cciss_add_disk(h, disk, drv_index) != 0) {
                        cciss_free_gendisk(h, drv_index);
                        cciss_free_drive_info(h, drv_index);
-                       printk(KERN_WARNING "cciss:%d could not update "
-                               "disk %d\n", h->ctlr, drv_index);
+                       dev_warn(&h->pdev->dev, "could not update disk %d\n",
+                               drv_index);
                        --h->num_luns;
                }
        }
                        --h->num_luns;
                }
        }
@@ -2035,7 +2076,7 @@ freeret:
        kfree(drvinfo);
        return;
 mem_msg:
        kfree(drvinfo);
        return;
 mem_msg:
-       printk(KERN_ERR "cciss: out of memory\n");
+       dev_err(&h->pdev->dev, "out of memory\n");
        goto freeret;
 }
 
        goto freeret;
 }
 
@@ -2127,9 +2168,9 @@ static int cciss_add_gendisk(ctlr_info_t *h, unsigned char lunid[],
                h->gendisk[drv_index] =
                        alloc_disk(1 << NWD_SHIFT);
                if (!h->gendisk[drv_index]) {
                h->gendisk[drv_index] =
                        alloc_disk(1 << NWD_SHIFT);
                if (!h->gendisk[drv_index]) {
-                       printk(KERN_ERR "cciss%d: could not "
-                               "allocate a new disk %d\n",
-                               h->ctlr, drv_index);
+                       dev_err(&h->pdev->dev,
+                               "could not allocate a new disk %d\n",
+                               drv_index);
                        goto err_free_drive_info;
                }
        }
                        goto err_free_drive_info;
                }
        }
@@ -2180,8 +2221,7 @@ static void cciss_add_controller_node(ctlr_info_t *h)
        cciss_free_gendisk(h, drv_index);
        cciss_free_drive_info(h, drv_index);
 error:
        cciss_free_gendisk(h, drv_index);
        cciss_free_drive_info(h, drv_index);
 error:
-       printk(KERN_WARNING "cciss%d: could not "
-               "add disk 0.\n", h->ctlr);
+       dev_warn(&h->pdev->dev, "could not add disk 0.\n");
        return;
 }
 
        return;
 }
 
@@ -2196,7 +2236,6 @@ error:
 static int rebuild_lun_table(ctlr_info_t *h, int first_time,
        int via_ioctl)
 {
 static int rebuild_lun_table(ctlr_info_t *h, int first_time,
        int via_ioctl)
 {
-       int ctlr = h->ctlr;
        int num_luns;
        ReportLunData_struct *ld_buff = NULL;
        int return_code;
        int num_luns;
        ReportLunData_struct *ld_buff = NULL;
        int return_code;
@@ -2211,27 +2250,27 @@ static int rebuild_lun_table(ctlr_info_t *h, int first_time,
                return -EPERM;
 
        /* Set busy_configuring flag for this operation */
                return -EPERM;
 
        /* Set busy_configuring flag for this operation */
-       spin_lock_irqsave(CCISS_LOCK(h->ctlr), flags);
+       spin_lock_irqsave(&h->lock, flags);
        if (h->busy_configuring) {
        if (h->busy_configuring) {
-               spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags);
+               spin_unlock_irqrestore(&h->lock, flags);
                return -EBUSY;
        }
        h->busy_configuring = 1;
                return -EBUSY;
        }
        h->busy_configuring = 1;
-       spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags);
+       spin_unlock_irqrestore(&h->lock, flags);
 
        ld_buff = kzalloc(sizeof(ReportLunData_struct), GFP_KERNEL);
        if (ld_buff == NULL)
                goto mem_msg;
 
 
        ld_buff = kzalloc(sizeof(ReportLunData_struct), GFP_KERNEL);
        if (ld_buff == NULL)
                goto mem_msg;
 
-       return_code = sendcmd_withirq(CISS_REPORT_LOG, ctlr, ld_buff,
+       return_code = sendcmd_withirq(h, CISS_REPORT_LOG, ld_buff,
                                      sizeof(ReportLunData_struct),
                                      0, CTLR_LUNID, TYPE_CMD);
 
        if (return_code == IO_OK)
                listlength = be32_to_cpu(*(__be32 *) ld_buff->LUNListLength);
        else {  /* reading number of logical volumes failed */
                                      sizeof(ReportLunData_struct),
                                      0, CTLR_LUNID, TYPE_CMD);
 
        if (return_code == IO_OK)
                listlength = be32_to_cpu(*(__be32 *) ld_buff->LUNListLength);
        else {  /* reading number of logical volumes failed */
-               printk(KERN_WARNING "cciss: report logical volume"
-                      " command failed\n");
+               dev_warn(&h->pdev->dev,
+                       "report logical volume command failed\n");
                listlength = 0;
                goto freeret;
        }
                listlength = 0;
                goto freeret;
        }
@@ -2239,7 +2278,7 @@ static int rebuild_lun_table(ctlr_info_t *h, int first_time,
        num_luns = listlength / 8;      /* 8 bytes per entry */
        if (num_luns > CISS_MAX_LUN) {
                num_luns = CISS_MAX_LUN;
        num_luns = listlength / 8;      /* 8 bytes per entry */
        if (num_luns > CISS_MAX_LUN) {
                num_luns = CISS_MAX_LUN;
-               printk(KERN_WARNING "cciss: more luns configured"
+               dev_warn(&h->pdev->dev, "more luns configured"
                       " on controller than can be handled by"
                       " this driver.\n");
        }
                       " on controller than can be handled by"
                       " this driver.\n");
        }
@@ -2270,9 +2309,9 @@ static int rebuild_lun_table(ctlr_info_t *h, int first_time,
                }
                if (!drv_found) {
                        /* Deregister it from the OS, it's gone. */
                }
                if (!drv_found) {
                        /* Deregister it from the OS, it's gone. */
-                       spin_lock_irqsave(CCISS_LOCK(h->ctlr), flags);
+                       spin_lock_irqsave(&h->lock, flags);
                        h->drv[i]->busy_configuring = 1;
                        h->drv[i]->busy_configuring = 1;
-                       spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags);
+                       spin_unlock_irqrestore(&h->lock, flags);
                        return_code = deregister_disk(h, i, 1, via_ioctl);
                        if (h->drv[i] != NULL)
                                h->drv[i]->busy_configuring = 0;
                        return_code = deregister_disk(h, i, 1, via_ioctl);
                        if (h->drv[i] != NULL)
                                h->drv[i]->busy_configuring = 0;
@@ -2311,8 +2350,7 @@ static int rebuild_lun_table(ctlr_info_t *h, int first_time,
                        if (drv_index == -1)
                                goto freeret;
                }
                        if (drv_index == -1)
                                goto freeret;
                }
-               cciss_update_drive_info(ctlr, drv_index, first_time,
-                       via_ioctl);
+               cciss_update_drive_info(h, drv_index, first_time, via_ioctl);
        }               /* end for */
 
 freeret:
        }               /* end for */
 
 freeret:
@@ -2324,7 +2362,7 @@ freeret:
         */
        return -1;
 mem_msg:
         */
        return -1;
 mem_msg:
-       printk(KERN_ERR "cciss: out of memory\n");
+       dev_err(&h->pdev->dev, "out of memory\n");
        h->busy_configuring = 0;
        goto freeret;
 }
        h->busy_configuring = 0;
        goto freeret;
 }
@@ -2444,11 +2482,10 @@ static int deregister_disk(ctlr_info_t *h, int drv_index,
        return 0;
 }
 
        return 0;
 }
 
-static int fill_cmd(CommandList_struct *c, __u8 cmd, int ctlr, void *buff,
+static int fill_cmd(ctlr_info_t *h, CommandList_struct *c, __u8 cmd, void *buff,
                size_t size, __u8 page_code, unsigned char *scsi3addr,
                int cmd_type)
 {
                size_t size, __u8 page_code, unsigned char *scsi3addr,
                int cmd_type)
 {
-       ctlr_info_t *h = hba[ctlr];
        u64bit buff_dma_handle;
        int status = IO_OK;
 
        u64bit buff_dma_handle;
        int status = IO_OK;
 
@@ -2532,8 +2569,7 @@ static int fill_cmd(CommandList_struct *c, __u8 cmd, int ctlr, void *buff,
                        c->Request.Timeout = 0;
                        break;
                default:
                        c->Request.Timeout = 0;
                        break;
                default:
-                       printk(KERN_WARNING
-                              "cciss%d:  Unknown Command 0x%c\n", ctlr, cmd);
+                       dev_warn(&h->pdev->dev, "Unknown Command 0x%c\n", cmd);
                        return IO_ERROR;
                }
        } else if (cmd_type == TYPE_MSG) {
                        return IO_ERROR;
                }
        } else if (cmd_type == TYPE_MSG) {
@@ -2565,13 +2601,12 @@ static int fill_cmd(CommandList_struct *c, __u8 cmd, int ctlr, void *buff,
                        c->Request.CDB[0] = cmd;
                        break;
                default:
                        c->Request.CDB[0] = cmd;
                        break;
                default:
-                       printk(KERN_WARNING
-                              "cciss%d: unknown message type %d\n", ctlr, cmd);
+                       dev_warn(&h->pdev->dev,
+                               "unknown message type %d\n", cmd);
                        return IO_ERROR;
                }
        } else {
                        return IO_ERROR;
                }
        } else {
-               printk(KERN_WARNING
-                      "cciss%d: unknown command type %d\n", ctlr, cmd_type);
+               dev_warn(&h->pdev->dev, "unknown command type %d\n", cmd_type);
                return IO_ERROR;
        }
        /* Fill in the scatter gather information */
                return IO_ERROR;
        }
        /* Fill in the scatter gather information */
@@ -2599,15 +2634,14 @@ static int check_target_status(ctlr_info_t *h, CommandList_struct *c)
                default:
                        if (check_for_unit_attention(h, c))
                                return IO_NEEDS_RETRY;
                default:
                        if (check_for_unit_attention(h, c))
                                return IO_NEEDS_RETRY;
-                       printk(KERN_WARNING "cciss%d: cmd 0x%02x "
+                       dev_warn(&h->pdev->dev, "cmd 0x%02x "
                                "check condition, sense key = 0x%02x\n",
                                "check condition, sense key = 0x%02x\n",
-                               h->ctlr, c->Request.CDB[0],
-                               c->err_info->SenseInfo[2]);
+                               c->Request.CDB[0], c->err_info->SenseInfo[2]);
                }
                break;
        default:
                }
                break;
        default:
-               printk(KERN_WARNING "cciss%d: cmd 0x%02x"
-                       "scsi status = 0x%02x\n", h->ctlr,
+               dev_warn(&h->pdev->dev, "cmd 0x%02x"
+                       "scsi status = 0x%02x\n",
                        c->Request.CDB[0], c->err_info->ScsiStatus);
                break;
        }
                        c->Request.CDB[0], c->err_info->ScsiStatus);
                break;
        }
@@ -2630,43 +2664,42 @@ static int process_sendcmd_error(ctlr_info_t *h, CommandList_struct *c)
                /* expected for inquiry and report lun commands */
                break;
        case CMD_INVALID:
                /* expected for inquiry and report lun commands */
                break;
        case CMD_INVALID:
-               printk(KERN_WARNING "cciss: cmd 0x%02x is "
+               dev_warn(&h->pdev->dev, "cmd 0x%02x is "
                       "reported invalid\n", c->Request.CDB[0]);
                return_status = IO_ERROR;
                break;
        case CMD_PROTOCOL_ERR:
                       "reported invalid\n", c->Request.CDB[0]);
                return_status = IO_ERROR;
                break;
        case CMD_PROTOCOL_ERR:
-               printk(KERN_WARNING "cciss: cmd 0x%02x has "
-                      "protocol error \n", c->Request.CDB[0]);
+               dev_warn(&h->pdev->dev, "cmd 0x%02x has "
+                      "protocol error\n", c->Request.CDB[0]);
                return_status = IO_ERROR;
                break;
        case CMD_HARDWARE_ERR:
                return_status = IO_ERROR;
                break;
        case CMD_HARDWARE_ERR:
-               printk(KERN_WARNING "cciss: cmd 0x%02x had "
+               dev_warn(&h->pdev->dev, "cmd 0x%02x had "
                       " hardware error\n", c->Request.CDB[0]);
                return_status = IO_ERROR;
                break;
        case CMD_CONNECTION_LOST:
                       " hardware error\n", c->Request.CDB[0]);
                return_status = IO_ERROR;
                break;
        case CMD_CONNECTION_LOST:
-               printk(KERN_WARNING "cciss: cmd 0x%02x had "
+               dev_warn(&h->pdev->dev, "cmd 0x%02x had "
                       "connection lost\n", c->Request.CDB[0]);
                return_status = IO_ERROR;
                break;
        case CMD_ABORTED:
                       "connection lost\n", c->Request.CDB[0]);
                return_status = IO_ERROR;
                break;
        case CMD_ABORTED:
-               printk(KERN_WARNING "cciss: cmd 0x%02x was "
+               dev_warn(&h->pdev->dev, "cmd 0x%02x was "
                       "aborted\n", c->Request.CDB[0]);
                return_status = IO_ERROR;
                break;
        case CMD_ABORT_FAILED:
                       "aborted\n", c->Request.CDB[0]);
                return_status = IO_ERROR;
                break;
        case CMD_ABORT_FAILED:
-               printk(KERN_WARNING "cciss: cmd 0x%02x reports "
+               dev_warn(&h->pdev->dev, "cmd 0x%02x reports "
                       "abort failed\n", c->Request.CDB[0]);
                return_status = IO_ERROR;
                break;
        case CMD_UNSOLICITED_ABORT:
                       "abort failed\n", c->Request.CDB[0]);
                return_status = IO_ERROR;
                break;
        case CMD_UNSOLICITED_ABORT:
-               printk(KERN_WARNING
-                      "cciss%d: unsolicited abort 0x%02x\n", h->ctlr,
+               dev_warn(&h->pdev->dev, "unsolicited abort 0x%02x\n",
                        c->Request.CDB[0]);
                return_status = IO_NEEDS_RETRY;
                break;
        default:
                        c->Request.CDB[0]);
                return_status = IO_NEEDS_RETRY;
                break;
        default:
-               printk(KERN_WARNING "cciss: cmd 0x%02x returned "
+               dev_warn(&h->pdev->dev, "cmd 0x%02x returned "
                       "unknown status %x\n", c->Request.CDB[0],
                       c->err_info->CommandStatus);
                return_status = IO_ERROR;
                       "unknown status %x\n", c->Request.CDB[0],
                       c->err_info->CommandStatus);
                return_status = IO_ERROR;
@@ -2679,17 +2712,11 @@ static int sendcmd_withirq_core(ctlr_info_t *h, CommandList_struct *c,
 {
        DECLARE_COMPLETION_ONSTACK(wait);
        u64bit buff_dma_handle;
 {
        DECLARE_COMPLETION_ONSTACK(wait);
        u64bit buff_dma_handle;
-       unsigned long flags;
        int return_status = IO_OK;
 
 resend_cmd2:
        c->waiting = &wait;
        int return_status = IO_OK;
 
 resend_cmd2:
        c->waiting = &wait;
-       /* Put the request on the tail of the queue and send it */
-       spin_lock_irqsave(CCISS_LOCK(h->ctlr), flags);
-       addQ(&h->reqQ, c);
-       h->Qdepth++;
-       start_io(h);
-       spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags);
+       enqueue_cmd_and_start_io(h, c);
 
        wait_for_completion(&wait);
 
 
        wait_for_completion(&wait);
 
@@ -2700,7 +2727,7 @@ resend_cmd2:
 
        if (return_status == IO_NEEDS_RETRY &&
                c->retry_count < MAX_CMD_RETRIES) {
 
        if (return_status == IO_NEEDS_RETRY &&
                c->retry_count < MAX_CMD_RETRIES) {
-               printk(KERN_WARNING "cciss%d: retrying 0x%02x\n", h->ctlr,
+               dev_warn(&h->pdev->dev, "retrying 0x%02x\n",
                        c->Request.CDB[0]);
                c->retry_count++;
                /* erase the old error information */
                        c->Request.CDB[0]);
                c->retry_count++;
                /* erase the old error information */
@@ -2719,27 +2746,26 @@ command_done:
        return return_status;
 }
 
        return return_status;
 }
 
-static int sendcmd_withirq(__u8 cmd, int ctlr, void *buff, size_t size,
+static int sendcmd_withirq(ctlr_info_t *h, __u8 cmd, void *buff, size_t size,
                           __u8 page_code, unsigned char scsi3addr[],
                        int cmd_type)
 {
                           __u8 page_code, unsigned char scsi3addr[],
                        int cmd_type)
 {
-       ctlr_info_t *h = hba[ctlr];
        CommandList_struct *c;
        int return_status;
 
        CommandList_struct *c;
        int return_status;
 
-       c = cmd_alloc(h, 0);
+       c = cmd_special_alloc(h);
        if (!c)
                return -ENOMEM;
        if (!c)
                return -ENOMEM;
-       return_status = fill_cmd(c, cmd, ctlr, buff, size, page_code,
+       return_status = fill_cmd(h, c, cmd, buff, size, page_code,
                scsi3addr, cmd_type);
        if (return_status == IO_OK)
                return_status = sendcmd_withirq_core(h, c, 1);
 
                scsi3addr, cmd_type);
        if (return_status == IO_OK)
                return_status = sendcmd_withirq_core(h, c, 1);
 
-       cmd_free(h, c, 0);
+       cmd_special_free(h, c);
        return return_status;
 }
 
        return return_status;
 }
 
-static void cciss_geometry_inquiry(int ctlr, int logvol,
+static void cciss_geometry_inquiry(ctlr_info_t *h, int logvol,
                                   sector_t total_size,
                                   unsigned int block_size,
                                   InquiryData_struct *inq_buff,
                                   sector_t total_size,
                                   unsigned int block_size,
                                   InquiryData_struct *inq_buff,
@@ -2750,13 +2776,13 @@ static void cciss_geometry_inquiry(int ctlr, int logvol,
        unsigned char scsi3addr[8];
 
        memset(inq_buff, 0, sizeof(InquiryData_struct));
        unsigned char scsi3addr[8];
 
        memset(inq_buff, 0, sizeof(InquiryData_struct));
-       log_unit_to_scsi3addr(hba[ctlr], scsi3addr, logvol);
-       return_code = sendcmd_withirq(CISS_INQUIRY, ctlr, inq_buff,
+       log_unit_to_scsi3addr(h, scsi3addr, logvol);
+       return_code = sendcmd_withirq(h, CISS_INQUIRY, inq_buff,
                        sizeof(*inq_buff), 0xC1, scsi3addr, TYPE_CMD);
        if (return_code == IO_OK) {
                if (inq_buff->data_byte[8] == 0xFF) {
                        sizeof(*inq_buff), 0xC1, scsi3addr, TYPE_CMD);
        if (return_code == IO_OK) {
                if (inq_buff->data_byte[8] == 0xFF) {
-                       printk(KERN_WARNING
-                              "cciss: reading geometry failed, volume "
+                       dev_warn(&h->pdev->dev,
+                              "reading geometry failed, volume "
                               "does not support reading geometry\n");
                        drv->heads = 255;
                        drv->sectors = 32;      /* Sectors per track */
                               "does not support reading geometry\n");
                        drv->heads = 255;
                        drv->sectors = 32;      /* Sectors per track */
@@ -2780,12 +2806,12 @@ static void cciss_geometry_inquiry(int ctlr, int logvol,
                        drv->cylinders = real_size;
                }
        } else {                /* Get geometry failed */
                        drv->cylinders = real_size;
                }
        } else {                /* Get geometry failed */
-               printk(KERN_WARNING "cciss: reading geometry failed\n");
+               dev_warn(&h->pdev->dev, "reading geometry failed\n");
        }
 }
 
 static void
        }
 }
 
 static void
-cciss_read_capacity(int ctlr, int logvol, sector_t *total_size,
+cciss_read_capacity(ctlr_info_t *h, int logvol, sector_t *total_size,
                    unsigned int *block_size)
 {
        ReadCapdata_struct *buf;
                    unsigned int *block_size)
 {
        ReadCapdata_struct *buf;
@@ -2794,25 +2820,25 @@ cciss_read_capacity(int ctlr, int logvol, sector_t *total_size,
 
        buf = kzalloc(sizeof(ReadCapdata_struct), GFP_KERNEL);
        if (!buf) {
 
        buf = kzalloc(sizeof(ReadCapdata_struct), GFP_KERNEL);
        if (!buf) {
-               printk(KERN_WARNING "cciss: out of memory\n");
+               dev_warn(&h->pdev->dev, "out of memory\n");
                return;
        }
 
                return;
        }
 
-       log_unit_to_scsi3addr(hba[ctlr], scsi3addr, logvol);
-       return_code = sendcmd_withirq(CCISS_READ_CAPACITY, ctlr, buf,
+       log_unit_to_scsi3addr(h, scsi3addr, logvol);
+       return_code = sendcmd_withirq(h, CCISS_READ_CAPACITY, buf,
                sizeof(ReadCapdata_struct), 0, scsi3addr, TYPE_CMD);
        if (return_code == IO_OK) {
                *total_size = be32_to_cpu(*(__be32 *) buf->total_size);
                *block_size = be32_to_cpu(*(__be32 *) buf->block_size);
        } else {                /* read capacity command failed */
                sizeof(ReadCapdata_struct), 0, scsi3addr, TYPE_CMD);
        if (return_code == IO_OK) {
                *total_size = be32_to_cpu(*(__be32 *) buf->total_size);
                *block_size = be32_to_cpu(*(__be32 *) buf->block_size);
        } else {                /* read capacity command failed */
-               printk(KERN_WARNING "cciss: read capacity failed\n");
+               dev_warn(&h->pdev->dev, "read capacity failed\n");
                *total_size = 0;
                *block_size = BLOCK_SIZE;
        }
        kfree(buf);
 }
 
                *total_size = 0;
                *block_size = BLOCK_SIZE;
        }
        kfree(buf);
 }
 
-static void cciss_read_capacity_16(int ctlr, int logvol,
+static void cciss_read_capacity_16(ctlr_info_t *h, int logvol,
        sector_t *total_size, unsigned int *block_size)
 {
        ReadCapdata_struct_16 *buf;
        sector_t *total_size, unsigned int *block_size)
 {
        ReadCapdata_struct_16 *buf;
@@ -2821,23 +2847,23 @@ static void cciss_read_capacity_16(int ctlr, int logvol,
 
        buf = kzalloc(sizeof(ReadCapdata_struct_16), GFP_KERNEL);
        if (!buf) {
 
        buf = kzalloc(sizeof(ReadCapdata_struct_16), GFP_KERNEL);
        if (!buf) {
-               printk(KERN_WARNING "cciss: out of memory\n");
+               dev_warn(&h->pdev->dev, "out of memory\n");
                return;
        }
 
                return;
        }
 
-       log_unit_to_scsi3addr(hba[ctlr], scsi3addr, logvol);
-       return_code = sendcmd_withirq(CCISS_READ_CAPACITY_16,
-               ctlr, buf, sizeof(ReadCapdata_struct_16),
+       log_unit_to_scsi3addr(h, scsi3addr, logvol);
+       return_code = sendcmd_withirq(h, CCISS_READ_CAPACITY_16,
+               buf, sizeof(ReadCapdata_struct_16),
                        0, scsi3addr, TYPE_CMD);
        if (return_code == IO_OK) {
                *total_size = be64_to_cpu(*(__be64 *) buf->total_size);
                *block_size = be32_to_cpu(*(__be32 *) buf->block_size);
        } else {                /* read capacity command failed */
                        0, scsi3addr, TYPE_CMD);
        if (return_code == IO_OK) {
                *total_size = be64_to_cpu(*(__be64 *) buf->total_size);
                *block_size = be32_to_cpu(*(__be32 *) buf->block_size);
        } else {                /* read capacity command failed */
-               printk(KERN_WARNING "cciss: read capacity failed\n");
+               dev_warn(&h->pdev->dev, "read capacity failed\n");
                *total_size = 0;
                *block_size = BLOCK_SIZE;
        }
                *total_size = 0;
                *block_size = BLOCK_SIZE;
        }
-       printk(KERN_INFO "      blocks= %llu block_size= %d\n",
+       dev_info(&h->pdev->dev, "      blocks= %llu block_size= %d\n",
               (unsigned long long)*total_size+1, *block_size);
        kfree(buf);
 }
               (unsigned long long)*total_size+1, *block_size);
        kfree(buf);
 }
@@ -2865,17 +2891,17 @@ static int cciss_revalidate(struct gendisk *disk)
 
        inq_buff = kmalloc(sizeof(InquiryData_struct), GFP_KERNEL);
        if (inq_buff == NULL) {
 
        inq_buff = kmalloc(sizeof(InquiryData_struct), GFP_KERNEL);
        if (inq_buff == NULL) {
-               printk(KERN_WARNING "cciss: out of memory\n");
+               dev_warn(&h->pdev->dev, "out of memory\n");
                return 1;
        }
        if (h->cciss_read == CCISS_READ_10) {
                return 1;
        }
        if (h->cciss_read == CCISS_READ_10) {
-               cciss_read_capacity(h->ctlr, logvol,
+               cciss_read_capacity(h, logvol,
                                        &total_size, &block_size);
        } else {
                                        &total_size, &block_size);
        } else {
-               cciss_read_capacity_16(h->ctlr, logvol,
+               cciss_read_capacity_16(h, logvol,
                                        &total_size, &block_size);
        }
                                        &total_size, &block_size);
        }
-       cciss_geometry_inquiry(h->ctlr, logvol, total_size, block_size,
+       cciss_geometry_inquiry(h, logvol, total_size, block_size,
                               inq_buff, drv);
 
        blk_queue_logical_block_size(drv->queue, drv->block_size);
                               inq_buff, drv);
 
        blk_queue_logical_block_size(drv->queue, drv->block_size);
@@ -2909,7 +2935,7 @@ static void start_io(ctlr_info_t *h)
                c = hlist_entry(h->reqQ.first, CommandList_struct, list);
                /* can't do anything if fifo is full */
                if ((h->access.fifo_full(h))) {
                c = hlist_entry(h->reqQ.first, CommandList_struct, list);
                /* can't do anything if fifo is full */
                if ((h->access.fifo_full(h))) {
-                       printk(KERN_WARNING "cciss: fifo full\n");
+                       dev_warn(&h->pdev->dev, "fifo full\n");
                        break;
                }
 
                        break;
                }
 
@@ -2925,7 +2951,7 @@ static void start_io(ctlr_info_t *h)
        }
 }
 
        }
 }
 
-/* Assumes that CCISS_LOCK(h->ctlr) is held. */
+/* Assumes that h->lock is held. */
 /* Zeros out the error record and then resends the command back */
 /* to the controller */
 static inline void resend_cciss_cmd(ctlr_info_t *h, CommandList_struct *c)
 /* Zeros out the error record and then resends the command back */
 /* to the controller */
 static inline void resend_cciss_cmd(ctlr_info_t *h, CommandList_struct *c)
@@ -2966,7 +2992,7 @@ static inline int evaluate_target_status(ctlr_info_t *h,
        driver_byte = DRIVER_OK;
        msg_byte = cmd->err_info->CommandStatus; /* correct?  seems too device specific */
 
        driver_byte = DRIVER_OK;
        msg_byte = cmd->err_info->CommandStatus; /* correct?  seems too device specific */
 
-       if (blk_pc_request(cmd->rq))
+       if (cmd->rq->cmd_type == REQ_TYPE_BLOCK_PC)
                host_byte = DID_PASSTHROUGH;
        else
                host_byte = DID_OK;
                host_byte = DID_PASSTHROUGH;
        else
                host_byte = DID_OK;
@@ -2975,8 +3001,8 @@ static inline int evaluate_target_status(ctlr_info_t *h,
                host_byte, driver_byte);
 
        if (cmd->err_info->ScsiStatus != SAM_STAT_CHECK_CONDITION) {
                host_byte, driver_byte);
 
        if (cmd->err_info->ScsiStatus != SAM_STAT_CHECK_CONDITION) {
-               if (!blk_pc_request(cmd->rq))
-                       printk(KERN_WARNING "cciss: cmd %p "
+               if (cmd->rq->cmd_type != REQ_TYPE_BLOCK_PC)
+                       dev_warn(&h->pdev->dev, "cmd %p "
                               "has SCSI Status 0x%x\n",
                               cmd, cmd->err_info->ScsiStatus);
                return error_value;
                               "has SCSI Status 0x%x\n",
                               cmd, cmd->err_info->ScsiStatus);
                return error_value;
@@ -2985,17 +3011,19 @@ static inline int evaluate_target_status(ctlr_info_t *h,
        /* check the sense key */
        sense_key = 0xf & cmd->err_info->SenseInfo[2];
        /* no status or recovered error */
        /* check the sense key */
        sense_key = 0xf & cmd->err_info->SenseInfo[2];
        /* no status or recovered error */
-       if (((sense_key == 0x0) || (sense_key == 0x1)) && !blk_pc_request(cmd->rq))
+       if (((sense_key == 0x0) || (sense_key == 0x1)) &&
+           (cmd->rq->cmd_type != REQ_TYPE_BLOCK_PC))
                error_value = 0;
 
        if (check_for_unit_attention(h, cmd)) {
                error_value = 0;
 
        if (check_for_unit_attention(h, cmd)) {
-               *retry_cmd = !blk_pc_request(cmd->rq);
+               *retry_cmd = !(cmd->rq->cmd_type == REQ_TYPE_BLOCK_PC);
                return 0;
        }
 
                return 0;
        }
 
-       if (!blk_pc_request(cmd->rq)) { /* Not SG_IO or similar? */
+       /* Not SG_IO or similar? */
+       if (cmd->rq->cmd_type != REQ_TYPE_BLOCK_PC) {
                if (error_value != 0)
                if (error_value != 0)
-                       printk(KERN_WARNING "cciss: cmd %p has CHECK CONDITION"
+                       dev_warn(&h->pdev->dev, "cmd %p has CHECK CONDITION"
                               " sense key = 0x%x\n", cmd, sense_key);
                return error_value;
        }
                               " sense key = 0x%x\n", cmd, sense_key);
                return error_value;
        }
@@ -3035,90 +3063,97 @@ static inline void complete_command(ctlr_info_t *h, CommandList_struct *cmd,
                rq->errors = evaluate_target_status(h, cmd, &retry_cmd);
                break;
        case CMD_DATA_UNDERRUN:
                rq->errors = evaluate_target_status(h, cmd, &retry_cmd);
                break;
        case CMD_DATA_UNDERRUN:
-               if (blk_fs_request(cmd->rq)) {
-                       printk(KERN_WARNING "cciss: cmd %p has"
+               if (cmd->rq->cmd_type == REQ_TYPE_FS) {
+                       dev_warn(&h->pdev->dev, "cmd %p has"
                               " completed with data underrun "
                               "reported\n", cmd);
                        cmd->rq->resid_len = cmd->err_info->ResidualCnt;
                }
                break;
        case CMD_DATA_OVERRUN:
                               " completed with data underrun "
                               "reported\n", cmd);
                        cmd->rq->resid_len = cmd->err_info->ResidualCnt;
                }
                break;
        case CMD_DATA_OVERRUN:
-               if (blk_fs_request(cmd->rq))
-                       printk(KERN_WARNING "cciss: cmd %p has"
+               if (cmd->rq->cmd_type == REQ_TYPE_FS)
+                       dev_warn(&h->pdev->dev, "cciss: cmd %p has"
                               " completed with data overrun "
                               "reported\n", cmd);
                break;
        case CMD_INVALID:
                               " completed with data overrun "
                               "reported\n", cmd);
                break;
        case CMD_INVALID:
-               printk(KERN_WARNING "cciss: cmd %p is "
+               dev_warn(&h->pdev->dev, "cciss: cmd %p is "
                       "reported invalid\n", cmd);
                rq->errors = make_status_bytes(SAM_STAT_GOOD,
                        cmd->err_info->CommandStatus, DRIVER_OK,
                       "reported invalid\n", cmd);
                rq->errors = make_status_bytes(SAM_STAT_GOOD,
                        cmd->err_info->CommandStatus, DRIVER_OK,
-                       blk_pc_request(cmd->rq) ? DID_PASSTHROUGH : DID_ERROR);
+                       (cmd->rq->cmd_type == REQ_TYPE_BLOCK_PC) ?
+                               DID_PASSTHROUGH : DID_ERROR);
                break;
        case CMD_PROTOCOL_ERR:
                break;
        case CMD_PROTOCOL_ERR:
-               printk(KERN_WARNING "cciss: cmd %p has "
-                      "protocol error \n", cmd);
+               dev_warn(&h->pdev->dev, "cciss: cmd %p has "
+                      "protocol error\n", cmd);
                rq->errors = make_status_bytes(SAM_STAT_GOOD,
                        cmd->err_info->CommandStatus, DRIVER_OK,
                rq->errors = make_status_bytes(SAM_STAT_GOOD,
                        cmd->err_info->CommandStatus, DRIVER_OK,
-                       blk_pc_request(cmd->rq) ? DID_PASSTHROUGH : DID_ERROR);
+                       (cmd->rq->cmd_type == REQ_TYPE_BLOCK_PC) ?
+                               DID_PASSTHROUGH : DID_ERROR);
                break;
        case CMD_HARDWARE_ERR:
                break;
        case CMD_HARDWARE_ERR:
-               printk(KERN_WARNING "cciss: cmd %p had "
+               dev_warn(&h->pdev->dev, "cciss: cmd %p had "
                       " hardware error\n", cmd);
                rq->errors = make_status_bytes(SAM_STAT_GOOD,
                        cmd->err_info->CommandStatus, DRIVER_OK,
                       " hardware error\n", cmd);
                rq->errors = make_status_bytes(SAM_STAT_GOOD,
                        cmd->err_info->CommandStatus, DRIVER_OK,
-                       blk_pc_request(cmd->rq) ? DID_PASSTHROUGH : DID_ERROR);
+                       (cmd->rq->cmd_type == REQ_TYPE_BLOCK_PC) ?
+                               DID_PASSTHROUGH : DID_ERROR);
                break;
        case CMD_CONNECTION_LOST:
                break;
        case CMD_CONNECTION_LOST:
-               printk(KERN_WARNING "cciss: cmd %p had "
+               dev_warn(&h->pdev->dev, "cciss: cmd %p had "
                       "connection lost\n", cmd);
                rq->errors = make_status_bytes(SAM_STAT_GOOD,
                        cmd->err_info->CommandStatus, DRIVER_OK,
                       "connection lost\n", cmd);
                rq->errors = make_status_bytes(SAM_STAT_GOOD,
                        cmd->err_info->CommandStatus, DRIVER_OK,
-                       blk_pc_request(cmd->rq) ? DID_PASSTHROUGH : DID_ERROR);
+                       (cmd->rq->cmd_type == REQ_TYPE_BLOCK_PC) ?
+                               DID_PASSTHROUGH : DID_ERROR);
                break;
        case CMD_ABORTED:
                break;
        case CMD_ABORTED:
-               printk(KERN_WARNING "cciss: cmd %p was "
+               dev_warn(&h->pdev->dev, "cciss: cmd %p was "
                       "aborted\n", cmd);
                rq->errors = make_status_bytes(SAM_STAT_GOOD,
                        cmd->err_info->CommandStatus, DRIVER_OK,
                       "aborted\n", cmd);
                rq->errors = make_status_bytes(SAM_STAT_GOOD,
                        cmd->err_info->CommandStatus, DRIVER_OK,
-                       blk_pc_request(cmd->rq) ? DID_PASSTHROUGH : DID_ABORT);
+                       (cmd->rq->cmd_type == REQ_TYPE_BLOCK_PC) ?
+                               DID_PASSTHROUGH : DID_ABORT);
                break;
        case CMD_ABORT_FAILED:
                break;
        case CMD_ABORT_FAILED:
-               printk(KERN_WARNING "cciss: cmd %p reports "
+               dev_warn(&h->pdev->dev, "cciss: cmd %p reports "
                       "abort failed\n", cmd);
                rq->errors = make_status_bytes(SAM_STAT_GOOD,
                        cmd->err_info->CommandStatus, DRIVER_OK,
                       "abort failed\n", cmd);
                rq->errors = make_status_bytes(SAM_STAT_GOOD,
                        cmd->err_info->CommandStatus, DRIVER_OK,
-                       blk_pc_request(cmd->rq) ? DID_PASSTHROUGH : DID_ERROR);
+                       (cmd->rq->cmd_type == REQ_TYPE_BLOCK_PC) ?
+                               DID_PASSTHROUGH : DID_ERROR);
                break;
        case CMD_UNSOLICITED_ABORT:
                break;
        case CMD_UNSOLICITED_ABORT:
-               printk(KERN_WARNING "cciss%d: unsolicited "
+               dev_warn(&h->pdev->dev, "cciss%d: unsolicited "
                       "abort %p\n", h->ctlr, cmd);
                if (cmd->retry_count < MAX_CMD_RETRIES) {
                        retry_cmd = 1;
                       "abort %p\n", h->ctlr, cmd);
                if (cmd->retry_count < MAX_CMD_RETRIES) {
                        retry_cmd = 1;
-                       printk(KERN_WARNING
-                              "cciss%d: retrying %p\n", h->ctlr, cmd);
+                       dev_warn(&h->pdev->dev, "retrying %p\n", cmd);
                        cmd->retry_count++;
                } else
                        cmd->retry_count++;
                } else
-                       printk(KERN_WARNING
-                              "cciss%d: %p retried too "
-                              "many times\n", h->ctlr, cmd);
+                       dev_warn(&h->pdev->dev,
+                               "%p retried too many times\n", cmd);
                rq->errors = make_status_bytes(SAM_STAT_GOOD,
                        cmd->err_info->CommandStatus, DRIVER_OK,
                rq->errors = make_status_bytes(SAM_STAT_GOOD,
                        cmd->err_info->CommandStatus, DRIVER_OK,
-                       blk_pc_request(cmd->rq) ? DID_PASSTHROUGH : DID_ABORT);
+                       (cmd->rq->cmd_type == REQ_TYPE_BLOCK_PC) ?
+                               DID_PASSTHROUGH : DID_ABORT);
                break;
        case CMD_TIMEOUT:
                break;
        case CMD_TIMEOUT:
-               printk(KERN_WARNING "cciss: cmd %p timedout\n", cmd);
+               dev_warn(&h->pdev->dev, "cmd %p timedout\n", cmd);
                rq->errors = make_status_bytes(SAM_STAT_GOOD,
                        cmd->err_info->CommandStatus, DRIVER_OK,
                rq->errors = make_status_bytes(SAM_STAT_GOOD,
                        cmd->err_info->CommandStatus, DRIVER_OK,
-                       blk_pc_request(cmd->rq) ? DID_PASSTHROUGH : DID_ERROR);
+                       (cmd->rq->cmd_type == REQ_TYPE_BLOCK_PC) ?
+                               DID_PASSTHROUGH : DID_ERROR);
                break;
        default:
                break;
        default:
-               printk(KERN_WARNING "cciss: cmd %p returned "
+               dev_warn(&h->pdev->dev, "cmd %p returned "
                       "unknown status %x\n", cmd,
                       cmd->err_info->CommandStatus);
                rq->errors = make_status_bytes(SAM_STAT_GOOD,
                        cmd->err_info->CommandStatus, DRIVER_OK,
                       "unknown status %x\n", cmd,
                       cmd->err_info->CommandStatus);
                rq->errors = make_status_bytes(SAM_STAT_GOOD,
                        cmd->err_info->CommandStatus, DRIVER_OK,
-                       blk_pc_request(cmd->rq) ? DID_PASSTHROUGH : DID_ERROR);
+                       (cmd->rq->cmd_type == REQ_TYPE_BLOCK_PC) ?
+                               DID_PASSTHROUGH : DID_ERROR);
        }
 
 after_error_processing:
        }
 
 after_error_processing:
@@ -3132,6 +3167,34 @@ after_error_processing:
        blk_complete_request(cmd->rq);
 }
 
        blk_complete_request(cmd->rq);
 }
 
+static inline u32 cciss_tag_contains_index(u32 tag)
+{
+#define DIRECT_LOOKUP_BIT 0x10
+       return tag & DIRECT_LOOKUP_BIT;
+}
+
+static inline u32 cciss_tag_to_index(u32 tag)
+{
+#define DIRECT_LOOKUP_SHIFT 5
+       return tag >> DIRECT_LOOKUP_SHIFT;
+}
+
+static inline u32 cciss_tag_discard_error_bits(u32 tag)
+{
+#define CCISS_ERROR_BITS 0x03
+       return tag & ~CCISS_ERROR_BITS;
+}
+
+static inline void cciss_mark_tag_indexed(u32 *tag)
+{
+       *tag |= DIRECT_LOOKUP_BIT;
+}
+
+static inline void cciss_set_tag_index(u32 *tag, u32 index)
+{
+       *tag |= (index << DIRECT_LOOKUP_SHIFT);
+}
+
 /*
  * Get a request and submit it to the controller.
  */
 /*
  * Get a request and submit it to the controller.
  */
@@ -3163,7 +3226,8 @@ static void do_cciss_request(struct request_queue *q)
 
        BUG_ON(creq->nr_phys_segments > h->maxsgentries);
 
 
        BUG_ON(creq->nr_phys_segments > h->maxsgentries);
 
-       if ((c = cmd_alloc(h, 1)) == NULL)
+       c = cmd_alloc(h);
+       if (!c)
                goto full;
 
        blk_start_request(creq);
                goto full;
 
        blk_start_request(creq);
@@ -3180,8 +3244,8 @@ static void do_cciss_request(struct request_queue *q)
        /* got command from pool, so use the command block index instead */
        /* for direct lookups. */
        /* The first 2 bits are reserved for controller error reporting. */
        /* got command from pool, so use the command block index instead */
        /* for direct lookups. */
        /* The first 2 bits are reserved for controller error reporting. */
-       c->Header.Tag.lower = (c->cmdindex << 3);
-       c->Header.Tag.lower |= 0x04;    /* flag for direct lookup. */
+       cciss_set_tag_index(&c->Header.Tag.lower, c->cmdindex);
+       cciss_mark_tag_indexed(&c->Header.Tag.lower);
        memcpy(&c->Header.LUN, drv->LunID, sizeof(drv->LunID));
        c->Request.CDBLen = 10; /* 12 byte commands not in FW yet; */
        c->Request.Type.Type = TYPE_CMD;        /* It is a command. */
        memcpy(&c->Header.LUN, drv->LunID, sizeof(drv->LunID));
        c->Request.CDBLen = 10; /* 12 byte commands not in FW yet; */
        c->Request.Type.Type = TYPE_CMD;        /* It is a command. */
@@ -3192,11 +3256,8 @@ static void do_cciss_request(struct request_queue *q)
        c->Request.CDB[0] =
            (rq_data_dir(creq) == READ) ? h->cciss_read : h->cciss_write;
        start_blk = blk_rq_pos(creq);
        c->Request.CDB[0] =
            (rq_data_dir(creq) == READ) ? h->cciss_read : h->cciss_write;
        start_blk = blk_rq_pos(creq);
-#ifdef CCISS_DEBUG
-       printk(KERN_DEBUG "ciss: sector =%d nr_sectors=%d\n",
+       dev_dbg(&h->pdev->dev, "sector =%d nr_sectors=%d\n",
               (int)blk_rq_pos(creq), (int)blk_rq_sectors(creq));
               (int)blk_rq_pos(creq), (int)blk_rq_sectors(creq));
-#endif                         /* CCISS_DEBUG */
-
        sg_init_table(tmp_sg, h->maxsgentries);
        seg = blk_rq_map_sg(q, creq, tmp_sg);
 
        sg_init_table(tmp_sg, h->maxsgentries);
        seg = blk_rq_map_sg(q, creq, tmp_sg);
 
@@ -3236,17 +3297,18 @@ static void do_cciss_request(struct request_queue *q)
        if (seg > h->maxSG)
                h->maxSG = seg;
 
        if (seg > h->maxSG)
                h->maxSG = seg;
 
-#ifdef CCISS_DEBUG
-       printk(KERN_DEBUG "cciss: Submitting %ld sectors in %d segments "
+       dev_dbg(&h->pdev->dev, "Submitting %u sectors in %d segments "
                        "chained[%d]\n",
                        blk_rq_sectors(creq), seg, chained);
                        "chained[%d]\n",
                        blk_rq_sectors(creq), seg, chained);
-#endif                         /* CCISS_DEBUG */
 
 
-       c->Header.SGList = c->Header.SGTotal = seg + chained;
-       if (seg > h->max_cmd_sgentries)
+       c->Header.SGTotal = seg + chained;
+       if (seg <= h->max_cmd_sgentries)
+               c->Header.SGList = c->Header.SGTotal;
+       else
                c->Header.SGList = h->max_cmd_sgentries;
                c->Header.SGList = h->max_cmd_sgentries;
+       set_performant_mode(h, c);
 
 
-       if (likely(blk_fs_request(creq))) {
+       if (likely(creq->cmd_type == REQ_TYPE_FS)) {
                if(h->cciss_read == CCISS_READ_10) {
                        c->Request.CDB[1] = 0;
                        c->Request.CDB[2] = (start_blk >> 24) & 0xff; /* MSB */
                if(h->cciss_read == CCISS_READ_10) {
                        c->Request.CDB[1] = 0;
                        c->Request.CDB[2] = (start_blk >> 24) & 0xff; /* MSB */
@@ -3276,11 +3338,12 @@ static void do_cciss_request(struct request_queue *q)
                        c->Request.CDB[13]= blk_rq_sectors(creq) & 0xff;
                        c->Request.CDB[14] = c->Request.CDB[15] = 0;
                }
                        c->Request.CDB[13]= blk_rq_sectors(creq) & 0xff;
                        c->Request.CDB[14] = c->Request.CDB[15] = 0;
                }
-       } else if (blk_pc_request(creq)) {
+       } else if (creq->cmd_type == REQ_TYPE_BLOCK_PC) {
                c->Request.CDBLen = creq->cmd_len;
                memcpy(c->Request.CDB, creq->cmd, BLK_MAX_CDB);
        } else {
                c->Request.CDBLen = creq->cmd_len;
                memcpy(c->Request.CDB, creq->cmd, BLK_MAX_CDB);
        } else {
-               printk(KERN_WARNING "cciss%d: bad request type %d\n", h->ctlr, creq->cmd_type);
+               dev_warn(&h->pdev->dev, "bad request type %d\n",
+                       creq->cmd_type);
                BUG();
        }
 
                BUG();
        }
 
@@ -3313,72 +3376,131 @@ static inline int interrupt_pending(ctlr_info_t *h)
 
 static inline long interrupt_not_for_us(ctlr_info_t *h)
 {
 
 static inline long interrupt_not_for_us(ctlr_info_t *h)
 {
-       return (((h->access.intr_pending(h) == 0) ||
-                (h->interrupts_enabled == 0)));
+       return ((h->access.intr_pending(h) == 0) ||
+               (h->interrupts_enabled == 0));
 }
 
 }
 
-static irqreturn_t do_cciss_intr(int irq, void *dev_id)
+static inline int bad_tag(ctlr_info_t *h, u32 tag_index,
+                       u32 raw_tag)
 {
 {
-       ctlr_info_t *h = dev_id;
+       if (unlikely(tag_index >= h->nr_cmds)) {
+               dev_warn(&h->pdev->dev, "bad tag 0x%08x ignored.\n", raw_tag);
+               return 1;
+       }
+       return 0;
+}
+
+static inline void finish_cmd(ctlr_info_t *h, CommandList_struct *c,
+                               u32 raw_tag)
+{
+       removeQ(c);
+       if (likely(c->cmd_type == CMD_RWREQ))
+               complete_command(h, c, 0);
+       else if (c->cmd_type == CMD_IOCTL_PEND)
+               complete(c->waiting);
+#ifdef CONFIG_CISS_SCSI_TAPE
+       else if (c->cmd_type == CMD_SCSI)
+               complete_scsi_command(c, 0, raw_tag);
+#endif
+}
+
+static inline u32 next_command(ctlr_info_t *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;
+}
+
+/* process completion of an indexed ("direct lookup") command */
+static inline u32 process_indexed_cmd(ctlr_info_t *h, u32 raw_tag)
+{
+       u32 tag_index;
        CommandList_struct *c;
        CommandList_struct *c;
+
+       tag_index = cciss_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(h, c, raw_tag);
+       return next_command(h);
+}
+
+/* process completion of a non-indexed command */
+static inline u32 process_nonindexed_cmd(ctlr_info_t *h, u32 raw_tag)
+{
+       u32 tag;
+       CommandList_struct *c = NULL;
+       struct hlist_node *tmp;
+       __u32 busaddr_masked, tag_masked;
+
+       tag = cciss_tag_discard_error_bits(raw_tag);
+       hlist_for_each_entry(c, tmp, &h->cmpQ, list) {
+               busaddr_masked = cciss_tag_discard_error_bits(c->busaddr);
+               tag_masked = cciss_tag_discard_error_bits(tag);
+               if (busaddr_masked == tag_masked) {
+                       finish_cmd(h, c, raw_tag);
+                       return next_command(h);
+               }
+       }
+       bad_tag(h, h->nr_cmds + 1, raw_tag);
+       return next_command(h);
+}
+
+static irqreturn_t do_cciss_intx(int irq, void *dev_id)
+{
+       ctlr_info_t *h = dev_id;
        unsigned long flags;
        unsigned long flags;
-       __u32 a, a1, a2;
+       u32 raw_tag;
 
        if (interrupt_not_for_us(h))
                return IRQ_NONE;
 
        if (interrupt_not_for_us(h))
                return IRQ_NONE;
-       /*
-        * If there are completed commands in the completion queue,
-        * we had better do something about it.
-        */
-       spin_lock_irqsave(CCISS_LOCK(h->ctlr), flags);
+       spin_lock_irqsave(&h->lock, flags);
        while (interrupt_pending(h)) {
        while (interrupt_pending(h)) {
-               while ((a = get_next_completion(h)) != FIFO_EMPTY) {
-                       a1 = a;
-                       if ((a & 0x04)) {
-                               a2 = (a >> 3);
-                               if (a2 >= h->nr_cmds) {
-                                       printk(KERN_WARNING
-                                              "cciss: controller cciss%d failed, stopping.\n",
-                                              h->ctlr);
-                                       spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags);
-                                       fail_all_cmds(h->ctlr);
-                                       return IRQ_HANDLED;
-                               }
-
-                               c = h->cmd_pool + a2;
-                               a = c->busaddr;
-
-                       } else {
-                               struct hlist_node *tmp;
-
-                               a &= ~3;
-                               c = NULL;
-                               hlist_for_each_entry(c, tmp, &h->cmpQ, list) {
-                                       if (c->busaddr == a)
-                                               break;
-                               }
-                       }
-                       /*
-                        * If we've found the command, take it off the
-                        * completion Q and free it
-                        */
-                       if (c && c->busaddr == a) {
-                               removeQ(c);
-                               if (c->cmd_type == CMD_RWREQ) {
-                                       complete_command(h, c, 0);
-                               } else if (c->cmd_type == CMD_IOCTL_PEND) {
-                                       complete(c->waiting);
-                               }
-#                              ifdef CONFIG_CISS_SCSI_TAPE
-                               else if (c->cmd_type == CMD_SCSI)
-                                       complete_scsi_command(c, 0, a1);
-#                              endif
-                               continue;
-                       }
+               raw_tag = get_next_completion(h);
+               while (raw_tag != FIFO_EMPTY) {
+                       if (cciss_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;
+}
 
 
-       spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags);
+/* Add a second interrupt handler for MSI/MSI-X mode. In this mode we never
+ * check the interrupt pending register because it is not set.
+ */
+static irqreturn_t do_cciss_msix_intr(int irq, void *dev_id)
+{
+       ctlr_info_t *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 (cciss_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;
 }
 
        return IRQ_HANDLED;
 }
 
@@ -3510,18 +3632,17 @@ static int check_for_unit_attention(ctlr_info_t *h, CommandList_struct *c)
 
        switch (c->err_info->SenseInfo[12]) {
        case STATE_CHANGED:
 
        switch (c->err_info->SenseInfo[12]) {
        case STATE_CHANGED:
-               printk(KERN_WARNING "cciss%d: a state change "
-                       "detected, command retried\n", h->ctlr);
+               dev_warn(&h->pdev->dev, "a state change "
+                       "detected, command retried\n");
                return 1;
        break;
        case LUN_FAILED:
                return 1;
        break;
        case LUN_FAILED:
-               printk(KERN_WARNING "cciss%d: LUN failure "
-                       "detected, action required\n", h->ctlr);
+               dev_warn(&h->pdev->dev, "LUN failure "
+                       "detected, action required\n");
                return 1;
        break;
        case REPORT_LUNS_CHANGED:
                return 1;
        break;
        case REPORT_LUNS_CHANGED:
-               printk(KERN_WARNING "cciss%d: report LUN data "
-                       "changed\n", h->ctlr);
+               dev_warn(&h->pdev->dev, "report LUN data changed\n");
        /*
         * 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
        /*
         * 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
@@ -3541,19 +3662,18 @@ static int check_for_unit_attention(ctlr_info_t *h, CommandList_struct *c)
                return 1;
        break;
        case POWER_OR_RESET:
                return 1;
        break;
        case POWER_OR_RESET:
-               printk(KERN_WARNING "cciss%d: a power on "
-                       "or device reset detected\n", h->ctlr);
+               dev_warn(&h->pdev->dev,
+                       "a power on or device reset detected\n");
                return 1;
        break;
        case UNIT_ATTENTION_CLEARED:
                return 1;
        break;
        case UNIT_ATTENTION_CLEARED:
-               printk(KERN_WARNING "cciss%d: unit attention "
-                   "cleared by another initiator\n", h->ctlr);
+               dev_warn(&h->pdev->dev,
+                       "unit attention cleared by another initiator\n");
                return 1;
        break;
        default:
                return 1;
        break;
        default:
-               printk(KERN_WARNING "cciss%d: unknown "
-                       "unit attention detected\n", h->ctlr);
-                               return 1;
+               dev_warn(&h->pdev->dev, "unknown unit attention detected\n");
+               return 1;
        }
 }
 
        }
 }
 
@@ -3562,39 +3682,41 @@ static int check_for_unit_attention(ctlr_info_t *h, CommandList_struct *c)
  *   the io functions.
  *   This is for debug only.
  */
  *   the io functions.
  *   This is for debug only.
  */
-#ifdef CCISS_DEBUG
-static void print_cfg_table(CfgTable_struct *tb)
+static void print_cfg_table(ctlr_info_t *h)
 {
        int i;
        char temp_name[17];
 {
        int i;
        char temp_name[17];
+       CfgTable_struct *tb = h->cfgtable;
 
 
-       printk("Controller Configuration information\n");
-       printk("------------------------------------\n");
+       dev_dbg(&h->pdev->dev, "Controller Configuration information\n");
+       dev_dbg(&h->pdev->dev, "------------------------------------\n");
        for (i = 0; i < 4; i++)
                temp_name[i] = readb(&(tb->Signature[i]));
        temp_name[4] = '\0';
        for (i = 0; i < 4; i++)
                temp_name[i] = readb(&(tb->Signature[i]));
        temp_name[4] = '\0';
-       printk("   Signature = %s\n", temp_name);
-       printk("   Spec Number = %d\n", readl(&(tb->SpecValence)));
-       printk("   Transport methods supported = 0x%x\n",
+       dev_dbg(&h->pdev->dev, "   Signature = %s\n", temp_name);
+       dev_dbg(&h->pdev->dev, "   Spec Number = %d\n",
+               readl(&(tb->SpecValence)));
+       dev_dbg(&h->pdev->dev, "   Transport methods supported = 0x%x\n",
               readl(&(tb->TransportSupport)));
               readl(&(tb->TransportSupport)));
-       printk("   Transport methods active = 0x%x\n",
+       dev_dbg(&h->pdev->dev, "   Transport methods active = 0x%x\n",
               readl(&(tb->TransportActive)));
               readl(&(tb->TransportActive)));
-       printk("   Requested transport Method = 0x%x\n",
+       dev_dbg(&h->pdev->dev, "   Requested transport Method = 0x%x\n",
               readl(&(tb->HostWrite.TransportRequest)));
               readl(&(tb->HostWrite.TransportRequest)));
-       printk("   Coalesce Interrupt Delay = 0x%x\n",
+       dev_dbg(&h->pdev->dev, "   Coalesce Interrupt Delay = 0x%x\n",
               readl(&(tb->HostWrite.CoalIntDelay)));
               readl(&(tb->HostWrite.CoalIntDelay)));
-       printk("   Coalesce Interrupt Count = 0x%x\n",
+       dev_dbg(&h->pdev->dev, "   Coalesce Interrupt Count = 0x%x\n",
               readl(&(tb->HostWrite.CoalIntCount)));
               readl(&(tb->HostWrite.CoalIntCount)));
-       printk("   Max outstanding commands = 0x%d\n",
+       dev_dbg(&h->pdev->dev, "   Max outstanding commands = 0x%d\n",
               readl(&(tb->CmdsOutMax)));
               readl(&(tb->CmdsOutMax)));
-       printk("   Bus Types = 0x%x\n", readl(&(tb->BusTypes)));
+       dev_dbg(&h->pdev->dev, "   Bus Types = 0x%x\n",
+               readl(&(tb->BusTypes)));
        for (i = 0; i < 16; i++)
                temp_name[i] = readb(&(tb->ServerName[i]));
        temp_name[16] = '\0';
        for (i = 0; i < 16; i++)
                temp_name[i] = readb(&(tb->ServerName[i]));
        temp_name[16] = '\0';
-       printk("   Server Name = %s\n", temp_name);
-       printk("   Heartbeat Counter = 0x%x\n\n\n", readl(&(tb->HeartBeat)));
+       dev_dbg(&h->pdev->dev, "   Server Name = %s\n", temp_name);
+       dev_dbg(&h->pdev->dev, "   Heartbeat Counter = 0x%x\n\n\n",
+               readl(&(tb->HeartBeat)));
 }
 }
-#endif                         /* CCISS_DEBUG */
 
 static int find_PCI_BAR_index(struct pci_dev *pdev, unsigned long pci_bar_addr)
 {
 
 static int find_PCI_BAR_index(struct pci_dev *pdev, unsigned long pci_bar_addr)
 {
@@ -3618,7 +3740,7 @@ static int find_PCI_BAR_index(struct pci_dev *pdev, unsigned long pci_bar_addr)
                                offset += 8;
                                break;
                        default:        /* reserved in PCI 2.2 */
                                offset += 8;
                                break;
                        default:        /* reserved in PCI 2.2 */
-                               printk(KERN_WARNING
+                               dev_warn(&pdev->dev,
                                       "Base address is invalid\n");
                                return -1;
                                break;
                                       "Base address is invalid\n");
                                return -1;
                                break;
@@ -3630,12 +3752,182 @@ static int find_PCI_BAR_index(struct pci_dev *pdev, unsigned long pci_bar_addr)
        return -1;
 }
 
        return -1;
 }
 
+/* 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 __devinit cciss_wait_for_mode_change_ack(ctlr_info_t *h)
+{
+       int i;
+
+       /* 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))
+                       break;
+               msleep(10);
+       }
+}
+
+static __devinit void cciss_enter_performant_mode(ctlr_info_t *h)
+{
+       /* 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.
+        */
+       __u32 trans_offset;
+       int bft[8] = { 5, 6, 8, 10, 12, 20, 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
+                        */
+       unsigned long register_value;
+       BUILD_BUG_ON(28 > MAXSGENTRIES + 4);
+
+       h->reply_pool_wraparound = 1; /* spec: init to 1 */
+
+       /* Controller spec: zero out this buffer. */
+       memset(h->reply_pool, 0, h->max_commands * sizeof(__u64));
+       h->reply_pool_head = h->reply_pool;
+
+       trans_offset = readl(&(h->cfgtable->TransMethodOffset));
+       calc_bucket_map(bft, ARRAY_SIZE(bft), h->maxsgentries,
+                               h->blockFetchTable);
+       writel(bft[0], &h->transtable->BlockFetch0);
+       writel(bft[1], &h->transtable->BlockFetch1);
+       writel(bft[2], &h->transtable->BlockFetch2);
+       writel(bft[3], &h->transtable->BlockFetch3);
+       writel(bft[4], &h->transtable->BlockFetch4);
+       writel(bft[5], &h->transtable->BlockFetch5);
+       writel(bft[6], &h->transtable->BlockFetch6);
+       writel(bft[7], &h->transtable->BlockFetch7);
+
+       /* 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);
+       cciss_wait_for_mode_change_ack(h);
+       register_value = readl(&(h->cfgtable->TransportActive));
+       if (!(register_value & CFGTBL_Trans_Performant))
+               dev_warn(&h->pdev->dev, "cciss: unable to get board into"
+                                       " performant mode\n");
+}
+
+static void __devinit cciss_put_controller_into_performant_mode(ctlr_info_t *h)
+{
+       __u32 trans_support;
+
+       dev_dbg(&h->pdev->dev, "Trying to put board into Performant mode\n");
+       /* Attempt to put controller into performant mode if supported */
+       /* Does board support performant mode? */
+       trans_support = readl(&(h->cfgtable->TransportSupport));
+       if (!(trans_support & PERFORMANT_MODE))
+               return;
+
+       dev_dbg(&h->pdev->dev, "Placing controller into performant mode\n");
+       /* Performant mode demands commands on a 32 byte boundary
+        * pci_alloc_consistent aligns on page boundarys already.
+        * Just need to check if divisible by 32
+        */
+       if ((sizeof(CommandList_struct) % 32) != 0) {
+               dev_warn(&h->pdev->dev, "%s %d %s\n",
+                       "cciss info: command size[",
+                       (int)sizeof(CommandList_struct),
+                       "] not divisible by 32, no performant mode..\n");
+               return;
+       }
+
+       /* Performant mode ring buffer and supporting data structures */
+       h->reply_pool = (__u64 *)pci_alloc_consistent(
+               h->pdev, h->max_commands * sizeof(__u64),
+               &(h->reply_pool_dhandle));
+
+       /* Need a block fetch table for performant mode */
+       h->blockFetchTable = kmalloc(((h->maxsgentries+1) *
+               sizeof(__u32)), GFP_KERNEL);
+
+       if ((h->reply_pool == NULL) || (h->blockFetchTable == NULL))
+               goto clean_up;
+
+       cciss_enter_performant_mode(h);
+
+       /* Change the access methods to the performant access methods */
+       h->access = SA5_performant_access;
+       h->transMethod = CFGTBL_Trans_Performant;
+
+       return;
+clean_up:
+       kfree(h->blockFetchTable);
+       if (h->reply_pool)
+               pci_free_consistent(h->pdev,
+                               h->max_commands * sizeof(__u64),
+                               h->reply_pool,
+                               h->reply_pool_dhandle);
+       return;
+
+} /* cciss_put_controller_into_performant_mode */
+
 /* If MSI/MSI-X is supported by the kernel we will try to enable it on
  * controllers that are capable. If not, we use IO-APIC mode.
  */
 
 /* If MSI/MSI-X is supported by the kernel we will try to enable it on
  * controllers that are capable. If not, we use IO-APIC mode.
  */
 
-static void __devinit cciss_interrupt_mode(ctlr_info_t *c,
-                                          struct pci_dev *pdev, __u32 board_id)
+static void __devinit cciss_interrupt_mode(ctlr_info_t *h)
 {
 #ifdef CONFIG_PCI_MSI
        int err;
 {
 #ifdef CONFIG_PCI_MSI
        int err;
@@ -3644,268 +3936,283 @@ static void __devinit cciss_interrupt_mode(ctlr_info_t *c,
        };
 
        /* Some boards advertise MSI but don't really support it */
        };
 
        /* 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;
 
                goto default_int_mode;
 
-       if (pci_find_capability(pdev, PCI_CAP_ID_MSIX)) {
-               err = pci_enable_msix(pdev, cciss_msix_entries, 4);
+       if (pci_find_capability(h->pdev, PCI_CAP_ID_MSIX)) {
+               err = pci_enable_msix(h->pdev, cciss_msix_entries, 4);
                if (!err) {
                if (!err) {
-                       c->intr[0] = cciss_msix_entries[0].vector;
-                       c->intr[1] = cciss_msix_entries[1].vector;
-                       c->intr[2] = cciss_msix_entries[2].vector;
-                       c->intr[3] = cciss_msix_entries[3].vector;
-                       c->msix_vector = 1;
+                       h->intr[0] = cciss_msix_entries[0].vector;
+                       h->intr[1] = cciss_msix_entries[1].vector;
+                       h->intr[2] = cciss_msix_entries[2].vector;
+                       h->intr[3] = cciss_msix_entries[3].vector;
+                       h->msix_vector = 1;
                        return;
                }
                if (err > 0) {
                        return;
                }
                if (err > 0) {
-                       printk(KERN_WARNING "cciss: only %d MSI-X vectors "
-                              "available\n", err);
+                       dev_warn(&h->pdev->dev,
+                               "only %d MSI-X vectors available\n", err);
                        goto default_int_mode;
                } else {
                        goto default_int_mode;
                } else {
-                       printk(KERN_WARNING "cciss: MSI-X init failed %d\n",
-                              err);
+                       dev_warn(&h->pdev->dev,
+                               "MSI-X init failed %d\n", err);
                        goto default_int_mode;
                }
        }
                        goto default_int_mode;
                }
        }
-       if (pci_find_capability(pdev, PCI_CAP_ID_MSI)) {
-               if (!pci_enable_msi(pdev)) {
-                       c->msi_vector = 1;
-               } else {
-                       printk(KERN_WARNING "cciss: MSI init failed\n");
-               }
+       if (pci_find_capability(h->pdev, PCI_CAP_ID_MSI)) {
+               if (!pci_enable_msi(h->pdev))
+                       h->msi_vector = 1;
+               else
+                       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 */
        }
 default_int_mode:
 #endif                         /* CONFIG_PCI_MSI */
        /* if we get here we're going to use the default interrupt mode */
-       c->intr[SIMPLE_MODE_INT] = pdev->irq;
+       h->intr[PERF_MODE_INT] = h->pdev->irq;
        return;
 }
 
        return;
 }
 
-static int __devinit cciss_pci_init(ctlr_info_t *c, struct pci_dev *pdev)
+static int __devinit cciss_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;
-       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;
 
        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++) {
                /* Stand aside for hpsa driver on request */
                if (cciss_allow_hpsa && products[i].board_id == HPSA_BOUNDARY)
                        return -ENODEV;
 
        for (i = 0; i < ARRAY_SIZE(products); i++) {
                /* Stand aside for hpsa driver on request */
                if (cciss_allow_hpsa && products[i].board_id == HPSA_BOUNDARY)
                        return -ENODEV;
-               if (board_id == products[i].board_id)
-                       break;
-       }
-       prod_index = i;
-       if (prod_index == ARRAY_SIZE(products)) {
-               dev_warn(&pdev->dev,
-                       "unrecognized board ID: 0x%08lx, ignoring.\n",
-                       (unsigned long) board_id);
-               return -ENODEV;
+               if (*board_id == products[i].board_id)
+                       return i;
        }
        }
+       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)) {
-               printk(KERN_WARNING
-                      "cciss: controller appears to be disabled\n");
-               return -ENODEV;
-       }
+static inline bool cciss_board_disabled(ctlr_info_t *h)
+{
+       u16 command;
 
 
-       err = pci_enable_device(pdev);
-       if (err) {
-               printk(KERN_ERR "cciss: Unable to Enable PCI device\n");
-               return err;
-       }
+       (void) pci_read_config_word(h->pdev, PCI_COMMAND, &command);
+       return ((command & PCI_COMMAND_MEMORY) == 0);
+}
 
 
-       err = pci_request_regions(pdev, "cciss");
-       if (err) {
-               printk(KERN_ERR "cciss: Cannot obtain PCI resources, "
-                      "aborting\n");
-               return err;
-       }
+static int __devinit cciss_pci_find_memory_BAR(struct pci_dev *pdev,
+       unsigned long *memory_bar)
+{
+       int i;
 
 
-#ifdef CCISS_DEBUG
-       printk("command = %x\n", command);
-       printk("irq = %x\n", pdev->irq);
-       printk("board_id = %x\n", board_id);
-#endif                         /* CCISS_DEBUG */
+       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;
+}
 
 
-/* If the kernel supports MSI/MSI-X we will try to enable that functionality,
- * else we use the IO-APIC interrupt assigned to us by system ROM.
- */
-       cciss_interrupt_mode(c, pdev, board_id);
+static int __devinit cciss_wait_for_board_ready(ctlr_info_t *h)
+{
+       int i;
+       u32 scratchpad;
 
 
-       /* 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) {
-               printk(KERN_WARNING "cciss: No memory BAR found\n");
-               err = -ENODEV;
-               goto err_out_free_res;
+       for (i = 0; i < CCISS_BOARD_READY_ITERATIONS; i++) {
+               scratchpad = readl(h->vaddr + SA5_SCRATCHPAD_OFFSET);
+               if (scratchpad == CCISS_FIRMWARE_READY)
+                       return 0;
+               msleep(CCISS_BOARD_READY_POLL_INTERVAL_MSECS);
        }
        }
+       dev_warn(&h->pdev->dev, "board not ready, timed out.\n");
+       return -ENODEV;
+}
 
 
-       c->paddr = pci_resource_start(pdev, i); /* addressing mode bits
-                                                * already removed
-                                                */
+static int __devinit cciss_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, "
+                       "*cfg_base_addr = 0x%08x\n", *cfg_base_addr);
+               return -ENODEV;
+       }
+       return 0;
+}
 
 
-#ifdef CCISS_DEBUG
-       printk("address 0 = %lx\n", c->paddr);
-#endif                         /* CCISS_DEBUG */
-       c->vaddr = remap_pci_mem(c->paddr, 0x250);
+static int __devinit cciss_find_cfgtables(ctlr_info_t *h)
+{
+       u64 cfg_offset;
+       u32 cfg_base_addr;
+       u64 cfg_base_addr_index;
+       u32 trans_offset;
+       int rc;
 
 
-       /* Wait for the board to become ready.  (PCI hotplug needs this.)
-        * We poll for up to 120 secs, once per 100ms. */
-       for (i = 0; i < 1200; i++) {
-               scratchpad = readl(c->vaddr + SA5_SCRATCHPAD_OFFSET);
-               if (scratchpad == CCISS_FIRMWARE_READY)
-                       break;
-               set_current_state(TASK_INTERRUPTIBLE);
-               schedule_timeout(msecs_to_jiffies(100));        /* wait 100ms */
-       }
-       if (scratchpad != CCISS_FIRMWARE_READY) {
-               printk(KERN_WARNING "cciss: Board not ready.  Timed out.\n");
-               err = -ENODEV;
-               goto err_out_free_res;
-       }
+       rc = cciss_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(h->pdev,
+                               cfg_base_addr_index)+cfg_offset+trans_offset,
+                               sizeof(*h->transtable));
+       if (!h->transtable)
+               return -ENOMEM;
+       return 0;
+}
 
 
-       /* get the address index number */
-       cfg_base_addr = readl(c->vaddr + SA5_CTCFG_OFFSET);
-       cfg_base_addr &= (__u32) 0x0000ffff;
-#ifdef CCISS_DEBUG
-       printk("cfg base address = %x\n", cfg_base_addr);
-#endif                         /* CCISS_DEBUG */
-       cfg_base_addr_index = find_PCI_BAR_index(pdev, cfg_base_addr);
-#ifdef CCISS_DEBUG
-       printk("cfg base address index = %llx\n",
-               (unsigned long long)cfg_base_addr_index);
-#endif                         /* CCISS_DEBUG */
-       if (cfg_base_addr_index == -1) {
-               printk(KERN_WARNING "cciss: Cannot find cfg_base_addr_index\n");
-               err = -ENODEV;
-               goto err_out_free_res;
+static void __devinit cciss_get_max_perf_mode_cmds(struct ctlr_info *h)
+{
+       h->max_commands = readl(&(h->cfgtable->MaxPerformantModeCommands));
+       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;
        }
        }
+}
 
 
-       cfg_offset = readl(c->vaddr + SA5_CTMEM_OFFSET);
-#ifdef CCISS_DEBUG
-       printk("cfg offset = %llx\n", (unsigned long long)cfg_offset);
-#endif                         /* CCISS_DEBUG */
-       c->cfgtable = remap_pci_mem(pci_resource_start(pdev,
-                                                      cfg_base_addr_index) +
-                                   cfg_offset, sizeof(CfgTable_struct));
-       c->board_id = board_id;
-
-#ifdef CCISS_DEBUG
-       print_cfg_table(c->cfgtable);
-#endif                         /* CCISS_DEBUG */
-
-       /* Some controllers support Zero Memory Raid (ZMR).
-        * When configured in ZMR mode the number of supported
-        * commands drops to 64. So instead of just setting an
-        * arbitrary value we make the driver a little smarter.
-        * We read the config table to tell us how many commands
-        * are supported on the controller then subtract 4 to
-        * leave a little room for ioctl calls.
-        */
-       c->max_commands = readl(&(c->cfgtable->CmdsOutMax));
-       c->maxsgentries = readl(&(c->cfgtable->MaxSGElements));
-
+/* Interrogate the hardware for some limits:
+ * max commands, max SG elements without chaining, and with chaining,
+ * SG chain block size, etc.
+ */
+static void __devinit cciss_find_board_params(ctlr_info_t *h)
+{
+       cciss_get_max_perf_mode_cmds(h);
+       h->nr_cmds = h->max_commands - 4; /* Allow room for some ioctls */
+       h->maxsgentries = readl(&(h->cfgtable->MaxSGElements));
        /*
        /*
-        * Limit native command to 32 s/g elements to save dma'able memory.
+        * Limit in-command s/g elements to 32 save dma'able memory.
         * Howvever spec says if 0, use 31
         */
         * Howvever spec says if 0, use 31
         */
-
-       c->max_cmd_sgentries = 31;
-       if (c->maxsgentries > 512) {
-               c->max_cmd_sgentries = 32;
-               c->chainsize = c->maxsgentries - c->max_cmd_sgentries + 1;
-               c->maxsgentries -= 1;   /* account for chain pointer */
+       h->max_cmd_sgentries = 31;
+       if (h->maxsgentries > 512) {
+               h->max_cmd_sgentries = 32;
+               h->chainsize = h->maxsgentries - h->max_cmd_sgentries + 1;
+               h->maxsgentries--; /* save one for chain pointer */
        } else {
        } else {
-               c->maxsgentries = 31;   /* Default to traditional value */
-               c->chainsize = 0;       /* traditional */
+               h->maxsgentries = 31; /* default to traditional values */
+               h->chainsize = 0;
        }
        }
+}
 
 
-       c->product_name = products[prod_index].product_name;
-       c->access = *(products[prod_index].access);
-       c->nr_cmds = c->max_commands - 4;
-       if ((readb(&c->cfgtable->Signature[0]) != 'C') ||
-           (readb(&c->cfgtable->Signature[1]) != 'I') ||
-           (readb(&c->cfgtable->Signature[2]) != 'S') ||
-           (readb(&c->cfgtable->Signature[3]) != 'S')) {
-               printk("Does not appear to be a valid CISS config table\n");
-               err = -ENODEV;
-               goto err_out_free_res;
+static inline bool CISS_signature_present(ctlr_info_t *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(&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 cciss_enable_scsi_prefetch(ctlr_info_t *h)
+{
 #ifdef CONFIG_X86
 #ifdef CONFIG_X86
-       {
-               /* Need to enable prefetch in the SCSI core for 6400 in x86 */
-               __u32 prefetch;
-               prefetch = readl(&(c->cfgtable->SCSI_Prefetch));
-               prefetch |= 0x100;
-               writel(prefetch, &(c->cfgtable->SCSI_Prefetch));
-       }
+       u32 prefetch;
+
+       prefetch = readl(&(h->cfgtable->SCSI_Prefetch));
+       prefetch |= 0x100;
+       writel(prefetch, &(h->cfgtable->SCSI_Prefetch));
 #endif
 #endif
+}
 
 
-       /* Disabling DMA prefetch and refetch for the P600.
-        * An ASIC bug may result in accesses to invalid memory addresses.
-        * We've disabled prefetch for some time now. Testing with XEN
-        * kernels revealed a bug in the refetch if dom0 resides on a P600.
-        */
-       if(board_id == 0x3225103C) {
-               __u32 dma_prefetch;
-               __u32 dma_refetch;
-               dma_prefetch = readl(c->vaddr + I2O_DMA1_CFG);
-               dma_prefetch |= 0x8000;
-               writel(dma_prefetch, c->vaddr + I2O_DMA1_CFG);
-               pci_read_config_dword(pdev, PCI_COMMAND_PARITY, &dma_refetch);
-               dma_refetch |= 0x1;
-               pci_write_config_dword(pdev, PCI_COMMAND_PARITY, dma_refetch);
+/* Disable DMA prefetch for the P600.  Otherwise an ASIC bug may result
+ * in a prefetch beyond physical memory.
+ */
+static inline void cciss_p600_dma_prefetch_quirk(ctlr_info_t *h)
+{
+       u32 dma_prefetch;
+       __u32 dma_refetch;
+
+       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);
+       pci_read_config_dword(h->pdev, PCI_COMMAND_PARITY, &dma_refetch);
+       dma_refetch |= 0x1;
+       pci_write_config_dword(h->pdev, PCI_COMMAND_PARITY, dma_refetch);
+}
+
+static int __devinit cciss_pci_init(ctlr_info_t *h)
+{
+       int prod_index, err;
+
+       prod_index = cciss_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 (cciss_board_disabled(h)) {
+               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;
        }
 
        }
 
-#ifdef CCISS_DEBUG
-       printk("Trying to put board into Simple mode\n");
-#endif                         /* CCISS_DEBUG */
-       c->max_commands = readl(&(c->cfgtable->CmdsOutMax));
-       /* Update the field, and then ring the doorbell */
-       writel(CFGTBL_Trans_Simple, &(c->cfgtable->HostWrite.TransportRequest));
-       writel(CFGTBL_ChangeReq, c->vaddr + SA5_DOORBELL);
+       err = pci_request_regions(h->pdev, "cciss");
+       if (err) {
+               dev_warn(&h->pdev->dev,
+                       "Cannot obtain PCI resources, aborting\n");
+               return err;
+       }
 
 
-       /* 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(c->vaddr + SA5_DOORBELL) & CFGTBL_ChangeReq))
-                       break;
-               /* delay and try again */
-               set_current_state(TASK_INTERRUPTIBLE);
-               schedule_timeout(msecs_to_jiffies(1));
+       dev_dbg(&h->pdev->dev, "irq = %x\n", h->pdev->irq);
+       dev_dbg(&h->pdev->dev, "board_id = %x\n", h->board_id);
+
+/* If the kernel supports MSI/MSI-X we will try to enable that functionality,
+ * else we use the IO-APIC interrupt assigned to us by system ROM.
+ */
+       cciss_interrupt_mode(h);
+       err = cciss_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 = cciss_wait_for_board_ready(h);
+       if (err)
+               goto err_out_free_res;
+       err = cciss_find_cfgtables(h);
+       if (err)
+               goto err_out_free_res;
+       print_cfg_table(h);
+       cciss_find_board_params(h);
 
 
-#ifdef CCISS_DEBUG
-       printk(KERN_DEBUG "I counter got to %d %x\n", i,
-              readl(c->vaddr + SA5_DOORBELL));
-#endif                         /* CCISS_DEBUG */
-#ifdef CCISS_DEBUG
-       print_cfg_table(c->cfgtable);
-#endif                         /* CCISS_DEBUG */
-
-       if (!(readl(&(c->cfgtable->TransportActive)) & CFGTBL_Trans_Simple)) {
-               printk(KERN_WARNING "cciss: unable to get board into"
-                      " simple mode\n");
+       if (!CISS_signature_present(h)) {
                err = -ENODEV;
                goto err_out_free_res;
        }
                err = -ENODEV;
                goto err_out_free_res;
        }
+       cciss_enable_scsi_prefetch(h);
+       cciss_p600_dma_prefetch_quirk(h);
+       cciss_put_controller_into_performant_mode(h);
        return 0;
 
 err_out_free_res:
        return 0;
 
 err_out_free_res:
@@ -3913,42 +4220,47 @@ err_out_free_res:
         * Deliberately omit pci_disable_device(): it does something nasty to
         * Smart Array controllers that pci_enable_device does not undo
         */
         * Deliberately omit pci_disable_device(): it does something nasty to
         * Smart Array controllers that pci_enable_device does not undo
         */
-       pci_release_regions(pdev);
+       if (h->transtable)
+               iounmap(h->transtable);
+       if (h->cfgtable)
+               iounmap(h->cfgtable);
+       if (h->vaddr)
+               iounmap(h->vaddr);
+       pci_release_regions(h->pdev);
        return err;
 }
 
 /* Function to find the first free pointer into our hba[] array
  * Returns -1 if no free entries are left.
  */
        return err;
 }
 
 /* Function to find the first free pointer into our hba[] array
  * Returns -1 if no free entries are left.
  */
-static int alloc_cciss_hba(void)
+static int alloc_cciss_hba(struct pci_dev *pdev)
 {
        int i;
 
        for (i = 0; i < MAX_CTLR; i++) {
                if (!hba[i]) {
 {
        int i;
 
        for (i = 0; i < MAX_CTLR; i++) {
                if (!hba[i]) {
-                       ctlr_info_t *p;
+                       ctlr_info_t *h;
 
 
-                       p = kzalloc(sizeof(ctlr_info_t), GFP_KERNEL);
-                       if (!p)
+                       h = kzalloc(sizeof(ctlr_info_t), GFP_KERNEL);
+                       if (!h)
                                goto Enomem;
                                goto Enomem;
-                       hba[i] = p;
+                       hba[i] = h;
                        return i;
                }
        }
                        return i;
                }
        }
-       printk(KERN_WARNING "cciss: This driver supports a maximum"
+       dev_warn(&pdev->dev, "This driver supports a maximum"
               " of %d controllers.\n", MAX_CTLR);
        return -1;
 Enomem:
               " of %d controllers.\n", MAX_CTLR);
        return -1;
 Enomem:
-       printk(KERN_ERR "cciss: out of memory.\n");
+       dev_warn(&pdev->dev, "out of memory.\n");
        return -1;
 }
 
        return -1;
 }
 
-static void free_hba(int n)
+static void free_hba(ctlr_info_t *h)
 {
 {
-       ctlr_info_t *h = hba[n];
        int i;
 
        int i;
 
-       hba[n] = NULL;
+       hba[h->ctlr] = NULL;
        for (i = 0; i < h->highest_lun + 1; i++)
                if (h->gendisk[i] != NULL)
                        put_disk(h->gendisk[i]);
        for (i = 0; i < h->highest_lun + 1; i++)
                if (h->gendisk[i] != NULL)
                        put_disk(h->gendisk[i]);
@@ -4028,7 +4340,8 @@ static __devinit int cciss_message(struct pci_dev *pdev, unsigned char opcode, u
        /* we leak the DMA buffer here ... no choice since the controller could
           still complete the command. */
        if (i == 10) {
        /* we leak the DMA buffer here ... no choice since the controller could
           still complete the command. */
        if (i == 10) {
-               printk(KERN_ERR "cciss: controller message %02x:%02x timed out\n",
+               dev_err(&pdev->dev,
+                       "controller message %02x:%02x timed out\n",
                        opcode, type);
                return -ETIMEDOUT;
        }
                        opcode, type);
                return -ETIMEDOUT;
        }
@@ -4036,12 +4349,12 @@ static __devinit int cciss_message(struct pci_dev *pdev, unsigned char opcode, u
        pci_free_consistent(pdev, cmd_sz, cmd, paddr64);
 
        if (tag & 2) {
        pci_free_consistent(pdev, cmd_sz, cmd, paddr64);
 
        if (tag & 2) {
-               printk(KERN_ERR "cciss: controller message %02x:%02x failed\n",
+               dev_err(&pdev->dev, "controller message %02x:%02x failed\n",
                        opcode, type);
                return -EIO;
        }
 
                        opcode, type);
                return -EIO;
        }
 
-       printk(KERN_INFO "cciss: controller message %02x:%02x succeeded\n",
+       dev_info(&pdev->dev, "controller message %02x:%02x succeeded\n",
                opcode, type);
        return 0;
 }
                opcode, type);
        return 0;
 }
@@ -4062,7 +4375,7 @@ static __devinit int cciss_reset_msi(struct pci_dev *pdev)
        if (pos) {
                pci_read_config_word(pdev, msi_control_reg(pos), &control);
                if (control & PCI_MSI_FLAGS_ENABLE) {
        if (pos) {
                pci_read_config_word(pdev, msi_control_reg(pos), &control);
                if (control & PCI_MSI_FLAGS_ENABLE) {
-                       printk(KERN_INFO "cciss: resetting MSI\n");
+                       dev_info(&pdev->dev, "resetting MSI\n");
                        pci_write_config_word(pdev, msi_control_reg(pos), control & ~PCI_MSI_FLAGS_ENABLE);
                }
        }
                        pci_write_config_word(pdev, msi_control_reg(pos), control & ~PCI_MSI_FLAGS_ENABLE);
                }
        }
@@ -4071,7 +4384,7 @@ static __devinit int cciss_reset_msi(struct pci_dev *pdev)
        if (pos) {
                pci_read_config_word(pdev, msi_control_reg(pos), &control);
                if (control & PCI_MSIX_FLAGS_ENABLE) {
        if (pos) {
                pci_read_config_word(pdev, msi_control_reg(pos), &control);
                if (control & PCI_MSIX_FLAGS_ENABLE) {
-                       printk(KERN_INFO "cciss: resetting MSI-X\n");
+                       dev_info(&pdev->dev, "resetting MSI-X\n");
                        pci_write_config_word(pdev, msi_control_reg(pos), control & ~PCI_MSIX_FLAGS_ENABLE);
                }
        }
                        pci_write_config_word(pdev, msi_control_reg(pos), control & ~PCI_MSIX_FLAGS_ENABLE);
                }
        }
@@ -4079,68 +4392,144 @@ static __devinit int cciss_reset_msi(struct pci_dev *pdev)
        return 0;
 }
 
        return 0;
 }
 
-/* This does a hard reset of the controller using PCI power management
- * states. */
-static __devinit int cciss_hard_reset_controller(struct pci_dev *pdev)
+static int cciss_controller_hard_reset(struct pci_dev *pdev,
+       void * __iomem vaddr, bool use_doorbell)
 {
 {
-       u16 pmcsr, saved_config_space[32];
-       int i, pos;
+       u16 pmcsr;
+       int pos;
 
 
-       printk(KERN_INFO "cciss: using PCI PM to reset controller\n");
+       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,
+                               "cciss_controller_hard_reset: "
+                               "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);
 
 
-       /* This is very nearly the same thing as
+               msleep(500);
 
 
-          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);
+               /* 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);
 
 
-          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 .... */
+               msleep(500);
+       }
+       return 0;
+}
 
 
-       for (i = 0; i < 32; i++)
-               pci_read_config_word(pdev, 2*i, &saved_config_space[i]);
+/* This does a hard reset of the controller using PCI power management
+ * states or using the doorbell register. */
+static __devinit int cciss_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;
+       CfgTable_struct __iomem *cfgtable;
+       bool use_doorbell;
+       u32 board_id;
+
+       /* For controllers as old a 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.
+        */
 
 
-       pos = pci_find_capability(pdev, PCI_CAP_ID_PM);
-       if (pos == 0) {
-               printk(KERN_ERR "cciss_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.
+        */
+       cciss_lookup_board_id(pdev, &board_id);
+       if (board_id == 0x409C0E11 || board_id == 0x409D0E11) {
+               dev_warn(&pdev->dev, "Cannot reset Smart Array 640x "
+                               "due to shared cache module.");
                return -ENODEV;
        }
 
                return -ENODEV;
        }
 
-       /* 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." */
+       for (i = 0; i < 32; i++)
+               pci_read_config_word(pdev, 2*i, &saved_config_space[i]);
 
 
-       /* 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 the first memory BAR, so we can find the cfg table */
+       rc = cciss_pci_find_memory_BAR(pdev, &paddr);
+       if (rc)
+               return rc;
+       vaddr = remap_pci_mem(paddr, 0x250);
+       if (!vaddr)
+               return -ENOMEM;
 
 
-       schedule_timeout_uninterruptible(HZ >> 1);
+       /* find cfgtable in order to check if reset via doorbell is supported */
+       rc = cciss_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;
+       }
 
 
-       /* 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);
+       /* 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;
 
 
-       schedule_timeout_uninterruptible(HZ >> 1);
+       rc = cciss_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,
 
        /* 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. */
+        * 16-bits at offset 06h."  Note that the offset is 2*i.
+        */
        for (i = 0; i < 32; i++) {
                if (i == 2 || i == 3)
                        continue;
        for (i = 0; i < 32; i++) {
                if (i == 2 || i == 3)
                        continue;
@@ -4149,6 +4538,63 @@ static __devinit int cciss_hard_reset_controller(struct pci_dev *pdev)
        wmb();
        pci_write_config_word(pdev, 4, saved_config_space[2]);
 
        wmb();
        pci_write_config_word(pdev, 4, saved_config_space[2]);
 
+       /* Some devices (notably the HP Smart Array 5i Controller)
+          need a little pause here */
+       msleep(CCISS_POST_RESET_PAUSE_MSECS);
+
+       /* 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.
+        */
+       active_transport = readl(&cfgtable->TransportActive);
+       if (active_transport & PERFORMANT_MODE) {
+               dev_warn(&pdev->dev, "Unable to successfully reset controller,"
+                       " Ignoring controller.\n");
+               rc = -ENODEV;
+       }
+
+unmap_cfgtable:
+       iounmap(cfgtable);
+
+unmap_vaddr:
+       iounmap(vaddr);
+       return rc;
+}
+
+static __devinit int cciss_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 = cciss_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;
+       if (cciss_reset_msi(pdev))
+               return -ENODEV;
+
+       /* Now try to get the controller to respond to a no-op */
+       for (i = 0; i < CCISS_POST_RESET_NOOP_RETRIES; i++) {
+               if (cciss_noop(pdev) == 0)
+                       break;
+               else
+                       dev_warn(&pdev->dev, "no-op failed%s\n",
+                               (i < CCISS_POST_RESET_NOOP_RETRIES - 1 ?
+                                       "; re-trying" : ""));
+               msleep(CCISS_POST_RESET_NOOP_INTERVAL_MSECS);
+       }
        return 0;
 }
 
        return 0;
 }
 
@@ -4166,46 +4612,31 @@ static int __devinit cciss_init_one(struct pci_dev *pdev,
        int rc;
        int dac, return_code;
        InquiryData_struct *inq_buff;
        int rc;
        int dac, return_code;
        InquiryData_struct *inq_buff;
+       ctlr_info_t *h;
 
 
-       if (reset_devices) {
-               /* Reset the controller with a PCI power-cycle */
-               if (cciss_hard_reset_controller(pdev) || cciss_reset_msi(pdev))
-                       return -ENODEV;
-
-               /* Now try to get the controller to respond to a no-op. Some
-                  devices (notably the HP Smart Array 5i Controller) need
-                  up to 30 seconds to respond. */
-               for (i=0; i<30; i++) {
-                       if (cciss_noop(pdev) == 0)
-                               break;
-
-                       schedule_timeout_uninterruptible(HZ);
-               }
-               if (i == 30) {
-                       printk(KERN_ERR "cciss: controller seems dead\n");
-                       return -EBUSY;
-               }
-       }
-
-       i = alloc_cciss_hba();
+       rc = cciss_init_reset_devices(pdev);
+       if (rc)
+               return rc;
+       i = alloc_cciss_hba(pdev);
        if (i < 0)
                return -1;
 
        if (i < 0)
                return -1;
 
-       hba[i]->busy_initializing = 1;
-       INIT_HLIST_HEAD(&hba[i]->cmpQ);
-       INIT_HLIST_HEAD(&hba[i]->reqQ);
-       mutex_init(&hba[i]->busy_shutting_down);
+       h = hba[i];
+       h->pdev = pdev;
+       h->busy_initializing = 1;
+       INIT_HLIST_HEAD(&h->cmpQ);
+       INIT_HLIST_HEAD(&h->reqQ);
+       mutex_init(&h->busy_shutting_down);
 
 
-       if (cciss_pci_init(hba[i], pdev) != 0)
+       if (cciss_pci_init(h) != 0)
                goto clean_no_release_regions;
 
                goto clean_no_release_regions;
 
-       sprintf(hba[i]->devname, "cciss%d", i);
-       hba[i]->ctlr = i;
-       hba[i]->pdev = pdev;
+       sprintf(h->devname, "cciss%d", i);
+       h->ctlr = i;
 
 
-       init_completion(&hba[i]->scan_wait);
+       init_completion(&h->scan_wait);
 
 
-       if (cciss_create_hba_sysfs_entry(hba[i]))
+       if (cciss_create_hba_sysfs_entry(h))
                goto clean0;
 
        /* configure PCI DMA stuff */
                goto clean0;
 
        /* configure PCI DMA stuff */
@@ -4214,7 +4645,7 @@ static int __devinit cciss_init_one(struct pci_dev *pdev,
        else if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32)))
                dac = 0;
        else {
        else if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32)))
                dac = 0;
        else {
-               printk(KERN_ERR "cciss: no suitable DMA available\n");
+               dev_err(&h->pdev->dev, "no suitable DMA available\n");
                goto clean1;
        }
 
                goto clean1;
        }
 
@@ -4224,151 +4655,161 @@ static int __devinit cciss_init_one(struct pci_dev *pdev,
         * 8 controller support.
         */
        if (i < MAX_CTLR_ORIG)
         * 8 controller support.
         */
        if (i < MAX_CTLR_ORIG)
-               hba[i]->major = COMPAQ_CISS_MAJOR + i;
-       rc = register_blkdev(hba[i]->major, hba[i]->devname);
+               h->major = COMPAQ_CISS_MAJOR + i;
+       rc = register_blkdev(h->major, h->devname);
        if (rc == -EBUSY || rc == -EINVAL) {
        if (rc == -EBUSY || rc == -EINVAL) {
-               printk(KERN_ERR
-                      "cciss:  Unable to get major number %d for %s "
-                      "on hba %d\n", hba[i]->major, hba[i]->devname, i);
+               dev_err(&h->pdev->dev,
+                      "Unable to get major number %d for %s "
+                      "on hba %d\n", h->major, h->devname, i);
                goto clean1;
        } else {
                if (i >= MAX_CTLR_ORIG)
                goto clean1;
        } else {
                if (i >= MAX_CTLR_ORIG)
-                       hba[i]->major = rc;
+                       h->major = rc;
        }
 
        /* make sure the board interrupts are off */
        }
 
        /* make sure the board interrupts are off */
-       hba[i]->access.set_intr_mask(hba[i], CCISS_INTR_OFF);
-       if (request_irq(hba[i]->intr[SIMPLE_MODE_INT], do_cciss_intr,
-                       IRQF_DISABLED | IRQF_SHARED, hba[i]->devname, hba[i])) {
-               printk(KERN_ERR "cciss: Unable to get irq %d for %s\n",
-                      hba[i]->intr[SIMPLE_MODE_INT], hba[i]->devname);
-               goto clean2;
+       h->access.set_intr_mask(h, CCISS_INTR_OFF);
+       if (h->msi_vector || h->msix_vector) {
+               if (request_irq(h->intr[PERF_MODE_INT],
+                               do_cciss_msix_intr,
+                               IRQF_DISABLED, h->devname, h)) {
+                       dev_err(&h->pdev->dev, "Unable to get irq %d for %s\n",
+                              h->intr[PERF_MODE_INT], h->devname);
+                       goto clean2;
+               }
+       } else {
+               if (request_irq(h->intr[PERF_MODE_INT], do_cciss_intx,
+                               IRQF_DISABLED, h->devname, h)) {
+                       dev_err(&h->pdev->dev, "Unable to get irq %d for %s\n",
+                              h->intr[PERF_MODE_INT], h->devname);
+                       goto clean2;
+               }
        }
 
        }
 
-       printk(KERN_INFO "%s: <0x%x> at PCI %s IRQ %d%s using DAC\n",
-              hba[i]->devname, pdev->device, pci_name(pdev),
-              hba[i]->intr[SIMPLE_MODE_INT], dac ? "" : " not");
+       dev_info(&h->pdev->dev, "%s: <0x%x> at PCI %s IRQ %d%s using DAC\n",
+              h->devname, pdev->device, pci_name(pdev),
+              h->intr[PERF_MODE_INT], dac ? "" : " not");
 
 
-       hba[i]->cmd_pool_bits =
-           kmalloc(DIV_ROUND_UP(hba[i]->nr_cmds, BITS_PER_LONG)
+       h->cmd_pool_bits =
+           kmalloc(DIV_ROUND_UP(h->nr_cmds, BITS_PER_LONG)
                        * sizeof(unsigned long), GFP_KERNEL);
                        * sizeof(unsigned long), GFP_KERNEL);
-       hba[i]->cmd_pool = (CommandList_struct *)
-           pci_alloc_consistent(hba[i]->pdev,
-                   hba[i]->nr_cmds * sizeof(CommandList_struct),
-                   &(hba[i]->cmd_pool_dhandle));
-       hba[i]->errinfo_pool = (ErrorInfo_struct *)
-           pci_alloc_consistent(hba[i]->pdev,
-                   hba[i]->nr_cmds * sizeof(ErrorInfo_struct),
-                   &(hba[i]->errinfo_pool_dhandle));
-       if ((hba[i]->cmd_pool_bits == NULL)
-           || (hba[i]->cmd_pool == NULL)
-           || (hba[i]->errinfo_pool == NULL)) {
-               printk(KERN_ERR "cciss: out of memory");
+       h->cmd_pool = (CommandList_struct *)
+           pci_alloc_consistent(h->pdev,
+                   h->nr_cmds * sizeof(CommandList_struct),
+                   &(h->cmd_pool_dhandle));
+       h->errinfo_pool = (ErrorInfo_struct *)
+           pci_alloc_consistent(h->pdev,
+                   h->nr_cmds * sizeof(ErrorInfo_struct),
+                   &(h->errinfo_pool_dhandle));
+       if ((h->cmd_pool_bits == NULL)
+           || (h->cmd_pool == NULL)
+           || (h->errinfo_pool == NULL)) {
+               dev_err(&h->pdev->dev, "out of memory");
                goto clean4;
        }
 
        /* Need space for temp scatter list */
                goto clean4;
        }
 
        /* Need space for temp scatter list */
-       hba[i]->scatter_list = kmalloc(hba[i]->max_commands *
+       h->scatter_list = kmalloc(h->max_commands *
                                                sizeof(struct scatterlist *),
                                                GFP_KERNEL);
                                                sizeof(struct scatterlist *),
                                                GFP_KERNEL);
-       for (k = 0; k < hba[i]->nr_cmds; k++) {
-               hba[i]->scatter_list[k] = kmalloc(sizeof(struct scatterlist) *
-                                                       hba[i]->maxsgentries,
+       for (k = 0; k < h->nr_cmds; k++) {
+               h->scatter_list[k] = kmalloc(sizeof(struct scatterlist) *
+                                                       h->maxsgentries,
                                                        GFP_KERNEL);
                                                        GFP_KERNEL);
-               if (hba[i]->scatter_list[k] == NULL) {
-                       printk(KERN_ERR "cciss%d: could not allocate "
-                               "s/g lists\n", i);
+               if (h->scatter_list[k] == NULL) {
+                       dev_err(&h->pdev->dev,
+                               "could not allocate s/g lists\n");
                        goto clean4;
                }
        }
                        goto clean4;
                }
        }
-       hba[i]->cmd_sg_list = cciss_allocate_sg_chain_blocks(hba[i],
-               hba[i]->chainsize, hba[i]->nr_cmds);
-       if (!hba[i]->cmd_sg_list && hba[i]->chainsize > 0)
+       h->cmd_sg_list = cciss_allocate_sg_chain_blocks(h,
+               h->chainsize, h->nr_cmds);
+       if (!h->cmd_sg_list && h->chainsize > 0)
                goto clean4;
 
                goto clean4;
 
-       spin_lock_init(&hba[i]->lock);
+       spin_lock_init(&h->lock);
 
        /* Initialize the pdev driver private data.
 
        /* Initialize the pdev driver private data.
-          have it point to hba[i].  */
-       pci_set_drvdata(pdev, hba[i]);
+          have it point to h.  */
+       pci_set_drvdata(pdev, h);
        /* command and error info recs zeroed out before
           they are used */
        /* command and error info recs zeroed out before
           they are used */
-       memset(hba[i]->cmd_pool_bits, 0,
-              DIV_ROUND_UP(hba[i]->nr_cmds, BITS_PER_LONG)
+       memset(h->cmd_pool_bits, 0,
+              DIV_ROUND_UP(h->nr_cmds, BITS_PER_LONG)
                        * sizeof(unsigned long));
 
                        * sizeof(unsigned long));
 
-       hba[i]->num_luns = 0;
-       hba[i]->highest_lun = -1;
+       h->num_luns = 0;
+       h->highest_lun = -1;
        for (j = 0; j < CISS_MAX_LUN; j++) {
        for (j = 0; j < CISS_MAX_LUN; j++) {
-               hba[i]->drv[j] = NULL;
-               hba[i]->gendisk[j] = NULL;
+               h->drv[j] = NULL;
+               h->gendisk[j] = NULL;
        }
 
        }
 
-       cciss_scsi_setup(i);
+       cciss_scsi_setup(h);
 
        /* Turn the interrupts on so we can service requests */
 
        /* Turn the interrupts on so we can service requests */
-       hba[i]->access.set_intr_mask(hba[i], CCISS_INTR_ON);
+       h->access.set_intr_mask(h, CCISS_INTR_ON);
 
        /* Get the firmware version */
        inq_buff = kzalloc(sizeof(InquiryData_struct), GFP_KERNEL);
        if (inq_buff == NULL) {
 
        /* Get the firmware version */
        inq_buff = kzalloc(sizeof(InquiryData_struct), GFP_KERNEL);
        if (inq_buff == NULL) {
-               printk(KERN_ERR "cciss: out of memory\n");
+               dev_err(&h->pdev->dev, "out of memory\n");
                goto clean4;
        }
 
                goto clean4;
        }
 
-       return_code = sendcmd_withirq(CISS_INQUIRY, i, inq_buff,
+       return_code = sendcmd_withirq(h, CISS_INQUIRY, inq_buff,
                sizeof(InquiryData_struct), 0, CTLR_LUNID, TYPE_CMD);
        if (return_code == IO_OK) {
                sizeof(InquiryData_struct), 0, CTLR_LUNID, TYPE_CMD);
        if (return_code == IO_OK) {
-               hba[i]->firm_ver[0] = inq_buff->data_byte[32];
-               hba[i]->firm_ver[1] = inq_buff->data_byte[33];
-               hba[i]->firm_ver[2] = inq_buff->data_byte[34];
-               hba[i]->firm_ver[3] = inq_buff->data_byte[35];
+               h->firm_ver[0] = inq_buff->data_byte[32];
+               h->firm_ver[1] = inq_buff->data_byte[33];
+               h->firm_ver[2] = inq_buff->data_byte[34];
+               h->firm_ver[3] = inq_buff->data_byte[35];
        } else {         /* send command failed */
        } else {         /* send command failed */
-               printk(KERN_WARNING "cciss: unable to determine firmware"
+               dev_warn(&h->pdev->dev, "unable to determine firmware"
                        " version of controller\n");
        }
        kfree(inq_buff);
 
                        " version of controller\n");
        }
        kfree(inq_buff);
 
-       cciss_procinit(i);
+       cciss_procinit(h);
 
 
-       hba[i]->cciss_max_sectors = 8192;
+       h->cciss_max_sectors = 8192;
 
 
-       rebuild_lun_table(hba[i], 1, 0);
-       hba[i]->busy_initializing = 0;
+       rebuild_lun_table(h, 1, 0);
+       h->busy_initializing = 0;
        return 1;
 
 clean4:
        return 1;
 
 clean4:
-       kfree(hba[i]->cmd_pool_bits);
+       kfree(h->cmd_pool_bits);
        /* Free up sg elements */
        /* Free up sg elements */
-       for (k = 0; k < hba[i]->nr_cmds; k++)
-               kfree(hba[i]->scatter_list[k]);
-       kfree(hba[i]->scatter_list);
-       cciss_free_sg_chain_blocks(hba[i]->cmd_sg_list, hba[i]->nr_cmds);
-       if (hba[i]->cmd_pool)
-               pci_free_consistent(hba[i]->pdev,
-                                   hba[i]->nr_cmds * sizeof(CommandList_struct),
-                                   hba[i]->cmd_pool, hba[i]->cmd_pool_dhandle);
-       if (hba[i]->errinfo_pool)
-               pci_free_consistent(hba[i]->pdev,
-                                   hba[i]->nr_cmds * sizeof(ErrorInfo_struct),
-                                   hba[i]->errinfo_pool,
-                                   hba[i]->errinfo_pool_dhandle);
-       free_irq(hba[i]->intr[SIMPLE_MODE_INT], hba[i]);
+       for (k = 0; k < h->nr_cmds; k++)
+               kfree(h->scatter_list[k]);
+       kfree(h->scatter_list);
+       cciss_free_sg_chain_blocks(h->cmd_sg_list, h->nr_cmds);
+       if (h->cmd_pool)
+               pci_free_consistent(h->pdev,
+                                   h->nr_cmds * sizeof(CommandList_struct),
+                                   h->cmd_pool, h->cmd_pool_dhandle);
+       if (h->errinfo_pool)
+               pci_free_consistent(h->pdev,
+                                   h->nr_cmds * sizeof(ErrorInfo_struct),
+                                   h->errinfo_pool,
+                                   h->errinfo_pool_dhandle);
+       free_irq(h->intr[PERF_MODE_INT], h);
 clean2:
 clean2:
-       unregister_blkdev(hba[i]->major, hba[i]->devname);
+       unregister_blkdev(h->major, h->devname);
 clean1:
 clean1:
-       cciss_destroy_hba_sysfs_entry(hba[i]);
+       cciss_destroy_hba_sysfs_entry(h);
 clean0:
        pci_release_regions(pdev);
 clean_no_release_regions:
 clean0:
        pci_release_regions(pdev);
 clean_no_release_regions:
-       hba[i]->busy_initializing = 0;
+       h->busy_initializing = 0;
 
        /*
         * Deliberately omit pci_disable_device(): it does something nasty to
         * Smart Array controllers that pci_enable_device does not undo
         */
        pci_set_drvdata(pdev, NULL);
 
        /*
         * Deliberately omit pci_disable_device(): it does something nasty to
         * Smart Array controllers that pci_enable_device does not undo
         */
        pci_set_drvdata(pdev, NULL);
-       free_hba(i);
+       free_hba(h);
        return -1;
 }
 
        return -1;
 }
 
@@ -4381,55 +4822,51 @@ static void cciss_shutdown(struct pci_dev *pdev)
        h = pci_get_drvdata(pdev);
        flush_buf = kzalloc(4, GFP_KERNEL);
        if (!flush_buf) {
        h = pci_get_drvdata(pdev);
        flush_buf = kzalloc(4, GFP_KERNEL);
        if (!flush_buf) {
-               printk(KERN_WARNING
-                       "cciss:%d cache not flushed, out of memory.\n",
-                       h->ctlr);
+               dev_warn(&h->pdev->dev, "cache not flushed, out of memory.\n");
                return;
        }
        /* write all data in the battery backed cache to disk */
        memset(flush_buf, 0, 4);
                return;
        }
        /* write all data in the battery backed cache to disk */
        memset(flush_buf, 0, 4);
-       return_code = sendcmd_withirq(CCISS_CACHE_FLUSH, h->ctlr, flush_buf,
+       return_code = sendcmd_withirq(h, CCISS_CACHE_FLUSH, flush_buf,
                4, 0, CTLR_LUNID, TYPE_CMD);
        kfree(flush_buf);
        if (return_code != IO_OK)
                4, 0, CTLR_LUNID, TYPE_CMD);
        kfree(flush_buf);
        if (return_code != IO_OK)
-               printk(KERN_WARNING "cciss%d: Error flushing cache\n",
-                       h->ctlr);
+               dev_warn(&h->pdev->dev, "Error flushing cache\n");
        h->access.set_intr_mask(h, CCISS_INTR_OFF);
        h->access.set_intr_mask(h, CCISS_INTR_OFF);
-       free_irq(h->intr[2], h);
+       free_irq(h->intr[PERF_MODE_INT], h);
 }
 
 static void __devexit cciss_remove_one(struct pci_dev *pdev)
 {
 }
 
 static void __devexit cciss_remove_one(struct pci_dev *pdev)
 {
-       ctlr_info_t *tmp_ptr;
+       ctlr_info_t *h;
        int i, j;
 
        if (pci_get_drvdata(pdev) == NULL) {
        int i, j;
 
        if (pci_get_drvdata(pdev) == NULL) {
-               printk(KERN_ERR "cciss: Unable to remove device \n");
+               dev_err(&pdev->dev, "Unable to remove device\n");
                return;
        }
 
                return;
        }
 
-       tmp_ptr = pci_get_drvdata(pdev);
-       i = tmp_ptr->ctlr;
+       h = pci_get_drvdata(pdev);
+       i = h->ctlr;
        if (hba[i] == NULL) {
        if (hba[i] == NULL) {
-               printk(KERN_ERR "cciss: device appears to "
-                      "already be removed \n");
+               dev_err(&pdev->dev, "device appears to already be removed\n");
                return;
        }
 
                return;
        }
 
-       mutex_lock(&hba[i]->busy_shutting_down);
+       mutex_lock(&h->busy_shutting_down);
 
 
-       remove_from_scan_list(hba[i]);
-       remove_proc_entry(hba[i]->devname, proc_cciss);
-       unregister_blkdev(hba[i]->major, hba[i]->devname);
+       remove_from_scan_list(h);
+       remove_proc_entry(h->devname, proc_cciss);
+       unregister_blkdev(h->major, h->devname);
 
        /* remove it from the disk list */
        for (j = 0; j < CISS_MAX_LUN; j++) {
 
        /* remove it from the disk list */
        for (j = 0; j < CISS_MAX_LUN; j++) {
-               struct gendisk *disk = hba[i]->gendisk[j];
+               struct gendisk *disk = h->gendisk[j];
                if (disk) {
                        struct request_queue *q = disk->queue;
 
                        if (disk->flags & GENHD_FL_UP) {
                if (disk) {
                        struct request_queue *q = disk->queue;
 
                        if (disk->flags & GENHD_FL_UP) {
-                               cciss_destroy_ld_sysfs_entry(hba[i], j, 1);
+                               cciss_destroy_ld_sysfs_entry(h, j, 1);
                                del_gendisk(disk);
                        }
                        if (q)
                                del_gendisk(disk);
                        }
                        if (q)
@@ -4438,39 +4875,41 @@ static void __devexit cciss_remove_one(struct pci_dev *pdev)
        }
 
 #ifdef CONFIG_CISS_SCSI_TAPE
        }
 
 #ifdef CONFIG_CISS_SCSI_TAPE
-       cciss_unregister_scsi(i);       /* unhook from SCSI subsystem */
+       cciss_unregister_scsi(h);       /* unhook from SCSI subsystem */
 #endif
 
        cciss_shutdown(pdev);
 
 #ifdef CONFIG_PCI_MSI
 #endif
 
        cciss_shutdown(pdev);
 
 #ifdef CONFIG_PCI_MSI
-       if (hba[i]->msix_vector)
-               pci_disable_msix(hba[i]->pdev);
-       else if (hba[i]->msi_vector)
-               pci_disable_msi(hba[i]->pdev);
+       if (h->msix_vector)
+               pci_disable_msix(h->pdev);
+       else if (h->msi_vector)
+               pci_disable_msi(h->pdev);
 #endif                         /* CONFIG_PCI_MSI */
 
 #endif                         /* CONFIG_PCI_MSI */
 
-       iounmap(hba[i]->vaddr);
+       iounmap(h->transtable);
+       iounmap(h->cfgtable);
+       iounmap(h->vaddr);
 
 
-       pci_free_consistent(hba[i]->pdev, hba[i]->nr_cmds * sizeof(CommandList_struct),
-                           hba[i]->cmd_pool, hba[i]->cmd_pool_dhandle);
-       pci_free_consistent(hba[i]->pdev, hba[i]->nr_cmds * sizeof(ErrorInfo_struct),
-                           hba[i]->errinfo_pool, hba[i]->errinfo_pool_dhandle);
-       kfree(hba[i]->cmd_pool_bits);
+       pci_free_consistent(h->pdev, h->nr_cmds * sizeof(CommandList_struct),
+                           h->cmd_pool, h->cmd_pool_dhandle);
+       pci_free_consistent(h->pdev, h->nr_cmds * sizeof(ErrorInfo_struct),
+                           h->errinfo_pool, h->errinfo_pool_dhandle);
+       kfree(h->cmd_pool_bits);
        /* Free up sg elements */
        /* Free up sg elements */
-       for (j = 0; j < hba[i]->nr_cmds; j++)
-               kfree(hba[i]->scatter_list[j]);
-       kfree(hba[i]->scatter_list);
-       cciss_free_sg_chain_blocks(hba[i]->cmd_sg_list, hba[i]->nr_cmds);
+       for (j = 0; j < h->nr_cmds; j++)
+               kfree(h->scatter_list[j]);
+       kfree(h->scatter_list);
+       cciss_free_sg_chain_blocks(h->cmd_sg_list, h->nr_cmds);
        /*
         * 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);
        /*
         * 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);
-       cciss_destroy_hba_sysfs_entry(hba[i]);
-       mutex_unlock(&hba[i]->busy_shutting_down);
-       free_hba(i);
+       cciss_destroy_hba_sysfs_entry(h);
+       mutex_unlock(&h->busy_shutting_down);
+       free_hba(h);
 }
 
 static struct pci_driver cciss_pci_driver = {
 }
 
 static struct pci_driver cciss_pci_driver = {
@@ -4495,7 +4934,6 @@ static int __init cciss_init(void)
         * array of them, the size must be a multiple of 8 bytes.
         */
        BUILD_BUG_ON(sizeof(CommandList_struct) % COMMANDLIST_ALIGNMENT);
         * array of them, the size must be a multiple of 8 bytes.
         */
        BUILD_BUG_ON(sizeof(CommandList_struct) % COMMANDLIST_ALIGNMENT);
-
        printk(KERN_INFO DRIVER_NAME "\n");
 
        err = bus_register(&cciss_bus_type);
        printk(KERN_INFO DRIVER_NAME "\n");
 
        err = bus_register(&cciss_bus_type);
@@ -4532,8 +4970,8 @@ static void __exit cciss_cleanup(void)
        /* double check that all controller entrys have been removed */
        for (i = 0; i < MAX_CTLR; i++) {
                if (hba[i] != NULL) {
        /* double check that all controller entrys have been removed */
        for (i = 0; i < MAX_CTLR; i++) {
                if (hba[i] != NULL) {
-                       printk(KERN_WARNING "cciss: had to remove"
-                              " controller %d\n", i);
+                       dev_warn(&hba[i]->pdev->dev,
+                               "had to remove controller\n");
                        cciss_remove_one(hba[i]->pdev);
                }
        }
                        cciss_remove_one(hba[i]->pdev);
                }
        }
@@ -4542,46 +4980,5 @@ static void __exit cciss_cleanup(void)
        bus_unregister(&cciss_bus_type);
 }
 
        bus_unregister(&cciss_bus_type);
 }
 
-static void fail_all_cmds(unsigned long ctlr)
-{
-       /* If we get here, the board is apparently dead. */
-       ctlr_info_t *h = hba[ctlr];
-       CommandList_struct *c;
-       unsigned long flags;
-
-       printk(KERN_WARNING "cciss%d: controller not responding.\n", h->ctlr);
-       h->alive = 0;           /* the controller apparently died... */
-
-       spin_lock_irqsave(CCISS_LOCK(ctlr), flags);
-
-       pci_disable_device(h->pdev);    /* Make sure it is really dead. */
-
-       /* move everything off the request queue onto the completed queue */
-       while (!hlist_empty(&h->reqQ)) {
-               c = hlist_entry(h->reqQ.first, CommandList_struct, list);
-               removeQ(c);
-               h->Qdepth--;
-               addQ(&h->cmpQ, c);
-       }
-
-       /* Now, fail everything on the completed queue with a HW error */
-       while (!hlist_empty(&h->cmpQ)) {
-               c = hlist_entry(h->cmpQ.first, CommandList_struct, list);
-               removeQ(c);
-               if (c->cmd_type != CMD_MSG_STALE)
-                       c->err_info->CommandStatus = CMD_HARDWARE_ERR;
-               if (c->cmd_type == CMD_RWREQ) {
-                       complete_command(h, c, 0);
-               } else if (c->cmd_type == CMD_IOCTL_PEND)
-                       complete(c->waiting);
-#ifdef CONFIG_CISS_SCSI_TAPE
-               else if (c->cmd_type == CMD_SCSI)
-                       complete_scsi_command(c, 0, 0);
-#endif
-       }
-       spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
-       return;
-}
-
 module_init(cciss_init);
 module_exit(cciss_cleanup);
 module_init(cciss_init);
 module_exit(cciss_cleanup);