Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3bc7bf1d authored by Michael Reed's avatar Michael Reed Committed by James Bottomley
Browse files

[SCSI] fusion: FC rport code fixes



This fix's problems with recent fc submission regarding
i/o being redirected to the wrong target.

Signed-off-by: default avatarMichael Reed <mdr@sgi.com>
Signed-off-by: default avatarEric Moore <Eric.Moore@lsil.com>
Signed-off-by: default avatarJames Bottomley <James.Bottomley@SteelEye.com>
parent 79de278e
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -29,6 +29,8 @@
#  For mptctl:
#CFLAGS_mptctl.o += -DMPT_DEBUG_IOCTL
#
#  For mptfc:
#CFLAGS_mptfc.o += -DMPT_DEBUG_FC

#=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-} LSI_LOGIC

+8 −1
Original line number Diff line number Diff line
@@ -510,9 +510,10 @@ struct mptfc_rport_info
{
	struct list_head list;
	struct fc_rport *rport;
	VirtDevice	*vdev;
	struct scsi_target *starget;
	FCDevicePage0_t pg0;
	u8		flags;
	u8		remap_needed;
};

/*
@@ -804,6 +805,12 @@ typedef struct _mpt_sge {
#define dreplyprintk(x)
#endif

#ifdef DMPT_DEBUG_FC
#define dfcprintk(x) printk x
#else
#define dfcprintk(x)
#endif

#ifdef MPT_DEBUG_TM
#define dtmprintk(x) printk x
#define DBG_DUMP_TM_REQUEST_FRAME(mfp) \
+141 −62
Original line number Diff line number Diff line
@@ -93,10 +93,11 @@ 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_target_alloc(struct scsi_target *starget);
static int mptfc_slave_alloc(struct scsi_device *sdev);
static int mptfc_qcmd(struct scsi_cmnd *SCpnt,
		      void (*done)(struct scsi_cmnd *));

static void mptfc_target_destroy(struct scsi_target *starget);
static void mptfc_set_rport_loss_tmo(struct fc_rport *rport, uint32_t timeout);
static void __devexit mptfc_remove(struct pci_dev *pdev);

@@ -107,10 +108,10 @@ static struct scsi_host_template mptfc_driver_template = {
	.name				= "MPT FC Host",
	.info				= mptscsih_info,
	.queuecommand			= mptfc_qcmd,
	.target_alloc			= mptscsih_target_alloc,
	.target_alloc			= mptfc_target_alloc,
	.slave_alloc			= mptfc_slave_alloc,
	.slave_configure		= mptscsih_slave_configure,
	.target_destroy			= mptscsih_target_destroy,
	.target_destroy			= mptfc_target_destroy,
	.slave_destroy			= mptscsih_slave_destroy,
	.change_queue_depth 		= mptscsih_change_queue_depth,
	.eh_abort_handler		= mptscsih_abort,
@@ -347,15 +348,34 @@ mptfc_generate_rport_ids(FCDevicePage0_t *pg0, struct fc_rport_identifiers *rid)
	return 0;
}

static void
mptfc_remap_sdev(struct scsi_device *sdev, void *arg)
{
	VirtDevice		*vdev;
	VirtTarget		*vtarget;
	struct scsi_target	*starget;

	starget = scsi_target(sdev);
	if (starget->hostdata == arg) {
		vtarget = arg;
		vdev = sdev->hostdata;
		if (vdev) {
			vdev->bus_id = vtarget->bus_id;
			vdev->target_id = vtarget->target_id;
		}
	}
}

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;
	int			new_ri = 1;
	u64			pn;
	unsigned long		flags;
	VirtTarget		*vtarget;

	if (mptfc_generate_rport_ids(pg0, &rport_ids) < 0)
		return;
@@ -363,14 +383,14 @@ mptfc_register_dev(MPT_ADAPTER *ioc, int channel, FCDevicePage0_t *pg0)
	/* 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 */
		pn = (u64)ri->pg0.WWPN.High << 32 | (u64)ri->pg0.WWPN.Low;
		if (pn == rport_ids.port_name) {	/* match */
			list_move_tail(&ri->list, &ioc->fc_rports);
			match = 1;
			new_ri = 0;
			break;
		}
	}
	if (!match) {	/* allocate one */
	if (new_ri) {	/* allocate one */
		spin_unlock_irqrestore(&ioc->fc_rport_lock, flags);
		ri = kzalloc(sizeof(struct mptfc_rport_info), GFP_KERNEL);
		if (!ri)
@@ -382,40 +402,43 @@ mptfc_register_dev(MPT_ADAPTER *ioc, int channel, FCDevicePage0_t *pg0)
	ri->pg0 = *pg0;	/* add/update pg0 data */
	ri->flags &= ~MPT_RPORT_INFO_FLAGS_MISSING;

	/* MPT_RPORT_INFO_FLAGS_REGISTERED - rport not previously deleted */
	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;
			}
			if (new_ri) /* may have been reset by user */
				rport->dev_loss_tmo = mptfc_dev_loss_tmo;
			*((struct mptfc_rport_info **)rport->dd_data) = ri;
			/*
			 * if already mapped, remap here.  If not mapped,
			 * slave_alloc will allocate vdev and map
			 * target_alloc will allocate vtarget and map,
			 * slave_alloc will fill in vdev from vtarget.
			 */
			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, "
			if (ri->starget) {
				vtarget = ri->starget->hostdata;
				if (vtarget) {
					vtarget->target_id = pg0->CurrentTargetID;
					vtarget->bus_id = pg0->CurrentBus;
					starget_for_each_device(ri->starget,
						vtarget,mptfc_remap_sdev);
				}
				ri->remap_needed = 0;
			}
			dfcprintk ((MYIOC_s_INFO_FMT
				"mptfc_reg_dev.%d: %x, %llx / %llx, tid %d, "
				"rport tid %d, tmo %d\n",
					ioc->sh->host_no,
					ioc->name,
					oc->sh->host_no,
					pg0->PortIdentifier,
					pg0->WWNN,
					pg0->WWPN,
					pg0->CurrentTargetID,
					ri->rport->scsi_target_id,
					ri->rport->dev_loss_tmo);
			#endif
					ri->rport->dev_loss_tmo));
		} else {
			list_del(&ri->list);
			kfree(ri);
@@ -426,6 +449,65 @@ mptfc_register_dev(MPT_ADAPTER *ioc, int channel, FCDevicePage0_t *pg0)

}

