[SCSI] zfcp: No automatic port_rescan on events
authorSteffen Maier <maier@linux.vnet.ibm.com>
Tue, 4 Sep 2012 13:23:35 +0000 (15:23 +0200)
committerJames Bottomley <JBottomley@Parallels.com>
Mon, 24 Sep 2012 08:11:02 +0000 (12:11 +0400)
In FC fabrics with large zones, the automatic port_rescan on incoming ELS
and any adapter recovery can cause quite some traffic at the very same
time, especially if lots of Linux images share an HBA, which is common on
s390. This can cause trouble and failures. Fix this by making such port
rescans dependent on a user configurable module parameter.

The following unconditional automatic port rescans remain as is:
On setting an adapter online and
on manual user-triggered writes to the sysfs attribute port_rescan.

Signed-off-by: Steffen Maier <maier@linux.vnet.ibm.com>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
drivers/s390/scsi/zfcp_ccw.c
drivers/s390/scsi/zfcp_erp.c
drivers/s390/scsi/zfcp_ext.h
drivers/s390/scsi/zfcp_fc.c
drivers/s390/scsi/zfcp_fsf.c

index 9646766360d3d5acf5052e4b21b5d2ce04114764..f2dd3a0a39eb04e421437f4eaef1b6d1d1f1f82f 100644 (file)
@@ -57,7 +57,7 @@ static int zfcp_ccw_activate(struct ccw_device *cdev, int clear, char *tag)
        zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED,
                                tag);
        zfcp_erp_wait(adapter);
-       flush_work(&adapter->scan_work);
+       flush_work(&adapter->scan_work); /* ok to call even if nothing queued */
 
        zfcp_ccw_adapter_put(adapter);
 
@@ -171,6 +171,11 @@ static int zfcp_ccw_set_online(struct ccw_device *cdev)
        adapter->req_no = 0;
 
        zfcp_ccw_activate(cdev, 0, "ccsonl1");
+       /* scan for remote ports
+          either at the end of any successful adapter recovery
+          or only after the adapter recovery for setting a device online */
+       zfcp_fc_inverse_conditional_port_scan(adapter);
+       flush_work(&adapter->scan_work); /* ok to call even if nothing queued */
        zfcp_ccw_adapter_put(adapter);
        return 0;
 }
index 92d3df6ac8ba9e6ef37ba3e24b503e6b12217ef2..4133ab6e20f1ab5ccfe058b49f125770e6c289e2 100644 (file)
@@ -1230,7 +1230,7 @@ static void zfcp_erp_action_cleanup(struct zfcp_erp_action *act, int result)
        case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
                if (result == ZFCP_ERP_SUCCEEDED) {
                        register_service_level(&adapter->service_level);
-                       queue_work(adapter->work_queue, &adapter->scan_work);
+                       zfcp_fc_conditional_port_scan(adapter);
                        queue_work(adapter->work_queue, &adapter->ns_up_work);
                } else
                        unregister_service_level(&adapter->service_level);
index 03441a7fb463c6fc062da5a20ba0abc4d174d893..1d3dd3f7d69994163c2dd1d860a7a6584c21f5d5 100644 (file)
@@ -99,6 +99,8 @@ extern void zfcp_fc_gs_destroy(struct zfcp_adapter *);
 extern int zfcp_fc_exec_bsg_job(struct fc_bsg_job *);
 extern int zfcp_fc_timeout_bsg_job(struct fc_bsg_job *);
 extern void zfcp_fc_sym_name_update(struct work_struct *);
+extern void zfcp_fc_conditional_port_scan(struct zfcp_adapter *);
+extern void zfcp_fc_inverse_conditional_port_scan(struct zfcp_adapter *);
 
 /* zfcp_fsf.c */
 extern struct kmem_cache *zfcp_fsf_qtcb_cache;
index 88688a80b2c11334bcc99686634bee964858b816..ff598cd68b2d0bde11c99c412ca0ea70a90d6ece 100644 (file)
@@ -26,6 +26,27 @@ static u32 zfcp_fc_rscn_range_mask[] = {
        [ELS_ADDR_FMT_FAB]              = 0x000000,
 };
 
+static bool no_auto_port_rescan;
+module_param_named(no_auto_port_rescan, no_auto_port_rescan, bool, 0600);
+MODULE_PARM_DESC(no_auto_port_rescan,
+                "no automatic port_rescan (default off)");
+
+void zfcp_fc_conditional_port_scan(struct zfcp_adapter *adapter)
+{
+       if (no_auto_port_rescan)
+               return;
+
+       queue_work(adapter->work_queue, &adapter->scan_work);
+}
+
+void zfcp_fc_inverse_conditional_port_scan(struct zfcp_adapter *adapter)
+{
+       if (!no_auto_port_rescan)
+               return;
+
+       queue_work(adapter->work_queue, &adapter->scan_work);
+}
+
 /**
  * zfcp_fc_post_event - post event to userspace via fc_transport
  * @work: work struct with enqueued events
@@ -206,7 +227,7 @@ static void zfcp_fc_incoming_rscn(struct zfcp_fsf_req *fsf_req)
                zfcp_fc_enqueue_event(fsf_req->adapter, FCH_EVT_RSCN,
                                      *(u32 *)page);
        }
-       queue_work(fsf_req->adapter->work_queue, &fsf_req->adapter->scan_work);
+       zfcp_fc_conditional_port_scan(fsf_req->adapter);
 }
 
 static void zfcp_fc_incoming_wwpn(struct zfcp_fsf_req *req, u64 wwpn)
index 6e2892e7c4be966097e64f0b73065d03d51cf9ab..9ffdc335429ccb8bab869d31a4bbf35792737a2b 100644 (file)
@@ -257,7 +257,7 @@ static void zfcp_fsf_status_read_handler(struct zfcp_fsf_req *req)
                if (sr_buf->status_subtype & FSF_STATUS_READ_SUB_ACT_UPDATED)
                        zfcp_cfdc_adapter_access_changed(adapter);
                if (sr_buf->status_subtype & FSF_STATUS_READ_SUB_INCOMING_ELS)
-                       queue_work(adapter->work_queue, &adapter->scan_work);
+                       zfcp_fc_conditional_port_scan(adapter);
                break;
        case FSF_STATUS_READ_CFDC_UPDATED:
                zfcp_cfdc_adapter_access_changed(adapter);