aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/block/cciss.c
diff options
context:
space:
mode:
authorMike Miller <mike.miller@hp.com>2006-01-08 04:03:50 -0500
committerLinus Torvalds <torvalds@g5.osdl.org>2006-01-08 23:14:00 -0500
commitfb86a35b9ded8a7e53a432cbf28df603cdd4849c (patch)
tree6cfc9de386c26f5b1c9a126aee2bdc8f80bc8e2b /drivers/block/cciss.c
parentd09cf7d77f62f6fb2f6d63fe5980583805f2d559 (diff)
[PATCH] cciss: adds MSI and MSI-X support
This creates a new function, cciss_interrupt_mode called from cciss_pci_init. This function determines what type of interrupt vector to use, i.e., MSI, MSI-X, or IO-APIC. One noticeable difference is changing the interrupt field of the controller struct to an array of 4 unsigned ints. The Smart Array HW is capable of generating 4 distinct interrupts depending on the transport method in use during operation. These are: #define DOORBELL_INT 0 Used to notify the contoller of configuration updates. We only use this feature when in polling mode. #define PERF_MODE_INT 0 Used when the controller is in Performant Mode. #define SIMPLE_MODE_INT 2 Used when the controller is in Simple Mode (current Linux implementation). #define MEMQ_INT_MODE 3 Not used. When using IO-APIC interrupts these 4 lines are OR'ed together so when any one fires an interrupt an is generated. In MSI or MSI-X mode this hardware OR'ing is ignored. We must register for our interrupt depending on what mode the controller is running. For Linux we use SIMPLE_MODE_INT exclusively at this time. Please consider this for inclusion. Signed-off-by: Mike Miller <mike.miller@hp.com> Cc: Jens Axboe <axboe@suse.de> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'drivers/block/cciss.c')
-rw-r--r--drivers/block/cciss.c87
1 files changed, 76 insertions, 11 deletions
diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c
index bdb9c2717d40..46e8356a962a 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");
@@ -167,7 +167,7 @@ static void cciss_geometry_inquiry(int ctlr, int logvol,
167 unsigned int block_size, InquiryData_struct *inq_buff, 167 unsigned int block_size, InquiryData_struct *inq_buff,
168 drive_info_struct *drv); 168 drive_info_struct *drv);
169static void cciss_getgeometry(int cntl_num); 169static void cciss_getgeometry(int cntl_num);
170 170static void __devinit cciss_interrupt_mode(ctlr_info_t *, struct pci_dev *, __u32);
171static void start_io( ctlr_info_t *h); 171static void start_io( ctlr_info_t *h);
172static int sendcmd( __u8 cmd, int ctlr, void *buff, size_t size, 172static int sendcmd( __u8 cmd, int ctlr, void *buff, size_t size,
173 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,
@@ -284,7 +284,7 @@ static int cciss_proc_get_info(char *buffer, char **start, off_t offset,
284 h->product_name, 284 h->product_name,
285 (unsigned long)h->board_id, 285 (unsigned long)h->board_id,
286 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],
287 (unsigned int)h->intr, 287 (unsigned int)h->intr[SIMPLE_MODE_INT],
288 h->num_luns, 288 h->num_luns,
289 h->Qdepth, h->commands_outstanding, 289 h->Qdepth, h->commands_outstanding,
290 h->maxQsinceinit, h->max_outstanding, h->maxSG); 290 h->maxQsinceinit, h->max_outstanding, h->maxSG);
@@ -2662,6 +2662,60 @@ static int find_PCI_BAR_index(struct pci_dev *pdev,
2662 return -1; 2662 return -1;
2663} 2663}
2664 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
2669static 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 */
2714default_int_mode:
2715 c->intr[SIMPLE_MODE_INT] = pdev->irq;
2716 return;
2717}
2718
2665static int cciss_pci_init(ctlr_info_t *c, struct pci_dev *pdev) 2719static int cciss_pci_init(ctlr_info_t *c, struct pci_dev *pdev)
2666{ 2720{
2667 ushort subsystem_vendor_id, subsystem_device_id, command; 2721 ushort subsystem_vendor_id, subsystem_device_id, command;
@@ -2722,7 +2776,10 @@ static int cciss_pci_init(ctlr_info_t *c, struct pci_dev *pdev)
2722 printk("board_id = %x\n", board_id); 2776 printk("board_id = %x\n", board_id);
2723#endif /* CCISS_DEBUG */ 2777#endif /* CCISS_DEBUG */
2724 2778
2725 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);
2726 2783
2727 /* 2784 /*
2728 * 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
@@ -3076,11 +3133,11 @@ static int __devinit cciss_init_one(struct pci_dev *pdev,
3076 3133
3077 /* make sure the board interrupts are off */ 3134 /* make sure the board interrupts are off */
3078 hba[i]->access.set_intr_mask(hba[i], CCISS_INTR_OFF); 3135 hba[i]->access.set_intr_mask(hba[i], CCISS_INTR_OFF);
3079 if( request_irq(hba[i]->intr, do_cciss_intr, 3136 if( request_irq(hba[i]->intr[SIMPLE_MODE_INT], do_cciss_intr,
3080 SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM, 3137 SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM,
3081 hba[i]->devname, hba[i])) { 3138 hba[i]->devname, hba[i])) {
3082 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",
3083 hba[i]->intr, hba[i]->devname); 3140 hba[i]->intr[SIMPLE_MODE_INT], hba[i]->devname);
3084 goto clean2; 3141 goto clean2;
3085 } 3142 }
3086 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);
@@ -3186,7 +3243,7 @@ clean4:
3186 NR_CMDS * sizeof( ErrorInfo_struct), 3243 NR_CMDS * sizeof( ErrorInfo_struct),
3187 hba[i]->errinfo_pool, 3244 hba[i]->errinfo_pool,
3188 hba[i]->errinfo_pool_dhandle); 3245 hba[i]->errinfo_pool_dhandle);
3189 free_irq(hba[i]->intr, hba[i]); 3246 free_irq(hba[i]->intr[SIMPLE_MODE_INT], hba[i]);
3190clean2: 3247clean2:
3191 unregister_blkdev(hba[i]->major, hba[i]->devname); 3248 unregister_blkdev(hba[i]->major, hba[i]->devname);
3192clean1: 3249clean1:
@@ -3227,7 +3284,15 @@ static void __devexit cciss_remove_one (struct pci_dev *pdev)
3227 printk(KERN_WARNING "Error Flushing cache on controller %d\n", 3284 printk(KERN_WARNING "Error Flushing cache on controller %d\n",
3228 i); 3285 i);
3229 } 3286 }
3230 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
3231 pci_set_drvdata(pdev, NULL); 3296 pci_set_drvdata(pdev, NULL);
3232 iounmap(hba[i]->vaddr); 3297 iounmap(hba[i]->vaddr);
3233 cciss_unregister_scsi(i); /* unhook from SCSI subsystem */ 3298 cciss_unregister_scsi(i); /* unhook from SCSI subsystem */