/*
 *	OS entry point to allow for host driver to free allocated memory
 *	Called if no device present or device being unloaded
 */
static void
mptfc_target_destroy(struct scsi_target *starget)
{
	struct fc_rport		*rport;
	struct mptfc_rport_info *ri;

	rport = starget_to_rport(starget);
	if (rport) {
		ri = *((struct mptfc_rport_info **)rport->dd_data);
		if (ri)	/* better be! */
			ri->starget = NULL;
	}
	if (starget->hostdata)
		kfree(starget->hostdata);
	starget->hostdata = NULL;
}

/*
 *	OS entry point to allow host driver to alloc memory
 *	for each scsi target. Called once per device the bus scan.
 *	Return non-zero if allocation fails.
 */
static int
mptfc_target_alloc(struct scsi_target *starget)
{
	VirtTarget		*vtarget;
	struct fc_rport		*rport;
	struct mptfc_rport_info *ri;
	int			rc;

	vtarget = kzalloc(sizeof(VirtTarget), GFP_KERNEL);
	if (!vtarget)
		return -ENOMEM;
	starget->hostdata = vtarget;

	rc = -ENODEV;
	rport = starget_to_rport(starget);
	if (rport) {
		ri = *((struct mptfc_rport_info **)rport->dd_data);
		if (ri) {	/* better be! */
			vtarget->target_id = ri->pg0.CurrentTargetID;
			vtarget->bus_id = ri->pg0.CurrentBus;
			ri->starget = starget;
			ri->remap_needed = 0;
			rc = 0;
		}
	}
	if (rc != 0) {
		kfree(vtarget);
		starget->hostdata = NULL;
	}

	return rc;
}

