aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/block/cciss.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/block/cciss.c')
-rw-r--r--drivers/block/cciss.c196
1 files changed, 141 insertions, 55 deletions
diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c
index d2815b7a9150..e4e9f255bd1f 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 */
54MODULE_AUTHOR("Hewlett-Packard Company"); 54MODULE_AUTHOR("Hewlett-Packard Company");
55MODULE_DESCRIPTION("Driver for HP Controller SA5xxx SA6xxx version 2.6.8"); 55MODULE_DESCRIPTION("Driver for HP Controller SA5xxx SA6xxx version 2.6.10");
56MODULE_SUPPORTED_DEVICE("HP SA5i SA5i+ SA532 SA5300 SA5312 SA641 SA642 SA6400" 56MODULE_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");
58MODULE_LICENSE("GPL"); 58MODULE_LICENSE("GPL");
@@ -103,7 +103,7 @@ static const struct pci_device_id cciss_pci_device_id[] = {
103}; 103};
104MODULE_DEVICE_TABLE(pci, cciss_pci_device_id); 104MODULE_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);
153static int cciss_release(struct inode *inode, struct file *filep); 153static int cciss_release(struct inode *inode, struct file *filep);
154static int cciss_ioctl(struct inode *inode, struct file *filep, 154static int cciss_ioctl(struct inode *inode, struct file *filep,
155 unsigned int cmd, unsigned long arg); 155 unsigned int cmd, unsigned long arg);
156static int cciss_getgeo(struct block_device *bdev, struct hd_geometry *geo);
156 157
157static int revalidate_allvol(ctlr_info_t *host); 158static int revalidate_allvol(ctlr_info_t *host);
158static int cciss_revalidate(struct gendisk *disk); 159static 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);
168static void cciss_getgeometry(int cntl_num); 169static void cciss_getgeometry(int cntl_num);
169 170static void __devinit cciss_interrupt_mode(ctlr_info_t *, struct pci_dev *, __u32);
170static void start_io( ctlr_info_t *h); 171static void start_io( ctlr_info_t *h);
171static int sendcmd( __u8 cmd, int ctlr, void *buff, size_t size, 172static 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
639static 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;
@@ -2177,16 +2178,48 @@ static inline void resend_cciss_cmd( ctlr_info_t *h, CommandList_struct *c)
2177 2178
2178 start_io(h); 2179 start_io(h);
2179} 2180}
2181
2182static void cciss_softirq_done(struct request *rq)
2183{
2184 CommandList_struct *cmd = rq->completion_data;
2185 ctlr_info_t *h = hba[cmd->ctlr];
2186 u64bit temp64;
2187 int i, ddir;
2188
2189 if (cmd->Request.Type.Direction == XFER_READ)
2190 ddir = PCI_DMA_FROMDEVICE;
2191 else
2192 ddir = PCI_DMA_TODEVICE;
2193
2194 /* command did not need to be retried */
2195 /* unmap the DMA mapping for all the scatter gather elements */
2196 for(i=0; i<cmd->Header.SGList; i++) {
2197 temp64.val32.lower = cmd->SG[i].Addr.lower;
2198 temp64.val32.upper = cmd->SG[i].Addr.upper;
2199 pci_unmap_page(h->pdev, temp64.val, cmd->SG[i].Len, ddir);
2200 }
2201
2202 complete_buffers(rq->bio, rq->errors);
2203
2204#ifdef CCISS_DEBUG
2205 printk("Done with %p\n", rq);
2206#endif /* CCISS_DEBUG */
2207
2208 spin_lock_irq(&h->lock);
2209 end_that_request_last(rq, rq->errors);
2210 cmd_free(h, cmd,1);
2211 spin_unlock_irq(&h->lock);
2212}
2213
2180/* checks the status of the job and calls complete buffers to mark all 2214/* checks the status of the job and calls complete buffers to mark all
2181 * buffers for the completed job. 2215 * buffers for the completed job. Note that this function does not need
2216 * to hold the hba/queue lock.
2182 */ 2217 */
2183static inline void complete_command( ctlr_info_t *h, CommandList_struct *cmd, 2218static inline void complete_command( ctlr_info_t *h, CommandList_struct *cmd,
2184 int timeout) 2219 int timeout)
2185{ 2220{
2186 int status = 1; 2221 int status = 1;
2187 int i;
2188 int retry_cmd = 0; 2222 int retry_cmd = 0;
2189 u64bit temp64;
2190 2223
2191 if (timeout) 2224 if (timeout)
2192 status = 0; 2225 status = 0;
@@ -2294,24 +2327,10 @@ static inline void complete_command( ctlr_info_t *h, CommandList_struct *cmd,
2294 resend_cciss_cmd(h,cmd); 2327 resend_cciss_cmd(h,cmd);
2295 return; 2328 return;
2296 } 2329 }
2297 /* command did not need to be retried */
2298 /* unmap the DMA mapping for all the scatter gather elements */
2299 for(i=0; i<cmd->Header.SGList; i++) {
2300 temp64.val32.lower = cmd->SG[i].Addr.lower;
2301 temp64.val32.upper = cmd->SG[i].Addr.upper;
2302 pci_unmap_page(hba[cmd->ctlr]->pdev,
2303 temp64.val, cmd->SG[i].Len,
2304 (cmd->Request.Type.Direction == XFER_READ) ?
2305 PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE);
2306 }
2307 complete_buffers(cmd->rq->bio, status);
2308 2330
2309#ifdef CCISS_DEBUG 2331 cmd->rq->completion_data = cmd;
2310 printk("Done with %p\n", cmd->rq); 2332 cmd->rq->errors = status;
2311#endif /* CCISS_DEBUG */ 2333 blk_complete_request(cmd->rq);
2312
2313 end_that_request_last(cmd->rq, status ? 1 : -EIO);
2314 cmd_free(h,cmd,1);
2315} 2334}
2316 2335
2317/* 2336/*
@@ -2661,6 +2680,60 @@ static int find_PCI_BAR_index(struct pci_dev *pdev,
2661 return -1; 2680 return -1;
2662} 2681}
2663 2682
2683/* If MSI/MSI-X is supported by the kernel we will try to enable it on
2684 * controllers that are capable. If not, we use IO-APIC mode.
2685 */
2686
2687static void __devinit cciss_interrupt_mode(ctlr_info_t *c, struct pci_dev *pdev, __u32 board_id)
2688{
2689#ifdef CONFIG_PCI_MSI
2690 int err;
2691 struct msix_entry cciss_msix_entries[4] = {{0,0}, {0,1},
2692 {0,2}, {0,3}};
2693
2694 /* Some boards advertise MSI but don't really support it */
2695 if ((board_id == 0x40700E11) ||
2696 (board_id == 0x40800E11) ||
2697 (board_id == 0x40820E11) ||
2698 (board_id == 0x40830E11))
2699 goto default_int_mode;
2700
2701 if (pci_find_capability(pdev, PCI_CAP_ID_MSIX)) {
2702 err = pci_enable_msix(pdev, cciss_msix_entries, 4);
2703 if (!err) {
2704 c->intr[0] = cciss_msix_entries[0].vector;
2705 c->intr[1] = cciss_msix_entries[1].vector;
2706 c->intr[2] = cciss_msix_entries[2].vector;
2707 c->intr[3] = cciss_msix_entries[3].vector;
2708 c->msix_vector = 1;
2709 return;
2710 }
2711 if (err > 0) {
2712 printk(KERN_WARNING "cciss: only %d MSI-X vectors "
2713 "available\n", err);
2714 } else {
2715 printk(KERN_WARNING "cciss: MSI-X init failed %d\n",
2716 err);
2717 }
2718 }
2719 if (pci_find_capability(pdev, PCI_CAP_ID_MSI)) {
2720 if (!pci_enable_msi(pdev)) {
2721 c->intr[SIMPLE_MODE_INT] = pdev->irq;
2722 c->msi_vector = 1;
2723 return;
2724 } else {
2725 printk(KERN_WARNING "cciss: MSI init failed\n");
2726 c->intr[SIMPLE_MODE_INT] = pdev->irq;
2727 return;
2728 }
2729 }
2730#endif /* CONFIG_PCI_MSI */
2731 /* if we get here we're going to use the default interrupt mode */
2732default_int_mode:
2733 c->intr[SIMPLE_MODE_INT] = pdev->irq;
2734 return;
2735}
2736
2664static int cciss_pci_init(ctlr_info_t *c, struct pci_dev *pdev) 2737static int cciss_pci_init(ctlr_info_t *c, struct pci_dev *pdev)
2665{ 2738{
2666 ushort subsystem_vendor_id, subsystem_device_id, command; 2739 ushort subsystem_vendor_id, subsystem_device_id, command;
@@ -2721,7 +2794,10 @@ static int cciss_pci_init(ctlr_info_t *c, struct pci_dev *pdev)
2721 printk("board_id = %x\n", board_id); 2794 printk("board_id = %x\n", board_id);
2722#endif /* CCISS_DEBUG */ 2795#endif /* CCISS_DEBUG */
2723 2796
2724 c->intr = pdev->irq; 2797/* If the kernel supports MSI/MSI-X we will try to enable that functionality,
2798 * else we use the IO-APIC interrupt assigned to us by system ROM.
2799 */
2800 cciss_interrupt_mode(c, pdev, board_id);
2725 2801
2726 /* 2802 /*
2727 * Memory base addr is first addr , the second points to the config 2803 * Memory base addr is first addr , the second points to the config
@@ -2775,7 +2851,7 @@ static int cciss_pci_init(ctlr_info_t *c, struct pci_dev *pdev)
2775 c->board_id = board_id; 2851 c->board_id = board_id;
2776 2852
2777#ifdef CCISS_DEBUG 2853#ifdef CCISS_DEBUG
2778 print_cfg_table(c->cfgtable); 2854 print_cfg_table(c->cfgtable);
2779#endif /* CCISS_DEBUG */ 2855#endif /* CCISS_DEBUG */
2780 2856
2781 for(i=0; i<NR_PRODUCTS; i++) { 2857 for(i=0; i<NR_PRODUCTS; i++) {
@@ -3060,7 +3136,7 @@ static int __devinit cciss_init_one(struct pci_dev *pdev,
3060 * 8 controller support. 3136 * 8 controller support.
3061 */ 3137 */
3062 if (i < MAX_CTLR_ORIG) 3138 if (i < MAX_CTLR_ORIG)
3063 hba[i]->major = MAJOR_NR + i; 3139 hba[i]->major = COMPAQ_CISS_MAJOR + i;
3064 rc = register_blkdev(hba[i]->major, hba[i]->devname); 3140 rc = register_blkdev(hba[i]->major, hba[i]->devname);
3065 if(rc == -EBUSY || rc == -EINVAL) { 3141 if(rc == -EBUSY || rc == -EINVAL) {
3066 printk(KERN_ERR 3142 printk(KERN_ERR
@@ -3075,11 +3151,11 @@ static int __devinit cciss_init_one(struct pci_dev *pdev,
3075 3151
3076 /* make sure the board interrupts are off */ 3152 /* make sure the board interrupts are off */
3077 hba[i]->access.set_intr_mask(hba[i], CCISS_INTR_OFF); 3153 hba[i]->access.set_intr_mask(hba[i], CCISS_INTR_OFF);
3078 if( request_irq(hba[i]->intr, do_cciss_intr, 3154 if( request_irq(hba[i]->intr[SIMPLE_MODE_INT], do_cciss_intr,
3079 SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM, 3155 SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM,
3080 hba[i]->devname, hba[i])) { 3156 hba[i]->devname, hba[i])) {
3081 printk(KERN_ERR "cciss: Unable to get irq %d for %s\n", 3157 printk(KERN_ERR "cciss: Unable to get irq %d for %s\n",
3082 hba[i]->intr, hba[i]->devname); 3158 hba[i]->intr[SIMPLE_MODE_INT], hba[i]->devname);
3083 goto clean2; 3159 goto clean2;
3084 } 3160 }
3085 hba[i]->cmd_pool_bits = kmalloc(((NR_CMDS+BITS_PER_LONG-1)/BITS_PER_LONG)*sizeof(unsigned long), GFP_KERNEL); 3161 hba[i]->cmd_pool_bits = kmalloc(((NR_CMDS+BITS_PER_LONG-1)/BITS_PER_LONG)*sizeof(unsigned long), GFP_KERNEL);
@@ -3141,15 +3217,17 @@ static int __devinit cciss_init_one(struct pci_dev *pdev,
3141 drv->queue = q; 3217 drv->queue = q;
3142 3218
3143 q->backing_dev_info.ra_pages = READ_AHEAD; 3219 q->backing_dev_info.ra_pages = READ_AHEAD;
3144 blk_queue_bounce_limit(q, hba[i]->pdev->dma_mask); 3220 blk_queue_bounce_limit(q, hba[i]->pdev->dma_mask);
3145 3221
3146 /* This is a hardware imposed limit. */ 3222 /* This is a hardware imposed limit. */
3147 blk_queue_max_hw_segments(q, MAXSGENTRIES); 3223 blk_queue_max_hw_segments(q, MAXSGENTRIES);
3148 3224
3149 /* This is a limit in the driver and could be eliminated. */ 3225 /* This is a limit in the driver and could be eliminated. */
3150 blk_queue_max_phys_segments(q, MAXSGENTRIES); 3226 blk_queue_max_phys_segments(q, MAXSGENTRIES);
3151 3227
3152 blk_queue_max_sectors(q, 512); 3228 blk_queue_max_sectors(q, 512);
3229
3230 blk_queue_softirq_done(q, cciss_softirq_done);
3153 3231
3154 q->queuedata = hba[i]; 3232 q->queuedata = hba[i];
3155 sprintf(disk->disk_name, "cciss/c%dd%d", i, j); 3233 sprintf(disk->disk_name, "cciss/c%dd%d", i, j);
@@ -3185,7 +3263,7 @@ clean4:
3185 NR_CMDS * sizeof( ErrorInfo_struct), 3263 NR_CMDS * sizeof( ErrorInfo_struct),
3186 hba[i]->errinfo_pool, 3264 hba[i]->errinfo_pool,
3187 hba[i]->errinfo_pool_dhandle); 3265 hba[i]->errinfo_pool_dhandle);
3188 free_irq(hba[i]->intr, hba[i]); 3266 free_irq(hba[i]->intr[SIMPLE_MODE_INT], hba[i]);
3189clean2: 3267clean2:
3190 unregister_blkdev(hba[i]->major, hba[i]->devname); 3268 unregister_blkdev(hba[i]->major, hba[i]->devname);
3191clean1: 3269clean1:
@@ -3226,7 +3304,15 @@ static void __devexit cciss_remove_one (struct pci_dev *pdev)
3226 printk(KERN_WARNING "Error Flushing cache on controller %d\n", 3304 printk(KERN_WARNING "Error Flushing cache on controller %d\n",
3227 i); 3305 i);
3228 } 3306 }
3229 free_irq(hba[i]->intr, hba[i]); 3307 free_irq(hba[i]->intr[2], hba[i]);
3308
3309#ifdef CONFIG_PCI_MSI
3310 if (hba[i]->msix_vector)
3311 pci_disable_msix(hba[i]->pdev);
3312 else if (hba[i]->msi_vector)
3313 pci_disable_msi(hba[i]->pdev);
3314#endif /* CONFIG_PCI_MSI */
3315
3230 pci_set_drvdata(pdev, NULL); 3316 pci_set_drvdata(pdev, NULL);
3231 iounmap(hba[i]->vaddr); 3317 iounmap(hba[i]->vaddr);
3232 cciss_unregister_scsi(i); /* unhook from SCSI subsystem */ 3318 cciss_unregister_scsi(i); /* unhook from SCSI subsystem */