[PATCH 2/7]MVSAS:add supporting MSI feature

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



>From 8b51aa63e8b123046a334d630ae045f479acbf6c Mon Sep 17 00:00:00 2001
From: andy <ayan@xxxxxxxxxxx>
Date: Fri, 6 Nov 2009 17:03:21 +0800
Subject: [PATCH 2/7] Add supporting MSI feature

MSI feature is implemented with mvsas driver.

Signed-off-by: Andy <ayan@xxxxxxxxxxx>
Signed-off-by: Jacky <jfeng@xxxxxxxxxxx>
Signed-off-by: Ke <kewei@xxxxxxxxxxx>

---
 drivers/scsi/mvsas/mv_init.c |  113 ++++++++++++++++++++++++++++++++++++++++--
 drivers/scsi/mvsas/mv_sas.c  |   28 ++++++-----
 drivers/scsi/mvsas/mv_sas.h  |    2 +
 3 files changed, 126 insertions(+), 17 deletions(-)

diff --git a/drivers/scsi/mvsas/mv_init.c b/drivers/scsi/mvsas/mv_init.c
index c790d45..d030959 100644
--- a/drivers/scsi/mvsas/mv_init.c
+++ b/drivers/scsi/mvsas/mv_init.c
@@ -25,6 +25,10 @@
 
 #include "mv_sas.h"
 
