diff options
author | Russell King <rmk@dyn-67.arm.linux.org.uk> | 2006-01-09 14:18:33 -0500 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2006-01-09 14:18:33 -0500 |
commit | 0a3a98f6dd4e8f4d928a09302c0d1c56f2192ac3 (patch) | |
tree | 92f55e374a84d06ce8213a4540454760fdecf137 /drivers/block/cciss.c | |
parent | 8ef12c9f01afba47c2d33bb939085111ca0d0f7d (diff) | |
parent | 5367f2d67c7d0bf1faae90e6e7b4e2ac3c9b5e0f (diff) |
Merge Linus' tree.
Diffstat (limited to 'drivers/block/cciss.c')
-rw-r--r-- | drivers/block/cciss.c | 124 |
1 files changed, 95 insertions, 29 deletions
diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index d2815b7a9150..88452c79fb64 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * Disk Array driver for HP SA 5xxx and 6xxx Controllers | 2 | * Disk Array driver for HP SA 5xxx and 6xxx Controllers |
3 | * Copyright 2000, 2005 Hewlett-Packard Development Company, L.P. | 3 | * Copyright 2000, 2006 Hewlett-Packard Development Company, L.P. |
4 | * | 4 | * |
5 | * This program is free software; you can redistribute it and/or modify | 5 | * This program is free software; you can redistribute it and/or modify |
6 | * it under the terms of the GNU General Public License as published by | 6 | * it under the terms of the GNU General Public License as published by |
@@ -47,12 +47,12 @@ | |||
47 | #include <linux/completion.h> | 47 | #include <linux/completion.h> |
48 | 48 | ||
49 | #define CCISS_DRIVER_VERSION(maj,min,submin) ((maj<<16)|(min<<8)|(submin)) | 49 | #define CCISS_DRIVER_VERSION(maj,min,submin) ((maj<<16)|(min<<8)|(submin)) |
50 | #define DRIVER_NAME "HP CISS Driver (v 2.6.8)" | 50 | #define DRIVER_NAME "HP CISS Driver (v 2.6.10)" |
51 | #define DRIVER_VERSION CCISS_DRIVER_VERSION(2,6,8) | 51 | #define DRIVER_VERSION CCISS_DRIVER_VERSION(2,6,10) |
52 | 52 | ||
53 | /* Embedded module documentation macros - see modules.h */ | 53 | /* Embedded module documentation macros - see modules.h */ |
54 | MODULE_AUTHOR("Hewlett-Packard Company"); | 54 | MODULE_AUTHOR("Hewlett-Packard Company"); |
55 | MODULE_DESCRIPTION("Driver for HP Controller SA5xxx SA6xxx version 2.6.8"); | 55 | MODULE_DESCRIPTION("Driver for HP Controller SA5xxx SA6xxx version 2.6.10"); |
56 | MODULE_SUPPORTED_DEVICE("HP SA5i SA5i+ SA532 SA5300 SA5312 SA641 SA642 SA6400" | 56 | MODULE_SUPPORTED_DEVICE("HP SA5i SA5i+ SA532 SA5300 SA5312 SA641 SA642 SA6400" |
57 | " SA6i P600 P800 P400 P400i E200 E200i"); | 57 | " SA6i P600 P800 P400 P400i E200 E200i"); |
58 | MODULE_LICENSE("GPL"); | 58 | MODULE_LICENSE("GPL"); |
@@ -103,7 +103,7 @@ static const struct pci_device_id cciss_pci_device_id[] = { | |||
103 | }; | 103 | }; |
104 | MODULE_DEVICE_TABLE(pci, cciss_pci_device_id); | 104 | MODULE_DEVICE_TABLE(pci, cciss_pci_device_id); |
105 | 105 | ||
106 | #define NR_PRODUCTS (sizeof(products)/sizeof(struct board_type)) | 106 | #define NR_PRODUCTS ARRAY_SIZE(products) |
107 | 107 | ||
108 | /* board_id = Subsystem Device ID & Vendor ID | 108 | /* board_id = Subsystem Device ID & Vendor ID |
109 | * product = Marketing Name for the board | 109 | * product = Marketing Name for the board |
@@ -153,6 +153,7 @@ static int cciss_open(struct inode *inode, struct file *filep); | |||
153 | static int cciss_release(struct inode *inode, struct file *filep); | 153 | static int cciss_release(struct inode *inode, struct file *filep); |
154 | static int cciss_ioctl(struct inode *inode, struct file *filep, | 154 | static int cciss_ioctl(struct inode *inode, struct file *filep, |
155 | unsigned int cmd, unsigned long arg); | 155 | unsigned int cmd, unsigned long arg); |
156 | static int cciss_getgeo(struct block_device *bdev, struct hd_geometry *geo); | ||
156 | 157 | ||
157 | static int revalidate_allvol(ctlr_info_t *host); | 158 | static int revalidate_allvol(ctlr_info_t *host); |
158 | static int cciss_revalidate(struct gendisk *disk); | 159 | static int cciss_revalidate(struct gendisk *disk); |
@@ -166,7 +167,7 @@ static void cciss_geometry_inquiry(int ctlr, int logvol, | |||
166 | unsigned int block_size, InquiryData_struct *inq_buff, | 167 | unsigned int block_size, InquiryData_struct *inq_buff, |
167 | drive_info_struct *drv); | 168 | drive_info_struct *drv); |
168 | static void cciss_getgeometry(int cntl_num); | 169 | static void cciss_getgeometry(int cntl_num); |
169 | 170 | static void __devinit cciss_interrupt_mode(ctlr_info_t *, struct pci_dev *, __u32); | |
170 | static void start_io( ctlr_info_t *h); | 171 | static void start_io( ctlr_info_t *h); |
171 | static int sendcmd( __u8 cmd, int ctlr, void *buff, size_t size, | 172 | static int sendcmd( __u8 cmd, int ctlr, void *buff, size_t size, |
172 | unsigned int use_unit_num, unsigned int log_unit, __u8 page_code, | 173 | unsigned int use_unit_num, unsigned int log_unit, __u8 page_code, |
@@ -194,6 +195,7 @@ static struct block_device_operations cciss_fops = { | |||
194 | .open = cciss_open, | 195 | .open = cciss_open, |
195 | .release = cciss_release, | 196 | .release = cciss_release, |
196 | .ioctl = cciss_ioctl, | 197 | .ioctl = cciss_ioctl, |
198 | .getgeo = cciss_getgeo, | ||
197 | #ifdef CONFIG_COMPAT | 199 | #ifdef CONFIG_COMPAT |
198 | .compat_ioctl = cciss_compat_ioctl, | 200 | .compat_ioctl = cciss_compat_ioctl, |
199 | #endif | 201 | #endif |
@@ -282,7 +284,7 @@ static int cciss_proc_get_info(char *buffer, char **start, off_t offset, | |||
282 | h->product_name, | 284 | h->product_name, |
283 | (unsigned long)h->board_id, | 285 | (unsigned long)h->board_id, |
284 | h->firm_ver[0], h->firm_ver[1], h->firm_ver[2], h->firm_ver[3], | 286 | h->firm_ver[0], h->firm_ver[1], h->firm_ver[2], h->firm_ver[3], |
285 | (unsigned int)h->intr, | 287 | (unsigned int)h->intr[SIMPLE_MODE_INT], |
286 | h->num_luns, | 288 | h->num_luns, |
287 | h->Qdepth, h->commands_outstanding, | 289 | h->Qdepth, h->commands_outstanding, |
288 | h->maxQsinceinit, h->max_outstanding, h->maxSG); | 290 | h->maxQsinceinit, h->max_outstanding, h->maxSG); |
@@ -633,6 +635,20 @@ static int cciss_ioctl32_big_passthru(struct file *file, unsigned cmd, unsigned | |||
633 | return err; | 635 | return err; |
634 | } | 636 | } |
635 | #endif | 637 | #endif |
638 | |||
639 | static int cciss_getgeo(struct block_device *bdev, struct hd_geometry *geo) | ||
640 | { | ||
641 | drive_info_struct *drv = get_drv(bdev->bd_disk); | ||
642 | |||
643 | if (!drv->cylinders) | ||
644 | return -ENXIO; | ||
645 | |||
646 | geo->heads = drv->heads; | ||
647 | geo->sectors = drv->sectors; | ||
648 | geo->cylinders = drv->cylinders; | ||
649 | return 0; | ||
650 | } | ||
651 | |||
636 | /* | 652 | /* |
637 | * ioctl | 653 | * ioctl |
638 | */ | 654 | */ |
@@ -651,21 +667,6 @@ static int cciss_ioctl(struct inode *inode, struct file *filep, | |||
651 | #endif /* CCISS_DEBUG */ | 667 | #endif /* CCISS_DEBUG */ |
652 | 668 | ||
653 | switch(cmd) { | 669 | switch(cmd) { |
654 | case HDIO_GETGEO: | ||
655 | { | ||
656 | struct hd_geometry driver_geo; | ||
657 | if (drv->cylinders) { | ||
658 | driver_geo.heads = drv->heads; | ||
659 | driver_geo.sectors = drv->sectors; | ||
660 | driver_geo.cylinders = drv->cylinders; | ||
661 | } else | ||
662 | return -ENXIO; | ||
663 | driver_geo.start= get_start_sect(inode->i_bdev); | ||
664 | if (copy_to_user(argp, &driver_geo, sizeof(struct hd_geometry))) | ||
665 | return -EFAULT; | ||
666 | return(0); | ||
667 | } | ||
668 | |||
669 | case CCISS_GETPCIINFO: | 670 | case CCISS_GETPCIINFO: |
670 | { | 671 | { |
671 | cciss_pci_info_struct pciinfo; | 672 | cciss_pci_info_struct pciinfo; |
@@ -2661,6 +2662,60 @@ static int find_PCI_BAR_index(struct pci_dev *pdev, | |||
2661 | return -1; | 2662 | return -1; |
2662 | } | 2663 | } |
2663 | 2664 | ||
2665 | /* If MSI/MSI-X is supported by the kernel we will try to enable it on | ||
2666 | * controllers that are capable. If not, we use IO-APIC mode. | ||
2667 | */ | ||
2668 | |||
2669 | static void __devinit cciss_interrupt_mode(ctlr_info_t *c, struct pci_dev *pdev, __u32 board_id) | ||
2670 | { | ||
2671 | #ifdef CONFIG_PCI_MSI | ||
2672 | int err; | ||
2673 | struct msix_entry cciss_msix_entries[4] = {{0,0}, {0,1}, | ||
2674 | {0,2}, {0,3}}; | ||
2675 | |||
2676 | /* Some boards advertise MSI but don't really support it */ | ||
2677 | if ((board_id == 0x40700E11) || | ||
2678 | (board_id == 0x40800E11) || | ||
2679 | (board_id == 0x40820E11) || | ||
2680 | (board_id == 0x40830E11)) | ||
2681 | goto default_int_mode; | ||
2682 | |||
2683 | if (pci_find_capability(pdev, PCI_CAP_ID_MSIX)) { | ||
2684 | err = pci_enable_msix(pdev, cciss_msix_entries, 4); | ||
2685 | if (!err) { | ||
2686 | c->intr[0] = cciss_msix_entries[0].vector; | ||
2687 | c->intr[1] = cciss_msix_entries[1].vector; | ||
2688 | c->intr[2] = cciss_msix_entries[2].vector; | ||
2689 | c->intr[3] = cciss_msix_entries[3].vector; | ||
2690 | c->msix_vector = 1; | ||
2691 | return; | ||
2692 | } | ||
2693 | if (err > 0) { | ||
2694 | printk(KERN_WARNING "cciss: only %d MSI-X vectors " | ||
2695 | "available\n", err); | ||
2696 | } else { | ||
2697 | printk(KERN_WARNING "cciss: MSI-X init failed %d\n", | ||
2698 | err); | ||
2699 | } | ||
2700 | } | ||
2701 | if (pci_find_capability(pdev, PCI_CAP_ID_MSI)) { | ||
2702 | if (!pci_enable_msi(pdev)) { | ||
2703 | c->intr[SIMPLE_MODE_INT] = pdev->irq; | ||
2704 | c->msi_vector = 1; | ||
2705 | return; | ||
2706 | } else { | ||
2707 | printk(KERN_WARNING "cciss: MSI init failed\n"); | ||
2708 | c->intr[SIMPLE_MODE_INT] = pdev->irq; | ||
2709 | return; | ||
2710 | } | ||
2711 | } | ||
2712 | #endif /* CONFIG_PCI_MSI */ | ||
2713 | /* if we get here we're going to use the default interrupt mode */ | ||
2714 | default_int_mode: | ||
2715 | c->intr[SIMPLE_MODE_INT] = pdev->irq; | ||
2716 | return; | ||
2717 | } | ||
2718 | |||
2664 | static int cciss_pci_init(ctlr_info_t *c, struct pci_dev *pdev) | 2719 | static int cciss_pci_init(ctlr_info_t *c, struct pci_dev *pdev) |
2665 | { | 2720 | { |
2666 | ushort subsystem_vendor_id, subsystem_device_id, command; | 2721 | ushort subsystem_vendor_id, subsystem_device_id, command; |
@@ -2721,7 +2776,10 @@ static int cciss_pci_init(ctlr_info_t *c, struct pci_dev *pdev) | |||
2721 | printk("board_id = %x\n", board_id); | 2776 | printk("board_id = %x\n", board_id); |
2722 | #endif /* CCISS_DEBUG */ | 2777 | #endif /* CCISS_DEBUG */ |
2723 | 2778 | ||
2724 | c->intr = pdev->irq; | 2779 | /* If the kernel supports MSI/MSI-X we will try to enable that functionality, |
2780 | * else we use the IO-APIC interrupt assigned to us by system ROM. | ||
2781 | */ | ||
2782 | cciss_interrupt_mode(c, pdev, board_id); | ||
2725 | 2783 | ||
2726 | /* | 2784 | /* |
2727 | * Memory base addr is first addr , the second points to the config | 2785 | * Memory base addr is first addr , the second points to the config |
@@ -2775,7 +2833,7 @@ static int cciss_pci_init(ctlr_info_t *c, struct pci_dev *pdev) | |||
2775 | c->board_id = board_id; | 2833 | c->board_id = board_id; |
2776 | 2834 | ||
2777 | #ifdef CCISS_DEBUG | 2835 | #ifdef CCISS_DEBUG |
2778 | print_cfg_table(c->cfgtable); | 2836 | print_cfg_table(c->cfgtable); |
2779 | #endif /* CCISS_DEBUG */ | 2837 | #endif /* CCISS_DEBUG */ |
2780 | 2838 | ||
2781 | for(i=0; i<NR_PRODUCTS; i++) { | 2839 | for(i=0; i<NR_PRODUCTS; i++) { |
@@ -3060,7 +3118,7 @@ static int __devinit cciss_init_one(struct pci_dev *pdev, | |||
3060 | * 8 controller support. | 3118 | * 8 controller support. |
3061 | */ | 3119 | */ |
3062 | if (i < MAX_CTLR_ORIG) | 3120 | if (i < MAX_CTLR_ORIG) |
3063 | hba[i]->major = MAJOR_NR + i; | 3121 | hba[i]->major = COMPAQ_CISS_MAJOR + i; |
3064 | rc = register_blkdev(hba[i]->major, hba[i]->devname); | 3122 | rc = register_blkdev(hba[i]->major, hba[i]->devname); |
3065 | if(rc == -EBUSY || rc == -EINVAL) { | 3123 | if(rc == -EBUSY || rc == -EINVAL) { |
3066 | printk(KERN_ERR | 3124 | printk(KERN_ERR |
@@ -3075,11 +3133,11 @@ static int __devinit cciss_init_one(struct pci_dev *pdev, | |||
3075 | 3133 | ||
3076 | /* make sure the board interrupts are off */ | 3134 | /* make sure the board interrupts are off */ |
3077 | hba[i]->access.set_intr_mask(hba[i], CCISS_INTR_OFF); | 3135 | hba[i]->access.set_intr_mask(hba[i], CCISS_INTR_OFF); |
3078 | if( request_irq(hba[i]->intr, do_cciss_intr, | 3136 | if( request_irq(hba[i]->intr[SIMPLE_MODE_INT], do_cciss_intr, |
3079 | SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM, | 3137 | SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM, |
3080 | hba[i]->devname, hba[i])) { | 3138 | hba[i]->devname, hba[i])) { |
3081 | printk(KERN_ERR "cciss: Unable to get irq %d for %s\n", | 3139 | printk(KERN_ERR "cciss: Unable to get irq %d for %s\n", |
3082 | hba[i]->intr, hba[i]->devname); | 3140 | hba[i]->intr[SIMPLE_MODE_INT], hba[i]->devname); |
3083 | goto clean2; | 3141 | goto clean2; |
3084 | } | 3142 | } |
3085 | hba[i]->cmd_pool_bits = kmalloc(((NR_CMDS+BITS_PER_LONG-1)/BITS_PER_LONG)*sizeof(unsigned long), GFP_KERNEL); | 3143 | hba[i]->cmd_pool_bits = kmalloc(((NR_CMDS+BITS_PER_LONG-1)/BITS_PER_LONG)*sizeof(unsigned long), GFP_KERNEL); |
@@ -3185,7 +3243,7 @@ clean4: | |||
3185 | NR_CMDS * sizeof( ErrorInfo_struct), | 3243 | NR_CMDS * sizeof( ErrorInfo_struct), |
3186 | hba[i]->errinfo_pool, | 3244 | hba[i]->errinfo_pool, |
3187 | hba[i]->errinfo_pool_dhandle); | 3245 | hba[i]->errinfo_pool_dhandle); |
3188 | free_irq(hba[i]->intr, hba[i]); | 3246 | free_irq(hba[i]->intr[SIMPLE_MODE_INT], hba[i]); |
3189 | clean2: | 3247 | clean2: |
3190 | unregister_blkdev(hba[i]->major, hba[i]->devname); | 3248 | unregister_blkdev(hba[i]->major, hba[i]->devname); |
3191 | clean1: | 3249 | clean1: |
@@ -3226,7 +3284,15 @@ static void __devexit cciss_remove_one (struct pci_dev *pdev) | |||
3226 | printk(KERN_WARNING "Error Flushing cache on controller %d\n", | 3284 | printk(KERN_WARNING "Error Flushing cache on controller %d\n", |
3227 | i); | 3285 | i); |
3228 | } | 3286 | } |
3229 | free_irq(hba[i]->intr, hba[i]); | 3287 | free_irq(hba[i]->intr[2], hba[i]); |
3288 | |||
3289 | #ifdef CONFIG_PCI_MSI | ||
3290 | if (hba[i]->msix_vector) | ||
3291 | pci_disable_msix(hba[i]->pdev); | ||
3292 | else if (hba[i]->msi_vector) | ||
3293 | pci_disable_msi(hba[i]->pdev); | ||
3294 | #endif /* CONFIG_PCI_MSI */ | ||
3295 | |||
3230 | pci_set_drvdata(pdev, NULL); | 3296 | pci_set_drvdata(pdev, NULL); |
3231 | iounmap(hba[i]->vaddr); | 3297 | iounmap(hba[i]->vaddr); |
3232 | cciss_unregister_scsi(i); /* unhook from SCSI subsystem */ | 3298 | cciss_unregister_scsi(i); /* unhook from SCSI subsystem */ |