Merge branch 'staging-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh...
[pandora-kernel.git] / drivers / block / cciss.c
index c484c96..a67d0a6 100644 (file)
@@ -66,11 +66,6 @@ MODULE_VERSION("3.6.26");
 MODULE_LICENSE("GPL");
 
 static DEFINE_MUTEX(cciss_mutex);
-static int cciss_allow_hpsa;
-module_param(cciss_allow_hpsa, int, S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(cciss_allow_hpsa,
-       "Prevent cciss driver from accessing hardware known to be "
-       " supported by the hpsa driver");
 
 #include "cciss_cmd.h"
 #include "cciss.h"
@@ -98,18 +93,6 @@ static const struct pci_device_id cciss_pci_device_id[] = {
        {PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSD,     0x103C, 0x3215},
        {PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSC,     0x103C, 0x3237},
        {PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSC,     0x103C, 0x323D},
-       {PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSE,     0x103C, 0x3241},
-       {PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSE,     0x103C, 0x3243},
-       {PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSE,     0x103C, 0x3245},
-       {PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSE,     0x103C, 0x3247},
-       {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,}
 };
 
@@ -130,6 +113,8 @@ static struct board_type products[] = {
        {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},
@@ -137,23 +122,9 @@ static struct board_type products[] = {
        {0x3214103C, "Smart Array E200i", &SA5_access},
        {0x3215103C, "Smart Array E200i", &SA5_access},
        {0x3237103C, "Smart Array E500", &SA5_access},
-/* controllers below this line are also supported by the hpsa driver. */
-#define HPSA_BOUNDARY 0x3223103C
        {0x3223103C, "Smart Array P800", &SA5_access},
        {0x3234103C, "Smart Array P400", &SA5_access},
        {0x323D103C, "Smart Array P700m", &SA5_access},
-       {0x3241103C, "Smart Array P212", &SA5_access},
-       {0x3243103C, "Smart Array P410", &SA5_access},
-       {0x3245103C, "Smart Array P410i", &SA5_access},
-       {0x3247103C, "Smart Array P411", &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 */
@@ -1182,6 +1153,7 @@ static int cciss_ioctl32_big_passthru(struct block_device *bdev, fmode_t mode,
        int err;
        u32 cp;
 
+       memset(&arg64, 0, sizeof(arg64));
        err = 0;
        err |=
            copy_from_user(&arg64.LUN_info, &arg32->LUN_info,
@@ -1232,470 +1204,452 @@ static void check_ioctl_unit_attention(ctlr_info_t *h, CommandList_struct *c)
                        c->err_info->ScsiStatus != SAM_STAT_CHECK_CONDITION)
                (void)check_for_unit_attention(h, c);
 }
-/*
- * ioctl
- */
-static int cciss_ioctl(struct block_device *bdev, fmode_t mode,
-                      unsigned int cmd, unsigned long arg)
+
+static int cciss_getpciinfo(ctlr_info_t *h, void __user *argp)
 {
-       struct gendisk *disk = bdev->bd_disk;
-       ctlr_info_t *h = get_host(disk);
-       drive_info_struct *drv = get_drv(disk);
-       void __user *argp = (void __user *)arg;
+       cciss_pci_info_struct pciinfo;
 
-       dev_dbg(&h->pdev->dev, "cciss_ioctl: Called with cmd=%x %lx\n",
-               cmd, arg);
-       switch (cmd) {
-       case CCISS_GETPCIINFO:
-               {
-                       cciss_pci_info_struct pciinfo;
-
-                       if (!arg)
-                               return -EINVAL;
-                       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;
-                       return 0;
-               }
-       case CCISS_GETINTINFO:
-               {
-                       cciss_coalint_struct intinfo;
-                       if (!arg)
-                               return -EINVAL;
-                       intinfo.delay =
-                           readl(&h->cfgtable->HostWrite.CoalIntDelay);
-                       intinfo.count =
-                           readl(&h->cfgtable->HostWrite.CoalIntCount);
-                       if (copy_to_user
-                           (argp, &intinfo, sizeof(cciss_coalint_struct)))
-                               return -EFAULT;
-                       return 0;
-               }
-       case CCISS_SETINTINFO:
-               {
-                       cciss_coalint_struct intinfo;
-                       unsigned long flags;
-                       int i;
-
-                       if (!arg)
-                               return -EINVAL;
-                       if (!capable(CAP_SYS_ADMIN))
-                               return -EPERM;
-                       if (copy_from_user
-                           (&intinfo, argp, sizeof(cciss_coalint_struct)))
-                               return -EFAULT;
-                       if ((intinfo.delay == 0) && (intinfo.count == 0))
-                               return -EINVAL;
-                       spin_lock_irqsave(&h->lock, flags);
-                       /* Update the field, and then ring the doorbell */
-                       writel(intinfo.delay,
-                              &(h->cfgtable->HostWrite.CoalIntDelay));
-                       writel(intinfo.count,
-                              &(h->cfgtable->HostWrite.CoalIntCount));
-                       writel(CFGTBL_ChangeReq, h->vaddr + SA5_DOORBELL);
-
-                       for (i = 0; i < MAX_IOCTL_CONFIG_WAIT; i++) {
-                               if (!(readl(h->vaddr + SA5_DOORBELL)
-                                     & CFGTBL_ChangeReq))
-                                       break;
-                               /* delay and try again */
-                               udelay(1000);
-                       }
-                       spin_unlock_irqrestore(&h->lock, flags);
-                       if (i >= MAX_IOCTL_CONFIG_WAIT)
-                               return -EAGAIN;
-                       return 0;
-               }
-       case CCISS_GETNODENAME:
-               {
-                       NodeName_type NodeName;
-                       int i;
-
-                       if (!arg)
-                               return -EINVAL;
-                       for (i = 0; i < 16; i++)
-                               NodeName[i] =
-                                   readb(&h->cfgtable->ServerName[i]);
-                       if (copy_to_user(argp, NodeName, sizeof(NodeName_type)))
-                               return -EFAULT;
-                       return 0;
-               }
-       case CCISS_SETNODENAME:
-               {
-                       NodeName_type NodeName;
-                       unsigned long flags;
-                       int i;
+       if (!argp)
+               return -EINVAL;
+       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;
+       return 0;
+}
 
-                       if (!arg)
-                               return -EINVAL;
-                       if (!capable(CAP_SYS_ADMIN))
-                               return -EPERM;
+static int cciss_getintinfo(ctlr_info_t *h, void __user *argp)
+{
+       cciss_coalint_struct intinfo;
 
-                       if (copy_from_user
-                           (NodeName, argp, sizeof(NodeName_type)))
-                               return -EFAULT;
+       if (!argp)
+               return -EINVAL;
+       intinfo.delay = readl(&h->cfgtable->HostWrite.CoalIntDelay);
+       intinfo.count = readl(&h->cfgtable->HostWrite.CoalIntCount);
+       if (copy_to_user
+           (argp, &intinfo, sizeof(cciss_coalint_struct)))
+               return -EFAULT;
+       return 0;
+}
 
-                       spin_lock_irqsave(&h->lock, flags);
+static int cciss_setintinfo(ctlr_info_t *h, void __user *argp)
+{
+       cciss_coalint_struct intinfo;
+       unsigned long flags;
+       int i;
 
-                       /* Update the field, and then ring the doorbell */
-                       for (i = 0; i < 16; i++)
-                               writeb(NodeName[i],
-                                      &h->cfgtable->ServerName[i]);
+       if (!argp)
+               return -EINVAL;
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+       if (copy_from_user(&intinfo, argp, sizeof(intinfo)))
+               return -EFAULT;
+       if ((intinfo.delay == 0) && (intinfo.count == 0))
+               return -EINVAL;
+       spin_lock_irqsave(&h->lock, flags);
+       /* Update the field, and then ring the doorbell */
+       writel(intinfo.delay, &(h->cfgtable->HostWrite.CoalIntDelay));
+       writel(intinfo.count, &(h->cfgtable->HostWrite.CoalIntCount));
+       writel(CFGTBL_ChangeReq, h->vaddr + SA5_DOORBELL);
 
-                       writel(CFGTBL_ChangeReq, h->vaddr + SA5_DOORBELL);
+       for (i = 0; i < MAX_IOCTL_CONFIG_WAIT; i++) {
+               if (!(readl(h->vaddr + SA5_DOORBELL) & CFGTBL_ChangeReq))
+                       break;
+               udelay(1000); /* delay and try again */
+       }
+       spin_unlock_irqrestore(&h->lock, flags);
+       if (i >= MAX_IOCTL_CONFIG_WAIT)
+               return -EAGAIN;
+       return 0;
+}
 
-                       for (i = 0; i < MAX_IOCTL_CONFIG_WAIT; i++) {
-                               if (!(readl(h->vaddr + SA5_DOORBELL)
-                                     & CFGTBL_ChangeReq))
-                                       break;
-                               /* delay and try again */
-                               udelay(1000);
-                       }
-                       spin_unlock_irqrestore(&h->lock, flags);
-                       if (i >= MAX_IOCTL_CONFIG_WAIT)
-                               return -EAGAIN;
-                       return 0;
-               }
+static int cciss_getnodename(ctlr_info_t *h, void __user *argp)
+{
+       NodeName_type NodeName;
+       int i;
 
-       case CCISS_GETHEARTBEAT:
-               {
-                       Heartbeat_type heartbeat;
-
-                       if (!arg)
-                               return -EINVAL;
-                       heartbeat = readl(&h->cfgtable->HeartBeat);
-                       if (copy_to_user
-                           (argp, &heartbeat, sizeof(Heartbeat_type)))
-                               return -EFAULT;
-                       return 0;
-               }
-       case CCISS_GETBUSTYPES:
-               {
-                       BusTypes_type BusTypes;
-
-                       if (!arg)
-                               return -EINVAL;
-                       BusTypes = readl(&h->cfgtable->BusTypes);
-                       if (copy_to_user
-                           (argp, &BusTypes, sizeof(BusTypes_type)))
-                               return -EFAULT;
-                       return 0;
-               }
-       case CCISS_GETFIRMVER:
-               {
-                       FirmwareVer_type firmware;
+       if (!argp)
+               return -EINVAL;
+       for (i = 0; i < 16; i++)
+               NodeName[i] = readb(&h->cfgtable->ServerName[i]);
+       if (copy_to_user(argp, NodeName, sizeof(NodeName_type)))
+               return -EFAULT;
+       return 0;
+}
 
-                       if (!arg)
-                               return -EINVAL;
-                       memcpy(firmware, h->firm_ver, 4);
+static int cciss_setnodename(ctlr_info_t *h, void __user *argp)
+{
+       NodeName_type NodeName;
+       unsigned long flags;
+       int i;
 
-                       if (copy_to_user
-                           (argp, firmware, sizeof(FirmwareVer_type)))
-                               return -EFAULT;
-                       return 0;
-               }
-       case CCISS_GETDRIVVER:
-               {
-                       DriverVer_type DriverVer = DRIVER_VERSION;
+       if (!argp)
+               return -EINVAL;
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+       if (copy_from_user(NodeName, argp, sizeof(NodeName_type)))
+               return -EFAULT;
+       spin_lock_irqsave(&h->lock, flags);
+       /* Update the field, and then ring the doorbell */
+       for (i = 0; i < 16; i++)
+               writeb(NodeName[i], &h->cfgtable->ServerName[i]);
+       writel(CFGTBL_ChangeReq, h->vaddr + SA5_DOORBELL);
+       for (i = 0; i < MAX_IOCTL_CONFIG_WAIT; i++) {
+               if (!(readl(h->vaddr + SA5_DOORBELL) & CFGTBL_ChangeReq))
+                       break;
+               udelay(1000); /* delay and try again */
+       }
+       spin_unlock_irqrestore(&h->lock, flags);
+       if (i >= MAX_IOCTL_CONFIG_WAIT)
+               return -EAGAIN;
+       return 0;
+}
 
-                       if (!arg)
-                               return -EINVAL;
+static int cciss_getheartbeat(ctlr_info_t *h, void __user *argp)
+{
+       Heartbeat_type heartbeat;
 
-                       if (copy_to_user
-                           (argp, &DriverVer, sizeof(DriverVer_type)))
-                               return -EFAULT;
-                       return 0;
-               }
+       if (!argp)
+               return -EINVAL;
+       heartbeat = readl(&h->cfgtable->HeartBeat);
+       if (copy_to_user(argp, &heartbeat, sizeof(Heartbeat_type)))
+               return -EFAULT;
+       return 0;
+}
 
-       case CCISS_DEREGDISK:
-       case CCISS_REGNEWD:
-       case CCISS_REVALIDVOLS:
-               return rebuild_lun_table(h, 0, 1);
+static int cciss_getbustypes(ctlr_info_t *h, void __user *argp)
+{
+       BusTypes_type BusTypes;
 
-       case CCISS_GETLUNINFO:{
-                       LogvolInfo_struct luninfo;
+       if (!argp)
+               return -EINVAL;
+       BusTypes = readl(&h->cfgtable->BusTypes);
+       if (copy_to_user(argp, &BusTypes, sizeof(BusTypes_type)))
+               return -EFAULT;
+       return 0;
+}
 
-                       memcpy(&luninfo.LunID, drv->LunID,
-                               sizeof(luninfo.LunID));
-                       luninfo.num_opens = drv->usage_count;
-                       luninfo.num_parts = 0;
-                       if (copy_to_user(argp, &luninfo,
-                                        sizeof(LogvolInfo_struct)))
-                               return -EFAULT;
-                       return 0;
+static int cciss_getfirmver(ctlr_info_t *h, void __user *argp)
+{
+       FirmwareVer_type firmware;
+
+       if (!argp)
+               return -EINVAL;
+       memcpy(firmware, h->firm_ver, 4);
+
+       if (copy_to_user
+           (argp, firmware, sizeof(FirmwareVer_type)))
+               return -EFAULT;
+       return 0;
+}
+
+static int cciss_getdrivver(ctlr_info_t *h, void __user *argp)
+{
+       DriverVer_type DriverVer = DRIVER_VERSION;
+
+       if (!argp)
+               return -EINVAL;
+       if (copy_to_user(argp, &DriverVer, sizeof(DriverVer_type)))
+               return -EFAULT;
+       return 0;
+}
+
+static int cciss_getluninfo(ctlr_info_t *h,
+       struct gendisk *disk, void __user *argp)
+{
+       LogvolInfo_struct luninfo;
+       drive_info_struct *drv = get_drv(disk);
+
+       if (!argp)
+               return -EINVAL;
+       memcpy(&luninfo.LunID, drv->LunID, sizeof(luninfo.LunID));
+       luninfo.num_opens = drv->usage_count;
+       luninfo.num_parts = 0;
+       if (copy_to_user(argp, &luninfo, sizeof(LogvolInfo_struct)))
+               return -EFAULT;
+       return 0;
+}
+
+static int cciss_passthru(ctlr_info_t *h, void __user *argp)
+{
+       IOCTL_Command_struct iocommand;
+       CommandList_struct *c;
+       char *buff = NULL;
+       u64bit temp64;
+       DECLARE_COMPLETION_ONSTACK(wait);
+
+       if (!argp)
+               return -EINVAL;
+
+       if (!capable(CAP_SYS_RAWIO))
+               return -EPERM;
+
+       if (copy_from_user
+           (&iocommand, argp, sizeof(IOCTL_Command_struct)))
+               return -EFAULT;
+       if ((iocommand.buf_size < 1) &&
+           (iocommand.Request.Type.Direction != XFER_NONE)) {
+               return -EINVAL;
+       }
+       if (iocommand.buf_size > 0) {
+               buff = kmalloc(iocommand.buf_size, GFP_KERNEL);
+               if (buff == NULL)
+                       return -EFAULT;
+       }
+       if (iocommand.Request.Type.Direction == XFER_WRITE) {
+               /* Copy the data into the buffer we created */
+               if (copy_from_user(buff, iocommand.buf, iocommand.buf_size)) {
+                       kfree(buff);
+                       return -EFAULT;
                }
-       case CCISS_PASSTHRU:
-               {
-                       IOCTL_Command_struct iocommand;
-                       CommandList_struct *c;
-                       char *buff = NULL;
-                       u64bit temp64;
-                       DECLARE_COMPLETION_ONSTACK(wait);
-
-                       if (!arg)
-                               return -EINVAL;
-
-                       if (!capable(CAP_SYS_RAWIO))
-                               return -EPERM;
-
-                       if (copy_from_user
-                           (&iocommand, argp, sizeof(IOCTL_Command_struct)))
-                               return -EFAULT;
-                       if ((iocommand.buf_size < 1) &&
-                           (iocommand.Request.Type.Direction != XFER_NONE)) {
-                               return -EINVAL;
-                       }
-#if 0                          /* 'buf_size' member is 16-bits, and always smaller than kmalloc limit */
-                       /* Check kmalloc limits */
-                       if (iocommand.buf_size > 128000)
-                               return -EINVAL;
-#endif
-                       if (iocommand.buf_size > 0) {
-                               buff = kmalloc(iocommand.buf_size, GFP_KERNEL);
-                               if (buff == NULL)
-                                       return -EFAULT;
-                       }
-                       if (iocommand.Request.Type.Direction == XFER_WRITE) {
-                               /* Copy the data into the buffer we created */
-                               if (copy_from_user
-                                   (buff, iocommand.buf, iocommand.buf_size)) {
-                                       kfree(buff);
-                                       return -EFAULT;
-                               }
-                       } else {
-                               memset(buff, 0, iocommand.buf_size);
-                       }
-                       c = cmd_special_alloc(h);
-                       if (!c) {
-                               kfree(buff);
-                               return -ENOMEM;
-                       }
-                       /* Fill in the command type */
-                       c->cmd_type = CMD_IOCTL_PEND;
-                       /* Fill in Command Header */
-                       c->Header.ReplyQueue = 0;   /* unused in simple mode */
-                       if (iocommand.buf_size > 0) /* buffer to fill */
-                       {
-                               c->Header.SGList = 1;
-                               c->Header.SGTotal = 1;
-                       } else /* no buffers to fill */
-                       {
-                               c->Header.SGList = 0;
-                               c->Header.SGTotal = 0;
-                       }
-                       c->Header.LUN = iocommand.LUN_info;
-                       /* use the kernel address the cmd block for tag */
-                       c->Header.Tag.lower = c->busaddr;
-
-                       /* Fill in Request block */
-                       c->Request = iocommand.Request;
-
-                       /* Fill in the scatter gather information */
-                       if (iocommand.buf_size > 0) {
-                               temp64.val = pci_map_single(h->pdev, buff,
-                                       iocommand.buf_size,
-                                       PCI_DMA_BIDIRECTIONAL);
-                               c->SG[0].Addr.lower = temp64.val32.lower;
-                               c->SG[0].Addr.upper = temp64.val32.upper;
-                               c->SG[0].Len = iocommand.buf_size;
-                               c->SG[0].Ext = 0;  /* we are not chaining */
-                       }
-                       c->waiting = &wait;
+       } else {
+               memset(buff, 0, iocommand.buf_size);
+       }
+       c = cmd_special_alloc(h);
+       if (!c) {
+               kfree(buff);
+               return -ENOMEM;
+       }
+       /* Fill in the command type */
+       c->cmd_type = CMD_IOCTL_PEND;
+       /* Fill in Command Header */
+       c->Header.ReplyQueue = 0;   /* unused in simple mode */
+       if (iocommand.buf_size > 0) { /* buffer to fill */
+               c->Header.SGList = 1;
+               c->Header.SGTotal = 1;
+       } else { /* no buffers to fill */
+               c->Header.SGList = 0;
+               c->Header.SGTotal = 0;
+       }
+       c->Header.LUN = iocommand.LUN_info;
+       /* use the kernel address the cmd block for tag */
+       c->Header.Tag.lower = c->busaddr;
 
-                       enqueue_cmd_and_start_io(h, c);
-                       wait_for_completion(&wait);
+       /* Fill in Request block */
+       c->Request = iocommand.Request;
 
-                       /* unlock the buffers from DMA */
-                       temp64.val32.lower = c->SG[0].Addr.lower;
-                       temp64.val32.upper = c->SG[0].Addr.upper;
-                       pci_unmap_single(h->pdev, (dma_addr_t) temp64.val,
-                                        iocommand.buf_size,
-                                        PCI_DMA_BIDIRECTIONAL);
+       /* Fill in the scatter gather information */
+       if (iocommand.buf_size > 0) {
+               temp64.val = pci_map_single(h->pdev, buff,
+                       iocommand.buf_size, PCI_DMA_BIDIRECTIONAL);
+               c->SG[0].Addr.lower = temp64.val32.lower;
+               c->SG[0].Addr.upper = temp64.val32.upper;
+               c->SG[0].Len = iocommand.buf_size;
+               c->SG[0].Ext = 0;  /* we are not chaining */
+       }
+       c->waiting = &wait;
 
-                       check_ioctl_unit_attention(h, c);
+       enqueue_cmd_and_start_io(h, c);
+       wait_for_completion(&wait);
 
-                       /* Copy the error information out */
-                       iocommand.error_info = *(c->err_info);
-                       if (copy_to_user
-                           (argp, &iocommand, sizeof(IOCTL_Command_struct))) {
-                               kfree(buff);
-                               cmd_special_free(h, c);
-                               return -EFAULT;
-                       }
+       /* unlock the buffers from DMA */
+       temp64.val32.lower = c->SG[0].Addr.lower;
+       temp64.val32.upper = c->SG[0].Addr.upper;
+       pci_unmap_single(h->pdev, (dma_addr_t) temp64.val, iocommand.buf_size,
+                        PCI_DMA_BIDIRECTIONAL);
+       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);
+               cmd_special_free(h, c);
+               return -EFAULT;
+       }
 
-                       if (iocommand.Request.Type.Direction == XFER_READ) {
-                               /* Copy the data out of the buffer we created */
-                               if (copy_to_user
-                                   (iocommand.buf, buff, iocommand.buf_size)) {
-                                       kfree(buff);
-                                       cmd_special_free(h, c);
-                                       return -EFAULT;
-                               }
-                       }
+       if (iocommand.Request.Type.Direction == XFER_READ) {
+               /* Copy the data out of the buffer we created */
+               if (copy_to_user(iocommand.buf, buff, iocommand.buf_size)) {
                        kfree(buff);
                        cmd_special_free(h, c);
-                       return 0;
+                       return -EFAULT;
                }
-       case CCISS_BIG_PASSTHRU:{
-                       BIG_IOCTL_Command_struct *ioc;
-                       CommandList_struct *c;
-                       unsigned char **buff = NULL;
-                       int *buff_size = NULL;
-                       u64bit temp64;
-                       BYTE sg_used = 0;
-                       int status = 0;
-                       int i;
-                       DECLARE_COMPLETION_ONSTACK(wait);
-                       __u32 left;
-                       __u32 sz;
-                       BYTE __user *data_ptr;
-
-                       if (!arg)
-                               return -EINVAL;
-                       if (!capable(CAP_SYS_RAWIO))
-                               return -EPERM;
-                       ioc = (BIG_IOCTL_Command_struct *)
-                           kmalloc(sizeof(*ioc), GFP_KERNEL);
-                       if (!ioc) {
-                               status = -ENOMEM;
-                               goto cleanup1;
-                       }
-                       if (copy_from_user(ioc, argp, sizeof(*ioc))) {
+       }
+       kfree(buff);
+       cmd_special_free(h, c);
+       return 0;
+}
+
+static int cciss_bigpassthru(ctlr_info_t *h, void __user *argp)
+{
+       BIG_IOCTL_Command_struct *ioc;
+       CommandList_struct *c;
+       unsigned char **buff = NULL;
+       int *buff_size = NULL;
+       u64bit temp64;
+       BYTE sg_used = 0;
+       int status = 0;
+       int i;
+       DECLARE_COMPLETION_ONSTACK(wait);
+       __u32 left;
+       __u32 sz;
+       BYTE __user *data_ptr;
+
+       if (!argp)
+               return -EINVAL;
+       if (!capable(CAP_SYS_RAWIO))
+               return -EPERM;
+       ioc = (BIG_IOCTL_Command_struct *)
+           kmalloc(sizeof(*ioc), GFP_KERNEL);
+       if (!ioc) {
+               status = -ENOMEM;
+               goto cleanup1;
+       }
+       if (copy_from_user(ioc, argp, sizeof(*ioc))) {
+               status = -EFAULT;
+               goto cleanup1;
+       }
+       if ((ioc->buf_size < 1) &&
+           (ioc->Request.Type.Direction != XFER_NONE)) {
+               status = -EINVAL;
+               goto cleanup1;
+       }
+       /* Check kmalloc limits  using all SGs */
+       if (ioc->malloc_size > MAX_KMALLOC_SIZE) {
+               status = -EINVAL;
+               goto cleanup1;
+       }
+       if (ioc->buf_size > ioc->malloc_size * MAXSGENTRIES) {
+               status = -EINVAL;
+               goto cleanup1;
+       }
+       buff = kzalloc(MAXSGENTRIES * sizeof(char *), GFP_KERNEL);
+       if (!buff) {
+               status = -ENOMEM;
+               goto cleanup1;
+       }
+       buff_size = kmalloc(MAXSGENTRIES * sizeof(int), GFP_KERNEL);
+       if (!buff_size) {
+               status = -ENOMEM;
+               goto cleanup1;
+       }
+       left = ioc->buf_size;
+       data_ptr = ioc->buf;
+       while (left) {
+               sz = (left > ioc->malloc_size) ? ioc->malloc_size : left;
+               buff_size[sg_used] = sz;
+               buff[sg_used] = kmalloc(sz, GFP_KERNEL);
+               if (buff[sg_used] == NULL) {
+                       status = -ENOMEM;
+                       goto cleanup1;
+               }
+               if (ioc->Request.Type.Direction == XFER_WRITE) {
+                       if (copy_from_user(buff[sg_used], data_ptr, sz)) {
                                status = -EFAULT;
                                goto cleanup1;
                        }
-                       if ((ioc->buf_size < 1) &&
-                           (ioc->Request.Type.Direction != XFER_NONE)) {
-                               status = -EINVAL;
-                               goto cleanup1;
-                       }
-                       /* Check kmalloc limits  using all SGs */
-                       if (ioc->malloc_size > MAX_KMALLOC_SIZE) {
-                               status = -EINVAL;
-                               goto cleanup1;
-                       }
-                       if (ioc->buf_size > ioc->malloc_size * MAXSGENTRIES) {
-                               status = -EINVAL;
-                               goto cleanup1;
-                       }
-                       buff =
-                           kzalloc(MAXSGENTRIES * sizeof(char *), GFP_KERNEL);
-                       if (!buff) {
-                               status = -ENOMEM;
-                               goto cleanup1;
-                       }
-                       buff_size = kmalloc(MAXSGENTRIES * sizeof(int),
-                                                  GFP_KERNEL);
-                       if (!buff_size) {
-                               status = -ENOMEM;
-                               goto cleanup1;
-                       }
-                       left = ioc->buf_size;
-                       data_ptr = ioc->buf;
-                       while (left) {
-                               sz = (left >
-                                     ioc->malloc_size) ? ioc->
-                                   malloc_size : left;
-                               buff_size[sg_used] = sz;
-                               buff[sg_used] = kmalloc(sz, GFP_KERNEL);
-                               if (buff[sg_used] == NULL) {
-                                       status = -ENOMEM;
-                                       goto cleanup1;
-                               }
-                               if (ioc->Request.Type.Direction == XFER_WRITE) {
-                                       if (copy_from_user
-                                           (buff[sg_used], data_ptr, sz)) {
-                                               status = -EFAULT;
-                                               goto cleanup1;
-                                       }
-                               } else {
-                                       memset(buff[sg_used], 0, sz);
-                               }
-                               left -= sz;
-                               data_ptr += sz;
-                               sg_used++;
-                       }
-                       c = cmd_special_alloc(h);
-                       if (!c) {
-                               status = -ENOMEM;
-                               goto cleanup1;
-                       }
-                       c->cmd_type = CMD_IOCTL_PEND;
-                       c->Header.ReplyQueue = 0;
+               } else {
+                       memset(buff[sg_used], 0, sz);
+               }
+               left -= sz;
+               data_ptr += sz;
+               sg_used++;
+       }
+       c = cmd_special_alloc(h);
+       if (!c) {
+               status = -ENOMEM;
+               goto cleanup1;
+       }
+       c->cmd_type = CMD_IOCTL_PEND;
+       c->Header.ReplyQueue = 0;
+       c->Header.SGList = sg_used;
+       c->Header.SGTotal = sg_used;
+       c->Header.LUN = ioc->LUN_info;
+       c->Header.Tag.lower = c->busaddr;
 
-                       if (ioc->buf_size > 0) {
-                               c->Header.SGList = sg_used;
-                               c->Header.SGTotal = sg_used;
-                       } else {
-                               c->Header.SGList = 0;
-                               c->Header.SGTotal = 0;
-                       }
-                       c->Header.LUN = ioc->LUN_info;
-                       c->Header.Tag.lower = c->busaddr;
-
-                       c->Request = ioc->Request;
-                       if (ioc->buf_size > 0) {
-                               for (i = 0; i < sg_used; i++) {
-                                       temp64.val =
-                                           pci_map_single(h->pdev, buff[i],
-                                                   buff_size[i],
-                                                   PCI_DMA_BIDIRECTIONAL);
-                                       c->SG[i].Addr.lower =
-                                           temp64.val32.lower;
-                                       c->SG[i].Addr.upper =
-                                           temp64.val32.upper;
-                                       c->SG[i].Len = buff_size[i];
-                                       c->SG[i].Ext = 0;       /* we are not chaining */
-                               }
-                       }
-                       c->waiting = &wait;
-                       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;
-                               pci_unmap_single(h->pdev,
-                                       (dma_addr_t) temp64.val, buff_size[i],
-                                       PCI_DMA_BIDIRECTIONAL);
-                       }
-                       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))) {
+       c->Request = ioc->Request;
+       for (i = 0; i < sg_used; i++) {
+               temp64.val = pci_map_single(h->pdev, buff[i], buff_size[i],
+                                   PCI_DMA_BIDIRECTIONAL);
+               c->SG[i].Addr.lower = temp64.val32.lower;
+               c->SG[i].Addr.upper = temp64.val32.upper;
+               c->SG[i].Len = buff_size[i];
+               c->SG[i].Ext = 0;       /* we are not chaining */
+       }
+       c->waiting = &wait;
+       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;
+               pci_unmap_single(h->pdev,
+                       (dma_addr_t) temp64.val, buff_size[i],
+                       PCI_DMA_BIDIRECTIONAL);
+       }
+       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))) {
+               cmd_special_free(h, c);
+               status = -EFAULT;
+               goto cleanup1;
+       }
+       if (ioc->Request.Type.Direction == XFER_READ) {
+               /* Copy the data out of the buffer we created */
+               BYTE __user *ptr = ioc->buf;
+               for (i = 0; i < sg_used; i++) {
+                       if (copy_to_user(ptr, buff[i], buff_size[i])) {
                                cmd_special_free(h, c);
                                status = -EFAULT;
                                goto cleanup1;
                        }
-                       if (ioc->Request.Type.Direction == XFER_READ) {
-                               /* Copy the data out of the buffer we created */
-                               BYTE __user *ptr = ioc->buf;
-                               for (i = 0; i < sg_used; i++) {
-                                       if (copy_to_user
-                                           (ptr, buff[i], buff_size[i])) {
-                                               cmd_special_free(h, c);
-                                               status = -EFAULT;
-                                               goto cleanup1;
-                                       }
-                                       ptr += buff_size[i];
-                               }
-                       }
-                       cmd_special_free(h, c);
-                       status = 0;
-                     cleanup1:
-                       if (buff) {
-                               for (i = 0; i < sg_used; i++)
-                                       kfree(buff[i]);
-                               kfree(buff);
-                       }
-                       kfree(buff_size);
-                       kfree(ioc);
-                       return status;
+                       ptr += buff_size[i];
                }
+       }
+       cmd_special_free(h, c);
+       status = 0;
+cleanup1:
+       if (buff) {
+               for (i = 0; i < sg_used; i++)
+                       kfree(buff[i]);
+               kfree(buff);
+       }
+       kfree(buff_size);
+       kfree(ioc);
+       return status;
+}
+
+static int cciss_ioctl(struct block_device *bdev, fmode_t mode,
+       unsigned int cmd, unsigned long arg)
+{
+       struct gendisk *disk = bdev->bd_disk;
+       ctlr_info_t *h = get_host(disk);
+       void __user *argp = (void __user *)arg;
+
+       dev_dbg(&h->pdev->dev, "cciss_ioctl: Called with cmd=%x %lx\n",
+               cmd, arg);
+       switch (cmd) {
+       case CCISS_GETPCIINFO:
+               return cciss_getpciinfo(h, argp);
+       case CCISS_GETINTINFO:
+               return cciss_getintinfo(h, argp);
+       case CCISS_SETINTINFO:
+               return cciss_setintinfo(h, argp);
+       case CCISS_GETNODENAME:
+               return cciss_getnodename(h, argp);
+       case CCISS_SETNODENAME:
+               return cciss_setnodename(h, argp);
+       case CCISS_GETHEARTBEAT:
+               return cciss_getheartbeat(h, argp);
+       case CCISS_GETBUSTYPES:
+               return cciss_getbustypes(h, argp);
+       case CCISS_GETFIRMVER:
+               return cciss_getfirmver(h, argp);
+       case CCISS_GETDRIVVER:
+               return cciss_getdrivver(h, argp);
+       case CCISS_DEREGDISK:
+       case CCISS_REGNEWD:
+       case CCISS_REVALIDVOLS:
+               return rebuild_lun_table(h, 0, 1);
+       case CCISS_GETLUNINFO:
+               return cciss_getluninfo(h, disk, argp);
+       case CCISS_PASSTHRU:
+               return cciss_passthru(h, argp);
+       case CCISS_BIG_PASSTHRU:
+               return cciss_bigpassthru(h, argp);
 
        /* scsi_cmd_ioctl handles these, below, though some are not */
        /* very meaningful for cciss.  SG_IO is the main one people want. */
@@ -3801,7 +3755,7 @@ static void __devinit cciss_wait_for_mode_change_ack(ctlr_info_t *h)
        for (i = 0; i < MAX_CONFIG_WAIT; i++) {
                if (!(readl(h->vaddr + SA5_DOORBELL) & CFGTBL_ChangeReq))
                        break;
-               msleep(10);
+               usleep_range(10000, 20000);
        }
 }
 
@@ -3985,13 +3939,9 @@ static int __devinit cciss_lookup_board_id(struct pci_dev *pdev, u32 *board_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++)
                if (*board_id == products[i].board_id)
                        return i;
-       }
        dev_warn(&pdev->dev, "unrecognized board ID: 0x%08x, ignoring.\n",
                *board_id);
        return -ENODEV;
