linux-scsi.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] mptfusion - fc transport attributes - REVISED
@ 2006-01-12 23:04 Michael Reed
  2006-01-13 10:31 ` Christoph Hellwig
  0 siblings, 1 reply; 9+ messages in thread
From: Michael Reed @ 2006-01-12 23:04 UTC (permalink / raw)
  To: linux-scsi
  Cc: Moore, Eric Dean, Shirron, Stephen, Hickerson, Roger,
	Jeremy Higdon, Michael Reed, Gary Hagensen

[-- Attachment #1: Type: text/plain, Size: 1050 bytes --]

Hello,

Attached is a patch which implements fibre channel transport attributes
for LSI's MPT Fusion driver.  This patch is a reissue of the patch I posted
on December 16, 2005.

http://marc.theaimsgroup.com/?l=linux-scsi&m=113477868225386&w=3

The differences between this patch and the previous patch are:

	- it incorporates review comments from LSI

	- it bumps the driver version number to 3.03.06 from 3.03.05 at
	  LSI's request

	- it has been rebased to 2.6.15-git8 + two patches from Eric Moore,
	  the first is referenced below,

	  http://marc.theaimsgroup.com/?l=linux-scsi&m=113710143317450&w=3

	  and the second I just posted instead of including in this patch.

	  http://marc.theaimsgroup.com/?l=linux-scsi&m=113710675626733&w=3


Until better integration of fc transport and scsi error recovery occurs, I
continue to urge (as a temporary measure) the application of my previous
scsi error recovery patch.

http://marc.theaimsgroup.com/?l=linux-scsi&m=113477788309880&w=3

Thanks,
 Mike


Signed-off-by: Michael Reed <mdr@sgi.com>


[-- Attachment #2: 1a-lsi_fc_transport.patch --]
[-- Type: text/x-patch, Size: 28533 bytes --]

diff -ru linux-2.6.15-git8/drivers/message/fusion/mptbase.c linux-2.6.15-git8-mdr/drivers/message/fusion/mptbase.c
--- linux-2.6.15-git8/drivers/message/fusion/mptbase.c	2006-01-12 16:08:15.000000000 -0600
+++ linux-2.6.15-git8-mdr/drivers/message/fusion/mptbase.c	2006-01-12 16:09:08.000000000 -0600
@@ -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++;
@@ -1884,7 +1889,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) &&
@@ -4203,7 +4208,7 @@
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
- *	GetFcPortPage0 - Fetch FCPort config Page0.
+ *	mptbase_GetFcPortPage0 - Fetch FCPort config Page0.
  *	@ioc: Pointer to MPT_ADAPTER structure
  *	@portnum: IOC Port number
  *
@@ -4213,8 +4218,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;
@@ -4224,6 +4229,8 @@
 	int			 data_sz;
 	int			 copy_sz;
 	int			 rc;
+	int			 count=400;
+
 
 	/* Get FCPort Page 0 header */
 	hdr.PageVersion = 0;
@@ -4247,6 +4254,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;
@@ -4278,6 +4287,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);
@@ -6362,6 +6381,7 @@
 EXPORT_SYMBOL(mpt_free_fw_memory);
 EXPORT_SYMBOL(mptbase_sas_persist_operation);
 EXPORT_SYMBOL(mpt_alt_ioc_wait);
+EXPORT_SYMBOL(mptbase_GetFcPortPage0);
 
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
diff -ru linux-2.6.15-git8/drivers/message/fusion/mptbase.h linux-2.6.15-git8-mdr/drivers/message/fusion/mptbase.h
--- linux-2.6.15-git8/drivers/message/fusion/mptbase.h	2006-01-12 16:06:49.000000000 -0600
+++ linux-2.6.15-git8-mdr/drivers/message/fusion/mptbase.h	2006-01-12 16:09:08.000000000 -0600
@@ -76,8 +76,8 @@
 #define COPYRIGHT	"Copyright (c) 1999-2005 " MODULEAUTHOR
 #endif
 
-#define MPT_LINUX_VERSION_COMMON	"3.03.05"
-#define MPT_LINUX_PACKAGE_NAME		"@(#)mptlinux-3.03.05"
+#define MPT_LINUX_VERSION_COMMON	"3.03.06"
+#define MPT_LINUX_PACKAGE_NAME		"@(#)mptlinux-3.03.06"
 #define WHAT_MAGIC_STRING		"@" "(" "#" ")"
 
 #define show_mptmod_ver(s,ver)  \
@@ -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);
 
 /*
diff -ru linux-2.6.15-git8/drivers/message/fusion/mptfc.c linux-2.6.15-git8-mdr/drivers/message/fusion/mptfc.c
--- linux-2.6.15-git8/drivers/message/fusion/mptfc.c	2006-01-12 16:06:49.000000000 -0600
+++ linux-2.6.15-git8-mdr/drivers/message/fusion/mptfc.c	2006-01-12 16:09:08.000000000 -0600
@@ -55,12 +55,14 @@
 #include <linux/reboot.h>	/* notifier code */
 #include <linux/sched.h>
 #include <linux/workqueue.h>
+#include <linux/sort.h>
 
 #include <scsi/scsi.h>
 #include <scsi/scsi_cmnd.h>
 #include <scsi/scsi_device.h>
 #include <scsi/scsi_host.h>
 #include <scsi/scsi_tcq.h>
+#include <scsi/scsi_transport_fc.h>
 
 #include "mptbase.h"
 #include "mptscsih.h"
@@ -79,19 +81,31 @@
 module_param(mpt_pq_filter, int, 0);
 MODULE_PARM_DESC(mpt_pq_filter, " Enable peripheral qualifier filter: enable=1  (default=0)");
 
+#define MPTFC_DEV_LOSS_TMO (60)
+static int mptfc_dev_loss_tmo = MPTFC_DEV_LOSS_TMO;	/* reasonable default */
+module_param(mptfc_dev_loss_tmo, int, 0);
+MODULE_PARM_DESC(mptfc_dev_loss_tmo, " Initial time the driver programs the transport to"
+				     " wait for an rport to return following a device"
+				     " loss event.  Default=60.");
+
 static int	mptfcDoneCtx = -1;
 static int	mptfcTaskCtx = -1;
 static int	mptfcInternalCtx = -1; /* Used only for internal commands */
 
+int mptfc_slave_alloc(struct scsi_device *device);
+static int mptfc_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *));
+static void mptfc_set_rport_loss_tmo(struct fc_rport *rport, uint32_t timeout);
+static void __devexit mptfc_remove(struct pci_dev *pdev);
+
 static struct scsi_host_template mptfc_driver_template = {
 	.module				= THIS_MODULE,
 	.proc_name			= "mptfc",
 	.proc_info			= mptscsih_proc_info,
 	.name				= "MPT FC Host",
 	.info				= mptscsih_info,
-	.queuecommand			= mptscsih_qcmd,
+	.queuecommand			= mptfc_qcmd,
 	.target_alloc			= mptscsih_target_alloc,
-	.slave_alloc			= mptscsih_slave_alloc,
+	.slave_alloc			= mptfc_slave_alloc,
 	.slave_configure		= mptscsih_slave_configure,
 	.target_destroy			= mptscsih_target_destroy,
 	.slave_destroy			= mptscsih_slave_destroy,
@@ -132,15 +146,451 @@
 };
 MODULE_DEVICE_TABLE(pci, mptfc_pci_table);
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static struct scsi_transport_template *mptfc_transport_template = NULL;
+
+struct fc_function_template mptfc_transport_functions = {
+	.show_host_node_name = 1,
+	.show_host_port_name = 1,
+	.show_host_supported_classes = 1,
+
+	.get_host_port_id = NULL,
+	.show_host_port_id = 1,
+
+	.dd_fcrport_size = 8,
+	.show_rport_supported_classes = 1,
+
+	.get_starget_node_name = NULL,
+	.show_starget_node_name = 1,
+	.get_starget_port_name = NULL,
+	.show_starget_port_name = 1,
+	.get_starget_port_id  = NULL,
+	.show_starget_port_id = 1,
+
+	.get_rport_dev_loss_tmo = NULL,
+	.set_rport_dev_loss_tmo = mptfc_set_rport_loss_tmo,
+	.show_rport_dev_loss_tmo = 1,
+
+};
+
+/* FIXME! values controlling firmware RESCAN event
+ * need to be set low to allow dev_loss_tmo to
+ * work as expected.  Currently, firmware doesn't
+ * notify driver of RESCAN event until some number
+ * of seconds elapse.  This value can be set via
+ * lsiutil.
+ */
+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;
+}
+
+static int
+mptfc_FcDevPage0_cmp_func(const void *a, const void *b)
+{
+	FCDevicePage0_t **aa=(FCDevicePage0_t **)a;
+	FCDevicePage0_t **bb=(FCDevicePage0_t **)b;
+
+	if ((*aa)->CurrentBus == (*bb)->CurrentBus) {
+		if ((*aa)->CurrentTargetID == (*bb)->CurrentTargetID)
+			return 0;
+		if ((*aa)->CurrentTargetID < (*bb)->CurrentTargetID)
+			return -1;
+		return 1;
+	}
+	if ((*aa)->CurrentBus < (*bb)->CurrentBus)
+		return -1;
+	return 1;
+}
+
+static int
+mptfc_GetFcDevPage0(MPT_ADAPTER *ioc, int ioc_port, 
+	void(*func)(MPT_ADAPTER *ioc,int channel, FCDevicePage0_t *arg))
+{
+	ConfigPageHeader_t	 hdr;
+	CONFIGPARMS		 cfg;
+	FCDevicePage0_t		*ppage0_alloc, *fc;
+	dma_addr_t		 page0_dma;
+	int			 data_sz;
+	int			 ii;
+
+	FCDevicePage0_t		*p0_array=NULL, *p_p0;
+	FCDevicePage0_t		**pp0_array=NULL, **p_pp0;
+
+	int			 rc = -ENOMEM;
+	U32			 port_id = 0xffffff;
+	int			 num_targ = 0;
+	int			 max_bus = ioc->facts.MaxBuses;
+	int			 max_targ = ioc->facts.MaxDevices;
+
+	if (max_bus == 0 || max_targ == 0)
+		goto out;
+
+	data_sz = sizeof(FCDevicePage0_t) * max_bus * max_targ;
+	p_p0 = p0_array =  kmalloc(data_sz,GFP_KERNEL);
+	if (!p0_array)
+		goto out;
+	memset((u8 *)p0_array, 0, data_sz);
+
+	data_sz = sizeof(FCDevicePage0_t *) * max_bus * max_targ;
+	p_pp0 = pp0_array = kmalloc(data_sz,GFP_KERNEL);
+	if (!pp0_array)
+		goto out;
+	memset((u8 *)pp0_array, 0, data_sz);
+
+	do {
+		/* Get FC Device Page 0 header */
+		hdr.PageVersion = 0;
+		hdr.PageLength = 0;
+		hdr.PageNumber = 0;
+		hdr.PageType = MPI_CONFIG_PAGETYPE_FC_DEVICE;
+		cfg.cfghdr.hdr = &hdr;
+		cfg.physAddr = -1;
+		cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+		cfg.dir = 0;
+		cfg.pageAddr = port_id;
+		cfg.timeout = 0;
+
+		if ((rc = mpt_config(ioc, &cfg)) != 0)
+			break;
+
+		if (hdr.PageLength <= 0)
+			break;
+		else {
+			data_sz = hdr.PageLength * 4;
+			ppage0_alloc = (FCDevicePage0_t *) 
+					pci_alloc_consistent(ioc->pcidev, data_sz, &page0_dma);
+			rc = -ENOMEM;
+			if (ppage0_alloc) {
+				memset((u8 *)ppage0_alloc, 0, data_sz);
+				cfg.physAddr = page0_dma;
+				cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+
+				if ((rc = mpt_config(ioc, &cfg)) == 0) {
+					le32_to_cpus(ppage0_alloc->PortIdentifier);
+					le32_to_cpus(ppage0_alloc->WWNN.Low);
+					le32_to_cpus(ppage0_alloc->WWNN.High);
+					le32_to_cpus(ppage0_alloc->WWPN.Low);
+					le32_to_cpus(ppage0_alloc->WWPN.High);
+					le16_to_cpus(ppage0_alloc->BBCredit);
+					le16_to_cpus(ppage0_alloc->MaxRxFrameSize);
+					
+					port_id = ppage0_alloc->PortIdentifier;
+					num_targ++;
+					*p_p0 = *ppage0_alloc;	/* save data */
+					*p_pp0++ = p_p0++;	/* save addr */
+				}
+				pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage0_alloc, page0_dma);
+				if (rc != 0)
+					break;
+			}
+			else break;
+		}
+	} while (port_id <= 0xff0000);
+
+	if (num_targ) {
+		/* sort array */
+		if (num_targ > 1)
+			sort (pp0_array,num_targ,sizeof(FCDevicePage0_t *), 
+				mptfc_FcDevPage0_cmp_func, NULL);
+		/* call caller's func for each targ */
+		for (ii=0; ii<num_targ;  ii++) {
+			fc = *(pp0_array+ii);
+			func(ioc,ioc_port,fc);
+		}
+	}
+
+ out:
+	if (pp0_array)
+		kfree(pp0_array);
+	if (p0_array)
+		kfree(p0_array);
+	return rc;
+}
+
+static int
+mptfc_generate_rport_identifiers(FCDevicePage0_t *pg0, struct fc_rport_identifiers *rid)
+{
+	/* not currently usable */
+	if (pg0->Flags & (MPI_FC_DEVICE_PAGE0_FLAGS_PLOGI_INVALID |
+			  MPI_FC_DEVICE_PAGE0_FLAGS_PRLI_INVALID))
+		return -1;
+
+	if (!(pg0->Flags & MPI_FC_DEVICE_PAGE0_FLAGS_TARGETID_BUS_VALID))
+		return -1;
+
+	if (!(pg0->Protocol & MPI_FC_DEVICE_PAGE0_PROT_FCP_TARGET))
+		return -1;
+
+	/* board data structure already normalized to platform endianness
+	 * shifted to avoid unaligned access on 64 bit architecture */
+	rid->node_name = ((u64)pg0->WWNN.High) << 32 | (u64)pg0->WWNN.Low;
+	rid->port_name = ((u64)pg0->WWPN.High) << 32 | (u64)pg0->WWPN.Low;
+	rid->port_id =   pg0->PortIdentifier;
+	rid->roles = FC_RPORT_ROLE_UNKNOWN;
+	rid->roles |= FC_RPORT_ROLE_FCP_TARGET;
+	if (pg0->Protocol & MPI_FC_DEVICE_PAGE0_PROT_FCP_INITIATOR)
+		rid->roles |= FC_RPORT_ROLE_FCP_INITIATOR;
+
+	return 0;
+}
+
+static void
+mptfc_register_dev(MPT_ADAPTER *ioc, int channel, FCDevicePage0_t *pg0)
+{
+	struct fc_rport_identifiers rport_ids;
+	struct fc_rport		*rport;
+	struct mptfc_rport_info	*ri;
+	int			match=0;
+	u64			port_name;
+	unsigned long		flags;
+
+	if (mptfc_generate_rport_identifiers(pg0,&rport_ids) < 0)
+		return;
+
+	/* scan list looking for a match */
+	spin_lock_irqsave(&ioc->fc_rport_lock,flags);
+	list_for_each_entry(ri, &ioc->l.fc_rports, list) {
+		port_name = (u64)ri->pg0.WWPN.High << 32 | (u64)ri->pg0.WWPN.Low;
+		if (port_name == rport_ids.port_name) {	/* match */
+			list_move_tail(&ri->list,&ioc->l.fc_rports);
+			match = 1;
+			break;
+		}
+	}
+	if (!match) {	/* allocate one */
+		spin_unlock_irqrestore(&ioc->fc_rport_lock,flags);
+		ri = kmalloc(sizeof(struct mptfc_rport_info), GFP_KERNEL);
+		if (!ri)
+			return;
+		memset(ri, 0, sizeof(struct mptfc_rport_info));
+		spin_lock_irqsave(&ioc->fc_rport_lock,flags);
+		list_add_tail(&ri->list,&ioc->l.fc_rports);
+	}
+
+	ri->pg0 = *pg0;	/* add/update pg0 data */
+	ri->flags &= ~MPT_RPORT_INFO_FLAGS_MISSING;
+
+	if (!(ri->flags & MPT_RPORT_INFO_FLAGS_REGISTERED)) {
+		ri->flags |= MPT_RPORT_INFO_FLAGS_REGISTERED;
+		spin_unlock_irqrestore(&ioc->fc_rport_lock,flags);
+		rport = fc_remote_port_add(ioc->sh,channel,&rport_ids);
+		spin_lock_irqsave(&ioc->fc_rport_lock,flags);
+		if (rport) {
+			if (*((struct mptfc_rport_info **)rport->dd_data) != ri) {
+				ri->flags &= ~MPT_RPORT_INFO_FLAGS_MAPPED_VDEV;
+				ri->vdev = NULL;
+				ri->rport = rport;
+				*((struct mptfc_rport_info **)rport->dd_data) = ri;
+			}
+			rport->dev_loss_tmo = mptfc_dev_loss_tmo;
+			/* if already mapped, remap here.  If not mapped,
+			 * slave_alloc will allocate vdev and map */
+			if (ri->flags & MPT_RPORT_INFO_FLAGS_MAPPED_VDEV) {
+				ri->vdev->target_id = ri->pg0.CurrentTargetID;
+				ri->vdev->bus_id = ri->pg0.CurrentBus;
+				ri->vdev->vtarget->target_id = ri->vdev->target_id;
+				ri->vdev->vtarget->bus_id = ri->vdev->bus_id;
+			}
+			#ifdef MPT_DEBUG
+			printk ("mptfc_reg_dev.%d: %x, %llx / %llx, tid %d, "
+				"rport tid %d, tmo %d\n",
+					ioc->sh->host_no,
+					pg0->PortIdentifier,
+					pg0->WWNN,
+					pg0->WWPN,
+					pg0->CurrentTargetID,
+					ri->rport->scsi_target_id,
+					ri->rport->dev_loss_tmo);
+			#endif
+		}
+		else {
+			list_del(&ri->list);
+			kfree(ri);
+			ri = NULL;
+		}
+	}
+	spin_unlock_irqrestore(&ioc->fc_rport_lock,flags);
+
+}
+
 /*
- *	mptfc_probe - Installs scsi devices per bus.
- *	@pdev: Pointer to pci_dev structure
- *
- *	Returns 0 for success, non-zero for failure.
- *
+ *	OS entry point to allow host driver to alloc memory
+ *	for each scsi device. Called once per device the bus scan.
+ *	Return non-zero if allocation fails.
+ *	Init memory once per LUN.
  */
+int
+mptfc_slave_alloc(struct scsi_device *sdev)
+{
+	MPT_SCSI_HOST		*hd;
+	VirtTarget		*vtarget;
+	VirtDevice		*vdev;
+	struct scsi_target	*starget;
+	struct fc_rport		*rport;
+	struct mptfc_rport_info *ri;
+	unsigned long		flags;
+
+
+	rport=starget_to_rport(scsi_target(sdev));
+
+	if (!rport || fc_remote_port_chkready(rport))
+		return -ENXIO;
+
+	hd = (MPT_SCSI_HOST *)sdev->host->hostdata;
+
+	vdev = kmalloc(sizeof(VirtDevice), GFP_KERNEL);
+	if (!vdev) {
+		printk(MYIOC_s_ERR_FMT "slave_alloc kmalloc(%zd) FAILED!\n",
+				hd->ioc->name, sizeof(VirtDevice));
+		return -ENOMEM;
+	}
+	memset(vdev, 0, sizeof(VirtDevice));
+
+	spin_lock_irqsave(&hd->ioc->fc_rport_lock,flags);
+
+	if (!(ri=*((struct mptfc_rport_info **)rport->dd_data))) {
+		spin_unlock_irqrestore(&hd->ioc->fc_rport_lock,flags);
+		kfree(vdev);
+		return -ENODEV;
+	}
+
+	sdev->hostdata = vdev;
+	starget = scsi_target(sdev);
+	vtarget = starget->hostdata;
+	if (vtarget->num_luns == 0) {
+		vtarget->tflags = MPT_TARGET_FLAGS_Q_YES | MPT_TARGET_FLAGS_VALID_INQUIRY;
+		hd->Targets[sdev->id] = vtarget;
+	}
+
+	vtarget->target_id = vdev->target_id;
+	vtarget->bus_id = vdev->bus_id;
+
+	vdev->vtarget = vtarget;
+	vdev->ioc_id = hd->ioc->id;
+	vdev->lun = sdev->lun;
+	vdev->target_id = ri->pg0.CurrentTargetID;
+	vdev->bus_id = ri->pg0.CurrentBus;
+
+	ri->flags |= MPT_RPORT_INFO_FLAGS_MAPPED_VDEV;
+	ri->vdev = vdev;
+
+	spin_unlock_irqrestore(&hd->ioc->fc_rport_lock,flags);
+
+	vtarget->num_luns++;
+
+#ifdef MPT_DEBUG
+	printk ("mptfc_slv_alloc.%d: num_luns %d, sdev.id %d, CurrentTargetID %d, "
+		"%x %llx %llx\n",sdev->host->host_no,
+		vtarget->num_luns,
+		sdev->id, ri->pg0.CurrentTargetID,
+		ri->pg0.PortIdentifier,ri->pg0.WWPN,ri->pg0.WWNN);
+#endif
+
+	return 0;
+}
+
+static int
+mptfc_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
+{
+	struct fc_rport	*rport = starget_to_rport(scsi_target(SCpnt->device));
+	int		err;
+
+	err = fc_remote_port_chkready(rport);
+	if (unlikely(err)) {
+		SCpnt->result = err;
+		done(SCpnt);
+		return 0;
+	}
+	return mptscsih_qcmd(SCpnt,done);
+}
+
+static void
+mptfc_init_host_attr(MPT_ADAPTER *ioc,int portnum)
+{
+	unsigned class=0, cos=0;
+
+	/* don't know what to do as only one scsi (fc) host was allocated */
+	if (portnum != 0)
+		return;
+
+	class = ioc->fc_port_page0[portnum].SupportedServiceClass;
+	if (class & MPI_FCPORTPAGE0_SUPPORT_CLASS_1)
+		cos |= FC_COS_CLASS1;
+	if (class & MPI_FCPORTPAGE0_SUPPORT_CLASS_2)
+		cos |= FC_COS_CLASS2;
+	if (class & MPI_FCPORTPAGE0_SUPPORT_CLASS_3)
+		cos |= FC_COS_CLASS3;
+
+	fc_host_node_name(ioc->sh) = (u64)ioc->fc_port_page0[portnum].WWNN.High << 32
+				    | (u64)ioc->fc_port_page0[portnum].WWNN.Low;
+
+	fc_host_port_name(ioc->sh) = (u64)ioc->fc_port_page0[portnum].WWPN.High << 32
+				    | (u64)ioc->fc_port_page0[portnum].WWPN.Low;
+
+	fc_host_port_id(ioc->sh) = ioc->fc_port_page0[portnum].PortIdentifier;
+
+	fc_host_supported_classes(ioc->sh) = cos;
+
+	fc_host_tgtid_bind_type(ioc->sh) = FC_TGTID_BIND_BY_WWPN;
+}
+
+static void
+mptfc_rescan_devices(void *arg)
+{
+	MPT_ADAPTER		*ioc = (MPT_ADAPTER *)arg;
+	int			ii;
+	int			work_to_do;
+	unsigned long		flags;
+	struct mptfc_rport_info *ri;
+
+	do {
+		/* start by tagging all ports as missing */
+		spin_lock_irqsave(&ioc->fc_rport_lock,flags);
+		list_for_each_entry(ri, &ioc->l.fc_rports, list) {
+			if (ri->flags & MPT_RPORT_INFO_FLAGS_REGISTERED) {
+				ri->flags |= MPT_RPORT_INFO_FLAGS_MISSING;
+			}
+		}
+		spin_unlock_irqrestore(&ioc->fc_rport_lock,flags);
+
+		/* now rescan devices known to adapter, will reregister existing rports */
+		for (ii=0; ii < ioc->facts.NumberOfPorts; ii++) {
+			(void) mptbase_GetFcPortPage0(ioc, ii);
+			mptfc_init_host_attr(ioc,ii);	/* refresh */
+			mptfc_GetFcDevPage0(ioc,ii,mptfc_register_dev);
+		}
+
+		/* delete devices still missing */
+		spin_lock_irqsave(&ioc->fc_rport_lock,flags);
+		list_for_each_entry(ri, &ioc->l.fc_rports, list) {
+			/* if newly missing, delete it */
+			if ((ri->flags & (MPT_RPORT_INFO_FLAGS_REGISTERED |
+					  MPT_RPORT_INFO_FLAGS_MISSING))
+			  == (MPT_RPORT_INFO_FLAGS_REGISTERED | MPT_RPORT_INFO_FLAGS_MISSING)) {
+				ri->flags &= ~(MPT_RPORT_INFO_FLAGS_REGISTERED|MPT_RPORT_INFO_FLAGS_MISSING);
+				fc_remote_port_delete(ri->rport);
+				/* remote port not really deleted 'cause binding is by WWPN
+				 * and driver only registers FCP_TARGETs */
+				#ifdef MPT_DEBUG
+				printk ("mptfc_rescan.%d: %llx deleted\n",ioc->sh->host_no,ri->pg0.WWPN);
+				#endif
+			}
+		}
+		spin_unlock_irqrestore(&ioc->fc_rport_lock,flags);
+
+		/* allow multiple passes as target state might have changed during scan */
+		spin_lock_irqsave(&ioc->work_lock,flags);
+		if (ioc->work_count > 2) 	/* don't need THAT many passes */
+			ioc->work_count = 2;
+		work_to_do = --ioc->work_count;
+		spin_unlock_irqrestore(&ioc->work_lock,flags);
+	} while (work_to_do);
+}
+
 static int
 mptfc_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 {
@@ -155,10 +605,10 @@
 	u8			*mem;
 	int			error=0;
 	int			r;
-		
+
 	if ((r = mpt_attach(pdev,id)) != 0)
 		return r;
-	
+
 	ioc = pci_get_drvdata(pdev);
 	ioc->DoneCtx = mptfcDoneCtx;
 	ioc->TaskCtx = mptfcTaskCtx;
@@ -194,7 +644,7 @@
 		printk(MYIOC_s_WARN_FMT
 			"Skipping ioc=%p because SCSI Initiator mode is NOT enabled!\n",
 			ioc->name, ioc);
-		return 0;
+		return -ENODEV;
 	}
 
 	sh = scsi_host_alloc(&mptfc_driver_template, sizeof(MPT_SCSI_HOST));
@@ -207,6 +657,8 @@
 		goto out_mptfc_probe;
         }
 
+	INIT_WORK(&ioc->work_task, mptfc_rescan_devices,(void *)ioc);
+
 	spin_lock_irqsave(&ioc->FreeQlock, flags);
 
 	/* Attach the SCSI Host to the IOC structure
@@ -332,6 +784,7 @@
 	hd->scandv_wait_done = 0;
 	hd->last_queue_full = 0;
 
+	sh->transportt = mptfc_transport_template;
 	error = scsi_add_host (sh, &ioc->pcidev->dev);
 	if(error) {
 		dprintk((KERN_ERR MYNAM
@@ -339,7 +792,11 @@
 		goto out_mptfc_probe;
 	}
 
-	scsi_scan_host(sh);
+	for (ii=0; ii < ioc->facts.NumberOfPorts; ii++) {
+		mptfc_init_host_attr(ioc,ii);
+		mptfc_GetFcDevPage0(ioc,ii,mptfc_register_dev);
+	}
+
 	return 0;
 
 out_mptfc_probe:
@@ -352,7 +809,7 @@
 	.name		= "mptfc",
 	.id_table	= mptfc_pci_table,
 	.probe		= mptfc_probe,
-	.remove		= __devexit_p(mptscsih_remove),
+	.remove		= __devexit_p(mptfc_remove),
 	.shutdown	= mptscsih_shutdown,
 #ifdef CONFIG_PM
 	.suspend	= mptscsih_suspend,
@@ -370,9 +827,18 @@
 static int __init
 mptfc_init(void)
 {
+	int error;
 
 	show_mptmod_ver(my_NAME, my_VERSION);
 
+	/* sanity check module parameter */
+	if (mptfc_dev_loss_tmo == 0)
+		mptfc_dev_loss_tmo = MPTFC_DEV_LOSS_TMO;
+
+	mptfc_transport_template = fc_attach_transport(&mptfc_transport_functions);
+	if (!mptfc_transport_template)
+		return -ENODEV;
+
 	mptfcDoneCtx = mpt_register(mptscsih_io_done, MPTFC_DRIVER);
 	mptfcTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTFC_DRIVER);
 	mptfcInternalCtx = mpt_register(mptscsih_scandv_complete, MPTFC_DRIVER);
@@ -387,7 +853,33 @@
 		  ": Registered for IOC reset notifications\n"));
 	}
 
-	return pci_register_driver(&mptfc_driver);
+	error = pci_register_driver(&mptfc_driver);
+	if (error) {
+		fc_release_transport(mptfc_transport_template);
+	}
+
+	return error;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *	mptfc_remove - Removed fc infrastructure for devices
+ *	@pdev: Pointer to pci_dev structure
+ *
+ */
+static void __devexit mptfc_remove(struct pci_dev *pdev)
+{
+	MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
+	struct mptfc_rport_info *p, *n;
+
+	fc_remove_host(ioc->sh);
+
+	list_for_each_entry_safe(p, n, &ioc->l.fc_rports, list) {
+		list_del(&p->list);
+		kfree(p);
+	}
+
+	mptscsih_remove(pdev);
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -400,7 +892,8 @@
 mptfc_exit(void)
 {
 	pci_unregister_driver(&mptfc_driver);
-	
+	fc_release_transport(mptfc_transport_template);
+
 	mpt_reset_deregister(mptfcDoneCtx);
 	dprintk((KERN_INFO MYNAM
 	  ": Deregistered for IOC reset notifications\n"));
diff -ru linux-2.6.15-git8/drivers/message/fusion/mptsas.c linux-2.6.15-git8-mdr/drivers/message/fusion/mptsas.c
--- linux-2.6.15-git8/drivers/message/fusion/mptsas.c	2006-01-12 16:06:49.000000000 -0600
+++ linux-2.6.15-git8-mdr/drivers/message/fusion/mptsas.c	2006-01-12 16:09:08.000000000 -0600
@@ -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);
 	}
diff -ru linux-2.6.15-git8/drivers/message/fusion/mptscsih.c linux-2.6.15-git8-mdr/drivers/message/fusion/mptscsih.c
--- linux-2.6.15-git8/drivers/message/fusion/mptscsih.c	2006-01-12 16:06:49.000000000 -0600
+++ linux-2.6.15-git8-mdr/drivers/message/fusion/mptscsih.c	2006-01-12 16:09:08.000000000 -0600
@@ -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)
 {

^ permalink raw reply	[flat|nested] 9+ messages in thread

* RE: [PATCH] mptfusion - fc transport attributes - REVISED
@ 2006-01-12 23:17 Moore, Eric
  0 siblings, 0 replies; 9+ messages in thread
From: Moore, Eric @ 2006-01-12 23:17 UTC (permalink / raw)
  To: Michael Reed, linux-scsi
  Cc: Shirron, Stephen, Hickerson, Roger, Jeremy Higdon, Gary Hagensen

On Thursday, January 12, 2006 4:04 PM,  Michael Reed wrote:

> 	- it has been rebased to 2.6.15-git8 + two patches from 
> Eric Moore,
> 	  the first is referenced below,
> 
> 	  
> http://marc.theaimsgroup.com/?l=linux-scsi&m=113710143317450&w=3
> 
> 	  and the second I just posted instead of including in 
> this patch.
> 
> 	  
> http://marc.theaimsgroup.com/?l=linux-scsi&m=113710675626733&w=3
> 
> 

One thing is missing in completing the 949ES support.
That is PCI_DEVICE_ID_LSI_FC949ES need to be added in the
mptfc_pci_table[]
in mptfc.c.  This is the table contains the list of support pci device
ids.  
Is that possible to add that?

Eric Moore

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH] mptfusion - fc transport attributes - REVISED
  2006-01-12 23:04 [PATCH] mptfusion - fc transport attributes - REVISED Michael Reed
@ 2006-01-13 10:31 ` Christoph Hellwig
  2006-01-13 18:18   ` Michael Reed
  0 siblings, 1 reply; 9+ messages in thread
From: Christoph Hellwig @ 2006-01-13 10:31 UTC (permalink / raw)
  To: Michael Reed
  Cc: linux-scsi, Moore, Eric Dean, Shirron, Stephen, Hickerson, Roger,
	Jeremy Higdon, Gary Hagensen


> +	int			 count=400;
> +

	Please add a space before and after the '='  Same things in various
	other places all over the patch.

> +			if (pp0dest->PortState == MPI_FCPORTPAGE0_PORTSTATE_UNKNOWN) {

	Please make sure you don't add lines longer than 80 characters.

> +				if (count-- > 0) {
> +					msleep_interruptible(100);
> +					goto try_again;
> +				}
> +				else

should be

				} else

> +#define MPT_RPORT_INFO_FLAGS_REGISTERED		0x01	/* rport registered */
> +#define	MPT_RPORT_INFO_FLAGS_MISSING		0x02	/* missing from DevPage0 scan */

	should also use a space after the #define, and again lines
	longer than 80 chars (and quite a few times more later in the
	patch)

> +
> +	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 */

	Please don't make this a union yet.  There's too much work going on
	in the SAS area and this would cause conflicts all over.  We can
	move to the union later on ones all the major pending changes have
	settled.

> +int mptfc_slave_alloc(struct scsi_device *device);
> +static int mptfc_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *));
> +static void mptfc_set_rport_loss_tmo(struct fc_rport *rport, uint32_t timeout);
> +static void __devexit mptfc_remove(struct pci_dev *pdev);

	Please try to order functions so that forward-prototypes aren't
	needed.  (where easily possible)


> +	.get_starget_node_name = NULL,

	no need to initialize unused memembers of static structures to zero.

> +	p_p0 = p0_array =  kmalloc(data_sz,GFP_KERNEL);
> +	if (!p0_array)
> +		goto out;
> +	memset((u8 *)p0_array, 0, data_sz);
> +
> +	data_sz = sizeof(FCDevicePage0_t *) * max_bus * max_targ;
> +	p_pp0 = pp0_array = kmalloc(data_sz,GFP_KERNEL);
> +	if (!pp0_array)
> +		goto out;
> +	memset((u8 *)pp0_array, 0, data_sz);

	just use kzalloc in those two cases.
	also please a whitespace after the , in arguments.

> +		if (hdr.PageLength <= 0)
> +			break;
> +		else {

	no need for the else here, the break already jumps out of the loop.
	and the lesser indentation should make the code quite a lot more
	readable aswell.

> +			data_sz = hdr.PageLength * 4;
> +			ppage0_alloc = (FCDevicePage0_t *) 
> + 					pci_alloc_consistent(ioc->pcidev, data_sz, &page0_dma);

	mo need to cast the return value of pci_alloc_consistent.


> +			rc = -ENOMEM;
> +			if (ppage0_alloc) {

	just break out of the loop in the !ppage0_alloc case, reduces
	indentation again and makes the code fit into 80 columes.

> +				memset((u8 *)ppage0_alloc, 0, data_sz);

	pci_alloc_consistent returns zeroed memory.

+				if ((rc = mpt_config(ioc, &cfg)) == 0) {
+					le32_to_cpus(ppage0_alloc->PortIdentifier);
+					le32_to_cpus(ppage0_alloc->WWNN.Low);
+					le32_to_cpus(ppage0_alloc->WWNN.High);
+					le32_to_cpus(ppage0_alloc->WWPN.Low);
+					le32_to_cpus(ppage0_alloc->WWPN.High);
+					le16_to_cpus(ppage0_alloc->BBCredit);
+					le16_to_cpus(ppage0_alloc->MaxRxFrameSize);

	please never use leXX_to_cpus but always leXX_to_cpu and assign to
	a separate variable.  Assigning hardware endian and host endian
	values to the same value defeats static typechecking with sparse.

> +		ri = kmalloc(sizeof(struct mptfc_rport_info), GFP_KERNEL);
> + 		if (!ri)
> +			return;
> +		memset(ri, 0, sizeof(struct mptfc_rport_info));

	case use kzalloc, too.

> +	INIT_WORK(&ioc->work_task, mptfc_rescan_devices,(void *)ioc);

	could you calls this ioc->fc_rescan_work?  also no need for the
	void cast.

@@ -332,6 +784,7 @@
 	hd->scandv_wait_done = 0;
 	hd->last_queue_full = 0;
 
+	sh->transportt = mptfc_transport_template;
 	error = scsi_add_host (sh, &ioc->pcidev->dev);
 	if(error) {
 		dprintk((KERN_ERR MYNAM
@@ -339,7 +792,11 @@
 		goto out_mptfc_probe;
 	}
 
-	scsi_scan_host(sh);
+	for (ii=0; ii < ioc->facts.NumberOfPorts; ii++) {
+		mptfc_init_host_attr(ioc,ii);
+		mptfc_GetFcDevPage0(ioc,ii,mptfc_register_dev);
+	}
+
 	return 0;
 
 out_mptfc_probe:

> +++ linux-2.6.15-git8-mdr/drivers/message/fusion/mptscsih.c	2006-01-12 16:09:08.000000000 -0600
> @@ -58,6 +58,7 @@
>  #include <linux/workqueue.h>
>  
>  #include <scsi/scsi.h>
> +#include <scsi/scsi_transport_fc.h>

	you must only use transport-class infrastructure in the per-transport
	files, but not in the common ones.



also don't we need a slave_destroy menthod, as in the SAS hotplug patches?
And you should probably remove the scsi_scan_host call as all additions
should be done through the FC transport class functionality.

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH] mptfusion - fc transport attributes - REVISED
  2006-01-13 10:31 ` Christoph Hellwig
