Skip to contentSkip to conversation

mptfusion - fc transport attributes

PATCH In review Michael Reed 2 participants 4 messages Dec 17, 2005 – Jan 9, 2006

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

PATCH 1/1 mptfusion - fc transport attributes

Hello,

Attached is a patch which implements fibre channel transport attributes for LSI's MPT Fusion driver. This patch is dependent upon the following patches submitted by LSI's Eric Moore on 11/16/2005 but which have not as yet advanced to the 2.6.15-rc5-git series.

	2-module-fix.patch
	3-probe-fix.patch
	4-spi-fix.patch
	5-dvprep-fix.patch
	6-mapping-fix.patch
	7-bump-fix.patch

For correct operation of the fc transport, I also recommend installing James Smart's fix of 12/15/2005 which stops recursion on the workqueue.

[PATCH] fix for fc transport recursion problem.

In addition, I also recommend my patch of 12/16/2005 to stop the scsi eh from taking targets offline while they remain blocked by the transport.

[PATCH] Make scsi error recovery play nice with devices blocked by transport

James Smart had previously reviewed my transport attributes RFC and I have addressed his comments in the patch.

- module parameter text has been revised
- shifting of wwn remains as board returns it little endian, not off the wire and I wish to avoid ia64 access errors
- show_rport_dev_loss_tmo attribute exported
- set_port_dev_loss_tmo function implemented
- revised usage of dd_data and dd_fcrport_size
- added calls to fc_remote_port_chkready()
- removed some unnecessary sanity tests

drivers/message/fusion/mptbase.c +25 -5
diff -ru 1/drivers/message/fusion/mptbase.c 2/drivers/message/fusion/mptbase.c
@@ -148,7 +148,6 @@
 static int	WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
 static int	WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
 static int	GetLanConfigPages(MPT_ADAPTER *ioc);
-static int	GetFcPortPage0(MPT_ADAPTER *ioc, int portnum);
 static int	GetIoUnitPage2(MPT_ADAPTER *ioc);
 int		mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode);
 static int	mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum);
@@ -1245,6 +1244,8 @@
 	ioc->pcidev = pdev;
 	ioc->diagPending = 0;
 	spin_lock_init(&ioc->diagLock);
+	spin_lock_init(&ioc->work_lock);
+	spin_lock_init(&ioc->fc_rport_lock);
 	spin_lock_init(&ioc->initializing_hba_lock);
 
 	/* Initialize the event logging.
@@ -1268,6 +1269,10 @@
 	 */
 	INIT_LIST_HEAD(&ioc->configQ);
 
+	/* Initialize the fc rport list head.
+	 */
+	INIT_LIST_HEAD(&ioc->l.fc_rports);
+
 	/* Find lookup slot. */
 	INIT_LIST_HEAD(&ioc->list);
 	ioc->id = mpt_ids++;
@@ -1880,7 +1885,7 @@
 			 *  (FCPortPage0_t stuff)
 			 */
 			for (ii=0; ii < ioc->facts.NumberOfPorts; ii++) {
-				(void) GetFcPortPage0(ioc, ii);
+				(void) mptbase_GetFcPortPage0(ioc, ii);
 			}
 
 			if ((ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) &&
@@ -4199,7 +4204,7 @@
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
- *	GetFcPortPage0 - Fetch FCPort config Page0.
+ *	mptbase_GetFcPortPage0 - Fetch FCPort config Page0.
  *	@ioc: Pointer to MPT_ADAPTER structure
  *	@portnum: IOC Port number
  *
@@ -4209,8 +4214,8 @@
  *		-EAGAIN if no msg frames currently available
  *		-EFAULT for non-successful reply or no reply (timeout)
  */
-static int
-GetFcPortPage0(MPT_ADAPTER *ioc, int portnum)
+int
+mptbase_GetFcPortPage0(MPT_ADAPTER *ioc, int portnum)
 {
 	ConfigPageHeader_t	 hdr;
 	CONFIGPARMS		 cfg;
@@ -4220,6 +4225,8 @@
 	int			 data_sz;
 	int			 copy_sz;
 	int			 rc;
+	int			 count=400;
+
 
 	/* Get FCPort Page 0 header */
 	hdr.PageVersion = 0;
@@ -4243,6 +4250,8 @@
 	rc = -ENOMEM;
 	ppage0_alloc = (FCPortPage0_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page0_dma);
 	if (ppage0_alloc) {
+
+ try_again:
 		memset((u8 *)ppage0_alloc, 0, data_sz);
 		cfg.physAddr = page0_dma;
 		cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
@@ -4274,6 +4283,16 @@
 			pp0dest->DiscoveredPortsCount = le32_to_cpu(pp0dest->DiscoveredPortsCount);
 			pp0dest->MaxInitiators = le32_to_cpu(pp0dest->MaxInitiators);
 
+			/* if still doing discovery, hang loose a while until finished */
+			if (pp0dest->PortState == MPI_FCPORTPAGE0_PORTSTATE_UNKNOWN) {
+				if (count-- > 0) {
+					msleep_interruptible(100);
+					goto try_again;
+				}
+				else
+					printk(MYIOC_s_INFO_FMT "Firmware discovery not complete.\n",
+						ioc->name);
+			}
 		}
 
 		pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage0_alloc, page0_dma);
@@ -6358,6 +6377,7 @@
 EXPORT_SYMBOL(mpt_free_fw_memory);
 EXPORT_SYMBOL(mptbase_sas_persist_operation);
 EXPORT_SYMBOL(mpt_alt_ioc_wait);
+EXPORT_SYMBOL(mptbase_GetFcPortPage0);
 
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
drivers/message/fusion/mptbase.h +28 -0
diff -ru 1/drivers/message/fusion/mptbase.h 2/drivers/message/fusion/mptbase.h
@@ -499,6 +499,22 @@
 	int		 isRaid;		/* bit field, 1 if RAID */
 }RaidCfgData;
 