+static int msi;
+module_param(msi, int, 0);
+MODULE_PARM_DESC(msi, "Enable Message Signaled Interrupts(0=off, 1=on)");
+int io_delay;
 static struct scsi_transport_template *mvs_stt;
 static const struct mvs_chip_info mvs_chips[] = {
 	[chip_6320] =	{ 1, 2, 0x400, 17, 16,  9, &mvs_64xx_dispatch, },
@@ -36,11 +40,13 @@ static const struct mvs_chip_info mvs_chips[] = {
 	[chip_1320] =	{ 2, 4, 0x800, 17, 64,  9, &mvs_94xx_dispatch, },
 };
 
+struct device_attribute *mvst_host_attrs[];
 #define SOC_SAS_NUM 2
 
 static struct scsi_host_template mvs_sht = {
 	.module			= THIS_MODULE,
-	.name			= DRV_NAME,
+	.name			= "Marvell Storage Controller",
+	.proc_name		= DRV_NAME,
 	.queuecommand		= sas_queuecommand,
 	.target_alloc		= sas_target_alloc,
 	.slave_configure	= mvs_slave_configure,
@@ -61,6 +67,7 @@ static struct scsi_host_template mvs_sht = {
 	.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 = {
@@ -89,6 +96,7 @@ static void __devinit mvs_phy_init(struct mvs_info *mvi, int 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;
@@ -118,7 +126,7 @@ 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];
@@ -183,6 +191,30 @@ static void mvs_tasklet(unsigned long opaque)
 }
 #endif
 
+void mvs_enable_msi(struct mvs_info *mvi)
+{
+	u32 tmp;
+	pci_read_config_dword(mvi->pdev, PCR_CMD, &tmp);
+	tmp |= 1 << 10;    	/* disable interrupt */
+	pci_write_config_dword(mvi->pdev, PCR_CMD, tmp);
+
+	pci_read_config_dword(mvi->pdev, PCR_MSI_CTRL, &tmp);
+	tmp |= 1 << 16; 		/* enable MSI */
+	pci_write_config_dword(mvi->pdev, PCR_MSI_CTRL, tmp);
+}
+void mvs_disable_msi(struct mvs_info *mvi)
+{
+	u32 tmp;
+	pci_read_config_dword(mvi->pdev, PCR_CMD, &tmp);
+	tmp &= ~(1 << 10);    	/* enable interrupt */
+	pci_write_config_dword(mvi->pdev, PCR_CMD, tmp);
+
+	pci_read_config_dword(mvi->pdev, PCR_MSI_CTRL, &tmp);
+	tmp &= ~(1 << 16); 	/* disable MSI */
+	pci_write_config_dword(mvi->pdev, PCR_MSI_CTRL, tmp);
+}
+
+
 static irqreturn_t mvs_interrupt(int irq, void *opaque)
 {
 	u32 core_nr, i = 0;
@@ -519,6 +551,7 @@ static int __devinit mvs_pci_init(struct pci_dev *pdev,
 
 	dev_printk(KERN_INFO, &pdev->dev,
 		"mvsas: driver version %s\n", DRV_VERSION);
+	io_delay = 0;
 	rc = pci_enable_device(pdev);
 	if (rc)
 		goto err_out_enable;
@@ -563,6 +596,8 @@ static int __devinit mvs_pci_init(struct pci_dev *pdev,
 			rc = -ENOMEM;
 			goto err_out_regions;
 		}
+		if (msi)
+			mvi->flags |= MVF_MSI;
 
 		mvs_init_sas_add(mvi);
 
@@ -581,13 +616,22 @@ static int __devinit mvs_pci_init(struct pci_dev *pdev,
 	if (rc)
 		goto err_out_shost;
 
+	if (mvi->flags & MVF_MSI) {
+		pci_enable_msi(pdev);
+		mvs_enable_msi(mvi);
+	}
 	rc = sas_register_ha(SHOST_TO_SAS_HA(shost));
 	if (rc)
 		goto err_out_shost;
 	rc = request_irq(pdev->irq, irq_handler, IRQF_SHARED,
 		DRV_NAME, SHOST_TO_SAS_HA(shost));
-	if (rc)
+	if (rc) {
+		if (mvi->flags & MVF_MSI) {
+			mvs_disable_msi(mvi);
+			pci_disable_msi(pdev);
+		}
 		goto err_not_sas;
+	}
 
 	MVS_CHIP_DISP->interrupt_enable(mvi);
 
@@ -620,13 +664,16 @@ static void __devexit mvs_pci_remove(struct pci_dev *pdev)
 	tasklet_kill(&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);
+	if (mvi->flags & MVF_MSI) {
+		mvs_disable_msi(mvi);
+		pci_disable_msi(pdev);
+	}
 	for (i = 0; i < core_nr; i++) {
 		mvi = ((struct mvs_prv_info *)sha->lldd_ha)->mvi[i];
 		mvs_free(mvi);
@@ -634,6 +681,7 @@ static void __devexit mvs_pci_remove(struct pci_dev *pdev)
 	kfree(sha->sas_phy);
 	kfree(sha->sas_port);
 	kfree(sha);
+	pci_set_drvdata(pdev, NULL);
 	pci_release_regions(pdev);
 	pci_disable_device(pdev);
 	return;
@@ -668,6 +716,57 @@ static struct pci_driver mvs_pci_driver = {
 	.remove		= __devexit_p(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_io_delay(struct device *cdev,
+			struct device_attribute *attr,
+			const char *buffer, size_t size)
+{
+
+	int val = 0;
+
+	if (buffer == NULL)
+		return size;
+
+	if (sscanf(buffer, "%d", &val) != 1)
+		return -EINVAL;
+
+	io_delay = val;
+	if (io_delay > 10) {
+		printk(KERN_NOTICE "io delay time %d seconds is too long, \
+			max is 10s\n",  io_delay);
+		io_delay = 10;
+		return strlen(buffer);
+	}
+	printk(KERN_NOTICE "set io delay time to %d seconds\n",  io_delay);
+	return strlen(buffer);
+}
+
+static ssize_t mvs_show_io_delay(struct device *cdev,
+				struct device_attribute *attr,
+				char *buffer)
+{
+	return snprintf(buffer, PAGE_SIZE, "%d\n", io_delay);
+}
+
+
+static DEVICE_ATTR(io_delay,
+			 S_IRUGO|S_IWUSR,
+			 mvs_show_io_delay,
+			 mvs_store_io_delay);
+
 /* task handler */
 struct task_struct *mvs_th;
 static int __init mvs_init(void)
@@ -695,6 +794,12 @@ static void __exit mvs_exit(void)
 	sas_release_transport(mvs_stt);
 }
 
+struct device_attribute *mvst_host_attrs[] = {
+	&dev_attr_driver_version,
+	&dev_attr_io_delay,
+	NULL,
+};
+
 module_init(mvs_init);
 module_exit(mvs_exit);
 
diff --git a/drivers/scsi/mvsas/mv_sas.c b/drivers/scsi/mvsas/mv_sas.c
index 0d21386..4fe365a 100644
--- a/drivers/scsi/mvsas/mv_sas.c
+++ b/drivers/scsi/mvsas/mv_sas.c
@@ -1935,15 +1935,15 @@ static void mvs_work_queue(struct work_struct *work)
 	struct delayed_work *dw = container_of(work, struct delayed_work, work);
 	struct mvs_wq *mwq = container_of(dw, struct mvs_wq, work_q);
 	struct mvs_info *mvi = mwq->mvi;
-	unsigned long flags;
 
-	spin_lock_irqsave(&mvi->lock, flags);
-	if (mwq->handler & PHY_PLUG_EVENT) {
 		u32 phy_no = (unsigned long) mwq->data;
 		struct sas_ha_struct *sas_ha = mvi->sas;
 		struct mvs_phy *phy = &mvi->phy[phy_no];
 		struct asd_sas_phy *sas_phy = &phy->sas_phy;
+	unsigned long flags;
 
+	spin_lock_irqsave(&mvi->lock, flags);
+	if (mwq->handler & PHY_PLUG_EVENT) {
 		if (phy->phy_event & PHY_PLUG_OUT) {
 			u32 tmp;
 			struct sas_identify_frame *id;
@@ -1964,6 +1964,10 @@ static void mvs_work_queue(struct work_struct *work)
 				mv_dprintk("phy%d Attached Device\n", phy_no);
 			}
 		}
+	} else if (mwq->handler & EXP_BRCT_CHG) {
+			phy->phy_event &= ~EXP_BRCT_CHG;
+			sas_ha->notify_port_event(sas_phy,
+					PORTE_BROADCAST_RCVD);
 	}
 	list_del(&mwq->entry);
 	spin_unlock_irqrestore(&mvi->lock, flags);
@@ -1982,7 +1986,7 @@ static int mvs_handle_event(struct mvs_info *mvi, void *data, int handler)
 		mwq->handler = handler;
 		MV_INIT_DELAYED_WORK(&mwq->work_q, mvs_work_queue, mwq);
 		list_add_tail(&mwq->entry, &mvi->wq_list);
-		schedule_delayed_work(&mwq->work_q, HZ * 2);
+		schedule_delayed_work(&mwq->work_q, HZ * io_delay);
 	} else
 		ret = -ENOMEM;
 
@@ -2014,14 +2018,14 @@ static void mvs_sig_remove_timer(struct mvs_phy *phy)
 void mvs_int_port(struct mvs_info *mvi, int phy_no, u32 events)
 {
 	u32 tmp;
-	struct sas_ha_struct *sas_ha = mvi->sas;
 	struct mvs_phy *phy = &mvi->phy[phy_no];
 	struct asd_sas_phy *sas_phy = &phy->sas_phy;
 
 	phy->irq_status = MVS_CHIP_DISP->read_port_irq_stat(mvi, phy_no);
-	mv_dprintk("port %d ctrl sts=0x%X.\n", phy_no+mvi->id*mvi->chip->n_phy,
+	MVS_CHIP_DISP->write_port_irq_stat(mvi, phy_no, phy->irq_status);
+	mv_dprintk("phy %d ctrl sts=%08X.\n", phy_no+mvi->id*mvi->chip->n_phy,
 		MVS_CHIP_DISP->read_phy_ctl(mvi, phy_no));
-	mv_dprintk("Port %d irq sts = 0x%X\n", phy_no+mvi->id*mvi->chip->n_phy,
+	mv_dprintk("phy %d irq sts = %08X\n", phy_no+mvi->id*mvi->chip->n_phy,
 		phy->irq_status);
 
 	/*
@@ -2096,13 +2100,11 @@ void mvs_int_port(struct mvs_info *mvi, int phy_no, u32 events)
 				phy_no + mvi->id*mvi->chip->n_phy);
 		}
 	} else if (phy->irq_status & PHYEV_BROAD_CH) {
-		mv_dprintk("port %d broadcast change.\n",
-			phy_no + mvi->id*mvi->chip->n_phy);
-		/* exception for Samsung disk drive*/
-		mdelay(1000);
-		sas_ha->notify_port_event(sas_phy, PORTE_BROADCAST_RCVD);
+			mv_dprintk("phy %d broadcast change.\n",
+				phy_no + mvi->id*mvi->chip->n_phy);
+			mvs_handle_event(mvi, (void *)(unsigned long)phy_no,
+					EXP_BRCT_CHG);
 	}
-	MVS_CHIP_DISP->write_port_irq_stat(mvi, phy_no, phy->irq_status);
 }
 
 int mvs_int_rx(struct mvs_info *mvi, bool self_clear)
diff --git a/drivers/scsi/mvsas/mv_sas.h b/drivers/scsi/mvsas/mv_sas.h
index aa2270a..7d3e5f6 100644
--- a/drivers/scsi/mvsas/mv_sas.h
+++ b/drivers/scsi/mvsas/mv_sas.h
@@ -61,6 +61,7 @@
 #endif
 #define MV_MAX_U32			0xffffffff
 
+extern int io_delay;
 extern struct mvs_tgt_initiator mvs_tgt;
 extern struct mvs_info *tgt_mvi;
 extern const struct mvs_dispatch mvs_64xx_dispatch;
@@ -93,6 +94,7 @@ extern const struct mvs_dispatch mvs_94xx_dispatch;
 enum dev_status {
 	MVS_DEV_NORMAL = 0x0,
 	MVS_DEV_EH	= 0x1,
+	MVS_DEV_OFF 	= 0x2,
 };
 
 
-- 
1.6.2.2

--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [SCSI Target Devel]     [Linux SCSI Target Infrastructure]     [Kernel Newbies]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Linux IIO]     [Samba]     [Device Mapper]
  Powered by Linux