@@ -4022,18 +3972,31 @@ static int __devinit cciss_pci_find_memory_BAR(struct pci_dev *pdev,
        return -ENODEV;
 }
 
-static int __devinit cciss_wait_for_board_ready(ctlr_info_t *h)
+static int __devinit cciss_wait_for_board_state(struct pci_dev *pdev,
+       void __iomem *vaddr, int wait_for_ready)
+#define BOARD_READY 1
+#define BOARD_NOT_READY 0
 {
-       int i;
+       int i, iterations;
        u32 scratchpad;
 
-       for (i = 0; i < CCISS_BOARD_READY_ITERATIONS; i++) {
-               scratchpad = readl(h->vaddr + SA5_SCRATCHPAD_OFFSET);
-               if (scratchpad == CCISS_FIRMWARE_READY)
-                       return 0;
+       if (wait_for_ready)
+               iterations = CCISS_BOARD_READY_ITERATIONS;
+       else
+               iterations = CCISS_BOARD_NOT_READY_ITERATIONS;
+
+       for (i = 0; i < iterations; i++) {
+               scratchpad = readl(vaddr + SA5_SCRATCHPAD_OFFSET);
+               if (wait_for_ready) {
+                       if (scratchpad == CCISS_FIRMWARE_READY)
+                               return 0;
+               } else {
+                       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");
+       dev_warn(&pdev->dev, "board not ready, timed out.\n");
        return -ENODEV;
 }
 
@@ -4082,6 +4045,11 @@ static int __devinit cciss_find_cfgtables(ctlr_info_t *h)
 static void __devinit cciss_get_max_perf_mode_cmds(struct ctlr_info *h)
 {
        h->max_commands = readl(&(h->cfgtable->MaxPerformantModeCommands));
+
+       /* Limit commands in memory limited kdump scenario. */
+       if (reset_devices && h->max_commands > 32)
+               h->max_commands = 32;
+
        if (h->max_commands < 16) {
                dev_warn(&h->pdev->dev, "Controller reports "
                        "max supported commands of %d, an obvious lie. "
@@ -4199,7 +4167,7 @@ static int __devinit cciss_pci_init(ctlr_info_t *h)
                err = -ENOMEM;
                goto err_out_free_res;
        }
-       err = cciss_wait_for_board_ready(h);
+       err = cciss_wait_for_board_state(h->pdev, h->vaddr, BOARD_READY);
        if (err)
                goto err_out_free_res;
        err = cciss_find_cfgtables(h);
@@ -4364,36 +4332,6 @@ static __devinit int cciss_message(struct pci_dev *pdev, unsigned char opcode, u
 #define cciss_soft_reset_controller(p) cciss_message(p, 1, 0)
 #define cciss_noop(p) cciss_message(p, 3, 0)
 
-static __devinit int cciss_reset_msi(struct pci_dev *pdev)
-{
-/* the #defines are stolen from drivers/pci/msi.h. */
-#define msi_control_reg(base)          (base + PCI_MSI_FLAGS)
-#define PCI_MSIX_FLAGS_ENABLE          (1 << 15)
-
-       int pos;
-       u16 control = 0;
-
-       pos = pci_find_capability(pdev, PCI_CAP_ID_MSI);
-       if (pos) {
-               pci_read_config_word(pdev, msi_control_reg(pos), &control);
-               if (control & PCI_MSI_FLAGS_ENABLE) {
-                       dev_info(&pdev->dev, "resetting MSI\n");
-                       pci_write_config_word(pdev, msi_control_reg(pos), control & ~PCI_MSI_FLAGS_ENABLE);
-               }
-       }
-
-       pos = pci_find_capability(pdev, PCI_CAP_ID_MSIX);
-       if (pos) {
-               pci_read_config_word(pdev, msi_control_reg(pos), &control);
-               if (control & PCI_MSIX_FLAGS_ENABLE) {
-                       dev_info(&pdev->dev, "resetting MSI-X\n");
-                       pci_write_config_word(pdev, msi_control_reg(pos), control & ~PCI_MSIX_FLAGS_ENABLE);
-               }
-       }
-
-       return 0;
-}
-
 static int cciss_controller_hard_reset(struct pci_dev *pdev,
        void * __iomem vaddr, bool use_doorbell)
 {
@@ -4448,17 +4386,17 @@ static int cciss_controller_hard_reset(struct pci_dev *pdev,
  * 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;
+       int rc;
        CfgTable_struct __iomem *cfgtable;
        bool use_doorbell;
        u32 board_id;
+       u16 command_register;
 
        /* For controllers as old a the p600, this is very nearly
         * the same thing as
@@ -4468,14 +4406,6 @@ static __devinit int cciss_kdump_hard_reset_controller(struct pci_dev *pdev)
         * pci_set_power_state(pci_dev, PCI_D0);
         * pci_restore_state(pci_dev);
         *
-        * but we can't use these nice canned kernel routines on
-        * kexec, because they also check the MSI/MSI-X state in PCI
-        * configuration space and do the wrong thing when it is
-        * set/cleared.  Also, the pci_save/restore_state functions
-        * violate the ordering requirements for restoring the
-        * configuration space from the CCISS document (see the
-        * comment below).  So we roll our own ....
-        *
         * For controllers newer than the P600, the pci power state
         * method of resetting doesn't work so we have another way
         * using the doorbell register.
@@ -4494,8 +4424,13 @@ static __devinit int cciss_kdump_hard_reset_controller(struct pci_dev *pdev)
                return -ENODEV;
        }
 
-       for (i = 0; i < 32; i++)
-               pci_read_config_word(pdev, 2*i, &saved_config_space[i]);
+       /* Save the PCI command register */
+       pci_read_config_word(pdev, 4, &command_register);
+       /* Turn the board off.  This is so that later pci_restore_state()
+        * won't turn the board on before the rest of config space is ready.
+        */
+       pci_disable_device(pdev);
+       pci_save_state(pdev);
 
        /* find the first memory BAR, so we can find the cfg table */
        rc = cciss_pci_find_memory_BAR(pdev, &paddr);
@@ -4530,26 +4465,32 @@ static __devinit int cciss_kdump_hard_reset_controller(struct pci_dev *pdev)
        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,
-        * 16-bits at offset 06h."  Note that the offset is 2*i.
-        */
-       for (i = 0; i < 32; i++) {
-               if (i == 2 || i == 3)
-                       continue;
-               pci_write_config_word(pdev, 2*i, saved_config_space[i]);
+       pci_restore_state(pdev);
+       rc = pci_enable_device(pdev);
+       if (rc) {
+               dev_warn(&pdev->dev, "failed to enable device.\n");
+               goto unmap_cfgtable;
        }
-       wmb();
-       pci_write_config_word(pdev, 4, saved_config_space[2]);
+       pci_write_config_word(pdev, 4, command_register);
 
        /* Some devices (notably the HP Smart Array 5i Controller)
           need a little pause here */
        msleep(CCISS_POST_RESET_PAUSE_MSECS);
 
+       /* Wait for board to become not ready, then ready. */
+       dev_info(&pdev->dev, "Waiting for board to become ready.\n");
+       rc = cciss_wait_for_board_state(pdev, vaddr, BOARD_NOT_READY);
+       if (rc) /* Don't bail, might be E500, etc. which can't be reset */
+               dev_warn(&pdev->dev,
+                       "failed waiting for board to become not ready\n");
+       rc = cciss_wait_for_board_state(pdev, vaddr, BOARD_READY);
+       if (rc) {
+               dev_warn(&pdev->dev,
+                       "failed waiting for board to become ready\n");
+               goto unmap_cfgtable;
+       }
+       dev_info(&pdev->dev, "board ready.\n");
+
        /* Controller should be in simple mode at this point.  If it's not,
         * It means we're on one of those controllers which doesn't support
         * the doorbell reset method and on which the PCI power management reset
@@ -4590,8 +4531,6 @@ static __devinit int cciss_init_reset_devices(struct pci_dev *pdev)
                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++) {
@@ -4987,7 +4926,8 @@ static void __exit cciss_cleanup(void)
                }
        }
        kthread_stop(cciss_scan_thread);
-       remove_proc_entry("driver/cciss", NULL);
+       if (proc_cciss)
+               remove_proc_entry("driver/cciss", NULL);
        bus_unregister(&cciss_bus_type);
 }