[SCSI] zfcp: Replace global config_lock with local list locks

The global config_lock was used to protect the configuration organized
in independent lists. It is not necessary to have a lock on driver
level for this purpose.  This patch replaces the global config_lock
with a set of local list locks.

Signed-off-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>
diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c
index f73e218..464f047 100644
--- a/drivers/s390/scsi/zfcp_erp.c
+++ b/drivers/s390/scsi/zfcp_erp.c
@@ -99,9 +99,12 @@
 
 	if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_INUSE)
 		zfcp_erp_action_dismiss(&port->erp_action);
-	else
-		list_for_each_entry(unit, &port->unit_list_head, list)
-		    zfcp_erp_action_dismiss_unit(unit);
+	else {
+		read_lock(&port->unit_list_lock);
+		list_for_each_entry(unit, &port->unit_list, list)
+			zfcp_erp_action_dismiss_unit(unit);
+		read_unlock(&port->unit_list_lock);
+	}
 }
 
 static void zfcp_erp_action_dismiss_adapter(struct zfcp_adapter *adapter)
@@ -110,9 +113,12 @@
 
 	if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_ERP_INUSE)
 		zfcp_erp_action_dismiss(&adapter->erp_action);
-	else
-		list_for_each_entry(port, &adapter->port_list_head, list)
+	else {
+		read_lock(&adapter->port_list_lock);
+		list_for_each_entry(port, &adapter->port_list, list)
 		    zfcp_erp_action_dismiss_port(port);
+		read_unlock(&adapter->port_list_lock);
+	}
 }
 
 static int zfcp_erp_required_act(int want, struct zfcp_adapter *adapter,
@@ -264,11 +270,16 @@
 {
 	unsigned long flags;
 
-	read_lock_irqsave(&zfcp_data.config_lock, flags);
-	write_lock(&adapter->erp_lock);
-	_zfcp_erp_adapter_reopen(adapter, clear, id, ref);
-	write_unlock(&adapter->erp_lock);
-	read_unlock_irqrestore(&zfcp_data.config_lock, flags);
+	zfcp_erp_adapter_block(adapter, clear);
+	zfcp_scsi_schedule_rports_block(adapter);
+
+	write_lock_irqsave(&adapter->erp_lock, flags);
+	if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_ERP_FAILED)
+		zfcp_erp_adapter_failed(adapter, "erareo1", NULL);
+	else
+		zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_ADAPTER, adapter,
+					NULL, NULL, id, ref);
+	write_unlock_irqrestore(&adapter->erp_lock, flags);
 }
 
 /**
@@ -345,11 +356,9 @@
 	unsigned long flags;
 	struct zfcp_adapter *adapter = port->adapter;
 
-	read_lock_irqsave(&zfcp_data.config_lock, flags);
-	write_lock(&adapter->erp_lock);
+	write_lock_irqsave(&adapter->erp_lock, flags);
 	_zfcp_erp_port_forced_reopen(port, clear, id, ref);
-	write_unlock(&adapter->erp_lock);
-	read_unlock_irqrestore(&zfcp_data.config_lock, flags);
+	write_unlock_irqrestore(&adapter->erp_lock, flags);
 }
 
 static int _zfcp_erp_port_reopen(struct zfcp_port *port, int clear, char *id,
@@ -377,15 +386,13 @@
  */
 int zfcp_erp_port_reopen(struct zfcp_port *port, int clear, char *id, void *ref)
 {
-	unsigned long flags;
 	int retval;
+	unsigned long flags;
 	struct zfcp_adapter *adapter = port->adapter;
 
-	read_lock_irqsave(&zfcp_data.config_lock, flags);
-	write_lock(&adapter->erp_lock);
+	write_lock_irqsave(&adapter->erp_lock, flags);
 	retval = _zfcp_erp_port_reopen(port, clear, id, ref);
-	write_unlock(&adapter->erp_lock);
-	read_unlock_irqrestore(&zfcp_data.config_lock, flags);
+	write_unlock_irqrestore(&adapter->erp_lock, flags);
 
 	return retval;
 }
@@ -424,11 +431,9 @@
 	struct zfcp_port *port = unit->port;
 	struct zfcp_adapter *adapter = port->adapter;
 
