cciss: Adds simple mode functionality

Signed-off-by: Joseph Handzik <joseph.t.handzik@beardog.cce.hp.com>
Acked-by: Stephen M. Cameron <scameron@beardog.cce.hp.com>
Signed-off-by: Jens Axboe <jaxboe@fusionio.com>
This commit is contained in:
Joseph Handzik 2011-08-08 11:40:15 +02:00 committed by Jens Axboe
parent 322a8b0340
commit 1304953700
3 changed files with 56 additions and 11 deletions

View File

@ -78,6 +78,16 @@ The device naming scheme is:
/dev/cciss/c1d1p2 Controller 1, disk 1, partition 2 /dev/cciss/c1d1p2 Controller 1, disk 1, partition 2
/dev/cciss/c1d1p3 Controller 1, disk 1, partition 3 /dev/cciss/c1d1p3 Controller 1, disk 1, partition 3
CCISS simple mode support
-------------------------
The "cciss_simple_mode=1" boot parameter may be used to prevent the driver
from putting the controller into "performant" mode. The difference is that
with simple mode, each command completion requires an interrupt, while with
"performant mode" (the default, and ordinarily better performing) it is
possible to have multiple command completions indicated by a single
interrupt.
SCSI tape drive and medium changer support SCSI tape drive and medium changer support
------------------------------------------ ------------------------------------------

View File