/*
 *	OS entry point to allow host driver to alloc memory
 *	for each scsi device. Called once per device the bus scan.
@@ -440,7 +522,6 @@ mptfc_slave_alloc(struct scsi_device *sdev)
	VirtDevice		*vdev;
	struct scsi_target	*starget;
	struct fc_rport		*rport;
	struct mptfc_rport_info *ri;
	unsigned long		flags;


@@ -451,55 +532,44 @@ mptfc_slave_alloc(struct scsi_device *sdev)

	hd = (MPT_SCSI_HOST *)sdev->host->hostdata;

	vdev = kmalloc(sizeof(VirtDevice), GFP_KERNEL);
	vdev = kzalloc(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->ioc_id = hd->ioc->id;
		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;
	vdev->target_id = vtarget->target_id;
	vdev->bus_id = vtarget->bus_id;

	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, "
	dfcprintk ((MYIOC_s_INFO_FMT
		"mptfc_slv_alloc.%d: num_luns %d, sdev.id %d, "
	        "CurrentTargetID %d, %x %llx %llx\n",
		ioc->name,
		sdev->host->host_no,
		vtarget->num_luns,
		sdev->id, ri->pg0.CurrentTargetID,
			ri->pg0.PortIdentifier, ri->pg0.WWPN, ri->pg0.WWNN);
#endif
		ri->pg0.PortIdentifier, ri->pg0.WWPN, ri->pg0.WWNN));

	return 0;
}
@@ -507,6 +577,7 @@ mptfc_slave_alloc(struct scsi_device *sdev)
static int
mptfc_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
{
	struct mptfc_rport_info	*ri;
	struct fc_rport	*rport = starget_to_rport(scsi_target(SCpnt->device));
	int		err;

@@ -516,6 +587,10 @@ mptfc_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
		done(SCpnt);
		return 0;
	}
	ri = *((struct mptfc_rport_info **)rport->dd_data);
	if (unlikely(ri->remap_needed))
		return SCSI_MLQUEUE_HOST_BUSY;

	return mptscsih_qcmd(SCpnt,done);
}

@@ -591,16 +666,20 @@ mptfc_rescan_devices(void *arg)

				ri->flags &= ~(MPT_RPORT_INFO_FLAGS_REGISTERED|
					       MPT_RPORT_INFO_FLAGS_MISSING);
				ri->remap_needed = 1;
				fc_remote_port_delete(ri->rport);
				/*
				 * remote port not really deleted 'cause
				 * binding is by WWPN and driver only
				 * registers FCP_TARGETs
				 * registers FCP_TARGETs but cannot trust
				 * data structures.
				 */
				#ifdef MPT_DEBUG
				printk ("mptfc_rescan.%d: %llx deleted\n",
					ioc->sh->host_no, ri->pg0.WWPN);
				#endif
				ri->rport = NULL;
				dfcprintk ((MYIOC_s_INFO_FMT
					"mptfc_rescan.%d: %llx deleted\n",
					ioc->name,
					ioc->sh->host_no,
					ri->pg0.WWPN));
			}
		}
		spin_unlock_irqrestore(&ioc->fc_rport_lock,flags);
@@ -872,9 +951,8 @@ mptfc_init(void)
	}

	error = pci_register_driver(&mptfc_driver);
	if (error) {
	if (error)
		fc_release_transport(mptfc_transport_template);
	}

	return error;
}
@@ -885,7 +963,8 @@ mptfc_init(void)
 *	@pdev: Pointer to pci_dev structure
 *
 */
static void __devexit mptfc_remove(struct pci_dev *pdev)
static void __devexit
mptfc_remove(struct pci_dev *pdev)
{
	MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
	struct mptfc_rport_info *p, *n;