]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/block/cciss.c
[PATCH] cciss: increase number of commands on controller
[linux-2.6-omap-h63xx.git] / drivers / block / cciss.c
index 2cd3391ff8783dcb8497600d833f4cedf4a24eb4..0f976aaaf0497e4526628c9d0ee47429cf36be49 100644 (file)
@@ -20,7 +20,6 @@
  *
  */
 
-#include <linux/config.h>      /* CONFIG_PROC_FS */
 #include <linux/module.h>
 #include <linux/interrupt.h>
 #include <linux/types.h>
 #include <linux/completion.h>
 
 #define CCISS_DRIVER_VERSION(maj,min,submin) ((maj<<16)|(min<<8)|(submin))
-#define DRIVER_NAME "HP CISS Driver (v 3.6.10)"
-#define DRIVER_VERSION CCISS_DRIVER_VERSION(3,6,10)
+#define DRIVER_NAME "HP CISS Driver (v 3.6.14)"
+#define DRIVER_VERSION CCISS_DRIVER_VERSION(3,6,14)
 
 /* Embedded module documentation macros - see modules.h */
 MODULE_AUTHOR("Hewlett-Packard Company");
-MODULE_DESCRIPTION("Driver for HP Controller SA5xxx SA6xxx version 3.6.10");
+MODULE_DESCRIPTION("Driver for HP Controller SA5xxx SA6xxx version 3.6.14");
 MODULE_SUPPORTED_DEVICE("HP SA5i SA5i+ SA532 SA5300 SA5312 SA641 SA642 SA6400"
                        " SA6i P600 P800 P400 P400i E200 E200i E500");
+MODULE_VERSION("3.6.14");
 MODULE_LICENSE("GPL");
 
 #include "cciss_cmd.h"
@@ -83,6 +83,8 @@ static const struct pci_device_id cciss_pci_device_id[] = {
        {PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSD,     0x103C, 0x3214},
        {PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSD,     0x103C, 0x3215},
        {PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSC,     0x103C, 0x3233},
+       {PCI_VENDOR_ID_HP,     PCI_ANY_ID,      PCI_ANY_ID, PCI_ANY_ID,
+               PCI_CLASS_STORAGE_RAID << 8, 0xffff << 8, 0},
        {0,}
 };
 
@@ -91,27 +93,29 @@ MODULE_DEVICE_TABLE(pci, cciss_pci_device_id);
 /*  board_id = Subsystem Device ID & Vendor ID
  *  product = Marketing Name for the board
  *  access = Address of the struct of function pointers
+ *  nr_cmds = Number of commands supported by controller
  */
 static struct board_type products[] = {
-       {0x40700E11, "Smart Array 5300", &SA5_access},
-       {0x40800E11, "Smart Array 5i", &SA5B_access},
-       {0x40820E11, "Smart Array 532", &SA5B_access},
-       {0x40830E11, "Smart Array 5312", &SA5B_access},
-       {0x409A0E11, "Smart Array 641", &SA5_access},
-       {0x409B0E11, "Smart Array 642", &SA5_access},
-       {0x409C0E11, "Smart Array 6400", &SA5_access},
-       {0x409D0E11, "Smart Array 6400 EM", &SA5_access},
-       {0x40910E11, "Smart Array 6i", &SA5_access},
-       {0x3225103C, "Smart Array P600", &SA5_access},
-       {0x3223103C, "Smart Array P800", &SA5_access},
-       {0x3234103C, "Smart Array P400", &SA5_access},
-       {0x3235103C, "Smart Array P400i", &SA5_access},
-       {0x3211103C, "Smart Array E200i", &SA5_access},
-       {0x3212103C, "Smart Array E200", &SA5_access},
-       {0x3213103C, "Smart Array E200i", &SA5_access},
-       {0x3214103C, "Smart Array E200i", &SA5_access},
-       {0x3215103C, "Smart Array E200i", &SA5_access},
-       {0x3233103C, "Smart Array E500", &SA5_access},
+       {0x40700E11, "Smart Array 5300", &SA5_access, 512},
+       {0x40800E11, "Smart Array 5i", &SA5B_access, 512},
+       {0x40820E11, "Smart Array 532", &SA5B_access, 512},
+       {0x40830E11, "Smart Array 5312", &SA5B_access, 512},
+       {0x409A0E11, "Smart Array 641", &SA5_access, 512},
+       {0x409B0E11, "Smart Array 642", &SA5_access, 512},
+       {0x409C0E11, "Smart Array 6400", &SA5_access, 512},
+       {0x409D0E11, "Smart Array 6400 EM", &SA5_access, 512},
+       {0x40910E11, "Smart Array 6i", &SA5_access, 512},
+       {0x3225103C, "Smart Array P600", &SA5_access, 512},
+       {0x3223103C, "Smart Array P800", &SA5_access, 512},
+       {0x3234103C, "Smart Array P400", &SA5_access, 512},
+       {0x3235103C, "Smart Array P400i", &SA5_access, 512},
+       {0x3211103C, "Smart Array E200i", &SA5_access, 120},
+       {0x3212103C, "Smart Array E200", &SA5_access, 120},
+       {0x3213103C, "Smart Array E200i", &SA5_access, 120},
+       {0x3214103C, "Smart Array E200i", &SA5_access, 120},
+       {0x3215103C, "Smart Array E200i", &SA5_access, 120},
+       {0x3233103C, "Smart Array E500", &SA5_access, 512},
+       {0xFFFF103C, "Unknown Smart Array", &SA5_access, 120},
 };
 
 /* How long to wait (in milliseconds) for board to go into simple mode */