-	read_lock_irqsave(&zfcp_data.config_lock, flags);
-	write_lock(&adapter->erp_lock);
+	write_lock_irqsave(&adapter->erp_lock, flags);
 	_zfcp_erp_unit_reopen(unit, clear, id, ref);
-	write_unlock(&adapter->erp_lock);
-	read_unlock_irqrestore(&zfcp_data.config_lock, flags);
+	write_unlock_irqrestore(&adapter->erp_lock, flags);
 }
 
 static int status_change_set(unsigned long mask, atomic_t *status)
@@ -540,8 +545,10 @@
 {
 	struct zfcp_port *port;
 
-	list_for_each_entry(port, &adapter->port_list_head, list)
+	read_lock(&adapter->port_list_lock);
+	list_for_each_entry(port, &adapter->port_list, list)
 		_zfcp_erp_port_reopen(port, clear, id, ref);
+	read_unlock(&adapter->port_list_lock);
 }
 
 static void _zfcp_erp_unit_reopen_all(struct zfcp_port *port, int clear,
@@ -549,8 +556,10 @@
 {
 	struct zfcp_unit *unit;
 
-	list_for_each_entry(unit, &port->unit_list_head, list)
+	read_lock(&port->unit_list_lock);
+	list_for_each_entry(unit, &port->unit_list, list)
 		_zfcp_erp_unit_reopen(unit, clear, id, ref);
+	read_unlock(&port->unit_list_lock);
 }
 
 static void zfcp_erp_strategy_followup_failed(struct zfcp_erp_action *act)
@@ -590,16 +599,14 @@
 {
 	unsigned long flags;
 
-	read_lock_irqsave(&zfcp_data.config_lock, flags);
-	read_lock(&adapter->erp_lock);
+	read_lock_irqsave(&adapter->erp_lock, flags);
 	if (list_empty(&adapter->erp_ready_head) &&
 	    list_empty(&adapter->erp_running_head)) {
 			atomic_clear_mask(ZFCP_STATUS_ADAPTER_ERP_PENDING,
 					  &adapter->status);
 			wake_up(&adapter->erp_done_wqh);
 	}
-	read_unlock(&adapter->erp_lock);
-	read_unlock_irqrestore(&zfcp_data.config_lock, flags);
+	read_unlock_irqrestore(&adapter->erp_lock, flags);
 }
 
 static int zfcp_erp_adapter_strategy_open_qdio(struct zfcp_erp_action *act)
@@ -1214,11 +1221,10 @@
 static int zfcp_erp_strategy(struct zfcp_erp_action *erp_action)
 {
 	int retval;
-	struct zfcp_adapter *adapter = erp_action->adapter;
 	unsigned long flags;
+	struct zfcp_adapter *adapter = erp_action->adapter;
 
-	read_lock_irqsave(&zfcp_data.config_lock, flags);
-	write_lock(&adapter->erp_lock);
+	write_lock_irqsave(&adapter->erp_lock, flags);
 
 	zfcp_erp_strategy_check_fsfreq(erp_action);
 
@@ -1231,11 +1237,9 @@
 	zfcp_erp_action_to_running(erp_action);
 
 	/* no lock to allow for blocking operations */
-	write_unlock(&adapter->erp_lock);
-	read_unlock_irqrestore(&zfcp_data.config_lock, flags);
+	write_unlock_irqrestore(&adapter->erp_lock, flags);
 	retval = zfcp_erp_strategy_do_action(erp_action);
-	read_lock_irqsave(&zfcp_data.config_lock, flags);
-	write_lock(&adapter->erp_lock);
+	write_lock_irqsave(&adapter->erp_lock, flags);
 
 	if (erp_action->status & ZFCP_STATUS_ERP_DISMISSED)
 		retval = ZFCP_ERP_CONTINUES;
@@ -1273,8 +1277,7 @@
 		zfcp_erp_strategy_followup_failed(erp_action);
 
  unlock:
-	write_unlock(&adapter->erp_lock);
-	read_unlock_irqrestore(&zfcp_data.config_lock, flags);
+	write_unlock_irqrestore(&adapter->erp_lock, flags);
 
 	if (retval != ZFCP_ERP_CONTINUES)
 		zfcp_erp_action_cleanup(erp_action, retval);
@@ -1415,6 +1418,7 @@
 				    void *ref, u32 mask, int set_or_clear)
 {
 	struct zfcp_port *port;
+	unsigned long flags;
 	u32 common_mask = mask & ZFCP_COMMON_FLAGS;
 
 	if (set_or_clear == ZFCP_SET) {
@@ -1429,10 +1433,13 @@
 			atomic_set(&adapter->erp_counter, 0);
 	}
 
-	if (common_mask)
-		list_for_each_entry(port, &adapter->port_list_head, list)
+	if (common_mask) {
+		read_lock_irqsave(&adapter->port_list_lock, flags);
+		list_for_each_entry(port, &adapter->port_list, list)
 			zfcp_erp_modify_port_status(port, id, ref, common_mask,
 						    set_or_clear);
+		read_unlock_irqrestore(&adapter->port_list_lock, flags);
+	}
 }
 
 /**
@@ -1449,6 +1456,7 @@
 				 u32 mask, int set_or_clear)
 {
 	struct zfcp_unit *unit;
+	unsigned long flags;
 	u32 common_mask = mask & ZFCP_COMMON_FLAGS;
 
 	if (set_or_clear == ZFCP_SET) {
@@ -1463,10 +1471,13 @@
 			atomic_set(&port->erp_counter, 0);
 	}
 
-	if (common_mask)
-		list_for_each_entry(unit, &port->unit_list_head, list)
+	if (common_mask) {
+		read_lock_irqsave(&port->unit_list_lock, flags);
+		list_for_each_entry(unit, &port->unit_list, list)
 			zfcp_erp_modify_unit_status(unit, id, ref, common_mask,
 						    set_or_clear);
+		read_unlock_irqrestore(&port->unit_list_lock, flags);
+	}
 }
 
 /**
@@ -1502,12 +1513,8 @@
  */
 void zfcp_erp_port_boxed(struct zfcp_port *port, char *id, void *ref)
 {
-	unsigned long flags;
-
-	read_lock_irqsave(&zfcp_data.config_lock, flags);
 	zfcp_erp_modify_port_status(port, id, ref,
 				    ZFCP_STATUS_COMMON_ACCESS_BOXED, ZFCP_SET);
-	read_unlock_irqrestore(&zfcp_data.config_lock, flags);
 	zfcp_erp_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED, id, ref);
 }
 
