diff options
Diffstat (limited to 'drivers/s390/scsi/zfcp_fsf.c')
| -rw-r--r-- | drivers/s390/scsi/zfcp_fsf.c | 561 |
1 files changed, 451 insertions, 110 deletions
diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index d94496ee6883..9418086368c3 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c @@ -4,13 +4,14 @@ * * Implementation of FSF commands. * - * Copyright IBM Corp. 2002, 2018 + * Copyright IBM Corp. 2002, 2023 */ -#define KMSG_COMPONENT "zfcp" -#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt +#define pr_fmt(fmt) "zfcp: " fmt #include <linux/blktrace_api.h> +#include <linux/jiffies.h> +#include <linux/types.h> #include <linux/slab.h> #include <scsi/fc/fc_els.h> #include "zfcp_ext.h" @@ -18,6 +19,7 @@ #include "zfcp_dbf.h" #include "zfcp_qdio.h" #include "zfcp_reqlist.h" +#include "zfcp_diag.h" /* timeout for FSF requests sent during scsi_eh: abort or FCP TMF */ #define ZFCP_FSF_SCSI_ER_TIMEOUT (10*HZ) @@ -26,9 +28,14 @@ struct kmem_cache *zfcp_fsf_qtcb_cache; +static bool ber_stop = true; +module_param(ber_stop, bool, 0600); +MODULE_PARM_DESC(ber_stop, + "Shuts down FCP devices for FCP channels that report a bit-error count in excess of its threshold (default on)"); + static void zfcp_fsf_request_timeout_handler(struct timer_list *t) { - struct zfcp_fsf_req *fsf_req = from_timer(fsf_req, t, timer); + struct zfcp_fsf_req *fsf_req = timer_container_of(fsf_req, t, timer); struct zfcp_adapter *adapter = fsf_req->adapter; zfcp_qdio_siosl(adapter); @@ -112,6 +119,27 @@ static void zfcp_fsf_status_read_port_closed(struct zfcp_fsf_req *req) read_unlock_irqrestore(&adapter->port_list_lock, flags); } +void zfcp_fsf_fc_host_link_down(struct zfcp_adapter *adapter) +{ + struct Scsi_Host *shost = adapter->scsi_host; + + adapter->hydra_version = 0; + adapter->peer_wwpn = 0; + adapter->peer_wwnn = 0; + adapter->peer_d_id = 0; + + /* if there is no shost yet, we have nothing to zero-out */ + if (shost == NULL) + return; + + 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; + snprintf(fc_host_model(shost), FC_SYMBOLIC_NAME_SIZE, "0x%04x", 0); + memset(fc_host_active_fc4s(shost), 0, FC_FC4_LIST_SIZE); +} + static void zfcp_fsf_link_down_info_eval(struct zfcp_fsf_req *req, struct fsf_link_down_info *link_down) { @@ -124,6 +152,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; @@ -211,6 +241,19 @@ static void zfcp_fsf_status_read_link_down(struct zfcp_fsf_req *req) } } +static void +zfcp_fsf_status_read_version_change(struct zfcp_adapter *adapter, + struct fsf_status_read_buffer *sr_buf) +{ + if (sr_buf->status_subtype == FSF_STATUS_READ_SUB_LIC_CHANGE) { + u32 version = sr_buf->payload.version_change.current_version; + + WRITE_ONCE(adapter->fsf_lic_version, version); + snprintf(fc_host_firmware_version(adapter->scsi_host), + FC_VERSION_STRING_SIZE, "%#08x", version); + } +} + static void zfcp_fsf_status_read_handler(struct zfcp_fsf_req *req) { struct zfcp_adapter *adapter = req->adapter; @@ -235,10 +278,15 @@ static void zfcp_fsf_status_read_handler(struct zfcp_fsf_req *req) case FSF_STATUS_READ_SENSE_DATA_AVAIL: break; case FSF_STATUS_READ_BIT_ERROR_THRESHOLD: - dev_warn(&adapter->ccw_device->dev, - "The error threshold for checksum statistics " - "has been exceeded\n"); zfcp_dbf_hba_bit_err("fssrh_3", req); + if (ber_stop) { + dev_warn(&adapter->ccw_device->dev, + "All paths over this FCP device are disused because of excessive bit errors\n"); + zfcp_erp_adapter_shutdown(adapter, 0, "fssrh_b"); + } else { + dev_warn(&adapter->ccw_device->dev, + "The error threshold for checksum statistics has been exceeded\n"); + } break; case FSF_STATUS_READ_LINK_DOWN: zfcp_fsf_status_read_link_down(req); @@ -260,10 +308,16 @@ static void zfcp_fsf_status_read_handler(struct zfcp_fsf_req *req) case FSF_STATUS_READ_NOTIFICATION_LOST: if (sr_buf->status_subtype & FSF_STATUS_READ_SUB_INCOMING_ELS) zfcp_fc_conditional_port_scan(adapter); + if (sr_buf->status_subtype & FSF_STATUS_READ_SUB_VERSION_CHANGE) + queue_work(adapter->work_queue, + &adapter->version_change_lost_work); break; case FSF_STATUS_READ_FEATURE_UPDATE_ALERT: adapter->adapter_features = sr_buf->payload.word[0]; break; + case FSF_STATUS_READ_VERSION_CHANGE: + zfcp_fsf_status_read_version_change(adapter, sr_buf); + break; } mempool_free(virt_to_page(sr_buf), adapter->pool.sr_data); @@ -390,21 +444,27 @@ static void zfcp_fsf_protstatus_eval(struct zfcp_fsf_req *req) * or it has been dismissed due to a queue shutdown, this function * is called to process the completion status and trigger further * events related to the FSF request. + * Caller must ensure that the request has been removed from + * adapter->req_list, to protect against concurrent modification + * by zfcp_erp_strategy_check_fsfreq(). */ static void zfcp_fsf_req_complete(struct zfcp_fsf_req *req) { + struct zfcp_erp_action *erp_action; + if (unlikely(zfcp_fsf_req_is_status_read_buffer(req))) { zfcp_fsf_status_read_handler(req); return; } - del_timer(&req->timer); + timer_delete_sync(&req->timer); zfcp_fsf_protstatus_eval(req); zfcp_fsf_fsfstatus_eval(req); req->handler(req); - if (req->erp_action) - zfcp_erp_notify(req->erp_action, 0); + erp_action = req->erp_action; + if (erp_action) + zfcp_erp_notify(erp_action, 0); if (likely(req->status & ZFCP_STATUS_FSFREQ_CLEANUP)) zfcp_fsf_req_free(req); @@ -447,7 +507,7 @@ void zfcp_fsf_req_dismiss_all(struct zfcp_adapter *adapter) #define ZFCP_FSF_PORTSPEED_128GBIT (1 << 8) #define ZFCP_FSF_PORTSPEED_NOT_NEGOTIATED (1 << 15) -static u32 zfcp_fsf_convert_portspeed(u32 fsf_speed) +u32 zfcp_fsf_convert_portspeed(u32 fsf_speed) { u32 fdmi_speed = 0; if (fsf_speed & ZFCP_FSF_PORTSPEED_1GBIT) @@ -477,40 +537,24 @@ static int zfcp_fsf_exchange_config_evaluate(struct zfcp_fsf_req *req) { struct fsf_qtcb_bottom_config *bottom = &req->qtcb->bottom.config; struct zfcp_adapter *adapter = req->adapter; - struct Scsi_Host *shost = adapter->scsi_host; - struct fc_els_flogi *nsp, *plogi; + struct fc_els_flogi *plogi; /* adjust pointers for missing command code */ - nsp = (struct fc_els_flogi *) ((u8 *)&bottom->nport_serv_param - - sizeof(u32)); plogi = (struct fc_els_flogi *) ((u8 *)&bottom->plogi_payload - sizeof(u32)); if (req->data) memcpy(req->data, bottom, sizeof(*bottom)); - fc_host_port_name(shost) = be64_to_cpu(nsp->fl_wwpn); - fc_host_node_name(shost) = be64_to_cpu(nsp->fl_wwnn); - fc_host_supported_classes(shost) = FC_COS_CLASS2 | FC_COS_CLASS3; - adapter->timer_ticks = bottom->timer_interval & ZFCP_FSF_TIMER_INT_MASK; 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 */ /* do not evaluate invalid fields */ if (req->qtcb->header.fsf_status == FSF_EXCHANGE_CONFIG_DATA_INCOMPLETE) return 0; - fc_host_port_id(shost) = ntoh24(bottom->s_id); - fc_host_speed(shost) = - zfcp_fsf_convert_portspeed(bottom->fc_link_speed); - adapter->hydra_version = bottom->adapter_type; switch (bottom->fc_topology) { @@ -518,17 +562,10 @@ static int zfcp_fsf_exchange_config_evaluate(struct zfcp_fsf_req *req) adapter->peer_d_id = ntoh24(bottom->peer_d_id); adapter->peer_wwpn = be64_to_cpu(plogi->fl_wwpn); adapter->peer_wwnn = be64_to_cpu(plogi->fl_wwnn); - fc_host_port_type(shost) = FC_PORTTYPE_PTP; break; case FSF_TOPO_FABRIC: - if (bottom->connection_features & FSF_FEATURE_NPIV_MODE) - fc_host_port_type(shost) = FC_PORTTYPE_NPIV; - else - fc_host_port_type(shost) = FC_PORTTYPE_NPORT; break; case FSF_TOPO_AL: - fc_host_port_type(shost) = FC_PORTTYPE_NLPORT; - /* fall through */ default: dev_err(&adapter->ccw_device->dev, "Unknown or unsupported arbitrated loop " @@ -543,9 +580,10 @@ static int zfcp_fsf_exchange_config_evaluate(struct zfcp_fsf_req *req) static void zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *req) { struct zfcp_adapter *adapter = req->adapter; + struct zfcp_diag_header *const diag_hdr = + &adapter->diagnostics->config_data.header; struct fsf_qtcb *qtcb = req->qtcb; struct fsf_qtcb_bottom_config *bottom = &qtcb->bottom.config; - struct Scsi_Host *shost = adapter->scsi_host; if (req->status & ZFCP_STATUS_FSFREQ_ERROR) return; @@ -559,6 +597,13 @@ static void zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *req) switch (qtcb->header.fsf_status) { case FSF_GOOD: + /* + * usually we wait with an update till the cache is too old, + * but because we have the data available, update it anyway + */ + zfcp_diag_update_xdata(diag_hdr, bottom, false); + + zfcp_scsi_shost_update_config_data(adapter, bottom, false); if (zfcp_fsf_exchange_config_evaluate(req)) return; @@ -574,12 +619,8 @@ static void zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *req) &adapter->status); break; case FSF_EXCHANGE_CONFIG_DATA_INCOMPLETE: - fc_host_node_name(shost) = 0; - fc_host_port_name(shost) = 0; - fc_host_port_id(shost) = 0; - fc_host_speed(shost) = FC_PORTSPEED_UNKNOWN; - fc_host_port_type(shost) = FC_PORTTYPE_UNKNOWN; - adapter->hydra_version = 0; + zfcp_diag_update_xdata(diag_hdr, bottom, true); + req->status |= ZFCP_STATUS_FSFREQ_XDATAINCOMPLETE; /* avoids adapter shutdown to be able to recognize * events such as LINK UP */ @@ -587,6 +628,8 @@ static void zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *req) &adapter->status); zfcp_fsf_link_down_info_eval(req, &qtcb->header.fsf_status_qual.link_down_info); + + zfcp_scsi_shost_update_config_data(adapter, bottom, true); if (zfcp_fsf_exchange_config_evaluate(req)) return; break; @@ -595,13 +638,8 @@ static void zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *req) return; } - if (adapter->adapter_features & FSF_FEATURE_HBAAPI_MANAGEMENT) { + if (adapter->adapter_features & FSF_FEATURE_HBAAPI_MANAGEMENT) adapter->hardware_version = bottom->hardware_version; - memcpy(fc_host_serial_number(shost), bottom->serial_number, - min(FC_SERIAL_NUMBER_SIZE, 17)); - EBCASC(fc_host_serial_number(shost), - min(FC_SERIAL_NUMBER_SIZE, 17)); - } if (FSF_QTCB_CURRENT_VERSION < bottom->low_qtcb_version) { dev_err(&adapter->ccw_device->dev, @@ -618,43 +656,145 @@ static void zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *req) } } +/* + * Mapping of FC Endpoint Security flag masks to mnemonics + * + * NOTE: Update macro ZFCP_FSF_MAX_FC_SECURITY_MNEMONIC_LENGTH when making any + * changes. + */ +static const struct { + u32 mask; + char *name; +} zfcp_fsf_fc_security_mnemonics[] = { + { FSF_FC_SECURITY_AUTH, "Authentication" }, + { FSF_FC_SECURITY_ENC_FCSP2 | + FSF_FC_SECURITY_ENC_ERAS, "Encryption" }, +}; + +/* maximum strlen(zfcp_fsf_fc_security_mnemonics[...].name) + 1 */ +#define ZFCP_FSF_MAX_FC_SECURITY_MNEMONIC_LENGTH 15 + +/** + * zfcp_fsf_scnprint_fc_security() - translate FC Endpoint Security flags into + * mnemonics and place in a buffer + * @buf : the buffer to place the translated FC Endpoint Security flag(s) + * into + * @size : the size of the buffer, including the trailing null space + * @fc_security: one or more FC Endpoint Security flags, or zero + * @fmt : specifies whether a list or a single item is to be put into the + * buffer + * + * The Fibre Channel (FC) Endpoint Security flags are translated into mnemonics. + * If the FC Endpoint Security flags are zero "none" is placed into the buffer. + * + * With ZFCP_FSF_PRINT_FMT_LIST the mnemonics are placed as a list separated by + * a comma followed by a space into the buffer. If one or more FC Endpoint + * Security flags cannot be translated into a mnemonic, as they are undefined + * in zfcp_fsf_fc_security_mnemonics, their bitwise ORed value in hexadecimal + * representation is placed into the buffer. + * + * With ZFCP_FSF_PRINT_FMT_SINGLEITEM only one single mnemonic is placed into + * the buffer. If the FC Endpoint Security flag cannot be translated, as it is + * undefined in zfcp_fsf_fc_security_mnemonics, its value in hexadecimal + * representation is placed into the buffer. If more than one FC Endpoint + * Security flag was specified, their value in hexadecimal representation is + * placed into the buffer. The macro ZFCP_FSF_MAX_FC_SECURITY_MNEMONIC_LENGTH + * can be used to define a buffer that is large enough to hold one mnemonic. + * + * Return: The number of characters written into buf not including the trailing + * '\0'. If size is == 0 the function returns 0. + */ +ssize_t zfcp_fsf_scnprint_fc_security(char *buf, size_t size, u32 fc_security, + enum zfcp_fsf_print_fmt fmt) +{ + const char *prefix = ""; + ssize_t len = 0; + int i; + + if (fc_security == 0) + return scnprintf(buf, size, "none"); + if (fmt == ZFCP_FSF_PRINT_FMT_SINGLEITEM && hweight32(fc_security) != 1) + return scnprintf(buf, size, "0x%08x", fc_security); + + for (i = 0; i < ARRAY_SIZE(zfcp_fsf_fc_security_mnemonics); i++) { + if (!(fc_security & zfcp_fsf_fc_security_mnemonics[i].mask)) + continue; + + len += scnprintf(buf + len, size - len, "%s%s", prefix, + zfcp_fsf_fc_security_mnemonics[i].name); + prefix = ", "; + fc_security &= ~zfcp_fsf_fc_security_mnemonics[i].mask; + } + + if (fc_security != 0) + len += scnprintf(buf + len, size - len, "%s0x%08x", + prefix, fc_security); + + return len; +} + +static void zfcp_fsf_dbf_adapter_fc_security(struct zfcp_adapter *adapter, + struct zfcp_fsf_req *req) +{ + if (adapter->fc_security_algorithms == + adapter->fc_security_algorithms_old) { + /* no change, no trace */ + return; + } + + zfcp_dbf_hba_fsf_fces("fsfcesa", req, ZFCP_DBF_INVALID_WWPN, + adapter->fc_security_algorithms_old, + adapter->fc_security_algorithms); + + adapter->fc_security_algorithms_old = adapter->fc_security_algorithms; +} + static void zfcp_fsf_exchange_port_evaluate(struct zfcp_fsf_req *req) { struct zfcp_adapter *adapter = req->adapter; struct fsf_qtcb_bottom_port *bottom = &req->qtcb->bottom.port; - struct Scsi_Host *shost = adapter->scsi_host; 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_maxframe_size(shost) = bottom->maximum_frame_size; - fc_host_supported_speeds(shost) = - zfcp_fsf_convert_portspeed(bottom->supported_speed); - memcpy(fc_host_supported_fc4s(shost), bottom->supported_fc4_types, - FC_FC4_LIST_SIZE); - memcpy(fc_host_active_fc4s(shost), bottom->active_fc4_types, - FC_FC4_LIST_SIZE); + if (adapter->adapter_features & FSF_FEATURE_FC_SECURITY) + adapter->fc_security_algorithms = + bottom->fc_security_algorithms; + else + adapter->fc_security_algorithms = 0; + zfcp_fsf_dbf_adapter_fc_security(adapter, req); } static void zfcp_fsf_exchange_port_data_handler(struct zfcp_fsf_req *req) { + struct zfcp_diag_header *const diag_hdr = + &req->adapter->diagnostics->port_data.header; struct fsf_qtcb *qtcb = req->qtcb; + struct fsf_qtcb_bottom_port *bottom = &qtcb->bottom.port; if (req->status & ZFCP_STATUS_FSFREQ_ERROR) return; switch (qtcb->header.fsf_status) { case FSF_GOOD: + /* + * usually we wait with an update till the cache is too old, + * but because we have the data available, update it anyway + */ + zfcp_diag_update_xdata(diag_hdr, bottom, false); + + zfcp_scsi_shost_update_port_data(req->adapter, bottom); zfcp_fsf_exchange_port_evaluate(req); break; case FSF_EXCHANGE_CONFIG_DATA_INCOMPLETE: - zfcp_fsf_exchange_port_evaluate(req); + zfcp_diag_update_xdata(diag_hdr, bottom, true); + req->status |= ZFCP_STATUS_FSFREQ_XDATAINCOMPLETE; + zfcp_fsf_link_down_info_eval(req, &qtcb->header.fsf_status_qual.link_down_info); + + zfcp_scsi_shost_update_port_data(req->adapter, bottom); + zfcp_fsf_exchange_port_evaluate(req); break; } } @@ -705,7 +845,6 @@ static struct zfcp_fsf_req *zfcp_fsf_req_create(struct zfcp_qdio *qdio, if (adapter->req_no == 0) adapter->req_no++; - INIT_LIST_HEAD(&req->list); timer_setup(&req->timer, NULL, 0); init_completion(&req->completion); @@ -741,24 +880,40 @@ static struct zfcp_fsf_req *zfcp_fsf_req_create(struct zfcp_qdio *qdio, static int zfcp_fsf_req_send(struct zfcp_fsf_req *req) { + const bool is_srb = zfcp_fsf_req_is_status_read_buffer(req); struct zfcp_adapter *adapter = req->adapter; struct zfcp_qdio *qdio = adapter->qdio; - int req_id = req->req_id; + u64 req_id = req->req_id; zfcp_reqlist_add(adapter->req_list, req); req->qdio_req.qdio_outb_usage = atomic_read(&qdio->req_q_free); req->issued = get_tod_clock(); if (zfcp_qdio_send(qdio, &req->qdio_req)) { - del_timer(&req->timer); + timer_delete_sync(&req->timer); + /* lookup request again, list might have changed */ - zfcp_reqlist_find_rm(adapter->req_list, req_id); + if (zfcp_reqlist_find_rm(adapter->req_list, req_id) == NULL) + zfcp_dbf_hba_fsf_reqid("fsrsrmf", 1, adapter, req_id); + zfcp_erp_adapter_reopen(adapter, 0, "fsrs__1"); return -EIO; } + /* + * NOTE: DO NOT TOUCH ASYNC req PAST THIS POINT. + * ONLY TOUCH SYNC req AGAIN ON req->completion. + * + * The request might complete and be freed concurrently at any point + * now. This is not protected by the QDIO-lock (req_q_lock). So any + * uncontrolled access after this might result in an use-after-free bug. + * Only if the request doesn't have ZFCP_STATUS_FSFREQ_CLEANUP set, and + * when it is completed via req->completion, is it safe to use req + * again. + */ + /* Don't increase for unsolicited status */ - if (!zfcp_fsf_req_is_status_read_buffer(req)) + if (!is_srb) adapter->fsf_req_seq_no++; adapter->req_no++; @@ -805,6 +960,7 @@ int zfcp_fsf_status_read(struct zfcp_qdio *qdio) retval = zfcp_fsf_req_send(req); if (retval) goto failed_req_send; + /* NOTE: DO NOT TOUCH req PAST THIS POINT! */ goto out; @@ -864,7 +1020,7 @@ static void zfcp_fsf_abort_fcp_command_handler(struct zfcp_fsf_req *req) switch (fsq->word[0]) { case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE: zfcp_fc_test_link(zfcp_sdev->port); - /* fall through */ + fallthrough; case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED: req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; @@ -888,7 +1044,7 @@ struct zfcp_fsf_req *zfcp_fsf_abort_fcp_cmnd(struct scsi_cmnd *scmnd) struct scsi_device *sdev = scmnd->device; struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); struct zfcp_qdio *qdio = zfcp_sdev->port->adapter->qdio; - unsigned long old_req_id = (unsigned long) scmnd->host_scribble; + u64 old_req_id = (u64) scmnd->host_scribble; spin_lock_irq(&qdio->req_q_lock); if (zfcp_qdio_sbal_get(qdio)) @@ -911,11 +1067,13 @@ struct zfcp_fsf_req *zfcp_fsf_abort_fcp_cmnd(struct scsi_cmnd *scmnd) req->handler = zfcp_fsf_abort_fcp_command_handler; req->qtcb->header.lun_handle = zfcp_sdev->lun_handle; req->qtcb->header.port_handle = zfcp_sdev->port->handle; - req->qtcb->bottom.support.req_handle = (u64) old_req_id; + req->qtcb->bottom.support.req_handle = old_req_id; zfcp_fsf_start_timer(req, ZFCP_FSF_SCSI_ER_TIMEOUT); - if (!zfcp_fsf_req_send(req)) + if (!zfcp_fsf_req_send(req)) { + /* NOTE: DO NOT TOUCH req, UNTIL IT COMPLETES! */ goto out; + } out_error_free: zfcp_fsf_req_free(req); @@ -957,7 +1115,7 @@ static void zfcp_fsf_send_ct_handler(struct zfcp_fsf_req *req) break; case FSF_PORT_HANDLE_NOT_VALID: zfcp_erp_adapter_reopen(adapter, 0, "fsscth1"); - /* fall through */ + fallthrough; case FSF_GENERIC_COMMAND_REJECTED: case FSF_PAYLOAD_SIZE_MISMATCH: case FSF_REQUEST_SIZE_TOO_LARGE: @@ -1059,7 +1217,7 @@ static int zfcp_fsf_setup_ct_els(struct zfcp_fsf_req *req, /** * zfcp_fsf_send_ct - initiate a Generic Service request (FC-GS) * @wka_port: pointer to zfcp WKA port to send CT/GS to - * @ct: pointer to struct zfcp_send_ct with data for request + * @ct: pointer to struct zfcp_fsf_ct_els with data for CT request * @pool: if non-null this mempool is used to allocate struct zfcp_fsf_req * @timeout: timeout that hardware should use, and a later software timeout */ @@ -1098,6 +1256,7 @@ int zfcp_fsf_send_ct(struct zfcp_fc_wka_port *wka_port, ret = zfcp_fsf_req_send(req); if (ret) goto failed_send; + /* NOTE: DO NOT TOUCH req PAST THIS POINT! */ goto out; @@ -1142,7 +1301,7 @@ static void zfcp_fsf_send_els_handler(struct zfcp_fsf_req *req) break; case FSF_SBAL_MISMATCH: /* should never occur, avoided in zfcp_fsf_send_els */ - /* fall through */ + fallthrough; default: req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; @@ -1156,7 +1315,7 @@ skip_fsfstatus: * zfcp_fsf_send_els - initiate an ELS command (FC-FS) * @adapter: pointer to zfcp adapter * @d_id: N_Port_ID to send ELS to - * @els: pointer to struct zfcp_send_els with data for the command + * @els: pointer to struct zfcp_fsf_ct_els with data for the ELS command * @timeout: timeout that hardware should use, and a later software timeout */ int zfcp_fsf_send_els(struct zfcp_adapter *adapter, u32 d_id, @@ -1198,6 +1357,7 @@ int zfcp_fsf_send_els(struct zfcp_adapter *adapter, u32 d_id, ret = zfcp_fsf_req_send(req); if (ret) goto failed_send; + /* NOTE: DO NOT TOUCH req PAST THIS POINT! */ goto out; @@ -1232,7 +1392,9 @@ int zfcp_fsf_exchange_config_data(struct zfcp_erp_action *erp_action) req->qtcb->bottom.config.feature_selection = FSF_FEATURE_NOTIFICATION_LOST | - FSF_FEATURE_UPDATE_ALERT; + FSF_FEATURE_UPDATE_ALERT | + FSF_FEATURE_REQUEST_SFP_DATA | + FSF_FEATURE_FC_SECURITY; req->erp_action = erp_action; req->handler = zfcp_fsf_exchange_config_data_handler; erp_action->fsf_req_id = req->req_id; @@ -1243,11 +1405,25 @@ int zfcp_fsf_exchange_config_data(struct zfcp_erp_action *erp_action) zfcp_fsf_req_free(req); erp_action->fsf_req_id = 0; } + /* NOTE: DO NOT TOUCH req PAST THIS POINT! */ out: spin_unlock_irq(&qdio->req_q_lock); return retval; } + +/** + * zfcp_fsf_exchange_config_data_sync() - Request information about FCP channel. + * @qdio: pointer to the QDIO-Queue to use for sending the command. + * @data: pointer to the QTCB-Bottom for storing the result of the command, + * might be %NULL. + * + * Returns: + * * 0 - Exchange Config Data was successful, @data is complete + * * -EIO - Exchange Config Data was not successful, @data is invalid + * * -EAGAIN - @data contains incomplete data + * * -ENOMEM - Some memory allocation failed along the way + */ int zfcp_fsf_exchange_config_data_sync(struct zfcp_qdio *qdio, struct fsf_qtcb_bottom_config *data) { @@ -1271,7 +1447,9 @@ int zfcp_fsf_exchange_config_data_sync(struct zfcp_qdio *qdio, req->qtcb->bottom.config.feature_selection = FSF_FEATURE_NOTIFICATION_LOST | - FSF_FEATURE_UPDATE_ALERT; + FSF_FEATURE_UPDATE_ALERT | + FSF_FEATURE_REQUEST_SFP_DATA | + FSF_FEATURE_FC_SECURITY; if (data) req->data = data; @@ -1279,9 +1457,18 @@ int zfcp_fsf_exchange_config_data_sync(struct zfcp_qdio *qdio, zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT); retval = zfcp_fsf_req_send(req); spin_unlock_irq(&qdio->req_q_lock); - if (!retval) + + if (!retval) { + /* NOTE: ONLY TOUCH SYNC req AGAIN ON req->completion. */ wait_for_completion(&req->completion); + if (req->status & + (ZFCP_STATUS_FSFREQ_ERROR | ZFCP_STATUS_FSFREQ_DISMISSED)) + retval = -EIO; + else if (req->status & ZFCP_STATUS_FSFREQ_XDATAINCOMPLETE) + retval = -EAGAIN; + } + zfcp_fsf_req_free(req); return retval; @@ -1330,16 +1517,24 @@ int zfcp_fsf_exchange_port_data(struct zfcp_erp_action *erp_action) zfcp_fsf_req_free(req); erp_action->fsf_req_id = 0; } + /* NOTE: DO NOT TOUCH req PAST THIS POINT! */ out: spin_unlock_irq(&qdio->req_q_lock); return retval; } /** - * zfcp_fsf_exchange_port_data_sync - request information about local port - * @qdio: pointer to struct zfcp_qdio - * @data: pointer to struct fsf_qtcb_bottom_port - * Returns: 0 on success, error otherwise + * zfcp_fsf_exchange_port_data_sync() - Request information about local port. + * @qdio: pointer to the QDIO-Queue to use for sending the command. + * @data: pointer to the QTCB-Bottom for storing the result of the command, + * might be %NULL. + * + * Returns: + * * 0 - Exchange Port Data was successful, @data is complete + * * -EIO - Exchange Port Data was not successful, @data is invalid + * * -EAGAIN - @data contains incomplete data + * * -ENOMEM - Some memory allocation failed along the way + * * -EOPNOTSUPP - This operation is not supported */ int zfcp_fsf_exchange_port_data_sync(struct zfcp_qdio *qdio, struct fsf_qtcb_bottom_port *data) @@ -1372,11 +1567,18 @@ int zfcp_fsf_exchange_port_data_sync(struct zfcp_qdio *qdio, retval = zfcp_fsf_req_send(req); spin_unlock_irq(&qdio->req_q_lock); - if (!retval) + if (!retval) { + /* NOTE: ONLY TOUCH SYNC req AGAIN ON req->completion. */ wait_for_completion(&req->completion); - zfcp_fsf_req_free(req); + if (req->status & + (ZFCP_STATUS_FSFREQ_ERROR | ZFCP_STATUS_FSFREQ_DISMISSED)) + retval = -EIO; + else if (req->status & ZFCP_STATUS_FSFREQ_XDATAINCOMPLETE) + retval = -EAGAIN; + } + zfcp_fsf_req_free(req); return retval; out_unlock: @@ -1384,10 +1586,117 @@ out_unlock: return retval; } +static void zfcp_fsf_log_port_fc_security(struct zfcp_port *port, + struct zfcp_fsf_req *req) +{ + char mnemonic_old[ZFCP_FSF_MAX_FC_SECURITY_MNEMONIC_LENGTH]; + char mnemonic_new[ZFCP_FSF_MAX_FC_SECURITY_MNEMONIC_LENGTH]; + + if (port->connection_info == port->connection_info_old) { + /* no change, no log nor trace */ + return; + } + + zfcp_dbf_hba_fsf_fces("fsfcesp", req, port->wwpn, + port->connection_info_old, + port->connection_info); + + zfcp_fsf_scnprint_fc_security(mnemonic_old, sizeof(mnemonic_old), + port->connection_info_old, + ZFCP_FSF_PRINT_FMT_SINGLEITEM); + zfcp_fsf_scnprint_fc_security(mnemonic_new, sizeof(mnemonic_new), + port->connection_info, + ZFCP_FSF_PRINT_FMT_SINGLEITEM); + + if (strncmp(mnemonic_old, mnemonic_new, + ZFCP_FSF_MAX_FC_SECURITY_MNEMONIC_LENGTH) == 0) { + /* no change in string representation, no log */ + goto out; + } + + if (port->connection_info_old == 0) { + /* activation */ + dev_info(&port->adapter->ccw_device->dev, + "FC Endpoint Security of connection to remote port 0x%16llx enabled: %s\n", + port->wwpn, mnemonic_new); + } else if (port->connection_info == 0) { + /* deactivation */ + dev_warn(&port->adapter->ccw_device->dev, + "FC Endpoint Security of connection to remote port 0x%16llx disabled: was %s\n", + port->wwpn, mnemonic_old); + } else { + /* change */ + dev_warn(&port->adapter->ccw_device->dev, + "FC Endpoint Security of connection to remote port 0x%16llx changed: from %s to %s\n", + port->wwpn, mnemonic_old, mnemonic_new); + } + +out: + port->connection_info_old = port->connection_info; +} + +static void zfcp_fsf_log_security_error(const struct device *dev, u32 fsf_sqw0, + u64 wwpn) +{ + switch (fsf_sqw0) { + + /* + * Open Port command error codes + */ + + case FSF_SQ_SECURITY_REQUIRED: + dev_warn_ratelimited(dev, + "FC Endpoint Security error: FC security is required but not supported or configured on remote port 0x%016llx\n", + wwpn); + break; + case FSF_SQ_SECURITY_TIMEOUT: + dev_warn_ratelimited(dev, + "FC Endpoint Security error: a timeout prevented opening remote port 0x%016llx\n", + wwpn); + break; + case FSF_SQ_SECURITY_KM_UNAVAILABLE: + dev_warn_ratelimited(dev, + "FC Endpoint Security error: opening remote port 0x%016llx failed because local and external key manager cannot communicate\n", + wwpn); + break; + case FSF_SQ_SECURITY_RKM_UNAVAILABLE: + dev_warn_ratelimited(dev, + "FC Endpoint Security error: opening remote port 0x%016llx failed because it cannot communicate with the external key manager\n", + wwpn); + break; + case FSF_SQ_SECURITY_AUTH_FAILURE: + dev_warn_ratelimited(dev, + "FC Endpoint Security error: the device could not verify the identity of remote port 0x%016llx\n", + wwpn); + break; + + /* + * Send FCP command error codes + */ + + case FSF_SQ_SECURITY_ENC_FAILURE: + dev_warn_ratelimited(dev, + "FC Endpoint Security error: FC connection to remote port 0x%016llx closed because encryption broke down\n", + wwpn); + break; + + /* + * Unknown error codes + */ + + default: + dev_warn_ratelimited(dev, + "FC Endpoint Security error: the device issued an unknown error code 0x%08x related to the FC connection to remote port 0x%016llx\n", + fsf_sqw0, wwpn); + } +} + static void zfcp_fsf_open_port_handler(struct zfcp_fsf_req *req) { + struct zfcp_adapter *adapter = req->adapter; struct zfcp_port *port = req->data; struct fsf_qtcb_header *header = &req->qtcb->header; + struct fsf_qtcb_bottom_support *bottom = &req->qtcb->bottom.support; struct fc_els_flogi *plogi; if (req->status & ZFCP_STATUS_FSFREQ_ERROR) @@ -1397,7 +1706,7 @@ static void zfcp_fsf_open_port_handler(struct zfcp_fsf_req *req) case FSF_PORT_ALREADY_OPEN: break; case FSF_MAXIMUM_NUMBER_OF_PORTS_EXCEEDED: - dev_warn(&req->adapter->ccw_device->dev, + dev_warn(&adapter->ccw_device->dev, "Not enough FCP adapter resources to open " "remote port 0x%016Lx\n", (unsigned long long)port->wwpn); @@ -1405,11 +1714,17 @@ static void zfcp_fsf_open_port_handler(struct zfcp_fsf_req *req) ZFCP_STATUS_COMMON_ERP_FAILED); req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; + case FSF_SECURITY_ERROR: + zfcp_fsf_log_security_error(&req->adapter->ccw_device->dev, + header->fsf_status_qual.word[0], + port->wwpn); + req->status |= ZFCP_STATUS_FSFREQ_ERROR; + break; case FSF_ADAPTER_STATUS_AVAILABLE: switch (header->fsf_status_qual.word[0]) { case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE: /* no zfcp_fc_test_link() with failed open port */ - /* fall through */ + fallthrough; case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED: case FSF_SQ_NO_RETRY_POSSIBLE: req->status |= ZFCP_STATUS_FSFREQ_ERROR; @@ -1418,6 +1733,11 @@ static void zfcp_fsf_open_port_handler(struct zfcp_fsf_req *req) break; case FSF_GOOD: port->handle = header->port_handle; + if (adapter->adapter_features & FSF_FEATURE_FC_SECURITY) + port->connection_info = bottom->connection_info; + else + port->connection_info = 0; + zfcp_fsf_log_port_fc_security(port, req); atomic_or(ZFCP_STATUS_COMMON_OPEN | ZFCP_STATUS_PORT_PHYS_OPEN, &port->status); atomic_andnot(ZFCP_STATUS_COMMON_ACCESS_BOXED, @@ -1437,10 +1757,9 @@ static void zfcp_fsf_open_port_handler(struct zfcp_fsf_req *req) * another GID_PN straight after a port has been opened. * Alternately, an ADISC/PDISC ELS should suffice, as well. */ - plogi = (struct fc_els_flogi *) req->qtcb->bottom.support.els; - if (req->qtcb->bottom.support.els1_length >= - FSF_PLOGI_MIN_LEN) - zfcp_fc_plogi_evaluate(port, plogi); + plogi = (struct fc_els_flogi *) bottom->els; + if (bottom->els1_length >= FSF_PLOGI_MIN_LEN) + zfcp_fc_plogi_evaluate(port, plogi); break; case FSF_UNKNOWN_OP_SUBTYPE: req->status |= ZFCP_STATUS_FSFREQ_ERROR; @@ -1493,6 +1812,7 @@ int zfcp_fsf_open_port(struct zfcp_erp_action *erp_action) erp_action->fsf_req_id = 0; put_device(&port->dev); } + /* NOTE: DO NOT TOUCH req PAST THIS POINT! */ out: spin_unlock_irq(&qdio->req_q_lock); return retval; @@ -1557,6 +1877,7 @@ int zfcp_fsf_close_port(struct zfcp_erp_action *erp_action) zfcp_fsf_req_free(req); erp_action->fsf_req_id = 0; } + /* NOTE: DO NOT TOUCH req PAST THIS POINT! */ out: spin_unlock_irq(&qdio->req_q_lock); return retval; @@ -1576,19 +1897,19 @@ static void zfcp_fsf_open_wka_port_handler(struct zfcp_fsf_req *req) case FSF_MAXIMUM_NUMBER_OF_PORTS_EXCEEDED: dev_warn(&req->adapter->ccw_device->dev, "Opening WKA port 0x%x failed\n", wka_port->d_id); - /* fall through */ + fallthrough; case FSF_ADAPTER_STATUS_AVAILABLE: req->status |= ZFCP_STATUS_FSFREQ_ERROR; wka_port->status = ZFCP_FC_WKA_PORT_OFFLINE; break; case FSF_GOOD: wka_port->handle = header->port_handle; - /* fall through */ + fallthrough; case FSF_PORT_ALREADY_OPEN: wka_port->status = ZFCP_FC_WKA_PORT_ONLINE; } out: - wake_up(&wka_port->completion_wq); + wake_up(&wka_port->opened); } /** @@ -1600,6 +1921,7 @@ int zfcp_fsf_open_wka_port(struct zfcp_fc_wka_port *wka_port) { struct zfcp_qdio *qdio = wka_port->adapter->qdio; struct zfcp_fsf_req *req; + u64 req_id = 0; int retval = -EIO; spin_lock_irq(&qdio->req_q_lock); @@ -1622,14 +1944,17 @@ int zfcp_fsf_open_wka_port(struct zfcp_fc_wka_port *wka_port) hton24(req->qtcb->bottom.support.d_id, wka_port->d_id); req->data = wka_port; + req_id = req->req_id; + zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT); retval = zfcp_fsf_req_send(req); if (retval) zfcp_fsf_req_free(req); + /* NOTE: DO NOT TOUCH req PAST THIS POINT! */ out: spin_unlock_irq(&qdio->req_q_lock); if (!retval) - zfcp_dbf_rec_run_wka("fsowp_1", wka_port, req->req_id); + zfcp_dbf_rec_run_wka("fsowp_1", wka_port, req_id); return retval; } @@ -1643,7 +1968,7 @@ static void zfcp_fsf_close_wka_port_handler(struct zfcp_fsf_req *req) } wka_port->status = ZFCP_FC_WKA_PORT_OFFLINE; - wake_up(&wka_port->completion_wq); + wake_up(&wka_port->closed); } /** @@ -1655,6 +1980,7 @@ int zfcp_fsf_close_wka_port(struct zfcp_fc_wka_port *wka_port) { struct zfcp_qdio *qdio = wka_port->adapter->qdio; struct zfcp_fsf_req *req; + u64 req_id = 0; int retval = -EIO; spin_lock_irq(&qdio->req_q_lock); @@ -1677,14 +2003,17 @@ int zfcp_fsf_close_wka_port(struct zfcp_fc_wka_port *wka_port) req->data = wka_port; req->qtcb->header.port_handle = wka_port->handle; + req_id = req->req_id; + zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT); retval = zfcp_fsf_req_send(req); if (retval) zfcp_fsf_req_free(req); + /* NOTE: DO NOT TOUCH req PAST THIS POINT! */ out: spin_unlock_irq(&qdio->req_q_lock); if (!retval) - zfcp_dbf_rec_run_wka("fscwp_1", wka_port, req->req_id); + zfcp_dbf_rec_run_wka("fscwp_1", wka_port, req_id); return retval; } @@ -1718,7 +2047,6 @@ static void zfcp_fsf_close_physical_port_handler(struct zfcp_fsf_req *req) case FSF_ADAPTER_STATUS_AVAILABLE: switch (header->fsf_status_qual.word[0]) { case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE: - /* fall through */ case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED: req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; @@ -1776,6 +2104,7 @@ int zfcp_fsf_close_physical_port(struct zfcp_erp_action *erp_action) zfcp_fsf_req_free(req); erp_action->fsf_req_id = 0; } + /* NOTE: DO NOT TOUCH req PAST THIS POINT! */ out: spin_unlock_irq(&qdio->req_q_lock); return retval; @@ -1802,7 +2131,7 @@ static void zfcp_fsf_open_lun_handler(struct zfcp_fsf_req *req) case FSF_PORT_HANDLE_NOT_VALID: zfcp_erp_adapter_reopen(adapter, 0, "fsouh_1"); - /* fall through */ + fallthrough; case FSF_LUN_ALREADY_OPEN: break; case FSF_PORT_BOXED: @@ -1833,7 +2162,7 @@ static void zfcp_fsf_open_lun_handler(struct zfcp_fsf_req *req) (unsigned long long)zfcp_scsi_dev_lun(sdev), (unsigned long long)zfcp_sdev->port->wwpn); zfcp_erp_set_lun_status(sdev, ZFCP_STATUS_COMMON_ERP_FAILED); - /* fall through */ + fallthrough; case FSF_INVALID_COMMAND_OPTION: req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; @@ -1841,7 +2170,7 @@ static void zfcp_fsf_open_lun_handler(struct zfcp_fsf_req *req) switch (header->fsf_status_qual.word[0]) { case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE: zfcp_fc_test_link(zfcp_sdev->port); - /* fall through */ + fallthrough; case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED: req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; @@ -1899,6 +2228,7 @@ int zfcp_fsf_open_lun(struct zfcp_erp_action *erp_action) zfcp_fsf_req_free(req); erp_action->fsf_req_id = 0; } + /* NOTE: DO NOT TOUCH req PAST THIS POINT! */ out: spin_unlock_irq(&qdio->req_q_lock); return retval; @@ -1934,7 +2264,7 @@ static void zfcp_fsf_close_lun_handler(struct zfcp_fsf_req *req) switch (req->qtcb->header.fsf_status_qual.word[0]) { case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE: zfcp_fc_test_link(zfcp_sdev->port); - /* fall through */ + fallthrough; case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED: req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; @@ -1947,7 +2277,7 @@ static void zfcp_fsf_close_lun_handler(struct zfcp_fsf_req *req) } /** - * zfcp_fsf_close_LUN - close LUN + * zfcp_fsf_close_lun - close LUN * @erp_action: pointer to erp_action triggering the "close LUN" * Returns: 0 on success, error otherwise */ @@ -1987,6 +2317,7 @@ int zfcp_fsf_close_lun(struct zfcp_erp_action *erp_action) zfcp_fsf_req_free(req); erp_action->fsf_req_id = 0; } + /* NOTE: DO NOT TOUCH req PAST THIS POINT! */ out: spin_unlock_irq(&qdio->req_q_lock); return retval; @@ -2048,8 +2379,7 @@ static void zfcp_fsf_req_trace(struct zfcp_fsf_req *req, struct scsi_cmnd *scsi) } } - blk_add_driver_data(scsi->request->q, scsi->request, &blktrc, - sizeof(blktrc)); + blk_add_driver_data(scsi_cmd_to_rq(scsi), &blktrc, sizeof(blktrc)); } /** @@ -2118,6 +2448,13 @@ static void zfcp_fsf_fcp_handler_common(struct zfcp_fsf_req *req, zfcp_fc_test_link(zfcp_sdev->port); req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; + case FSF_SECURITY_ERROR: + zfcp_fsf_log_security_error(&req->adapter->ccw_device->dev, + header->fsf_status_qual.word[0], + zfcp_sdev->port->wwpn); + zfcp_erp_port_forced_reopen(zfcp_sdev->port, 0, "fssfch7"); + req->status |= ZFCP_STATUS_FSFREQ_ERROR; + break; } } @@ -2166,7 +2503,7 @@ skip_fsfstatus: zfcp_dbf_scsi_result(scpnt, req); scpnt->host_scribble = NULL; - (scpnt->scsi_done) (scpnt); + scsi_done(scpnt); /* * We must hold this lock until scsi_done has been called. * Otherwise we may call scsi_done after abort regarding this @@ -2252,6 +2589,7 @@ int zfcp_fsf_fcp_cmnd(struct scsi_cmnd *scsi_cmnd) goto out; } + BUILD_BUG_ON(sizeof(scsi_cmnd->host_scribble) < sizeof(req->req_id)); scsi_cmnd->host_scribble = (unsigned char *) req->req_id; io = &req->qtcb->bottom.io; @@ -2264,8 +2602,8 @@ int zfcp_fsf_fcp_cmnd(struct scsi_cmnd *scsi_cmnd) io->fcp_cmnd_length = FCP_CMND_LEN; if (scsi_get_prot_op(scsi_cmnd) != SCSI_PROT_NORMAL) { - io->data_block_length = scsi_cmnd->device->sector_size; - io->ref_tag_value = scsi_get_lba(scsi_cmnd) & 0xFFFFFFFF; + io->data_block_length = scsi_prot_interval(scsi_cmnd); + io->ref_tag_value = scsi_prot_ref_tag(scsi_cmnd); } if (zfcp_fsf_set_data_dir(scsi_cmnd, &io->data_direction)) @@ -2299,6 +2637,7 @@ int zfcp_fsf_fcp_cmnd(struct scsi_cmnd *scsi_cmnd) retval = zfcp_fsf_req_send(req); if (unlikely(retval)) goto failed_scsi_cmnd; + /* NOTE: DO NOT TOUCH req PAST THIS POINT! */ goto out; @@ -2373,8 +2712,10 @@ struct zfcp_fsf_req *zfcp_fsf_fcp_task_mgmt(struct scsi_device *sdev, zfcp_fc_fcp_tm(fcp_cmnd, sdev, tm_flags); zfcp_fsf_start_timer(req, ZFCP_FSF_SCSI_ER_TIMEOUT); - if (!zfcp_fsf_req_send(req)) + if (!zfcp_fsf_req_send(req)) { + /* NOTE: DO NOT TOUCH req, UNTIL IT COMPLETES! */ goto out; + } zfcp_fsf_req_free(req); req = NULL; @@ -2394,13 +2735,13 @@ void zfcp_fsf_reqid_check(struct zfcp_qdio *qdio, int sbal_idx) struct qdio_buffer *sbal = qdio->res_q[sbal_idx]; struct qdio_buffer_element *sbale; struct zfcp_fsf_req *fsf_req; - unsigned long req_id; + u64 req_id; int idx; for (idx = 0; idx < QDIO_MAX_ELEMENTS_PER_BUFFER; idx++) { sbale = &sbal->element[idx]; - req_id = (unsigned long) sbale->addr; + req_id = dma64_to_u64(sbale->addr); fsf_req = zfcp_reqlist_find_rm(adapter->req_list, req_id); if (!fsf_req) { @@ -2409,7 +2750,7 @@ void zfcp_fsf_reqid_check(struct zfcp_qdio *qdio, int sbal_idx) * corruption and must stop the machine immediately. */ zfcp_qdio_siosl(adapter); - panic("error: unknown req_id (%lx) on adapter %s.\n", + panic("error: unknown req_id (%llx) on adapter %s.\n", req_id, dev_name(&adapter->ccw_device->dev)); } |