@ 2006-01-13 18:18   ` Michael Reed
  2006-01-13 18:22     ` Christoph Hellwig
  0 siblings, 1 reply; 9+ messages in thread
From: Michael Reed @ 2006-01-13 18:18 UTC (permalink / raw)
  To: Christoph Hellwig
  Cc: linux-scsi, Moore, Eric Dean, Shirron, Stephen, Hickerson, Roger,
	Jeremy Higdon, Gary Hagensen



Christoph Hellwig wrote:
>>+	int			 count=400;
>>+
> 
> 	Please add a space before and after the '='  Same things in various
> 	other places all over the patch.

OK.

> 
>>+			if (pp0dest->PortState == MPI_FCPORTPAGE0_PORTSTATE_UNKNOWN) {
> 
> 	Please make sure you don't add lines longer than 80 characters.

This driver is full of lines longer than 80 characters....  I'll see what I can
do.  I'm not planning on reworking the entire driver to shorten the line lengths
but if there are obvious places in my patch, like above, I'll do what I can to
conform.

I suspect it should be a separate patch to clean up all the white space / style/long line / other issues in this driver.  :)

> 
>>+				if (count-- > 0) {
>>+					msleep_interruptible(100);
>>+					goto try_again;
>>+				}
>>+				else
> 
> should be
> 
> 				} else

