Message ID | 20220118165803.3667947-1-maier@linux.ibm.com (mailing list archive) |
---|---|
State | Accepted |
Headers | show |
Series | zfcp: fix failed recovery on gone remote port with non-NPIV FCP devices | expand |
Steffen, > Suppose we have an environment with a number of non-NPIV FCP devices > (virtual HBAs / FCP devices / zfcp "adapter"s) sharing the same > physical FCP channel (HBA port) and its I_T nexus. [...] Applied to 5.17/scsi-staging, thanks!
On Tue, 18 Jan 2022 17:58:03 +0100, Steffen Maier wrote: > Suppose we have an environment with a number of non-NPIV FCP devices > (virtual HBAs / FCP devices / zfcp "adapter"s) sharing the same physical > FCP channel (HBA port) and its I_T nexus. Plus a number of storage target > ports zoned to such shared channel. Now one target port logs out of the > fabric causing an RSCN. Zfcp reacts with an ADISC ELS and subsequent port > recovery depending on the ADISC result. This happens on all such FCP > devices (in different Linux images) concurrently as they all receive a copy > of this RSCN. In the following we look at one of those FCP devices. > > [...] Applied to 5.17/scsi-fixes, thanks! [1/1] zfcp: fix failed recovery on gone remote port with non-NPIV FCP devices https://git.kernel.org/mkp/scsi/c/8c9db6679be4
diff --git a/drivers/s390/scsi/zfcp_fc.c b/drivers/s390/scsi/zfcp_fc.c index d24cafe02708..511bf8e0a436 100644 --- a/drivers/s390/scsi/zfcp_fc.c +++ b/drivers/s390/scsi/zfcp_fc.c @@ -521,6 +521,8 @@ static void zfcp_fc_adisc_handler(void *data) goto out; } + /* re-init to undo drop from zfcp_fc_adisc() */ + port->d_id = ntoh24(adisc_resp->adisc_port_id); /* port is good, unblock rport without going through erp */ zfcp_scsi_schedule_rport_register(port); out: @@ -534,6 +536,7 @@ static int zfcp_fc_adisc(struct zfcp_port *port) struct zfcp_fc_req *fc_req; struct zfcp_adapter *adapter = port->adapter; struct Scsi_Host *shost = adapter->scsi_host; + u32 d_id; int ret; fc_req = kmem_cache_zalloc(zfcp_fc_req_cache, GFP_ATOMIC); @@ -558,7 +561,15 @@ static int zfcp_fc_adisc(struct zfcp_port *port) fc_req->u.adisc.req.adisc_cmd = ELS_ADISC; hton24(fc_req->u.adisc.req.adisc_port_id, fc_host_port_id(shost)); - ret = zfcp_fsf_send_els(adapter, port->d_id, &fc_req->ct_els, + d_id = port->d_id; /* remember as destination for send els below */ + /* + * Force fresh GID_PN lookup on next port recovery. + * Must happen after request setup and before sending request, + * to prevent race with port->d_id re-init in zfcp_fc_adisc_handler(). + */ + port->d_id = 0; + + ret = zfcp_fsf_send_els(adapter, d_id, &fc_req->ct_els, ZFCP_FC_CTELS_TMO); if (ret) kmem_cache_free(zfcp_fc_req_cache, fc_req);