+#define MPT_RPORT_INFO_FLAGS_REGISTERED		0x01	/* rport registered */
+#define	MPT_RPORT_INFO_FLAGS_MISSING		0x02	/* missing from DevPage0 scan */
+#define MPT_RPORT_INFO_FLAGS_MAPPED_VDEV	0x04	/* target mapped in vdev */
+
+/*
+ * data allocated for each fc rport device
+ */
+struct mptfc_rport_info
+{
+	struct list_head list;
+	struct fc_rport *rport;
+	VirtDevice	*vdev;
+	FCDevicePage0_t pg0;
+	u8		flags;
+};
+
 /*
  *  Adapter Structure - pci_dev specific. Maximum: MPT_MAX_ADAPTERS
  */
@@ -611,7 +627,18 @@
 	int 	 		 initializing_hba_lock_flag;
 	struct list_head	 list;
 	struct net_device	*netdev;
+
+	union {
 	struct list_head	 sas_topology;
+	struct list_head	 fc_rports;	/* list of wwpn / sdev target / rport ptr */
+	} l;
+
+	spinlock_t		 fc_rport_lock;	/* for all accesses of list and ri flags */
+
+	spinlock_t		 work_lock;
+	int			 work_count;
+	struct work_struct	 work_task;	/* for use by personality, i.e., fc, sas, spi, lan */
+
 	MPT_SAS_MGMT		 sas_mgmt;
 } MPT_ADAPTER;
 
@@ -999,6 +1026,7 @@
 extern int	 mpt_findImVolumes(MPT_ADAPTER *ioc);
 extern int	 mpt_read_ioc_pg_3(MPT_ADAPTER *ioc);
 extern int	 mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode);
+extern int	 mptbase_GetFcPortPage0(MPT_ADAPTER *ioc, int portnum);
 extern int	 mpt_alt_ioc_wait(MPT_ADAPTER *ioc);
 
 /*
drivers/message/fusion/mptfc.c +509 -16

621 lines not on this page · raw message

drivers/message/fusion/mptsas.c +6 -6
diff -ru 1/drivers/message/fusion/mptsas.c 2/drivers/message/fusion/mptsas.c
@@ -257,7 +257,7 @@
 	}
 
 	rphy = dev_to_rphy(sdev->sdev_target->dev.parent);
-	list_for_each_entry(p, &hd->ioc->sas_topology, list) {
+	list_for_each_entry(p, &hd->ioc->l.sas_topology, list) {
 		for (i = 0; i < p->num_phys; i++) {
 			if (p->phy_info[i].attached.sas_address ==
 					rphy->identify.sas_address) {
@@ -994,7 +994,7 @@
 	if (error)
 		goto out_free_port_info;
 
-	list_add_tail(&port_info->list, &ioc->sas_topology);
+	list_add_tail(&port_info->list, &ioc->l.sas_topology);
 	for (i = 0; i < port_info->num_phys; i++) {
 		mptsas_sas_phy_pg0(ioc, &port_info->phy_info[i],
 			(MPI_SAS_PHY_PGAD_FORM_PHY_NUMBER <<
@@ -1047,7 +1047,7 @@
 
 	*handle = port_info->handle;
 
-	list_add_tail(&port_info->list, &ioc->sas_topology);
+	list_add_tail(&port_info->list, &ioc->l.sas_topology);
 	for (i = 0; i < port_info->num_phys; i++) {
 		struct device *parent;
 
@@ -1079,7 +1079,7 @@
 		 * HBA phys.
 		 */
 		parent = &ioc->sh->shost_gendev;