OK

> 
>>+#define MPT_RPORT_INFO_FLAGS_REGISTERED		0x01	/* rport registered */
>>+#define	MPT_RPORT_INFO_FLAGS_MISSING		0x02	/* missing from DevPage0 scan */
> 
> 	should also use a space after the #define, and again lines
> 	longer than 80 chars (and quite a few times more later in the
> 	patch)

OK.

> 
>>+
>>+	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 */
> 
> 	Please don't make this a union yet.  There's too much work going on
> 	in the SAS area and this would cause conflicts all over.  We can
> 	move to the union later on ones all the major pending changes have
> 	settled.

OK.

> 
>>+int mptfc_slave_alloc(struct scsi_device *device);
>>+static int mptfc_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *));
>>+static void mptfc_set_rport_loss_tmo(struct fc_rport *rport, uint32_t timeout);
>>+static void __devexit mptfc_remove(struct pci_dev *pdev);
> 
> 	Please try to order functions so that forward-prototypes aren't
> 	needed.  (where easily possible)

In this case, most references are needed for the scsi_host_template
or the fc_function_template and I'm chosing to not move those function
templates.

> 
> 
>>+	.get_starget_node_name = NULL,
> 
> 	no need to initialize unused memembers of static structures to zero.

Agreed.

> 
>>+	p_p0 = p0_array =  kmalloc(data_sz,GFP_KERNEL);
>>+	if (!p0_array)
>>+		goto out;
>>+	memset((u8 *)p0_array, 0, data_sz);
>>+
>>+	data_sz = sizeof(FCDevicePage0_t *) * max_bus * max_targ;
>>+	p_pp0 = pp0_array = kmalloc(data_sz,GFP_KERNEL);
>>+	if (!pp0_array)
>>+		goto out;
>>+	memset((u8 *)pp0_array, 0, data_sz);
> 
> 	just use kzalloc in those two cases.
OK

