X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fblock%2Fcciss.c;h=967c0f31edeade9a2986ccfeffe64ff3e1120db9;hb=6a77f38946aaee1cd85eeec6cf4229b204c15071;hp=5509e56208afa55dffbd973ad8e9c659baaac327;hpb=9bf4aaab3e101692164d49b7ca357651eb691cb6;p=linux-2.6.git diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index 5509e5620..967c0f31e 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -16,7 +16,7 @@ * 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 * */ @@ -46,14 +46,14 @@ #include #define CCISS_DRIVER_VERSION(maj,min,submin) ((maj<<16)|(min<<8)|(submin)) -#define DRIVER_NAME "Compaq CISS Driver (v 2.6.2)" -#define DRIVER_VERSION CCISS_DRIVER_VERSION(2,6,2) +#define DRIVER_NAME "HP CISS Driver (v 2.6.4)" +#define DRIVER_VERSION CCISS_DRIVER_VERSION(2,6,4) /* Embedded module documentation macros - see modules.h */ MODULE_AUTHOR("Hewlett-Packard Company"); -MODULE_DESCRIPTION("Driver for HP Controller SA5xxx SA6xxx version 2.6.2"); +MODULE_DESCRIPTION("Driver for HP Controller SA5xxx SA6xxx version 2.6.4"); MODULE_SUPPORTED_DEVICE("HP SA5i SA5i+ SA532 SA5300 SA5312 SA641 SA642 SA6400" - " SA6i"); + " SA6i P600"); MODULE_LICENSE("GPL"); #include "cciss_cmd.h" @@ -80,10 +80,8 @@ const struct pci_device_id cciss_pci_device_id[] = { 0x0E11, 0x409D, 0, 0, 0}, { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSC, 0x0E11, 0x4091, 0, 0, 0}, - { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSC, - 0x0E11, 0x409E, 0, 0, 0}, - { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSC, - 0x103C, 0x3211, 0, 0, 0}, + { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSA, + 0x103C, 0x3225, 0, 0, 0}, {0,} }; MODULE_DEVICE_TABLE(pci, cciss_pci_device_id); @@ -104,8 +102,7 @@ static struct board_type products[] = { { 0x409C0E11, "Smart Array 6400", &SA5_access}, { 0x409D0E11, "Smart Array 6400 EM", &SA5_access}, { 0x40910E11, "Smart Array 6i", &SA5_access}, - { 0x409E0E11, "Smart Array 6422", &SA5_access}, - { 0x3211103C, "Smart Array V100", &SA5_access}, + { 0x3225103C, "Smart Array P600", &SA5_access}, }; /* How long to wait (in millesconds) for board to go into simple mode */ @@ -115,7 +112,7 @@ static struct board_type products[] = { /*define how many times we will try a command because of bus resets */ #define MAX_CMD_RETRIES 3 -#define READ_AHEAD 256 +#define READ_AHEAD 1024 #define NR_CMDS 384 /* #commands that can be outstanding */ #define MAX_CTLR 8 @@ -149,11 +146,18 @@ static void cciss_procinit(int i); 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, }; @@ -185,17 +189,18 @@ static inline CommandList_struct *removeQ(CommandList_struct **Qptr, } return c; } -#ifdef CONFIG_PROC_FS #include "cciss_scsi.c" /* For SCSI tape support */ +#ifdef CONFIG_PROC_FS + /* * Report information about this controller. */ -#define ENG_GIG 1048576000 +#define ENG_GIG 1000000000 #define ENG_GIG_FACTOR (ENG_GIG/512) #define RAID_UNKNOWN 6 -static const char *raid_label[] = {"0","4","1(0+1)","5","5+1","ADG", +static const char *raid_label[] = {"0","4","1(1+0)","5","5+1","ADG", "UNKNOWN"}; static struct proc_dir_entry *proc_cciss; @@ -209,7 +214,7 @@ static int cciss_proc_get_info(char *buffer, char **start, off_t offset, ctlr_info_t *h = (ctlr_info_t*)data; drive_info_struct *drv; unsigned long flags; - unsigned int vol_sz, vol_sz_frac; + sector_t vol_sz, vol_sz_frac; ctlr = h->ctlr; @@ -246,32 +251,21 @@ static int cciss_proc_get_info(char *buffer, char **start, off_t offset, pos += size; len += size; cciss_proc_tape_report(ctlr, buffer, &pos, &len); for(i=0; i<=h->highest_lun; i++) { - sector_t tmp; drv = &h->drv[i]; if (drv->block_size == 0) continue; - vol_sz = drv->nr_blocks; - sector_div(vol_sz, ENG_GIG_FACTOR); - - /* - * Awkwardly do this: - * vol_sz_frac = - * (drv->nr_blocks%ENG_GIG_FACTOR)*100/ENG_GIG_FACTOR; - */ - tmp = drv->nr_blocks; - vol_sz_frac = sector_div(tmp, ENG_GIG_FACTOR); - - /* Now, vol_sz_frac = (drv->nr_blocks%ENG_GIG_FACTOR) */ + vol_sz = drv->nr_blocks; + vol_sz_frac = sector_div(vol_sz, ENG_GIG_FACTOR); vol_sz_frac *= 100; sector_div(vol_sz_frac, ENG_GIG_FACTOR); if (drv->raid_level > 5) drv->raid_level = RAID_UNKNOWN; size = sprintf(buffer+len, "cciss/c%dd%d:" - "\t%4d.%02dGB\tRAID %s\n", - ctlr, i, vol_sz,vol_sz_frac, + "\t%4u.%02uGB\tRAID %s\n", + ctlr, i, (int)vol_sz, (int)vol_sz_frac, raid_label[drv->raid_level]); pos += size; len += size; } @@ -449,13 +443,22 @@ static int cciss_open(struct inode *inode, struct file *filep) /* * Root is allowed to open raw volume zero even if it's not configured - * so array config can still work. I don't think I really like this, + * so array config can still work. Root is also allowed to open any + * volume that has a LUN ID, so it can issue IOCTL to reread the + * disk information. I don't think I really like this * but I'm already using way to many device nodes to claim another one * for "raw controller". */ if (drv->nr_blocks == 0) { - if (iminor(inode) != 0) + if (iminor(inode) != 0) { /* not node 0? */ + /* if not node 0 make sure it is a partition = 0 */ + if (iminor(inode) & 0x0f) { return -ENXIO; + /* if it is, make sure we have a LUN ID */ + } else if (drv->LunID == 0) { + return -ENXIO; + } + } if (!capable(CAP_SYS_ADMIN)) return -EPERM; } @@ -481,80 +484,50 @@ static int cciss_release(struct inode *inode, struct file *filep) } #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; @@ -575,17 +548,16 @@ int cciss_ioctl32_passthru(unsigned int fd, unsigned cmd, unsigned long 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)); + err |= copy_in_user(&arg32->error_info, &p->error_info, sizeof(arg32->error_info)); if (err) return -EFAULT; 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; @@ -607,17 +579,14 @@ int cciss_ioctl32_big_passthru(unsigned int fd, unsigned cmd, unsigned long 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)); + err |= copy_in_user(&arg32->error_info, &p->error_info, sizeof(arg32->error_info)); if (err) return -EFAULT; return err; } -#else -static inline void register_cciss_ioctl32(void) {} -static inline void unregister_cciss_ioctl32(void) {} #endif /* * ioctl @@ -810,7 +779,7 @@ static int cciss_ioctl(struct inode *inode, struct file *filep, luninfo.num_opens = drv->usage_count; luninfo.num_parts = 0; /* count partitions 1 to 15 with sizes > 0 */ - for(i=1; i part[i]) continue; if (disk->part[i]->nr_sects != 0) @@ -866,6 +835,8 @@ static int cciss_ioctl(struct inode *inode, struct file *filep, kfree(buff); return -EFAULT; } + } else { + memset(buff, 0, iocommand.buf_size); } if ((c = cmd_alloc(host , 0)) == NULL) { @@ -1012,6 +983,8 @@ static int cciss_ioctl(struct inode *inode, struct file *filep, copy_from_user(buff[sg_used], data_ptr, sz)) { status = -ENOMEM; goto cleanup1; + } else { + memset(buff[sg_used], 0, sz); } left -= sz; data_ptr += sz; @@ -1097,18 +1070,11 @@ cleanup1: return(status); } default: - return -EBADRQC; + return -ENOTTY; } } -static int cciss_revalidate(struct gendisk *disk) -{ - drive_info_struct *drv = disk->private_data; - set_capacity(disk, drv->nr_blocks); - return 0; -} - /* * revalidate_allvol is for online array config utilities. After a * utility reconfigures the drives in the array, it can use this function @@ -1160,7 +1126,9 @@ static int revalidate_allvol(ctlr_info_t *host) for (i = 0; i < NWD; i++) { struct gendisk *disk = host->gendisk[i]; drive_info_struct *drv = &(host->drv[i]); - if (!drv->nr_blocks) + /* we must register the controller even if no disks exist */ + /* this is for the online array utilities */ + if (!drv->heads && i) continue; blk_queue_hardsect_size(host->queue, drv->block_size); set_capacity(disk, drv->nr_blocks); @@ -1477,21 +1445,22 @@ static void cciss_geometry_inquiry(int ctlr, int logvol, 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; + } } } else { /* Get geometry failed */ - printk(KERN_WARNING "cciss: reading geometry failed, " - "continuing with default 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; + printk(KERN_WARNING "cciss: reading geometry failed\n"); } printk(KERN_INFO " heads= %d, sectors= %d, cylinders= %d\n\n", drv->heads, drv->sectors, drv->cylinders); @@ -1509,8 +1478,8 @@ cciss_read_capacity(int ctlr, int logvol, ReadCapdata_struct *buf, return_code = sendcmd(CCISS_READ_CAPACITY, ctlr, buf, sizeof(*buf), 1, logvol, 0, NULL, TYPE_CMD); if (return_code == IO_OK) { - *total_size = be32_to_cpu(*((__u32 *) &buf->total_size[0]))+1; - *block_size = be32_to_cpu(*((__u32 *) &buf->block_size[0])); + *total_size = be32_to_cpu(*((__be32 *) &buf->total_size[0]))+1; + *block_size = be32_to_cpu(*((__be32 *) &buf->block_size[0])); } else { /* read capacity command failed */ printk(KERN_WARNING "cciss: read capacity failed\n"); *total_size = 0; @@ -1520,6 +1489,7 @@ cciss_read_capacity(int ctlr, int logvol, ReadCapdata_struct *buf, *total_size, *block_size); return; } + static int register_new_disk(ctlr_info_t *h) { struct gendisk *disk; @@ -1663,7 +1633,9 @@ static int register_new_disk(ctlr_info_t *h) /* setup partitions per disk */ disk = h->gendisk[logvol]; set_capacity(disk, h->drv[logvol].nr_blocks); - add_disk(disk); + /* if it's the controller it's already added */ + if(logvol) + add_disk(disk); freeret: kfree(ld_buff); kfree(size_buff); @@ -1675,6 +1647,53 @@ free_err: logvol = -1; goto freeret; } + +static int cciss_revalidate(struct gendisk *disk) +{ + ctlr_info_t *h = get_host(disk); + drive_info_struct *drv = get_drv(disk); + int logvol; + int FOUND=0; + unsigned int block_size; + unsigned int total_size; + ReadCapdata_struct *size_buff = NULL; + InquiryData_struct *inq_buff = NULL; + + for(logvol=0; logvol < CISS_MAX_LUN; logvol++) + { + if(h->drv[logvol].LunID == drv->LunID) { + FOUND=1; + break; + } + } + + 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); + cciss_geometry_inquiry(h->ctlr, logvol, 1, total_size, block_size, inq_buff, drv); + + blk_queue_hardsect_size(h->queue, drv->block_size); + set_capacity(disk, drv->nr_blocks); + + kfree(size_buff); + kfree(inq_buff); + return 0; +} + /* * Wait polling for a command to complete. * The memory mapped FIFO is polled for the completion. @@ -1844,13 +1863,13 @@ cleanup1: /* * Map (physical) PCI mem into (virtual) kernel space */ -static ulong remap_pci_mem(ulong base, ulong size) +static void __iomem *remap_pci_mem(ulong base, ulong size) { ulong page_base = ((ulong) base) & PAGE_MASK; ulong page_offs = ((ulong) base) - page_base; - ulong page_remapped = (ulong) ioremap(page_base, page_offs+size); + void __iomem *page_remapped = ioremap(page_base, page_offs+size); - return (ulong) (page_remapped ? (page_remapped + page_offs) : 0UL); + return page_remapped ? (page_remapped + page_offs) : NULL; } /* @@ -2300,7 +2319,6 @@ static int find_PCI_BAR_index(struct pci_dev *pdev, static int cciss_pci_init(ctlr_info_t *c, struct pci_dev *pdev) { ushort subsystem_vendor_id, subsystem_device_id, command; - unchar irq = pdev->irq; __u32 board_id, scratchpad = 0; __u64 cfg_offset; __u32 cfg_base_addr; @@ -2359,11 +2377,11 @@ static int cciss_pci_init(ctlr_info_t *c, struct pci_dev *pdev) #ifdef CCISS_DEBUG printk("command = %x\n", command); - printk("irq = %x\n", irq); + printk("irq = %x\n", pdev->irq); printk("board_id = %x\n", board_id); #endif /* CCISS_DEBUG */ - c->intr = irq; + c->intr = pdev->irq; /* * Memory base addr is first addr , the second points to the config @@ -2411,9 +2429,9 @@ static int cciss_pci_init(ctlr_info_t *c, struct pci_dev *pdev) #ifdef CCISS_DEBUG printk("cfg offset = %x\n", cfg_offset); #endif /* CCISS_DEBUG */ - c->cfgtable = (CfgTable_struct *) - remap_pci_mem(pci_resource_start(pdev, cfg_base_addr_index) - + cfg_offset, sizeof(CfgTable_struct)); + c->cfgtable = remap_pci_mem(pci_resource_start(pdev, + cfg_base_addr_index) + cfg_offset, + sizeof(CfgTable_struct)); c->board_id = board_id; #ifdef CCISS_DEBUG @@ -2763,7 +2781,9 @@ static int __devinit cciss_init_one(struct pci_dev *pdev, disk->fops = &cciss_fops; disk->queue = hba[i]->queue; disk->private_data = drv; - if( !(drv->nr_blocks)) + /* we must register the controller even if no disks exist */ + /* this is for the online array utilities */ + if(!drv->heads && j) continue; blk_queue_hardsect_size(hba[i]->queue, drv->block_size); set_capacity(disk, drv->nr_blocks); @@ -2825,7 +2845,7 @@ static void __devexit cciss_remove_one (struct pci_dev *pdev) } free_irq(hba[i]->intr, hba[i]); pci_set_drvdata(pdev, NULL); - iounmap((void*)hba[i]->vaddr); + iounmap(hba[i]->vaddr); cciss_unregister_scsi(i); /* unhook from SCSI subsystem */ unregister_blkdev(COMPAQ_CISS_MAJOR+i, hba[i]->devname); remove_proc_entry(hba[i]->devname, proc_cciss); @@ -2868,7 +2888,6 @@ int __init cciss_init(void) static int __init init_cciss_module(void) { - register_cciss_ioctl32(); return ( cciss_init()); } @@ -2876,7 +2895,6 @@ static void __exit cleanup_cciss_module(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++)