@@ -1535,13 +1542,9 @@
  */
 void zfcp_erp_port_access_denied(struct zfcp_port *port, char *id, void *ref)
 {
-	unsigned long flags;
-
-	read_lock_irqsave(&zfcp_data.config_lock, flags);
 	zfcp_erp_modify_port_status(port, id, ref,
 				    ZFCP_STATUS_COMMON_ERP_FAILED |
 				    ZFCP_STATUS_COMMON_ACCESS_DENIED, ZFCP_SET);
-	read_unlock_irqrestore(&zfcp_data.config_lock, flags);
 }
 
 /**
@@ -1574,12 +1577,15 @@
 					 void *ref)
 {
 	struct zfcp_unit *unit;
+	unsigned long flags;
 	int status = atomic_read(&port->status);
 
 	if (!(status & (ZFCP_STATUS_COMMON_ACCESS_DENIED |
 			ZFCP_STATUS_COMMON_ACCESS_BOXED))) {
-		list_for_each_entry(unit, &port->unit_list_head, list)
+		read_lock_irqsave(&port->unit_list_lock, flags);
+		list_for_each_entry(unit, &port->unit_list, list)
 				    zfcp_erp_unit_access_changed(unit, id, ref);
+		read_unlock_irqrestore(&port->unit_list_lock, flags);
 		return;
 	}
 
@@ -1595,14 +1601,14 @@
 void zfcp_erp_adapter_access_changed(struct zfcp_adapter *adapter, char *id,
 				     void *ref)
 {
-	struct zfcp_port *port;
 	unsigned long flags;
+	struct zfcp_port *port;
 
 	if (adapter->connection_features & FSF_FEATURE_NPIV_MODE)
 		return;
 
-	read_lock_irqsave(&zfcp_data.config_lock, flags);
-	list_for_each_entry(port, &adapter->port_list_head, list)
+	read_lock_irqsave(&adapter->port_list_lock, flags);
+	list_for_each_entry(port, &adapter->port_list, list)
 		zfcp_erp_port_access_changed(port, id, ref);
-	read_unlock_irqrestore(&zfcp_data.config_lock, flags);
+	read_unlock_irqrestore(&adapter->port_list_lock, flags);
 }