From 3734d24b2e8d85796de70c13705cfb7cbb1d77df Mon Sep 17 00:00:00 2001 From: Andreas Herrmann Date: Tue, 13 Sep 2005 21:47:11 +0200 Subject: [SCSI] zfcp: fix race conditions when accessing erp_action lists o always use locking when changing erp_action lists, o avoid escalation to ERP_ACTION_REOPEN_PORT_FORCED if erp_action is still in use for ERP_ACTION_REOPEN_PORT Signed-off-by: Andreas Herrmann Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_erp.c | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) (limited to 'drivers/s390/scsi/zfcp_erp.c') diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c index cb4f612550b..376cb0f6cb7 100644 --- a/drivers/s390/scsi/zfcp_erp.c +++ b/drivers/s390/scsi/zfcp_erp.c @@ -886,7 +886,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 +896,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, @@ -2291,7 +2291,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; @@ -3194,11 +3196,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; -- cgit v1.2.3 From aef4a983090fa590481a86d9690dc3fa6bb121fa Mon Sep 17 00:00:00 2001 From: Maxim Shchetynin Date: Tue, 13 Sep 2005 21:51:16 +0200 Subject: [SCSI] zfcp: provide support for NPIV N_Port ID Virtualization (NPIV) allows a single FCP port to appear as multiple, distinct ports providing separate port identification. NPIV is supported by FC HBAs on System z9. zfcp was adapted to support this new feature. Signed-off-by: Andreas Herrmann Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_erp.c | 95 ++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 87 insertions(+), 8 deletions(-) (limited to 'drivers/s390/scsi/zfcp_erp.c') diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c index 376cb0f6cb7..c4a6799aed4 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 *); @@ -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); } /* @@ -2350,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: * @@ -3599,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); -- cgit v1.2.3 From 13e1e1f08c1c098c7574c1fa72bd8c67792dc89b Mon Sep 17 00:00:00 2001 From: Andreas Herrmann Date: Mon, 19 Sep 2005 16:56:17 +0200 Subject: [SCSI] zfcp: add additional fc_host attributes this patch adds some fc host attributes and removes its equivalents from the zfcp_adapter structure and zfcp specific sysfs subtree. Furthermore it removes superfluous calls to fc_remort_port_delete when an adapter is set offline because rports will be removed by fc_remove_host anyway. Signed-off-by: Andreas Herrmann Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_erp.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers/s390/scsi/zfcp_erp.c') diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c index c4a6799aed4..023f4e558ae 100644 --- a/drivers/s390/scsi/zfcp_erp.c +++ b/drivers/s390/scsi/zfcp_erp.c @@ -346,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); @@ -405,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; @@ -436,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) -- cgit v1.2.3