[SCSI] zfcp: Trigger logging in the FCP channel on qdio error conditions
authorChristof Schmitt <christof.schmitt@de.ibm.com>
Fri, 16 Jul 2010 13:37:43 +0000 (15:37 +0200)
committerJames Bottomley <James.Bottomley@suse.de>
Wed, 28 Jul 2010 14:48:58 +0000 (09:48 -0500)
Exploit the cio siosl function to trigger logging in the FCP channel
on qdio error conditions. Add a helper function in zfcp_qdio to ensure
that tracing is only triggered once before calling qdio_shutdown.

Trigger in zfcp for hardware logs are:
 - timeout for FSF requests to the FCP channel
 - "no recommendation" status from FCP channel
 - invalid FSF protocol status
 - stalled outbound queue
 - unknown request id on inbound queue
 - QDIO_ERROR_SLSB_STATE

All of the above triggers run from the Linux qdio softirq context, so
no additional synchronization is necessary for the handling of the
ZFCP_STATUS_ADAPTER_SIOSL_ISSUED flag.

Reviewed-by: Swen Schillig <swen@vnet.ibm.com>
Signed-off-by: Christof Schmitt <christof.schmitt@de.ibm.com>
Signed-off-by: James Bottomley <James.Bottomley@suse.de>
drivers/s390/scsi/zfcp_def.h
drivers/s390/scsi/zfcp_ext.h
drivers/s390/scsi/zfcp_fsf.c
drivers/s390/scsi/zfcp_qdio.c

index 6c6374ba1807de39afcc382664ee94a3c1e43e32..e1c6b6e05a75ea6e66b8cc4e2a18ebc84b3be1e3 100644 (file)
@@ -73,6 +73,7 @@ struct zfcp_reqlist;
 
 /* adapter status */
 #define ZFCP_STATUS_ADAPTER_QDIOUP             0x00000002
+#define ZFCP_STATUS_ADAPTER_SIOSL_ISSUED       0x00000004
 #define ZFCP_STATUS_ADAPTER_XCONFIG_OK         0x00000008
 #define ZFCP_STATUS_ADAPTER_HOST_CON_INIT      0x00000010
 #define ZFCP_STATUS_ADAPTER_ERP_PENDING                0x00000100
index de0925f25dcc5b51e737f3d73b1ce69596106241..3b93239c6f69ceb3cea30089938b6580820ece85 100644 (file)
@@ -152,6 +152,7 @@ extern int zfcp_qdio_sbals_from_sg(struct zfcp_qdio *, struct zfcp_qdio_req *,
                                   struct scatterlist *);
 extern int zfcp_qdio_open(struct zfcp_qdio *);
 extern void zfcp_qdio_close(struct zfcp_qdio *);
+extern void zfcp_qdio_siosl(struct zfcp_adapter *);
 
 /* zfcp_scsi.c */
 extern struct zfcp_data zfcp_data;
index f9be5d60d92a1b7310cb4463e1f59403c2e96ac4..9d1d7d1842cef7f3d8abd73fc7be931502360110 100644 (file)
@@ -21,6 +21,7 @@
 static void zfcp_fsf_request_timeout_handler(unsigned long data)
 {
        struct zfcp_adapter *adapter = (struct zfcp_adapter *) data;
+       zfcp_qdio_siosl(adapter);
        zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED,
                                "fsrth_1", NULL);
 }
@@ -326,6 +327,7 @@ static void zfcp_fsf_fsfstatus_qual_eval(struct zfcp_fsf_req *req)
                dev_err(&req->adapter->ccw_device->dev,
                        "The FCP adapter reported a problem "
                        "that cannot be recovered\n");
+               zfcp_qdio_siosl(req->adapter);
                zfcp_erp_adapter_shutdown(req->adapter, 0, "fsfsqe1", req);
                break;
        }
@@ -416,6 +418,7 @@ static void zfcp_fsf_protstatus_eval(struct zfcp_fsf_req *req)
                dev_err(&adapter->ccw_device->dev,
                        "0x%x is not a valid transfer protocol status\n",
                        qtcb->prefix.prot_status);
+               zfcp_qdio_siosl(adapter);
                zfcp_erp_adapter_shutdown(adapter, 0, "fspse_9", req);
        }
        req->status |= ZFCP_STATUS_FSFREQ_ERROR;
