diff options
Diffstat (limited to 'drivers/s390/scsi/zfcp_fsf.c')
| -rw-r--r-- | drivers/s390/scsi/zfcp_fsf.c | 82 |
1 files changed, 54 insertions, 28 deletions
diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index c795f22249d8..9418086368c3 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c @@ -4,11 +4,10 @@ * * Implementation of FSF commands. * - * Copyright IBM Corp. 2002, 2020 + * 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> @@ -36,7 +35,7 @@ MODULE_PARM_DESC(ber_stop, 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); @@ -242,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; @@ -296,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); @@ -426,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); @@ -821,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); @@ -860,16 +883,19 @@ 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; } @@ -1018,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)) @@ -1041,7 +1067,7 @@ 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)) { @@ -1191,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 */ @@ -1289,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, @@ -1883,7 +1909,7 @@ static void zfcp_fsf_open_wka_port_handler(struct zfcp_fsf_req *req) wka_port->status = ZFCP_FC_WKA_PORT_ONLINE; } out: - wake_up(&wka_port->completion_wq); + wake_up(&wka_port->opened); } /** @@ -1895,7 +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; - unsigned long req_id = 0; + u64 req_id = 0; int retval = -EIO; spin_lock_irq(&qdio->req_q_lock); @@ -1942,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); } /** @@ -1954,7 +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; - unsigned long req_id = 0; + u64 req_id = 0; int retval = -EIO; spin_lock_irq(&qdio->req_q_lock); @@ -2251,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 */ @@ -2353,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)); } /** @@ -2478,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 @@ -2564,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; @@ -2576,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)) @@ -2709,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 = sbale->addr; + req_id = dma64_to_u64(sbale->addr); fsf_req = zfcp_reqlist_find_rm(adapter->req_list, req_id); if (!fsf_req) { @@ -2724,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)); } |
