scsi: zfcp: fix missing REC trigger trace on terminate_rport_io early return
authorSteffen Maier <maier@linux.ibm.com>
Thu, 17 May 2018 17:14:46 +0000 (19:14 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 3 Jul 2018 09:24:58 +0000 (11:24 +0200)
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")
Cc: <stable@vger.kernel.org> #2.6.38+
Reviewed-by: Benjamin Block <bblock@linux.ibm.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/s390/scsi/zfcp_erp.c
drivers/s390/scsi/zfcp_ext.h
drivers/s390/scsi/zfcp_scsi.c

index 379d034..c842ba6 100644 (file)
@@ -283,6 +283,26 @@ static int zfcp_erp_action_enqueue(int want, struct zfcp_adapter *adapter,
        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)
 {
index 5cd028a..c1092a1 100644 (file)
@@ -58,6 +58,9 @@ extern void zfcp_dbf_scsi_eh(char *tag, struct zfcp_adapter *adapter,
 /* 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);
index 4033ad6..0b6f514 100644 (file)
@@ -605,6 +605,11 @@ static void zfcp_scsi_terminate_rport_io(struct fc_rport *rport)
        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 */);
        }
 }