diff options
Diffstat (limited to 'drivers/scsi/mvsas/mv_init.c')
| -rw-r--r-- | drivers/scsi/mvsas/mv_init.c | 309 | 
1 files changed, 236 insertions, 73 deletions
diff --git a/drivers/scsi/mvsas/mv_init.c b/drivers/scsi/mvsas/mv_init.c index 19ad34f381a..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,27 +26,40 @@  #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 -#define SG_MX 64  static struct scsi_host_template mvs_sht = {  	.module			= THIS_MODULE,  	.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, @@ -54,14 +68,14 @@ static struct scsi_host_template mvs_sht = {  	.can_queue		= 1,  	.cmd_per_lun		= 1,  	.this_id		= -1, -	.sg_tablesize		= SG_MX, +	.sg_tablesize		= SG_ALL,  	.max_sectors		= SCSI_DEFAULT_MAX_SECTORS,  	.use_clustering		= ENABLE_CLUSTERING,  	.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 = { @@ -82,12 +96,13 @@ static struct sas_domain_function_template mvs_transport_ops = {  }; -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; @@ -107,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; @@ -117,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, @@ -141,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; @@ -172,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]; @@ -210,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 = 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++) { @@ -228,7 +254,7 @@ 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; @@ -446,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; @@ -459,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; @@ -484,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;  } @@ -509,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; @@ -565,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; @@ -575,8 +606,9 @@ static int __devinit mvs_pci_init(struct pci_dev *pdev,  		}  		nhost++;  	} while (nhost < chip->n_host); -#ifdef MVS_USE_TASKLET -	tasklet_init(&mv_tasklet, mvs_tasklet, +	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 @@ -612,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); @@ -621,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); @@ -644,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 },  	{ @@ -663,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 */  }; @@ -671,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) @@ -683,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) @@ -699,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);  | 
