|
@@ -3,7 +3,7 @@
|
|
|
*
|
|
|
* Error Recovery Procedures (ERP).
|
|
|
*
|
|
|
- * Copyright IBM Corp. 2002, 2015
|
|
|
+ * Copyright IBM Corp. 2002, 2016
|
|
|
*/
|
|
|
|
|
|
#define KMSG_COMPONENT "zfcp"
|
|
@@ -1204,6 +1204,62 @@ static void zfcp_erp_action_dequeue(struct zfcp_erp_action *erp_action)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * zfcp_erp_try_rport_unblock - unblock rport if no more/new recovery
|
|
|
+ * @port: zfcp_port whose fc_rport we should try to unblock
|
|
|
+ */
|
|
|
+static void zfcp_erp_try_rport_unblock(struct zfcp_port *port)
|
|
|
+{
|
|
|
+ unsigned long flags;
|
|
|
+ struct zfcp_adapter *adapter = port->adapter;
|
|
|
+ int port_status;
|
|
|
+ struct Scsi_Host *shost = adapter->scsi_host;
|
|
|
+ struct scsi_device *sdev;
|
|
|
+
|
|
|
+ write_lock_irqsave(&adapter->erp_lock, flags);
|
|
|
+ port_status = atomic_read(&port->status);
|
|
|
+ if ((port_status & ZFCP_STATUS_COMMON_UNBLOCKED) == 0 ||
|
|
|
+ (port_status & (ZFCP_STATUS_COMMON_ERP_INUSE |
|
|
|
+ ZFCP_STATUS_COMMON_ERP_FAILED)) != 0) {
|
|
|
+ /* new ERP of severity >= port triggered elsewhere meanwhile or
|
|
|
+ * local link down (adapter erp_failed but not clear unblock)
|
|
|
+ */
|
|
|
+ zfcp_dbf_rec_run_lvl(4, "ertru_p", &port->erp_action);
|
|
|
+ write_unlock_irqrestore(&adapter->erp_lock, flags);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ spin_lock(shost->host_lock);
|
|
|
+ __shost_for_each_device(sdev, shost) {
|
|
|
+ struct zfcp_scsi_dev *zsdev = sdev_to_zfcp(sdev);
|
|
|
+ int lun_status;
|
|
|
+
|
|
|
+ if (zsdev->port != port)
|
|
|
+ continue;
|
|
|
+ /* LUN under port of interest */
|
|
|
+ lun_status = atomic_read(&zsdev->status);
|
|
|
+ if ((lun_status & ZFCP_STATUS_COMMON_ERP_FAILED) != 0)
|
|
|
+ continue; /* unblock rport despite failed LUNs */
|
|
|
+ /* LUN recovery not given up yet [maybe follow-up pending] */
|
|
|
+ if ((lun_status & ZFCP_STATUS_COMMON_UNBLOCKED) == 0 ||
|
|
|
+ (lun_status & ZFCP_STATUS_COMMON_ERP_INUSE) != 0) {
|
|
|
+ /* LUN blocked:
|
|
|
+ * not yet unblocked [LUN recovery pending]
|
|
|
+ * or meanwhile blocked [new LUN recovery triggered]
|
|
|
+ */
|
|
|
+ zfcp_dbf_rec_run_lvl(4, "ertru_l", &zsdev->erp_action);
|
|
|
+ spin_unlock(shost->host_lock);
|
|
|
+ write_unlock_irqrestore(&adapter->erp_lock, flags);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ /* now port has no child or all children have completed recovery,
|
|
|
+ * and no ERP of severity >= port was meanwhile triggered elsewhere
|
|
|
+ */
|
|
|
+ zfcp_scsi_schedule_rport_register(port);
|
|
|
+ spin_unlock(shost->host_lock);
|
|
|
+ write_unlock_irqrestore(&adapter->erp_lock, flags);
|
|
|
+}
|
|
|
+
|
|
|
static void zfcp_erp_action_cleanup(struct zfcp_erp_action *act, int result)
|
|
|
{
|
|
|
struct zfcp_adapter *adapter = act->adapter;
|
|
@@ -1214,6 +1270,7 @@ static void zfcp_erp_action_cleanup(struct zfcp_erp_action *act, int result)
|
|
|
case ZFCP_ERP_ACTION_REOPEN_LUN:
|
|
|
if (!(act->status & ZFCP_STATUS_ERP_NO_REF))
|
|
|
scsi_device_put(sdev);
|
|
|
+ zfcp_erp_try_rport_unblock(port);
|
|
|
break;
|
|
|
|
|
|
case ZFCP_ERP_ACTION_REOPEN_PORT:
|
|
@@ -1224,7 +1281,7 @@ static void zfcp_erp_action_cleanup(struct zfcp_erp_action *act, int result)
|
|
|
*/
|
|
|
if (act->step != ZFCP_ERP_STEP_UNINITIALIZED)
|
|
|
if (result == ZFCP_ERP_SUCCEEDED)
|
|
|
- zfcp_scsi_schedule_rport_register(port);
|
|
|
+ zfcp_erp_try_rport_unblock(port);
|
|
|
/* fall through */
|
|
|
case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
|
|
|
put_device(&port->dev);
|