@@ -122,7 +126,6 @@ static struct board_type products[] = {
 #define MAX_CMD_RETRIES 3
 
 #define READ_AHEAD      1024
-#define NR_CMDS                 384    /* #commands that can be outstanding */
 #define MAX_CTLR       32
 
 /* Originally cciss driver only supports 8 major numbers */
@@ -131,7 +134,7 @@ static struct board_type products[] = {
 static ctlr_info_t *hba[MAX_CTLR];
 
 static void do_cciss_request(request_queue_t *q);
-static irqreturn_t do_cciss_intr(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t do_cciss_intr(int irq, void *dev_id);
 static int cciss_open(struct inode *inode, struct file *filep);
 static int cciss_release(struct inode *inode, struct file *filep);
 static int cciss_ioctl(struct inode *inode, struct file *filep,
@@ -144,13 +147,13 @@ static int rebuild_lun_table(ctlr_info_t *h, struct gendisk *del_disk);
 static int deregister_disk(struct gendisk *disk, drive_info_struct *drv,
                           int clear_all);
 
-static void cciss_read_capacity(int ctlr, int logvol, ReadCapdata_struct *buf,
-                               int withirq, unsigned int *total_size,
-                               unsigned int *block_size);
-static void cciss_geometry_inquiry(int ctlr, int logvol, int withirq,
-                                  unsigned int total_size,
-                                  unsigned int block_size,
-                                  InquiryData_struct *inq_buff,
+static void cciss_read_capacity(int ctlr, int logvol, int withirq,
+                       sector_t *total_size, unsigned int *block_size);
+static void cciss_read_capacity_16(int ctlr, int logvol, int withirq,
+                       sector_t *total_size, unsigned int *block_size);
+static void cciss_geometry_inquiry(int ctlr, int logvol,
+                       int withirq, sector_t total_size,
+                       unsigned int block_size, InquiryData_struct *inq_buff,
                                   drive_info_struct *drv);
 static void cciss_getgeometry(int cntl_num);
 static void __devinit cciss_interrupt_mode(ctlr_info_t *, struct pci_dev *,
@@ -401,8 +404,8 @@ static CommandList_struct *cmd_alloc(ctlr_info_t *h, int get_from_pool)
        } else {                /* get it out of the controllers pool */
 
                do {
-                       i = find_first_zero_bit(h->cmd_pool_bits, NR_CMDS);
-                       if (i == NR_CMDS)
+                       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),
@@ -879,7 +882,7 @@ static int cciss_ioctl(struct inode *inode, struct file *filep,
                        char *buff = NULL;
                        u64bit temp64;
                        unsigned long flags;
-                       DECLARE_COMPLETION(wait);
+                       DECLARE_COMPLETION_ONSTACK(wait);
 
                        if (!arg)
                                return -EINVAL;
@@ -997,7 +1000,7 @@ static int cciss_ioctl(struct inode *inode, struct file *filep,
                        BYTE sg_used = 0;
                        int status = 0;
                        int i;
-                       DECLARE_COMPLETION(wait);
+                       DECLARE_COMPLETION_ONSTACK(wait);
                        __u32 left;
                        __u32 sz;
                        BYTE __user *data_ptr;
@@ -1229,7 +1232,6 @@ static inline void complete_buffers(struct bio *bio, int status)
                int nr_sectors = bio_sectors(bio);
 
                bio->bi_next = NULL;
-               blk_finished_io(len);
                bio_endio(bio, nr_sectors << 9, status ? 0 : -EIO);
                bio = xbh;
        }
@@ -1245,7 +1247,7 @@ static void cciss_check_queues(ctlr_info_t *h)
         * in case the interrupt we serviced was from an ioctl and did not
         * free any new commands.
         */
-       if ((find_first_zero_bit(h->cmd_pool_bits, NR_CMDS)) == NR_CMDS)
+       if ((find_first_zero_bit(h->cmd_pool_bits, h->nr_cmds)) == h->nr_cmds)
                return;
 
        /* We have room on the queue for more commands.  Now we need to queue
@@ -1264,7 +1266,7 @@ static void cciss_check_queues(ctlr_info_t *h)
                /* check to see if we have maxed out the number of commands
                 * that can be placed on the queue.
                 */
-               if ((find_first_zero_bit(h->cmd_pool_bits, NR_CMDS)) == NR_CMDS) {
+               if ((find_first_zero_bit(h->cmd_pool_bits, h->nr_cmds)) == h->nr_cmds) {
                        if (curr_queue == start_queue) {
                                h->next_to_run =
                                    (start_queue + 1) % (h->highest_lun + 1);
@@ -1302,6 +1304,12 @@ static void cciss_softirq_done(struct request *rq)
 
        complete_buffers(rq->bio, rq->errors);
 
+       if (blk_fs_request(rq)) {
+               const int rw = rq_data_dir(rq);
+
+               disk_stat_add(rq->rq_disk, sectors[rw], rq->nr_sectors);
+       }
+
 #ifdef CCISS_DEBUG
        printk("Done with %p\n", rq);
 #endif                         /* CCISS_DEBUG */
@@ -1326,10 +1334,9 @@ static void cciss_update_drive_info(int ctlr, int drv_index)
 {
        ctlr_info_t *h = hba[ctlr];
        struct gendisk *disk;
-       ReadCapdata_struct *size_buff = NULL;
        InquiryData_struct *inq_buff = NULL;
        unsigned int block_size;
-       unsigned int total_size;
+       sector_t total_size;
        unsigned long flags = 0;
        int ret = 0;
 
@@ -1348,15 +1355,25 @@ static void cciss_update_drive_info(int ctlr, int drv_index)
                return;
 
        /* Get information about the disk and modify the driver structure */
-       size_buff = kmalloc(sizeof(ReadCapdata_struct), GFP_KERNEL);
-       if (size_buff == NULL)
-               goto mem_msg;
        inq_buff = kmalloc(sizeof(InquiryData_struct), GFP_KERNEL);
        if (inq_buff == NULL)
                goto mem_msg;
 
-       cciss_read_capacity(ctlr, drv_index, size_buff, 1,
+       cciss_read_capacity(ctlr, drv_index, 1,
                            &total_size, &block_size);
+
+       /* total size = last LBA + 1 */
+       /* FFFFFFFF + 1 = 0, cannot have a logical volume of size 0 */
+       /* so we assume this volume this must be >2TB in size */
+       if (total_size == (__u32) 0) {
+               cciss_read_capacity_16(ctlr, drv_index, 1,
+               &total_size, &block_size);
+               h->cciss_read = CCISS_READ_16;
+               h->cciss_write = CCISS_WRITE_16;
+       } else {
+               h->cciss_read = CCISS_READ_10;
+               h->cciss_write = CCISS_WRITE_10;
+       }
        cciss_geometry_inquiry(ctlr, drv_index, 1, total_size, block_size,
                               inq_buff, &h->drv[drv_index]);
 
@@ -1392,7 +1409,6 @@ static void cciss_update_drive_info(int ctlr, int drv_index)
        }
 
       freeret:
-       kfree(size_buff);
        kfree(inq_buff);
        return;
       mem_msg:
@@ -1717,6 +1733,22 @@ static int fill_cmd(CommandList_struct *c, __u8 cmd, int ctlr, void *buff, size_
                        c->Request.Timeout = 0;
                        c->Request.CDB[0] = cmd;
                        break;
+               case CCISS_READ_CAPACITY_16:
+                       c->Header.LUN.LogDev.VolId = h->drv[log_unit].LunID;
+                       c->Header.LUN.LogDev.Mode = 1;
+                       c->Request.CDBLen = 16;
+                       c->Request.Type.Attribute = ATTR_SIMPLE;
+                       c->Request.Type.Direction = XFER_READ;
+                       c->Request.Timeout = 0;
+                       c->Request.CDB[0] = cmd;
+                       c->Request.CDB[1] = 0x10;
+                       c->Request.CDB[10] = (size >> 24) & 0xFF;
+                       c->Request.CDB[11] = (size >> 16) & 0xFF;
+                       c->Request.CDB[12] = (size >> 8) & 0xFF;
+                       c->Request.CDB[13] = size & 0xFF;
+                       c->Request.Timeout = 0;
+                       c->Request.CDB[0] = cmd;
+                       break;
                case CCISS_CACHE_FLUSH:
                        c->Request.CDBLen = 12;
                        c->Request.Type.Attribute = ATTR_SIMPLE;
@@ -1750,6 +1782,7 @@ static int fill_cmd(CommandList_struct *c, __u8 cmd, int ctlr, void *buff, size_
                        memset(&c->Request.CDB[0], 0, sizeof(c->Request.CDB));
                        c->Request.CDB[0] = cmd;        /* reset */
                        c->Request.CDB[1] = 0x04;       /* reset a LUN */
+                       break;
                case 3: /* No-Op message */
                        c->Request.CDBLen = 1;
                        c->Request.Type.Attribute = ATTR_SIMPLE;
@@ -1792,7 +1825,7 @@ static int sendcmd_withirq(__u8 cmd,
        u64bit buff_dma_handle;
        unsigned long flags;
        int return_status;
-       DECLARE_COMPLETION(wait);
+       DECLARE_COMPLETION_ONSTACK(wait);
 
        if ((c = cmd_alloc(h, 0)) == NULL)
                return -ENOMEM;
@@ -1893,12 +1926,14 @@ static int sendcmd_withirq(__u8 cmd,
 }
 
 static void cciss_geometry_inquiry(int ctlr, int logvol,
-                                  int withirq, unsigned int total_size,
+                                  int withirq, sector_t total_size,
                                   unsigned int block_size,
                                   InquiryData_struct *inq_buff,
                                   drive_info_struct *drv)
 {
        int return_code;
+       unsigned long t;
+
        memset(inq_buff, 0, sizeof(InquiryData_struct));
        if (withirq)
                return_code = sendcmd_withirq(CISS_INQUIRY, ctlr,
@@ -1913,59 +1948,98 @@ static void cciss_geometry_inquiry(int ctlr, int logvol,
                        printk(KERN_WARNING
                               "cciss: reading geometry failed, volume "
                               "does not support reading geometry\n");
-                       drv->block_size = block_size;
-                       drv->nr_blocks = total_size;
                        drv->heads = 255;
                        drv->sectors = 32;      // Sectors per track
-                       drv->cylinders = total_size / 255 / 32;
                } else {
-                       unsigned int t;
-
-                       drv->block_size = block_size;
-                       drv->nr_blocks = total_size;
                        drv->heads = inq_buff->data_byte[6];
                        drv->sectors = inq_buff->data_byte[7];
                        drv->cylinders = (inq_buff->data_byte[4] & 0xff) << 8;
                        drv->cylinders += inq_buff->data_byte[5];
                        drv->raid_level = inq_buff->data_byte[8];
-                       t = drv->heads * drv->sectors;
-                       if (t > 1) {
-                               drv->cylinders = total_size / t;
-                       }
+               }
+               drv->block_size = block_size;
+               drv->nr_blocks = total_size;
+               t = drv->heads * drv->sectors;
+               if (t > 1) {
+                       unsigned rem = sector_div(total_size, t);
+                       if (rem)
+                               total_size++;
+                       drv->cylinders = total_size;
                }
        } else {                /* Get geometry failed */
                printk(KERN_WARNING "cciss: reading geometry failed\n");
        }
-       printk(KERN_INFO "      heads= %d, sectors= %d, cylinders= %d\n\n",
+       printk(KERN_INFO "      heads=%d, sectors=%d, cylinders=%d\n\n",
               drv->heads, drv->sectors, drv->cylinders);
 }
 
 static void
-cciss_read_capacity(int ctlr, int logvol, ReadCapdata_struct *buf,
-                   int withirq, unsigned int *total_size,
+cciss_read_capacity(int ctlr, int logvol, int withirq, sector_t *total_size,
                    unsigned int *block_size)
 {
+       ReadCapdata_struct *buf;
        int return_code;
-       memset(buf, 0, sizeof(*buf));
+       buf = kmalloc(sizeof(ReadCapdata_struct), GFP_KERNEL);
+       if (buf == NULL) {
+               printk(KERN_WARNING "cciss: out of memory\n");
+               return;
+       }
+       memset(buf, 0, sizeof(ReadCapdata_struct));
        if (withirq)
                return_code = sendcmd_withirq(CCISS_READ_CAPACITY,
-                                             ctlr, buf, sizeof(*buf), 1,
-                                             logvol, 0, TYPE_CMD);
+                               ctlr, buf, sizeof(ReadCapdata_struct),
+                                       1, logvol, 0, TYPE_CMD);
        else
                return_code = sendcmd(CCISS_READ_CAPACITY,
-                                     ctlr, buf, sizeof(*buf), 1, logvol, 0,
-                                     NULL, TYPE_CMD);
+                               ctlr, buf, sizeof(ReadCapdata_struct),
+                                       1, logvol, 0, NULL, TYPE_CMD);
+       if (return_code == IO_OK) {
+               *total_size = be32_to_cpu(*(__u32 *) buf->total_size)+1;
+               *block_size = be32_to_cpu(*(__u32 *) buf->block_size);
+       } else {                /* read capacity command failed */
+               printk(KERN_WARNING "cciss: read capacity failed\n");
+               *total_size = 0;
+               *block_size = BLOCK_SIZE;
+       }
+       if (*total_size != (__u32) 0)
+               printk(KERN_INFO "      blocks= %llu block_size= %d\n",
+               (unsigned long long)*total_size, *block_size);
+       kfree(buf);
+       return;
+}
+
+static void
+cciss_read_capacity_16(int ctlr, int logvol, int withirq, sector_t *total_size,                                unsigned int *block_size)
+{
+       ReadCapdata_struct_16 *buf;
+       int return_code;
+       buf = kmalloc(sizeof(ReadCapdata_struct_16), GFP_KERNEL);
+       if (buf == NULL) {
+               printk(KERN_WARNING "cciss: out of memory\n");
+               return;
+       }
+       memset(buf, 0, sizeof(ReadCapdata_struct_16));
+       if (withirq) {
+               return_code = sendcmd_withirq(CCISS_READ_CAPACITY_16,
+                       ctlr, buf, sizeof(ReadCapdata_struct_16),
+                               1, logvol, 0, TYPE_CMD);
+       }
+       else {
+               return_code = sendcmd(CCISS_READ_CAPACITY_16,
+                       ctlr, buf, sizeof(ReadCapdata_struct_16),
+                               1, logvol, 0, NULL, TYPE_CMD);
+       }
        if (return_code == IO_OK) {
-               *total_size =
-                   be32_to_cpu(*((__be32 *) & buf->total_size[0])) + 1;
-               *block_size = be32_to_cpu(*((__be32 *) & buf->block_size[0]));
+               *total_size = be64_to_cpu(*(__u64 *) buf->total_size)+1;
+               *block_size = be32_to_cpu(*(__u32 *) buf->block_size);
        } else {                /* read capacity command failed */
                printk(KERN_WARNING "cciss: read capacity failed\n");
                *total_size = 0;
                *block_size = BLOCK_SIZE;
        }
-       printk(KERN_INFO "      blocks= %u block_size= %d\n",
-              *total_size, *block_size);
+       printk(KERN_INFO "      blocks= %llu block_size= %d\n",
+              (unsigned long long)*total_size, *block_size);
+       kfree(buf);
        return;
 }
 
@@ -1976,8 +2050,7 @@ static int cciss_revalidate(struct gendisk *disk)
        int logvol;
        int FOUND = 0;
        unsigned int block_size;
-       unsigned int total_size;
-       ReadCapdata_struct *size_buff = NULL;
+       sector_t total_size;
        InquiryData_struct *inq_buff = NULL;
 
        for (logvol = 0; logvol < CISS_MAX_LUN; logvol++) {
@@ -1990,27 +2063,24 @@ static int cciss_revalidate(struct gendisk *disk)
        if (!FOUND)
                return 1;
 
-       size_buff = kmalloc(sizeof(ReadCapdata_struct), GFP_KERNEL);
-       if (size_buff == NULL) {
-               printk(KERN_WARNING "cciss: out of memory\n");
-               return 1;
-       }
        inq_buff = kmalloc(sizeof(InquiryData_struct), GFP_KERNEL);
        if (inq_buff == NULL) {
                printk(KERN_WARNING "cciss: out of memory\n");
-               kfree(size_buff);
                return 1;
        }
-
-       cciss_read_capacity(h->ctlr, logvol, size_buff, 1, &total_size,
-                           &block_size);
+       if (h->cciss_read == CCISS_READ_10) {
+               cciss_read_capacity(h->ctlr, logvol, 1,
+                                       &total_size, &block_size);
+       } else {
+               cciss_read_capacity_16(h->ctlr, logvol, 1,
+                                       &total_size, &block_size);
+       }
        cciss_geometry_inquiry(h->ctlr, logvol, 1, total_size, block_size,
                               inq_buff, drv);
 
        blk_queue_hardsect_size(drv->queue, drv->block_size);
        set_capacity(disk, drv->nr_blocks);
 
-       kfree(size_buff);
        kfree(inq_buff);
        return 0;
 }
@@ -2070,7 +2140,7 @@ static int add_sendcmd_reject(__u8 cmd, int ctlr, unsigned long complete)
 
        /* We've sent down an abort or reset, but something else
           has completed */
-       if (srl->ncompletions >= (NR_CMDS + 2)) {
+       if (srl->ncompletions >= (hba[ctlr]->nr_cmds + 2)) {
                /* Uh oh.  No room to save it for later... */
                printk(KERN_WARNING "cciss%d: Sendcmd: Invalid command addr, "
                       "reject list overflow, command lost!\n", ctlr);
@@ -2236,7 +2306,7 @@ static int sendcmd(__u8 cmd, int ctlr, void *buff, size_t size, unsigned int use
 #ifdef CONFIG_CISS_SCSI_TAPE
        /* if we saved some commands for later, process them now. */
        if (info_p->scsi_rejects.ncompletions > 0)
-               do_cciss_intr(0, info_p, NULL);
+               do_cciss_intr(0, info_p);
 #endif
        cmd_free(info_p, c, 1);
        return status;
@@ -2419,7 +2489,8 @@ static void do_cciss_request(request_queue_t *q)
 {
        ctlr_info_t *h = q->queuedata;
        CommandList_struct *c;
-       int start_blk, seg;
+       sector_t start_blk;
+       int seg;
        struct request *creq;
        u64bit temp64;
        struct scatterlist tmp_sg[MAXSGENTRIES];
@@ -2463,10 +2534,10 @@ static void do_cciss_request(request_queue_t *q)
        c->Request.Type.Type = TYPE_CMD;        // It is a command.
        c->Request.Type.Attribute = ATTR_SIMPLE;
        c->Request.Type.Direction =
-           (rq_data_dir(creq) == READ) ? XFER_READ : XFER_WRITE;
+           (rq_data_dir(creq) == READ) ? h->cciss_read : h->cciss_write;
        c->Request.Timeout = 0; // Don't time out
        c->Request.CDB[0] =
-           (rq_data_dir(creq) == READ) ? CCISS_READ : CCISS_WRITE;
+           (rq_data_dir(creq) == READ) ? h->cciss_read : h->cciss_write;
        start_blk = creq->sector;
 #ifdef CCISS_DEBUG
        printk(KERN_DEBUG "ciss: sector =%d nr_sectors=%d\n", (int)creq->sector,
@@ -2500,15 +2571,33 @@ static void do_cciss_request(request_queue_t *q)
 #endif                         /* CCISS_DEBUG */
 
        c->Header.SGList = c->Header.SGTotal = seg;
-       c->Request.CDB[1] = 0;
-       c->Request.CDB[2] = (start_blk >> 24) & 0xff;   //MSB
-       c->Request.CDB[3] = (start_blk >> 16) & 0xff;
-       c->Request.CDB[4] = (start_blk >> 8) & 0xff;
-       c->Request.CDB[5] = start_blk & 0xff;
-       c->Request.CDB[6] = 0;  // (sect >> 24) & 0xff; MSB
-       c->Request.CDB[7] = (creq->nr_sectors >> 8) & 0xff;
-       c->Request.CDB[8] = creq->nr_sectors & 0xff;
-       c->Request.CDB[9] = c->Request.CDB[11] = c->Request.CDB[12] = 0;
+       if(h->cciss_read == CCISS_READ_10) {
+               c->Request.CDB[1] = 0;
+               c->Request.CDB[2] = (start_blk >> 24) & 0xff;   //MSB
+               c->Request.CDB[3] = (start_blk >> 16) & 0xff;
+               c->Request.CDB[4] = (start_blk >> 8) & 0xff;
+               c->Request.CDB[5] = start_blk & 0xff;
+               c->Request.CDB[6] = 0;  // (sect >> 24) & 0xff; MSB
+               c->Request.CDB[7] = (creq->nr_sectors >> 8) & 0xff;
+               c->Request.CDB[8] = creq->nr_sectors & 0xff;
+               c->Request.CDB[9] = c->Request.CDB[11] = c->Request.CDB[12] = 0;
+       } else {
+               c->Request.CDBLen = 16;
+               c->Request.CDB[1]= 0;
+               c->Request.CDB[2]= (start_blk >> 56) & 0xff;    //MSB
+               c->Request.CDB[3]= (start_blk >> 48) & 0xff;
+               c->Request.CDB[4]= (start_blk >> 40) & 0xff;
+               c->Request.CDB[5]= (start_blk >> 32) & 0xff;
+               c->Request.CDB[6]= (start_blk >> 24) & 0xff;
+               c->Request.CDB[7]= (start_blk >> 16) & 0xff;
+               c->Request.CDB[8]= (start_blk >>  8) & 0xff;
+               c->Request.CDB[9]= start_blk & 0xff;
+               c->Request.CDB[10]= (creq->nr_sectors >>  24) & 0xff;
+               c->Request.CDB[11]= (creq->nr_sectors >>  16) & 0xff;
+               c->Request.CDB[12]= (creq->nr_sectors >>  8) & 0xff;
+               c->Request.CDB[13]= creq->nr_sectors & 0xff;
+               c->Request.CDB[14] = c->Request.CDB[15] = 0;
+       }
 
        spin_lock_irq(q->queue_lock);
 
@@ -2518,9 +2607,9 @@ static void do_cciss_request(request_queue_t *q)
                h->maxQsinceinit = h->Qdepth;
 
        goto queue;
-      full:
+full:
        blk_stop_queue(q);
-      startio:
+startio:
        /* We will already have the driver lock here so not need
         * to lock it.
         */
@@ -2569,7 +2658,7 @@ static inline long interrupt_not_for_us(ctlr_info_t *h)
 #endif
 }
 
-static irqreturn_t do_cciss_intr(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t do_cciss_intr(int irq, void *dev_id)
 {
        ctlr_info_t *h = dev_id;
        CommandList_struct *c;
@@ -2588,7 +2677,7 @@ static irqreturn_t do_cciss_intr(int irq, void *dev_id, struct pt_regs *regs)
                        a1 = a;
                        if ((a & 0x04)) {
                                a2 = (a >> 3);
-                               if (a2 >= NR_CMDS) {
+                               if (a2 >= h->nr_cmds) {
                                        printk(KERN_WARNING
                                               "cciss: controller cciss%d failed, stopping.\n",
                                               h->ctlr);
@@ -2871,16 +2960,10 @@ static int cciss_pci_init(ctlr_info_t *c, struct pci_dev *pdev)
                if (board_id == products[i].board_id) {
                        c->product_name = products[i].product_name;
                        c->access = *(products[i].access);
+                       c->nr_cmds = products[i].nr_cmds;
                        break;
                }
        }
-       if (i == ARRAY_SIZE(products)) {
-               printk(KERN_WARNING "cciss: Sorry, I don't know how"
-                      " to access the Smart Array controller %08lx\n",
-                      (unsigned long)board_id);
-               err = -ENODEV;
-               goto err_out_free_res;
-       }
        if ((readb(&c->cfgtable->Signature[0]) != 'C') ||
            (readb(&c->cfgtable->Signature[1]) != 'I') ||
            (readb(&c->cfgtable->Signature[2]) != 'S') ||
@@ -2889,6 +2972,27 @@ static int cciss_pci_init(ctlr_info_t *c, struct pci_dev *pdev)
                err = -ENODEV;
                goto err_out_free_res;
        }
+       /* We didn't find the controller in our list. We know the
+        * signature is valid. If it's an HP device let's try to
+        * bind to the device and fire it up. Otherwise we bail.
+        */
+       if (i == ARRAY_SIZE(products)) {
+               if (subsystem_vendor_id == PCI_VENDOR_ID_HP) {
+                       c->product_name = products[i-1].product_name;
+                       c->access = *(products[i-1].access);
+                       c->nr_cmds = products[i-1].nr_cmds;
+                       printk(KERN_WARNING "cciss: This is an unknown "
+                               "Smart Array controller.\n"
+                               "cciss: Please update to the latest driver "
+                               "available from www.hp.com.\n");
+               } else {
+                       printk(KERN_WARNING "cciss: Sorry, I don't know how"
+                               " to access the Smart Array controller %08lx\n"
+                                       , (unsigned long)board_id);
+                       err = -ENODEV;
+                       goto err_out_free_res;
+               }
+       }
 #ifdef CONFIG_X86
        {
                /* Need to enable prefetch in the SCSI core for 6400 in x86 */
@@ -2948,31 +3052,23 @@ static int cciss_pci_init(ctlr_info_t *c, struct pci_dev *pdev)
 static void cciss_getgeometry(int cntl_num)
 {
        ReportLunData_struct *ld_buff;
-       ReadCapdata_struct *size_buff;
        InquiryData_struct *inq_buff;
        int return_code;
        int i;
        int listlength = 0;
        __u32 lunid = 0;
        int block_size;
-       int total_size;
+       sector_t total_size;
 
        ld_buff = kzalloc(sizeof(ReportLunData_struct), GFP_KERNEL);
        if (ld_buff == NULL) {
                printk(KERN_ERR "cciss: out of memory\n");
                return;
        }
-       size_buff = kmalloc(sizeof(ReadCapdata_struct), GFP_KERNEL);
-       if (size_buff == NULL) {
-               printk(KERN_ERR "cciss: out of memory\n");
-               kfree(ld_buff);
-               return;
-       }
        inq_buff = kmalloc(sizeof(InquiryData_struct), GFP_KERNEL);
        if (inq_buff == NULL) {
                printk(KERN_ERR "cciss: out of memory\n");
                kfree(ld_buff);
-               kfree(size_buff);
                return;
        }
        /* Get the firmware version */
@@ -3027,7 +3123,6 @@ static void cciss_getgeometry(int cntl_num)
 #endif                         /* CCISS_DEBUG */
 
        hba[cntl_num]->highest_lun = hba[cntl_num]->num_luns - 1;
-//      for(i=0; i<  hba[cntl_num]->num_luns; i++)
        for (i = 0; i < CISS_MAX_LUN; i++) {
                if (i < hba[cntl_num]->num_luns) {
                        lunid = (0xff & (unsigned int)(ld_buff->LUN[i][3]))
@@ -3046,8 +3141,26 @@ static void cciss_getgeometry(int cntl_num)
                               ld_buff->LUN[i][2], ld_buff->LUN[i][3],
                               hba[cntl_num]->drv[i].LunID);
 #endif                         /* CCISS_DEBUG */
-                       cciss_read_capacity(cntl_num, i, size_buff, 0,
+
+               /* testing to see if 16-byte CDBs are already being used */
+               if(hba[cntl_num]->cciss_read == CCISS_READ_16) {
+                       cciss_read_capacity_16(cntl_num, i, 0,
                                            &total_size, &block_size);
+                       goto geo_inq;
+               }
+               cciss_read_capacity(cntl_num, i, 0, &total_size, &block_size);
+
+               /* total_size = last LBA + 1 */
+               if(total_size == (__u32) 0) {
+                       cciss_read_capacity_16(cntl_num, i, 0,
+                       &total_size, &block_size);
+                       hba[cntl_num]->cciss_read = CCISS_READ_16;
+                       hba[cntl_num]->cciss_write = CCISS_WRITE_16;
+               } else {
+                       hba[cntl_num]->cciss_read = CCISS_READ_10;
+                       hba[cntl_num]->cciss_write = CCISS_WRITE_10;
+               }
+geo_inq:
                        cciss_geometry_inquiry(cntl_num, i, 0, total_size,
                                               block_size, inq_buff,
                                               &hba[cntl_num]->drv[i]);
@@ -3057,7 +3170,6 @@ static void cciss_getgeometry(int cntl_num)
                }
        }
        kfree(ld_buff);
-       kfree(size_buff);
        kfree(inq_buff);
 }
 
@@ -3176,15 +3288,15 @@ static int __devinit cciss_init_one(struct pci_dev *pdev,
               hba[i]->intr[SIMPLE_MODE_INT], dac ? "" : " not");
 
        hba[i]->cmd_pool_bits =
-           kmalloc(((NR_CMDS + BITS_PER_LONG -
+           kmalloc(((hba[i]->nr_cmds + BITS_PER_LONG -
                      1) / BITS_PER_LONG) * sizeof(unsigned long), GFP_KERNEL);
        hba[i]->cmd_pool = (CommandList_struct *)
            pci_alloc_consistent(hba[i]->pdev,
-                   NR_CMDS * sizeof(CommandList_struct),
+                   hba[i]->nr_cmds * sizeof(CommandList_struct),
                    &(hba[i]->cmd_pool_dhandle));
        hba[i]->errinfo_pool = (ErrorInfo_struct *)
            pci_alloc_consistent(hba[i]->pdev,
-                   NR_CMDS * sizeof(ErrorInfo_struct),
+                   hba[i]->nr_cmds * sizeof(ErrorInfo_struct),
                    &(hba[i]->errinfo_pool_dhandle));
        if ((hba[i]->cmd_pool_bits == NULL)
            || (hba[i]->cmd_pool == NULL)
@@ -3195,7 +3307,7 @@ static int __devinit cciss_init_one(struct pci_dev *pdev,
 #ifdef CONFIG_CISS_SCSI_TAPE
        hba[i]->scsi_rejects.complete =
            kmalloc(sizeof(hba[i]->scsi_rejects.complete[0]) *
-                   (NR_CMDS + 5), GFP_KERNEL);
+                   (hba[i]->nr_cmds + 5), GFP_KERNEL);
        if (hba[i]->scsi_rejects.complete == NULL) {
                printk(KERN_ERR "cciss: out of memory");
                goto clean4;
@@ -3209,7 +3321,7 @@ static int __devinit cciss_init_one(struct pci_dev *pdev,
        /* command and error info recs zeroed out before
           they are used */
        memset(hba[i]->cmd_pool_bits, 0,
-              ((NR_CMDS + BITS_PER_LONG -
+              ((hba[i]->nr_cmds + BITS_PER_LONG -
                 1) / BITS_PER_LONG) * sizeof(unsigned long));
 
 #ifdef CCISS_DEBUG
@@ -3278,11 +3390,11 @@ static int __devinit cciss_init_one(struct pci_dev *pdev,
        kfree(hba[i]->cmd_pool_bits);
        if (hba[i]->cmd_pool)
                pci_free_consistent(hba[i]->pdev,
-                                   NR_CMDS * sizeof(CommandList_struct),
+                                   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,
-                                   NR_CMDS * sizeof(ErrorInfo_struct),
+                                   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]);
@@ -3349,9 +3461,9 @@ static void __devexit cciss_remove_one(struct pci_dev *pdev)
                }
        }
 
-       pci_free_consistent(hba[i]->pdev, NR_CMDS * sizeof(CommandList_struct),
+       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, NR_CMDS * sizeof(ErrorInfo_struct),
+       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);
 #ifdef CONFIG_CISS_SCSI_TAPE