@@ -2485,13 +2488,15 @@ void zfcp_fsf_reqid_check(struct zfcp_qdio *qdio, int sbal_idx)
                req_id = (unsigned long) sbale->addr;
                fsf_req = zfcp_reqlist_find_rm(adapter->req_list, req_id);
 
-               if (!fsf_req)
+               if (!fsf_req) {
                        /*
                         * Unknown request means that we have potentially memory
                         * corruption and must stop the machine immediately.
                         */
+                       zfcp_qdio_siosl(adapter);
                        panic("error: unknown req_id (%lx) on adapter %s.\n",
                              req_id, dev_name(&adapter->ccw_device->dev));
+               }
 
                fsf_req->qdio_req.sbal_response = sbal_idx;
                zfcp_fsf_req_complete(fsf_req);
index aceced8ec7e4aca7dff75975e6d0515e0c860485..b2635759721cd81db28c4de2dfe6097568836d6f 100644 (file)
@@ -30,12 +30,15 @@ static int zfcp_qdio_buffers_enqueue(struct qdio_buffer **sbal)
        return 0;
 }
 
-static void zfcp_qdio_handler_error(struct zfcp_qdio *qdio, char *id)
+static void zfcp_qdio_handler_error(struct zfcp_qdio *qdio, char *id,
+                                   unsigned int qdio_err)
 {
        struct zfcp_adapter *adapter = qdio->adapter;
 
        dev_warn(&adapter->ccw_device->dev, "A QDIO problem occurred\n");
 
+       if (qdio_err & QDIO_ERROR_SLSB_STATE)
+               zfcp_qdio_siosl(adapter);
        zfcp_erp_adapter_reopen(adapter,
                                ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED |
                                ZFCP_STATUS_COMMON_ERP_FAILED, id, NULL);
@@ -74,7 +77,7 @@ static void zfcp_qdio_int_req(struct ccw_device *cdev, unsigned int qdio_err,
 
        if (unlikely(qdio_err)) {
                zfcp_dbf_hba_qdio(qdio->adapter->dbf, qdio_err, idx, count);
-               zfcp_qdio_handler_error(qdio, "qdireq1");
+               zfcp_qdio_handler_error(qdio, "qdireq1", qdio_err);
                return;
        }
 
@@ -95,7 +98,7 @@ static void zfcp_qdio_int_resp(struct ccw_device *cdev, unsigned int qdio_err,
 
        if (unlikely(qdio_err)) {
                zfcp_dbf_hba_qdio(qdio->adapter->dbf, qdio_err, idx, count);
-               zfcp_qdio_handler_error(qdio, "qdires1");
+               zfcp_qdio_handler_error(qdio, "qdires1", qdio_err);
                return;
        }
 
@@ -361,6 +364,9 @@ int zfcp_qdio_open(struct zfcp_qdio *qdio)
        if (atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_QDIOUP)
                return -EIO;
 
+       atomic_clear_mask(ZFCP_STATUS_ADAPTER_SIOSL_ISSUED,
+                         &qdio->adapter->status);
+
        zfcp_qdio_setup_init_data(&init_data, qdio);
 
        if (qdio_establish(&init_data))
@@ -440,3 +446,26 @@ int zfcp_qdio_setup(struct zfcp_adapter *adapter)
        return 0;
 }
 
+/**
+ * zfcp_qdio_siosl - Trigger logging in FCP channel
+ * @adapter: The zfcp_adapter where to trigger logging
+ *
+ * Call the cio siosl function to trigger hardware logging.  This
+ * wrapper function sets a flag to ensure hardware logging is only
+ * triggered once before going through qdio shutdown.
+ *
+ * The triggers are always run from qdio tasklet context, so no
+ * additional synchronization is necessary.
+ */
+void zfcp_qdio_siosl(struct zfcp_adapter *adapter)
+{
+       int rc;
+
+       if (atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_SIOSL_ISSUED)
+               return;
+
+       rc = ccw_device_siosl(adapter->ccw_device);
+       if (!rc)
+               atomic_set_mask(ZFCP_STATUS_ADAPTER_SIOSL_ISSUED,
+                               &adapter->status);
+}