diff options
Diffstat (limited to 'drivers/scsi/mvsas/mv_init.c')
| -rw-r--r-- | drivers/scsi/mvsas/mv_init.c | 318 |
1 files changed, 243 insertions, 75 deletions
diff --git a/drivers/scsi/mvsas/mv_init.c b/drivers/scsi/mvsas/mv_init.c index cae6b2cf492..eacee48a955 100644 --- a/drivers/scsi/mvsas/mv_init.c +++ b/drivers/scsi/mvsas/mv_init.c @@ -3,6 +3,7 @@ * * Copyright 2007 Red Hat, Inc. * Copyright 2008 Marvell. <kewei@marvell.com> + * Copyright 2009-2011 Marvell. <yuxiangl@marvell.com> * * This file is licensed under GPLv2. * @@ -25,17 +26,32 @@ #include "mv_sas.h" +static int lldd_max_execute_num = 1; +module_param_named(collector, lldd_max_execute_num, int, S_IRUGO); +MODULE_PARM_DESC(collector, "\n" + "\tIf greater than one, tells the SAS Layer to run in Task Collector\n" + "\tMode. If 1 or 0, tells the SAS Layer to run in Direct Mode.\n" + "\tThe mvsas SAS LLDD supports both modes.\n" + "\tDefault: 1 (Direct Mode).\n"); + +int interrupt_coalescing = 0x80; + static struct scsi_transport_template *mvs_stt; +struct kmem_cache *mvs_task_list_cache; static const struct mvs_chip_info mvs_chips[] = { - [chip_6320] = { 1, 2, 0x400, 17, 16, 9, &mvs_64xx_dispatch, }, - [chip_6440] = { 1, 4, 0x400, 17, 16, 9, &mvs_64xx_dispatch, }, - [chip_6485] = { 1, 8, 0x800, 33, 32, 10, &mvs_64xx_dispatch, }, - [chip_9180] = { 2, 4, 0x800, 17, 64, 9, &mvs_94xx_dispatch, }, - [chip_9480] = { 2, 4, 0x800, 17, 64, 9, &mvs_94xx_dispatch, }, - [chip_1300] = { 1, 4, 0x400, 17, 16, 9, &mvs_64xx_dispatch, }, - [chip_1320] = { 2, 4, 0x800, 17, 64, 9, &mvs_94xx_dispatch, }, + [chip_6320] = { 1, 2, 0x400, 17, 16, 6, 9, &mvs_64xx_dispatch, }, + [chip_6440] = { 1, 4, 0x400, 17, 16, 6, 9, &mvs_64xx_dispatch, }, + [chip_6485] = { 1, 8, 0x800, 33, 32, 6, 10, &mvs_64xx_dispatch, }, + [chip_9180] = { 2, 4, 0x800, 17, 64, 8, 9, &mvs_94xx_dispatch, }, + [chip_9480] = { 2, 4, 0x800, 17, 64, 8, 9, &mvs_94xx_dispatch, }, + [chip_9445] = { 1, 4, 0x800, 17, 64, 8, 11, &mvs_94xx_dispatch, }, + [chip_9485] = { 2, 4, 0x800, 17, 64, 8, 11, &mvs_94xx_dispatch, }, + [chip_1300] = { 1, 4, 0x400, 17, 16, 6, 9, &mvs_64xx_dispatch, }, + [chip_1320] = { 2, 4, 0x800, 17, 64, 8, 9, &mvs_94xx_dispatch, }, }; +struct device_attribute *mvst_host_attrs[]; + #define SOC_SAS_NUM 2 static struct scsi_host_template mvs_sht = { @@ -43,8 +59,7 @@ static struct scsi_host_template mvs_sht = { .name = DRV_NAME, .queuecommand = sas_queuecommand, .target_alloc = sas_target_alloc, - .slave_configure = mvs_slave_configure, - .slave_destroy = sas_slave_destroy, + .slave_configure = sas_slave_configure, .scan_finished = mvs_scan_finished, .scan_start = mvs_scan_start, .change_queue_depth = sas_change_queue_depth, @@ -56,39 +71,38 @@ static struct scsi_host_template mvs_sht = { .sg_tablesize = SG_ALL, .max_sectors = SCSI_DEFAULT_MAX_SECTORS, .use_clustering = ENABLE_CLUSTERING, - .eh_device_reset_handler = sas_eh_device_reset_handler, + .eh_device_reset_handler = sas_eh_device_reset_handler, .eh_bus_reset_handler = sas_eh_bus_reset_handler, - .slave_alloc = mvs_slave_alloc, .target_destroy = sas_target_destroy, .ioctl = sas_ioctl, + .shost_attrs = mvst_host_attrs, }; static struct sas_domain_function_template mvs_transport_ops = { .lldd_dev_found = mvs_dev_found, - .lldd_dev_gone = mvs_dev_gone, - + .lldd_dev_gone = mvs_dev_gone, .lldd_execute_task = mvs_queue_command, .lldd_control_phy = mvs_phy_control, .lldd_abort_task = mvs_abort_task, .lldd_abort_task_set = mvs_abort_task_set, .lldd_clear_aca = mvs_clear_aca, - .lldd_clear_task_set = mvs_clear_task_set, + .lldd_clear_task_set = mvs_clear_task_set, .lldd_I_T_nexus_reset = mvs_I_T_nexus_reset, .lldd_lu_reset = mvs_lu_reset, .lldd_query_task = mvs_query_task, - .lldd_port_formed = mvs_port_formed, .lldd_port_deformed = mvs_port_deformed, }; -static void __devinit mvs_phy_init(struct mvs_info *mvi, int phy_id) +static void mvs_phy_init(struct mvs_info *mvi, int phy_id) { struct mvs_phy *phy = &mvi->phy[phy_id]; struct asd_sas_phy *sas_phy = &phy->sas_phy; phy->mvi = mvi; + phy->port = NULL; init_timer(&phy->timer); sas_phy->enabled = (phy_id < mvi->chip->n_phy) ? 1 : 0; sas_phy->class = SAS; @@ -108,7 +122,6 @@ static void __devinit mvs_phy_init(struct mvs_info *mvi, int phy_id) static void mvs_free(struct mvs_info *mvi) { - int i; struct mvs_wq *mwq; int slot_nr; @@ -118,14 +131,10 @@ static void mvs_free(struct mvs_info *mvi) if (mvi->flags & MVF_FLAG_SOC) slot_nr = MVS_SOC_SLOTS; else - slot_nr = MVS_SLOTS; + slot_nr = MVS_CHIP_SLOT_SZ; - for (i = 0; i < mvi->tags_num; i++) { - struct mvs_slot_info *slot = &mvi->slot_info[i]; - if (slot->buf) - dma_free_coherent(mvi->dev, MVS_SLOT_BUF_SZ, - slot->buf, slot->buf_dma); - } + if (mvi->dma_pool) + pci_pool_destroy(mvi->dma_pool); if (mvi->tx) dma_free_coherent(mvi->dev, @@ -142,25 +151,26 @@ static void mvs_free(struct mvs_info *mvi) dma_free_coherent(mvi->dev, sizeof(*mvi->slot) * slot_nr, mvi->slot, mvi->slot_dma); -#ifndef DISABLE_HOTPLUG_DMA_FIX + if (mvi->bulk_buffer) dma_free_coherent(mvi->dev, TRASH_BUCKET_SIZE, mvi->bulk_buffer, mvi->bulk_buffer_dma); -#endif + if (mvi->bulk_buffer1) + dma_free_coherent(mvi->dev, TRASH_BUCKET_SIZE, + mvi->bulk_buffer1, mvi->bulk_buffer_dma1); MVS_CHIP_DISP->chip_iounmap(mvi); if (mvi->shost) scsi_host_put(mvi->shost); list_for_each_entry(mwq, &mvi->wq_list, entry) cancel_delayed_work(&mwq->work_q); + kfree(mvi->tags); kfree(mvi); } -#ifdef MVS_USE_TASKLET -struct tasklet_struct mv_tasklet; +#ifdef CONFIG_SCSI_MVSAS_TASKLET static void mvs_tasklet(unsigned long opaque) { - unsigned long flags; u32 stat; u16 core_nr, i = 0; @@ -173,35 +183,49 @@ static void mvs_tasklet(unsigned long opaque) if (unlikely(!mvi)) BUG_ON(1); + stat = MVS_CHIP_DISP->isr_status(mvi, mvi->pdev->irq); + if (!stat) + goto out; + for (i = 0; i < core_nr; i++) { mvi = ((struct mvs_prv_info *)sha->lldd_ha)->mvi[i]; - stat = MVS_CHIP_DISP->isr_status(mvi, mvi->irq); - if (stat) - MVS_CHIP_DISP->isr(mvi, mvi->irq, stat); + MVS_CHIP_DISP->isr(mvi, mvi->pdev->irq, stat); } +out: + MVS_CHIP_DISP->interrupt_enable(mvi); } #endif static irqreturn_t mvs_interrupt(int irq, void *opaque) { - u32 core_nr, i = 0; + u32 core_nr; u32 stat; struct mvs_info *mvi; struct sas_ha_struct *sha = opaque; +#ifndef CONFIG_SCSI_MVSAS_TASKLET + u32 i; +#endif core_nr = ((struct mvs_prv_info *)sha->lldd_ha)->n_host; mvi = ((struct mvs_prv_info *)sha->lldd_ha)->mvi[0]; if (unlikely(!mvi)) return IRQ_NONE; +#ifdef CONFIG_SCSI_MVSAS_TASKLET + MVS_CHIP_DISP->interrupt_disable(mvi); +#endif stat = MVS_CHIP_DISP->isr_status(mvi, irq); - if (!stat) + if (!stat) { + #ifdef CONFIG_SCSI_MVSAS_TASKLET + MVS_CHIP_DISP->interrupt_enable(mvi); + #endif return IRQ_NONE; + } -#ifdef MVS_USE_TASKLET - tasklet_schedule(&mv_tasklet); +#ifdef CONFIG_SCSI_MVSAS_TASKLET + tasklet_schedule(&((struct mvs_prv_info *)sha->lldd_ha)->mv_tasklet); #else for (i = 0; i < core_nr; i++) { mvi = ((struct mvs_prv_info *)sha->lldd_ha)->mvi[i]; @@ -211,14 +235,15 @@ static irqreturn_t mvs_interrupt(int irq, void *opaque) return IRQ_HANDLED; } -static int __devinit mvs_alloc(struct mvs_info *mvi, struct Scsi_Host *shost) +static int mvs_alloc(struct mvs_info *mvi, struct Scsi_Host *shost) { - int i, slot_nr; + int i = 0, slot_nr; + char pool_name[32]; if (mvi->flags & MVF_FLAG_SOC) slot_nr = MVS_SOC_SLOTS; else - slot_nr = MVS_SLOTS; + slot_nr = MVS_CHIP_SLOT_SZ; spin_lock_init(&mvi->lock); for (i = 0; i < mvi->chip->n_phy; i++) { @@ -229,9 +254,10 @@ static int __devinit mvs_alloc(struct mvs_info *mvi, struct Scsi_Host *shost) } for (i = 0; i < MVS_MAX_DEVICES; i++) { mvi->devices[i].taskfileset = MVS_ID_NOT_MAPPED; - mvi->devices[i].dev_type = NO_DEVICE; + mvi->devices[i].dev_type = SAS_PHY_UNUSED; mvi->devices[i].device_id = i; mvi->devices[i].dev_status = MVS_DEV_NORMAL; + init_timer(&mvi->devices[i].timer); } /* @@ -265,25 +291,26 @@ static int __devinit mvs_alloc(struct mvs_info *mvi, struct Scsi_Host *shost) goto err_out; memset(mvi->slot, 0, sizeof(*mvi->slot) * slot_nr); -#ifndef DISABLE_HOTPLUG_DMA_FIX mvi->bulk_buffer = dma_alloc_coherent(mvi->dev, TRASH_BUCKET_SIZE, &mvi->bulk_buffer_dma, GFP_KERNEL); if (!mvi->bulk_buffer) goto err_out; -#endif - for (i = 0; i < slot_nr; i++) { - struct mvs_slot_info *slot = &mvi->slot_info[i]; - slot->buf = dma_alloc_coherent(mvi->dev, MVS_SLOT_BUF_SZ, - &slot->buf_dma, GFP_KERNEL); - if (!slot->buf) { - printk(KERN_DEBUG"failed to allocate slot->buf.\n"); + mvi->bulk_buffer1 = dma_alloc_coherent(mvi->dev, + TRASH_BUCKET_SIZE, + &mvi->bulk_buffer_dma1, GFP_KERNEL); + if (!mvi->bulk_buffer1) + goto err_out; + + sprintf(pool_name, "%s%d", "mvs_dma_pool", mvi->id); + mvi->dma_pool = pci_pool_create(pool_name, mvi->pdev, MVS_SLOT_BUF_SZ, 16, 0); + if (!mvi->dma_pool) { + printk(KERN_DEBUG "failed to create dma pool %s.\n", pool_name); goto err_out; - } - memset(slot->buf, 0, MVS_SLOT_BUF_SZ); - ++mvi->tags_num; } + mvi->tags_num = slot_nr; + /* Initialize tags */ mvs_tag_init(mvi); return 0; @@ -346,15 +373,16 @@ void mvs_iounmap(void __iomem *regs) iounmap(regs); } -static struct mvs_info *__devinit mvs_pci_alloc(struct pci_dev *pdev, +static struct mvs_info *mvs_pci_alloc(struct pci_dev *pdev, const struct pci_device_id *ent, struct Scsi_Host *shost, unsigned int id) { - struct mvs_info *mvi; + struct mvs_info *mvi = NULL; struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); - mvi = kzalloc(sizeof(*mvi) + MVS_SLOTS * sizeof(struct mvs_slot_info), - GFP_KERNEL); + mvi = kzalloc(sizeof(*mvi) + + (1L << mvs_chips[ent->driver_data].slot_width) * + sizeof(struct mvs_slot_info), GFP_KERNEL); if (!mvi) return NULL; @@ -363,7 +391,6 @@ static struct mvs_info *__devinit mvs_pci_alloc(struct pci_dev *pdev, mvi->chip_id = ent->driver_data; mvi->chip = &mvs_chips[mvi->chip_id]; INIT_LIST_HEAD(&mvi->wq_list); - mvi->irq = pdev->irq; ((struct mvs_prv_info *)sha->lldd_ha)->mvi[id] = mvi; ((struct mvs_prv_info *)sha->lldd_ha)->n_phy = mvi->chip->n_phy; @@ -371,9 +398,10 @@ static struct mvs_info *__devinit mvs_pci_alloc(struct pci_dev *pdev, mvi->id = id; mvi->sas = sha; mvi->shost = shost; -#ifdef MVS_USE_TASKLET - tasklet_init(&mv_tasklet, mvs_tasklet, (unsigned long)sha); -#endif + + mvi->tags = kzalloc(MVS_CHIP_SLOT_SZ>>3, GFP_KERNEL); + if (!mvi->tags) + goto err_out; if (MVS_CHIP_DISP->chip_ioremap(mvi)) goto err_out; @@ -384,7 +412,6 @@ err_out: return NULL; } -/* move to PCI layer or libata core? */ static int pci_go_64(struct pci_dev *pdev) { int rc; @@ -417,7 +444,7 @@ static int pci_go_64(struct pci_dev *pdev) return rc; } -static int __devinit mvs_prep_sas_ha_init(struct Scsi_Host *shost, +static int mvs_prep_sas_ha_init(struct Scsi_Host *shost, const struct mvs_chip_info *chip_info) { int phy_nr, port_nr; unsigned short core_nr; @@ -437,6 +464,7 @@ static int __devinit mvs_prep_sas_ha_init(struct Scsi_Host *shost, sha->sas_phy = arr_phy; sha->sas_port = arr_port; + sha->core.shost = shost; sha->lldd_ha = kzalloc(sizeof(struct mvs_prv_info), GFP_KERNEL); if (!sha->lldd_ha) @@ -445,7 +473,7 @@ static int __devinit mvs_prep_sas_ha_init(struct Scsi_Host *shost, ((struct mvs_prv_info *)sha->lldd_ha)->n_host = core_nr; shost->transportt = mvs_stt; - shost->max_id = 128; + shost->max_id = MVS_MAX_DEVICES; shost->max_lun = ~0; shost->max_channel = 1; shost->max_cmd_len = 16; @@ -458,7 +486,7 @@ exit_free: } -static void __devinit mvs_post_sas_ha_init(struct Scsi_Host *shost, +static void mvs_post_sas_ha_init(struct Scsi_Host *shost, const struct mvs_chip_info *chip_info) { int can_queue, i = 0, j = 0; @@ -483,16 +511,17 @@ static void __devinit mvs_post_sas_ha_init(struct Scsi_Host *shost, sha->num_phys = nr_core * chip_info->n_phy; - sha->lldd_max_execute_num = 1; + sha->lldd_max_execute_num = lldd_max_execute_num; if (mvi->flags & MVF_FLAG_SOC) can_queue = MVS_SOC_CAN_QUEUE; else - can_queue = MVS_CAN_QUEUE; + can_queue = MVS_CHIP_SLOT_SZ; sha->lldd_queue_size = can_queue; + shost->sg_tablesize = min_t(u16, SG_ALL, MVS_MAX_SG); shost->can_queue = can_queue; - mvi->shost->cmd_per_lun = MVS_SLOTS/sha->num_phys; + mvi->shost->cmd_per_lun = MVS_QUEUE_SIZE; sha->core.shost = mvi->shost; } @@ -508,11 +537,11 @@ static void mvs_init_sas_add(struct mvs_info *mvi) memcpy(mvi->sas_addr, &mvi->phy[0].dev_sas_addr, SAS_ADDR_SIZE); } -static int __devinit mvs_pci_init(struct pci_dev *pdev, - const struct pci_device_id *ent) +static int mvs_pci_init(struct pci_dev *pdev, const struct pci_device_id *ent) { unsigned int rc, nhost = 0; struct mvs_info *mvi; + struct mvs_prv_info *mpi; irq_handler_t irq_handler = mvs_interrupt; struct Scsi_Host *shost = NULL; const struct mvs_chip_info *chip; @@ -564,6 +593,9 @@ static int __devinit mvs_pci_init(struct pci_dev *pdev, goto err_out_regions; } + memset(&mvi->hba_info_param, 0xFF, + sizeof(struct hba_info_page)); + mvs_init_sas_add(mvi); mvi->instance = nhost; @@ -574,6 +606,11 @@ static int __devinit mvs_pci_init(struct pci_dev *pdev, } nhost++; } while (nhost < chip->n_host); + mpi = (struct mvs_prv_info *)(SHOST_TO_SAS_HA(shost)->lldd_ha); +#ifdef CONFIG_SCSI_MVSAS_TASKLET + tasklet_init(&(mpi->mv_tasklet), mvs_tasklet, + (unsigned long)SHOST_TO_SAS_HA(shost)); +#endif mvs_post_sas_ha_init(shost, chip); @@ -607,7 +644,7 @@ err_out_enable: return rc; } -static void __devexit mvs_pci_remove(struct pci_dev *pdev) +static void mvs_pci_remove(struct pci_dev *pdev) { unsigned short core_nr, i = 0; struct sas_ha_struct *sha = pci_get_drvdata(pdev); @@ -616,17 +653,16 @@ static void __devexit mvs_pci_remove(struct pci_dev *pdev) core_nr = ((struct mvs_prv_info *)sha->lldd_ha)->n_host; mvi = ((struct mvs_prv_info *)sha->lldd_ha)->mvi[0]; -#ifdef MVS_USE_TASKLET - tasklet_kill(&mv_tasklet); +#ifdef CONFIG_SCSI_MVSAS_TASKLET + tasklet_kill(&((struct mvs_prv_info *)sha->lldd_ha)->mv_tasklet); #endif - pci_set_drvdata(pdev, NULL); sas_unregister_ha(sha); sas_remove_host(mvi->shost); scsi_remove_host(mvi->shost); MVS_CHIP_DISP->interrupt_disable(mvi); - free_irq(mvi->irq, sha); + free_irq(mvi->pdev->irq, sha); for (i = 0; i < core_nr; i++) { mvi = ((struct mvs_prv_info *)sha->lldd_ha)->mvi[i]; mvs_free(mvi); @@ -639,7 +675,7 @@ static void __devexit mvs_pci_remove(struct pci_dev *pdev) return; } -static struct pci_device_id __devinitdata mvs_pci_table[] = { +static struct pci_device_id mvs_pci_table[] = { { PCI_VDEVICE(MARVELL, 0x6320), chip_6320 }, { PCI_VDEVICE(MARVELL, 0x6340), chip_6440 }, { @@ -658,6 +694,59 @@ static struct pci_device_id __devinitdata mvs_pci_table[] = { { PCI_VDEVICE(ARECA, PCI_DEVICE_ID_ARECA_1300), chip_1300 }, { PCI_VDEVICE(ARECA, PCI_DEVICE_ID_ARECA_1320), chip_1320 }, { PCI_VDEVICE(ADAPTEC2, 0x0450), chip_6440 }, + { PCI_VDEVICE(TTI, 0x2710), chip_9480 }, + { PCI_VDEVICE(TTI, 0x2720), chip_9480 }, + { PCI_VDEVICE(TTI, 0x2721), chip_9480 }, + { PCI_VDEVICE(TTI, 0x2722), chip_9480 }, + { PCI_VDEVICE(TTI, 0x2740), chip_9480 }, + { PCI_VDEVICE(TTI, 0x2744), chip_9480 }, + { PCI_VDEVICE(TTI, 0x2760), chip_9480 }, + { + .vendor = PCI_VENDOR_ID_MARVELL_EXT, + .device = 0x9480, + .subvendor = PCI_ANY_ID, + .subdevice = 0x9480, + .class = 0, + .class_mask = 0, + .driver_data = chip_9480, + }, + { + .vendor = PCI_VENDOR_ID_MARVELL_EXT, + .device = 0x9445, + .subvendor = PCI_ANY_ID, + .subdevice = 0x9480, + .class = 0, + .class_mask = 0, + .driver_data = chip_9445, + }, + { + .vendor = PCI_VENDOR_ID_MARVELL_EXT, + .device = 0x9485, + .subvendor = PCI_ANY_ID, + .subdevice = 0x9480, + .class = 0, + .class_mask = 0, + .driver_data = chip_9485, + }, + { + .vendor = PCI_VENDOR_ID_MARVELL_EXT, + .device = 0x9485, + .subvendor = PCI_ANY_ID, + .subdevice = 0x9485, + .class = 0, + .class_mask = 0, + .driver_data = chip_9485, + }, + { PCI_VDEVICE(OCZ, 0x1021), chip_9485}, /* OCZ RevoDrive3 */ + { PCI_VDEVICE(OCZ, 0x1022), chip_9485}, /* OCZ RevoDrive3/zDriveR4 (exact model unknown) */ + { PCI_VDEVICE(OCZ, 0x1040), chip_9485}, /* OCZ RevoDrive3/zDriveR4 (exact model unknown) */ + { PCI_VDEVICE(OCZ, 0x1041), chip_9485}, /* OCZ RevoDrive3/zDriveR4 (exact model unknown) */ + { PCI_VDEVICE(OCZ, 0x1042), chip_9485}, /* OCZ RevoDrive3/zDriveR4 (exact model unknown) */ + { PCI_VDEVICE(OCZ, 0x1043), chip_9485}, /* OCZ RevoDrive3/zDriveR4 (exact model unknown) */ + { PCI_VDEVICE(OCZ, 0x1044), chip_9485}, /* OCZ RevoDrive3/zDriveR4 (exact model unknown) */ + { PCI_VDEVICE(OCZ, 0x1080), chip_9485}, /* OCZ RevoDrive3/zDriveR4 (exact model unknown) */ + { PCI_VDEVICE(OCZ, 0x1083), chip_9485}, /* OCZ RevoDrive3/zDriveR4 (exact model unknown) */ + { PCI_VDEVICE(OCZ, 0x1084), chip_9485}, /* OCZ RevoDrive3/zDriveR4 (exact model unknown) */ { } /* terminate list */ }; @@ -666,9 +755,73 @@ static struct pci_driver mvs_pci_driver = { .name = DRV_NAME, .id_table = mvs_pci_table, .probe = mvs_pci_init, - .remove = __devexit_p(mvs_pci_remove), + .remove = mvs_pci_remove, }; +static ssize_t +mvs_show_driver_version(struct device *cdev, + struct device_attribute *attr, char *buffer) +{ + return snprintf(buffer, PAGE_SIZE, "%s\n", DRV_VERSION); +} + +static DEVICE_ATTR(driver_version, + S_IRUGO, + mvs_show_driver_version, + NULL); + +static ssize_t +mvs_store_interrupt_coalescing(struct device *cdev, + struct device_attribute *attr, + const char *buffer, size_t size) +{ + int val = 0; + struct mvs_info *mvi = NULL; + struct Scsi_Host *shost = class_to_shost(cdev); + struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); + u8 i, core_nr; + if (buffer == NULL) + return size; + + if (sscanf(buffer, "%d", &val) != 1) + return -EINVAL; + + if (val >= 0x10000) { + mv_dprintk("interrupt coalescing timer %d us is" + "too long\n", val); + return strlen(buffer); + } + + interrupt_coalescing = val; + + core_nr = ((struct mvs_prv_info *)sha->lldd_ha)->n_host; + mvi = ((struct mvs_prv_info *)sha->lldd_ha)->mvi[0]; + + if (unlikely(!mvi)) + return -EINVAL; + + for (i = 0; i < core_nr; i++) { + mvi = ((struct mvs_prv_info *)sha->lldd_ha)->mvi[i]; + if (MVS_CHIP_DISP->tune_interrupt) + MVS_CHIP_DISP->tune_interrupt(mvi, + interrupt_coalescing); + } + mv_dprintk("set interrupt coalescing time to %d us\n", + interrupt_coalescing); + return strlen(buffer); +} + +static ssize_t mvs_show_interrupt_coalescing(struct device *cdev, + struct device_attribute *attr, char *buffer) +{ + return snprintf(buffer, PAGE_SIZE, "%d\n", interrupt_coalescing); +} + +static DEVICE_ATTR(interrupt_coalescing, + S_IRUGO|S_IWUSR, + mvs_show_interrupt_coalescing, + mvs_store_interrupt_coalescing); + /* task handler */ struct task_struct *mvs_th; static int __init mvs_init(void) @@ -678,6 +831,14 @@ static int __init mvs_init(void) if (!mvs_stt) return -ENOMEM; + mvs_task_list_cache = kmem_cache_create("mvs_task_list", sizeof(struct mvs_task_list), + 0, SLAB_HWCACHE_ALIGN, NULL); + if (!mvs_task_list_cache) { + rc = -ENOMEM; + mv_printk("%s: mvs_task_list_cache alloc failed! \n", __func__); + goto err_out; + } + rc = pci_register_driver(&mvs_pci_driver); if (rc) @@ -694,8 +855,15 @@ static void __exit mvs_exit(void) { pci_unregister_driver(&mvs_pci_driver); sas_release_transport(mvs_stt); + kmem_cache_destroy(mvs_task_list_cache); } +struct device_attribute *mvst_host_attrs[] = { + &dev_attr_driver_version, + &dev_attr_interrupt_coalescing, + NULL, +}; + module_init(mvs_init); module_exit(mvs_exit); |
