162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * zfcp device driver 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Interface to Linux SCSI midlayer. 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Copyright IBM Corp. 2002, 2020 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#define KMSG_COMPONENT "zfcp" 1162306a36Sopenharmony_ci#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include <linux/module.h> 1462306a36Sopenharmony_ci#include <linux/types.h> 1562306a36Sopenharmony_ci#include <linux/slab.h> 1662306a36Sopenharmony_ci#include <scsi/fc/fc_fcp.h> 1762306a36Sopenharmony_ci#include <scsi/scsi_eh.h> 1862306a36Sopenharmony_ci#include <linux/atomic.h> 1962306a36Sopenharmony_ci#include "zfcp_ext.h" 2062306a36Sopenharmony_ci#include "zfcp_dbf.h" 2162306a36Sopenharmony_ci#include "zfcp_fc.h" 2262306a36Sopenharmony_ci#include "zfcp_reqlist.h" 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_cistatic unsigned int default_depth = 32; 2562306a36Sopenharmony_cimodule_param_named(queue_depth, default_depth, uint, 0600); 2662306a36Sopenharmony_ciMODULE_PARM_DESC(queue_depth, "Default queue depth for new SCSI devices"); 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_cistatic bool enable_dif; 2962306a36Sopenharmony_cimodule_param_named(dif, enable_dif, bool, 0400); 3062306a36Sopenharmony_ciMODULE_PARM_DESC(dif, "Enable DIF data integrity support (default off)"); 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_cibool zfcp_experimental_dix; 3362306a36Sopenharmony_cimodule_param_named(dix, zfcp_experimental_dix, bool, 0400); 3462306a36Sopenharmony_ciMODULE_PARM_DESC(dix, "Enable experimental DIX (data integrity extension) support which implies DIF support (default off)"); 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_cistatic bool allow_lun_scan = true; 3762306a36Sopenharmony_cimodule_param(allow_lun_scan, bool, 0600); 3862306a36Sopenharmony_ciMODULE_PARM_DESC(allow_lun_scan, "For NPIV, scan and attach all storage LUNs"); 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_cistatic void zfcp_scsi_slave_destroy(struct scsi_device *sdev) 4162306a36Sopenharmony_ci{ 4262306a36Sopenharmony_ci struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci /* if previous slave_alloc returned early, there is nothing to do */ 4562306a36Sopenharmony_ci if (!zfcp_sdev->port) 4662306a36Sopenharmony_ci return; 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci zfcp_erp_lun_shutdown_wait(sdev, "scssd_1"); 4962306a36Sopenharmony_ci put_device(&zfcp_sdev->port->dev); 5062306a36Sopenharmony_ci} 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_cistatic int zfcp_scsi_slave_configure(struct scsi_device *sdp) 5362306a36Sopenharmony_ci{ 5462306a36Sopenharmony_ci if (sdp->tagged_supported) 5562306a36Sopenharmony_ci scsi_change_queue_depth(sdp, default_depth); 5662306a36Sopenharmony_ci return 0; 5762306a36Sopenharmony_ci} 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_cistatic void zfcp_scsi_command_fail(struct scsi_cmnd *scpnt, int result) 6062306a36Sopenharmony_ci{ 6162306a36Sopenharmony_ci set_host_byte(scpnt, result); 6262306a36Sopenharmony_ci zfcp_dbf_scsi_fail_send(scpnt); 6362306a36Sopenharmony_ci scsi_done(scpnt); 6462306a36Sopenharmony_ci} 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_cistatic 6762306a36Sopenharmony_ciint zfcp_scsi_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *scpnt) 6862306a36Sopenharmony_ci{ 6962306a36Sopenharmony_ci struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(scpnt->device); 7062306a36Sopenharmony_ci struct fc_rport *rport = starget_to_rport(scsi_target(scpnt->device)); 7162306a36Sopenharmony_ci int status, scsi_result, ret; 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci /* reset the status for this request */ 7462306a36Sopenharmony_ci scpnt->result = 0; 7562306a36Sopenharmony_ci scpnt->host_scribble = NULL; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci scsi_result = fc_remote_port_chkready(rport); 7862306a36Sopenharmony_ci if (unlikely(scsi_result)) { 7962306a36Sopenharmony_ci scpnt->result = scsi_result; 8062306a36Sopenharmony_ci zfcp_dbf_scsi_fail_send(scpnt); 8162306a36Sopenharmony_ci scsi_done(scpnt); 8262306a36Sopenharmony_ci return 0; 8362306a36Sopenharmony_ci } 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci status = atomic_read(&zfcp_sdev->status); 8662306a36Sopenharmony_ci if (unlikely(status & ZFCP_STATUS_COMMON_ERP_FAILED) && 8762306a36Sopenharmony_ci !(atomic_read(&zfcp_sdev->port->status) & 8862306a36Sopenharmony_ci ZFCP_STATUS_COMMON_ERP_FAILED)) { 8962306a36Sopenharmony_ci /* only LUN access denied, but port is good 9062306a36Sopenharmony_ci * not covered by FC transport, have to fail here */ 9162306a36Sopenharmony_ci zfcp_scsi_command_fail(scpnt, DID_ERROR); 9262306a36Sopenharmony_ci return 0; 9362306a36Sopenharmony_ci } 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci if (unlikely(!(status & ZFCP_STATUS_COMMON_UNBLOCKED))) { 9662306a36Sopenharmony_ci /* This could be 9762306a36Sopenharmony_ci * call to rport_delete pending: mimic retry from 9862306a36Sopenharmony_ci * fc_remote_port_chkready until rport is BLOCKED 9962306a36Sopenharmony_ci */ 10062306a36Sopenharmony_ci zfcp_scsi_command_fail(scpnt, DID_IMM_RETRY); 10162306a36Sopenharmony_ci return 0; 10262306a36Sopenharmony_ci } 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci ret = zfcp_fsf_fcp_cmnd(scpnt); 10562306a36Sopenharmony_ci if (unlikely(ret == -EBUSY)) 10662306a36Sopenharmony_ci return SCSI_MLQUEUE_DEVICE_BUSY; 10762306a36Sopenharmony_ci else if (unlikely(ret < 0)) 10862306a36Sopenharmony_ci return SCSI_MLQUEUE_HOST_BUSY; 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci return ret; 11162306a36Sopenharmony_ci} 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_cistatic int zfcp_scsi_slave_alloc(struct scsi_device *sdev) 11462306a36Sopenharmony_ci{ 11562306a36Sopenharmony_ci struct fc_rport *rport = starget_to_rport(scsi_target(sdev)); 11662306a36Sopenharmony_ci struct zfcp_adapter *adapter = 11762306a36Sopenharmony_ci (struct zfcp_adapter *) sdev->host->hostdata[0]; 11862306a36Sopenharmony_ci struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); 11962306a36Sopenharmony_ci struct zfcp_port *port; 12062306a36Sopenharmony_ci struct zfcp_unit *unit; 12162306a36Sopenharmony_ci int npiv = adapter->connection_features & FSF_FEATURE_NPIV_MODE; 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci zfcp_sdev->erp_action.adapter = adapter; 12462306a36Sopenharmony_ci zfcp_sdev->erp_action.sdev = sdev; 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci port = zfcp_get_port_by_wwpn(adapter, rport->port_name); 12762306a36Sopenharmony_ci if (!port) 12862306a36Sopenharmony_ci return -ENXIO; 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci zfcp_sdev->erp_action.port = port; 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci mutex_lock(&zfcp_sysfs_port_units_mutex); 13362306a36Sopenharmony_ci if (zfcp_sysfs_port_is_removing(port)) { 13462306a36Sopenharmony_ci /* port is already gone */ 13562306a36Sopenharmony_ci mutex_unlock(&zfcp_sysfs_port_units_mutex); 13662306a36Sopenharmony_ci put_device(&port->dev); /* undo zfcp_get_port_by_wwpn() */ 13762306a36Sopenharmony_ci return -ENXIO; 13862306a36Sopenharmony_ci } 13962306a36Sopenharmony_ci mutex_unlock(&zfcp_sysfs_port_units_mutex); 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci unit = zfcp_unit_find(port, zfcp_scsi_dev_lun(sdev)); 14262306a36Sopenharmony_ci if (unit) 14362306a36Sopenharmony_ci put_device(&unit->dev); 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci if (!unit && !(allow_lun_scan && npiv)) { 14662306a36Sopenharmony_ci put_device(&port->dev); 14762306a36Sopenharmony_ci return -ENXIO; 14862306a36Sopenharmony_ci } 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci zfcp_sdev->port = port; 15162306a36Sopenharmony_ci zfcp_sdev->latencies.write.channel.min = 0xFFFFFFFF; 15262306a36Sopenharmony_ci zfcp_sdev->latencies.write.fabric.min = 0xFFFFFFFF; 15362306a36Sopenharmony_ci zfcp_sdev->latencies.read.channel.min = 0xFFFFFFFF; 15462306a36Sopenharmony_ci zfcp_sdev->latencies.read.fabric.min = 0xFFFFFFFF; 15562306a36Sopenharmony_ci zfcp_sdev->latencies.cmd.channel.min = 0xFFFFFFFF; 15662306a36Sopenharmony_ci zfcp_sdev->latencies.cmd.fabric.min = 0xFFFFFFFF; 15762306a36Sopenharmony_ci spin_lock_init(&zfcp_sdev->latencies.lock); 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci zfcp_erp_set_lun_status(sdev, ZFCP_STATUS_COMMON_RUNNING); 16062306a36Sopenharmony_ci zfcp_erp_lun_reopen(sdev, 0, "scsla_1"); 16162306a36Sopenharmony_ci zfcp_erp_wait(port->adapter); 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci return 0; 16462306a36Sopenharmony_ci} 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_cistatic int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt) 16762306a36Sopenharmony_ci{ 16862306a36Sopenharmony_ci struct Scsi_Host *scsi_host = scpnt->device->host; 16962306a36Sopenharmony_ci struct zfcp_adapter *adapter = 17062306a36Sopenharmony_ci (struct zfcp_adapter *) scsi_host->hostdata[0]; 17162306a36Sopenharmony_ci struct zfcp_fsf_req *old_req, *abrt_req; 17262306a36Sopenharmony_ci unsigned long flags; 17362306a36Sopenharmony_ci u64 old_reqid = (u64) scpnt->host_scribble; 17462306a36Sopenharmony_ci int retval = SUCCESS, ret; 17562306a36Sopenharmony_ci int retry = 3; 17662306a36Sopenharmony_ci char *dbf_tag; 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci /* avoid race condition between late normal completion and abort */ 17962306a36Sopenharmony_ci write_lock_irqsave(&adapter->abort_lock, flags); 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci old_req = zfcp_reqlist_find(adapter->req_list, old_reqid); 18262306a36Sopenharmony_ci if (!old_req) { 18362306a36Sopenharmony_ci write_unlock_irqrestore(&adapter->abort_lock, flags); 18462306a36Sopenharmony_ci zfcp_dbf_scsi_abort("abrt_or", scpnt, NULL); 18562306a36Sopenharmony_ci return FAILED; /* completion could be in progress */ 18662306a36Sopenharmony_ci } 18762306a36Sopenharmony_ci old_req->data = NULL; 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci /* don't access old fsf_req after releasing the abort_lock */ 19062306a36Sopenharmony_ci write_unlock_irqrestore(&adapter->abort_lock, flags); 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci while (retry--) { 19362306a36Sopenharmony_ci abrt_req = zfcp_fsf_abort_fcp_cmnd(scpnt); 19462306a36Sopenharmony_ci if (abrt_req) 19562306a36Sopenharmony_ci break; 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci zfcp_dbf_scsi_abort("abrt_wt", scpnt, NULL); 19862306a36Sopenharmony_ci zfcp_erp_wait(adapter); 19962306a36Sopenharmony_ci ret = fc_block_scsi_eh(scpnt); 20062306a36Sopenharmony_ci if (ret) { 20162306a36Sopenharmony_ci zfcp_dbf_scsi_abort("abrt_bl", scpnt, NULL); 20262306a36Sopenharmony_ci return ret; 20362306a36Sopenharmony_ci } 20462306a36Sopenharmony_ci if (!(atomic_read(&adapter->status) & 20562306a36Sopenharmony_ci ZFCP_STATUS_COMMON_RUNNING)) { 20662306a36Sopenharmony_ci zfcp_dbf_scsi_abort("abrt_ru", scpnt, NULL); 20762306a36Sopenharmony_ci return SUCCESS; 20862306a36Sopenharmony_ci } 20962306a36Sopenharmony_ci } 21062306a36Sopenharmony_ci if (!abrt_req) { 21162306a36Sopenharmony_ci zfcp_dbf_scsi_abort("abrt_ar", scpnt, NULL); 21262306a36Sopenharmony_ci return FAILED; 21362306a36Sopenharmony_ci } 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci wait_for_completion(&abrt_req->completion); 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci if (abrt_req->status & ZFCP_STATUS_FSFREQ_ABORTSUCCEEDED) 21862306a36Sopenharmony_ci dbf_tag = "abrt_ok"; 21962306a36Sopenharmony_ci else if (abrt_req->status & ZFCP_STATUS_FSFREQ_ABORTNOTNEEDED) 22062306a36Sopenharmony_ci dbf_tag = "abrt_nn"; 22162306a36Sopenharmony_ci else { 22262306a36Sopenharmony_ci dbf_tag = "abrt_fa"; 22362306a36Sopenharmony_ci retval = FAILED; 22462306a36Sopenharmony_ci } 22562306a36Sopenharmony_ci zfcp_dbf_scsi_abort(dbf_tag, scpnt, abrt_req); 22662306a36Sopenharmony_ci zfcp_fsf_req_free(abrt_req); 22762306a36Sopenharmony_ci return retval; 22862306a36Sopenharmony_ci} 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_cistruct zfcp_scsi_req_filter { 23162306a36Sopenharmony_ci u8 tmf_scope; 23262306a36Sopenharmony_ci u32 lun_handle; 23362306a36Sopenharmony_ci u32 port_handle; 23462306a36Sopenharmony_ci}; 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_cistatic void zfcp_scsi_forget_cmnd(struct zfcp_fsf_req *old_req, void *data) 23762306a36Sopenharmony_ci{ 23862306a36Sopenharmony_ci struct zfcp_scsi_req_filter *filter = 23962306a36Sopenharmony_ci (struct zfcp_scsi_req_filter *)data; 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci /* already aborted - prevent side-effects - or not a SCSI command */ 24262306a36Sopenharmony_ci if (old_req->data == NULL || 24362306a36Sopenharmony_ci zfcp_fsf_req_is_status_read_buffer(old_req) || 24462306a36Sopenharmony_ci old_req->qtcb->header.fsf_command != FSF_QTCB_FCP_CMND) 24562306a36Sopenharmony_ci return; 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci /* (tmf_scope == FCP_TMF_TGT_RESET || tmf_scope == FCP_TMF_LUN_RESET) */ 24862306a36Sopenharmony_ci if (old_req->qtcb->header.port_handle != filter->port_handle) 24962306a36Sopenharmony_ci return; 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci if (filter->tmf_scope == FCP_TMF_LUN_RESET && 25262306a36Sopenharmony_ci old_req->qtcb->header.lun_handle != filter->lun_handle) 25362306a36Sopenharmony_ci return; 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci zfcp_dbf_scsi_nullcmnd((struct scsi_cmnd *)old_req->data, old_req); 25662306a36Sopenharmony_ci old_req->data = NULL; 25762306a36Sopenharmony_ci} 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_cistatic void zfcp_scsi_forget_cmnds(struct zfcp_scsi_dev *zsdev, u8 tm_flags) 26062306a36Sopenharmony_ci{ 26162306a36Sopenharmony_ci struct zfcp_adapter *adapter = zsdev->port->adapter; 26262306a36Sopenharmony_ci struct zfcp_scsi_req_filter filter = { 26362306a36Sopenharmony_ci .tmf_scope = FCP_TMF_TGT_RESET, 26462306a36Sopenharmony_ci .port_handle = zsdev->port->handle, 26562306a36Sopenharmony_ci }; 26662306a36Sopenharmony_ci unsigned long flags; 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci if (tm_flags == FCP_TMF_LUN_RESET) { 26962306a36Sopenharmony_ci filter.tmf_scope = FCP_TMF_LUN_RESET; 27062306a36Sopenharmony_ci filter.lun_handle = zsdev->lun_handle; 27162306a36Sopenharmony_ci } 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci /* 27462306a36Sopenharmony_ci * abort_lock secures against other processings - in the abort-function 27562306a36Sopenharmony_ci * and normal cmnd-handler - of (struct zfcp_fsf_req *)->data 27662306a36Sopenharmony_ci */ 27762306a36Sopenharmony_ci write_lock_irqsave(&adapter->abort_lock, flags); 27862306a36Sopenharmony_ci zfcp_reqlist_apply_for_all(adapter->req_list, zfcp_scsi_forget_cmnd, 27962306a36Sopenharmony_ci &filter); 28062306a36Sopenharmony_ci write_unlock_irqrestore(&adapter->abort_lock, flags); 28162306a36Sopenharmony_ci} 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci/** 28462306a36Sopenharmony_ci * zfcp_scsi_task_mgmt_function() - Send a task management function (sync). 28562306a36Sopenharmony_ci * @sdev: Pointer to SCSI device to send the task management command to. 28662306a36Sopenharmony_ci * @tm_flags: Task management flags, 28762306a36Sopenharmony_ci * here we only handle %FCP_TMF_TGT_RESET or %FCP_TMF_LUN_RESET. 28862306a36Sopenharmony_ci */ 28962306a36Sopenharmony_cistatic int zfcp_scsi_task_mgmt_function(struct scsi_device *sdev, u8 tm_flags) 29062306a36Sopenharmony_ci{ 29162306a36Sopenharmony_ci struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); 29262306a36Sopenharmony_ci struct zfcp_adapter *adapter = zfcp_sdev->port->adapter; 29362306a36Sopenharmony_ci struct fc_rport *rport = starget_to_rport(scsi_target(sdev)); 29462306a36Sopenharmony_ci struct zfcp_fsf_req *fsf_req = NULL; 29562306a36Sopenharmony_ci int retval = SUCCESS, ret; 29662306a36Sopenharmony_ci int retry = 3; 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci while (retry--) { 29962306a36Sopenharmony_ci fsf_req = zfcp_fsf_fcp_task_mgmt(sdev, tm_flags); 30062306a36Sopenharmony_ci if (fsf_req) 30162306a36Sopenharmony_ci break; 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci zfcp_dbf_scsi_devreset("wait", sdev, tm_flags, NULL); 30462306a36Sopenharmony_ci zfcp_erp_wait(adapter); 30562306a36Sopenharmony_ci ret = fc_block_rport(rport); 30662306a36Sopenharmony_ci if (ret) { 30762306a36Sopenharmony_ci zfcp_dbf_scsi_devreset("fiof", sdev, tm_flags, NULL); 30862306a36Sopenharmony_ci return ret; 30962306a36Sopenharmony_ci } 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci if (!(atomic_read(&adapter->status) & 31262306a36Sopenharmony_ci ZFCP_STATUS_COMMON_RUNNING)) { 31362306a36Sopenharmony_ci zfcp_dbf_scsi_devreset("nres", sdev, tm_flags, NULL); 31462306a36Sopenharmony_ci return SUCCESS; 31562306a36Sopenharmony_ci } 31662306a36Sopenharmony_ci } 31762306a36Sopenharmony_ci if (!fsf_req) { 31862306a36Sopenharmony_ci zfcp_dbf_scsi_devreset("reqf", sdev, tm_flags, NULL); 31962306a36Sopenharmony_ci return FAILED; 32062306a36Sopenharmony_ci } 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci wait_for_completion(&fsf_req->completion); 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci if (fsf_req->status & ZFCP_STATUS_FSFREQ_TMFUNCFAILED) { 32562306a36Sopenharmony_ci zfcp_dbf_scsi_devreset("fail", sdev, tm_flags, fsf_req); 32662306a36Sopenharmony_ci retval = FAILED; 32762306a36Sopenharmony_ci } else { 32862306a36Sopenharmony_ci zfcp_dbf_scsi_devreset("okay", sdev, tm_flags, fsf_req); 32962306a36Sopenharmony_ci zfcp_scsi_forget_cmnds(zfcp_sdev, tm_flags); 33062306a36Sopenharmony_ci } 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci zfcp_fsf_req_free(fsf_req); 33362306a36Sopenharmony_ci return retval; 33462306a36Sopenharmony_ci} 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_cistatic int zfcp_scsi_eh_device_reset_handler(struct scsi_cmnd *scpnt) 33762306a36Sopenharmony_ci{ 33862306a36Sopenharmony_ci struct scsi_device *sdev = scpnt->device; 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci return zfcp_scsi_task_mgmt_function(sdev, FCP_TMF_LUN_RESET); 34162306a36Sopenharmony_ci} 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_cistatic int zfcp_scsi_eh_target_reset_handler(struct scsi_cmnd *scpnt) 34462306a36Sopenharmony_ci{ 34562306a36Sopenharmony_ci struct scsi_target *starget = scsi_target(scpnt->device); 34662306a36Sopenharmony_ci struct fc_rport *rport = starget_to_rport(starget); 34762306a36Sopenharmony_ci struct Scsi_Host *shost = rport_to_shost(rport); 34862306a36Sopenharmony_ci struct scsi_device *sdev = NULL, *tmp_sdev; 34962306a36Sopenharmony_ci struct zfcp_adapter *adapter = 35062306a36Sopenharmony_ci (struct zfcp_adapter *)shost->hostdata[0]; 35162306a36Sopenharmony_ci int ret; 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci shost_for_each_device(tmp_sdev, shost) { 35462306a36Sopenharmony_ci if (tmp_sdev->id == starget->id) { 35562306a36Sopenharmony_ci sdev = tmp_sdev; 35662306a36Sopenharmony_ci break; 35762306a36Sopenharmony_ci } 35862306a36Sopenharmony_ci } 35962306a36Sopenharmony_ci if (!sdev) { 36062306a36Sopenharmony_ci ret = FAILED; 36162306a36Sopenharmony_ci zfcp_dbf_scsi_eh("tr_nosd", adapter, starget->id, ret); 36262306a36Sopenharmony_ci return ret; 36362306a36Sopenharmony_ci } 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci ret = zfcp_scsi_task_mgmt_function(sdev, FCP_TMF_TGT_RESET); 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci /* release reference from above shost_for_each_device */ 36862306a36Sopenharmony_ci if (sdev) 36962306a36Sopenharmony_ci scsi_device_put(tmp_sdev); 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci return ret; 37262306a36Sopenharmony_ci} 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_cistatic int zfcp_scsi_eh_host_reset_handler(struct scsi_cmnd *scpnt) 37562306a36Sopenharmony_ci{ 37662306a36Sopenharmony_ci struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(scpnt->device); 37762306a36Sopenharmony_ci struct zfcp_adapter *adapter = zfcp_sdev->port->adapter; 37862306a36Sopenharmony_ci int ret = SUCCESS, fc_ret; 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci if (!(adapter->connection_features & FSF_FEATURE_NPIV_MODE)) { 38162306a36Sopenharmony_ci zfcp_erp_port_forced_reopen_all(adapter, 0, "schrh_p"); 38262306a36Sopenharmony_ci zfcp_erp_wait(adapter); 38362306a36Sopenharmony_ci } 38462306a36Sopenharmony_ci zfcp_erp_adapter_reopen(adapter, 0, "schrh_1"); 38562306a36Sopenharmony_ci zfcp_erp_wait(adapter); 38662306a36Sopenharmony_ci fc_ret = fc_block_scsi_eh(scpnt); 38762306a36Sopenharmony_ci if (fc_ret) 38862306a36Sopenharmony_ci ret = fc_ret; 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci zfcp_dbf_scsi_eh("schrh_r", adapter, ~0, ret); 39162306a36Sopenharmony_ci return ret; 39262306a36Sopenharmony_ci} 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci/** 39562306a36Sopenharmony_ci * zfcp_scsi_sysfs_host_reset() - Support scsi_host sysfs attribute host_reset. 39662306a36Sopenharmony_ci * @shost: Pointer to Scsi_Host to perform action on. 39762306a36Sopenharmony_ci * @reset_type: We support %SCSI_ADAPTER_RESET but not %SCSI_FIRMWARE_RESET. 39862306a36Sopenharmony_ci * 39962306a36Sopenharmony_ci * Return: 0 on %SCSI_ADAPTER_RESET, -%EOPNOTSUPP otherwise. 40062306a36Sopenharmony_ci * 40162306a36Sopenharmony_ci * This is similar to zfcp_sysfs_adapter_failed_store(). 40262306a36Sopenharmony_ci */ 40362306a36Sopenharmony_cistatic int zfcp_scsi_sysfs_host_reset(struct Scsi_Host *shost, int reset_type) 40462306a36Sopenharmony_ci{ 40562306a36Sopenharmony_ci struct zfcp_adapter *adapter = 40662306a36Sopenharmony_ci (struct zfcp_adapter *)shost->hostdata[0]; 40762306a36Sopenharmony_ci int ret = 0; 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci if (reset_type != SCSI_ADAPTER_RESET) { 41062306a36Sopenharmony_ci ret = -EOPNOTSUPP; 41162306a36Sopenharmony_ci zfcp_dbf_scsi_eh("scshr_n", adapter, ~0, ret); 41262306a36Sopenharmony_ci return ret; 41362306a36Sopenharmony_ci } 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci zfcp_erp_adapter_reset_sync(adapter, "scshr_y"); 41662306a36Sopenharmony_ci return ret; 41762306a36Sopenharmony_ci} 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_cistruct scsi_transport_template *zfcp_scsi_transport_template; 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_cistatic const struct scsi_host_template zfcp_scsi_host_template = { 42262306a36Sopenharmony_ci .module = THIS_MODULE, 42362306a36Sopenharmony_ci .name = "zfcp", 42462306a36Sopenharmony_ci .queuecommand = zfcp_scsi_queuecommand, 42562306a36Sopenharmony_ci .eh_timed_out = fc_eh_timed_out, 42662306a36Sopenharmony_ci .eh_abort_handler = zfcp_scsi_eh_abort_handler, 42762306a36Sopenharmony_ci .eh_device_reset_handler = zfcp_scsi_eh_device_reset_handler, 42862306a36Sopenharmony_ci .eh_target_reset_handler = zfcp_scsi_eh_target_reset_handler, 42962306a36Sopenharmony_ci .eh_host_reset_handler = zfcp_scsi_eh_host_reset_handler, 43062306a36Sopenharmony_ci .slave_alloc = zfcp_scsi_slave_alloc, 43162306a36Sopenharmony_ci .slave_configure = zfcp_scsi_slave_configure, 43262306a36Sopenharmony_ci .slave_destroy = zfcp_scsi_slave_destroy, 43362306a36Sopenharmony_ci .change_queue_depth = scsi_change_queue_depth, 43462306a36Sopenharmony_ci .host_reset = zfcp_scsi_sysfs_host_reset, 43562306a36Sopenharmony_ci .proc_name = "zfcp", 43662306a36Sopenharmony_ci .can_queue = 4096, 43762306a36Sopenharmony_ci .this_id = -1, 43862306a36Sopenharmony_ci .sg_tablesize = (((QDIO_MAX_ELEMENTS_PER_BUFFER - 1) 43962306a36Sopenharmony_ci * ZFCP_QDIO_MAX_SBALS_PER_REQ) - 2), 44062306a36Sopenharmony_ci /* GCD, adjusted later */ 44162306a36Sopenharmony_ci .max_sectors = (((QDIO_MAX_ELEMENTS_PER_BUFFER - 1) 44262306a36Sopenharmony_ci * ZFCP_QDIO_MAX_SBALS_PER_REQ) - 2) * 8, 44362306a36Sopenharmony_ci /* GCD, adjusted later */ 44462306a36Sopenharmony_ci /* report size limit per scatter-gather segment */ 44562306a36Sopenharmony_ci .max_segment_size = ZFCP_QDIO_SBALE_LEN, 44662306a36Sopenharmony_ci .dma_boundary = ZFCP_QDIO_SBALE_LEN - 1, 44762306a36Sopenharmony_ci .shost_groups = zfcp_sysfs_shost_attr_groups, 44862306a36Sopenharmony_ci .sdev_groups = zfcp_sysfs_sdev_attr_groups, 44962306a36Sopenharmony_ci .track_queue_depth = 1, 45062306a36Sopenharmony_ci .supported_mode = MODE_INITIATOR, 45162306a36Sopenharmony_ci}; 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci/** 45462306a36Sopenharmony_ci * zfcp_scsi_adapter_register() - Allocate and register SCSI and FC host with 45562306a36Sopenharmony_ci * SCSI midlayer 45662306a36Sopenharmony_ci * @adapter: The zfcp adapter to register with the SCSI midlayer 45762306a36Sopenharmony_ci * 45862306a36Sopenharmony_ci * Allocates the SCSI host object for the given adapter, sets basic properties 45962306a36Sopenharmony_ci * (such as the transport template, QDIO limits, ...), and registers it with 46062306a36Sopenharmony_ci * the midlayer. 46162306a36Sopenharmony_ci * 46262306a36Sopenharmony_ci * During registration with the midlayer the corresponding FC host object for 46362306a36Sopenharmony_ci * the referenced transport class is also implicitely allocated. 46462306a36Sopenharmony_ci * 46562306a36Sopenharmony_ci * Upon success adapter->scsi_host is set, and upon failure it remains NULL. If 46662306a36Sopenharmony_ci * adapter->scsi_host is already set, nothing is done. 46762306a36Sopenharmony_ci * 46862306a36Sopenharmony_ci * Return: 46962306a36Sopenharmony_ci * * 0 - Allocation and registration was successful 47062306a36Sopenharmony_ci * * -EEXIST - SCSI and FC host did already exist, nothing was done, nothing 47162306a36Sopenharmony_ci * was changed 47262306a36Sopenharmony_ci * * -EIO - Allocation or registration failed 47362306a36Sopenharmony_ci */ 47462306a36Sopenharmony_ciint zfcp_scsi_adapter_register(struct zfcp_adapter *adapter) 47562306a36Sopenharmony_ci{ 47662306a36Sopenharmony_ci struct ccw_dev_id dev_id; 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci if (adapter->scsi_host) 47962306a36Sopenharmony_ci return -EEXIST; 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci ccw_device_get_id(adapter->ccw_device, &dev_id); 48262306a36Sopenharmony_ci /* register adapter as SCSI host with mid layer of SCSI stack */ 48362306a36Sopenharmony_ci adapter->scsi_host = scsi_host_alloc(&zfcp_scsi_host_template, 48462306a36Sopenharmony_ci sizeof (struct zfcp_adapter *)); 48562306a36Sopenharmony_ci if (!adapter->scsi_host) 48662306a36Sopenharmony_ci goto err_out; 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci /* tell the SCSI stack some characteristics of this adapter */ 48962306a36Sopenharmony_ci adapter->scsi_host->max_id = 511; 49062306a36Sopenharmony_ci adapter->scsi_host->max_lun = 0xFFFFFFFF; 49162306a36Sopenharmony_ci adapter->scsi_host->max_channel = 0; 49262306a36Sopenharmony_ci adapter->scsi_host->unique_id = dev_id.devno; 49362306a36Sopenharmony_ci adapter->scsi_host->max_cmd_len = 16; /* in struct fcp_cmnd */ 49462306a36Sopenharmony_ci adapter->scsi_host->transportt = zfcp_scsi_transport_template; 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci /* make all basic properties known at registration time */ 49762306a36Sopenharmony_ci zfcp_qdio_shost_update(adapter, adapter->qdio); 49862306a36Sopenharmony_ci zfcp_scsi_set_prot(adapter); 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci adapter->scsi_host->hostdata[0] = (unsigned long) adapter; 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci if (scsi_add_host(adapter->scsi_host, &adapter->ccw_device->dev)) { 50362306a36Sopenharmony_ci scsi_host_put(adapter->scsi_host); 50462306a36Sopenharmony_ci goto err_out; 50562306a36Sopenharmony_ci } 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci return 0; 50862306a36Sopenharmony_cierr_out: 50962306a36Sopenharmony_ci adapter->scsi_host = NULL; 51062306a36Sopenharmony_ci dev_err(&adapter->ccw_device->dev, 51162306a36Sopenharmony_ci "Registering the FCP device with the SCSI stack failed\n"); 51262306a36Sopenharmony_ci return -EIO; 51362306a36Sopenharmony_ci} 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci/** 51662306a36Sopenharmony_ci * zfcp_scsi_adapter_unregister - Unregister SCSI and FC host from SCSI midlayer 51762306a36Sopenharmony_ci * @adapter: The zfcp adapter to unregister. 51862306a36Sopenharmony_ci */ 51962306a36Sopenharmony_civoid zfcp_scsi_adapter_unregister(struct zfcp_adapter *adapter) 52062306a36Sopenharmony_ci{ 52162306a36Sopenharmony_ci struct Scsi_Host *shost; 52262306a36Sopenharmony_ci struct zfcp_port *port; 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci shost = adapter->scsi_host; 52562306a36Sopenharmony_ci if (!shost) 52662306a36Sopenharmony_ci return; 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci read_lock_irq(&adapter->port_list_lock); 52962306a36Sopenharmony_ci list_for_each_entry(port, &adapter->port_list, list) 53062306a36Sopenharmony_ci port->rport = NULL; 53162306a36Sopenharmony_ci read_unlock_irq(&adapter->port_list_lock); 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci fc_remove_host(shost); 53462306a36Sopenharmony_ci scsi_remove_host(shost); 53562306a36Sopenharmony_ci scsi_host_put(shost); 53662306a36Sopenharmony_ci adapter->scsi_host = NULL; 53762306a36Sopenharmony_ci} 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_cistatic struct fc_host_statistics* 54062306a36Sopenharmony_cizfcp_scsi_init_fc_host_stats(struct zfcp_adapter *adapter) 54162306a36Sopenharmony_ci{ 54262306a36Sopenharmony_ci struct fc_host_statistics *fc_stats; 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_ci if (!adapter->fc_stats) { 54562306a36Sopenharmony_ci fc_stats = kmalloc(sizeof(*fc_stats), GFP_KERNEL); 54662306a36Sopenharmony_ci if (!fc_stats) 54762306a36Sopenharmony_ci return NULL; 54862306a36Sopenharmony_ci adapter->fc_stats = fc_stats; /* freed in adapter_release */ 54962306a36Sopenharmony_ci } 55062306a36Sopenharmony_ci memset(adapter->fc_stats, 0, sizeof(*adapter->fc_stats)); 55162306a36Sopenharmony_ci return adapter->fc_stats; 55262306a36Sopenharmony_ci} 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_cistatic void zfcp_scsi_adjust_fc_host_stats(struct fc_host_statistics *fc_stats, 55562306a36Sopenharmony_ci struct fsf_qtcb_bottom_port *data, 55662306a36Sopenharmony_ci struct fsf_qtcb_bottom_port *old) 55762306a36Sopenharmony_ci{ 55862306a36Sopenharmony_ci fc_stats->seconds_since_last_reset = 55962306a36Sopenharmony_ci data->seconds_since_last_reset - old->seconds_since_last_reset; 56062306a36Sopenharmony_ci fc_stats->tx_frames = data->tx_frames - old->tx_frames; 56162306a36Sopenharmony_ci fc_stats->tx_words = data->tx_words - old->tx_words; 56262306a36Sopenharmony_ci fc_stats->rx_frames = data->rx_frames - old->rx_frames; 56362306a36Sopenharmony_ci fc_stats->rx_words = data->rx_words - old->rx_words; 56462306a36Sopenharmony_ci fc_stats->lip_count = data->lip - old->lip; 56562306a36Sopenharmony_ci fc_stats->nos_count = data->nos - old->nos; 56662306a36Sopenharmony_ci fc_stats->error_frames = data->error_frames - old->error_frames; 56762306a36Sopenharmony_ci fc_stats->dumped_frames = data->dumped_frames - old->dumped_frames; 56862306a36Sopenharmony_ci fc_stats->link_failure_count = data->link_failure - old->link_failure; 56962306a36Sopenharmony_ci fc_stats->loss_of_sync_count = data->loss_of_sync - old->loss_of_sync; 57062306a36Sopenharmony_ci fc_stats->loss_of_signal_count = 57162306a36Sopenharmony_ci data->loss_of_signal - old->loss_of_signal; 57262306a36Sopenharmony_ci fc_stats->prim_seq_protocol_err_count = 57362306a36Sopenharmony_ci data->psp_error_counts - old->psp_error_counts; 57462306a36Sopenharmony_ci fc_stats->invalid_tx_word_count = 57562306a36Sopenharmony_ci data->invalid_tx_words - old->invalid_tx_words; 57662306a36Sopenharmony_ci fc_stats->invalid_crc_count = data->invalid_crcs - old->invalid_crcs; 57762306a36Sopenharmony_ci fc_stats->fcp_input_requests = 57862306a36Sopenharmony_ci data->input_requests - old->input_requests; 57962306a36Sopenharmony_ci fc_stats->fcp_output_requests = 58062306a36Sopenharmony_ci data->output_requests - old->output_requests; 58162306a36Sopenharmony_ci fc_stats->fcp_control_requests = 58262306a36Sopenharmony_ci data->control_requests - old->control_requests; 58362306a36Sopenharmony_ci fc_stats->fcp_input_megabytes = data->input_mb - old->input_mb; 58462306a36Sopenharmony_ci fc_stats->fcp_output_megabytes = data->output_mb - old->output_mb; 58562306a36Sopenharmony_ci} 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_cistatic void zfcp_scsi_set_fc_host_stats(struct fc_host_statistics *fc_stats, 58862306a36Sopenharmony_ci struct fsf_qtcb_bottom_port *data) 58962306a36Sopenharmony_ci{ 59062306a36Sopenharmony_ci fc_stats->seconds_since_last_reset = data->seconds_since_last_reset; 59162306a36Sopenharmony_ci fc_stats->tx_frames = data->tx_frames; 59262306a36Sopenharmony_ci fc_stats->tx_words = data->tx_words; 59362306a36Sopenharmony_ci fc_stats->rx_frames = data->rx_frames; 59462306a36Sopenharmony_ci fc_stats->rx_words = data->rx_words; 59562306a36Sopenharmony_ci fc_stats->lip_count = data->lip; 59662306a36Sopenharmony_ci fc_stats->nos_count = data->nos; 59762306a36Sopenharmony_ci fc_stats->error_frames = data->error_frames; 59862306a36Sopenharmony_ci fc_stats->dumped_frames = data->dumped_frames; 59962306a36Sopenharmony_ci fc_stats->link_failure_count = data->link_failure; 60062306a36Sopenharmony_ci fc_stats->loss_of_sync_count = data->loss_of_sync; 60162306a36Sopenharmony_ci fc_stats->loss_of_signal_count = data->loss_of_signal; 60262306a36Sopenharmony_ci fc_stats->prim_seq_protocol_err_count = data->psp_error_counts; 60362306a36Sopenharmony_ci fc_stats->invalid_tx_word_count = data->invalid_tx_words; 60462306a36Sopenharmony_ci fc_stats->invalid_crc_count = data->invalid_crcs; 60562306a36Sopenharmony_ci fc_stats->fcp_input_requests = data->input_requests; 60662306a36Sopenharmony_ci fc_stats->fcp_output_requests = data->output_requests; 60762306a36Sopenharmony_ci fc_stats->fcp_control_requests = data->control_requests; 60862306a36Sopenharmony_ci fc_stats->fcp_input_megabytes = data->input_mb; 60962306a36Sopenharmony_ci fc_stats->fcp_output_megabytes = data->output_mb; 61062306a36Sopenharmony_ci} 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_cistatic struct fc_host_statistics * 61362306a36Sopenharmony_cizfcp_scsi_get_fc_host_stats(struct Scsi_Host *host) 61462306a36Sopenharmony_ci{ 61562306a36Sopenharmony_ci struct zfcp_adapter *adapter; 61662306a36Sopenharmony_ci struct fc_host_statistics *fc_stats; 61762306a36Sopenharmony_ci struct fsf_qtcb_bottom_port *data; 61862306a36Sopenharmony_ci int ret; 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci adapter = (struct zfcp_adapter *)host->hostdata[0]; 62162306a36Sopenharmony_ci fc_stats = zfcp_scsi_init_fc_host_stats(adapter); 62262306a36Sopenharmony_ci if (!fc_stats) 62362306a36Sopenharmony_ci return NULL; 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci data = kzalloc(sizeof(*data), GFP_KERNEL); 62662306a36Sopenharmony_ci if (!data) 62762306a36Sopenharmony_ci return NULL; 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_ci ret = zfcp_fsf_exchange_port_data_sync(adapter->qdio, data); 63062306a36Sopenharmony_ci if (ret != 0 && ret != -EAGAIN) { 63162306a36Sopenharmony_ci kfree(data); 63262306a36Sopenharmony_ci return NULL; 63362306a36Sopenharmony_ci } 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci if (adapter->stats_reset && 63662306a36Sopenharmony_ci ((jiffies/HZ - adapter->stats_reset) < 63762306a36Sopenharmony_ci data->seconds_since_last_reset)) 63862306a36Sopenharmony_ci zfcp_scsi_adjust_fc_host_stats(fc_stats, data, 63962306a36Sopenharmony_ci adapter->stats_reset_data); 64062306a36Sopenharmony_ci else 64162306a36Sopenharmony_ci zfcp_scsi_set_fc_host_stats(fc_stats, data); 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci kfree(data); 64462306a36Sopenharmony_ci return fc_stats; 64562306a36Sopenharmony_ci} 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_cistatic void zfcp_scsi_reset_fc_host_stats(struct Scsi_Host *shost) 64862306a36Sopenharmony_ci{ 64962306a36Sopenharmony_ci struct zfcp_adapter *adapter; 65062306a36Sopenharmony_ci struct fsf_qtcb_bottom_port *data; 65162306a36Sopenharmony_ci int ret; 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_ci adapter = (struct zfcp_adapter *)shost->hostdata[0]; 65462306a36Sopenharmony_ci data = kzalloc(sizeof(*data), GFP_KERNEL); 65562306a36Sopenharmony_ci if (!data) 65662306a36Sopenharmony_ci return; 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_ci ret = zfcp_fsf_exchange_port_data_sync(adapter->qdio, data); 65962306a36Sopenharmony_ci if (ret != 0 && ret != -EAGAIN) 66062306a36Sopenharmony_ci kfree(data); 66162306a36Sopenharmony_ci else { 66262306a36Sopenharmony_ci adapter->stats_reset = jiffies/HZ; 66362306a36Sopenharmony_ci kfree(adapter->stats_reset_data); 66462306a36Sopenharmony_ci adapter->stats_reset_data = data; /* finally freed in 66562306a36Sopenharmony_ci adapter_release */ 66662306a36Sopenharmony_ci } 66762306a36Sopenharmony_ci} 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_cistatic void zfcp_scsi_get_host_port_state(struct Scsi_Host *shost) 67062306a36Sopenharmony_ci{ 67162306a36Sopenharmony_ci struct zfcp_adapter *adapter = 67262306a36Sopenharmony_ci (struct zfcp_adapter *)shost->hostdata[0]; 67362306a36Sopenharmony_ci int status = atomic_read(&adapter->status); 67462306a36Sopenharmony_ci 67562306a36Sopenharmony_ci if ((status & ZFCP_STATUS_COMMON_RUNNING) && 67662306a36Sopenharmony_ci !(status & ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED)) 67762306a36Sopenharmony_ci fc_host_port_state(shost) = FC_PORTSTATE_ONLINE; 67862306a36Sopenharmony_ci else if (status & ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED) 67962306a36Sopenharmony_ci fc_host_port_state(shost) = FC_PORTSTATE_LINKDOWN; 68062306a36Sopenharmony_ci else if (status & ZFCP_STATUS_COMMON_ERP_FAILED) 68162306a36Sopenharmony_ci fc_host_port_state(shost) = FC_PORTSTATE_ERROR; 68262306a36Sopenharmony_ci else 68362306a36Sopenharmony_ci fc_host_port_state(shost) = FC_PORTSTATE_UNKNOWN; 68462306a36Sopenharmony_ci} 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_cistatic void zfcp_scsi_set_rport_dev_loss_tmo(struct fc_rport *rport, 68762306a36Sopenharmony_ci u32 timeout) 68862306a36Sopenharmony_ci{ 68962306a36Sopenharmony_ci rport->dev_loss_tmo = timeout; 69062306a36Sopenharmony_ci} 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_ci/** 69362306a36Sopenharmony_ci * zfcp_scsi_terminate_rport_io - Terminate all I/O on a rport 69462306a36Sopenharmony_ci * @rport: The FC rport where to teminate I/O 69562306a36Sopenharmony_ci * 69662306a36Sopenharmony_ci * Abort all pending SCSI commands for a port by closing the 69762306a36Sopenharmony_ci * port. Using a reopen avoids a conflict with a shutdown 69862306a36Sopenharmony_ci * overwriting a reopen. The "forced" ensures that a disappeared port 69962306a36Sopenharmony_ci * is not opened again as valid due to the cached plogi data in 70062306a36Sopenharmony_ci * non-NPIV mode. 70162306a36Sopenharmony_ci */ 70262306a36Sopenharmony_cistatic void zfcp_scsi_terminate_rport_io(struct fc_rport *rport) 70362306a36Sopenharmony_ci{ 70462306a36Sopenharmony_ci struct zfcp_port *port; 70562306a36Sopenharmony_ci struct Scsi_Host *shost = rport_to_shost(rport); 70662306a36Sopenharmony_ci struct zfcp_adapter *adapter = 70762306a36Sopenharmony_ci (struct zfcp_adapter *)shost->hostdata[0]; 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_ci port = zfcp_get_port_by_wwpn(adapter, rport->port_name); 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ci if (port) { 71262306a36Sopenharmony_ci zfcp_erp_port_forced_reopen(port, 0, "sctrpi1"); 71362306a36Sopenharmony_ci put_device(&port->dev); 71462306a36Sopenharmony_ci } else { 71562306a36Sopenharmony_ci zfcp_erp_port_forced_no_port_dbf( 71662306a36Sopenharmony_ci "sctrpin", adapter, 71762306a36Sopenharmony_ci rport->port_name /* zfcp_scsi_rport_register */, 71862306a36Sopenharmony_ci rport->port_id /* zfcp_scsi_rport_register */); 71962306a36Sopenharmony_ci } 72062306a36Sopenharmony_ci} 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_cistatic void zfcp_scsi_rport_register(struct zfcp_port *port) 72362306a36Sopenharmony_ci{ 72462306a36Sopenharmony_ci struct fc_rport_identifiers ids; 72562306a36Sopenharmony_ci struct fc_rport *rport; 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_ci if (port->rport) 72862306a36Sopenharmony_ci return; 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_ci ids.node_name = port->wwnn; 73162306a36Sopenharmony_ci ids.port_name = port->wwpn; 73262306a36Sopenharmony_ci ids.port_id = port->d_id; 73362306a36Sopenharmony_ci ids.roles = FC_RPORT_ROLE_FCP_TARGET; 73462306a36Sopenharmony_ci 73562306a36Sopenharmony_ci zfcp_dbf_rec_trig_lock("scpaddy", port->adapter, port, NULL, 73662306a36Sopenharmony_ci ZFCP_PSEUDO_ERP_ACTION_RPORT_ADD, 73762306a36Sopenharmony_ci ZFCP_PSEUDO_ERP_ACTION_RPORT_ADD); 73862306a36Sopenharmony_ci rport = fc_remote_port_add(port->adapter->scsi_host, 0, &ids); 73962306a36Sopenharmony_ci if (!rport) { 74062306a36Sopenharmony_ci dev_err(&port->adapter->ccw_device->dev, 74162306a36Sopenharmony_ci "Registering port 0x%016Lx failed\n", 74262306a36Sopenharmony_ci (unsigned long long)port->wwpn); 74362306a36Sopenharmony_ci return; 74462306a36Sopenharmony_ci } 74562306a36Sopenharmony_ci 74662306a36Sopenharmony_ci rport->maxframe_size = port->maxframe_size; 74762306a36Sopenharmony_ci rport->supported_classes = port->supported_classes; 74862306a36Sopenharmony_ci port->rport = rport; 74962306a36Sopenharmony_ci port->starget_id = rport->scsi_target_id; 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ci zfcp_unit_queue_scsi_scan(port); 75262306a36Sopenharmony_ci} 75362306a36Sopenharmony_ci 75462306a36Sopenharmony_cistatic void zfcp_scsi_rport_block(struct zfcp_port *port) 75562306a36Sopenharmony_ci{ 75662306a36Sopenharmony_ci struct fc_rport *rport = port->rport; 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_ci if (rport) { 75962306a36Sopenharmony_ci zfcp_dbf_rec_trig_lock("scpdely", port->adapter, port, NULL, 76062306a36Sopenharmony_ci ZFCP_PSEUDO_ERP_ACTION_RPORT_DEL, 76162306a36Sopenharmony_ci ZFCP_PSEUDO_ERP_ACTION_RPORT_DEL); 76262306a36Sopenharmony_ci fc_remote_port_delete(rport); 76362306a36Sopenharmony_ci port->rport = NULL; 76462306a36Sopenharmony_ci } 76562306a36Sopenharmony_ci} 76662306a36Sopenharmony_ci 76762306a36Sopenharmony_civoid zfcp_scsi_schedule_rport_register(struct zfcp_port *port) 76862306a36Sopenharmony_ci{ 76962306a36Sopenharmony_ci get_device(&port->dev); 77062306a36Sopenharmony_ci port->rport_task = RPORT_ADD; 77162306a36Sopenharmony_ci 77262306a36Sopenharmony_ci if (!queue_work(port->adapter->work_queue, &port->rport_work)) 77362306a36Sopenharmony_ci put_device(&port->dev); 77462306a36Sopenharmony_ci} 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_civoid zfcp_scsi_schedule_rport_block(struct zfcp_port *port) 77762306a36Sopenharmony_ci{ 77862306a36Sopenharmony_ci get_device(&port->dev); 77962306a36Sopenharmony_ci port->rport_task = RPORT_DEL; 78062306a36Sopenharmony_ci 78162306a36Sopenharmony_ci if (port->rport && queue_work(port->adapter->work_queue, 78262306a36Sopenharmony_ci &port->rport_work)) 78362306a36Sopenharmony_ci return; 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_ci put_device(&port->dev); 78662306a36Sopenharmony_ci} 78762306a36Sopenharmony_ci 78862306a36Sopenharmony_civoid zfcp_scsi_schedule_rports_block(struct zfcp_adapter *adapter) 78962306a36Sopenharmony_ci{ 79062306a36Sopenharmony_ci unsigned long flags; 79162306a36Sopenharmony_ci struct zfcp_port *port; 79262306a36Sopenharmony_ci 79362306a36Sopenharmony_ci read_lock_irqsave(&adapter->port_list_lock, flags); 79462306a36Sopenharmony_ci list_for_each_entry(port, &adapter->port_list, list) 79562306a36Sopenharmony_ci zfcp_scsi_schedule_rport_block(port); 79662306a36Sopenharmony_ci read_unlock_irqrestore(&adapter->port_list_lock, flags); 79762306a36Sopenharmony_ci} 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_civoid zfcp_scsi_rport_work(struct work_struct *work) 80062306a36Sopenharmony_ci{ 80162306a36Sopenharmony_ci struct zfcp_port *port = container_of(work, struct zfcp_port, 80262306a36Sopenharmony_ci rport_work); 80362306a36Sopenharmony_ci 80462306a36Sopenharmony_ci set_worker_desc("zrp%c-%16llx", 80562306a36Sopenharmony_ci (port->rport_task == RPORT_ADD) ? 'a' : 'd', 80662306a36Sopenharmony_ci port->wwpn); /* < WORKER_DESC_LEN=24 */ 80762306a36Sopenharmony_ci while (port->rport_task) { 80862306a36Sopenharmony_ci if (port->rport_task == RPORT_ADD) { 80962306a36Sopenharmony_ci port->rport_task = RPORT_NONE; 81062306a36Sopenharmony_ci zfcp_scsi_rport_register(port); 81162306a36Sopenharmony_ci } else { 81262306a36Sopenharmony_ci port->rport_task = RPORT_NONE; 81362306a36Sopenharmony_ci zfcp_scsi_rport_block(port); 81462306a36Sopenharmony_ci } 81562306a36Sopenharmony_ci } 81662306a36Sopenharmony_ci 81762306a36Sopenharmony_ci put_device(&port->dev); 81862306a36Sopenharmony_ci} 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_ci/** 82162306a36Sopenharmony_ci * zfcp_scsi_set_prot - Configure DIF/DIX support in scsi_host 82262306a36Sopenharmony_ci * @adapter: The adapter where to configure DIF/DIX for the SCSI host 82362306a36Sopenharmony_ci */ 82462306a36Sopenharmony_civoid zfcp_scsi_set_prot(struct zfcp_adapter *adapter) 82562306a36Sopenharmony_ci{ 82662306a36Sopenharmony_ci unsigned int mask = 0; 82762306a36Sopenharmony_ci unsigned int data_div; 82862306a36Sopenharmony_ci struct Scsi_Host *shost = adapter->scsi_host; 82962306a36Sopenharmony_ci 83062306a36Sopenharmony_ci data_div = atomic_read(&adapter->status) & 83162306a36Sopenharmony_ci ZFCP_STATUS_ADAPTER_DATA_DIV_ENABLED; 83262306a36Sopenharmony_ci 83362306a36Sopenharmony_ci if ((enable_dif || zfcp_experimental_dix) && 83462306a36Sopenharmony_ci adapter->adapter_features & FSF_FEATURE_DIF_PROT_TYPE1) 83562306a36Sopenharmony_ci mask |= SHOST_DIF_TYPE1_PROTECTION; 83662306a36Sopenharmony_ci 83762306a36Sopenharmony_ci if (zfcp_experimental_dix && data_div && 83862306a36Sopenharmony_ci adapter->adapter_features & FSF_FEATURE_DIX_PROT_TCPIP) { 83962306a36Sopenharmony_ci mask |= SHOST_DIX_TYPE1_PROTECTION; 84062306a36Sopenharmony_ci scsi_host_set_guard(shost, SHOST_DIX_GUARD_IP); 84162306a36Sopenharmony_ci shost->sg_prot_tablesize = adapter->qdio->max_sbale_per_req / 2; 84262306a36Sopenharmony_ci shost->sg_tablesize = adapter->qdio->max_sbale_per_req / 2; 84362306a36Sopenharmony_ci shost->max_sectors = shost->sg_tablesize * 8; 84462306a36Sopenharmony_ci } 84562306a36Sopenharmony_ci 84662306a36Sopenharmony_ci scsi_host_set_prot(shost, mask); 84762306a36Sopenharmony_ci} 84862306a36Sopenharmony_ci 84962306a36Sopenharmony_ci/** 85062306a36Sopenharmony_ci * zfcp_scsi_dif_sense_error - Report DIF/DIX error as driver sense error 85162306a36Sopenharmony_ci * @scmd: The SCSI command to report the error for 85262306a36Sopenharmony_ci * @ascq: The ASCQ to put in the sense buffer 85362306a36Sopenharmony_ci * 85462306a36Sopenharmony_ci * See the error handling in sd_done for the sense codes used here. 85562306a36Sopenharmony_ci * Set DID_SOFT_ERROR to retry the request, if possible. 85662306a36Sopenharmony_ci */ 85762306a36Sopenharmony_civoid zfcp_scsi_dif_sense_error(struct scsi_cmnd *scmd, int ascq) 85862306a36Sopenharmony_ci{ 85962306a36Sopenharmony_ci scsi_build_sense(scmd, 1, ILLEGAL_REQUEST, 0x10, ascq); 86062306a36Sopenharmony_ci set_host_byte(scmd, DID_SOFT_ERROR); 86162306a36Sopenharmony_ci} 86262306a36Sopenharmony_ci 86362306a36Sopenharmony_civoid zfcp_scsi_shost_update_config_data( 86462306a36Sopenharmony_ci struct zfcp_adapter *const adapter, 86562306a36Sopenharmony_ci const struct fsf_qtcb_bottom_config *const bottom, 86662306a36Sopenharmony_ci const bool bottom_incomplete) 86762306a36Sopenharmony_ci{ 86862306a36Sopenharmony_ci struct Scsi_Host *const shost = adapter->scsi_host; 86962306a36Sopenharmony_ci const struct fc_els_flogi *nsp, *plogi; 87062306a36Sopenharmony_ci 87162306a36Sopenharmony_ci if (shost == NULL) 87262306a36Sopenharmony_ci return; 87362306a36Sopenharmony_ci 87462306a36Sopenharmony_ci snprintf(fc_host_firmware_version(shost), FC_VERSION_STRING_SIZE, 87562306a36Sopenharmony_ci "0x%08x", bottom->lic_version); 87662306a36Sopenharmony_ci 87762306a36Sopenharmony_ci if (adapter->adapter_features & FSF_FEATURE_HBAAPI_MANAGEMENT) { 87862306a36Sopenharmony_ci snprintf(fc_host_hardware_version(shost), 87962306a36Sopenharmony_ci FC_VERSION_STRING_SIZE, 88062306a36Sopenharmony_ci "0x%08x", bottom->hardware_version); 88162306a36Sopenharmony_ci memcpy(fc_host_serial_number(shost), bottom->serial_number, 88262306a36Sopenharmony_ci min(FC_SERIAL_NUMBER_SIZE, 17)); 88362306a36Sopenharmony_ci EBCASC(fc_host_serial_number(shost), 88462306a36Sopenharmony_ci min(FC_SERIAL_NUMBER_SIZE, 17)); 88562306a36Sopenharmony_ci } 88662306a36Sopenharmony_ci 88762306a36Sopenharmony_ci /* adjust pointers for missing command code */ 88862306a36Sopenharmony_ci nsp = (struct fc_els_flogi *) ((u8 *)&bottom->nport_serv_param 88962306a36Sopenharmony_ci - sizeof(u32)); 89062306a36Sopenharmony_ci plogi = (struct fc_els_flogi *) ((u8 *)&bottom->plogi_payload 89162306a36Sopenharmony_ci - sizeof(u32)); 89262306a36Sopenharmony_ci 89362306a36Sopenharmony_ci snprintf(fc_host_manufacturer(shost), FC_SERIAL_NUMBER_SIZE, "%s", 89462306a36Sopenharmony_ci "IBM"); 89562306a36Sopenharmony_ci fc_host_port_name(shost) = be64_to_cpu(nsp->fl_wwpn); 89662306a36Sopenharmony_ci fc_host_node_name(shost) = be64_to_cpu(nsp->fl_wwnn); 89762306a36Sopenharmony_ci fc_host_supported_classes(shost) = FC_COS_CLASS2 | FC_COS_CLASS3; 89862306a36Sopenharmony_ci 89962306a36Sopenharmony_ci zfcp_scsi_set_prot(adapter); 90062306a36Sopenharmony_ci 90162306a36Sopenharmony_ci /* do not evaluate invalid fields */ 90262306a36Sopenharmony_ci if (bottom_incomplete) 90362306a36Sopenharmony_ci return; 90462306a36Sopenharmony_ci 90562306a36Sopenharmony_ci fc_host_port_id(shost) = ntoh24(bottom->s_id); 90662306a36Sopenharmony_ci fc_host_speed(shost) = 90762306a36Sopenharmony_ci zfcp_fsf_convert_portspeed(bottom->fc_link_speed); 90862306a36Sopenharmony_ci 90962306a36Sopenharmony_ci snprintf(fc_host_model(shost), FC_SYMBOLIC_NAME_SIZE, "0x%04x", 91062306a36Sopenharmony_ci bottom->adapter_type); 91162306a36Sopenharmony_ci 91262306a36Sopenharmony_ci switch (bottom->fc_topology) { 91362306a36Sopenharmony_ci case FSF_TOPO_P2P: 91462306a36Sopenharmony_ci fc_host_port_type(shost) = FC_PORTTYPE_PTP; 91562306a36Sopenharmony_ci fc_host_fabric_name(shost) = 0; 91662306a36Sopenharmony_ci break; 91762306a36Sopenharmony_ci case FSF_TOPO_FABRIC: 91862306a36Sopenharmony_ci fc_host_fabric_name(shost) = be64_to_cpu(plogi->fl_wwnn); 91962306a36Sopenharmony_ci if (bottom->connection_features & FSF_FEATURE_NPIV_MODE) 92062306a36Sopenharmony_ci fc_host_port_type(shost) = FC_PORTTYPE_NPIV; 92162306a36Sopenharmony_ci else 92262306a36Sopenharmony_ci fc_host_port_type(shost) = FC_PORTTYPE_NPORT; 92362306a36Sopenharmony_ci break; 92462306a36Sopenharmony_ci case FSF_TOPO_AL: 92562306a36Sopenharmony_ci fc_host_port_type(shost) = FC_PORTTYPE_NLPORT; 92662306a36Sopenharmony_ci fallthrough; 92762306a36Sopenharmony_ci default: 92862306a36Sopenharmony_ci fc_host_fabric_name(shost) = 0; 92962306a36Sopenharmony_ci break; 93062306a36Sopenharmony_ci } 93162306a36Sopenharmony_ci} 93262306a36Sopenharmony_ci 93362306a36Sopenharmony_civoid zfcp_scsi_shost_update_port_data( 93462306a36Sopenharmony_ci struct zfcp_adapter *const adapter, 93562306a36Sopenharmony_ci const struct fsf_qtcb_bottom_port *const bottom) 93662306a36Sopenharmony_ci{ 93762306a36Sopenharmony_ci struct Scsi_Host *const shost = adapter->scsi_host; 93862306a36Sopenharmony_ci 93962306a36Sopenharmony_ci if (shost == NULL) 94062306a36Sopenharmony_ci return; 94162306a36Sopenharmony_ci 94262306a36Sopenharmony_ci fc_host_permanent_port_name(shost) = bottom->wwpn; 94362306a36Sopenharmony_ci fc_host_maxframe_size(shost) = bottom->maximum_frame_size; 94462306a36Sopenharmony_ci fc_host_supported_speeds(shost) = 94562306a36Sopenharmony_ci zfcp_fsf_convert_portspeed(bottom->supported_speed); 94662306a36Sopenharmony_ci memcpy(fc_host_supported_fc4s(shost), bottom->supported_fc4_types, 94762306a36Sopenharmony_ci FC_FC4_LIST_SIZE); 94862306a36Sopenharmony_ci memcpy(fc_host_active_fc4s(shost), bottom->active_fc4_types, 94962306a36Sopenharmony_ci FC_FC4_LIST_SIZE); 95062306a36Sopenharmony_ci} 95162306a36Sopenharmony_ci 95262306a36Sopenharmony_cistruct fc_function_template zfcp_transport_functions = { 95362306a36Sopenharmony_ci .show_starget_port_id = 1, 95462306a36Sopenharmony_ci .show_starget_port_name = 1, 95562306a36Sopenharmony_ci .show_starget_node_name = 1, 95662306a36Sopenharmony_ci .show_rport_supported_classes = 1, 95762306a36Sopenharmony_ci .show_rport_maxframe_size = 1, 95862306a36Sopenharmony_ci .show_rport_dev_loss_tmo = 1, 95962306a36Sopenharmony_ci .show_host_node_name = 1, 96062306a36Sopenharmony_ci .show_host_port_name = 1, 96162306a36Sopenharmony_ci .show_host_permanent_port_name = 1, 96262306a36Sopenharmony_ci .show_host_supported_classes = 1, 96362306a36Sopenharmony_ci .show_host_supported_fc4s = 1, 96462306a36Sopenharmony_ci .show_host_supported_speeds = 1, 96562306a36Sopenharmony_ci .show_host_maxframe_size = 1, 96662306a36Sopenharmony_ci .show_host_serial_number = 1, 96762306a36Sopenharmony_ci .show_host_manufacturer = 1, 96862306a36Sopenharmony_ci .show_host_model = 1, 96962306a36Sopenharmony_ci .show_host_hardware_version = 1, 97062306a36Sopenharmony_ci .show_host_firmware_version = 1, 97162306a36Sopenharmony_ci .get_fc_host_stats = zfcp_scsi_get_fc_host_stats, 97262306a36Sopenharmony_ci .reset_fc_host_stats = zfcp_scsi_reset_fc_host_stats, 97362306a36Sopenharmony_ci .set_rport_dev_loss_tmo = zfcp_scsi_set_rport_dev_loss_tmo, 97462306a36Sopenharmony_ci .get_host_port_state = zfcp_scsi_get_host_port_state, 97562306a36Sopenharmony_ci .terminate_rport_io = zfcp_scsi_terminate_rport_io, 97662306a36Sopenharmony_ci .show_host_port_state = 1, 97762306a36Sopenharmony_ci .show_host_active_fc4s = 1, 97862306a36Sopenharmony_ci .bsg_request = zfcp_fc_exec_bsg_job, 97962306a36Sopenharmony_ci .bsg_timeout = zfcp_fc_timeout_bsg_job, 98062306a36Sopenharmony_ci /* no functions registered for following dynamic attributes but 98162306a36Sopenharmony_ci directly set by LLDD */ 98262306a36Sopenharmony_ci .show_host_port_type = 1, 98362306a36Sopenharmony_ci .show_host_symbolic_name = 1, 98462306a36Sopenharmony_ci .show_host_speed = 1, 98562306a36Sopenharmony_ci .show_host_port_id = 1, 98662306a36Sopenharmony_ci .show_host_fabric_name = 1, 98762306a36Sopenharmony_ci .dd_bsg_size = sizeof(struct zfcp_fsf_ct_els), 98862306a36Sopenharmony_ci}; 989