Commit 419835e2 authored by Michael Reed's avatar Michael Reed Committed by James Bottomley

[SCSI] mptfc: fix fibre channel infinite request/response loop

While doing board reset testing I was able to put the system in
an infinite request/response loop between the scsi layer and
mptscsih_qcmd() by aborting the reset.  This patch installs
a "SETUP RESET" handler which calls fc_remote_port_delete()
for all registered rports.  This blocks the target which
prevents the loop.  Additionally, should the reset fail to
complete, the transport will now terminate i/o to the target.
Signed-off-by: default avatarMichael Reed <mdr@sgi.com>
Signed-off-by: default avatarJames Bottomley <James.Bottomley@SteelEye.com>
parent ca2f938e
...@@ -635,6 +635,7 @@ typedef struct _MPT_ADAPTER ...@@ -635,6 +635,7 @@ typedef struct _MPT_ADAPTER
int num_ports; int num_ports;
struct work_struct mptscsih_persistTask; struct work_struct mptscsih_persistTask;
struct work_struct fc_setup_reset_work;
struct list_head fc_rports; struct list_head fc_rports;
spinlock_t fc_rescan_work_lock; spinlock_t fc_rescan_work_lock;
int fc_rescan_work_count; int fc_rescan_work_count;
......
...@@ -580,10 +580,10 @@ mptfc_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)) ...@@ -580,10 +580,10 @@ mptfc_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
#ifdef DMPT_DEBUG_FC #ifdef DMPT_DEBUG_FC
if (unlikely(err)) { if (unlikely(err)) {
dfcprintk ((MYIOC_s_INFO_FMT dfcprintk ((MYIOC_s_INFO_FMT
"mptfc_qcmd.%d: %d:%d, mptscsih_qcmd returns non-zero.\n", "mptfc_qcmd.%d: %d:%d, mptscsih_qcmd returns non-zero, (%x).\n",
((MPT_SCSI_HOST *) SCpnt->device->host->hostdata)->ioc->name, ((MPT_SCSI_HOST *) SCpnt->device->host->hostdata)->ioc->name,
((MPT_SCSI_HOST *) SCpnt->device->host->hostdata)->ioc->sh->host_no, ((MPT_SCSI_HOST *) SCpnt->device->host->hostdata)->ioc->sh->host_no,
SCpnt->device->id,SCpnt->device->lun)); SCpnt->device->id,SCpnt->device->lun,err));
} }
#endif #endif
return err; return err;
...@@ -872,6 +872,31 @@ mptfc_init_host_attr(MPT_ADAPTER *ioc,int portnum) ...@@ -872,6 +872,31 @@ mptfc_init_host_attr(MPT_ADAPTER *ioc,int portnum)
fc_host_tgtid_bind_type(ioc->sh) = FC_TGTID_BIND_BY_WWPN; fc_host_tgtid_bind_type(ioc->sh) = FC_TGTID_BIND_BY_WWPN;
} }
static void
mptfc_setup_reset(void *arg)
{
MPT_ADAPTER *ioc = (MPT_ADAPTER *)arg;
u64 pn;
struct mptfc_rport_info *ri;
/* reset about to happen, delete (block) all rports */
list_for_each_entry(ri, &ioc->fc_rports, list) {
if (ri->flags & MPT_RPORT_INFO_FLAGS_REGISTERED) {
ri->flags &= ~MPT_RPORT_INFO_FLAGS_REGISTERED;
fc_remote_port_delete(ri->rport); /* won't sleep */
ri->rport = NULL;
pn = (u64)ri->pg0.WWPN.High << 32 |
(u64)ri->pg0.WWPN.Low;
dfcprintk ((MYIOC_s_INFO_FMT
"mptfc_setup_reset.%d: %llx deleted\n",
ioc->name,
ioc->sh->host_no,
(unsigned long long)pn));
}
}
}
static void static void
mptfc_rescan_devices(void *arg) mptfc_rescan_devices(void *arg)
{ {
...@@ -999,6 +1024,7 @@ mptfc_probe(struct pci_dev *pdev, const struct pci_device_id *id) ...@@ -999,6 +1024,7 @@ mptfc_probe(struct pci_dev *pdev, const struct pci_device_id *id)
spin_lock_init(&ioc->fc_rescan_work_lock); spin_lock_init(&ioc->fc_rescan_work_lock);
INIT_WORK(&ioc->fc_rescan_work, mptfc_rescan_devices,(void *)ioc); INIT_WORK(&ioc->fc_rescan_work, mptfc_rescan_devices,(void *)ioc);
INIT_WORK(&ioc->fc_setup_reset_work, mptfc_setup_reset, (void *)ioc);
spin_lock_irqsave(&ioc->FreeQlock, flags); spin_lock_irqsave(&ioc->FreeQlock, flags);
...@@ -1221,6 +1247,12 @@ mptfc_ioc_reset(MPT_ADAPTER *ioc, int reset_phase) ...@@ -1221,6 +1247,12 @@ mptfc_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post"))); reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
if (reset_phase == MPT_IOC_SETUP_RESET) { if (reset_phase == MPT_IOC_SETUP_RESET) {
spin_lock_irqsave(&ioc->fc_rescan_work_lock, flags);
if (ioc->fc_rescan_work_q) {
queue_work(ioc->fc_rescan_work_q,
&ioc->fc_setup_reset_work);
}
spin_unlock_irqrestore(&ioc->fc_rescan_work_lock, flags);
} }
else if (reset_phase == MPT_IOC_PRE_RESET) { else if (reset_phase == MPT_IOC_PRE_RESET) {
......
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