| From: Steffen Maier <maier@linux.ibm.com> |
| Date: Thu, 17 May 2018 19:14:46 +0200 |
| Subject: scsi: zfcp: fix missing REC trigger trace on terminate_rport_io early |
| return |
| |
| commit 96d9270499471545048ed8a6d7f425a49762283d upstream. |
| |
| get_device() and its internally used kobject_get() only return NULL if they |
| get passed NULL as argument. zfcp_get_port_by_wwpn() loops over |
| adapter->port_list so the iteration variable port is always non-NULL. |
| Struct device is embedded in struct zfcp_port so &port->dev is always |
| non-NULL. This is the argument to get_device(). However, if we get an |
| fc_rport in terminate_rport_io() for which we cannot find a match within |
| zfcp_get_port_by_wwpn(), the latter can return NULL. v2.6.30 commit |
| 70932935b61e ("[SCSI] zfcp: Fix oops when port disappears") introduced an |
| early return without adding a trace record for this case. Even if we don't |
| need recovery in this case, for debugging we should still see that our |
| callback was invoked originally by scsi_transport_fc. |
| |
| Example trace record formatted with zfcpdbf from s390-tools: |
| |
| Timestamp : ... |
| Area : REC |
| Subarea : 00 |
| Level : 1 |
| Exception : - |
| CPU ID : .. |
| Caller : 0x... |
| Record ID : 1 |
| Tag : sctrpin SCSI terminate rport I/O, no zfcp port |
| LUN : 0xffffffffffffffff none (invalid) |
| WWPN : 0x<wwpn> WWPN |
| D_ID : 0x<n_port_id> N_Port-ID |
| Adapter status : 0x... |
| Port status : 0xffffffff unknown (-1) |
| LUN status : 0x00000000 none (invalid) |
| Ready count : 0x... |
| Running count : 0x... |
| ERP want : 0x03 ZFCP_ERP_ACTION_REOPEN_PORT_FORCED |
| ERP need : 0xc0 ZFCP_ERP_ACTION_NONE |
| |
| Signed-off-by: Steffen Maier <maier@linux.ibm.com> |
| Fixes: 70932935b61e ("[SCSI] zfcp: Fix oops when port disappears") |
| Reviewed-by: Benjamin Block <bblock@linux.ibm.com> |
| Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com> |
| Signed-off-by: Ben Hutchings <ben@decadent.org.uk> |
| --- |
| drivers/s390/scsi/zfcp_erp.c | 20 ++++++++++++++++++++ |
| drivers/s390/scsi/zfcp_ext.h | 3 +++ |
| drivers/s390/scsi/zfcp_scsi.c | 5 +++++ |
| 3 files changed, 28 insertions(+) |
| |
| --- a/drivers/s390/scsi/zfcp_erp.c |
| +++ b/drivers/s390/scsi/zfcp_erp.c |
| @@ -282,6 +282,26 @@ static int zfcp_erp_action_enqueue(int w |
| return retval; |
| } |
| |
| +void zfcp_erp_port_forced_no_port_dbf(char *id, struct zfcp_adapter *adapter, |
| + u64 port_name, u32 port_id) |
| +{ |
| + unsigned long flags; |
| + static /* don't waste stack */ struct zfcp_port tmpport; |
| + |
| + write_lock_irqsave(&adapter->erp_lock, flags); |
| + /* Stand-in zfcp port with fields just good enough for |
| + * zfcp_dbf_rec_trig() and zfcp_dbf_set_common(). |
| + * Under lock because tmpport is static. |
| + */ |
| + atomic_set(&tmpport.status, -1); /* unknown */ |
| + tmpport.wwpn = port_name; |
| + tmpport.d_id = port_id; |
| + zfcp_dbf_rec_trig(id, adapter, &tmpport, NULL, |
| + ZFCP_ERP_ACTION_REOPEN_PORT_FORCED, |
| + ZFCP_ERP_ACTION_NONE); |
| + write_unlock_irqrestore(&adapter->erp_lock, flags); |
| +} |
| + |
| static int _zfcp_erp_adapter_reopen(struct zfcp_adapter *adapter, |
| int clear_mask, char *id) |
| { |
| --- a/drivers/s390/scsi/zfcp_ext.h |
| +++ b/drivers/s390/scsi/zfcp_ext.h |
| @@ -58,6 +58,9 @@ extern void zfcp_dbf_scsi_eh(char *tag, |
| /* zfcp_erp.c */ |
| extern void zfcp_erp_set_adapter_status(struct zfcp_adapter *, u32); |
| extern void zfcp_erp_clear_adapter_status(struct zfcp_adapter *, u32); |
| +extern void zfcp_erp_port_forced_no_port_dbf(char *id, |
| + struct zfcp_adapter *adapter, |
| + u64 port_name, u32 port_id); |
| extern void zfcp_erp_adapter_reopen(struct zfcp_adapter *, int, char *); |
| extern void zfcp_erp_adapter_shutdown(struct zfcp_adapter *, int, char *); |
| extern void zfcp_erp_set_port_status(struct zfcp_port *, u32); |
| --- a/drivers/s390/scsi/zfcp_scsi.c |
| +++ b/drivers/s390/scsi/zfcp_scsi.c |
| @@ -624,6 +624,11 @@ static void zfcp_scsi_terminate_rport_io |
| if (port) { |
| zfcp_erp_port_forced_reopen(port, 0, "sctrpi1"); |
| put_device(&port->dev); |
| + } else { |
| + zfcp_erp_port_forced_no_port_dbf( |
| + "sctrpin", adapter, |
| + rport->port_name /* zfcp_scsi_rport_register */, |
| + rport->port_id /* zfcp_scsi_rport_register */); |
| } |
| } |
| |