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 <ma...@linux.ibm.com>
Fixes: 70932935b61e ("[SCSI] zfcp: Fix oops when port disappears")
Cc: <sta...@vger.kernel.org> #2.6.38+
Reviewed-by: Benjamin Block <bbl...@linux.ibm.com>
---
 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(+)

diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c
index d9cd25b56cfa..3489b1bc9121 100644
--- a/drivers/s390/scsi/zfcp_erp.c
+++ b/drivers/s390/scsi/zfcp_erp.c
@@ -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)
 {
diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h
index e55f42ce1168..3299bd345076 100644
--- a/drivers/s390/scsi/zfcp_ext.h
+++ b/drivers/s390/scsi/zfcp_ext.h
@@ -55,6 +55,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);
diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c
index 4fdb1665b0e6..478e7ef9ea2f 100644
--- a/drivers/s390/scsi/zfcp_scsi.c
+++ b/drivers/s390/scsi/zfcp_scsi.c
@@ -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 */);
        }
 }
 
-- 
2.16.3

Reply via email to