Commit 05e8ec17 authored by Michael Reed's avatar Michael Reed Committed by James Bottomley
Browse files

[SCSI] mptfusion - fc transport attributes

parent d158d261
Loading
Loading
Loading
Loading
+28 −5
Original line number Diff line number Diff line
@@ -148,7 +148,6 @@ static int WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
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 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
	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 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
	 */
	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 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
			 *  (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 @@ GetLanConfigPages(MPT_ADAPTER *ioc)

/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/*
 *	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 @@ GetLanConfigPages(MPT_ADAPTER *ioc)
 *		-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 @@ GetFcPortPage0(MPT_ADAPTER *ioc, int portnum)
	int			 data_sz;
	int			 copy_sz;
	int			 rc;
	int			 count = 400;


	/* Get FCPort Page 0 header */
	hdr.PageVersion = 0;
@@ -4242,6 +4249,8 @@ GetFcPortPage0(MPT_ADAPTER *ioc, int portnum)
	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 @@ GetFcPortPage0(MPT_ADAPTER *ioc, int portnum)
			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_alloc_fw_memory);
EXPORT_SYMBOL(mpt_free_fw_memory);
EXPORT_SYMBOL(mptbase_sas_persist_operation);
EXPORT_SYMBOL(mpt_alt_ioc_wait);
EXPORT_SYMBOL(mptbase_GetFcPortPage0);


/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+26 −2
Original line number Diff line number Diff line
@@ -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 @@ typedef struct _RaidCfgData {
	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 @@ typedef struct _MPT_ADAPTER
	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 void mpt_free_fw_memory(MPT_ADAPTER *ioc);
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);

/*
+535 −16
Original line number Diff line number Diff line
@@ -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 @@ static int mpt_pq_filter = 0;
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 @@ static struct pci_device_id mptfc_pci_table[] = {
};
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;

	/*
 *	mptfc_probe - Installs scsi devices per bus.
 *	@pdev: Pointer to pci_dev structure
 *
 *	Returns 0 for success, non-zero for failure.
 *
	 * 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);

}

/*
 *	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)
{
@@ -193,7 +667,7 @@ mptfc_probe(struct pci_dev *pdev, const struct pci_device_id *id)
		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 @@ mptfc_probe(struct pci_dev *pdev, const struct pci_device_id *id)
		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 @@ mptfc_probe(struct pci_dev *pdev, const struct pci_device_id *id)
	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 @@ mptfc_probe(struct pci_dev *pdev, const struct pci_device_id *id)
		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 @@ static struct pci_driver mptfc_driver = {
	.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 struct pci_driver mptfc_driver = {
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 @@ mptfc_init(void)
		  ": 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,6 +908,7 @@ static void __exit
mptfc_exit(void)
{
	pci_unregister_driver(&mptfc_driver);
	fc_release_transport(mptfc_transport_template);

	mpt_reset_deregister(mptfcDoneCtx);
	dprintk((KERN_INFO MYNAM
+24 −4
Original line number Diff line number Diff line
@@ -893,6 +893,7 @@ mptscsih_flush_running_cmds(MPT_SCSI_HOST *hd)
 *		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 @@ mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
			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 @@ mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
{
	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 @@ mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
		/* 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 */
		/*
@@ -3950,8 +3972,6 @@ mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
		mptscsih_do_cmd(hd, &iocmd);
}

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