* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
- * Questions/Comments/Bugfixes to Cciss-discuss@lists.sourceforge.net
+ * Questions/Comments/Bugfixes to iss_storagedev@hp.com
*
*/
#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_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_VERSION("2.6.6");
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 */
static void cciss_procinit(int i) {}
#endif /* CONFIG_PROC_FS */
+#ifdef CONFIG_COMPAT
+static long cciss_compat_ioctl(struct file *f, unsigned cmd, unsigned long arg);
+#endif
+
static struct block_device_operations cciss_fops = {
.owner = THIS_MODULE,
.open = cciss_open,
.release = cciss_release,
.ioctl = cciss_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = cciss_compat_ioctl,
+#endif
.revalidate_disk= cciss_revalidate,
};
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) {
}
#ifdef CONFIG_COMPAT
-/* for AMD 64 bit kernel compatibility with 32-bit userland ioctls */
-extern long sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg);
-extern int
-register_ioctl32_conversion(unsigned int cmd, int (*handler)(unsigned int,
- unsigned int, unsigned long, struct file *));
-extern int unregister_ioctl32_conversion(unsigned int cmd);
-
-static int cciss_ioctl32_passthru(unsigned int fd, unsigned cmd, unsigned long arg, struct file *file);
-static int cciss_ioctl32_big_passthru(unsigned int fd, unsigned cmd, unsigned long arg,
- struct file *file);
-
-typedef int (*handler_type) (unsigned int, unsigned int, unsigned long, struct file *);
-
-static struct ioctl32_map {
- unsigned int cmd;
- handler_type handler;
- int registered;
-} cciss_ioctl32_map[] = {
- { CCISS_GETPCIINFO, (handler_type) sys_ioctl, 0 },
- { CCISS_GETINTINFO, (handler_type) sys_ioctl, 0 },
- { CCISS_SETINTINFO, (handler_type) sys_ioctl, 0 },
- { CCISS_GETNODENAME, (handler_type) sys_ioctl, 0 },
- { CCISS_SETNODENAME, (handler_type) sys_ioctl, 0 },
- { CCISS_GETHEARTBEAT, (handler_type) sys_ioctl, 0 },
- { CCISS_GETBUSTYPES, (handler_type) sys_ioctl, 0 },
- { CCISS_GETFIRMVER, (handler_type) sys_ioctl, 0 },
- { CCISS_GETDRIVVER, (handler_type) sys_ioctl, 0 },
- { CCISS_REVALIDVOLS, (handler_type) sys_ioctl, 0 },
- { CCISS_PASSTHRU32, cciss_ioctl32_passthru, 0 },
- { CCISS_DEREGDISK, (handler_type) sys_ioctl, 0 },
- { CCISS_REGNEWDISK, (handler_type) sys_ioctl, 0 },
- { CCISS_REGNEWD, (handler_type) sys_ioctl, 0 },
- { CCISS_RESCANDISK, (handler_type) sys_ioctl, 0 },
- { CCISS_GETLUNINFO, (handler_type) sys_ioctl, 0 },
- { CCISS_BIG_PASSTHRU32, cciss_ioctl32_big_passthru, 0 },
-};
-#define NCCISS_IOCTL32_ENTRIES (sizeof(cciss_ioctl32_map) / sizeof(cciss_ioctl32_map[0]))
-static void register_cciss_ioctl32(void)
+
+static int do_ioctl(struct file *f, unsigned cmd, unsigned long arg)
{
- int i, rc;
-
- for (i=0; i < NCCISS_IOCTL32_ENTRIES; i++) {
- rc = register_ioctl32_conversion(
- cciss_ioctl32_map[i].cmd,
- cciss_ioctl32_map[i].handler);
- if (rc != 0) {
- printk(KERN_WARNING "cciss: failed to register "
- "32 bit compatible ioctl 0x%08x\n",
- cciss_ioctl32_map[i].cmd);
- cciss_ioctl32_map[i].registered = 0;
- } else
- cciss_ioctl32_map[i].registered = 1;
- }
+ int ret;
+ lock_kernel();
+ ret = cciss_ioctl(f->f_dentry->d_inode, f, cmd, arg);
+ unlock_kernel();
+ return ret;
}
-static void unregister_cciss_ioctl32(void)
+
+static int cciss_ioctl32_passthru(struct file *f, unsigned cmd, unsigned long arg);
+static int cciss_ioctl32_big_passthru(struct file *f, unsigned cmd, unsigned long arg);
+
+static long cciss_compat_ioctl(struct file *f, unsigned cmd, unsigned long arg)
{
- int i, rc;
+ switch (cmd) {
+ case CCISS_GETPCIINFO:
+ case CCISS_GETINTINFO:
+ case CCISS_SETINTINFO:
+ case CCISS_GETNODENAME:
+ case CCISS_SETNODENAME:
+ case CCISS_GETHEARTBEAT:
+ case CCISS_GETBUSTYPES:
+ case CCISS_GETFIRMVER:
+ case CCISS_GETDRIVVER:
+ case CCISS_REVALIDVOLS:
+ case CCISS_DEREGDISK:
+ case CCISS_REGNEWDISK:
+ case CCISS_REGNEWD:
+ case CCISS_RESCANDISK:
+ case CCISS_GETLUNINFO:
+ return do_ioctl(f, cmd, arg);
- for (i=0; i < NCCISS_IOCTL32_ENTRIES; i++) {
- if (!cciss_ioctl32_map[i].registered)
- continue;
- rc = unregister_ioctl32_conversion(
- cciss_ioctl32_map[i].cmd);
- if (rc == 0) {
- cciss_ioctl32_map[i].registered = 0;
- continue;
- }
- printk(KERN_WARNING "cciss: failed to unregister "
- "32 bit compatible ioctl 0x%08x\n",
- cciss_ioctl32_map[i].cmd);
+ case CCISS_PASSTHRU32:
+ return cciss_ioctl32_passthru(f, cmd, arg);
+ case CCISS_BIG_PASSTHRU32:
+ return cciss_ioctl32_big_passthru(f, cmd, arg);
+
+ default:
+ return -ENOIOCTLCMD;
}
}
-int cciss_ioctl32_passthru(unsigned int fd, unsigned cmd, unsigned long arg,
- struct file *file)
+
+static int cciss_ioctl32_passthru(struct file *f, unsigned cmd, unsigned long arg)
{
IOCTL32_Command_struct __user *arg32 =
(IOCTL32_Command_struct __user *) arg;
if (err)
return -EFAULT;
- err = sys_ioctl(fd, CCISS_PASSTHRU, (unsigned long) p);
+ err = do_ioctl(f, CCISS_PASSTHRU, (unsigned long) p);
if (err)
return err;
err |= copy_in_user(&arg32->error_info, &p->error_info, sizeof(arg32->error_info));
return err;
}
-int cciss_ioctl32_big_passthru(unsigned int fd, unsigned cmd, unsigned long arg,
- struct file *file)
+static int cciss_ioctl32_big_passthru(struct file *file, unsigned cmd, unsigned long arg)
{
BIG_IOCTL32_Command_struct __user *arg32 =
(BIG_IOCTL32_Command_struct __user *) arg;
if (err)
return -EFAULT;
- err = sys_ioctl(fd, CCISS_BIG_PASSTHRU, (unsigned long) p);
+ err = do_ioctl(file, CCISS_BIG_PASSTHRU, (unsigned long) p);
if (err)
return err;
err |= copy_in_user(&arg32->error_info, &p->error_info, sizeof(arg32->error_info));
return -EFAULT;
return err;
}
-#else
-static inline void register_cciss_ioctl32(void) {}
-static inline void unregister_cciss_ioctl32(void) {}
#endif
/*
* ioctl
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)
-{
- register_cciss_ioctl32();
- return ( cciss_init());
-}
-
-static void __exit cleanup_cciss_module(void)
+static void __exit cciss_cleanup(void)
{
int i;
- unregister_cciss_ioctl32();
pci_unregister_driver(&cciss_pci_driver);
/* double check that all controller entrys have been removed */
for (i=0; i< MAX_CTLR; 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);