> 	also please a whitespace after the , in arguments.
OK

> 
>>+		if (hdr.PageLength <= 0)
>>+			break;
>>+		else {
> 
> 	no need for the else here, the break already jumps out of the loop.
> 	and the lesser indentation should make the code quite a lot more
> 	readable aswell.

Nice catch.

> 
>>+			data_sz = hdr.PageLength * 4;
>>+			ppage0_alloc = (FCDevicePage0_t *) 
>>+ 					pci_alloc_consistent(ioc->pcidev, data_sz, &page0_dma);
> 
> 	mo need to cast the return value of pci_alloc_consistent.

OK

> 
> 
>>+			rc = -ENOMEM;
>>+			if (ppage0_alloc) {
> 
> 	just break out of the loop in the !ppage0_alloc case, reduces
> 	indentation again and makes the code fit into 80 columes.

OK

> 
>>+				memset((u8 *)ppage0_alloc, 0, data_sz);
> 
> 	pci_alloc_consistent returns zeroed memory.

OK

> 
> +				if ((rc = mpt_config(ioc, &cfg)) == 0) {
> +					le32_to_cpus(ppage0_alloc->PortIdentifier);
> +					le32_to_cpus(ppage0_alloc->WWNN.Low);
> +					le32_to_cpus(ppage0_alloc->WWNN.High);
> +					le32_to_cpus(ppage0_alloc->WWPN.Low);
> +					le32_to_cpus(ppage0_alloc->WWPN.High);
> +					le16_to_cpus(ppage0_alloc->BBCredit);
> +					le16_to_cpus(ppage0_alloc->MaxRxFrameSize);
> 
> 	please never use leXX_to_cpus but always leXX_to_cpu and assign to
> 	a separate variable.  Assigning hardware endian and host endian
> 	values to the same value defeats static typechecking with sparse.

OK

> 
>>+		ri = kmalloc(sizeof(struct mptfc_rport_info), GFP_KERNEL);
>>+ 		if (!ri)
>>+			return;
>>+		memset(ri, 0, sizeof(struct mptfc_rport_info));
> 
> 	case use kzalloc, too.
> 
>>+	INIT_WORK(&ioc->work_task, mptfc_rescan_devices,(void *)ioc);
> 
> 	could you calls this ioc->fc_rescan_work?  also no need for the
> 	void cast.

I had intended to create a "generic" work_task structure that could be
used by all personalities of the driver as, AFAIK, only one will
own an hba.  However, I understand the point and will change it.  If
this is important enough to me, I can make it a union later once the
dust settles.

> 
> @@ -332,6 +784,7 @@
>  	hd->scandv_wait_done = 0;
>  	hd->last_queue_full = 0;
>  
> +	sh->transportt = mptfc_transport_template;
>  	error = scsi_add_host (sh, &ioc->pcidev->dev);
>  	if(error) {
>  		dprintk((KERN_ERR MYNAM
> @@ -339,7 +792,11 @@
>  		goto out_mptfc_probe;
>  	}
>  
> -	scsi_scan_host(sh);
> +	for (ii=0; ii < ioc->facts.NumberOfPorts; ii++) {
> +		mptfc_init_host_attr(ioc,ii);
> +		mptfc_GetFcDevPage0(ioc,ii,mptfc_register_dev);
> +	}
> +
>  	return 0;
>  
>  out_mptfc_probe:
> 
>>+++ linux-2.6.15-git8-mdr/drivers/message/fusion/mptscsih.c	2006-01-12 16:09:08.000000000 -0600
>>@@ -58,6 +58,7 @@
>> #include <linux/workqueue.h>
>> 
>> #include <scsi/scsi.h>
>>+#include <scsi/scsi_transport_fc.h>
> 
> 	you must only use transport-class infrastructure in the per-transport
> 	files, but not in the common ones.

Another good catch.  This was left over from earlier code and not needed.

> 
> 
> 
> also don't we need a slave_destroy menthod, as in the SAS hotplug patches?
> And you should probably remove the scsi_scan_host call as all additions
> should be done through the FC transport class functionality.

I looked at your patch to mptsas for slave_destroy.  I believe that since the
fc_transport retains rport info for the case when the rport returns
after destroy, that mptfc should retain its data structure.

I'll think about this for a subsequent patch.  It's on my white board!
(No software is ever finished!)


scsi_scan_host was a delete, not an insert point....

> 

A revised patch will be forthcoming.

Mike


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH] mptfusion - fc transport attributes - REVISED
  2006-01-13 18:18   ` Michael Reed
@ 2006-01-13 18:22     ` Christoph Hellwig
  2006-01-13 20:31       ` Michael Reed
  0 siblings, 1 reply; 9+ messages in thread
From: Christoph Hellwig @ 2006-01-13 18:22 UTC (permalink / raw)
  To: Michael Reed
  Cc: Christoph Hellwig, linux-scsi, Moore, Eric Dean, Shirron, Stephen,
	Hickerson, Roger, Jeremy Higdon, Gary Hagensen

> This driver is full of lines longer than 80 characters....  I'll see what I can
> do.  I'm not planning on reworking the entire driver to shorten the line lengths
> but if there are obvious places in my patch, like above, I'll do what I can to
> conform.

sure, no need to fix up existing code - just don't introduce new ones.

> I suspect it should be a separate patch to clean up all the white space / style/long line / other issues in this driver.  :)

yeah, small cleanup patches are always nice, just don't mix them up with
real bugfixes or new features.

> > 	Please try to order functions so that forward-prototypes aren't
> > 	needed.  (where easily possible)
> 
> In this case, most references are needed for the scsi_host_template
> or the fc_function_template and I'm chosing to not move those function
> templates.

ok

> > 	could you calls this ioc->fc_rescan_work?  also no need for the
> > 	void cast.
> 
> I had intended to create a "generic" work_task structure that could be
> used by all personalities of the driver as, AFAIK, only one will
> own an hba.  However, I understand the point and will change it.  If
> this is important enough to me, I can make it a union later once the
> dust settles.

ok.

> I looked at your patch to mptsas for slave_destroy.  I believe that since the
> fc_transport retains rport info for the case when the rport returns
> after destroy, that mptfc should retain its data structure.

indeed, that makes sense.

> scsi_scan_host was a delete, not an insert point....

sorry, looks like I misread the patch.


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH] mptfusion - fc transport attributes - REVISED
  2006-01-13 18:22     ` Christoph Hellwig
@ 2006-01-13 20:31       ` Michael Reed
  2006-01-14 11:33         ` Christoph Hellwig
  0 siblings, 1 reply; 9+ messages in thread
From: Michael Reed @ 2006-01-13 20:31 UTC (permalink / raw)
  To: linux-scsi
  Cc: Christoph Hellwig, Moore, Eric Dean, Shirron, Stephen,
	Hickerson, Roger, Jeremy Higdon, Gary Hagensen, James Bottomley,
	James.Smart

[-- Attachment #1: Type: text/plain, Size: 361 bytes --]

OK.  I've re-based the code to work with scsi-misc and Christoph's
recent patches.  I've tested it on my ia64 test mule and it appears to
function as did the previous patch.

Perhaps the target will now stand still for a while?  :)

Attached is version 1f of the patch.  Previous versions should
be disregarded.

Mike

Signed-off-by: Michael Reed <mdr@sgi.com>

[-- Attachment #2: 1f-lsi_fc_transport.patch --]
[-- Type: text/x-patch, Size: 26360 bytes --]

diff -ru scsi-misc-2.6/drivers/message/fusion/mptbase.c scsi-misc-2.6-patched/drivers/message/fusion/mptbase.c
--- scsi-misc-2.6/drivers/message/fusion/mptbase.c	2006-01-13 12:39:21.000000000 -0600
+++ scsi-misc-2.6-patched/drivers/message/fusion/mptbase.c	2006-01-13 13:32:54.000000000 -0600
@@ -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);
@@ -1244,6 +1243,8 @@
 	ioc->pcidev = pdev;
 	ioc->diagPending = 0;
 	spin_lock_init(&ioc->diagLock);
+	spin_lock_init(&ioc->fc_rescan_work_lock);
+	spin_lock_init(&ioc->fc_rport_lock);
 	spin_lock_init(&ioc->initializing_hba_lock);
 
 	/* Initialize the event logging.
@@ -1267,6 +1268,10 @@
 	 */
 	INIT_LIST_HEAD(&ioc->configQ);
 
+	/* Initialize the fc rport list head.
+	 */
+	INIT_LIST_HEAD(&ioc->fc_rports);
+
 	/* Find lookup slot. */
 	INIT_LIST_HEAD(&ioc->list);
 	ioc->id = mpt_ids++;
@@ -1879,7 +1884,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) &&
@@ -4198,7 +4203,7 @@
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
- *	GetFcPortPage0 - Fetch FCPort config Page0.
+ *	mptbase_GetFcPortPage0 - Fetch FCPort config Page0.
  *	@ioc: Pointer to MPT_ADAPTER structure
  *	@portnum: IOC Port number
  *
@@ -4208,8 +4213,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;
@@ -4219,6 +4224,8 @@
 	int			 data_sz;
 	int			 copy_sz;
 	int			 rc;
+	int			 count = 400;
+
 
 	/* Get FCPort Page 0 header */
 	hdr.PageVersion = 0;
@@ -4242,6 +4249,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;
@@ -4273,6 +4282,19 @@
 			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;
+				}
+				printk(MYIOC_s_INFO_FMT "Firmware discovery not"
+							" complete.\n",
+						ioc->name);
+			}
 		}
 
 		pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage0_alloc, page0_dma);
