#include <linux/completion.h>
#define CCISS_DRIVER_VERSION(maj,min,submin) ((maj<<16)|(min<<8)|(submin))
-#define DRIVER_NAME "HP CISS Driver (v 2.6.4)"
-#define DRIVER_VERSION CCISS_DRIVER_VERSION(2,6,4)
+#define DRIVER_NAME "HP CISS Driver (v 2.6.6)"
+#define DRIVER_VERSION CCISS_DRIVER_VERSION(2,6,6)
/* Embedded module documentation macros - see modules.h */
MODULE_AUTHOR("Hewlett-Packard Company");
-MODULE_DESCRIPTION("Driver for HP Controller SA5xxx SA6xxx version 2.6.4");
+MODULE_DESCRIPTION("Driver for HP Controller SA5xxx SA6xxx version 2.6.6");
MODULE_SUPPORTED_DEVICE("HP SA5i SA5i+ SA532 SA5300 SA5312 SA641 SA642 SA6400"
- " SA6i P600");
+ " SA6i P600 P800 E400");
MODULE_LICENSE("GPL");
#include "cciss_cmd.h"
#include <linux/cciss_ioctl.h>
/* define the PCI info for the cards we can control */
-const struct pci_device_id cciss_pci_device_id[] = {
+static const struct pci_device_id cciss_pci_device_id[] = {
{ PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISS,
0x0E11, 0x4070, 0, 0, 0},
{ PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSB,
0x0E11, 0x4091, 0, 0, 0},
{ PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSA,
0x103C, 0x3225, 0, 0, 0},
+ { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSB,
+ 0x103c, 0x3223, 0, 0, 0},
+ { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSB,
+ 0x103c, 0x3231, 0, 0, 0},
{0,}
};
MODULE_DEVICE_TABLE(pci, cciss_pci_device_id);
{ 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},
+ { 0x3231103C, "Smart Array E400", &SA5_access},
};
/* How long to wait (in millesconds) for board to go into simple mode */
#define READ_AHEAD 1024
#define NR_CMDS 384 /* #commands that can be outstanding */
-#define MAX_CTLR 8
+#define MAX_CTLR 32
+
+/* Originally cciss driver only supports 8 major numbers */
+#define MAX_CTLR_ORIG 8
+
#define CCISS_DMA_MASK 0xFFFFFFFF /* 32 bit DMA */
if (copy_from_user(cmd, buffer, count)) return -EFAULT;
cmd[count] = '\0';
len = strlen(cmd); // above 3 lines ensure safety
- if (cmd[len-1] == '\n')
+ if (len && cmd[len-1] == '\n')
cmd[--len] = '\0';
# ifdef CONFIG_CISS_SCSI_TAPE
if (strcmp("engage scsi", cmd)==0) {
drive_info_struct *drv;
int i, dir;
+ /* We call start_io here in case there is a command waiting on the
+ * queue that has not been sent.
+ */
if (blk_queue_plugged(q))
goto startio;
full:
blk_stop_queue(q);
startio:
+ /* We will already have the driver lock here so not need
+ * to lock it.
+ */
start_io(h);
}
CommandList_struct *c;
unsigned long flags;
__u32 a, a1;
-
+ int j;
+ int start_queue = h->next_to_run;
/* Is this interrupt for us? */
if (( h->access.intr_pending(h) == 0) || (h->interrupts_enabled == 0))
}
}
- /*
- * See if we can queue up some more IO
+ /* check to see if we have maxed out the number of commands that can
+ * be placed on the queue. If so then exit. We do this check here
+ * in case the interrupt we serviced was from an ioctl and did not
+ * free any new commands.
*/
- blk_start_queue(h->queue);
+ if ((find_first_zero_bit(h->cmd_pool_bits, NR_CMDS)) == NR_CMDS)
+ goto cleanup;
+
+ /* We have room on the queue for more commands. Now we need to queue
+ * them up. We will also keep track of the next queue to run so
+ * that every queue gets a chance to be started first.
+ */
+ for (j=0; j < NWD; j++){
+ int curr_queue = (start_queue + j) % NWD;
+ /* make sure the disk has been added and the drive is real
+ * because this can be called from the middle of init_one.
+ */
+ if(!(h->gendisk[curr_queue]->queue) ||
+ !(h->drv[curr_queue].heads))
+ continue;
+ blk_start_queue(h->gendisk[curr_queue]->queue);
+
+ /* 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 (curr_queue == start_queue){
+ h->next_to_run = (start_queue + 1) % NWD;
+ goto cleanup;
+ } else {
+ h->next_to_run = curr_queue;
+ goto cleanup;
+ }
+ } else {
+ curr_queue = (curr_queue + 1) % NWD;
+ }
+ }
+
+cleanup:
spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags);
return IRQ_HANDLED;
}
+
/*
* We cannot read the structure directly, for portablity we must use
* the io functions.
}
}
printk(KERN_WARNING "cciss: This driver supports a maximum"
- " of 8 controllers.\n");
+ " of %d controllers.\n", MAX_CTLR);
goto out;
Enomem:
printk(KERN_ERR "cciss: out of memory.\n");
request_queue_t *q;
int i;
int j;
+ int rc;
printk(KERN_DEBUG "cciss: Device 0x%x has been found at"
" bus %d dev %d func %d\n",
pdev->device, pdev->bus->number, PCI_SLOT(pdev->devfn),
PCI_FUNC(pdev->devfn));
i = alloc_cciss_hba();
- if( i < 0 )
+ if(i < 0)
return (-1);
if (cciss_pci_init(hba[i], pdev) != 0)
goto clean1;
goto clean1;
}
- if (register_blkdev(COMPAQ_CISS_MAJOR+i, hba[i]->devname)) {
- printk(KERN_ERR "cciss: Unable to register device %s\n",
- hba[i]->devname);
+ /*
+ * register with the major number, or get a dynamic major number
+ * by passing 0 as argument. This is done for greater than
+ * 8 controller support.
+ */
+ if (i < MAX_CTLR_ORIG)
+ hba[i]->major = MAJOR_NR + i;
+ rc = register_blkdev(hba[i]->major, hba[i]->devname);
+ 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);
goto clean1;
}
+ else {
+ if (i >= MAX_CTLR_ORIG)
+ hba[i]->major = rc;
+ }
/* make sure the board interrupts are off */
hba[i]->access.set_intr_mask(hba[i], CCISS_INTR_OFF);
sprintf(disk->disk_name, "cciss/c%dd%d", i, j);
sprintf(disk->devfs_name, "cciss/host%d/target%d", i, j);
- disk->major = COMPAQ_CISS_MAJOR + i;
+ disk->major = hba[i]->major;
disk->first_minor = j << NWD_SHIFT;
disk->fops = &cciss_fops;
disk->queue = hba[i]->queue;
hba[i]->errinfo_pool_dhandle);
free_irq(hba[i]->intr, hba[i]);
clean2:
- unregister_blkdev(COMPAQ_CISS_MAJOR+i, hba[i]->devname);
+ unregister_blkdev(hba[i]->major, hba[i]->devname);
clean1:
release_io_mem(hba[i]);
free_hba(i);
pci_set_drvdata(pdev, NULL);
iounmap(hba[i]->vaddr);
cciss_unregister_scsi(i); /* unhook from SCSI subsystem */
- unregister_blkdev(COMPAQ_CISS_MAJOR+i, hba[i]->devname);
+ unregister_blkdev(hba[i]->major, hba[i]->devname);
remove_proc_entry(hba[i]->devname, proc_cciss);
/* remove it from the disk list */
* This is it. Register the PCI driver information for the cards we control
* the OS will call our registered routines when it finds one of our cards.
*/
-int __init cciss_init(void)
+static int __init cciss_init(void)
{
printk(KERN_INFO DRIVER_NAME "\n");
return pci_module_init(&cciss_pci_driver);
}
-static int __init init_cciss_module(void)
-{
- return ( cciss_init());
-}
-
-static void __exit cleanup_cciss_module(void)
+static void __exit cciss_cleanup(void)
{
int i;
remove_proc_entry("cciss", proc_root_driver);
}
-module_init(init_cciss_module);
-module_exit(cleanup_cciss_module);
+module_init(cciss_init);
+module_exit(cciss_cleanup);