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 @@ ...@@ -29,6 +29,8 @@
# For mptctl: # For mptctl:
#CFLAGS_mptctl.o += -DMPT_DEBUG_IOCTL #CFLAGS_mptctl.o += -DMPT_DEBUG_IOCTL
# #
# For mptfc:
#CFLAGS_mptfc.o += -DMPT_DEBUG_FC
#=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-} LSI_LOGIC #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-} LSI_LOGIC
......
...@@ -510,9 +510,10 @@ struct mptfc_rport_info ...@@ -510,9 +510,10 @@ struct mptfc_rport_info
{ {
struct list_head list; struct list_head list;
struct fc_rport *rport; struct fc_rport *rport;
VirtDevice *vdev; struct scsi_target *starget;
FCDevicePage0_t pg0; FCDevicePage0_t pg0;
u8 flags; u8 flags;
u8 remap_needed;
}; };
/* /*
...@@ -804,6 +805,12 @@ typedef struct _mpt_sge { ...@@ -804,6 +805,12 @@ typedef struct _mpt_sge {
#define dreplyprintk(x) #define dreplyprintk(x)
#endif #endif
#ifdef DMPT_DEBUG_FC
#define dfcprintk(x) printk x
#else
#define dfcprintk(x)
#endif
#ifdef MPT_DEBUG_TM #ifdef MPT_DEBUG_TM
#define dtmprintk(x) printk x #define dtmprintk(x) printk x
#define DBG_DUMP_TM_REQUEST_FRAME(mfp) \ #define DBG_DUMP_TM_REQUEST_FRAME(mfp) \
......
...@@ -93,10 +93,11 @@ static int mptfcDoneCtx = -1; ...@@ -93,10 +93,11 @@ static int mptfcDoneCtx = -1;
static int mptfcTaskCtx = -1; static int mptfcTaskCtx = -1;
static int mptfcInternalCtx = -1; /* Used only for internal commands */ 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, static int mptfc_qcmd(struct scsi_cmnd *SCpnt,
void (*done)(struct scsi_cmnd *)); 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 mptfc_set_rport_loss_tmo(struct fc_rport *rport, uint32_t timeout);
static void __devexit mptfc_remove(struct pci_dev *pdev); static void __devexit mptfc_remove(struct pci_dev *pdev);
...@@ -107,10 +108,10 @@ static struct scsi_host_template mptfc_driver_template = { ...@@ -107,10 +108,10 @@ static struct scsi_host_template mptfc_driver_template = {
.name = "MPT FC Host", .name = "MPT FC Host",
.info = mptscsih_info, .info = mptscsih_info,
.queuecommand = mptfc_qcmd, .queuecommand = mptfc_qcmd,
.target_alloc = mptscsih_target_alloc, .target_alloc = mptfc_target_alloc,
.slave_alloc = mptfc_slave_alloc, .slave_alloc = mptfc_slave_alloc,
.slave_configure = mptscsih_slave_configure, .slave_configure = mptscsih_slave_configure,
.target_destroy = mptscsih_target_destroy, .target_destroy = mptfc_target_destroy,
.slave_destroy = mptscsih_slave_destroy, .slave_destroy = mptscsih_slave_destroy,
.change_queue_depth = mptscsih_change_queue_depth, .change_queue_depth = mptscsih_change_queue_depth,
.eh_abort_handler = mptscsih_abort, .eh_abort_handler = mptscsih_abort,
...@@ -347,15 +348,34 @@ mptfc_generate_rport_ids(FCDevicePage0_t *pg0, struct fc_rport_identifiers *rid) ...@@ -347,15 +348,34 @@ mptfc_generate_rport_ids(FCDevicePage0_t *pg0, struct fc_rport_identifiers *rid)
return 0; 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 static void
mptfc_register_dev(MPT_ADAPTER *ioc, int channel, FCDevicePage0_t *pg0) mptfc_register_dev(MPT_ADAPTER *ioc, int channel, FCDevicePage0_t *pg0)
{ {
struct fc_rport_identifiers rport_ids; struct fc_rport_identifiers rport_ids;
struct fc_rport *rport; struct fc_rport *rport;
struct mptfc_rport_info *ri; struct mptfc_rport_info *ri;
int match = 0; int new_ri = 1;
u64 port_name; u64 pn;
unsigned long flags; unsigned long flags;
VirtTarget *vtarget;
if (mptfc_generate_rport_ids(pg0, &rport_ids) < 0) if (mptfc_generate_rport_ids(pg0, &rport_ids) < 0)
return; return;
...@@ -363,14 +383,14 @@ mptfc_register_dev(MPT_ADAPTER *ioc, int channel, FCDevicePage0_t *pg0) ...@@ -363,14 +383,14 @@ mptfc_register_dev(MPT_ADAPTER *ioc, int channel, FCDevicePage0_t *pg0)
/* scan list looking for a match */ /* scan list looking for a match */
spin_lock_irqsave(&ioc->fc_rport_lock, flags); spin_lock_irqsave(&ioc->fc_rport_lock, flags);
list_for_each_entry(ri, &ioc->fc_rports, list) { list_for_each_entry(ri, &ioc->fc_rports, list) {
port_name = (u64)ri->pg0.WWPN.High << 32 | (u64)ri->pg0.WWPN.Low; pn = (u64)ri->pg0.WWPN.High << 32 | (u64)ri->pg0.WWPN.Low;
if (port_name == rport_ids.port_name) { /* match */ if (pn == rport_ids.port_name) { /* match */
list_move_tail(&ri->list, &ioc->fc_rports); list_move_tail(&ri->list, &ioc->fc_rports);
match = 1; new_ri = 0;
break; break;
} }
} }
if (!match) { /* allocate one */ if (new_ri) { /* allocate one */
spin_unlock_irqrestore(&ioc->fc_rport_lock, flags); spin_unlock_irqrestore(&ioc->fc_rport_lock, flags);
ri = kzalloc(sizeof(struct mptfc_rport_info), GFP_KERNEL); ri = kzalloc(sizeof(struct mptfc_rport_info), GFP_KERNEL);
if (!ri) if (!ri)
...@@ -382,40 +402,43 @@ mptfc_register_dev(MPT_ADAPTER *ioc, int channel, FCDevicePage0_t *pg0) ...@@ -382,40 +402,43 @@ mptfc_register_dev(MPT_ADAPTER *ioc, int channel, FCDevicePage0_t *pg0)
ri->pg0 = *pg0; /* add/update pg0 data */ ri->pg0 = *pg0; /* add/update pg0 data */
ri->flags &= ~MPT_RPORT_INFO_FLAGS_MISSING; ri->flags &= ~MPT_RPORT_INFO_FLAGS_MISSING;
/* MPT_RPORT_INFO_FLAGS_REGISTERED - rport not previously deleted */
if (!(ri->flags & MPT_RPORT_INFO_FLAGS_REGISTERED)) { if (!(ri->flags & MPT_RPORT_INFO_FLAGS_REGISTERED)) {
ri->flags |= MPT_RPORT_INFO_FLAGS_REGISTERED; ri->flags |= MPT_RPORT_INFO_FLAGS_REGISTERED;
spin_unlock_irqrestore(&ioc->fc_rport_lock, flags); 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); spin_lock_irqsave(&ioc->fc_rport_lock, flags);
if (rport) { if (rport) {
if (*((struct mptfc_rport_info **)rport->dd_data) != ri) { ri->rport = rport;
ri->flags &= ~MPT_RPORT_INFO_FLAGS_MAPPED_VDEV; if (new_ri) /* may have been reset by user */
ri->vdev = NULL; rport->dev_loss_tmo = mptfc_dev_loss_tmo;
ri->rport = rport; *((struct mptfc_rport_info **)rport->dd_data) = ri;
*((struct mptfc_rport_info **)rport->dd_data) = ri;
}
rport->dev_loss_tmo = mptfc_dev_loss_tmo;
/* /*
* if already mapped, remap here. If not mapped, * 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) { if (ri->starget) {
ri->vdev->target_id = ri->pg0.CurrentTargetID; vtarget = ri->starget->hostdata;
ri->vdev->bus_id = ri->pg0.CurrentBus; if (vtarget) {
ri->vdev->vtarget->target_id = ri->vdev->target_id; vtarget->target_id = pg0->CurrentTargetID;
ri->vdev->vtarget->bus_id = ri->vdev->bus_id; vtarget->bus_id = pg0->CurrentBus;
starget_for_each_device(ri->starget,
vtarget,mptfc_remap_sdev);
}
ri->remap_needed = 0;
} }
#ifdef MPT_DEBUG dfcprintk ((MYIOC_s_INFO_FMT
printk ("mptfc_reg_dev.%d: %x, %llx / %llx, tid %d, " "mptfc_reg_dev.%d: %x, %llx / %llx, tid %d, "
"rport tid %d, tmo %d\n", "rport tid %d, tmo %d\n",
ioc->sh->host_no, ioc->name,
oc->sh->host_no,
pg0->PortIdentifier, pg0->PortIdentifier,
pg0->WWNN, pg0->WWNN,
pg0->WWPN, pg0->WWPN,
pg0->CurrentTargetID, pg0->CurrentTargetID,
ri->rport->scsi_target_id, ri->rport->scsi_target_id,
ri->rport->dev_loss_tmo); ri->rport->dev_loss_tmo));
#endif
} else { } else {
list_del(&ri->list); list_del(&ri->list);
kfree(ri); kfree(ri);
...@@ -426,6 +449,65 @@ mptfc_register_dev(MPT_ADAPTER *ioc, int channel, FCDevicePage0_t *pg0) ...@@ -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 * OS entry point to allow host driver to alloc memory
* for each scsi device. Called once per device the bus scan. * for each scsi device. Called once per device the bus scan.
...@@ -440,7 +522,6 @@ mptfc_slave_alloc(struct scsi_device *sdev) ...@@ -440,7 +522,6 @@ mptfc_slave_alloc(struct scsi_device *sdev)
VirtDevice *vdev; VirtDevice *vdev;
struct scsi_target *starget; struct scsi_target *starget;
struct fc_rport *rport; struct fc_rport *rport;
struct mptfc_rport_info *ri;
unsigned long flags; unsigned long flags;
...@@ -451,55 +532,44 @@ mptfc_slave_alloc(struct scsi_device *sdev) ...@@ -451,55 +532,44 @@ mptfc_slave_alloc(struct scsi_device *sdev)
hd = (MPT_SCSI_HOST *)sdev->host->hostdata; hd = (MPT_SCSI_HOST *)sdev->host->hostdata;
vdev = kmalloc(sizeof(VirtDevice), GFP_KERNEL); vdev = kzalloc(sizeof(VirtDevice), GFP_KERNEL);
if (!vdev) { if (!vdev) {
printk(MYIOC_s_ERR_FMT "slave_alloc kmalloc(%zd) FAILED!\n", printk(MYIOC_s_ERR_FMT "slave_alloc kmalloc(%zd) FAILED!\n",
hd->ioc->name, sizeof(VirtDevice)); hd->ioc->name, sizeof(VirtDevice));
return -ENOMEM; return -ENOMEM;
} }
memset(vdev, 0, sizeof(VirtDevice));
spin_lock_irqsave(&hd->ioc->fc_rport_lock,flags); 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; sdev->hostdata = vdev;
starget = scsi_target(sdev); starget = scsi_target(sdev);
vtarget = starget->hostdata; vtarget = starget->hostdata;
if (vtarget->num_luns == 0) { if (vtarget->num_luns == 0) {
vtarget->ioc_id = hd->ioc->id;
vtarget->tflags = MPT_TARGET_FLAGS_Q_YES | vtarget->tflags = MPT_TARGET_FLAGS_Q_YES |
MPT_TARGET_FLAGS_VALID_INQUIRY; MPT_TARGET_FLAGS_VALID_INQUIRY;
hd->Targets[sdev->id] = vtarget; hd->Targets[sdev->id] = vtarget;
} }
vtarget->target_id = vdev->target_id;
vtarget->bus_id = vdev->bus_id;
vdev->vtarget = vtarget; vdev->vtarget = vtarget;
vdev->ioc_id = hd->ioc->id; vdev->ioc_id = hd->ioc->id;
vdev->lun = sdev->lun; vdev->lun = sdev->lun;
vdev->target_id = ri->pg0.CurrentTargetID; vdev->target_id = vtarget->target_id;
vdev->bus_id = ri->pg0.CurrentBus; vdev->bus_id = vtarget->bus_id;
ri->flags |= MPT_RPORT_INFO_FLAGS_MAPPED_VDEV;
ri->vdev = vdev;
spin_unlock_irqrestore(&hd->ioc->fc_rport_lock,flags); spin_unlock_irqrestore(&hd->ioc->fc_rport_lock,flags);
vtarget->num_luns++; vtarget->num_luns++;
#ifdef MPT_DEBUG dfcprintk ((MYIOC_s_INFO_FMT
printk ("mptfc_slv_alloc.%d: num_luns %d, sdev.id %d, " "mptfc_slv_alloc.%d: num_luns %d, sdev.id %d, "
"CurrentTargetID %d, %x %llx %llx\n", "CurrentTargetID %d, %x %llx %llx\n",
sdev->host->host_no, ioc->name,
vtarget->num_luns, sdev->host->host_no,
sdev->id, ri->pg0.CurrentTargetID, vtarget->num_luns,
ri->pg0.PortIdentifier, ri->pg0.WWPN, ri->pg0.WWNN); sdev->id, ri->pg0.CurrentTargetID,
#endif ri->pg0.PortIdentifier, ri->pg0.WWPN, ri->pg0.WWNN));
return 0; return 0;
} }
...@@ -507,6 +577,7 @@ mptfc_slave_alloc(struct scsi_device *sdev) ...@@ -507,6 +577,7 @@ mptfc_slave_alloc(struct scsi_device *sdev)
static int static int
mptfc_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)) 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)); struct fc_rport *rport = starget_to_rport(scsi_target(SCpnt->device));
int err; int err;
...@@ -516,6 +587,10 @@ mptfc_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)) ...@@ -516,6 +587,10 @@ mptfc_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
done(SCpnt); done(SCpnt);
return 0; 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); return mptscsih_qcmd(SCpnt,done);
} }
...@@ -591,16 +666,20 @@ mptfc_rescan_devices(void *arg) ...@@ -591,16 +666,20 @@ mptfc_rescan_devices(void *arg)
ri->flags &= ~(MPT_RPORT_INFO_FLAGS_REGISTERED| ri->flags &= ~(MPT_RPORT_INFO_FLAGS_REGISTERED|
MPT_RPORT_INFO_FLAGS_MISSING); MPT_RPORT_INFO_FLAGS_MISSING);
ri->remap_needed = 1;
fc_remote_port_delete(ri->rport); fc_remote_port_delete(ri->rport);
/* /*
* remote port not really deleted 'cause * remote port not really deleted 'cause
* binding is by WWPN and driver only * binding is by WWPN and driver only
* registers FCP_TARGETs * registers FCP_TARGETs but cannot trust
* data structures.
*/ */
#ifdef MPT_DEBUG ri->rport = NULL;
printk ("mptfc_rescan.%d: %llx deleted\n", dfcprintk ((MYIOC_s_INFO_FMT
ioc->sh->host_no, ri->pg0.WWPN); "mptfc_rescan.%d: %llx deleted\n",
#endif ioc->name,
ioc->sh->host_no,
ri->pg0.WWPN));
} }
} }
spin_unlock_irqrestore(&ioc->fc_rport_lock,flags); spin_unlock_irqrestore(&ioc->fc_rport_lock,flags);
...@@ -872,9 +951,8 @@ mptfc_init(void) ...@@ -872,9 +951,8 @@ mptfc_init(void)
} }
error = pci_register_driver(&mptfc_driver); error = pci_register_driver(&mptfc_driver);
if (error) { if (error)
fc_release_transport(mptfc_transport_template); fc_release_transport(mptfc_transport_template);
}
return error; return error;
} }
...@@ -885,7 +963,8 @@ mptfc_init(void) ...@@ -885,7 +963,8 @@ mptfc_init(void)
* @pdev: Pointer to pci_dev structure * @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); MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
struct mptfc_rport_info *p, *n; 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