@@ -6357,6 +6379,7 @@
 EXPORT_SYMBOL(mpt_free_fw_memory);
 EXPORT_SYMBOL(mptbase_sas_persist_operation);
 EXPORT_SYMBOL(mpt_alt_ioc_wait);
+EXPORT_SYMBOL(mptbase_GetFcPortPage0);
 
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
diff -ru scsi-misc-2.6/drivers/message/fusion/mptbase.h scsi-misc-2.6-patched/drivers/message/fusion/mptbase.h
--- scsi-misc-2.6/drivers/message/fusion/mptbase.h	2006-01-13 12:39:07.000000000 -0600
+++ scsi-misc-2.6-patched/drivers/message/fusion/mptbase.h	2006-01-13 13:34:36.000000000 -0600
@@ -76,8 +76,8 @@
 #define COPYRIGHT	"Copyright (c) 1999-2005 " MODULEAUTHOR
 #endif
 
-#define MPT_LINUX_VERSION_COMMON	"3.03.05"
-#define MPT_LINUX_PACKAGE_NAME		"@(#)mptlinux-3.03.05"
+#define MPT_LINUX_VERSION_COMMON	"3.03.06"
+#define MPT_LINUX_PACKAGE_NAME		"@(#)mptlinux-3.03.06"
 #define WHAT_MAGIC_STRING		"@" "(" "#" ")"
 
 #define show_mptmod_ver(s,ver)  \
@@ -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
  */
@@ -614,6 +630,13 @@
 	struct list_head	 sas_topology;
 	struct mutex		 sas_topology_mutex;
 	MPT_SAS_MGMT		 sas_mgmt;
