--- zzzz-none-000/linux-3.10.107/drivers/s390/scsi/zfcp_fc.c 2017-06-27 09:49:32.000000000 +0000 +++ scorpion-7490-727/linux-3.10.107/drivers/s390/scsi/zfcp_fc.c 2021-02-04 17:41:59.000000000 +0000 @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include "zfcp_ext.h" @@ -31,12 +32,54 @@ MODULE_PARM_DESC(no_auto_port_rescan, "no automatic port_rescan (default off)"); +static unsigned int port_scan_backoff = 500; +module_param(port_scan_backoff, uint, 0600); +MODULE_PARM_DESC(port_scan_backoff, + "upper limit of port scan random backoff in msecs (default 500)"); + +static unsigned int port_scan_ratelimit = 60000; +module_param(port_scan_ratelimit, uint, 0600); +MODULE_PARM_DESC(port_scan_ratelimit, + "minimum interval between port scans in msecs (default 60000)"); + +unsigned int zfcp_fc_port_scan_backoff(void) +{ + if (!port_scan_backoff) + return 0; + return get_random_int() % port_scan_backoff; +} + +static void zfcp_fc_port_scan_time(struct zfcp_adapter *adapter) +{ + unsigned long interval = msecs_to_jiffies(port_scan_ratelimit); + unsigned long backoff = msecs_to_jiffies(zfcp_fc_port_scan_backoff()); + + adapter->next_port_scan = jiffies + interval + backoff; +} + +static void zfcp_fc_port_scan(struct zfcp_adapter *adapter) +{ + unsigned long now = jiffies; + unsigned long next = adapter->next_port_scan; + unsigned long delay = 0, max; + + /* delay only needed within waiting period */ + if (time_before(now, next)) { + delay = next - now; + /* paranoia: never ever delay scans longer than specified */ + max = msecs_to_jiffies(port_scan_ratelimit + port_scan_backoff); + delay = min(delay, max); + } + + queue_delayed_work(adapter->work_queue, &adapter->scan_work, delay); +} + void zfcp_fc_conditional_port_scan(struct zfcp_adapter *adapter) { if (no_auto_port_rescan) return; - queue_work(adapter->work_queue, &adapter->scan_work); + zfcp_fc_port_scan(adapter); } void zfcp_fc_inverse_conditional_port_scan(struct zfcp_adapter *adapter) @@ -44,7 +87,7 @@ if (!no_auto_port_rescan) return; - queue_work(adapter->work_queue, &adapter->scan_work); + zfcp_fc_port_scan(adapter); } /** @@ -465,7 +508,7 @@ /* port is good, unblock rport without going through erp */ zfcp_scsi_schedule_rport_register(port); out: - atomic_clear_mask(ZFCP_STATUS_PORT_LINK_TEST, &port->status); + atomic_andnot(ZFCP_STATUS_PORT_LINK_TEST, &port->status); put_device(&port->dev); kmem_cache_free(zfcp_fc_req_cache, fc_req); } @@ -521,14 +564,14 @@ if (atomic_read(&port->status) & ZFCP_STATUS_PORT_LINK_TEST) goto out; - atomic_set_mask(ZFCP_STATUS_PORT_LINK_TEST, &port->status); + atomic_or(ZFCP_STATUS_PORT_LINK_TEST, &port->status); retval = zfcp_fc_adisc(port); if (retval == 0) return; /* send of ADISC was not possible */ - atomic_clear_mask(ZFCP_STATUS_PORT_LINK_TEST, &port->status); + atomic_andnot(ZFCP_STATUS_PORT_LINK_TEST, &port->status); zfcp_erp_port_forced_reopen(port, 0, "fcltwk1"); out: @@ -597,7 +640,7 @@ if (!(atomic_read(&port->status) & ZFCP_STATUS_COMMON_NOESC)) return; - atomic_clear_mask(ZFCP_STATUS_COMMON_NOESC, &port->status); + atomic_andnot(ZFCP_STATUS_COMMON_NOESC, &port->status); if ((port->supported_classes != 0) || !list_empty(&port->unit_list)) @@ -668,7 +711,7 @@ list_for_each_entry_safe(port, tmp, &remove_lh, list) { zfcp_erp_port_shutdown(port, 0, "fcegpf2"); - zfcp_device_unregister(&port->dev, &zfcp_sysfs_port_attrs); + device_unregister(&port->dev); } return ret; @@ -680,12 +723,15 @@ */ void zfcp_fc_scan_ports(struct work_struct *work) { - struct zfcp_adapter *adapter = container_of(work, struct zfcp_adapter, + struct delayed_work *dw = to_delayed_work(work); + struct zfcp_adapter *adapter = container_of(dw, struct zfcp_adapter, scan_work); int ret, i; struct zfcp_fc_req *fc_req; int chain, max_entries, buf_num, max_bytes; + zfcp_fc_port_scan_time(adapter); + chain = adapter->adapter_features & FSF_FEATURE_ELS_CT_CHAINED_SBALS; buf_num = chain ? ZFCP_FC_GPN_FT_NUM_BUFS : 1; max_entries = chain ? ZFCP_FC_GPN_FT_MAX_ENT : ZFCP_FC_GPN_FT_ENT_PAGE;