/** * zfcp_erp_adapter_reopen - Reopen adapter. * @adapter: Adapter to reopen. * @clear: Status flags to clear. * @id: Id for debug trace event. * @ref: Reference for debug trace event. */ void zfcp_erp_adapter_reopen(struct zfcp_adapter *adapter, int clear, char *id, void *ref) { 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); }
static void zfcp_erp_strategy_followup_actions(struct zfcp_erp_action *act) { struct zfcp_adapter *adapter = act->adapter; struct zfcp_port *port = act->port; struct zfcp_unit *unit = act->unit; u32 status = act->status; /* initiate follow-up actions depending on success of finished action */ switch (act->action) { case ZFCP_ERP_ACTION_REOPEN_ADAPTER: if (status == ZFCP_ERP_SUCCEEDED) _zfcp_erp_port_reopen_all(adapter, 0, "ersfa_1", NULL); else _zfcp_erp_adapter_reopen(adapter, 0, "ersfa_2", NULL); break; case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: if (status == ZFCP_ERP_SUCCEEDED) _zfcp_erp_port_reopen(port, 0, "ersfa_3", NULL); else _zfcp_erp_adapter_reopen(adapter, 0, "ersfa_4", NULL); break; case ZFCP_ERP_ACTION_REOPEN_PORT: if (status == ZFCP_ERP_SUCCEEDED) _zfcp_erp_unit_reopen_all(port, 0, "ersfa_5", NULL); else _zfcp_erp_port_forced_reopen(port, 0, "ersfa_6", NULL); break; case ZFCP_ERP_ACTION_REOPEN_UNIT: if (status != ZFCP_ERP_SUCCEEDED) _zfcp_erp_port_reopen(unit->port, 0, "ersfa_7", NULL); break; } }
static void zfcp_erp_strategy_followup_failed(struct zfcp_erp_action *act) { switch (act->action) { case ZFCP_ERP_ACTION_REOPEN_ADAPTER: _zfcp_erp_adapter_reopen(act->adapter, 0, "ersff_1", NULL); break; case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: _zfcp_erp_port_forced_reopen(act->port, 0, "ersff_2", NULL); break; case ZFCP_ERP_ACTION_REOPEN_PORT: _zfcp_erp_port_reopen(act->port, 0, "ersff_3", NULL); break; case ZFCP_ERP_ACTION_REOPEN_UNIT: _zfcp_erp_unit_reopen(act->unit, 0, "ersff_4", NULL); break; } }
static int zfcp_erp_strategy_statechange(struct zfcp_erp_action *act, int ret) { int action = act->action; struct zfcp_adapter *adapter = act->adapter; struct zfcp_port *port = act->port; struct scsi_device *sdev = act->sdev; struct zfcp_scsi_dev *zfcp_sdev; u32 erp_status = act->status; switch (action) { case ZFCP_ERP_ACTION_REOPEN_ADAPTER: if (zfcp_erp_strat_change_det(&adapter->status, erp_status)) { _zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED, "ersscg1"); return ZFCP_ERP_EXIT; } break; case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: case ZFCP_ERP_ACTION_REOPEN_PORT: if (zfcp_erp_strat_change_det(&port->status, erp_status)) { _zfcp_erp_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED, "ersscg2"); return ZFCP_ERP_EXIT; } break; case ZFCP_ERP_ACTION_REOPEN_LUN: zfcp_sdev = sdev_to_zfcp(sdev); if (zfcp_erp_strat_change_det(&zfcp_sdev->status, erp_status)) { _zfcp_erp_lun_reopen(sdev, ZFCP_STATUS_COMMON_ERP_FAILED, "ersscg3", 0); return ZFCP_ERP_EXIT; } break; } return ret; }
static int zfcp_erp_strategy_statechange(struct zfcp_erp_action *act, int ret) { int action = act->action; struct zfcp_adapter *adapter = act->adapter; struct zfcp_port *port = act->port; struct zfcp_unit *unit = act->unit; u32 erp_status = act->status; switch (action) { case ZFCP_ERP_ACTION_REOPEN_ADAPTER: if (zfcp_erp_strat_change_det(&adapter->status, erp_status)) { _zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED, "ersscg1", NULL); return ZFCP_ERP_EXIT; } break; case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: case ZFCP_ERP_ACTION_REOPEN_PORT: if (zfcp_erp_strat_change_det(&port->status, erp_status)) { _zfcp_erp_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED, "ersscg2", NULL); return ZFCP_ERP_EXIT; } break; case ZFCP_ERP_ACTION_REOPEN_UNIT: if (zfcp_erp_strat_change_det(&unit->status, erp_status)) { _zfcp_erp_unit_reopen(unit, ZFCP_STATUS_COMMON_ERP_FAILED, "ersscg3", NULL); return ZFCP_ERP_EXIT; } break; } return ret; }
static int zfcp_erp_strategy(struct zfcp_erp_action *erp_action) { int retval; struct zfcp_adapter *adapter = erp_action->adapter; unsigned long flags; read_lock_irqsave(&zfcp_data.config_lock, flags); write_lock(&adapter->erp_lock); zfcp_erp_strategy_check_fsfreq(erp_action); if (erp_action->status & ZFCP_STATUS_ERP_DISMISSED) { zfcp_erp_action_dequeue(erp_action); retval = ZFCP_ERP_DISMISSED; goto unlock; } if (erp_action->status & ZFCP_STATUS_ERP_TIMEDOUT) { retval = ZFCP_ERP_FAILED; goto check_target; } 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); retval = zfcp_erp_strategy_do_action(erp_action); read_lock_irqsave(&zfcp_data.config_lock, flags); write_lock(&adapter->erp_lock); if (erp_action->status & ZFCP_STATUS_ERP_DISMISSED) retval = ZFCP_ERP_CONTINUES; switch (retval) { case ZFCP_ERP_NOMEM: if (!(erp_action->status & ZFCP_STATUS_ERP_LOWMEM)) { ++adapter->erp_low_mem_count; erp_action->status |= ZFCP_STATUS_ERP_LOWMEM; } if (adapter->erp_total_count == adapter->erp_low_mem_count) _zfcp_erp_adapter_reopen(adapter, 0, "erstgy1", NULL); else { zfcp_erp_strategy_memwait(erp_action); retval = ZFCP_ERP_CONTINUES; } goto unlock; case ZFCP_ERP_CONTINUES: if (erp_action->status & ZFCP_STATUS_ERP_LOWMEM) { --adapter->erp_low_mem_count; erp_action->status &= ~ZFCP_STATUS_ERP_LOWMEM; } goto unlock; } check_target: retval = zfcp_erp_strategy_check_target(erp_action, retval); zfcp_erp_action_dequeue(erp_action); retval = zfcp_erp_strategy_statechange(erp_action, retval); if (retval == ZFCP_ERP_EXIT) goto unlock; if (retval == ZFCP_ERP_SUCCEEDED) zfcp_erp_strategy_followup_success(erp_action); if (retval == ZFCP_ERP_FAILED) zfcp_erp_strategy_followup_failed(erp_action); unlock: write_unlock(&adapter->erp_lock); read_unlock_irqrestore(&zfcp_data.config_lock, flags); if (retval != ZFCP_ERP_CONTINUES) zfcp_erp_action_cleanup(erp_action, retval); return retval; }