+
+	struct list_head	 fc_rports;
+	spinlock_t		 fc_rport_lock; /* list and ri flags */
+	spinlock_t		 fc_rescan_work_lock;
+	int			 fc_rescan_work_count;
+	struct work_struct	 fc_rescan_work;
+
 } MPT_ADAPTER;
 
 /*
@@ -1000,6 +1023,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);
 
 /*
diff -ru scsi-misc-2.6/drivers/message/fusion/mptfc.c scsi-misc-2.6-patched/drivers/message/fusion/mptfc.c
--- scsi-misc-2.6/drivers/message/fusion/mptfc.c	2006-01-13 12:39:21.000000000 -0600
+++ scsi-misc-2.6-patched/drivers/message/fusion/mptfc.c	2006-01-13 13:32:54.000000000 -0600
@@ -55,12 +55,14 @@
 #include <linux/reboot.h>	/* notifier code */
 #include <linux/sched.h>
 #include <linux/workqueue.h>
+#include <linux/sort.h>
 
 #include <scsi/scsi.h>
 #include <scsi/scsi_cmnd.h>
 #include <scsi/scsi_device.h>
 #include <scsi/scsi_host.h>
 #include <scsi/scsi_tcq.h>
+#include <scsi/scsi_transport_fc.h>
 
 #include "mptbase.h"
 #include "mptscsih.h"
@@ -79,19 +81,34 @@
 module_param(mpt_pq_filter, int, 0);
 MODULE_PARM_DESC(mpt_pq_filter, " Enable peripheral qualifier filter: enable=1  (default=0)");
 
+#define MPTFC_DEV_LOSS_TMO (60)
+static int mptfc_dev_loss_tmo = MPTFC_DEV_LOSS_TMO;	/* reasonable default */
+module_param(mptfc_dev_loss_tmo, int, 0);
+MODULE_PARM_DESC(mptfc_dev_loss_tmo, " Initial time the driver programs the "
+    				     " transport to wait for an rport to "
+				     " return following a device loss event."
+				     "  Default=60.");
+
 static int	mptfcDoneCtx = -1;
 static int	mptfcTaskCtx = -1;
 static int	mptfcInternalCtx = -1; /* Used only for internal commands */
 
+int mptfc_slave_alloc(struct scsi_device *device);
+static int mptfc_qcmd(struct scsi_cmnd *SCpnt,
+    void (*done)(struct scsi_cmnd *));
+
+static void mptfc_set_rport_loss_tmo(struct fc_rport *rport, uint32_t timeout);
+static void __devexit mptfc_remove(struct pci_dev *pdev);
+
 static struct scsi_host_template mptfc_driver_template = {
 	.module				= THIS_MODULE,
 	.proc_name			= "mptfc",
 	.proc_info			= mptscsih_proc_info,
 	.name				= "MPT FC Host",
 	.info				= mptscsih_info,
-	.queuecommand			= mptscsih_qcmd,
+	.queuecommand			= mptfc_qcmd,
 	.target_alloc			= mptscsih_target_alloc,
-	.slave_alloc			= mptscsih_slave_alloc,
+	.slave_alloc			= mptfc_slave_alloc,
 	.slave_configure		= mptscsih_slave_configure,
 	.target_destroy			= mptscsih_target_destroy,
 	.slave_destroy			= mptscsih_slave_destroy,
@@ -132,15 +149,472 @@
 };
 MODULE_DEVICE_TABLE(pci, mptfc_pci_table);
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static struct scsi_transport_template *mptfc_transport_template = NULL;
+
+struct fc_function_template mptfc_transport_functions = {
+	.dd_fcrport_size = 8,
+	.show_host_node_name = 1,
+	.show_host_port_name = 1,
+	.show_host_supported_classes = 1,
+	.show_host_port_id = 1,
+	.show_rport_supported_classes = 1,
+	.show_starget_node_name = 1,
+	.show_starget_port_name = 1,
+	.show_starget_port_id = 1,
+	.set_rport_dev_loss_tmo = mptfc_set_rport_loss_tmo,
+	.show_rport_dev_loss_tmo = 1,
+
+};
+
+/* FIXME! values controlling firmware RESCAN event
+ * need to be set low to allow dev_loss_tmo to
+ * work as expected.  Currently, firmware doesn't
+ * notify driver of RESCAN event until some number
+ * of seconds elapse.  This value can be set via
+ * lsiutil.
+ */
+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;
+}
+
+static int
+mptfc_FcDevPage0_cmp_func(const void *a, const void *b)
+{
+	FCDevicePage0_t **aa = (FCDevicePage0_t **)a;
+	FCDevicePage0_t **bb = (FCDevicePage0_t **)b;
+
+	if ((*aa)->CurrentBus == (*bb)->CurrentBus) {
+		if ((*aa)->CurrentTargetID == (*bb)->CurrentTargetID)
+			return 0;
+		if ((*aa)->CurrentTargetID < (*bb)->CurrentTargetID)
+			return -1;
+		return 1;
+	}
+	if ((*aa)->CurrentBus < (*bb)->CurrentBus)
+		return -1;
+	return 1;
+}
+
+static int
+mptfc_GetFcDevPage0(MPT_ADAPTER *ioc, int ioc_port,
+	void(*func)(MPT_ADAPTER *ioc,int channel, FCDevicePage0_t *arg))
+{
+	ConfigPageHeader_t	 hdr;
+	CONFIGPARMS		 cfg;
+	FCDevicePage0_t		*ppage0_alloc, *fc;
+	dma_addr_t		 page0_dma;
+	int			 data_sz;
+	int			 ii;
+
+	FCDevicePage0_t		*p0_array=NULL, *p_p0;
+	FCDevicePage0_t		**pp0_array=NULL, **p_pp0;
+
+	int			 rc = -ENOMEM;
+	U32			 port_id = 0xffffff;
+	int			 num_targ = 0;
+	int			 max_bus = ioc->facts.MaxBuses;
+	int			 max_targ = ioc->facts.MaxDevices;
+
+	if (max_bus == 0 || max_targ == 0)
+		goto out;
+
+	data_sz = sizeof(FCDevicePage0_t) * max_bus * max_targ;
+	p_p0 = p0_array =  kzalloc(data_sz, GFP_KERNEL);
+	if (!p0_array)
+		goto out;
+
+	data_sz = sizeof(FCDevicePage0_t *) * max_bus * max_targ;
+	p_pp0 = pp0_array = kzalloc(data_sz, GFP_KERNEL);
+	if (!pp0_array)
+		goto out;
+
+	do {
+		/* Get FC Device Page 0 header */
+		hdr.PageVersion = 0;
+		hdr.PageLength = 0;
+		hdr.PageNumber = 0;
+		hdr.PageType = MPI_CONFIG_PAGETYPE_FC_DEVICE;
+		cfg.cfghdr.hdr = &hdr;
+		cfg.physAddr = -1;
+		cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+		cfg.dir = 0;
+		cfg.pageAddr = port_id;
+		cfg.timeout = 0;
+
+		if ((rc = mpt_config(ioc, &cfg)) != 0)
+			break;
+
+		if (hdr.PageLength <= 0)
+			break;
+
+		data_sz = hdr.PageLength * 4;
+		ppage0_alloc = pci_alloc_consistent(ioc->pcidev, data_sz,
+		    					&page0_dma);
+		rc = -ENOMEM;
+		if (!ppage0_alloc)
+			break;
+
+		cfg.physAddr = page0_dma;
+		cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+
+		if ((rc = mpt_config(ioc, &cfg)) == 0) {
+			ppage0_alloc->PortIdentifier =
+				le32_to_cpu(ppage0_alloc->PortIdentifier);
+
+			ppage0_alloc->WWNN.Low =
+				le32_to_cpu(ppage0_alloc->WWNN.Low);
+
+			ppage0_alloc->WWNN.High =
+				le32_to_cpu(ppage0_alloc->WWNN.High);
+
+			ppage0_alloc->WWPN.Low =
+				le32_to_cpu(ppage0_alloc->WWPN.Low);
+
+			ppage0_alloc->WWPN.High =
+				le32_to_cpu(ppage0_alloc->WWPN.High);
+
+			ppage0_alloc->BBCredit =
+				le16_to_cpu(ppage0_alloc->BBCredit);
+
+			ppage0_alloc->MaxRxFrameSize =
+				le16_to_cpu(ppage0_alloc->MaxRxFrameSize);
+
+			port_id = ppage0_alloc->PortIdentifier;
+			num_targ++;
+			*p_p0 = *ppage0_alloc;	/* save data */
+			*p_pp0++ = p_p0++;	/* save addr */
+		}
+		pci_free_consistent(ioc->pcidev, data_sz,
+		    			(u8 *) ppage0_alloc, page0_dma);
+		if (rc != 0)
+			break;
+
+	} while (port_id <= 0xff0000);
+
+	if (num_targ) {
+		/* sort array */
+		if (num_targ > 1)
+			sort (pp0_array, num_targ, sizeof(FCDevicePage0_t *),
+				mptfc_FcDevPage0_cmp_func, NULL);
+		/* call caller's func for each targ */
+		for (ii = 0; ii < num_targ;  ii++) {
+			fc = *(pp0_array+ii);
+			func(ioc, ioc_port, fc);
+		}
+	}
+
+ out:
+	if (pp0_array)
+		kfree(pp0_array);
+	if (p0_array)
+		kfree(p0_array);
+	return rc;
+}
+
+static int
+mptfc_generate_rport_ids(FCDevicePage0_t *pg0, struct fc_rport_identifiers *rid)
+{
+	/* not currently usable */
+	if (pg0->Flags & (MPI_FC_DEVICE_PAGE0_FLAGS_PLOGI_INVALID |
+			  MPI_FC_DEVICE_PAGE0_FLAGS_PRLI_INVALID))
+		return -1;
+
+	if (!(pg0->Flags & MPI_FC_DEVICE_PAGE0_FLAGS_TARGETID_BUS_VALID))
+		return -1;
+
+	if (!(pg0->Protocol & MPI_FC_DEVICE_PAGE0_PROT_FCP_TARGET))
+		return -1;
+
+	/*
+	 * board data structure already normalized to platform endianness
+	 * shifted to avoid unaligned access on 64 bit architecture
+	 */
+	rid->node_name = ((u64)pg0->WWNN.High) << 32 | (u64)pg0->WWNN.Low;
+	rid->port_name = ((u64)pg0->WWPN.High) << 32 | (u64)pg0->WWPN.Low;
+	rid->port_id =   pg0->PortIdentifier;
+	rid->roles = FC_RPORT_ROLE_UNKNOWN;
+	rid->roles |= FC_RPORT_ROLE_FCP_TARGET;
+	if (pg0->Protocol & MPI_FC_DEVICE_PAGE0_PROT_FCP_INITIATOR)
+		rid->roles |= FC_RPORT_ROLE_FCP_INITIATOR;
+
+	return 0;
+}
+
+static void
+mptfc_register_dev(MPT_ADAPTER *ioc, int channel, FCDevicePage0_t *pg0)
+{
+	struct fc_rport_identifiers rport_ids;
+	struct fc_rport		*rport;
+	struct mptfc_rport_info	*ri;
+	int			match = 0;
+	u64			port_name;
+	unsigned long		flags;
+
+	if (mptfc_generate_rport_ids(pg0, &rport_ids) < 0)
+		return;
+
+	/* scan list looking for a match */
+	spin_lock_irqsave(&ioc->fc_rport_lock, flags);
+	list_for_each_entry(ri, &ioc->fc_rports, list) {
+		port_name = (u64)ri->pg0.WWPN.High << 32 | (u64)ri->pg0.WWPN.Low;
+		if (port_name == rport_ids.port_name) {	/* match */
+			list_move_tail(&ri->list, &ioc->fc_rports);
+			match = 1;
+			break;
+		}
+	}
+	if (!match) {	/* allocate one */
+		spin_unlock_irqrestore(&ioc->fc_rport_lock, flags);
+		ri = kzalloc(sizeof(struct mptfc_rport_info), GFP_KERNEL);
+		if (!ri)
+			return;
+		spin_lock_irqsave(&ioc->fc_rport_lock, flags);
+		list_add_tail(&ri->list, &ioc->fc_rports);
+	}
+
+	ri->pg0 = *pg0;	/* add/update pg0 data */
+	ri->flags &= ~MPT_RPORT_INFO_FLAGS_MISSING;
+
+	if (!(ri->flags & MPT_RPORT_INFO_FLAGS_REGISTERED)) {
+		ri->flags |= MPT_RPORT_INFO_FLAGS_REGISTERED;
+		spin_unlock_irqrestore(&ioc->fc_rport_lock, flags);
+		rport = fc_remote_port_add(ioc->sh,channel, &rport_ids);
+		spin_lock_irqsave(&ioc->fc_rport_lock, flags);
+		if (rport) {
+			if (*((struct mptfc_rport_info **)rport->dd_data) != ri) {
+				ri->flags &= ~MPT_RPORT_INFO_FLAGS_MAPPED_VDEV;
+				ri->vdev = NULL;
+				ri->rport = rport;
+				*((struct mptfc_rport_info **)rport->dd_data) = ri;
+			}
+			rport->dev_loss_tmo = mptfc_dev_loss_tmo;
+			/*
+			 * if already mapped, remap here.  If not mapped,
+			 * slave_alloc will allocate vdev and map
+			 */
+			if (ri->flags & MPT_RPORT_INFO_FLAGS_MAPPED_VDEV) {
+				ri->vdev->target_id = ri->pg0.CurrentTargetID;
+				ri->vdev->bus_id = ri->pg0.CurrentBus;
+				ri->vdev->vtarget->target_id = ri->vdev->target_id;
+				ri->vdev->vtarget->bus_id = ri->vdev->bus_id;
+			}
+			#ifdef MPT_DEBUG
+			printk ("mptfc_reg_dev.%d: %x, %llx / %llx, tid %d, "
+				"rport tid %d, tmo %d\n",
+					ioc->sh->host_no,
+					pg0->PortIdentifier,
+					pg0->WWNN,
+					pg0->WWPN,
+					pg0->CurrentTargetID,
+					ri->rport->scsi_target_id,
+					ri->rport->dev_loss_tmo);
+			#endif
+		} else {
+			list_del(&ri->list);
+			kfree(ri);
+			ri = NULL;
+		}
+	}
+	spin_unlock_irqrestore(&ioc->fc_rport_lock,flags);
+
+}
+
 /*
- *	mptfc_probe - Installs scsi devices per bus.
- *	@pdev: Pointer to pci_dev structure
- *
- *	Returns 0 for success, non-zero for failure.
- *
+ *	OS entry point to allow host driver to alloc memory
+ *	for each scsi device. Called once per device the bus scan.
+ *	Return non-zero if allocation fails.
+ *	Init memory once per LUN.
  */
+int
+mptfc_slave_alloc(struct scsi_device *sdev)
+{
+	MPT_SCSI_HOST		*hd;
+	VirtTarget		*vtarget;
+	VirtDevice		*vdev;
+	struct scsi_target	*starget;
+	struct fc_rport		*rport;
+	struct mptfc_rport_info *ri;
+	unsigned long		flags;
+
+
+	rport = starget_to_rport(scsi_target(sdev));
+
+	if (!rport || fc_remote_port_chkready(rport))
+		return -ENXIO;
+
+	hd = (MPT_SCSI_HOST *)sdev->host->hostdata;
+
+	vdev = kmalloc(sizeof(VirtDevice), GFP_KERNEL);
+	if (!vdev) {
+		printk(MYIOC_s_ERR_FMT "slave_alloc kmalloc(%zd) FAILED!\n",
+				hd->ioc->name, sizeof(VirtDevice));
+		return -ENOMEM;
+	}
+	memset(vdev, 0, sizeof(VirtDevice));
+
+	spin_lock_irqsave(&hd->ioc->fc_rport_lock,flags);
+
+	if (!(ri = *((struct mptfc_rport_info **)rport->dd_data))) {
+		spin_unlock_irqrestore(&hd->ioc->fc_rport_lock,flags);
+		kfree(vdev);
+		return -ENODEV;
+	}
+
+	sdev->hostdata = vdev;
+	starget = scsi_target(sdev);
+	vtarget = starget->hostdata;
+	if (vtarget->num_luns == 0) {
+		vtarget->tflags = MPT_TARGET_FLAGS_Q_YES |
+		    		  MPT_TARGET_FLAGS_VALID_INQUIRY;
+		hd->Targets[sdev->id] = vtarget;
+	}
+
+	vtarget->target_id = vdev->target_id;
+	vtarget->bus_id = vdev->bus_id;
+
+	vdev->vtarget = vtarget;
+	vdev->ioc_id = hd->ioc->id;
+	vdev->lun = sdev->lun;
+	vdev->target_id = ri->pg0.CurrentTargetID;
+	vdev->bus_id = ri->pg0.CurrentBus;
+
+	ri->flags |= MPT_RPORT_INFO_FLAGS_MAPPED_VDEV;
+	ri->vdev = vdev;
+
+	spin_unlock_irqrestore(&hd->ioc->fc_rport_lock,flags);
+
+	vtarget->num_luns++;
+
+#ifdef MPT_DEBUG
+	printk ("mptfc_slv_alloc.%d: num_luns %d, sdev.id %d, "
+	        "CurrentTargetID %d, %x %llx %llx\n",
+			sdev->host->host_no,
+			vtarget->num_luns,
+			sdev->id, ri->pg0.CurrentTargetID,
+			ri->pg0.PortIdentifier, ri->pg0.WWPN, ri->pg0.WWNN);
+#endif
+
+	return 0;
+}
+
+static int
+mptfc_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
+{
+	struct fc_rport	*rport = starget_to_rport(scsi_target(SCpnt->device));
+	int		err;
+
+	err = fc_remote_port_chkready(rport);
+	if (unlikely(err)) {
+		SCpnt->result = err;
+		done(SCpnt);
+		return 0;
+	}
+	return mptscsih_qcmd(SCpnt,done);
+}
+
+static void
+mptfc_init_host_attr(MPT_ADAPTER *ioc,int portnum)
+{
+	unsigned class = 0, cos = 0;
+
+	/* don't know what to do as only one scsi (fc) host was allocated */
+	if (portnum != 0)
+		return;
+
+	class = ioc->fc_port_page0[portnum].SupportedServiceClass;
+	if (class & MPI_FCPORTPAGE0_SUPPORT_CLASS_1)
+		cos |= FC_COS_CLASS1;
+	if (class & MPI_FCPORTPAGE0_SUPPORT_CLASS_2)
+		cos |= FC_COS_CLASS2;
+	if (class & MPI_FCPORTPAGE0_SUPPORT_CLASS_3)
+		cos |= FC_COS_CLASS3;
+
+	fc_host_node_name(ioc->sh) =
+	    	(u64)ioc->fc_port_page0[portnum].WWNN.High << 32
+		    | (u64)ioc->fc_port_page0[portnum].WWNN.Low;
+
+	fc_host_port_name(ioc->sh) =
+	    	(u64)ioc->fc_port_page0[portnum].WWPN.High << 32
+		    | (u64)ioc->fc_port_page0[portnum].WWPN.Low;
+
+	fc_host_port_id(ioc->sh) = ioc->fc_port_page0[portnum].PortIdentifier;
+
+	fc_host_supported_classes(ioc->sh) = cos;
+
+	fc_host_tgtid_bind_type(ioc->sh) = FC_TGTID_BIND_BY_WWPN;
+}
+
+static void
+mptfc_rescan_devices(void *arg)
+{
+	MPT_ADAPTER		*ioc = (MPT_ADAPTER *)arg;
+	int			ii;
+	int			work_to_do;
+	unsigned long		flags;
+	struct mptfc_rport_info *ri;
+
+	do {
+		/* start by tagging all ports as missing */
+		spin_lock_irqsave(&ioc->fc_rport_lock,flags);
+		list_for_each_entry(ri, &ioc->fc_rports, list) {
+			if (ri->flags & MPT_RPORT_INFO_FLAGS_REGISTERED) {
+				ri->flags |= MPT_RPORT_INFO_FLAGS_MISSING;
+			}
+		}
+		spin_unlock_irqrestore(&ioc->fc_rport_lock,flags);
+
+		/*
+		 * now rescan devices known to adapter,
+		 * will reregister existing rports
+		 */
+		for (ii=0; ii < ioc->facts.NumberOfPorts; ii++) {
+			(void) mptbase_GetFcPortPage0(ioc, ii);
+			mptfc_init_host_attr(ioc,ii);	/* refresh */
+			mptfc_GetFcDevPage0(ioc,ii,mptfc_register_dev);
+		}
+
+		/* delete devices still missing */
+		spin_lock_irqsave(&ioc->fc_rport_lock, flags);
+		list_for_each_entry(ri, &ioc->fc_rports, list) {
+			/* if newly missing, delete it */
+			if ((ri->flags & (MPT_RPORT_INFO_FLAGS_REGISTERED |
+					  MPT_RPORT_INFO_FLAGS_MISSING))
+			  == (MPT_RPORT_INFO_FLAGS_REGISTERED |
+			      MPT_RPORT_INFO_FLAGS_MISSING)) {
+
+				ri->flags &= ~(MPT_RPORT_INFO_FLAGS_REGISTERED|
+					       MPT_RPORT_INFO_FLAGS_MISSING);
+				fc_remote_port_delete(ri->rport);
+				/*
+				 * remote port not really deleted 'cause
+				 * binding is by WWPN and driver only
+				 * registers FCP_TARGETs
+				 */
+				#ifdef MPT_DEBUG
+				printk ("mptfc_rescan.%d: %llx deleted\n",
+					ioc->sh->host_no, ri->pg0.WWPN);
+				#endif
+			}
+		}
+		spin_unlock_irqrestore(&ioc->fc_rport_lock,flags);
+
+		/*
+		 * allow multiple passes as target state
+		 * might have changed during scan
+		 */
+		spin_lock_irqsave(&ioc->fc_rescan_work_lock, flags);
+		if (ioc->fc_rescan_work_count > 2) 	/* only need one more */
+			ioc->fc_rescan_work_count = 2;
+		work_to_do = --ioc->fc_rescan_work_count;
+		spin_unlock_irqrestore(&ioc->fc_rescan_work_lock, flags);
+	} while (work_to_do);
+}
+
 static int
 mptfc_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 {
@@ -154,10 +628,10 @@
 	int			 ioc_cap;
 	int			error=0;
 	int			r;
-		
+
 	if ((r = mpt_attach(pdev,id)) != 0)
 		return r;
-	
+
 	ioc = pci_get_drvdata(pdev);
 	ioc->DoneCtx = mptfcDoneCtx;
 	ioc->TaskCtx = mptfcTaskCtx;
@@ -193,7 +667,7 @@
 		printk(MYIOC_s_WARN_FMT
 			"Skipping ioc=%p because SCSI Initiator mode is NOT enabled!\n",
 			ioc->name, ioc);
-		return 0;
+		return -ENODEV;
 	}
 
 	sh = scsi_host_alloc(&mptfc_driver_template, sizeof(MPT_SCSI_HOST));
@@ -206,6 +680,8 @@
 		goto out_mptfc_probe;
         }
 
+	INIT_WORK(&ioc->fc_rescan_work, mptfc_rescan_devices,(void *)ioc);
+
 	spin_lock_irqsave(&ioc->FreeQlock, flags);
 
 	/* Attach the SCSI Host to the IOC structure
@@ -322,6 +798,7 @@
 	hd->scandv_wait_done = 0;
 	hd->last_queue_full = 0;
 
+	sh->transportt = mptfc_transport_template;
 	error = scsi_add_host (sh, &ioc->pcidev->dev);
 	if(error) {
 		dprintk((KERN_ERR MYNAM
@@ -329,7 +806,11 @@
 		goto out_mptfc_probe;
 	}
 
-	scsi_scan_host(sh);
+	for (ii=0; ii < ioc->facts.NumberOfPorts; ii++) {
+		mptfc_init_host_attr(ioc,ii);
+		mptfc_GetFcDevPage0(ioc,ii,mptfc_register_dev);
+	}
+
 	return 0;
 
 out_mptfc_probe:
@@ -342,7 +823,7 @@
 	.name		= "mptfc",
 	.id_table	= mptfc_pci_table,
 	.probe		= mptfc_probe,
-	.remove		= __devexit_p(mptscsih_remove),
+	.remove		= __devexit_p(mptfc_remove),
 	.shutdown	= mptscsih_shutdown,
 #ifdef CONFIG_PM
 	.suspend	= mptscsih_suspend,
@@ -360,9 +841,20 @@
 static int __init
 mptfc_init(void)
 {
+	int error;
 
 	show_mptmod_ver(my_NAME, my_VERSION);
 
+	/* sanity check module parameter */
+	if (mptfc_dev_loss_tmo == 0)
+		mptfc_dev_loss_tmo = MPTFC_DEV_LOSS_TMO;
+
+	mptfc_transport_template =
+		fc_attach_transport(&mptfc_transport_functions);
+
+	if (!mptfc_transport_template)
+		return -ENODEV;
+
 	mptfcDoneCtx = mpt_register(mptscsih_io_done, MPTFC_DRIVER);
 	mptfcTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTFC_DRIVER);
 	mptfcInternalCtx = mpt_register(mptscsih_scandv_complete, MPTFC_DRIVER);
@@ -377,7 +869,33 @@
 		  ": Registered for IOC reset notifications\n"));
 	}
 
-	return pci_register_driver(&mptfc_driver);
+	error = pci_register_driver(&mptfc_driver);
+	if (error) {
+		fc_release_transport(mptfc_transport_template);
+	}
+
+	return error;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *	mptfc_remove - Removed fc infrastructure for devices
+ *	@pdev: Pointer to pci_dev structure
+ *
+ */
+static void __devexit mptfc_remove(struct pci_dev *pdev)
+{
+	MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
+	struct mptfc_rport_info *p, *n;
+
+	fc_remove_host(ioc->sh);
+
+	list_for_each_entry_safe(p, n, &ioc->fc_rports, list) {
+		list_del(&p->list);
+		kfree(p);
+	}
+
+	mptscsih_remove(pdev);
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -390,7 +908,8 @@
 mptfc_exit(void)
 {
 	pci_unregister_driver(&mptfc_driver);
-	
+	fc_release_transport(mptfc_transport_template);
+
 	mpt_reset_deregister(mptfcDoneCtx);
 	dprintk((KERN_INFO MYNAM
 	  ": Deregistered for IOC reset notifications\n"));
diff -ru scsi-misc-2.6/drivers/message/fusion/mptscsih.c scsi-misc-2.6-patched/drivers/message/fusion/mptscsih.c
--- scsi-misc-2.6/drivers/message/fusion/mptscsih.c	2006-01-13 12:39:21.000000000 -0600
+++ scsi-misc-2.6-patched/drivers/message/fusion/mptscsih.c	2006-01-13 14:26:51.000000000 -0600
@@ -893,6 +893,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
  *
@@ -2557,13 +2558,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->fc_rescan_work_lock, flags);
+			work_count = ++ioc->fc_rescan_work_count;
+			spin_unlock_irqrestore(&ioc->fc_rescan_work_lock, flags);
+			if (work_count == 1)
+				schedule_work(&ioc->fc_rescan_work);
+		}
 		dtmprintk((MYIOC_s_WARN_FMT "Post-Reset complete.\n", ioc->name));
 
 	}
@@ -2587,6 +2600,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));
@@ -2608,11 +2623,18 @@
 		/* FIXME! */
 		break;
 
+	case MPI_EVENT_RESCAN:				/* 06 */
+		spin_lock_irqsave(&ioc->fc_rescan_work_lock, flags);
+		work_count = ++ioc->fc_rescan_work_count;
+		spin_unlock_irqrestore(&ioc->fc_rescan_work_lock, flags);
+		if (work_count == 1)
+			schedule_work(&ioc->fc_rescan_work);
+		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 */
 		/*
@@ -3952,8 +3974,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)
 {

^ permalink raw reply	[flat|nested] 9+ messages in thread

* RE: [PATCH] mptfusion - fc transport attributes - REVISED
@ 2006-01-13 21:00 Moore, Eric
  0 siblings, 0 replies; 9+ messages in thread
From: Moore, Eric @ 2006-01-13 21:00 UTC (permalink / raw)
  To: Michael Reed, linux-scsi
  Cc: Shirron, Stephen, Hickerson, Roger, Jeremy Higdon, Gary Hagensen

I had steped out for lunch, and just got back.
I'm in the process of patching, testing this.

Thankyou,
Eric

> -----Original Message-----
> From: Michael Reed [mailto:mdr@sgi.com] 
> Sent: Friday, January 13, 2006 1:32 PM
> To: linux-scsi
> Cc: Christoph Hellwig; Moore, Eric; Shirron, Stephen; 
> Hickerson, Roger; Jeremy Higdon; Gary Hagensen; James 
> Bottomley; James.Smart@Emulex.Com
> Subject: Re: [PATCH] mptfusion - fc transport attributes - REVISED
> 
> OK.  I've re-based the code to work with scsi-misc and Christoph's
> recent patches.  I've tested it on my ia64 test mule and it appears to
> function as did the previous patch.
> 
> Perhaps the target will now stand still for a while?  :)
> 
> Attached is version 1f of the patch.  Previous versions should
> be disregarded.
> 
> Mike
> 
> Signed-off-by: Michael Reed <mdr@sgi.com>
> 

^ permalink raw reply	[flat|nested] 9+ messages in thread

* RE: [PATCH] mptfusion - fc transport attributes - REVISED
@ 2006-01-13 23:06 Moore, Eric
  0 siblings, 0 replies; 9+ messages in thread
From: Moore, Eric @ 2006-01-13 23:06 UTC (permalink / raw)
  To: Michael Reed, linux-scsi
  Cc: Christoph Hellwig, Shirron, Stephen, Hickerson, Roger,
	Jeremy Higdon, Gary Hagensen, James Bottomley, James.Smart

On Friday, January 13, 2006 1:32 PM,  Michael Reed wrote:
> OK.  I've re-based the code to work with scsi-misc and Christoph's
> recent patches.  I've tested it on my ia64 test mule and it appears to
> function as did the previous patch.
> 
> Perhaps the target will now stand still for a while?  :)
> 
> Attached is version 1f of the patch.  Previous versions should
> be disregarded.
> 
> Mike
> 
> Signed-off-by: Michael Reed <mdr@sgi.com>
>

ACK, please apply

Signed-off-by: Eric Moore <Eric.Moore@lsil.com>

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH] mptfusion - fc transport attributes - REVISED
  2006-01-13 20:31       ` Michael Reed
@ 2006-01-14 11:33         ` Christoph Hellwig
  0 siblings, 0 replies; 9+ messages in thread
From: Christoph Hellwig @ 2006-01-14 11:33 UTC (permalink / raw)
  To: Michael Reed
  Cc: linux-scsi, Christoph Hellwig, Moore, Eric Dean, Shirron, Stephen,
	Hickerson, Roger, Jeremy Higdon, Gary Hagensen, James Bottomley,
	James.Smart

On Fri, Jan 13, 2006 at 02:31:54PM -0600, Michael Reed wrote:
> OK.  I've re-based the code to work with scsi-misc and Christoph's
> recent patches.  I've tested it on my ia64 test mule and it appears to
> function as did the previous patch.
> 
> Perhaps the target will now stand still for a while?  :)
> 
> Attached is version 1f of the patch.  Previous versions should
> be disregarded.

looks good.


^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2006-01-14 11:33 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-01-12 23:04 [PATCH] mptfusion - fc transport attributes - REVISED Michael Reed
2006-01-13 10:31 ` Christoph Hellwig
2006-01-13 18:18   ` Michael Reed
2006-01-13 18:22     ` Christoph Hellwig
2006-01-13 20:31       ` Michael Reed
2006-01-14 11:33         ` Christoph Hellwig
  -- strict thread matches above, loose matches on Subject: below --
2006-01-12 23:17 Moore, Eric
2006-01-13 21:00 Moore, Eric
2006-01-13 23:06 Moore, Eric

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).