scsi: zfcp: fix fc_host attributes that should be unknown on local link down
When we get an unsolicited notification on local link went down,
zfcp_fsf_status_read_link_down() calls zfcp_fsf_link_down_info_eval().
This only blocks rports, and sets ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED and
ZFCP_STATUS_COMMON_ERP_FAILED. Only the fc_host port_state changes to
"Linkdown", because zfcp_scsi_get_host_port_state() is an active callback
and uses the adapter status.
Other fc_host attributes model, port_id, port_type, speed, fabric_name (and
zfcp device attributes card_version, peer_wwpn, peer_wwnn, peer_d_id) which
depend on a local link, continued to show their last known "good" value.
Only if something triggered an exchange config data, some values were
updated to their unknown equivalent via case
FSF_EXCHANGE_CONFIG_DATA_INCOMPLETE due to local link down. Triggers for
exchange config data are adapter recovery, or reading any of the following
zfcp-specific scsi host sysfs attributes "requests", "megabytes", or
"seconds_active" in /sys/devices/css*/*.*.*/*.*.*/host*/scsi_host/host*/.
The other fc_host attributes active_fc4s and permanent_port_name continued
to show their last known "good" value. Only if something triggered an
exchange port data, some values changed. Active_fc4s became all zeros as
unknown equivalent during link down. Permanent_port_name does not depend
on a local link. But for non-NPIV FCP devices, permanent_port_name
erroneously became whatever value fc_host port_name had at that point in
time (see previous paragraph). Triggers for exchange port data are the
zfcp-specific scsi host sysfs attribute "utilization", or
[{reset,get}_fc_host_stats] write anything into "reset_statistics" or read
any of the other attributes under
/sys/devices/css*/*.*.*/*.*.*/host*/fc_host/host*/statistics/.
(cf. v4.9 commit bd77befa5b
("zfcp: fix fc_host port_type with NPIV"))
This is particularly confusing when using "lszfcp -b <fcpdevbusid> -Ha" or
dbginfo.sh which read fc_host attributes and also scsi_host attributes.
After link down, the first invocation produces (abbreviated):
Class = "fc_host"
active_fc4s = "0x00 0x00 0x01 0x00 ..."
...
fabric_name = "0x10000027f8e04c49"
...
permanent_port_name = "0xc05076e4588059c1"
port_id = "0x244800"
port_state = "Linkdown"
port_type = "NPort (fabric via point-to-point)"
...
speed = "16 Gbit"
Class = "scsi_host"
...
megabytes = "0 0"
...
requests = "0 0 0"
seconds_active = "37"
...
utilization = "0 0 0"
The second and next invocations produce (abbreviated):
Class = "fc_host"
active_fc4s = "0x00 0x00 0x00 0x00 ..."
...
fabric_name = "0x0"
...
permanent_port_name = "0x0"
port_id = "0x000000"
port_state = "Linkdown"
port_type = "Unknown"
...
speed = "unknown"
Class = "scsi_host"
...
megabytes = "0 0"
...
requests = "0 0 0"
seconds_active = "38"
...
utilization = "0 0 0"
Factor out the resetting of local link dependent fc_host attributes from
zfcp_fsf_exchange_config_data_handler() case
FSF_EXCHANGE_CONFIG_DATA_INCOMPLETE into a new helper function
zfcp_fsf_fc_host_link_down(). All code places that detect local link down
(SRB, FSF_PROT_LINK_DOWN, xconf data/port incomplete) call
zfcp_fsf_link_down_info_eval(). Call the new helper from there. This works
because zfcp_fsf_link_down_info_eval() and thus the helper is called before
zfcp_fsf_exchange_{config,port}_evaluate().
Port_name and node_name are always valid, so never reset them.
Get the permanent_port_name from exchange port data unconditionally as it
always has a valid known good value, even during link down.
Note: Rather than hardcode in zfcp_fsf_exchange_config_evaluate(), fc_host
supported_classes could theoretically get its value from
fsf_qtcb_bottom_port.class_of_service in zfcp_fsf_exchange_port_evaluate().
When the link comes back, we get a different notification, perform adapter
recovery, and this triggers an implicit exchange config data followed by
exchange port data filling in the link dependent fc_host attributes with
known good values again.
Link: https://lore.kernel.org/r/20200312174505.51294-5-maier@linux.ibm.com
Reviewed-by: Jens Remus <jremus@linux.ibm.com>
Reviewed-by: Benjamin Block <bblock@linux.ibm.com>
Signed-off-by: Steffen Maier <maier@linux.ibm.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
This commit is contained in:
Родитель
538c6e910b
Коммит
7e0e4e0958
|
@ -120,6 +120,23 @@ static void zfcp_fsf_status_read_port_closed(struct zfcp_fsf_req *req)
|
|||
read_unlock_irqrestore(&adapter->port_list_lock, flags);
|
||||
}
|
||||
|
||||
static void zfcp_fsf_fc_host_link_down(struct zfcp_adapter *adapter)
|
||||
{
|
||||
struct Scsi_Host *shost = adapter->scsi_host;
|
||||
|
||||
fc_host_port_id(shost) = 0;
|
||||
fc_host_fabric_name(shost) = 0;
|
||||
fc_host_speed(shost) = FC_PORTSPEED_UNKNOWN;
|
||||
fc_host_port_type(shost) = FC_PORTTYPE_UNKNOWN;
|
||||
adapter->hydra_version = 0;
|
||||
snprintf(fc_host_model(shost), FC_SYMBOLIC_NAME_SIZE, "0x%04x", 0);
|
||||
memset(fc_host_active_fc4s(shost), 0, FC_FC4_LIST_SIZE);
|
||||
|
||||
adapter->peer_wwpn = 0;
|
||||
adapter->peer_wwnn = 0;
|
||||
adapter->peer_d_id = 0;
|
||||
}
|
||||
|
||||
static void zfcp_fsf_link_down_info_eval(struct zfcp_fsf_req *req,
|
||||
struct fsf_link_down_info *link_down)
|
||||
{
|
||||
|
@ -132,6 +149,8 @@ static void zfcp_fsf_link_down_info_eval(struct zfcp_fsf_req *req,
|
|||
|
||||
zfcp_scsi_schedule_rports_block(adapter);
|
||||
|
||||
zfcp_fsf_fc_host_link_down(adapter);
|
||||
|
||||
if (!link_down)
|
||||
goto out;
|
||||
|
||||
|
@ -512,9 +531,6 @@ static int zfcp_fsf_exchange_config_evaluate(struct zfcp_fsf_req *req)
|
|||
adapter->stat_read_buf_num = max(bottom->status_read_buf_num,
|
||||
(u16)FSF_STATUS_READS_RECOM);
|
||||
|
||||
if (fc_host_permanent_port_name(shost) == -1)
|
||||
fc_host_permanent_port_name(shost) = fc_host_port_name(shost);
|
||||
|
||||
zfcp_scsi_set_prot(adapter);
|
||||
|
||||
/* no error return above here, otherwise must fix call chains */
|
||||
|
@ -608,16 +624,6 @@ static void zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *req)
|
|||
zfcp_diag_update_xdata(diag_hdr, bottom, true);
|
||||
req->status |= ZFCP_STATUS_FSFREQ_XDATAINCOMPLETE;
|
||||
|
||||
fc_host_node_name(shost) = 0;
|
||||
fc_host_port_name(shost) = 0;
|
||||
fc_host_port_id(shost) = 0;
|
||||
fc_host_fabric_name(shost) = 0;
|
||||
fc_host_speed(shost) = FC_PORTSPEED_UNKNOWN;
|
||||
fc_host_port_type(shost) = FC_PORTTYPE_UNKNOWN;
|
||||
adapter->hydra_version = 0;
|
||||
snprintf(fc_host_model(shost), FC_SYMBOLIC_NAME_SIZE, "0x%04x",
|
||||
0);
|
||||
|
||||
/* avoids adapter shutdown to be able to recognize
|
||||
* events such as LINK UP */
|
||||
atomic_or(ZFCP_STATUS_ADAPTER_XCONFIG_OK,
|
||||
|
@ -667,10 +673,7 @@ static void zfcp_fsf_exchange_port_evaluate(struct zfcp_fsf_req *req)
|
|||
if (req->data)
|
||||
memcpy(req->data, bottom, sizeof(*bottom));
|
||||
|
||||
if (adapter->connection_features & FSF_FEATURE_NPIV_MODE) {
|
||||
fc_host_permanent_port_name(shost) = bottom->wwpn;
|
||||
} else
|
||||
fc_host_permanent_port_name(shost) = fc_host_port_name(shost);
|
||||
fc_host_permanent_port_name(shost) = bottom->wwpn;
|
||||
fc_host_maxframe_size(shost) = bottom->maximum_frame_size;
|
||||
fc_host_supported_speeds(shost) =
|
||||
zfcp_fsf_convert_portspeed(bottom->supported_speed);
|
||||
|
@ -704,9 +707,9 @@ static void zfcp_fsf_exchange_port_data_handler(struct zfcp_fsf_req *req)
|
|||
zfcp_diag_update_xdata(diag_hdr, bottom, true);
|
||||
req->status |= ZFCP_STATUS_FSFREQ_XDATAINCOMPLETE;
|
||||
|
||||
zfcp_fsf_exchange_port_evaluate(req);
|
||||
zfcp_fsf_link_down_info_eval(req,
|
||||
&qtcb->header.fsf_status_qual.link_down_info);
|
||||
zfcp_fsf_exchange_port_evaluate(req);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче