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

[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
......@@ -29,6 +29,8 @@
# For mptctl:
#CFLAGS_mptctl.o += -DMPT_DEBUG_IOCTL
#
# For mptfc:
#CFLAGS_mptfc.o += -DMPT_DEBUG_FC
#=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-} LSI_LOGIC
......
......@@ -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) \
......
......@@ -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);
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;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment