diff options
Diffstat (limited to 'drivers/s390/scsi/zfcp_erp.c')
-rw-r--r-- | drivers/s390/scsi/zfcp_erp.c | 135 |
1 files changed, 112 insertions, 23 deletions
diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c index cb4f612550ba..023f4e558ae4 100644 --- a/drivers/s390/scsi/zfcp_erp.c +++ b/drivers/s390/scsi/zfcp_erp.c @@ -82,6 +82,7 @@ static int zfcp_erp_adapter_strategy_open(struct zfcp_erp_action *); static int zfcp_erp_adapter_strategy_open_qdio(struct zfcp_erp_action *); static int zfcp_erp_adapter_strategy_open_fsf(struct zfcp_erp_action *); static int zfcp_erp_adapter_strategy_open_fsf_xconfig(struct zfcp_erp_action *); +static int zfcp_erp_adapter_strategy_open_fsf_xport(struct zfcp_erp_action *); static int zfcp_erp_adapter_strategy_open_fsf_statusread( struct zfcp_erp_action *); @@ -345,13 +346,13 @@ zfcp_erp_adisc(struct zfcp_port *port) /* acc. to FC-FS, hard_nport_id in ADISC should not be set for ports without FC-AL-2 capability, so we don't set it */ - adisc->wwpn = adapter->wwpn; - adisc->wwnn = adapter->wwnn; - adisc->nport_id = adapter->s_id; + adisc->wwpn = fc_host_port_name(adapter->scsi_host); + adisc->wwnn = fc_host_node_name(adapter->scsi_host); + adisc->nport_id = fc_host_port_id(adapter->scsi_host); ZFCP_LOG_INFO("ADISC request from s_id 0x%08x to d_id 0x%08x " "(wwpn=0x%016Lx, wwnn=0x%016Lx, " "hard_nport_id=0x%08x, nport_id=0x%08x)\n", - adapter->s_id, send_els->d_id, (wwn_t) adisc->wwpn, + adisc->nport_id, send_els->d_id, (wwn_t) adisc->wwpn, (wwn_t) adisc->wwnn, adisc->hard_nport_id, adisc->nport_id); @@ -404,7 +405,7 @@ zfcp_erp_adisc_handler(unsigned long data) struct zfcp_send_els *send_els; struct zfcp_port *port; struct zfcp_adapter *adapter; - fc_id_t d_id; + u32 d_id; struct zfcp_ls_adisc_acc *adisc; send_els = (struct zfcp_send_els *) data; @@ -435,9 +436,9 @@ zfcp_erp_adisc_handler(unsigned long data) ZFCP_LOG_INFO("ADISC response from d_id 0x%08x to s_id " "0x%08x (wwpn=0x%016Lx, wwnn=0x%016Lx, " "hard_nport_id=0x%08x, nport_id=0x%08x)\n", - d_id, adapter->s_id, (wwn_t) adisc->wwpn, - (wwn_t) adisc->wwnn, adisc->hard_nport_id, - adisc->nport_id); + d_id, fc_host_port_id(adapter->scsi_host), + (wwn_t) adisc->wwpn, (wwn_t) adisc->wwnn, + adisc->hard_nport_id, adisc->nport_id); /* set wwnn for port */ if (port->wwnn == 0) @@ -886,7 +887,7 @@ static int zfcp_erp_strategy_check_fsfreq(struct zfcp_erp_action *erp_action) { int retval = 0; - struct zfcp_fsf_req *fsf_req; + struct zfcp_fsf_req *fsf_req = NULL; struct zfcp_adapter *adapter = erp_action->adapter; if (erp_action->fsf_req) { @@ -896,7 +897,7 @@ zfcp_erp_strategy_check_fsfreq(struct zfcp_erp_action *erp_action) list_for_each_entry(fsf_req, &adapter->fsf_req_list_head, list) if (fsf_req == erp_action->fsf_req) break; - if (fsf_req == erp_action->fsf_req) { + if (fsf_req && (fsf_req->erp_action == erp_action)) { /* fsf_req still exists */ debug_text_event(adapter->erp_dbf, 3, "a_ca_req"); debug_event(adapter->erp_dbf, 3, &fsf_req, @@ -2258,16 +2259,21 @@ zfcp_erp_adapter_strategy_close_qdio(struct zfcp_erp_action *erp_action) static int zfcp_erp_adapter_strategy_open_fsf(struct zfcp_erp_action *erp_action) { - int retval; + int xconfig, xport; + + if (atomic_test_mask(ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED, + &erp_action->adapter->status)) { + zfcp_erp_adapter_strategy_open_fsf_xport(erp_action); + atomic_set(&erp_action->adapter->erp_counter, 0); + return ZFCP_ERP_FAILED; + } - /* do 'exchange configuration data' */ - retval = zfcp_erp_adapter_strategy_open_fsf_xconfig(erp_action); - if (retval == ZFCP_ERP_FAILED) - return retval; + xconfig = zfcp_erp_adapter_strategy_open_fsf_xconfig(erp_action); + xport = zfcp_erp_adapter_strategy_open_fsf_xport(erp_action); + if ((xconfig == ZFCP_ERP_FAILED) || (xport == ZFCP_ERP_FAILED)) + return ZFCP_ERP_FAILED; - /* start the desired number of Status Reads */ - retval = zfcp_erp_adapter_strategy_open_fsf_statusread(erp_action); - return retval; + return zfcp_erp_adapter_strategy_open_fsf_statusread(erp_action); } /* @@ -2291,7 +2297,9 @@ zfcp_erp_adapter_strategy_open_fsf_xconfig(struct zfcp_erp_action *erp_action) atomic_clear_mask(ZFCP_STATUS_ADAPTER_HOST_CON_INIT, &adapter->status); ZFCP_LOG_DEBUG("Doing exchange config data\n"); + write_lock(&adapter->erp_lock); zfcp_erp_action_to_running(erp_action); + write_unlock(&adapter->erp_lock); zfcp_erp_timeout_init(erp_action); if (zfcp_fsf_exchange_config_data(erp_action)) { retval = ZFCP_ERP_FAILED; @@ -2348,6 +2356,76 @@ zfcp_erp_adapter_strategy_open_fsf_xconfig(struct zfcp_erp_action *erp_action) return retval; } +static int +zfcp_erp_adapter_strategy_open_fsf_xport(struct zfcp_erp_action *erp_action) +{ + int retval = ZFCP_ERP_SUCCEEDED; + int retries; + int sleep; + struct zfcp_adapter *adapter = erp_action->adapter; + + atomic_clear_mask(ZFCP_STATUS_ADAPTER_XPORT_OK, &adapter->status); + + for (retries = 0; ; retries++) { + ZFCP_LOG_DEBUG("Doing exchange port data\n"); + zfcp_erp_action_to_running(erp_action); + zfcp_erp_timeout_init(erp_action); + if (zfcp_fsf_exchange_port_data(erp_action, adapter, NULL)) { + retval = ZFCP_ERP_FAILED; + debug_text_event(adapter->erp_dbf, 5, "a_fstx_xf"); + ZFCP_LOG_INFO("error: initiation of exchange of " + "port data failed for adapter %s\n", + zfcp_get_busid_by_adapter(adapter)); + break; + } + debug_text_event(adapter->erp_dbf, 6, "a_fstx_xok"); + ZFCP_LOG_DEBUG("Xchange underway\n"); + + /* + * Why this works: + * Both the normal completion handler as well as the timeout + * handler will do an 'up' when the 'exchange port data' + * request completes or times out. Thus, the signal to go on + * won't be lost utilizing this semaphore. + * Furthermore, this 'adapter_reopen' action is + * guaranteed to be the only action being there (highest action + * which prevents other actions from being created). + * Resulting from that, the wake signal recognized here + * _must_ be the one belonging to the 'exchange port + * data' request. + */ + down(&adapter->erp_ready_sem); + if (erp_action->status & ZFCP_STATUS_ERP_TIMEDOUT) { + ZFCP_LOG_INFO("error: exchange of port data " + "for adapter %s timed out\n", + zfcp_get_busid_by_adapter(adapter)); + break; + } + + if (!atomic_test_mask(ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED, + &adapter->status)) + break; + + ZFCP_LOG_DEBUG("host connection still initialising... " + "waiting and retrying...\n"); + /* sleep a little bit before retry */ + sleep = retries < ZFCP_EXCHANGE_PORT_DATA_SHORT_RETRIES ? + ZFCP_EXCHANGE_PORT_DATA_SHORT_SLEEP : + ZFCP_EXCHANGE_PORT_DATA_LONG_SLEEP; + msleep(jiffies_to_msecs(sleep)); + } + + if (atomic_test_mask(ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED, + &adapter->status)) { + ZFCP_LOG_INFO("error: exchange of port data for " + "adapter %s failed\n", + zfcp_get_busid_by_adapter(adapter)); + retval = ZFCP_ERP_FAILED; + } + + return retval; +} + /* * function: * @@ -3194,11 +3272,19 @@ zfcp_erp_action_enqueue(int action, /* fall through !!! */ case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: - if (atomic_test_mask - (ZFCP_STATUS_COMMON_ERP_INUSE, &port->status) - && port->erp_action.action == - ZFCP_ERP_ACTION_REOPEN_PORT_FORCED) { - debug_text_event(adapter->erp_dbf, 4, "pf_actenq_drp"); + if (atomic_test_mask(ZFCP_STATUS_COMMON_ERP_INUSE, + &port->status)) { + if (port->erp_action.action != + ZFCP_ERP_ACTION_REOPEN_PORT_FORCED) { + ZFCP_LOG_INFO("dropped erp action %i (port " + "0x%016Lx, action in use: %i)\n", + action, port->wwpn, + port->erp_action.action); + debug_text_event(adapter->erp_dbf, 4, + "pf_actenq_drp"); + } else + debug_text_event(adapter->erp_dbf, 4, + "pf_actenq_drpcp"); debug_event(adapter->erp_dbf, 4, &port->wwpn, sizeof (wwn_t)); goto out; @@ -3589,6 +3675,9 @@ zfcp_erp_adapter_access_changed(struct zfcp_adapter *adapter) struct zfcp_port *port; unsigned long flags; + if (adapter->connection_features & FSF_FEATURE_NPIV_MODE) + return; + debug_text_event(adapter->erp_dbf, 3, "a_access_recover"); debug_event(adapter->erp_dbf, 3, &adapter->name, 8); |