@ -68,6 +68,10 @@ static int cciss_tape_cmds = 6;
module_param(cciss_tape_cmds, int, 0644); module_param(cciss_tape_cmds, int, 0644);
MODULE_PARM_DESC(cciss_tape_cmds, MODULE_PARM_DESC(cciss_tape_cmds,
"number of commands to allocate for tape devices (default: 6)"); "number of commands to allocate for tape devices (default: 6)");
static int cciss_simple_mode;
module_param(cciss_simple_mode, int, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(cciss_simple_mode,
"Use 'simple mode' rather than 'performant mode'");
static DEFINE_MUTEX(cciss_mutex); static DEFINE_MUTEX(cciss_mutex);
static struct proc_dir_entry *proc_cciss; static struct proc_dir_entry *proc_cciss;
@ -176,6 +180,7 @@ static void cciss_geometry_inquiry(ctlr_info_t *h, int logvol,
unsigned int block_size, InquiryData_struct *inq_buff, unsigned int block_size, InquiryData_struct *inq_buff,
drive_info_struct *drv); drive_info_struct *drv);
static void __devinit cciss_interrupt_mode(ctlr_info_t *); static void __devinit cciss_interrupt_mode(ctlr_info_t *);
static int __devinit cciss_enter_simple_mode(struct ctlr_info *h);
static void start_io(ctlr_info_t *h); static void start_io(ctlr_info_t *h);
static int sendcmd_withirq(ctlr_info_t *h, __u8 cmd, void *buff, size_t size, static int sendcmd_withirq(ctlr_info_t *h, __u8 cmd, void *buff, size_t size,
__u8 page_code, unsigned char scsi3addr[], __u8 page_code, unsigned char scsi3addr[],
@ -388,7 +393,7 @@ static void cciss_seq_show_header(struct seq_file *seq)
h->product_name, h->product_name,
(unsigned long)h->board_id, (unsigned long)h->board_id,
h->firm_ver[0], h->firm_ver[1], h->firm_ver[2], h->firm_ver[0], h->firm_ver[1], h->firm_ver[2],
h->firm_ver[3], (unsigned int)h->intr[PERF_MODE_INT], h->firm_ver[3], (unsigned int)h->intr[h->intr_mode],
h->num_luns, h->num_luns,
h->Qdepth, h->commands_outstanding, h->Qdepth, h->commands_outstanding,
h->maxQsinceinit, h->max_outstanding, h->maxSG); h->maxQsinceinit, h->max_outstanding, h->maxSG);
@ -3984,6 +3989,9 @@ static void __devinit cciss_put_controller_into_performant_mode(ctlr_info_t *h)
{ {
__u32 trans_support; __u32 trans_support;
if (cciss_simple_mode)
return;
dev_dbg(&h->pdev->dev, "Trying to put board into Performant mode\n"); dev_dbg(&h->pdev->dev, "Trying to put board into Performant mode\n");
/* Attempt to put controller into performant mode if supported */ /* Attempt to put controller into performant mode if supported */
/* Does board support performant mode? */ /* Does board support performant mode? */
@ -4081,7 +4089,7 @@ static void __devinit cciss_interrupt_mode(ctlr_info_t *h)
default_int_mode: default_int_mode:
#endif /* CONFIG_PCI_MSI */ #endif /* CONFIG_PCI_MSI */
/* if we get here we're going to use the default interrupt mode */ /* if we get here we're going to use the default interrupt mode */
h->intr[PERF_MODE_INT] = h->pdev->irq; h->intr[h->intr_mode] = h->pdev->irq;
return; return;
} }
@ -4341,6 +4349,9 @@ static int __devinit cciss_pci_init(ctlr_info_t *h)
} }
cciss_enable_scsi_prefetch(h); cciss_enable_scsi_prefetch(h);
cciss_p600_dma_prefetch_quirk(h); cciss_p600_dma_prefetch_quirk(h);
err = cciss_enter_simple_mode(h);
if (err)
goto err_out_free_res;
cciss_put_controller_into_performant_mode(h); cciss_put_controller_into_performant_mode(h);
return 0; return 0;
@ -4843,20 +4854,20 @@ static int cciss_request_irq(ctlr_info_t *h,
irqreturn_t (*intxhandler)(int, void *)) irqreturn_t (*intxhandler)(int, void *))
{ {
if (h->msix_vector || h->msi_vector) { if (h->msix_vector || h->msi_vector) {
if (!request_irq(h->intr[PERF_MODE_INT], msixhandler, if (!request_irq(h->intr[h->intr_mode], msixhandler,
IRQF_DISABLED, h->devname, h)) IRQF_DISABLED, h->devname, h))
return 0; return 0;
dev_err(&h->pdev->dev, "Unable to get msi irq %d" dev_err(&h->pdev->dev, "Unable to get msi irq %d"
" for %s\n", h->intr[PERF_MODE_INT], " for %s\n", h->intr[h->intr_mode],
h->devname); h->devname);
return -1; return -1;
} }
if (!request_irq(h->intr[PERF_MODE_INT], intxhandler, if (!request_irq(h->intr[h->intr_mode], intxhandler,
IRQF_DISABLED, h->devname, h)) IRQF_DISABLED, h->devname, h))
return 0; return 0;
dev_err(&h->pdev->dev, "Unable to get irq %d for %s\n", dev_err(&h->pdev->dev, "Unable to get irq %d for %s\n",
h->intr[PERF_MODE_INT], h->devname); h->intr[h->intr_mode], h->devname);
return -1; return -1;
} }
@ -4887,7 +4898,7 @@ static void cciss_undo_allocations_after_kdump_soft_reset(ctlr_info_t *h)
{ {
int ctlr = h->ctlr; int ctlr = h->ctlr;
free_irq(h->intr[PERF_MODE_INT], h); free_irq(h->intr[h->intr_mode], h);
#ifdef CONFIG_PCI_MSI #ifdef CONFIG_PCI_MSI
if (h->msix_vector) if (h->msix_vector)
pci_disable_msix(h->pdev); pci_disable_msix(h->pdev);
@ -4953,6 +4964,7 @@ reinit_after_soft_reset:
h = hba[i]; h = hba[i];
h->pdev = pdev; h->pdev = pdev;
h->busy_initializing = 1; h->busy_initializing = 1;
h->intr_mode = cciss_simple_mode ? SIMPLE_MODE_INT : PERF_MODE_INT;
INIT_LIST_HEAD(&h->cmpQ); INIT_LIST_HEAD(&h->cmpQ);
INIT_LIST_HEAD(&h->reqQ); INIT_LIST_HEAD(&h->reqQ);
mutex_init(&h->busy_shutting_down); mutex_init(&h->busy_shutting_down);
@ -5009,7 +5021,7 @@ reinit_after_soft_reset:
dev_info(&h->pdev->dev, "%s: <0x%x> at PCI %s IRQ %d%s using DAC\n", dev_info(&h->pdev->dev, "%s: <0x%x> at PCI %s IRQ %d%s using DAC\n",
h->devname, pdev->device, pci_name(pdev), h->devname, pdev->device, pci_name(pdev),
h->intr[PERF_MODE_INT], dac ? "" : " not"); h->intr[h->intr_mode], dac ? "" : " not");
if (cciss_allocate_cmd_pool(h)) if (cciss_allocate_cmd_pool(h))
goto clean4; goto clean4;
@ -5056,7 +5068,7 @@ reinit_after_soft_reset:
spin_lock_irqsave(&h->lock, flags); spin_lock_irqsave(&h->lock, flags);
h->access.set_intr_mask(h, CCISS_INTR_OFF); h->access.set_intr_mask(h, CCISS_INTR_OFF);
spin_unlock_irqrestore(&h->lock, flags); spin_unlock_irqrestore(&h->lock, flags);
free_irq(h->intr[PERF_MODE_INT], h); free_irq(h->intr[h->intr_mode], h);
rc = cciss_request_irq(h, cciss_msix_discard_completions, rc = cciss_request_irq(h, cciss_msix_discard_completions,
cciss_intx_discard_completions); cciss_intx_discard_completions);
if (rc) { if (rc) {
@ -5133,7 +5145,7 @@ clean4:
cciss_free_cmd_pool(h); cciss_free_cmd_pool(h);
cciss_free_scatterlists(h); cciss_free_scatterlists(h);
cciss_free_sg_chain_blocks(h->cmd_sg_list, h->nr_cmds); cciss_free_sg_chain_blocks(h->cmd_sg_list, h->nr_cmds);
free_irq(h->intr[PERF_MODE_INT], h); free_irq(h->intr[h->intr_mode], h);
clean2: clean2:
unregister_blkdev(h->major, h->devname); unregister_blkdev(h->major, h->devname);
clean1: clean1:
@ -5172,9 +5184,31 @@ static void cciss_shutdown(struct pci_dev *pdev)
if (return_code != IO_OK) if (return_code != IO_OK)
dev_warn(&h->pdev->dev, "Error flushing cache\n"); dev_warn(&h->pdev->dev, "Error flushing cache\n");
h->access.set_intr_mask(h, CCISS_INTR_OFF); h->access.set_intr_mask(h, CCISS_INTR_OFF);
free_irq(h->intr[PERF_MODE_INT], h); free_irq(h->intr[h->intr_mode], h);
} }
static int __devinit cciss_enter_simple_mode(struct ctlr_info *h)
{
u32 trans_support;
trans_support = readl(&(h->cfgtable->TransportSupport));
if (!(trans_support & SIMPLE_MODE))
return -ENOTSUPP;
h->max_commands = readl(&(h->cfgtable->CmdsOutMax));
writel(CFGTBL_Trans_Simple, &(h->cfgtable->HostWrite.TransportRequest));
writel(CFGTBL_ChangeReq, h->vaddr + SA5_DOORBELL);
cciss_wait_for_mode_change_ack(h);
print_cfg_table(h);
if (!(readl(&(h->cfgtable->TransportActive)) & CFGTBL_Trans_Simple)) {
dev_warn(&h->pdev->dev, "unable to get board into simple mode\n");
return -ENODEV;
}
h->transMethod = CFGTBL_Trans_Simple;
return 0;
}
static void __devexit cciss_remove_one(struct pci_dev *pdev) static void __devexit cciss_remove_one(struct pci_dev *pdev)
{ {
ctlr_info_t *h; ctlr_info_t *h;

View File

@ -92,6 +92,7 @@ struct ctlr_info
unsigned int intr[4]; unsigned int intr[4];
unsigned int msix_vector; unsigned int msix_vector;
unsigned int msi_vector; unsigned int msi_vector;
int intr_mode;
int cciss_max_sectors; int cciss_max_sectors;
BYTE cciss_read; BYTE cciss_read;
BYTE cciss_write; BYTE cciss_write;