-		list_for_each_entry(p, &ioc->sas_topology, list) {
+		list_for_each_entry(p, &ioc->l.sas_topology, list) {
 			for (j = 0; j < p->num_phys; j++) {
 				if (port_info->phy_info[i].identify.handle ==
 						p->phy_info[j].attached.handle)
@@ -1202,7 +1202,7 @@
 	 */
 	sh->unique_id = ioc->id;
 
-	INIT_LIST_HEAD(&ioc->sas_topology);
+	INIT_LIST_HEAD(&ioc->l.sas_topology);
 	init_MUTEX(&ioc->sas_mgmt.mutex);
 	init_completion(&ioc->sas_mgmt.done);
 
@@ -1339,7 +1339,7 @@
 
 	sas_remove_host(ioc->sh);
 
-	list_for_each_entry_safe(p, n, &ioc->sas_topology, list) {
+	list_for_each_entry_safe(p, n, &ioc->l.sas_topology, list) {
 		list_del(&p->list);
 		kfree(p);
 	}
drivers/message/fusion/mptscsih.c +25 -4
diff -ru 1/drivers/message/fusion/mptscsih.c 2/drivers/message/fusion/mptscsih.c
@@ -58,6 +58,7 @@
 #include <linux/workqueue.h>
 
 #include <scsi/scsi.h>
+#include <scsi/scsi_transport_fc.h>
 #include <scsi/scsi_cmnd.h>
 #include <scsi/scsi_device.h>
 #include <scsi/scsi_host.h>
@@ -893,6 +894,7 @@
  *		when a lun is disable by mid-layer.
  *		Do NOT access the referenced scsi_cmnd structure or
  *		members. Will cause either a paging or NULL ptr error.
+ *		(BUT, BUT, BUT, the code does reference it! - mdr)
  *      @hd: Pointer to a SCSI HOST structure
  *	@vdevice: per device private data
  *
@@ -2559,13 +2561,25 @@
 			hd->cmdPtr = NULL;
 		}
 
-		/* 7. Set flag to force DV and re-read IOC Page 3
+		/* 7. SPI: Set flag to force DV and re-read IOC Page 3
 		 */
 		if (ioc->bus_type == SPI) {
 			ioc->spi_data.forceDv = MPT_SCSICFG_NEED_DV | MPT_SCSICFG_RELOAD_IOC_PG3;
 			ddvtprintk(("Set reload IOC Pg3 Flag\n"));
 		}
 
+		/* 7. FC: Rescan for blocked rports which might have returned.
+		 */
+		else if (ioc->bus_type == FC) {
+			int work_count;
+			unsigned long flags;
+
+			spin_lock_irqsave(&ioc->work_lock,flags);
+			work_count = ++ioc->work_count;
+			spin_unlock_irqrestore(&ioc->work_lock,flags);
+			if (work_count == 1)
+				schedule_work(&ioc->work_task);
+		}
 		dtmprintk((MYIOC_s_WARN_FMT "Post-Reset complete.\n", ioc->name));
 
 	}
@@ -2589,6 +2603,8 @@
 {
 	MPT_SCSI_HOST *hd;
 	u8 event = le32_to_cpu(pEvReply->Event) & 0xFF;
+	int work_count;
+	unsigned long flags;
 
 	devtprintk((MYIOC_s_INFO_FMT "MPT event (=%02Xh) routed to SCSI host driver!\n",
 			ioc->name, event));
@@ -2610,11 +2626,18 @@
 		/* FIXME! */
 		break;
 
+	case MPI_EVENT_RESCAN:				/* 06 */
+		spin_lock_irqsave(&ioc->work_lock,flags);
+		work_count = ++ioc->work_count;
+		spin_unlock_irqrestore(&ioc->work_lock,flags);
+		if (work_count == 1)
+			schedule_work(&ioc->work_task);
+		break;
+
 		/*
 		 *  CHECKME! Don't think we need to do
 		 *  anything for these, but...
 		 */
-	case MPI_EVENT_RESCAN:				/* 06 */
 	case MPI_EVENT_LINK_STATUS_CHANGE:		/* 07 */
 	case MPI_EVENT_LOOP_STATE_CHANGE:		/* 08 */
 		/*
@@ -3954,8 +3977,6 @@
 
 /* Search IOC page 3 to determine if this is hidden physical disk
  */
-/* Search IOC page 3 to determine if this is hidden physical disk
- */
 static int
 mptscsih_is_phys_disk(MPT_ADAPTER *ioc, int id)
 {
#1 lore raw

drivers/message/fusion/mptfc.c line 189

Quoted 9 lines
drivers/message/fusion/mptfc.c +8 -0
+static void
+mptfc_set_rport_loss_tmo(struct fc_rport *rport, uint32_t timeout)
+{
+	if (timeout > 0)
+		rport->dev_loss_tmo = timeout;
+	else
+		rport->dev_loss_tmo = mptfc_dev_loss_tmo;
+}

The only function of the if-test here is checking for 0 or >0, as the fc transport ensures it is nothing else. What bothers me is if the value is 0, then you are overriding it with the mptfc default value without any warning or error report to the user.

Perhaps we should be dealing with a zero value differently in the transport.

The rest looks ok...

-- james s

#2 lore raw

lpfc and qla2x00 have something similar. I chose the driver default instead of
1. Is setting it to one correct for the api?

static void
lpfc_set_rport_loss_tmo(struct fc_rport *rport, uint32_t timeout)

{
        /*
         * The driver doesn't have a per-target timeout setting.  Set
         * this value globally. lpfc_nodev_tmo should be greater then 0.
         */
        if (timeout)
                lpfc_nodev_tmo = timeout;
        else
                lpfc_nodev_tmo = 1;
        rport->dev_loss_tmo = lpfc_nodev_tmo + 5;
}

Mike

Quoted 27 lines · James Smart

drivers/message/fusion/mptfc.c line 189

Quoted 9 lines
drivers/message/fusion/mptfc.c +8 -0
+static void
+mptfc_set_rport_loss_tmo(struct fc_rport *rport, uint32_t timeout)
+{
+    if (timeout > 0)
+        rport->dev_loss_tmo = timeout;
+    else
+        rport->dev_loss_tmo = mptfc_dev_loss_tmo;
+}

The only function of the if-test here is checking for 0 or >0, as the fc transport ensures it is nothing else. What bothers me is if the value is 0, then you are overriding it with the mptfc default value without any warning or error report to the user.

Perhaps we should be dealing with a zero value differently in the transport.

The rest looks ok...

-- james s
-
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

#3 lore raw

As we are all trying to avoid a value of zero, we should just make the transport set function validate the range so that
1 <= dev_loss_tmo <= whatever_the_max_define_is

-- james s

Quoted 46 lines · Michael Reed

lpfc and qla2x00 have something similar. I chose the driver default instead of
1. Is setting it to one correct for the api?

static void
lpfc_set_rport_loss_tmo(struct fc_rport *rport, uint32_t timeout)

{
        /*
         * The driver doesn't have a per-target timeout setting.  Set
         * this value globally. lpfc_nodev_tmo should be greater then 0.
         */
        if (timeout)
                lpfc_nodev_tmo = timeout;
        else
                lpfc_nodev_tmo = 1;
        rport->dev_loss_tmo = lpfc_nodev_tmo + 5;
}

Mike

Quoted 25 lines · James Smart

drivers/message/fusion/mptfc.c line 189

Quoted 8 lines
drivers/message/fusion/mptfc.c +8 -0
+static void
+mptfc_set_rport_loss_tmo(struct fc_rport *rport, uint32_t timeout)
+{
+    if (timeout > 0)
+        rport->dev_loss_tmo = timeout;
+    else
+        rport->dev_loss_tmo = mptfc_dev_loss_tmo;
+}

The only function of the if-test here is checking for 0 or >0, as the fc transport ensures it is nothing else. What bothers me is if the value is 0, then you are overriding it with the mptfc default value without any warning or error report to the user.

Perhaps we should be dealing with a zero value differently in the transport.

The rest looks ok...

-- james s
-
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html