[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: Michael Reed <mdr@sgi.com> Signed-off-by: Eric Moore <Eric.Moore@lsil.com> Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
This commit is contained in:
parent
79de278e86
commit
3bc7bf1d12
|
@ -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 *));
|
||||
|
||||
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;
|
||||
}
|
||||
rport->dev_loss_tmo = mptfc_dev_loss_tmo;
|
||||
ri->rport = rport;
|
||||
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;
|
||||
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;
|
||||
}
|
||||
#ifdef MPT_DEBUG
|
||||
printk ("mptfc_reg_dev.%d: %x, %llx / %llx, tid %d, "
|
||||
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",
|
||||
sdev->host->host_no,
|
||||
vtarget->num_luns,
|
||||
sdev->id, ri->pg0.CurrentTargetID,
|
||||
ri->pg0.PortIdentifier, ri->pg0.WWPN, ri->pg0.WWNN);
|
||||
#endif
|
||||
ioc->name,
|
||||
sdev->host->host_no,
|
||||
vtarget->num_luns,
|
||||
sdev->id, ri->pg0.CurrentTargetID,
|
||||
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;
|
||||
|
|
Loading…
Reference in New Issue