diff options
Diffstat (limited to 'drivers/block/cciss.c')
-rw-r--r-- | drivers/block/cciss.c | 56 |
1 files changed, 45 insertions, 11 deletions
diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index 8f4ef656a1a..61f0b5b6a41 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c | |||
@@ -68,6 +68,10 @@ static int cciss_tape_cmds = 6; | |||
68 | module_param(cciss_tape_cmds, int, 0644); | 68 | module_param(cciss_tape_cmds, int, 0644); |
69 | MODULE_PARM_DESC(cciss_tape_cmds, | 69 | MODULE_PARM_DESC(cciss_tape_cmds, |
70 | "number of commands to allocate for tape devices (default: 6)"); | 70 | "number of commands to allocate for tape devices (default: 6)"); |
71 | static int cciss_simple_mode; | ||
72 | module_param(cciss_simple_mode, int, S_IRUGO|S_IWUSR); | ||
73 | MODULE_PARM_DESC(cciss_simple_mode, | ||
74 | "Use 'simple mode' rather than 'performant mode'"); | ||
71 | 75 | ||
72 | static DEFINE_MUTEX(cciss_mutex); | 76 | static DEFINE_MUTEX(cciss_mutex); |
73 | static struct proc_dir_entry *proc_cciss; | 77 | static struct proc_dir_entry *proc_cciss; |
@@ -176,6 +180,7 @@ static void cciss_geometry_inquiry(ctlr_info_t *h, int logvol, | |||
176 | unsigned int block_size, InquiryData_struct *inq_buff, | 180 | unsigned int block_size, InquiryData_struct *inq_buff, |
177 | drive_info_struct *drv); | 181 | drive_info_struct *drv); |
178 | static void __devinit cciss_interrupt_mode(ctlr_info_t *); | 182 | static void __devinit cciss_interrupt_mode(ctlr_info_t *); |
183 | static int __devinit cciss_enter_simple_mode(struct ctlr_info *h); | ||
179 | static void start_io(ctlr_info_t *h); | 184 | static void start_io(ctlr_info_t *h); |
180 | static int sendcmd_withirq(ctlr_info_t *h, __u8 cmd, void *buff, size_t size, | 185 | static int sendcmd_withirq(ctlr_info_t *h, __u8 cmd, void *buff, size_t size, |
181 | __u8 page_code, unsigned char scsi3addr[], | 186 | __u8 page_code, unsigned char scsi3addr[], |
@@ -388,7 +393,7 @@ static void cciss_seq_show_header(struct seq_file *seq) | |||
388 | h->product_name, | 393 | h->product_name, |
389 | (unsigned long)h->board_id, | 394 | (unsigned long)h->board_id, |
390 | h->firm_ver[0], h->firm_ver[1], h->firm_ver[2], | 395 | h->firm_ver[0], h->firm_ver[1], h->firm_ver[2], |
391 | h->firm_ver[3], (unsigned int)h->intr[PERF_MODE_INT], | 396 | h->firm_ver[3], (unsigned int)h->intr[h->intr_mode], |
392 | h->num_luns, | 397 | h->num_luns, |
393 | h->Qdepth, h->commands_outstanding, | 398 | h->Qdepth, h->commands_outstanding, |
394 | h->maxQsinceinit, h->max_outstanding, h->maxSG); | 399 | h->maxQsinceinit, h->max_outstanding, h->maxSG); |
@@ -3984,6 +3989,9 @@ static void __devinit cciss_put_controller_into_performant_mode(ctlr_info_t *h) | |||
3984 | { | 3989 | { |
3985 | __u32 trans_support; | 3990 | __u32 trans_support; |
3986 | 3991 | ||
3992 | if (cciss_simple_mode) | ||
3993 | return; | ||
3994 | |||
3987 | dev_dbg(&h->pdev->dev, "Trying to put board into Performant mode\n"); | 3995 | dev_dbg(&h->pdev->dev, "Trying to put board into Performant mode\n"); |
3988 | /* Attempt to put controller into performant mode if supported */ | 3996 | /* Attempt to put controller into performant mode if supported */ |
3989 | /* Does board support performant mode? */ | 3997 | /* Does board support performant mode? */ |
@@ -4081,7 +4089,7 @@ static void __devinit cciss_interrupt_mode(ctlr_info_t *h) | |||
4081 | default_int_mode: | 4089 | default_int_mode: |
4082 | #endif /* CONFIG_PCI_MSI */ | 4090 | #endif /* CONFIG_PCI_MSI */ |
4083 | /* if we get here we're going to use the default interrupt mode */ | 4091 | /* if we get here we're going to use the default interrupt mode */ |
4084 | h->intr[PERF_MODE_INT] = h->pdev->irq; | 4092 | h->intr[h->intr_mode] = h->pdev->irq; |
4085 | return; | 4093 | return; |
4086 | } | 4094 | } |
4087 | 4095 | ||
@@ -4341,6 +4349,9 @@ static int __devinit cciss_pci_init(ctlr_info_t *h) | |||
4341 | } | 4349 | } |
4342 | cciss_enable_scsi_prefetch(h); | 4350 | cciss_enable_scsi_prefetch(h); |
4343 | cciss_p600_dma_prefetch_quirk(h); | 4351 | cciss_p600_dma_prefetch_quirk(h); |
4352 | err = cciss_enter_simple_mode(h); | ||
4353 | if (err) | ||
4354 | goto err_out_free_res; | ||
4344 | cciss_put_controller_into_performant_mode(h); | 4355 | cciss_put_controller_into_performant_mode(h); |
4345 | return 0; | 4356 | return 0; |
4346 | 4357 | ||
@@ -4843,20 +4854,20 @@ static int cciss_request_irq(ctlr_info_t *h, | |||
4843 | irqreturn_t (*intxhandler)(int, void *)) | 4854 | irqreturn_t (*intxhandler)(int, void *)) |
4844 | { | 4855 | { |
4845 | if (h->msix_vector || h->msi_vector) { | 4856 | if (h->msix_vector || h->msi_vector) { |
4846 | if (!request_irq(h->intr[PERF_MODE_INT], msixhandler, | 4857 | if (!request_irq(h->intr[h->intr_mode], msixhandler, |
4847 | IRQF_DISABLED, h->devname, h)) | 4858 | IRQF_DISABLED, h->devname, h)) |
4848 | return 0; | 4859 | return 0; |
4849 | dev_err(&h->pdev->dev, "Unable to get msi irq %d" | 4860 | dev_err(&h->pdev->dev, "Unable to get msi irq %d" |
4850 | " for %s\n", h->intr[PERF_MODE_INT], | 4861 | " for %s\n", h->intr[h->intr_mode], |
4851 | h->devname); | 4862 | h->devname); |
4852 | return -1; | 4863 | return -1; |
4853 | } | 4864 | } |
4854 | 4865 | ||
4855 | if (!request_irq(h->intr[PERF_MODE_INT], intxhandler, | 4866 | if (!request_irq(h->intr[h->intr_mode], intxhandler, |
4856 | IRQF_DISABLED, h->devname, h)) | 4867 | IRQF_DISABLED, h->devname, h)) |
4857 | return 0; | 4868 | return 0; |
4858 | dev_err(&h->pdev->dev, "Unable to get irq %d for %s\n", | 4869 | dev_err(&h->pdev->dev, "Unable to get irq %d for %s\n", |
4859 | h->intr[PERF_MODE_INT], h->devname); | 4870 | h->intr[h->intr_mode], h->devname); |
4860 | return -1; | 4871 | return -1; |
4861 | } | 4872 | } |
4862 | 4873 | ||
@@ -4887,7 +4898,7 @@ static void cciss_undo_allocations_after_kdump_soft_reset(ctlr_info_t *h) | |||
4887 | { | 4898 | { |
4888 | int ctlr = h->ctlr; | 4899 | int ctlr = h->ctlr; |
4889 | 4900 | ||
4890 | free_irq(h->intr[PERF_MODE_INT], h); | 4901 | free_irq(h->intr[h->intr_mode], h); |
4891 | #ifdef CONFIG_PCI_MSI | 4902 | #ifdef CONFIG_PCI_MSI |
4892 | if (h->msix_vector) | 4903 | if (h->msix_vector) |
4893 | pci_disable_msix(h->pdev); | 4904 | pci_disable_msix(h->pdev); |
@@ -4953,6 +4964,7 @@ reinit_after_soft_reset: | |||
4953 | h = hba[i]; | 4964 | h = hba[i]; |
4954 | h->pdev = pdev; | 4965 | h->pdev = pdev; |
4955 | h->busy_initializing = 1; | 4966 | h->busy_initializing = 1; |
4967 | h->intr_mode = cciss_simple_mode ? SIMPLE_MODE_INT : PERF_MODE_INT; | ||
4956 | INIT_LIST_HEAD(&h->cmpQ); | 4968 | INIT_LIST_HEAD(&h->cmpQ); |
4957 | INIT_LIST_HEAD(&h->reqQ); | 4969 | INIT_LIST_HEAD(&h->reqQ); |
4958 | mutex_init(&h->busy_shutting_down); | 4970 | mutex_init(&h->busy_shutting_down); |
@@ -5009,7 +5021,7 @@ reinit_after_soft_reset: | |||
5009 | 5021 | ||
5010 | dev_info(&h->pdev->dev, "%s: <0x%x> at PCI %s IRQ %d%s using DAC\n", | 5022 | dev_info(&h->pdev->dev, "%s: <0x%x> at PCI %s IRQ %d%s using DAC\n", |
5011 | h->devname, pdev->device, pci_name(pdev), | 5023 | h->devname, pdev->device, pci_name(pdev), |
5012 | h->intr[PERF_MODE_INT], dac ? "" : " not"); | 5024 | h->intr[h->intr_mode], dac ? "" : " not"); |
5013 | 5025 | ||
5014 | if (cciss_allocate_cmd_pool(h)) | 5026 | if (cciss_allocate_cmd_pool(h)) |
5015 | goto clean4; | 5027 | goto clean4; |
@@ -5056,7 +5068,7 @@ reinit_after_soft_reset: | |||
5056 | spin_lock_irqsave(&h->lock, flags); | 5068 | spin_lock_irqsave(&h->lock, flags); |
5057 | h->access.set_intr_mask(h, CCISS_INTR_OFF); | 5069 | h->access.set_intr_mask(h, CCISS_INTR_OFF); |
5058 | spin_unlock_irqrestore(&h->lock, flags); | 5070 | spin_unlock_irqrestore(&h->lock, flags); |
5059 | free_irq(h->intr[PERF_MODE_INT], h); | 5071 | free_irq(h->intr[h->intr_mode], h); |
5060 | rc = cciss_request_irq(h, cciss_msix_discard_completions, | 5072 | rc = cciss_request_irq(h, cciss_msix_discard_completions, |
5061 | cciss_intx_discard_completions); | 5073 | cciss_intx_discard_completions); |
5062 | if (rc) { | 5074 | if (rc) { |
@@ -5133,7 +5145,7 @@ clean4: | |||
5133 | cciss_free_cmd_pool(h); | 5145 | cciss_free_cmd_pool(h); |
5134 | cciss_free_scatterlists(h); | 5146 | cciss_free_scatterlists(h); |
5135 | cciss_free_sg_chain_blocks(h->cmd_sg_list, h->nr_cmds); | 5147 | cciss_free_sg_chain_blocks(h->cmd_sg_list, h->nr_cmds); |
5136 | free_irq(h->intr[PERF_MODE_INT], h); | 5148 | free_irq(h->intr[h->intr_mode], h); |
5137 | clean2: | 5149 | clean2: |
5138 | unregister_blkdev(h->major, h->devname); | 5150 | unregister_blkdev(h->major, h->devname); |
5139 | clean1: | 5151 | clean1: |
@@ -5172,9 +5184,31 @@ static void cciss_shutdown(struct pci_dev *pdev) | |||
5172 | if (return_code != IO_OK) | 5184 | if (return_code != IO_OK) |
5173 | dev_warn(&h->pdev->dev, "Error flushing cache\n"); | 5185 | dev_warn(&h->pdev->dev, "Error flushing cache\n"); |
5174 | h->access.set_intr_mask(h, CCISS_INTR_OFF); | 5186 | h->access.set_intr_mask(h, CCISS_INTR_OFF); |
5175 | free_irq(h->intr[PERF_MODE_INT], h); | 5187 | free_irq(h->intr[h->intr_mode], h); |
5176 | } | 5188 | } |
5177 | 5189 | ||
5190 | static int __devinit cciss_enter_simple_mode(struct ctlr_info *h) | ||
5191 | { | ||
5192 | u32 trans_support; | ||
5193 | |||
5194 | trans_support = readl(&(h->cfgtable->TransportSupport)); | ||
5195 | if (!(trans_support & SIMPLE_MODE)) | ||
5196 | return -ENOTSUPP; | ||
5197 | |||
5198 | h->max_commands = readl(&(h->cfgtable->CmdsOutMax)); | ||
5199 | writel(CFGTBL_Trans_Simple, &(h->cfgtable->HostWrite.TransportRequest)); | ||
5200 | writel(CFGTBL_ChangeReq, h->vaddr + SA5_DOORBELL); | ||
5201 | cciss_wait_for_mode_change_ack(h); | ||
5202 | print_cfg_table(h); | ||
5203 | if (!(readl(&(h->cfgtable->TransportActive)) & CFGTBL_Trans_Simple)) { | ||
5204 | dev_warn(&h->pdev->dev, "unable to get board into simple mode\n"); | ||
5205 | return -ENODEV; | ||
5206 | } | ||
5207 | h->transMethod = CFGTBL_Trans_Simple; | ||
5208 | return 0; | ||
5209 | } | ||
5210 | |||
5211 | |||
5178 | static void __devexit cciss_remove_one(struct pci_dev *pdev) | 5212 | static void __devexit cciss_remove_one(struct pci_dev *pdev) |
5179 | { | 5213 | { |
5180 | ctlr_info_t *h; | 5214 | ctlr_info_t *h; |