From 290237d2aa832ec418e9abb229f6869aa8b6dbb5 Mon Sep 17 00:00:00 2001 From: Sebastian Herbszt Date: Mon, 31 Aug 2015 16:48:08 -0400 Subject: lpfc: fix model description Remove trailing space from model description. Signed-off-by: Sebastian Herbszt Signed-off-by: James Smart Reviewed-by: Hannes Reinecke Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc_init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index f962118..1992e74 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -2253,7 +2253,7 @@ lpfc_get_hba_model_desc(struct lpfc_hba *phba, uint8_t *mdp, uint8_t *descp) phba->Port); else if (max_speed == 0) snprintf(descp, 255, - "Emulex %s %s %s ", + "Emulex %s %s %s", m.name, m.bus, m.function); else snprintf(descp, 255, -- cgit v1.1 From c6cb9b4fd984334b420115e6a504a2ef92cf7f3f Mon Sep 17 00:00:00 2001 From: Firo Yang Date: Mon, 31 Aug 2015 16:48:09 -0400 Subject: lpfc: Remove unnessary cast kzalloc() returns a void pointer - no need to cast it in drivers/scsi/lpfc/lpfc_init.c::lpfc_sli_driver_resource_setup() Signed-off-by: Firo Yang Signed-off-by: James Smart Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc_init.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 1992e74..da9b6fc 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -4982,8 +4982,7 @@ lpfc_sli_driver_resource_setup(struct lpfc_hba *phba) } if (!phba->sli.ring) - phba->sli.ring = (struct lpfc_sli_ring *) - kzalloc(LPFC_SLI3_MAX_RING * + phba->sli.ring = kzalloc(LPFC_SLI3_MAX_RING * sizeof(struct lpfc_sli_ring), GFP_KERNEL); if (!phba->sli.ring) return -ENOMEM; -- cgit v1.1 From 5f406fae01e4243d128956421815518d00212c3a Mon Sep 17 00:00:00 2001 From: Bodo Stroesser Date: Mon, 31 Aug 2015 16:48:10 -0400 Subject: lpfc: in sli3 use configured sg_seg_cnt for sg_tablesize Currently the module parameter lpfc_sg_seg_count does not have effect for sli3 devices. In lpfc_sli_driver_resource_setup(), which is used for sli3, the code writes the configured sg_seg_cnt into lpfc_template.sg_tablesize. But lpfc_template is the template used for sli4 only. Thus the value should correctly be written to lpfc_template_s3->sg_tablesize. This patch is for kernel 4.1-rc5, but is tested with lpfc 10.2.405.26 only. Signed-off-by: Bodo Stroesser Signed-off-by: James Smart Reviewed-by: Sebastian Herbszt Reviewed-by: Hannes Reinecke Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc_init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index da9b6fc..81bfb2d 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -4994,7 +4994,7 @@ lpfc_sli_driver_resource_setup(struct lpfc_hba *phba) /* Initialize the host templates the configured values. */ lpfc_vport_template.sg_tablesize = phba->cfg_sg_seg_cnt; - lpfc_template.sg_tablesize = phba->cfg_sg_seg_cnt; + lpfc_template_s3.sg_tablesize = phba->cfg_sg_seg_cnt; /* There are going to be 2 reserved BDEs: 1 FCP cmnd + 1 FCP rsp */ if (phba->cfg_enable_bg) { -- cgit v1.1 From 7973967f803da922af10599fb2bf4d66889e40d1 Mon Sep 17 00:00:00 2001 From: Johannes Thumshirn Date: Mon, 31 Aug 2015 16:48:11 -0400 Subject: lpfc: Destroy lpfc_hba_index IDR on module exit Destroy lpfc_hba_index IDR on module exit, reclaiming the allocated memory. This was detected by the following semantic patch (written by Luis Rodriguez ) @ defines_module_init @ declarer name module_init, module_exit; declarer name DEFINE_IDR; identifier init; @@ module_init(init); @ defines_module_exit @ identifier exit; @@ module_exit(exit); @ declares_idr depends on defines_module_init && defines_module_exit @ identifier idr; @@ DEFINE_IDR(idr); @ on_exit_calls_destroy depends on declares_idr && defines_module_exit @ identifier declares_idr.idr, defines_module_exit.exit; @@ exit(void) { ... idr_destroy(&idr); ... } @ missing_module_idr_destroy depends on declares_idr && defines_module_exit && !on_exit_calls_destroy @ identifier declares_idr.idr, defines_module_exit.exit; @@ exit(void) { ... +idr_destroy(&idr); } Signed-off-by: Johannes Thumshirn Signed-off-by: James Smart Reviewed-by: Hannes Reinecke Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc_init.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 81bfb2d..eaf121a 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -11476,6 +11476,7 @@ lpfc_exit(void) free_pages((unsigned long)_dump_buf_dif, _dump_buf_dif_order); } kfree(lpfc_used_cpu); + idr_destroy(&lpfc_hba_index); } module_init(lpfc_init); -- cgit v1.1 From c0365c0692d6ea038bb4feda308eec69e11292a3 Mon Sep 17 00:00:00 2001 From: Ian Mitchell Date: Mon, 31 Aug 2015 16:48:12 -0400 Subject: Fix kmalloc overflow in LPFC driver at large core count This patch allows the LPFC to start up without a fatal kernel bug based on an exceeded KMALLOC_MAX_SIZE and a too large NR_CPU-based maskbits field. The bug was based on the number of CPU cores in a system. Using the get_cpu_mask() function declared in kernel/cpu.c allows the driver to load on the community kernel 4.2 RC1. Below is the kernel bug reproduced: 8<-------------------------------------------------------------------- 2199382.828437 ( 0.005216)| lpfc 0003:02:00.0: enabling device (0140 -> 0142) 2199382.999272 ( 0.170835)| ------------[ cut here ]------------ 2199382.999337 ( 0.000065)| WARNING: CPU: 84 PID: 404 at mm/slab_common.c:653 kmalloc_slab+0x2f/0x89() 2199383.004534 ( 0.005197)| Modules linked in: lpfc(+) usbcore(+) mptctl scsi_transport_fc sg lpc_ich i2c_i801 usb_common tpm_tis mfd_core tpm acpi_cpufreq button scsi_dh_alua scsi_dh_rdacusbcore: registered new device driver usb 2199383.020568 ( 0.016034)| 2199383.020581 ( 0.000013)| scsi_dh_hp_sw scsi_dh_emc scsi_dh gru thermal sata_nv processor piix fan thermal_sysehci_hcd: USB 2.0 'Enhanced' Host Controller (EHCI) Driver 2199383.035288 ( 0.014707)| 2199383.035306 ( 0.000018)| hwmon ata_piix 2199383.035336 ( 0.000030)| CPU: 84 PID: 404 Comm: kworker/84:0 Not tainted 3.18.0-rc2-gat-00106-ga7ca10f-dirty #178 2199383.047077 ( 0.011741)| ehci-pci: EHCI PCI platform driver 2199383.047134 ( 0.000057)| Hardware name: SGI UV2000/ROMLEY, BIOS SGI UV 2000/3000 series BIOS 01/15/2013 2199383.056245 ( 0.009111)| Workqueue: events work_for_cpu_fn 2199383.066174 ( 0.009929)| 000000000000028d ffff88eef827bbe8 ffffffff815a542f 000000000000028d 2199383.069545 ( 0.003371)| ffffffff810ea142 ffff88eef827bc28 ffffffff8104365c ffff88eefe4006c8 2199383.076214 ( 0.006669)| 0000000000000000 00000000000080d0 0000000000000000 0000000000000004 2199383.079213 ( 0.002999)| Call Trace: 2199383.084084 ( 0.004871)| [] dump_stack+0x49/0x62 2199383.087283 ( 0.003199)| [] ? kmalloc_slab+0x2f/0x89 2199383.091415 ( 0.004132)| [] warn_slowpath_common+0x77/0x92 2199383.095197 ( 0.003782)| [] warn_slowpath_null+0x15/0x17 2199383.103336 ( 0.008139)| [] kmalloc_slab+0x2f/0x89 2199383.107082 ( 0.003746)| [] __kmalloc+0x13/0x16a 2199383.112531 ( 0.005449)| [] lpfc_pci_probe_one_s4+0x105b/0x1644 [lpfc] 2199383.115316 ( 0.002785)| [] ? pci_bus_read_config_dword+0x75/0x87 2199383.123431 ( 0.008115)| [] lpfc_pci_probe_one+0x5d/0xcb5 [lpfc] 2199383.127364 ( 0.003933)| [] ? dbs_check_cpu+0x168/0x177 2199383.136438 ( 0.009074)| [] ? gov_queue_work+0xb4/0xc0 2199383.140407 ( 0.003969)| [] local_pci_probe+0x1e/0x52 2199383.143105 ( 0.002698)| [] work_for_cpu_fn+0x13/0x1b 2199383.147315 ( 0.004210)| [] process_one_work+0x222/0x35e 2199383.151379 ( 0.004064)| [] worker_thread+0x3d5/0x46e 2199383.159402 ( 0.008023)| [] ? process_one_work+0x35e/0x35e 2199383.163097 ( 0.003695)| [] kthread+0xc8/0xd2 2199383.167476 ( 0.004379)| [] ? kthread_freezable_should_stop+0x5b/0x5b 2199383.176434 ( 0.008958)| [] ret_from_fork+0x7c/0xb0 2199383.180086 ( 0.003652)| [] ? kthread_freezable_should_stop+0x5b/0x5b 2199383.192333 ( 0.012247)| ehci-pci 0000:00:1a.0: EHCI Host Controller -------------------------------------------------------------------->8 The proposed solution was approved by James Smart at Emulex and tested on a UV2 machine with 6144 cores. With the fix, the LPFC module loads with no unwanted effects on the system. Signed-off-by: Ian Mitchell Signed-off-by: Alex Thorlton Suggested-by: Robert Elliot [james.smart: resolve unused variable warning] Signed-off-by: James Smart Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc_init.c | 6 +----- drivers/scsi/lpfc/lpfc_sli4.h | 1 - 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index eaf121a..bedbfe6 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -8678,7 +8678,6 @@ lpfc_sli4_set_affinity(struct lpfc_hba *phba, int vectors) #ifdef CONFIG_X86 struct cpuinfo_x86 *cpuinfo; #endif - struct cpumask *mask; uint8_t chann[LPFC_FCP_IO_CHAN_MAX+1]; /* If there is no mapping, just return */ @@ -8772,11 +8771,8 @@ found: first_cpu = cpu; /* Now affinitize to the selected CPU */ - mask = &cpup->maskbits; - cpumask_clear(mask); - cpumask_set_cpu(cpu, mask); i = irq_set_affinity_hint(phba->sli4_hba.msix_entries[idx]. - vector, mask); + vector, get_cpu_mask(cpu)); lpfc_printf_log(phba, KERN_INFO, LOG_INIT, "3330 Set Affinity: CPU %d channel %d " diff --git a/drivers/scsi/lpfc/lpfc_sli4.h b/drivers/scsi/lpfc/lpfc_sli4.h index d1a5b05..1e916e1 100644 --- a/drivers/scsi/lpfc/lpfc_sli4.h +++ b/drivers/scsi/lpfc/lpfc_sli4.h @@ -454,7 +454,6 @@ struct lpfc_vector_map_info { uint16_t core_id; uint16_t irq; uint16_t channel_id; - struct cpumask maskbits; }; #define LPFC_VECTOR_MAP_EMPTY 0xffff -- cgit v1.1 From 3bb11fc5d0584adc075ddc6b42abdfb2ee776e9d Mon Sep 17 00:00:00 2001 From: Nicholas Krause Date: Mon, 31 Aug 2015 16:48:13 -0400 Subject: lpfc:Make the function lpfc_sli4_mbox_completions_pending static in order to comply with function prototype This makes the function lpfc_sli4_mbox_completion's definition static now in order to comply with its prototype being also declared as static too. Signed-off-by: Nicholas Krause Signed-off-by: James Smart Reviewed-by: Sebastian Herbszt Reviewed-by: Hannes Reinecke Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc_sli.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 4feb931..95d53c7 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -6696,7 +6696,7 @@ lpfc_mbox_timeout(unsigned long ptr) * This function checks if any mailbox completions are present on the mailbox * completion queue. **/ -bool +static bool lpfc_sli4_mbox_completions_pending(struct lpfc_hba *phba) { -- cgit v1.1 From db6f1c2f900b536d23de386dc7f2a53aa80d7307 Mon Sep 17 00:00:00 2001 From: Sebastian Herbszt Date: Mon, 31 Aug 2015 16:48:14 -0400 Subject: lpfc: remove set but not used variables Remove set but not used variables. Signed-off-by: Sebastian Herbszt Signed-off-by: James Smart Reviewed-by: Hannes Reinecke Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc_attr.c | 6 ---- drivers/scsi/lpfc/lpfc_bsg.c | 20 -------------- drivers/scsi/lpfc/lpfc_ct.c | 5 ---- drivers/scsi/lpfc/lpfc_els.c | 56 +------------------------------------- drivers/scsi/lpfc/lpfc_hbadisc.c | 11 +++----- drivers/scsi/lpfc/lpfc_init.c | 4 +-- drivers/scsi/lpfc/lpfc_mbox.c | 8 ------ drivers/scsi/lpfc/lpfc_nportdisc.c | 2 -- drivers/scsi/lpfc/lpfc_scsi.c | 14 +--------- drivers/scsi/lpfc/lpfc_sli.c | 8 ------ 10 files changed, 8 insertions(+), 126 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index d65bd17..3c6cc9d 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -1642,8 +1642,6 @@ lpfc_##attr##_show(struct device *dev, struct device_attribute *attr, \ struct Scsi_Host *shost = class_to_shost(dev);\ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;\ struct lpfc_hba *phba = vport->phba;\ - uint val = 0;\ - val = phba->cfg_##attr;\ return snprintf(buf, PAGE_SIZE, "%d\n",\ phba->cfg_##attr);\ } @@ -1808,8 +1806,6 @@ lpfc_##attr##_show(struct device *dev, struct device_attribute *attr, \ { \ struct Scsi_Host *shost = class_to_shost(dev);\ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;\ - uint val = 0;\ - val = vport->cfg_##attr;\ return snprintf(buf, PAGE_SIZE, "%d\n", vport->cfg_##attr);\ } @@ -1835,8 +1831,6 @@ lpfc_##attr##_show(struct device *dev, struct device_attribute *attr, \ { \ struct Scsi_Host *shost = class_to_shost(dev);\ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;\ - uint val = 0;\ - val = vport->cfg_##attr;\ return snprintf(buf, PAGE_SIZE, "%#x\n", vport->cfg_##attr);\ } diff --git a/drivers/scsi/lpfc/lpfc_bsg.c b/drivers/scsi/lpfc/lpfc_bsg.c index b705068..05dcc2a 100644 --- a/drivers/scsi/lpfc/lpfc_bsg.c +++ b/drivers/scsi/lpfc/lpfc_bsg.c @@ -904,7 +904,6 @@ lpfc_bsg_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, { uint32_t evt_req_id = 0; uint32_t cmd; - uint32_t len; struct lpfc_dmabuf *dmabuf = NULL; struct lpfc_bsg_event *evt; struct event_data *evt_dat = NULL; @@ -946,7 +945,6 @@ lpfc_bsg_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, ct_req = (struct lpfc_sli_ct_request *)dmabuf->virt; evt_req_id = ct_req->FsType; cmd = ct_req->CommandResponse.bits.CmdRsp; - len = ct_req->CommandResponse.bits.Size; if (!(phba->sli3_options & LPFC_SLI3_HBQ_ENABLED)) lpfc_sli_ringpostbuf_put(phba, pring, dmabuf); @@ -2988,7 +2986,6 @@ lpfc_bsg_diag_loopback_run(struct fc_bsg_job *job) { struct lpfc_vport *vport = (struct lpfc_vport *)job->shost->hostdata; struct lpfc_hba *phba = vport->phba; - struct diag_mode_test *diag_mode; struct lpfc_bsg_event *evt; struct event_data *evdat; struct lpfc_sli *psli = &phba->sli; @@ -3031,8 +3028,6 @@ lpfc_bsg_diag_loopback_run(struct fc_bsg_job *job) rc = -EINVAL; goto loopback_test_exit; } - diag_mode = (struct diag_mode_test *) - job->request->rqst_data.h_vendor.vendor_cmd; if ((phba->link_state == LPFC_HBA_ERROR) || (psli->sli_flag & LPFC_BLOCK_MGMT_IO) || @@ -3293,7 +3288,6 @@ lpfc_bsg_get_dfc_rev(struct fc_bsg_job *job) { struct lpfc_vport *vport = (struct lpfc_vport *)job->shost->hostdata; struct lpfc_hba *phba = vport->phba; - struct get_mgmt_rev *event_req; struct get_mgmt_rev_reply *event_reply; int rc = 0; @@ -3306,9 +3300,6 @@ lpfc_bsg_get_dfc_rev(struct fc_bsg_job *job) goto job_error; } - event_req = (struct get_mgmt_rev *) - job->request->rqst_data.h_vendor.vendor_cmd; - event_reply = (struct get_mgmt_rev_reply *) job->reply->reply_data.vendor_reply.vendor_rsp; @@ -4348,7 +4339,6 @@ static int lpfc_bsg_write_ebuf_set(struct lpfc_hba *phba, struct fc_bsg_job *job, struct lpfc_dmabuf *dmabuf) { - struct lpfc_sli_config_mbox *sli_cfg_mbx; struct bsg_job_data *dd_data = NULL; LPFC_MBOXQ_t *pmboxq = NULL; MAILBOX_t *pmb; @@ -4362,9 +4352,6 @@ lpfc_bsg_write_ebuf_set(struct lpfc_hba *phba, struct fc_bsg_job *job, phba->mbox_ext_buf_ctx.seqNum++; nemb_tp = phba->mbox_ext_buf_ctx.nembType; - sli_cfg_mbx = (struct lpfc_sli_config_mbox *) - phba->mbox_ext_buf_ctx.mbx_dmabuf->virt; - dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL); if (!dd_data) { rc = -ENOMEM; @@ -4606,7 +4593,6 @@ lpfc_bsg_issue_mbox(struct lpfc_hba *phba, struct fc_bsg_job *job, uint32_t transmit_length, receive_length, mode; struct lpfc_mbx_sli4_config *sli4_config; struct lpfc_mbx_nembed_cmd *nembed_sge; - struct mbox_header *header; struct ulp_bde64 *bde; uint8_t *ext = NULL; int rc = 0; @@ -4804,8 +4790,6 @@ lpfc_bsg_issue_mbox(struct lpfc_hba *phba, struct fc_bsg_job *job, /* rebuild the command for sli4 using our * own buffers like we do for biu diags */ - header = (struct mbox_header *) - &pmb->un.varWords[0]; nembed_sge = (struct lpfc_mbx_nembed_cmd *) &pmb->un.varWords[0]; receive_length = nembed_sge->sge[0].length; @@ -5048,7 +5032,6 @@ lpfc_menlo_cmd(struct fc_bsg_job *job) IOCB_t *cmd; int rc = 0; struct menlo_command *menlo_cmd; - struct menlo_response *menlo_resp; struct lpfc_dmabuf *bmp = NULL, *cmp = NULL, *rmp = NULL; int request_nseg; int reply_nseg; @@ -5088,9 +5071,6 @@ lpfc_menlo_cmd(struct fc_bsg_job *job) menlo_cmd = (struct menlo_command *) job->request->rqst_data.h_vendor.vendor_cmd; - menlo_resp = (struct menlo_response *) - job->reply->reply_data.vendor_reply.vendor_rsp; - /* allocate our bsg tracking structure */ dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL); if (!dd_data) { diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c index af12996..aaf1cd74 100644 --- a/drivers/scsi/lpfc/lpfc_ct.c +++ b/drivers/scsi/lpfc/lpfc_ct.c @@ -575,7 +575,6 @@ lpfc_cmpl_ct_cmd_gid_ft(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, struct lpfc_vport *vport = cmdiocb->vport; struct Scsi_Host *shost = lpfc_shost_from_vport(vport); IOCB_t *irsp; - struct lpfc_dmabuf *bmp; struct lpfc_dmabuf *outp; struct lpfc_sli_ct_request *CTrsp; struct lpfc_nodelist *ndlp; @@ -588,7 +587,6 @@ lpfc_cmpl_ct_cmd_gid_ft(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, cmdiocb->context_un.rsp_iocb = rspiocb; outp = (struct lpfc_dmabuf *) cmdiocb->context2; - bmp = (struct lpfc_dmabuf *) cmdiocb->context3; irsp = &rspiocb->iocb; lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_CT, @@ -1733,12 +1731,9 @@ hba_out: case SLI_MGMT_RPRT: case SLI_MGMT_RPA: { - lpfc_vpd_t *vp; struct serv_parm *hsp; int len = 0; - vp = &phba->vpd; - if (cmdcode == SLI_MGMT_RPRT) { rh = (struct lpfc_fdmi_reg_hba *) &CtReq->un.PortID; diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index 36bf58b..c859aa3 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -457,11 +457,9 @@ lpfc_issue_reg_vfi(struct lpfc_vport *vport) struct lpfc_hba *phba = vport->phba; LPFC_MBOXQ_t *mboxq; struct lpfc_nodelist *ndlp; - struct serv_parm *sp; struct lpfc_dmabuf *dmabuf; int rc = 0; - sp = &phba->fc_fabparam; /* move forward in case of SLI4 FC port loopback test and pt2pt mode */ if ((phba->sli_rev == LPFC_SLI_REV4) && !(phba->link_flag & LS_LOOPBACK_MODE) && @@ -1205,14 +1203,11 @@ lpfc_issue_els_flogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, struct serv_parm *sp; IOCB_t *icmd; struct lpfc_iocbq *elsiocb; - struct lpfc_sli_ring *pring; uint8_t *pcmd; uint16_t cmdsize; uint32_t tmo; int rc; - pring = &phba->sli.ring[LPFC_ELS_RING]; - cmdsize = (sizeof(uint32_t) + sizeof(struct serv_parm)); elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp, ndlp->nlp_DID, ELS_CMD_FLOGI); @@ -1454,8 +1449,6 @@ lpfc_initial_fdisc(struct lpfc_vport *vport) void lpfc_more_plogi(struct lpfc_vport *vport) { - int sentplogi; - if (vport->num_disc_nodes) vport->num_disc_nodes--; @@ -1468,7 +1461,7 @@ lpfc_more_plogi(struct lpfc_vport *vport) /* Check to see if there are more PLOGIs to be sent */ if (vport->fc_flag & FC_NLP_MORE) /* go thru NPR nodes and issue any remaining ELS PLOGIs */ - sentplogi = lpfc_els_disc_plogi(vport); + lpfc_els_disc_plogi(vport); return; } @@ -1956,16 +1949,12 @@ lpfc_issue_els_plogi(struct lpfc_vport *vport, uint32_t did, uint8_t retry) { struct lpfc_hba *phba = vport->phba; struct serv_parm *sp; - IOCB_t *icmd; struct lpfc_nodelist *ndlp; struct lpfc_iocbq *elsiocb; - struct lpfc_sli *psli; uint8_t *pcmd; uint16_t cmdsize; int ret; - psli = &phba->sli; - ndlp = lpfc_findnode_did(vport, did); if (ndlp && !NLP_CHK_NODE_ACT(ndlp)) ndlp = NULL; @@ -1977,7 +1966,6 @@ lpfc_issue_els_plogi(struct lpfc_vport *vport, uint32_t did, uint8_t retry) if (!elsiocb) return 1; - icmd = &elsiocb->iocb; pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt); /* For PLOGI request, remainder of payload is service parameters */ @@ -2034,10 +2022,8 @@ lpfc_cmpl_els_prli(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, struct lpfc_vport *vport = cmdiocb->vport; struct Scsi_Host *shost = lpfc_shost_from_vport(vport); IOCB_t *irsp; - struct lpfc_sli *psli; struct lpfc_nodelist *ndlp; - psli = &phba->sli; /* we pass cmdiocb to state machine which needs rspiocb as well */ cmdiocb->context_un.rsp_iocb = rspiocb; @@ -2117,7 +2103,6 @@ lpfc_issue_els_prli(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, struct Scsi_Host *shost = lpfc_shost_from_vport(vport); struct lpfc_hba *phba = vport->phba; PRLI *npr; - IOCB_t *icmd; struct lpfc_iocbq *elsiocb; uint8_t *pcmd; uint16_t cmdsize; @@ -2128,7 +2113,6 @@ lpfc_issue_els_prli(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, if (!elsiocb) return 1; - icmd = &elsiocb->iocb; pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt); /* For PRLI request, remainder of payload is service parameters */ @@ -2413,7 +2397,6 @@ lpfc_issue_els_adisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, struct Scsi_Host *shost = lpfc_shost_from_vport(vport); struct lpfc_hba *phba = vport->phba; ADISC *ap; - IOCB_t *icmd; struct lpfc_iocbq *elsiocb; uint8_t *pcmd; uint16_t cmdsize; @@ -2424,7 +2407,6 @@ lpfc_issue_els_adisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, if (!elsiocb) return 1; - icmd = &elsiocb->iocb; pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt); /* For ADISC request, remainder of payload is service parameters */ @@ -2478,12 +2460,10 @@ lpfc_cmpl_els_logo(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, struct lpfc_vport *vport = ndlp->vport; struct Scsi_Host *shost = lpfc_shost_from_vport(vport); IOCB_t *irsp; - struct lpfc_sli *psli; struct lpfcMboxq *mbox; unsigned long flags; uint32_t skip_recovery = 0; - psli = &phba->sli; /* we pass cmdiocb to state machine which needs rspiocb as well */ cmdiocb->context_un.rsp_iocb = rspiocb; @@ -2609,7 +2589,6 @@ lpfc_issue_els_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, { struct Scsi_Host *shost = lpfc_shost_from_vport(vport); struct lpfc_hba *phba = vport->phba; - IOCB_t *icmd; struct lpfc_iocbq *elsiocb; uint8_t *pcmd; uint16_t cmdsize; @@ -2628,7 +2607,6 @@ lpfc_issue_els_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, if (!elsiocb) return 1; - icmd = &elsiocb->iocb; pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt); *((uint32_t *) (pcmd)) = ELS_CMD_LOGO; pcmd += sizeof(uint32_t); @@ -2742,14 +2720,11 @@ int lpfc_issue_els_scr(struct lpfc_vport *vport, uint32_t nportid, uint8_t retry) { struct lpfc_hba *phba = vport->phba; - IOCB_t *icmd; struct lpfc_iocbq *elsiocb; - struct lpfc_sli *psli; uint8_t *pcmd; uint16_t cmdsize; struct lpfc_nodelist *ndlp; - psli = &phba->sli; cmdsize = (sizeof(uint32_t) + sizeof(SCR)); ndlp = lpfc_findnode_did(vport, nportid); @@ -2776,7 +2751,6 @@ lpfc_issue_els_scr(struct lpfc_vport *vport, uint32_t nportid, uint8_t retry) return 1; } - icmd = &elsiocb->iocb; pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt); *((uint32_t *) (pcmd)) = ELS_CMD_SCR; @@ -2836,9 +2810,7 @@ static int lpfc_issue_els_farpr(struct lpfc_vport *vport, uint32_t nportid, uint8_t retry) { struct lpfc_hba *phba = vport->phba; - IOCB_t *icmd; struct lpfc_iocbq *elsiocb; - struct lpfc_sli *psli; FARP *fp; uint8_t *pcmd; uint32_t *lp; @@ -2846,7 +2818,6 @@ lpfc_issue_els_farpr(struct lpfc_vport *vport, uint32_t nportid, uint8_t retry) struct lpfc_nodelist *ondlp; struct lpfc_nodelist *ndlp; - psli = &phba->sli; cmdsize = (sizeof(uint32_t) + sizeof(FARP)); ndlp = lpfc_findnode_did(vport, nportid); @@ -2872,7 +2843,6 @@ lpfc_issue_els_farpr(struct lpfc_vport *vport, uint32_t nportid, uint8_t retry) return 1; } - icmd = &elsiocb->iocb; pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt); *((uint32_t *) (pcmd)) = ELS_CMD_FARPR; @@ -3922,13 +3892,11 @@ lpfc_els_rsp_acc(struct lpfc_vport *vport, uint32_t flag, IOCB_t *icmd; IOCB_t *oldcmd; struct lpfc_iocbq *elsiocb; - struct lpfc_sli *psli; uint8_t *pcmd; uint16_t cmdsize; int rc; ELS_PKT *els_pkt_ptr; - psli = &phba->sli; oldcmd = &oldiocb->iocb; switch (flag) { @@ -4061,12 +4029,10 @@ lpfc_els_rsp_reject(struct lpfc_vport *vport, uint32_t rejectError, IOCB_t *icmd; IOCB_t *oldcmd; struct lpfc_iocbq *elsiocb; - struct lpfc_sli *psli; uint8_t *pcmd; uint16_t cmdsize; int rc; - psli = &phba->sli; cmdsize = 2 * sizeof(uint32_t); elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, oldiocb->retry, ndlp, ndlp->nlp_DID, ELS_CMD_LS_RJT); @@ -4212,13 +4178,10 @@ lpfc_els_rsp_prli_acc(struct lpfc_vport *vport, struct lpfc_iocbq *oldiocb, IOCB_t *icmd; IOCB_t *oldcmd; struct lpfc_iocbq *elsiocb; - struct lpfc_sli *psli; uint8_t *pcmd; uint16_t cmdsize; int rc; - psli = &phba->sli; - cmdsize = sizeof(uint32_t) + sizeof(PRLI); elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, oldiocb->retry, ndlp, ndlp->nlp_DID, (ELS_CMD_ACC | (ELS_CMD_PRLI & ~ELS_RSP_MASK))); @@ -4315,12 +4278,10 @@ lpfc_els_rsp_rnid_acc(struct lpfc_vport *vport, uint8_t format, RNID *rn; IOCB_t *icmd, *oldcmd; struct lpfc_iocbq *elsiocb; - struct lpfc_sli *psli; uint8_t *pcmd; uint16_t cmdsize; int rc; - psli = &phba->sli; cmdsize = sizeof(uint32_t) + sizeof(uint32_t) + (2 * sizeof(struct lpfc_name)); if (format) @@ -4447,12 +4408,10 @@ lpfc_els_rsp_echo_acc(struct lpfc_vport *vport, uint8_t *data, { struct lpfc_hba *phba = vport->phba; struct lpfc_iocbq *elsiocb; - struct lpfc_sli *psli; uint8_t *pcmd; uint16_t cmdsize; int rc; - psli = &phba->sli; cmdsize = oldiocb->iocb.unsli3.rcvsli3.acc_len; /* The accumulated length can exceed the BPL_SIZE. For @@ -5181,14 +5140,12 @@ lpfc_els_rcv_lcb(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, { struct lpfc_hba *phba = vport->phba; struct lpfc_dmabuf *pcmd; - IOCB_t *icmd; uint8_t *lp; struct fc_lcb_request_frame *beacon; struct lpfc_lcb_context *lcb_context; uint8_t state, rjt_err; struct ls_rjt stat; - icmd = &cmdiocb->iocb; pcmd = (struct lpfc_dmabuf *)cmdiocb->context2; lp = (uint8_t *)pcmd->virt; beacon = (struct fc_lcb_request_frame *)pcmd->virt; @@ -5481,13 +5438,11 @@ lpfc_els_rcv_rscn(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, struct lpfc_hba *phba = vport->phba; struct lpfc_dmabuf *pcmd; uint32_t *lp, *datap; - IOCB_t *icmd; uint32_t payload_len, length, nportid, *cmd; int rscn_cnt; int rscn_id = 0, hba_id = 0; int i; - icmd = &cmdiocb->iocb; pcmd = (struct lpfc_dmabuf *) cmdiocb->context2; lp = (uint32_t *) pcmd->virt; @@ -5943,12 +5898,10 @@ lpfc_els_rcv_rnid(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, { struct lpfc_dmabuf *pcmd; uint32_t *lp; - IOCB_t *icmd; RNID *rn; struct ls_rjt stat; uint32_t cmd; - icmd = &cmdiocb->iocb; pcmd = (struct lpfc_dmabuf *) cmdiocb->context2; lp = (uint32_t *) pcmd->virt; @@ -6259,7 +6212,6 @@ lpfc_els_rcv_rls(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, { struct lpfc_hba *phba = vport->phba; LPFC_MBOXQ_t *mbox; - struct lpfc_dmabuf *pcmd; struct ls_rjt stat; if ((ndlp->nlp_state != NLP_STE_UNMAPPED_NODE) && @@ -6267,8 +6219,6 @@ lpfc_els_rcv_rls(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, /* reject the unsolicited RPS request and done with it */ goto reject_out; - pcmd = (struct lpfc_dmabuf *) cmdiocb->context2; - mbox = mempool_alloc(phba->mbox_mem_pool, GFP_ATOMIC); if (mbox) { lpfc_read_lnk_stat(phba, mbox); @@ -6482,7 +6432,6 @@ lpfc_issue_els_rrq(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, { struct lpfc_hba *phba = vport->phba; struct RRQ *els_rrq; - IOCB_t *icmd; struct lpfc_iocbq *elsiocb; uint8_t *pcmd; uint16_t cmdsize; @@ -6501,7 +6450,6 @@ lpfc_issue_els_rrq(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, if (!elsiocb) return 1; - icmd = &elsiocb->iocb; pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt); /* For RRQ request, remainder of payload is Exchange IDs */ @@ -8428,7 +8376,6 @@ lpfc_issue_els_npiv_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) { struct Scsi_Host *shost = lpfc_shost_from_vport(vport); struct lpfc_hba *phba = vport->phba; - IOCB_t *icmd; struct lpfc_iocbq *elsiocb; uint8_t *pcmd; uint16_t cmdsize; @@ -8439,7 +8386,6 @@ lpfc_issue_els_npiv_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) if (!elsiocb) return 1; - icmd = &elsiocb->iocb; pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt); *((uint32_t *) (pcmd)) = ELS_CMD_LOGO; pcmd += sizeof(uint32_t); diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index 759cbeb..71b9044 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -800,7 +800,6 @@ lpfc_cleanup_rpis(struct lpfc_vport *vport, int remove) struct Scsi_Host *shost = lpfc_shost_from_vport(vport); struct lpfc_hba *phba = vport->phba; struct lpfc_nodelist *ndlp, *next_ndlp; - int rc; list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) { if (!NLP_CHK_NODE_ACT(ndlp)) @@ -816,10 +815,10 @@ lpfc_cleanup_rpis(struct lpfc_vport *vport, int remove) if ((phba->sli_rev < LPFC_SLI_REV4) && (!remove && ndlp->nlp_type & NLP_FABRIC)) continue; - rc = lpfc_disc_state_machine(vport, ndlp, NULL, - remove - ? NLP_EVT_DEVICE_RM - : NLP_EVT_DEVICE_RECOVERY); + lpfc_disc_state_machine(vport, ndlp, NULL, + remove + ? NLP_EVT_DEVICE_RM + : NLP_EVT_DEVICE_RECOVERY); } if (phba->sli3_options & LPFC_SLI3_VPORT_TEARDOWN) { if (phba->sli_rev == LPFC_SLI_REV4) @@ -1774,7 +1773,6 @@ lpfc_sli4_fcf_rec_mbox_parse(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq, uint16_t *next_fcf_index) { void *virt_addr; - dma_addr_t phys_addr; struct lpfc_mbx_sge sge; struct lpfc_mbx_read_fcf_tbl *read_fcf; uint32_t shdr_status, shdr_add_status, if_type; @@ -1785,7 +1783,6 @@ lpfc_sli4_fcf_rec_mbox_parse(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq, * routine only uses a single SGE. */ lpfc_sli4_mbx_sge_get(mboxq, 0, &sge); - phys_addr = getPaddr(sge.pa_hi, sge.pa_lo); if (unlikely(!mboxq->sge_array)) { lpfc_printf_log(phba, KERN_ERR, LOG_MBOX, "2524 Failed to get the non-embedded SGE " diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index bedbfe6..5a97867 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -10282,7 +10282,7 @@ lpfc_pci_probe_one_s4(struct pci_dev *pdev, const struct pci_device_id *pid) struct lpfc_hba *phba; struct lpfc_vport *vport = NULL; struct Scsi_Host *shost = NULL; - int error, ret; + int error; uint32_t cfg_mode, intr_mode; int adjusted_fcp_io_channel; @@ -10406,7 +10406,7 @@ lpfc_pci_probe_one_s4(struct pci_dev *pdev, const struct pci_device_id *pid) /* check for firmware upgrade or downgrade */ if (phba->cfg_request_firmware_upgrade) - ret = lpfc_sli4_request_firmware_update(phba, INT_FW_UPGRADE); + lpfc_sli4_request_firmware_update(phba, INT_FW_UPGRADE); /* Check if there are static vports to be created. */ lpfc_create_static_vport(phba); diff --git a/drivers/scsi/lpfc/lpfc_mbox.c b/drivers/scsi/lpfc/lpfc_mbox.c index 4abb93a..18838ea 100644 --- a/drivers/scsi/lpfc/lpfc_mbox.c +++ b/drivers/scsi/lpfc/lpfc_mbox.c @@ -289,9 +289,7 @@ lpfc_read_topology(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb, struct lpfc_dmabuf *mp) { MAILBOX_t *mb; - struct lpfc_sli *psli; - psli = &phba->sli; mb = &pmb->u.mb; memset(pmb, 0, sizeof (LPFC_MBOXQ_t)); @@ -483,13 +481,11 @@ lpfc_init_link(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb, uint32_t topology, uint32_t linkspeed) { lpfc_vpd_t *vpd; - struct lpfc_sli *psli; MAILBOX_t *mb; mb = &pmb->u.mb; memset(pmb, 0, sizeof (LPFC_MBOXQ_t)); - psli = &phba->sli; switch (topology) { case FLAGS_TOPOLOGY_MODE_LOOP_PT: mb->un.varInitLnk.link_flags = FLAGS_TOPOLOGY_MODE_LOOP; @@ -585,9 +581,7 @@ lpfc_read_sparam(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb, int vpi) { struct lpfc_dmabuf *mp; MAILBOX_t *mb; - struct lpfc_sli *psli; - psli = &phba->sli; mb = &pmb->u.mb; memset(pmb, 0, sizeof (LPFC_MBOXQ_t)); @@ -2010,7 +2004,6 @@ lpfc_sli4_mbx_read_fcf_rec(struct lpfc_hba *phba, uint16_t fcf_index) { void *virt_addr; - dma_addr_t phys_addr; uint8_t *bytep; struct lpfc_mbx_sge sge; uint32_t alloc_len, req_len; @@ -2039,7 +2032,6 @@ lpfc_sli4_mbx_read_fcf_rec(struct lpfc_hba *phba, * routine only uses a single SGE. */ lpfc_sli4_mbx_sge_get(mboxq, 0, &sge); - phys_addr = getPaddr(sge.pa_hi, sge.pa_lo); virt_addr = mboxq->sge_array->addr[0]; read_fcf = (struct lpfc_mbx_read_fcf_tbl *)virt_addr; diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c index af3b38a..ed9a2c8 100644 --- a/drivers/scsi/lpfc/lpfc_nportdisc.c +++ b/drivers/scsi/lpfc/lpfc_nportdisc.c @@ -820,7 +820,6 @@ lpfc_disc_illegal(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, { struct lpfc_hba *phba; LPFC_MBOXQ_t *pmb = (LPFC_MBOXQ_t *) arg; - MAILBOX_t *mb; uint16_t rpi; phba = vport->phba; @@ -828,7 +827,6 @@ lpfc_disc_illegal(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, if (!(phba->pport->load_flag & FC_UNLOADING) && (evt == NLP_EVT_CMPL_REG_LOGIN) && (!pmb->u.mb.mbxStatus)) { - mb = &pmb->u.mb; rpi = pmb->u.mb.un.varWords[0]; lpfc_release_rpi(phba, vport, rpi); } diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index e5eb40d..051b3b3 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -1293,7 +1293,6 @@ lpfc_bg_err_inject(struct lpfc_hba *phba, struct scsi_cmnd *sc, uint32_t *reftag, uint16_t *apptag, uint32_t new_guard) { struct scatterlist *sgpe; /* s/g prot entry */ - struct scatterlist *sgde; /* s/g data entry */ struct lpfc_scsi_buf *lpfc_cmd = NULL; struct scsi_dif_tuple *src = NULL; struct lpfc_nodelist *ndlp; @@ -1309,7 +1308,6 @@ lpfc_bg_err_inject(struct lpfc_hba *phba, struct scsi_cmnd *sc, return 0; sgpe = scsi_prot_sglist(sc); - sgde = scsi_sglist(sc); lba = scsi_get_lba(sc); /* First check if we need to match the LBA */ @@ -1882,7 +1880,6 @@ lpfc_bg_setup_bpl(struct lpfc_hba *phba, struct scsi_cmnd *sc, #endif uint32_t checking = 1; uint32_t reftag; - unsigned blksize; uint8_t txop, rxop; status = lpfc_sc_to_bg_opcodes(phba, sc, &txop, &rxop); @@ -1890,7 +1887,6 @@ lpfc_bg_setup_bpl(struct lpfc_hba *phba, struct scsi_cmnd *sc, goto out; /* extract some info from the scsi command for pde*/ - blksize = lpfc_cmd_blksize(sc); reftag = (uint32_t)scsi_get_lba(sc); /* Truncate LBA */ #ifdef CONFIG_SCSI_LPFC_DEBUG_FS @@ -2263,7 +2259,6 @@ lpfc_bg_setup_sgl(struct lpfc_hba *phba, struct scsi_cmnd *sc, dma_addr_t physaddr; int i = 0, num_sge = 0, status; uint32_t reftag; - unsigned blksize; uint8_t txop, rxop; #ifdef CONFIG_SCSI_LPFC_DEBUG_FS uint32_t rc; @@ -2277,7 +2272,6 @@ lpfc_bg_setup_sgl(struct lpfc_hba *phba, struct scsi_cmnd *sc, goto out; /* extract some info from the scsi command for pde*/ - blksize = lpfc_cmd_blksize(sc); reftag = (uint32_t)scsi_get_lba(sc); /* Truncate LBA */ #ifdef CONFIG_SCSI_LPFC_DEBUG_FS @@ -2881,7 +2875,7 @@ lpfc_calc_bg_err(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd) struct scsi_cmnd *cmd = lpfc_cmd->pCmd; struct scsi_dif_tuple *src = NULL; uint8_t *data_src = NULL; - uint16_t guard_tag, guard_type; + uint16_t guard_tag; uint16_t start_app_tag, app_tag; uint32_t start_ref_tag, ref_tag; int prot, protsegcnt; @@ -2922,7 +2916,6 @@ lpfc_calc_bg_err(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd) data_len = sgde->length; if ((data_len & (blksize - 1)) == 0) chk_guard = 1; - guard_type = scsi_host_get_guard(cmd->device->host); src = (struct scsi_dif_tuple *)sg_virt(sgpe); start_ref_tag = (uint32_t)scsi_get_lba(cmd); /* Truncate LBA */ @@ -3908,12 +3901,10 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, struct lpfc_rport_data *rdata = lpfc_cmd->rdata; struct lpfc_nodelist *pnode = rdata->pnode; struct scsi_cmnd *cmd; - int result; int depth; unsigned long flags; struct lpfc_fast_path_event *fast_path_evt; struct Scsi_Host *shost; - uint32_t queue_depth, scsi_id; uint32_t logit = LOG_FCP; /* Sanity check on return of outstanding command */ @@ -4095,7 +4086,6 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, } lpfc_update_stats(phba, lpfc_cmd); - result = cmd->result; if (vport->cfg_max_scsicmpl_time && time_after(jiffies, lpfc_cmd->start_time + msecs_to_jiffies(vport->cfg_max_scsicmpl_time))) { @@ -4132,8 +4122,6 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, lpfc_scsi_unprep_dma_buf(phba, lpfc_cmd); /* The sdev is not guaranteed to be valid post scsi_done upcall. */ - queue_depth = cmd->device->queue_depth; - scsi_id = cmd->device->id; cmd->scsi_done(cmd); if (phba->cfg_poll & ENABLE_FCP_RING_POLLING) { diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 95d53c7..f9585cd 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -12491,12 +12491,10 @@ lpfc_sli4_fof_intr_handler(int irq, void *dev_id) struct lpfc_eqe *eqe; unsigned long iflag; int ecount = 0; - uint32_t eqidx; /* Get the driver's phba structure from the dev_id */ fcp_eq_hdl = (struct lpfc_fcp_eq_hdl *)dev_id; phba = fcp_eq_hdl->phba; - eqidx = fcp_eq_hdl->idx; if (unlikely(!phba)) return IRQ_NONE; @@ -12831,12 +12829,8 @@ out_fail: static void __iomem * lpfc_dual_chute_pci_bar_map(struct lpfc_hba *phba, uint16_t pci_barset) { - struct pci_dev *pdev; - if (!phba->pcidev) return NULL; - else - pdev = phba->pcidev; switch (pci_barset) { case WQ_PCI_BAR_0_AND_1: @@ -15920,7 +15914,6 @@ lpfc_sli4_add_fcf_record(struct lpfc_hba *phba, struct fcf_record *fcf_record) LPFC_MBOXQ_t *mboxq; uint8_t *bytep; void *virt_addr; - dma_addr_t phys_addr; struct lpfc_mbx_sge sge; uint32_t alloc_len, req_len; uint32_t fcfindex; @@ -15953,7 +15946,6 @@ lpfc_sli4_add_fcf_record(struct lpfc_hba *phba, struct fcf_record *fcf_record) * routine only uses a single SGE. */ lpfc_sli4_mbx_sge_get(mboxq, 0, &sge); - phys_addr = getPaddr(sge.pa_hi, sge.pa_lo); virt_addr = mboxq->sge_array->addr[0]; /* * Configure the FCF record for FCFI 0. This is the driver's -- cgit v1.1 From 6599eaaa45e0f40ddbbcf164cf3e3524faed9383 Mon Sep 17 00:00:00 2001 From: Ales Novak Date: Mon, 31 Aug 2015 16:48:16 -0400 Subject: fix: lpfc_send_rscn_event sends bigger buffer size lpfc_send_rscn_event() allocates data for sizeof(struct lpfc_rscn_event_header) + payload_len, but claims that the data has size of sizeof(struct lpfc_els_event_header) + payload_len. That leads to buffer overruns. Signed-off-by: Ales Novak Signed-off-by: James Smart Reviewed-by: Hannes Reinecke Reviewed-by: Sebastian Herbszt Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc_els.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index c859aa3..f9c957d 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -5401,7 +5401,7 @@ lpfc_send_rscn_event(struct lpfc_vport *vport, fc_host_post_vendor_event(shost, fc_get_event_number(), - sizeof(struct lpfc_els_event_header) + payload_len, + sizeof(struct lpfc_rscn_event_header) + payload_len, (char *)rscn_event_data, LPFC_NL_VENDOR_ID); -- cgit v1.1 From d38dd52c79bc117a2ba7c27949d50721adc9d1d3 Mon Sep 17 00:00:00 2001 From: James Smart Date: Mon, 31 Aug 2015 16:48:17 -0400 Subject: lpfc: Add support for Lancer G6 and 32G FC links Signed-off-by: Dick Kennedy Signed-off-by: James Smart Reviewed-by: Hannes Reinecke Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc.h | 8 +++++--- drivers/scsi/lpfc/lpfc_attr.c | 17 +++++++++++++---- drivers/scsi/lpfc/lpfc_ct.c | 6 ++++++ drivers/scsi/lpfc/lpfc_els.c | 2 ++ drivers/scsi/lpfc/lpfc_hbadisc.c | 1 + drivers/scsi/lpfc/lpfc_hw.h | 4 ++++ drivers/scsi/lpfc/lpfc_init.c | 18 ++++++++++++++++-- drivers/scsi/lpfc/lpfc_mbox.c | 11 +++++++++++ 8 files changed, 58 insertions(+), 9 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index a5a56fa..ceee9a3 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h @@ -495,15 +495,17 @@ struct unsol_rcv_ct_ctx { #define LPFC_USER_LINK_SPEED_8G 8 /* 8 Gigabaud */ #define LPFC_USER_LINK_SPEED_10G 10 /* 10 Gigabaud */ #define LPFC_USER_LINK_SPEED_16G 16 /* 16 Gigabaud */ -#define LPFC_USER_LINK_SPEED_MAX LPFC_USER_LINK_SPEED_16G -#define LPFC_USER_LINK_SPEED_BITMAP ((1 << LPFC_USER_LINK_SPEED_16G) | \ +#define LPFC_USER_LINK_SPEED_32G 32 /* 32 Gigabaud */ +#define LPFC_USER_LINK_SPEED_MAX LPFC_USER_LINK_SPEED_32G +#define LPFC_USER_LINK_SPEED_BITMAP ((1ULL << LPFC_USER_LINK_SPEED_32G) | \ + (1 << LPFC_USER_LINK_SPEED_16G) | \ (1 << LPFC_USER_LINK_SPEED_10G) | \ (1 << LPFC_USER_LINK_SPEED_8G) | \ (1 << LPFC_USER_LINK_SPEED_4G) | \ (1 << LPFC_USER_LINK_SPEED_2G) | \ (1 << LPFC_USER_LINK_SPEED_1G) | \ (1 << LPFC_USER_LINK_SPEED_AUTO)) -#define LPFC_LINK_SPEED_STRING "0, 1, 2, 4, 8, 10, 16" +#define LPFC_LINK_SPEED_STRING "0, 1, 2, 4, 8, 10, 16, 32" enum nemb_type { nemb_mse = 1, diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index 3c6cc9d..f6446d7 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -3276,15 +3276,20 @@ lpfc_topology_store(struct device *dev, struct device_attribute *attr, if (val >= 0 && val <= 6) { prev_val = phba->cfg_topology; - phba->cfg_topology = val; if (phba->cfg_link_speed == LPFC_USER_LINK_SPEED_16G && val == 4) { lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, "3113 Loop mode not supported at speed %d\n", - phba->cfg_link_speed); - phba->cfg_topology = prev_val; + val); return -EINVAL; } + if (phba->pcidev->device == PCI_DEVICE_ID_LANCER_G6_FC && + val == 4) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, + "3114 Loop mode not supported\n"); + return -EINVAL; + } + phba->cfg_topology = val; if (nolip) return strlen(buf); @@ -3725,7 +3730,8 @@ lpfc_link_speed_store(struct device *dev, struct device_attribute *attr, ((val == LPFC_USER_LINK_SPEED_4G) && !(phba->lmt & LMT_4Gb)) || ((val == LPFC_USER_LINK_SPEED_8G) && !(phba->lmt & LMT_8Gb)) || ((val == LPFC_USER_LINK_SPEED_10G) && !(phba->lmt & LMT_10Gb)) || - ((val == LPFC_USER_LINK_SPEED_16G) && !(phba->lmt & LMT_16Gb))) { + ((val == LPFC_USER_LINK_SPEED_16G) && !(phba->lmt & LMT_16Gb)) || + ((val == LPFC_USER_LINK_SPEED_32G) && !(phba->lmt & LMT_32Gb))) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "2879 lpfc_link_speed attribute cannot be set " "to %d. Speed is not supported by this port.\n", @@ -5261,6 +5267,9 @@ lpfc_get_host_speed(struct Scsi_Host *shost) case LPFC_LINK_SPEED_16GHZ: fc_host_speed(shost) = FC_PORTSPEED_16GBIT; break; + case LPFC_LINK_SPEED_32GHZ: + fc_host_speed(shost) = FC_PORTSPEED_32GBIT; + break; default: fc_host_speed(shost) = FC_PORTSPEED_UNKNOWN; break; diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c index aaf1cd74..8fded1f 100644 --- a/drivers/scsi/lpfc/lpfc_ct.c +++ b/drivers/scsi/lpfc/lpfc_ct.c @@ -55,6 +55,7 @@ #define HBA_PORTSPEED_10GBIT 0x0004 /* 10 GBit/sec */ #define HBA_PORTSPEED_8GBIT 0x0010 /* 8 GBit/sec */ #define HBA_PORTSPEED_16GBIT 0x0020 /* 16 GBit/sec */ +#define HBA_PORTSPEED_32GBIT 0x0040 /* 32 GBit/sec */ #define HBA_PORTSPEED_UNKNOWN 0x0800 /* Unknown */ #define FOURBYTES 4 @@ -1773,6 +1774,8 @@ hba_out: ad->AttrType = cpu_to_be16(RPRT_SUPPORTED_SPEED); ad->AttrLen = cpu_to_be16(FOURBYTES + 4); ae->un.SupportSpeed = 0; + if (phba->lmt & LMT_32Gb) + ae->un.SupportSpeed |= HBA_PORTSPEED_32GBIT; if (phba->lmt & LMT_16Gb) ae->un.SupportSpeed |= HBA_PORTSPEED_16GBIT; if (phba->lmt & LMT_10Gb) @@ -1816,6 +1819,9 @@ hba_out: case LPFC_LINK_SPEED_16GHZ: ae->un.PortSpeed = HBA_PORTSPEED_16GBIT; break; + case LPFC_LINK_SPEED_32GHZ: + ae->un.PortSpeed = HBA_PORTSPEED_32GBIT; + break; default: ae->un.PortSpeed = HBA_PORTSPEED_UNKNOWN; break; diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index f9c957d..598313d 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -4705,6 +4705,8 @@ lpfc_rdp_res_speed(struct fc_rdp_port_speed_desc *desc, struct lpfc_hba *phba) desc->info.port_speed.speed = cpu_to_be16(rdp_speed); + if (phba->lmt & LMT_32Gb) + rdp_cap |= RDP_PS_32GB; if (phba->lmt & LMT_16Gb) rdp_cap |= RDP_PS_16GB; if (phba->lmt & LMT_10Gb) diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index 71b9044..614d8e9 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -3029,6 +3029,7 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, struct lpfc_mbx_read_top *la) case LPFC_LINK_SPEED_8GHZ: case LPFC_LINK_SPEED_10GHZ: case LPFC_LINK_SPEED_16GHZ: + case LPFC_LINK_SPEED_32GHZ: phba->fc_linkspeed = bf_get(lpfc_mbx_read_top_link_spd, la); break; default: diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h index 892c525..f73b6e1 100644 --- a/drivers/scsi/lpfc/lpfc_hw.h +++ b/drivers/scsi/lpfc/lpfc_hw.h @@ -1400,6 +1400,7 @@ struct lpfc_fdmi_reg_portattr { #define PCI_DEVICE_ID_LANCER_FC_VF 0xe208 #define PCI_DEVICE_ID_LANCER_FCOE 0xe260 #define PCI_DEVICE_ID_LANCER_FCOE_VF 0xe268 +#define PCI_DEVICE_ID_LANCER_G6_FC 0xe300 #define PCI_DEVICE_ID_SAT_SMB 0xf011 #define PCI_DEVICE_ID_SAT_MID 0xf015 #define PCI_DEVICE_ID_RFLY 0xf095 @@ -2075,6 +2076,7 @@ typedef struct { #define LINK_SPEED_8G 0x8 /* 8 Gigabaud */ #define LINK_SPEED_10G 0x10 /* 10 Gigabaud */ #define LINK_SPEED_16G 0x11 /* 16 Gigabaud */ +#define LINK_SPEED_32G 0x14 /* 32 Gigabaud */ } INIT_LINK_VAR; @@ -2246,6 +2248,7 @@ typedef struct { #define LMT_8Gb 0x080 #define LMT_10Gb 0x100 #define LMT_16Gb 0x200 +#define LMT_32Gb 0x400 uint32_t rsvd2; uint32_t rsvd3; uint32_t max_xri; @@ -2727,6 +2730,7 @@ struct lpfc_mbx_read_top { #define LPFC_LINK_SPEED_8GHZ 0x20 #define LPFC_LINK_SPEED_10GHZ 0x40 #define LPFC_LINK_SPEED_16GHZ 0x80 +#define LPFC_LINK_SPEED_32GHZ 0x90 }; /* Structure for MB Command CLEAR_LA (22) */ diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 5a97867..db9446c 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -699,7 +699,9 @@ lpfc_hba_init_link_fc_topology(struct lpfc_hba *phba, uint32_t fc_topology, ((phba->cfg_link_speed == LPFC_USER_LINK_SPEED_10G) && !(phba->lmt & LMT_10Gb)) || ((phba->cfg_link_speed == LPFC_USER_LINK_SPEED_16G) && - !(phba->lmt & LMT_16Gb))) { + !(phba->lmt & LMT_16Gb)) || + ((phba->cfg_link_speed == LPFC_USER_LINK_SPEED_32G) && + !(phba->lmt & LMT_32Gb))) { /* Reset link speed to auto */ lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT, "1302 Invalid speed for this board:%d " @@ -2035,7 +2037,9 @@ lpfc_get_hba_model_desc(struct lpfc_hba *phba, uint8_t *mdp, uint8_t *descp) && descp && descp[0] != '\0') return; - if (phba->lmt & LMT_16Gb) + if (phba->lmt & LMT_32Gb) + max_speed = 32; + else if (phba->lmt & LMT_16Gb) max_speed = 16; else if (phba->lmt & LMT_10Gb) max_speed = 10; @@ -2229,6 +2233,9 @@ lpfc_get_hba_model_desc(struct lpfc_hba *phba, uint8_t *mdp, uint8_t *descp) m = (typeof(m)){"OCe15100", "PCIe", "Obsolete, Unsupported FCoE"}; break; + case PCI_DEVICE_ID_LANCER_G6_FC: + m = (typeof(m)){"LPe32000", "PCIe", "Fibre Channel Adapter"}; + break; case PCI_DEVICE_ID_SKYHAWK: case PCI_DEVICE_ID_SKYHAWK_VF: oneConnect = 1; @@ -3491,6 +3498,8 @@ void lpfc_host_attrib_init(struct Scsi_Host *shost) sizeof fc_host_symbolic_name(shost)); fc_host_supported_speeds(shost) = 0; + if (phba->lmt & LMT_32Gb) + fc_host_supported_speeds(shost) |= FC_PORTSPEED_32GBIT; if (phba->lmt & LMT_16Gb) fc_host_supported_speeds(shost) |= FC_PORTSPEED_16GBIT; if (phba->lmt & LMT_10Gb) @@ -3854,6 +3863,9 @@ lpfc_sli4_port_speed_parse(struct lpfc_hba *phba, uint32_t evt_code, case LPFC_FC_LA_SPEED_16G: port_speed = 16000; break; + case LPFC_FC_LA_SPEED_32G: + port_speed = 32000; + break; default: port_speed = 0; } @@ -11349,6 +11361,8 @@ static struct pci_device_id lpfc_id_table[] = { PCI_ANY_ID, PCI_ANY_ID, }, {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_LANCER_FCOE_VF, PCI_ANY_ID, PCI_ANY_ID, }, + {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_LANCER_G6_FC, + PCI_ANY_ID, PCI_ANY_ID, }, {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_SKYHAWK, PCI_ANY_ID, PCI_ANY_ID, }, {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_SKYHAWK_VF, diff --git a/drivers/scsi/lpfc/lpfc_mbox.c b/drivers/scsi/lpfc/lpfc_mbox.c index 18838ea..f87f90e 100644 --- a/drivers/scsi/lpfc/lpfc_mbox.c +++ b/drivers/scsi/lpfc/lpfc_mbox.c @@ -506,6 +506,13 @@ lpfc_init_link(struct lpfc_hba * phba, break; } + if (phba->pcidev->device == PCI_DEVICE_ID_LANCER_G6_FC && + mb->un.varInitLnk.link_flags & FLAGS_TOPOLOGY_MODE_LOOP) { + /* Failover is not tried for Lancer G6 */ + mb->un.varInitLnk.link_flags = FLAGS_TOPOLOGY_MODE_PT_PT; + phba->cfg_topology = FLAGS_TOPOLOGY_MODE_PT_PT; + } + /* Enable asynchronous ABTS responses from firmware */ mb->un.varInitLnk.link_flags |= FLAGS_IMED_ABORT; @@ -539,6 +546,10 @@ lpfc_init_link(struct lpfc_hba * phba, mb->un.varInitLnk.link_flags |= FLAGS_LINK_SPEED; mb->un.varInitLnk.link_speed = LINK_SPEED_16G; break; + case LPFC_USER_LINK_SPEED_32G: + mb->un.varInitLnk.link_flags |= FLAGS_LINK_SPEED; + mb->un.varInitLnk.link_speed = LINK_SPEED_32G; + break; case LPFC_USER_LINK_SPEED_AUTO: default: mb->un.varInitLnk.link_speed = LINK_SPEED_AUTO; -- cgit v1.1 From eec3d3121988fa9c24f50ece81244ca1c85b7c25 Mon Sep 17 00:00:00 2001 From: James Smart Date: Mon, 31 Aug 2015 16:48:18 -0400 Subject: lpfc: Fix for discovery failure in PT2PT when FLOGI's ELS ACC response gets aborted Fix for discovery failure in PT2PT when FLOGI's ELS ACC response gets aborted Change login state machine to: - Restart FLOGI if prior is ABTS'd - Reject incoming FLOGIs if we have one pending The above ensures that we always finish FLOGI processing, regardless of who initated FLOGI, before processing PLOGI's. Signed-off-by: Dick Kennedy Signed-off-by: James Smart Reviewed-by: Hannes Reinecke Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc_els.c | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index 598313d..759fa9b 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -5850,6 +5850,13 @@ lpfc_els_rcv_flogi(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, return 1; } + /* send our FLOGI first */ + if (vport->port_state < LPFC_FLOGI) { + vport->fc_myDID = 0; + lpfc_initial_flogi(vport); + vport->fc_myDID = Fabric_DID; + } + /* Send back ACC */ lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, cmdiocb, ndlp, NULL); @@ -7324,6 +7331,15 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, "Data: x%x x%x x%x x%x\n", cmd, did, vport->port_state, vport->fc_flag, vport->fc_myDID, vport->fc_prevDID); + + /* reject till our FLOGI completes */ + if ((vport->port_state < LPFC_FABRIC_CFG_LINK) && + (cmd != ELS_CMD_FLOGI)) { + rjt_err = LSRJT_UNABLE_TPC; + rjt_exp = LSEXP_NOTHING_MORE; + goto lsrjt; + } + switch (cmd) { case ELS_CMD_PLOGI: lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, @@ -7361,20 +7377,6 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, rjt_exp = LSEXP_NOTHING_MORE; break; } - /* We get here, and drop thru, if we are PT2PT with - * another NPort and the other side has initiated - * the PLOGI before responding to our FLOGI. - */ - if (phba->sli_rev == LPFC_SLI_REV4 && - (phba->fc_topology_changed || - vport->fc_myDID != vport->fc_prevDID)) { - lpfc_unregister_fcf_prep(phba); - spin_lock_irq(shost->host_lock); - vport->fc_flag &= ~FC_VFI_REGISTERED; - spin_unlock_irq(shost->host_lock); - phba->fc_topology_changed = 0; - lpfc_issue_reg_vfi(vport); - } } spin_lock_irq(shost->host_lock); @@ -7605,6 +7607,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, break; } +lsrjt: /* check if need to LS_RJT received ELS cmd */ if (rjt_err) { memset(&stat, 0, sizeof(stat)); -- cgit v1.1 From 8fe5c1655759b353cf4f0d045dd1773aa3b7ef4e Mon Sep 17 00:00:00 2001 From: James Smart Date: Mon, 31 Aug 2015 16:48:19 -0400 Subject: lpfc: The linux driver does not reinitiate discovery after a failed FLOGI Forgot to clear FCF Discovery in-progress flag upon FLOGI failures. Thus we didn't restart FLOGI. Signed-off-by: Dick Kennedy Signed-off-by: James Smart Reviewed-by: Hannes Reinecke Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc_els.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index 759fa9b..3feeb44 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -1026,9 +1026,11 @@ lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, stop_rr_fcf_flogi: /* FLOGI failure */ lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, - "2858 FLOGI failure Status:x%x/x%x TMO:x%x\n", + "2858 FLOGI failure Status:x%x/x%x TMO:x%x " + "Data x%x x%x\n", irsp->ulpStatus, irsp->un.ulpWord[4], - irsp->ulpTimeout); + irsp->ulpTimeout, phba->hba_flag, + phba->fcf.fcf_flag); /* Check for retry */ if (lpfc_els_retry(phba, cmdiocb, rspiocb)) @@ -1152,6 +1154,9 @@ stop_rr_fcf_flogi: } flogifail: + spin_lock_irq(&phba->hbalock); + phba->fcf.fcf_flag &= ~FCF_DISCOVERY; + spin_unlock_irq(&phba->hbalock); lpfc_nlp_put(ndlp); if (!lpfc_error_lost_link(irsp)) { -- cgit v1.1 From 21bf0b977afd1825100b43c464766dc4acdd43d3 Mon Sep 17 00:00:00 2001 From: James Smart Date: Mon, 31 Aug 2015 16:48:21 -0400 Subject: lpfc: Fix default RA_TOV and ED_TOV in the FC/FCoE driver for all topologies Initial link up defaults were not properly being tracked relative to initial FLOGI or pt2pt PLOGI. Add code to initialize them. Signed-off-by: Dick Kennedy Signed-off-by: James Smart Reviewed-by: Hannes Reinecke Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc_hbadisc.c | 15 ++++++++++++++- drivers/scsi/lpfc/lpfc_hw.h | 2 +- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index 614d8e9..bfc2442 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -2974,7 +2974,8 @@ lpfc_mbx_cmpl_read_sparam(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) MAILBOX_t *mb = &pmb->u.mb; struct lpfc_dmabuf *mp = (struct lpfc_dmabuf *) pmb->context1; struct lpfc_vport *vport = pmb->vport; - + struct serv_parm *sp = &vport->fc_sparam; + uint32_t ed_tov; /* Check for error */ if (mb->mbxStatus) { @@ -2989,6 +2990,18 @@ lpfc_mbx_cmpl_read_sparam(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) memcpy((uint8_t *) &vport->fc_sparam, (uint8_t *) mp->virt, sizeof (struct serv_parm)); + + ed_tov = be32_to_cpu(sp->cmn.e_d_tov); + if (sp->cmn.edtovResolution) /* E_D_TOV ticks are in nanoseconds */ + ed_tov = (ed_tov + 999999) / 1000000; + + phba->fc_edtov = ed_tov; + phba->fc_ratov = (2 * ed_tov) / 1000; + if (phba->fc_ratov < FF_DEF_RATOV) { + /* RA_TOV should be atleast 10sec for initial flogi */ + phba->fc_ratov = FF_DEF_RATOV; + } + lpfc_update_vport_wwn(vport); if (vport->port_type == LPFC_PHYSICAL_PORT) { memcpy(&phba->wwnn, &vport->fc_nodename, sizeof(phba->wwnn)); diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h index f73b6e1..2cce88e 100644 --- a/drivers/scsi/lpfc/lpfc_hw.h +++ b/drivers/scsi/lpfc/lpfc_hw.h @@ -33,7 +33,7 @@ #define FF_DEF_EDTOV 2000 /* Default E_D_TOV (2000ms) */ #define FF_DEF_ALTOV 15 /* Default AL_TIME (15ms) */ -#define FF_DEF_RATOV 2 /* Default RA_TOV (2s) */ +#define FF_DEF_RATOV 10 /* Default RA_TOV (10s) */ #define FF_DEF_ARBTOV 1900 /* Default ARB_TOV (1900ms) */ #define LPFC_BUF_RING0 64 /* Number of buffers to post to RING -- cgit v1.1 From baae8fac019a5d0dc3f39be0f867d13b5c8ee59a Mon Sep 17 00:00:00 2001 From: James Smart Date: Mon, 31 Aug 2015 16:48:22 -0400 Subject: lpfc: Update version to 11.0.0.0 for upstream patch set Signed-off-by: Dick Kennedy Signed-off-by: James Smart Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc_version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h index 6258d3d..ea53aa6 100644 --- a/drivers/scsi/lpfc/lpfc_version.h +++ b/drivers/scsi/lpfc/lpfc_version.h @@ -18,7 +18,7 @@ * included with this package. * *******************************************************************/ -#define LPFC_DRIVER_VERSION "10.7.0.0." +#define LPFC_DRIVER_VERSION "11.0.0.0." #define LPFC_DRIVER_NAME "lpfc" /* Used for SLI 2/3 */ -- cgit v1.1 From d6dbad420a00fbc06c7c9168f75ec66bb2120a18 Mon Sep 17 00:00:00 2001 From: Shirish Pargaonkar Date: Fri, 6 Jun 2014 13:05:59 -0500 Subject: bnx2fc: Do not log error for netevents that need no action Do not log error for netevents that need no action such as NETDEV_REGISTER 0x0005, NETDEV_CHANGEADDR, and NETDEV_CHANGENAME. It results in logging error messages such as these [ 35.315872] bnx2fc: Unknown netevent 5 [ 35.315935] bnx2fc: Unknown netevent 8 [ 35.353866] bnx2fc: Unknown netevent 10 and generating bug reports. Remove logging this message as an ERROR instead of turning them into either DEBUG or INFO level messages. Signed-off-by: Shirish Pargaonkar Acked-by: Eddie Wai Acked-by: Chad Dupuis Signed-off-by: James Bottomley --- drivers/scsi/bnx2fc/bnx2fc_fcoe.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c index d5cdc47..b0bc5ff 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c +++ b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c @@ -856,7 +856,6 @@ static void bnx2fc_indicate_netevent(void *context, unsigned long event, return; default: - printk(KERN_ERR PFX "Unknown netevent %ld", event); return; } -- cgit v1.1 From 9d27e2163168dc5f42785e19fca2e8de453c5e44 Mon Sep 17 00:00:00 2001 From: Ketan Mukadam Date: Sat, 4 Jul 2015 04:12:23 +0530 Subject: MAINTAINERS: Update be2iscsi driver Signed-off-by: Ketan Mukadam Reviewed-by: Mike Christie Signed-off-by: James Bottomley --- MAINTAINERS | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index 7ba7ab7..d382b61 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -9310,8 +9310,8 @@ F: include/uapi/linux/phantom.h SERVER ENGINES 10Gbps iSCSI - BladeEngine 2 DRIVER M: Jayamohan Kallickal -M: Minh Tran -M: John Soni Jose +M: Ketan Mukadam +M: John Soni Jose L: linux-scsi@vger.kernel.org W: http://www.avagotech.com S: Supported -- cgit v1.1 From c4f39bdaf40e2651f4fb3e6944e05166f1ab1d38 Mon Sep 17 00:00:00 2001 From: Ketan Mukadam Date: Sat, 4 Jul 2015 04:12:33 +0530 Subject: be2iscsi: Revert ownership to Emulex We would like to get the following updates in: Revert ownership to "Emulex" from "Avago Technologies" Signed-off-by: Ketan Mukadam Reviewed-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/be2iscsi/Kconfig | 4 ++-- drivers/scsi/be2iscsi/Makefile | 2 +- drivers/scsi/be2iscsi/be.h | 4 ++-- drivers/scsi/be2iscsi/be_cmds.c | 4 ++-- drivers/scsi/be2iscsi/be_cmds.h | 4 ++-- drivers/scsi/be2iscsi/be_iscsi.c | 4 ++-- drivers/scsi/be2iscsi/be_main.c | 8 ++++---- drivers/scsi/be2iscsi/be_main.h | 6 +++--- drivers/scsi/be2iscsi/be_mgmt.c | 4 ++-- drivers/scsi/be2iscsi/be_mgmt.h | 4 ++-- 10 files changed, 22 insertions(+), 22 deletions(-) diff --git a/drivers/scsi/be2iscsi/Kconfig b/drivers/scsi/be2iscsi/Kconfig index ceaca32..4e7cad2 100644 --- a/drivers/scsi/be2iscsi/Kconfig +++ b/drivers/scsi/be2iscsi/Kconfig @@ -1,9 +1,9 @@ config BE2ISCSI - tristate "ServerEngines' 10Gbps iSCSI - BladeEngine 2" + tristate "Emulex 10Gbps iSCSI - BladeEngine 2" depends on PCI && SCSI && NET select SCSI_ISCSI_ATTRS select ISCSI_BOOT_SYSFS help - This driver implements the iSCSI functionality for ServerEngines' + This driver implements the iSCSI functionality for Emulex 10Gbps Storage adapter - BladeEngine 2. diff --git a/drivers/scsi/be2iscsi/Makefile b/drivers/scsi/be2iscsi/Makefile index c11f443..d0488ea 100644 --- a/drivers/scsi/be2iscsi/Makefile +++ b/drivers/scsi/be2iscsi/Makefile @@ -1,5 +1,5 @@ # -# Makefile to build the iSCSI driver for ServerEngine's BladeEngine. +# Makefile to build the iSCSI driver for Emulex OneConnect. # # diff --git a/drivers/scsi/be2iscsi/be.h b/drivers/scsi/be2iscsi/be.h index 3207009..77f992e 100644 --- a/drivers/scsi/be2iscsi/be.h +++ b/drivers/scsi/be2iscsi/be.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2005 - 2015 Avago Technologies + * Copyright (C) 2005 - 2015 Emulex * All rights reserved. * * This program is free software; you can redistribute it and/or @@ -10,7 +10,7 @@ * Contact Information: * linux-drivers@avagotech.com * - * Avago Technologies + * Emulex * 3333 Susan Street * Costa Mesa, CA 92626 */ diff --git a/drivers/scsi/be2iscsi/be_cmds.c b/drivers/scsi/be2iscsi/be_cmds.c index 185391a..2778089 100644 --- a/drivers/scsi/be2iscsi/be_cmds.c +++ b/drivers/scsi/be2iscsi/be_cmds.c @@ -1,5 +1,5 @@ /** - * Copyright (C) 2005 - 2015 Avago Technologies + * Copyright (C) 2005 - 2015 Emulex * All rights reserved. * * This program is free software; you can redistribute it and/or @@ -10,7 +10,7 @@ * Contact Information: * linux-drivers@avagotech.com * - * Avago Technologies + * Emulex * 3333 Susan Street * Costa Mesa, CA 92626 */ diff --git a/drivers/scsi/be2iscsi/be_cmds.h b/drivers/scsi/be2iscsi/be_cmds.h index cdfbc5c..4bfca35 100644 --- a/drivers/scsi/be2iscsi/be_cmds.h +++ b/drivers/scsi/be2iscsi/be_cmds.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2005 - 2015 Avago Technologies + * Copyright (C) 2005 - 2015 Emulex * All rights reserved. * * This program is free software; you can redistribute it and/or @@ -10,7 +10,7 @@ * Contact Information: * linux-drivers@avagotech.com * - * Avago Technologies + * Emulex * 3333 Susan Street * Costa Mesa, CA 92626 */ diff --git a/drivers/scsi/be2iscsi/be_iscsi.c b/drivers/scsi/be2iscsi/be_iscsi.c index 2f07007..b7087ba 100644 --- a/drivers/scsi/be2iscsi/be_iscsi.c +++ b/drivers/scsi/be2iscsi/be_iscsi.c @@ -1,5 +1,5 @@ /** - * Copyright (C) 2005 - 2015 Avago Technologies + * Copyright (C) 2005 - 2015 Emulex * All rights reserved. * * This program is free software; you can redistribute it and/or @@ -12,7 +12,7 @@ * Contact Information: * linux-drivers@avagotech.com * - * Avago Technologies + * Emulex * 3333 Susan Street * Costa Mesa, CA 92626 */ diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c index 7a6dbfb..2e6abe7 100644 --- a/drivers/scsi/be2iscsi/be_main.c +++ b/drivers/scsi/be2iscsi/be_main.c @@ -1,5 +1,5 @@ /** - * Copyright (C) 2005 - 2015 Avago Technologies + * Copyright (C) 2005 - 2015 Emulex * All rights reserved. * * This program is free software; you can redistribute it and/or @@ -12,7 +12,7 @@ * Contact Information: * linux-drivers@avagotech.com * - * Avago Technologies + * Emulex * 3333 Susan Street * Costa Mesa, CA 92626 */ @@ -50,7 +50,7 @@ static unsigned int enable_msix = 1; MODULE_DESCRIPTION(DRV_DESC " " BUILD_STR); MODULE_VERSION(BUILD_STR); -MODULE_AUTHOR("Avago Technologies"); +MODULE_AUTHOR("Emulex Corporation"); MODULE_LICENSE("GPL"); module_param(be_iopoll_budget, int, 0); module_param(enable_msix, int, 0); @@ -552,7 +552,7 @@ MODULE_DEVICE_TABLE(pci, beiscsi_pci_id_table); static struct scsi_host_template beiscsi_sht = { .module = THIS_MODULE, - .name = "Avago Technologies 10Gbe open-iscsi Initiator Driver", + .name = "Emulex 10Gbe open-iscsi Initiator Driver", .proc_name = DRV_NAME, .queuecommand = iscsi_queuecommand, .change_queue_depth = scsi_change_queue_depth, diff --git a/drivers/scsi/be2iscsi/be_main.h b/drivers/scsi/be2iscsi/be_main.h index b8c0c78..51366de 100644 --- a/drivers/scsi/be2iscsi/be_main.h +++ b/drivers/scsi/be2iscsi/be_main.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2005 - 2015 Avago Technologies + * Copyright (C) 2005 - 2015 Emulex * All rights reserved. * * This program is free software; you can redistribute it and/or @@ -12,7 +12,7 @@ * Contact Information: * linux-drivers@avagotech.com * - * Avago Technologies + * Emulex * 3333 Susan Street * Costa Mesa, CA 92626 */ @@ -37,7 +37,7 @@ #define DRV_NAME "be2iscsi" #define BUILD_STR "10.6.0.0" -#define BE_NAME "Avago Technologies OneConnect" \ +#define BE_NAME "Emulex OneConnect" \ "Open-iSCSI Driver version" BUILD_STR #define DRV_DESC BE_NAME " " "Driver" diff --git a/drivers/scsi/be2iscsi/be_mgmt.c b/drivers/scsi/be2iscsi/be_mgmt.c index ca4016f..1b2bd04 100644 --- a/drivers/scsi/be2iscsi/be_mgmt.c +++ b/drivers/scsi/be2iscsi/be_mgmt.c @@ -1,5 +1,5 @@ /** - * Copyright (C) 2005 - 2015 Avago Technologies + * Copyright (C) 2005 - 2015 Emulex * All rights reserved. * * This program is free software; you can redistribute it and/or @@ -12,7 +12,7 @@ * Contact Information: * linux-drivers@avagotech.com * - * Avago Technologies + * Emulex * 3333 Susan Street * Costa Mesa, CA 92626 */ diff --git a/drivers/scsi/be2iscsi/be_mgmt.h b/drivers/scsi/be2iscsi/be_mgmt.h index b58a7de..afa326d 100644 --- a/drivers/scsi/be2iscsi/be_mgmt.h +++ b/drivers/scsi/be2iscsi/be_mgmt.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2005 - 2015 Avago Technologies + * Copyright (C) 2005 - 2015 Emulex * All rights reserved. * * This program is free software; you can redistribute it and/or @@ -12,7 +12,7 @@ * Contact Information: * linux-drivers@avagotech.com * - * Avago Technologies + * Emulex * 3333 Susan Street * Costa Mesa, CA 92626 */ -- cgit v1.1 From fd6ddfa4c1ddfb4a149b31845144b4cf3cbef54d Mon Sep 17 00:00:00 2001 From: Maurizio Lombardi Date: Wed, 12 Aug 2015 17:00:23 +0200 Subject: fnic: check pci_map_single() return value the kernel prints some warnings when compiled with CONFIG_DMA_API_DEBUG. This is because the fnic driver doesn't check the return value of pci_map_single(). [ 11.942770] scsi host12: fnic [ 11.950811] ------------[ cut here ]------------ [ 11.950818] WARNING: at lib/dma-debug.c:937 check_unmap+0x47b/0x920() [ 11.950821] fnic 0000:0c:00.0: DMA-API: device driver failed to check map error[device address=0x0000002020a30040] [size=44 bytes] [mapped as single] Signed-off-by: Maurizio Lombardi Reviewed-by: Johannes Thumshirn Reviewed By: Tomas Henzl Signed-off-by: James Bottomley --- drivers/scsi/fnic/fnic_fcs.c | 46 +++++++++++++++++++++++++++++++++++-------- drivers/scsi/fnic/fnic_scsi.c | 16 +++++++++++++++ 2 files changed, 54 insertions(+), 8 deletions(-) diff --git a/drivers/scsi/fnic/fnic_fcs.c b/drivers/scsi/fnic/fnic_fcs.c index bf0bbd4..67669a9 100644 --- a/drivers/scsi/fnic/fnic_fcs.c +++ b/drivers/scsi/fnic/fnic_fcs.c @@ -939,6 +939,7 @@ int fnic_alloc_rq_frame(struct vnic_rq *rq) struct sk_buff *skb; u16 len; dma_addr_t pa; + int r; len = FC_FRAME_HEADROOM + FC_MAX_FRAME + FC_FRAME_TAILROOM; skb = dev_alloc_skb(len); @@ -952,8 +953,19 @@ int fnic_alloc_rq_frame(struct vnic_rq *rq) skb_reset_network_header(skb); skb_put(skb, len); pa = pci_map_single(fnic->pdev, skb->data, len, PCI_DMA_FROMDEVICE); + + r = pci_dma_mapping_error(fnic->pdev, pa); + if (r) { + printk(KERN_ERR "PCI mapping failed with error %d\n", r); + goto free_skb; + } + fnic_queue_rq_desc(rq, skb, pa, len); return 0; + +free_skb: + kfree_skb(skb); + return r; } void fnic_free_rq_buf(struct vnic_rq *rq, struct vnic_rq_buf *buf) @@ -981,6 +993,7 @@ void fnic_eth_send(struct fcoe_ctlr *fip, struct sk_buff *skb) struct ethhdr *eth_hdr; struct vlan_ethhdr *vlan_hdr; unsigned long flags; + int r; if (!fnic->vlan_hw_insert) { eth_hdr = (struct ethhdr *)skb_mac_header(skb); @@ -1003,18 +1016,27 @@ void fnic_eth_send(struct fcoe_ctlr *fip, struct sk_buff *skb) pa = pci_map_single(fnic->pdev, skb->data, skb->len, PCI_DMA_TODEVICE); - spin_lock_irqsave(&fnic->wq_lock[0], flags); - if (!vnic_wq_desc_avail(wq)) { - pci_unmap_single(fnic->pdev, pa, skb->len, PCI_DMA_TODEVICE); - spin_unlock_irqrestore(&fnic->wq_lock[0], flags); - kfree_skb(skb); - return; + r = pci_dma_mapping_error(fnic->pdev, pa); + if (r) { + printk(KERN_ERR "PCI mapping failed with error %d\n", r); + goto free_skb; } + spin_lock_irqsave(&fnic->wq_lock[0], flags); + if (!vnic_wq_desc_avail(wq)) + goto irq_restore; + fnic_queue_wq_eth_desc(wq, skb, pa, skb->len, 0 /* hw inserts cos value */, fnic->vlan_id, 1); spin_unlock_irqrestore(&fnic->wq_lock[0], flags); + return; + +irq_restore: + spin_unlock_irqrestore(&fnic->wq_lock[0], flags); + pci_unmap_single(fnic->pdev, pa, skb->len, PCI_DMA_TODEVICE); +free_skb: + kfree_skb(skb); } /* @@ -1071,6 +1093,12 @@ static int fnic_send_frame(struct fnic *fnic, struct fc_frame *fp) pa = pci_map_single(fnic->pdev, eth_hdr, tot_len, PCI_DMA_TODEVICE); + ret = pci_dma_mapping_error(fnic->pdev, pa); + if (ret) { + printk(KERN_ERR "DMA map failed with error %d\n", ret); + goto free_skb_on_err; + } + if ((fnic_fc_trace_set_data(fnic->lport->host->host_no, FNIC_FC_SEND, (char *)eth_hdr, tot_len)) != 0) { printk(KERN_ERR "fnic ctlr frame trace error!!!"); @@ -1082,15 +1110,17 @@ static int fnic_send_frame(struct fnic *fnic, struct fc_frame *fp) pci_unmap_single(fnic->pdev, pa, tot_len, PCI_DMA_TODEVICE); ret = -1; - goto fnic_send_frame_end; + goto irq_restore; } fnic_queue_wq_desc(wq, skb, pa, tot_len, fr_eof(fp), 0 /* hw inserts cos value */, fnic->vlan_id, 1, 1, 1); -fnic_send_frame_end: + +irq_restore: spin_unlock_irqrestore(&fnic->wq_lock[0], flags); +free_skb_on_err: if (ret) dev_kfree_skb_any(fp_skb(fp)); diff --git a/drivers/scsi/fnic/fnic_scsi.c b/drivers/scsi/fnic/fnic_scsi.c index 25436cd..266b909 100644 --- a/drivers/scsi/fnic/fnic_scsi.c +++ b/drivers/scsi/fnic/fnic_scsi.c @@ -330,6 +330,7 @@ static inline int fnic_queue_wq_copy_desc(struct fnic *fnic, int flags; u8 exch_flags; struct scsi_lun fc_lun; + int r; if (sg_count) { /* For each SGE, create a device desc entry */ @@ -346,6 +347,12 @@ static inline int fnic_queue_wq_copy_desc(struct fnic *fnic, io_req->sgl_list, sizeof(io_req->sgl_list[0]) * sg_count, PCI_DMA_TODEVICE); + + r = pci_dma_mapping_error(fnic->pdev, io_req->sgl_list_pa); + if (r) { + printk(KERN_ERR "PCI mapping failed with error %d\n", r); + return SCSI_MLQUEUE_HOST_BUSY; + } } io_req->sense_buf_pa = pci_map_single(fnic->pdev, @@ -353,6 +360,15 @@ static inline int fnic_queue_wq_copy_desc(struct fnic *fnic, SCSI_SENSE_BUFFERSIZE, PCI_DMA_FROMDEVICE); + r = pci_dma_mapping_error(fnic->pdev, io_req->sense_buf_pa); + if (r) { + pci_unmap_single(fnic->pdev, io_req->sgl_list_pa, + sizeof(io_req->sgl_list[0]) * sg_count, + PCI_DMA_TODEVICE); + printk(KERN_ERR "PCI mapping failed with error %d\n", r); + return SCSI_MLQUEUE_HOST_BUSY; + } + int_to_scsilun(sc->device->lun, &fc_lun); /* Enqueue the descriptor in the Copy WQ */ -- cgit v1.1 From c42b3654f48bc06189a2d99629c9cf7bb79e8fe3 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Mon, 3 Aug 2015 11:57:21 -0400 Subject: SCSI: refactor device-matching code in scsi_devinfo.c In drivers/scsi/scsi_devinfo.c, the scsi_dev_info_list_del_keyed() and scsi_get_device_flags_keyed() routines contain a large amount of duplicate code for finding vendor/product matches in a scsi_dev_info_list. This patch factors out the duplicate code and puts it in a separate function, scsi_dev_info_list_find(). Signed-off-by: Alan Stern Suggested-by: Giulio Bernardi Signed-off-by: James Bottomley --- drivers/scsi/scsi_devinfo.c | 112 ++++++++++++++++---------------------------- 1 file changed, 41 insertions(+), 71 deletions(-) diff --git a/drivers/scsi/scsi_devinfo.c b/drivers/scsi/scsi_devinfo.c index 9f77d23..2f49a22 100644 --- a/drivers/scsi/scsi_devinfo.c +++ b/drivers/scsi/scsi_devinfo.c @@ -390,25 +390,26 @@ int scsi_dev_info_list_add_keyed(int compatible, char *vendor, char *model, EXPORT_SYMBOL(scsi_dev_info_list_add_keyed); /** - * scsi_dev_info_list_del_keyed - remove one dev_info list entry. + * scsi_dev_info_list_find - find a matching dev_info list entry. * @vendor: vendor string * @model: model (product) string * @key: specify list to use * * Description: - * Remove and destroy one dev_info entry for @vendor, @model + * Finds the first dev_info entry matching @vendor, @model * in list specified by @key. * - * Returns: 0 OK, -error on failure. + * Returns: pointer to matching entry, or ERR_PTR on failure. **/ -int scsi_dev_info_list_del_keyed(char *vendor, char *model, int key) +static struct scsi_dev_info_list *scsi_dev_info_list_find(const char *vendor, + const char *model, int key) { - struct scsi_dev_info_list *devinfo, *found = NULL; + struct scsi_dev_info_list *devinfo; struct scsi_dev_info_list_table *devinfo_table = scsi_devinfo_lookup_by_key(key); if (IS_ERR(devinfo_table)) - return PTR_ERR(devinfo_table); + return (struct scsi_dev_info_list *) devinfo_table; list_for_each_entry(devinfo, &devinfo_table->scsi_dev_info_list, dev_info_list) { @@ -452,25 +453,42 @@ int scsi_dev_info_list_del_keyed(char *vendor, char *model, int key) if (memcmp(devinfo->model, model, min(max, strlen(devinfo->model)))) continue; - found = devinfo; + return devinfo; } else { if (!memcmp(devinfo->vendor, vendor, sizeof(devinfo->vendor)) && !memcmp(devinfo->model, model, sizeof(devinfo->model))) - found = devinfo; + return devinfo; } - if (found) - break; } - if (found) { - list_del(&found->dev_info_list); - kfree(found); - return 0; - } + return ERR_PTR(-ENOENT); +} + +/** + * scsi_dev_info_list_del_keyed - remove one dev_info list entry. + * @vendor: vendor string + * @model: model (product) string + * @key: specify list to use + * + * Description: + * Remove and destroy one dev_info entry for @vendor, @model + * in list specified by @key. + * + * Returns: 0 OK, -error on failure. + **/ +int scsi_dev_info_list_del_keyed(char *vendor, char *model, int key) +{ + struct scsi_dev_info_list *found; - return -ENOENT; + found = scsi_dev_info_list_find(vendor, model, key); + if (IS_ERR(found)) + return PTR_ERR(found); + + list_del(&found->dev_info_list); + kfree(found); + return 0; } EXPORT_SYMBOL(scsi_dev_info_list_del_keyed); @@ -565,64 +583,16 @@ int scsi_get_device_flags_keyed(struct scsi_device *sdev, int key) { struct scsi_dev_info_list *devinfo; - struct scsi_dev_info_list_table *devinfo_table; + int err; - devinfo_table = scsi_devinfo_lookup_by_key(key); + devinfo = scsi_dev_info_list_find(vendor, model, key); + if (!IS_ERR(devinfo)) + return devinfo->flags; - if (IS_ERR(devinfo_table)) - return PTR_ERR(devinfo_table); + err = PTR_ERR(devinfo); + if (err != -ENOENT) + return err; - list_for_each_entry(devinfo, &devinfo_table->scsi_dev_info_list, - dev_info_list) { - if (devinfo->compatible) { - /* - * Behave like the older version of get_device_flags. - */ - size_t max; - /* - * XXX why skip leading spaces? If an odd INQUIRY - * value, that should have been part of the - * scsi_static_device_list[] entry, such as " FOO" - * rather than "FOO". Since this code is already - * here, and we don't know what device it is - * trying to work with, leave it as-is. - */ - max = 8; /* max length of vendor */ - while ((max > 0) && *vendor == ' ') { - max--; - vendor++; - } - /* - * XXX removing the following strlen() would be - * good, using it means that for a an entry not in - * the list, we scan every byte of every vendor - * listed in scsi_static_device_list[], and never match - * a single one (and still have to compare at - * least the first byte of each vendor). - */ - if (memcmp(devinfo->vendor, vendor, - min(max, strlen(devinfo->vendor)))) - continue; - /* - * Skip spaces again. - */ - max = 16; /* max length of model */ - while ((max > 0) && *model == ' ') { - max--; - model++; - } - if (memcmp(devinfo->model, model, - min(max, strlen(devinfo->model)))) - continue; - return devinfo->flags; - } else { - if (!memcmp(devinfo->vendor, vendor, - sizeof(devinfo->vendor)) && - !memcmp(devinfo->model, model, - sizeof(devinfo->model))) - return devinfo->flags; - } - } /* nothing found, return nothing */ if (key != SCSI_DEVINFO_GLOBAL) return 0; -- cgit v1.1 From b704f70ce2003c8046d5c0128303aeeb0d93d890 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Mon, 3 Aug 2015 11:57:29 -0400 Subject: SCSI: fix bug in scsi_dev_info_list matching The "compatible" matching algorithm used for looking up old-style blacklist entries in a scsi_dev_info_list is buggy. The core of the algorithm looks like this: if (memcmp(devinfo->vendor, vendor, min(max, strlen(devinfo->vendor)))) /* not a match */ where max is the length of the device's vendor string after leading spaces have been removed but trailing spaces have not. Because of the min() computation, either entry could be a proper substring of the other and the code would still think that they match. In the case originally reported, the device's vendor and product strings were "Inateck " and " ". These matched against the following entry in the global device list: {"", "Scanner", "1.80", BLIST_NOLUN} because "" is a substring of "Inateck " and "" (the result of removing leading spaces from the device's product string) is a substring of "Scanner". The mistaken match prevented the system from scanning and finding the device's second Logical Unit. This patch fixes the problem by making two changes. First, the code for leading-space removal is hoisted out of the loop. (This means it will sometimes run unnecessarily, but since a large percentage of all lookups involve the "compatible" entries in global device list, this should be an overall improvement.) Second and more importantly, the patch removes trailing spaces and adds a check to verify that the two resulting strings are exactly the same length. This prevents matches where one entry is a proper substring of the other. Signed-off-by: Alan Stern Reported-by: Giulio Bernardi Tested-by: Giulio Bernardi Signed-off-by: James Bottomley --- drivers/scsi/scsi_devinfo.c | 69 +++++++++++++++++++++++---------------------- 1 file changed, 35 insertions(+), 34 deletions(-) diff --git a/drivers/scsi/scsi_devinfo.c b/drivers/scsi/scsi_devinfo.c index 2f49a22..2c1160c7 100644 --- a/drivers/scsi/scsi_devinfo.c +++ b/drivers/scsi/scsi_devinfo.c @@ -407,51 +407,52 @@ static struct scsi_dev_info_list *scsi_dev_info_list_find(const char *vendor, struct scsi_dev_info_list *devinfo; struct scsi_dev_info_list_table *devinfo_table = scsi_devinfo_lookup_by_key(key); + size_t vmax, mmax; + const char *vskip, *mskip; if (IS_ERR(devinfo_table)) return (struct scsi_dev_info_list *) devinfo_table; + /* Prepare for "compatible" matches */ + + /* + * XXX why skip leading spaces? If an odd INQUIRY + * value, that should have been part of the + * scsi_static_device_list[] entry, such as " FOO" + * rather than "FOO". Since this code is already + * here, and we don't know what device it is + * trying to work with, leave it as-is. + */ + vmax = 8; /* max length of vendor */ + vskip = vendor; + while (vmax > 0 && *vskip == ' ') { + vmax--; + vskip++; + } + /* Also skip trailing spaces */ + while (vmax > 0 && vskip[vmax - 1] == ' ') + --vmax; + + mmax = 16; /* max length of model */ + mskip = model; + while (mmax > 0 && *mskip == ' ') { + mmax--; + mskip++; + } + while (mmax > 0 && mskip[mmax - 1] == ' ') + --mmax; + list_for_each_entry(devinfo, &devinfo_table->scsi_dev_info_list, dev_info_list) { if (devinfo->compatible) { /* * Behave like the older version of get_device_flags. */ - size_t max; - /* - * XXX why skip leading spaces? If an odd INQUIRY - * value, that should have been part of the - * scsi_static_device_list[] entry, such as " FOO" - * rather than "FOO". Since this code is already - * here, and we don't know what device it is - * trying to work with, leave it as-is. - */ - max = 8; /* max length of vendor */ - while ((max > 0) && *vendor == ' ') { - max--; - vendor++; - } - /* - * XXX removing the following strlen() would be - * good, using it means that for a an entry not in - * the list, we scan every byte of every vendor - * listed in scsi_static_device_list[], and never match - * a single one (and still have to compare at - * least the first byte of each vendor). - */ - if (memcmp(devinfo->vendor, vendor, - min(max, strlen(devinfo->vendor)))) + if (memcmp(devinfo->vendor, vskip, vmax) || + devinfo->vendor[vmax]) continue; - /* - * Skip spaces again. - */ - max = 16; /* max length of model */ - while ((max > 0) && *model == ' ') { - max--; - model++; - } - if (memcmp(devinfo->model, model, - min(max, strlen(devinfo->model)))) + if (memcmp(devinfo->model, mskip, mmax) || + devinfo->model[mmax]) continue; return devinfo; } else { -- cgit v1.1 From fa4aa632da19fba0154b66a50329acd738304291 Mon Sep 17 00:00:00 2001 From: Manoj Kumar Date: Wed, 21 Oct 2015 15:10:31 -0500 Subject: cxlflash: Fix to avoid invalid port_sel value If two concurrent MANAGE_LUN ioctls are issued with the same WWID parameter, it would result in an incorrect value of port_sel. This is because port_sel is modified without any locks being held. If the first caller stalls after the return from find_and_create_lun(), the value of port_sel will be set incorrectly to indicate a single port, though in this case it should have been set to both ports. To fix, use the global mutex to serialize the lookup of the WWID and the subsequent modification of port_sel. Signed-off-by: Matthew R. Ochs Signed-off-by: Manoj N. Kumar Reviewed-by: Brian King Reviewed-by: Tomas Henzl Signed-off-by: James Bottomley --- drivers/scsi/cxlflash/lunmgt.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/cxlflash/lunmgt.c b/drivers/scsi/cxlflash/lunmgt.c index d98ad0f..8c372fc 100644 --- a/drivers/scsi/cxlflash/lunmgt.c +++ b/drivers/scsi/cxlflash/lunmgt.c @@ -120,7 +120,8 @@ static struct glun_info *lookup_global(u8 *wwid) * * The LUN is kept both in a local list (per adapter) and in a global list * (across all adapters). Certain attributes of the LUN are local to the - * adapter (such as index, port selection mask etc.). + * adapter (such as index, port selection mask, etc.). + * * The block allocation map is shared across all adapters (i.e. associated * wih the global list). Since different attributes are associated with * the per adapter and global entries, allocate two separate structures for each @@ -128,6 +129,8 @@ static struct glun_info *lookup_global(u8 *wwid) * * Keep a pointer back from the local to the global entry. * + * This routine assumes the caller holds the global mutex. + * * Return: Found/Allocated local lun_info structure on success, NULL on failure */ static struct llun_info *find_and_create_lun(struct scsi_device *sdev, u8 *wwid) @@ -137,7 +140,6 @@ static struct llun_info *find_and_create_lun(struct scsi_device *sdev, u8 *wwid) struct Scsi_Host *shost = sdev->host; struct cxlflash_cfg *cfg = shost_priv(shost); - mutex_lock(&global.mutex); if (unlikely(!wwid)) goto out; @@ -169,7 +171,6 @@ static struct llun_info *find_and_create_lun(struct scsi_device *sdev, u8 *wwid) list_add(&gli->list, &global.gluns); out: - mutex_unlock(&global.mutex); pr_debug("%s: returning %p\n", __func__, lli); return lli; } @@ -235,6 +236,7 @@ int cxlflash_manage_lun(struct scsi_device *sdev, u64 flags = manage->hdr.flags; u32 chan = sdev->channel; + mutex_lock(&global.mutex); lli = find_and_create_lun(sdev, manage->wwid); pr_debug("%s: ENTER: WWID = %016llX%016llX, flags = %016llX li = %p\n", __func__, get_unaligned_le64(&manage->wwid[0]), @@ -261,6 +263,7 @@ int cxlflash_manage_lun(struct scsi_device *sdev, } out: + mutex_unlock(&global.mutex); pr_debug("%s: returning rc=%d\n", __func__, rc); return rc; } -- cgit v1.1 From 3ebf203093b4ee07d62ef1a02dbbf7a293770388 Mon Sep 17 00:00:00 2001 From: Manoj Kumar Date: Wed, 21 Oct 2015 15:11:00 -0500 Subject: cxlflash: Replace magic numbers with literals Magic numbers are not meaningful and can create confusion. As a remedy, replace them with descriptive literals. Replace 512 with literal MAX_SECTOR_UNIT. Replace 5 with literal CMD_RETRIES. Signed-off-by: Matthew R. Ochs Signed-off-by: Manoj N. Kumar Reviewed-by: Brian King Reviewed-by: Andrew Donnellan Reviewed-by: Tomas Henzl Signed-off-by: James Bottomley --- drivers/scsi/cxlflash/superpipe.c | 6 ++++-- drivers/scsi/cxlflash/superpipe.h | 3 +++ drivers/scsi/cxlflash/vlun.c | 3 ++- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/cxlflash/superpipe.c b/drivers/scsi/cxlflash/superpipe.c index f1b62ce..7df985d 100644 --- a/drivers/scsi/cxlflash/superpipe.c +++ b/drivers/scsi/cxlflash/superpipe.c @@ -315,7 +315,8 @@ retry: retry_cnt ? "re" : "", scsi_cmd[0]); result = scsi_execute(sdev, scsi_cmd, DMA_FROM_DEVICE, cmd_buf, - CMD_BUFSIZE, sense_buf, tout, 5, 0, NULL); + CMD_BUFSIZE, sense_buf, tout, CMD_RETRIES, + 0, NULL); if (driver_byte(result) == DRIVER_SENSE) { result &= ~(0xFF<<24); /* DRIVER_SENSE is not an error */ @@ -1375,7 +1376,8 @@ out_attach: attach->block_size = gli->blk_len; attach->mmio_size = sizeof(afu->afu_map->hosts[0].harea); attach->last_lba = gli->max_lba; - attach->max_xfer = (sdev->host->max_sectors * 512) / gli->blk_len; + attach->max_xfer = (sdev->host->max_sectors * MAX_SECTOR_UNIT) / + gli->blk_len; out: attach->adap_fd = fd; diff --git a/drivers/scsi/cxlflash/superpipe.h b/drivers/scsi/cxlflash/superpipe.h index d7dc88b..3f7856b 100644 --- a/drivers/scsi/cxlflash/superpipe.h +++ b/drivers/scsi/cxlflash/superpipe.h @@ -29,6 +29,9 @@ extern struct cxlflash_global global; #define MC_CHUNK_SIZE (1 << MC_RHT_NMASK) /* in LBAs */ #define MC_DISCOVERY_TIMEOUT 5 /* 5 secs */ +#define CMD_RETRIES 5 /* 5 retries for scsi_execute */ + +#define MAX_SECTOR_UNIT 512 /* max_sector is in 512 byte multiples */ #define CHAN2PORT(_x) ((_x) + 1) #define PORT2CHAN(_x) ((_x) - 1) diff --git a/drivers/scsi/cxlflash/vlun.c b/drivers/scsi/cxlflash/vlun.c index 6155cb1..6d6608b 100644 --- a/drivers/scsi/cxlflash/vlun.c +++ b/drivers/scsi/cxlflash/vlun.c @@ -434,7 +434,8 @@ static int write_same16(struct scsi_device *sdev, &scsi_cmd[10]); result = scsi_execute(sdev, scsi_cmd, DMA_TO_DEVICE, cmd_buf, - CMD_BUFSIZE, sense_buf, tout, 5, 0, NULL); + CMD_BUFSIZE, sense_buf, tout, CMD_RETRIES, + 0, NULL); if (result) { dev_err_ratelimited(dev, "%s: command failed for " "offset %lld result=0x%x\n", -- cgit v1.1 From 471a5a60aaf13b2323d2b63d212bbdd6ce2bef28 Mon Sep 17 00:00:00 2001 From: Manoj Kumar Date: Wed, 21 Oct 2015 15:11:10 -0500 Subject: cxlflash: Fix read capacity timeout The timeout value for read capacity is too small. Certain devices may take longer to respond and thus the command may prematurely timeout. Additionally the literal used for the timeout is stale. Update the timeout to 30 seconds (matches the value used in sd.c) and rework the timeout literal to a more appropriate description. Signed-off-by: Matthew R. Ochs Signed-off-by: Manoj N. Kumar Reviewed-by: Brian King Reviewed-by: Tomas Henzl Signed-off-by: James Bottomley --- drivers/scsi/cxlflash/superpipe.c | 9 ++++----- drivers/scsi/cxlflash/superpipe.h | 2 +- drivers/scsi/cxlflash/vlun.c | 4 ++-- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/drivers/scsi/cxlflash/superpipe.c b/drivers/scsi/cxlflash/superpipe.c index 7df985d..c3c229e 100644 --- a/drivers/scsi/cxlflash/superpipe.c +++ b/drivers/scsi/cxlflash/superpipe.c @@ -296,7 +296,7 @@ static int read_cap16(struct scsi_device *sdev, struct llun_info *lli) int rc = 0; int result = 0; int retry_cnt = 0; - u32 tout = (MC_DISCOVERY_TIMEOUT * HZ); + u32 to = CMD_TIMEOUT * HZ; retry: cmd_buf = kzalloc(CMD_BUFSIZE, GFP_KERNEL); @@ -315,8 +315,7 @@ retry: retry_cnt ? "re" : "", scsi_cmd[0]); result = scsi_execute(sdev, scsi_cmd, DMA_FROM_DEVICE, cmd_buf, - CMD_BUFSIZE, sense_buf, tout, CMD_RETRIES, - 0, NULL); + CMD_BUFSIZE, sense_buf, to, CMD_RETRIES, 0, NULL); if (driver_byte(result) == DRIVER_SENSE) { result &= ~(0xFF<<24); /* DRIVER_SENSE is not an error */ @@ -1376,8 +1375,8 @@ out_attach: attach->block_size = gli->blk_len; attach->mmio_size = sizeof(afu->afu_map->hosts[0].harea); attach->last_lba = gli->max_lba; - attach->max_xfer = (sdev->host->max_sectors * MAX_SECTOR_UNIT) / - gli->blk_len; + attach->max_xfer = sdev->host->max_sectors * MAX_SECTOR_UNIT; + attach->max_xfer /= gli->blk_len; out: attach->adap_fd = fd; diff --git a/drivers/scsi/cxlflash/superpipe.h b/drivers/scsi/cxlflash/superpipe.h index 3f7856b..fffb179 100644 --- a/drivers/scsi/cxlflash/superpipe.h +++ b/drivers/scsi/cxlflash/superpipe.h @@ -28,7 +28,7 @@ extern struct cxlflash_global global; */ #define MC_CHUNK_SIZE (1 << MC_RHT_NMASK) /* in LBAs */ -#define MC_DISCOVERY_TIMEOUT 5 /* 5 secs */ +#define CMD_TIMEOUT 30 /* 30 secs */ #define CMD_RETRIES 5 /* 5 retries for scsi_execute */ #define MAX_SECTOR_UNIT 512 /* max_sector is in 512 byte multiples */ diff --git a/drivers/scsi/cxlflash/vlun.c b/drivers/scsi/cxlflash/vlun.c index 6d6608b..68994c4 100644 --- a/drivers/scsi/cxlflash/vlun.c +++ b/drivers/scsi/cxlflash/vlun.c @@ -414,7 +414,7 @@ static int write_same16(struct scsi_device *sdev, int ws_limit = SISLITE_MAX_WS_BLOCKS; u64 offset = lba; int left = nblks; - u32 tout = sdev->request_queue->rq_timeout; + u32 to = sdev->request_queue->rq_timeout; struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)sdev->host->hostdata; struct device *dev = &cfg->dev->dev; @@ -434,7 +434,7 @@ static int write_same16(struct scsi_device *sdev, &scsi_cmd[10]); result = scsi_execute(sdev, scsi_cmd, DMA_TO_DEVICE, cmd_buf, - CMD_BUFSIZE, sense_buf, tout, CMD_RETRIES, + CMD_BUFSIZE, sense_buf, to, CMD_RETRIES, 0, NULL); if (result) { dev_err_ratelimited(dev, "%s: command failed for " -- cgit v1.1 From 22fe1ae80fd14cb64be61d004b5e6c324bb6e984 Mon Sep 17 00:00:00 2001 From: "Matthew R. Ochs" Date: Wed, 21 Oct 2015 15:11:18 -0500 Subject: cxlflash: Fix potential oops following LUN removal When a LUN is removed, the sdev that is associated with the LUN remains intact until its reference count drops to 0. In order to prevent an sdev from being removed while a context is still associated with it, obtain an additional reference per-context for each LUN attached to the context. This resolves a potential Oops in the release handler when a dealing with a LUN that has already been removed. Signed-off-by: Matthew R. Ochs Signed-off-by: Manoj N. Kumar Reviewed-by: Brian King Reviewed-by: Tomas Henzl Signed-off-by: James Bottomley --- drivers/scsi/cxlflash/superpipe.c | 35 +++++++++++++++++++++++------------ 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/drivers/scsi/cxlflash/superpipe.c b/drivers/scsi/cxlflash/superpipe.c index c3c229e..8ea018b 100644 --- a/drivers/scsi/cxlflash/superpipe.c +++ b/drivers/scsi/cxlflash/superpipe.c @@ -880,6 +880,9 @@ static int _cxlflash_disk_detach(struct scsi_device *sdev, sys_close(lfd); } + /* Release the sdev reference that bound this LUN to the context */ + scsi_device_put(sdev); + out: if (put_ctx) put_context(ctxi); @@ -1287,11 +1290,17 @@ static int cxlflash_disk_attach(struct scsi_device *sdev, } } + rc = scsi_device_get(sdev); + if (unlikely(rc)) { + dev_err(dev, "%s: Unable to get sdev reference!\n", __func__); + goto out; + } + lun_access = kzalloc(sizeof(*lun_access), GFP_KERNEL); if (unlikely(!lun_access)) { dev_err(dev, "%s: Unable to allocate lun_access!\n", __func__); rc = -ENOMEM; - goto out; + goto err0; } lun_access->lli = lli; @@ -1311,21 +1320,21 @@ static int cxlflash_disk_attach(struct scsi_device *sdev, dev_err(dev, "%s: Could not initialize context %p\n", __func__, ctx); rc = -ENODEV; - goto err0; + goto err1; } ctxid = cxl_process_element(ctx); if (unlikely((ctxid > MAX_CONTEXT) || (ctxid < 0))) { dev_err(dev, "%s: ctxid (%d) invalid!\n", __func__, ctxid); rc = -EPERM; - goto err1; + goto err2; } file = cxl_get_fd(ctx, &cfg->cxl_fops, &fd); if (unlikely(fd < 0)) { rc = -ENODEV; dev_err(dev, "%s: Could not get file descriptor\n", __func__); - goto err1; + goto err2; } /* Translate read/write O_* flags from fcntl.h to AFU permission bits */ @@ -1335,7 +1344,7 @@ static int cxlflash_disk_attach(struct scsi_device *sdev, if (unlikely(!ctxi)) { dev_err(dev, "%s: Failed to create context! (%d)\n", __func__, ctxid); - goto err2; + goto err3; } work = &ctxi->work; @@ -1346,13 +1355,13 @@ static int cxlflash_disk_attach(struct scsi_device *sdev, if (unlikely(rc)) { dev_dbg(dev, "%s: Could not start context rc=%d\n", __func__, rc); - goto err3; + goto err4; } rc = afu_attach(cfg, ctxi); if (unlikely(rc)) { dev_err(dev, "%s: Could not attach AFU rc %d\n", __func__, rc); - goto err4; + goto err5; } /* @@ -1388,13 +1397,13 @@ out: __func__, ctxid, fd, attach->block_size, rc, attach->last_lba); return rc; -err4: +err5: cxl_stop_context(ctx); -err3: +err4: put_context(ctxi); destroy_context(cfg, ctxi); ctxi = NULL; -err2: +err3: /* * Here, we're overriding the fops with a dummy all-NULL fops because * fput() calls the release fop, which will cause us to mistakenly @@ -1406,10 +1415,12 @@ err2: fput(file); put_unused_fd(fd); fd = -1; -err1: +err2: cxl_release_context(ctx); -err0: +err1: kfree(lun_access); +err0: + scsi_device_put(sdev); goto out; } -- cgit v1.1 From 2843fdbddd188edb4d7e60f72f513ad8b82d1a54 Mon Sep 17 00:00:00 2001 From: "Matthew R. Ochs" Date: Wed, 21 Oct 2015 15:11:26 -0500 Subject: cxlflash: Fix data corruption when vLUN used over multiple cards If the same virtual LUN is accessed over multiple cards, only accesses made over the first card will be valid. Accesses made over the second card will go to the wrong LUN causing data corruption. This is because the global LUN's mode word was being used to determine whether the LUN table for that card needs to be programmed. The mode word would be setup by the first card, causing the LUN table for the second card to not be programmed. By unconditionally initializing the LUN table (not depending on the mode word), the problem is avoided. Signed-off-by: Matthew R. Ochs Signed-off-by: Manoj N. Kumar Reviewed-by: Brian King Reviewed-by: Tomas Henzl Signed-off-by: James Bottomley --- drivers/scsi/cxlflash/vlun.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/scsi/cxlflash/vlun.c b/drivers/scsi/cxlflash/vlun.c index 68994c4..96b074f 100644 --- a/drivers/scsi/cxlflash/vlun.c +++ b/drivers/scsi/cxlflash/vlun.c @@ -915,16 +915,9 @@ int cxlflash_disk_virtual_open(struct scsi_device *sdev, void *arg) pr_debug("%s: ctxid=%llu ls=0x%llx\n", __func__, ctxid, lun_size); + /* Setup the LUNs block allocator on first call */ mutex_lock(&gli->mutex); if (gli->mode == MODE_NONE) { - /* Setup the LUN table and block allocator on first call */ - rc = init_luntable(cfg, lli); - if (rc) { - dev_err(dev, "%s: call to init_luntable failed " - "rc=%d!\n", __func__, rc); - goto err0; - } - rc = init_vlun(lli); if (rc) { dev_err(dev, "%s: call to init_vlun failed rc=%d!\n", @@ -942,6 +935,13 @@ int cxlflash_disk_virtual_open(struct scsi_device *sdev, void *arg) } mutex_unlock(&gli->mutex); + rc = init_luntable(cfg, lli); + if (rc) { + dev_err(dev, "%s: call to init_luntable failed rc=%d!\n", + __func__, rc); + goto err1; + } + ctxi = get_context(cfg, rctxid, lli, 0); if (unlikely(!ctxi)) { dev_err(dev, "%s: Bad context! (%llu)\n", __func__, ctxid); -- cgit v1.1 From e568e23f3c6d7bf60ce00a4e8f1331a5b38bbea0 Mon Sep 17 00:00:00 2001 From: "Matthew R. Ochs" Date: Wed, 21 Oct 2015 15:11:34 -0500 Subject: cxlflash: Fix to avoid sizeof(bool) Using sizeof(bool) is considered poor form for various reasons and sparse warns us of that. Correct by changing type from bool to u8. Signed-off-by: Matthew R. Ochs Signed-off-by: Manoj N. Kumar Reviewed-by: Brian King Reviewed-by: Daniel Axtens Reviewed-by: Tomas Henzl Signed-off-by: James Bottomley --- drivers/scsi/cxlflash/superpipe.c | 2 +- drivers/scsi/cxlflash/superpipe.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/cxlflash/superpipe.c b/drivers/scsi/cxlflash/superpipe.c index 8ea018b..c75f3ef 100644 --- a/drivers/scsi/cxlflash/superpipe.c +++ b/drivers/scsi/cxlflash/superpipe.c @@ -737,7 +737,7 @@ static struct ctx_info *create_context(struct cxlflash_cfg *cfg, struct afu *afu = cfg->afu; struct ctx_info *ctxi = NULL; struct llun_info **lli = NULL; - bool *ws = NULL; + u8 *ws = NULL; struct sisl_rht_entry *rhte; ctxi = kzalloc(sizeof(*ctxi), GFP_KERNEL); diff --git a/drivers/scsi/cxlflash/superpipe.h b/drivers/scsi/cxlflash/superpipe.h index fffb179..72d53cf 100644 --- a/drivers/scsi/cxlflash/superpipe.h +++ b/drivers/scsi/cxlflash/superpipe.h @@ -97,7 +97,7 @@ struct ctx_info { u32 rht_out; /* Number of checked out RHT entries */ u32 rht_perms; /* User-defined permissions for RHT entries */ struct llun_info **rht_lun; /* Mapping of RHT entries to LUNs */ - bool *rht_needs_ws; /* User-desired write-same function per RHTE */ + u8 *rht_needs_ws; /* User-desired write-same function per RHTE */ struct cxl_ioctl_start_work work; u64 ctxid; -- cgit v1.1 From a76df368beb31f55aca03c6cd34c272b86e49470 Mon Sep 17 00:00:00 2001 From: "Matthew R. Ochs" Date: Wed, 21 Oct 2015 15:11:43 -0500 Subject: cxlflash: Fix context encode mask width The context encode mask covers more than 32-bits, making it a long integer. This should be noted by appending the ULL width suffix to the mask. Signed-off-by: Matthew R. Ochs Signed-off-by: Manoj N. Kumar Reviewed-by: Brian King Reviewed-by: Daniel Axtens Reviewed-by: Tomas Henzl Signed-off-by: James Bottomley --- drivers/scsi/cxlflash/superpipe.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/cxlflash/superpipe.h b/drivers/scsi/cxlflash/superpipe.h index 72d53cf..7947091 100644 --- a/drivers/scsi/cxlflash/superpipe.h +++ b/drivers/scsi/cxlflash/superpipe.h @@ -87,7 +87,7 @@ enum ctx_ctrl { CTX_CTRL_FILE = (1 << 5) }; -#define ENCODE_CTXID(_ctx, _id) (((((u64)_ctx) & 0xFFFFFFFF0) << 28) | _id) +#define ENCODE_CTXID(_ctx, _id) (((((u64)_ctx) & 0xFFFFFFFF0ULL) << 28) | _id) #define DECODE_CTXID(_val) (_val & 0xFFFFFFFF) struct ctx_info { -- cgit v1.1 From 0a27ae514740b4d64b586043d6b837ad5d0c40f8 Mon Sep 17 00:00:00 2001 From: "Matthew R. Ochs" Date: Wed, 21 Oct 2015 15:11:52 -0500 Subject: cxlflash: Fix to avoid CXL services during EEH During an EEH freeze event, certain CXL services should not be called until after the hardware reset has taken place. Doing so can result in unnecessary failures and possibly cause other ill effects by triggering hardware accesses. This translates to a requirement to quiesce all threads that may potentially use CXL runtime service during this window. In particular, multiple ioctls make use of the CXL services when acting on contexts on behalf of the user. Thus, it is essential to 'drain' running ioctls _before_ proceeding with handling the EEH freeze event. Create the ability to drain ioctls by wrapping the ioctl handler call in a read semaphore and then implementing a small routine that obtains the write semaphore, effectively creating a wait point for all currently executing ioctls. Signed-off-by: Matthew R. Ochs Signed-off-by: Manoj N. Kumar Reviewed-by: Brian King Reviewed-by: Daniel Axtens Reviewed-by: Tomas Henzl Signed-off-by: James Bottomley --- drivers/scsi/cxlflash/common.h | 2 + drivers/scsi/cxlflash/main.c | 18 +++++-- drivers/scsi/cxlflash/superpipe.c | 98 ++++++++++++++++++++++++--------------- 3 files changed, 77 insertions(+), 41 deletions(-) diff --git a/drivers/scsi/cxlflash/common.h b/drivers/scsi/cxlflash/common.h index 1c56037..1abe4e0 100644 --- a/drivers/scsi/cxlflash/common.h +++ b/drivers/scsi/cxlflash/common.h @@ -16,6 +16,7 @@ #define _CXLFLASH_COMMON_H #include +#include #include #include #include @@ -110,6 +111,7 @@ struct cxlflash_cfg { atomic_t recovery_threads; struct mutex ctx_recovery_mutex; struct mutex ctx_tbl_list_mutex; + struct rw_semaphore ioctl_rwsem; struct ctx_info *ctx_tbl[MAX_CONTEXT]; struct list_head ctx_err_recovery; /* contexts w/ recovery pending */ struct file_operations cxl_fops; diff --git a/drivers/scsi/cxlflash/main.c b/drivers/scsi/cxlflash/main.c index 3e3ccf1..6e85c77 100644 --- a/drivers/scsi/cxlflash/main.c +++ b/drivers/scsi/cxlflash/main.c @@ -2311,6 +2311,7 @@ static int cxlflash_probe(struct pci_dev *pdev, cfg->lr_port = -1; mutex_init(&cfg->ctx_tbl_list_mutex); mutex_init(&cfg->ctx_recovery_mutex); + init_rwsem(&cfg->ioctl_rwsem); INIT_LIST_HEAD(&cfg->ctx_err_recovery); INIT_LIST_HEAD(&cfg->lluns); @@ -2365,6 +2366,19 @@ out_remove: } /** + * drain_ioctls() - wait until all currently executing ioctls have completed + * @cfg: Internal structure associated with the host. + * + * Obtain write access to read/write semaphore that wraps ioctl + * handling to 'drain' ioctls currently executing. + */ +static void drain_ioctls(struct cxlflash_cfg *cfg) +{ + down_write(&cfg->ioctl_rwsem); + up_write(&cfg->ioctl_rwsem); +} + +/** * cxlflash_pci_error_detected() - called when a PCI error is detected * @pdev: PCI device struct. * @state: PCI channel state. @@ -2383,16 +2397,14 @@ static pci_ers_result_t cxlflash_pci_error_detected(struct pci_dev *pdev, switch (state) { case pci_channel_io_frozen: cfg->state = STATE_LIMBO; - - /* Turn off legacy I/O */ scsi_block_requests(cfg->host); + drain_ioctls(cfg); rc = cxlflash_mark_contexts_error(cfg); if (unlikely(rc)) dev_err(dev, "%s: Failed to mark user contexts!(%d)\n", __func__, rc); term_mc(cfg, UNDO_START); stop_afu(cfg); - return PCI_ERS_RESULT_NEED_RESET; case pci_channel_io_perm_failure: cfg->state = STATE_FAILTERM; diff --git a/drivers/scsi/cxlflash/superpipe.c b/drivers/scsi/cxlflash/superpipe.c index c75f3ef..6e8fc11 100644 --- a/drivers/scsi/cxlflash/superpipe.c +++ b/drivers/scsi/cxlflash/superpipe.c @@ -1214,6 +1214,46 @@ static const struct file_operations null_fops = { }; /** + * check_state() - checks and responds to the current adapter state + * @cfg: Internal structure associated with the host. + * + * This routine can block and should only be used on process context. + * It assumes that the caller is an ioctl thread and holding the ioctl + * read semaphore. This is temporarily let up across the wait to allow + * for draining actively running ioctls. Also note that when waking up + * from waiting in reset, the state is unknown and must be checked again + * before proceeding. + * + * Return: 0 on success, -errno on failure + */ +static int check_state(struct cxlflash_cfg *cfg) +{ + struct device *dev = &cfg->dev->dev; + int rc = 0; + +retry: + switch (cfg->state) { + case STATE_LIMBO: + dev_dbg(dev, "%s: Limbo state, going to wait...\n", __func__); + up_read(&cfg->ioctl_rwsem); + rc = wait_event_interruptible(cfg->limbo_waitq, + cfg->state != STATE_LIMBO); + down_read(&cfg->ioctl_rwsem); + if (unlikely(rc)) + break; + goto retry; + case STATE_FAILTERM: + dev_dbg(dev, "%s: Failed/Terminating!\n", __func__); + rc = -ENODEV; + break; + default: + break; + } + + return rc; +} + +/** * cxlflash_disk_attach() - attach a LUN to a context * @sdev: SCSI device associated with LUN. * @attach: Attach ioctl data structure. @@ -1523,41 +1563,6 @@ err1: } /** - * check_state() - checks and responds to the current adapter state - * @cfg: Internal structure associated with the host. - * - * This routine can block and should only be used on process context. - * Note that when waking up from waiting in limbo, the state is unknown - * and must be checked again before proceeding. - * - * Return: 0 on success, -errno on failure - */ -static int check_state(struct cxlflash_cfg *cfg) -{ - struct device *dev = &cfg->dev->dev; - int rc = 0; - -retry: - switch (cfg->state) { - case STATE_LIMBO: - dev_dbg(dev, "%s: Limbo, going to wait...\n", __func__); - rc = wait_event_interruptible(cfg->limbo_waitq, - cfg->state != STATE_LIMBO); - if (unlikely(rc)) - break; - goto retry; - case STATE_FAILTERM: - dev_dbg(dev, "%s: Failed/Terminating!\n", __func__); - rc = -ENODEV; - break; - default: - break; - } - - return rc; -} - -/** * cxlflash_afu_recover() - initiates AFU recovery * @sdev: SCSI device associated with LUN. * @recover: Recover ioctl data structure. @@ -1646,9 +1651,14 @@ retry_recover: /* Test if in error state */ reg = readq_be(&afu->ctrl_map->mbox_r); if (reg == -1) { - dev_dbg(dev, "%s: MMIO read fail! Wait for recovery...\n", - __func__); - mutex_unlock(&ctxi->mutex); + dev_dbg(dev, "%s: MMIO fail, wait for recovery.\n", __func__); + + /* + * Before checking the state, put back the context obtained with + * get_context() as it is no longer needed and sleep for a short + * period of time (see prolog notes). + */ + put_context(ctxi); ctxi = NULL; ssleep(1); rc = check_state(cfg); @@ -1967,6 +1977,14 @@ out: * @cmd: IOCTL command. * @arg: Userspace ioctl data structure. * + * A read/write semaphore is used to implement a 'drain' of currently + * running ioctls. The read semaphore is taken at the beginning of each + * ioctl thread and released upon concluding execution. Additionally the + * semaphore should be released and then reacquired in any ioctl execution + * path which will wait for an event to occur that is outside the scope of + * the ioctl (i.e. an adapter reset). To drain the ioctls currently running, + * a thread simply needs to acquire the write semaphore. + * * Return: 0 on success, -errno on failure */ int cxlflash_ioctl(struct scsi_device *sdev, int cmd, void __user *arg) @@ -2001,6 +2019,9 @@ int cxlflash_ioctl(struct scsi_device *sdev, int cmd, void __user *arg) {sizeof(struct dk_cxlflash_clone), (sioctl)cxlflash_disk_clone}, }; + /* Hold read semaphore so we can drain if needed */ + down_read(&cfg->ioctl_rwsem); + /* Restrict command set to physical support only for internal LUN */ if (afu->internal_lun) switch (cmd) { @@ -2082,6 +2103,7 @@ int cxlflash_ioctl(struct scsi_device *sdev, int cmd, void __user *arg) /* fall through to exit */ cxlflash_ioctl_exit: + up_read(&cfg->ioctl_rwsem); if (unlikely(rc && known_ioctl)) dev_err(dev, "%s: ioctl %s (%08X) on dev(%d/%d/%d/%llu) " "returned rc %d\n", __func__, -- cgit v1.1 From 439e85c1e89bd1ed8c99f8b46f87f495a675d95e Mon Sep 17 00:00:00 2001 From: "Matthew R. Ochs" Date: Wed, 21 Oct 2015 15:12:00 -0500 Subject: cxlflash: Correct naming of limbo state and waitq Limbo is not an accurate representation of this state and is also not consistent with the terminology that other drivers use to represent this concept. Rename the state and and its associated waitq to 'reset'. Signed-off-by: Matthew R. Ochs Signed-off-by: Manoj N. Kumar Reviewed-by: Brian King Reviewed-by: Daniel Axtens Reviewed-by: Tomas Henzl Signed-off-by: James Bottomley --- drivers/scsi/cxlflash/common.h | 4 ++-- drivers/scsi/cxlflash/main.c | 26 +++++++++++++------------- drivers/scsi/cxlflash/superpipe.c | 14 +++++++------- 3 files changed, 22 insertions(+), 22 deletions(-) diff --git a/drivers/scsi/cxlflash/common.h b/drivers/scsi/cxlflash/common.h index 1abe4e0..11318de 100644 --- a/drivers/scsi/cxlflash/common.h +++ b/drivers/scsi/cxlflash/common.h @@ -79,7 +79,7 @@ enum cxlflash_init_state { enum cxlflash_state { STATE_NORMAL, /* Normal running state, everything good */ - STATE_LIMBO, /* Limbo running state, trying to reset/recover */ + STATE_RESET, /* Reset state, trying to reset/recover */ STATE_FAILTERM /* Failed/terminating state, error out users/threads */ }; @@ -125,7 +125,7 @@ struct cxlflash_cfg { wait_queue_head_t tmf_waitq; bool tmf_active; - wait_queue_head_t limbo_waitq; + wait_queue_head_t reset_waitq; enum cxlflash_state state; }; diff --git a/drivers/scsi/cxlflash/main.c b/drivers/scsi/cxlflash/main.c index 6e85c77..8940336 100644 --- a/drivers/scsi/cxlflash/main.c +++ b/drivers/scsi/cxlflash/main.c @@ -382,8 +382,8 @@ static int cxlflash_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scp) spin_unlock_irqrestore(&cfg->tmf_waitq.lock, lock_flags); switch (cfg->state) { - case STATE_LIMBO: - dev_dbg_ratelimited(&cfg->dev->dev, "%s: device in limbo!\n", + case STATE_RESET: + dev_dbg_ratelimited(&cfg->dev->dev, "%s: device is in reset!\n", __func__); rc = SCSI_MLQUEUE_HOST_BUSY; goto out; @@ -479,8 +479,8 @@ static int cxlflash_eh_device_reset_handler(struct scsi_cmnd *scp) if (unlikely(rcr)) rc = FAILED; break; - case STATE_LIMBO: - wait_event(cfg->limbo_waitq, cfg->state != STATE_LIMBO); + case STATE_RESET: + wait_event(cfg->reset_waitq, cfg->state != STATE_RESET); if (cfg->state == STATE_NORMAL) break; /* fall through */ @@ -519,7 +519,7 @@ static int cxlflash_eh_host_reset_handler(struct scsi_cmnd *scp) switch (cfg->state) { case STATE_NORMAL: - cfg->state = STATE_LIMBO; + cfg->state = STATE_RESET; scsi_block_requests(cfg->host); cxlflash_mark_contexts_error(cfg); rcr = cxlflash_afu_reset(cfg); @@ -528,11 +528,11 @@ static int cxlflash_eh_host_reset_handler(struct scsi_cmnd *scp) cfg->state = STATE_FAILTERM; } else cfg->state = STATE_NORMAL; - wake_up_all(&cfg->limbo_waitq); + wake_up_all(&cfg->reset_waitq); scsi_unblock_requests(cfg->host); break; - case STATE_LIMBO: - wait_event(cfg->limbo_waitq, cfg->state != STATE_LIMBO); + case STATE_RESET: + wait_event(cfg->reset_waitq, cfg->state != STATE_RESET); if (cfg->state == STATE_NORMAL) break; /* fall through */ @@ -705,7 +705,7 @@ static void cxlflash_wait_for_pci_err_recovery(struct cxlflash_cfg *cfg) struct pci_dev *pdev = cfg->dev; if (pci_channel_offline(pdev)) - wait_event_timeout(cfg->limbo_waitq, + wait_event_timeout(cfg->reset_waitq, !pci_channel_offline(pdev), CXLFLASH_PCI_ERROR_RECOVERY_TIMEOUT); } @@ -2304,7 +2304,7 @@ static int cxlflash_probe(struct pci_dev *pdev, cfg->mcctx = NULL; init_waitqueue_head(&cfg->tmf_waitq); - init_waitqueue_head(&cfg->limbo_waitq); + init_waitqueue_head(&cfg->reset_waitq); INIT_WORK(&cfg->work_q, cxlflash_worker_thread); cfg->lr_state = LINK_RESET_INVALID; @@ -2396,7 +2396,7 @@ static pci_ers_result_t cxlflash_pci_error_detected(struct pci_dev *pdev, switch (state) { case pci_channel_io_frozen: - cfg->state = STATE_LIMBO; + cfg->state = STATE_RESET; scsi_block_requests(cfg->host); drain_ioctls(cfg); rc = cxlflash_mark_contexts_error(cfg); @@ -2408,7 +2408,7 @@ static pci_ers_result_t cxlflash_pci_error_detected(struct pci_dev *pdev, return PCI_ERS_RESULT_NEED_RESET; case pci_channel_io_perm_failure: cfg->state = STATE_FAILTERM; - wake_up_all(&cfg->limbo_waitq); + wake_up_all(&cfg->reset_waitq); scsi_unblock_requests(cfg->host); return PCI_ERS_RESULT_DISCONNECT; default: @@ -2455,7 +2455,7 @@ static void cxlflash_pci_resume(struct pci_dev *pdev) dev_dbg(dev, "%s: pdev=%p\n", __func__, pdev); cfg->state = STATE_NORMAL; - wake_up_all(&cfg->limbo_waitq); + wake_up_all(&cfg->reset_waitq); scsi_unblock_requests(cfg->host); } diff --git a/drivers/scsi/cxlflash/superpipe.c b/drivers/scsi/cxlflash/superpipe.c index 6e8fc11..577aa25 100644 --- a/drivers/scsi/cxlflash/superpipe.c +++ b/drivers/scsi/cxlflash/superpipe.c @@ -100,7 +100,7 @@ void cxlflash_stop_term_user_contexts(struct cxlflash_cfg *cfg) dev_dbg(dev, "%s: Wait for user contexts to quiesce...\n", __func__); - wake_up_all(&cfg->limbo_waitq); + wake_up_all(&cfg->reset_waitq); ssleep(1); } } @@ -1233,11 +1233,11 @@ static int check_state(struct cxlflash_cfg *cfg) retry: switch (cfg->state) { - case STATE_LIMBO: - dev_dbg(dev, "%s: Limbo state, going to wait...\n", __func__); + case STATE_RESET: + dev_dbg(dev, "%s: Reset state, going to wait...\n", __func__); up_read(&cfg->ioctl_rwsem); - rc = wait_event_interruptible(cfg->limbo_waitq, - cfg->state != STATE_LIMBO); + rc = wait_event_interruptible(cfg->reset_waitq, + cfg->state != STATE_RESET); down_read(&cfg->ioctl_rwsem); if (unlikely(rc)) break; @@ -1578,10 +1578,10 @@ err1: * quite possible for this routine to act as the kernel's EEH detection * source (MMIO read of mbox_r). Because of this, there is a window of * time where an EEH might have been detected but not yet 'serviced' - * (callback invoked, causing the device to enter limbo state). To avoid + * (callback invoked, causing the device to enter reset state). To avoid * looping in this routine during that window, a 1 second sleep is in place * between the time the MMIO failure is detected and the time a wait on the - * limbo wait queue is attempted via check_state(). + * reset wait queue is attempted via check_state(). * * Return: 0 on success, -errno on failure */ -- cgit v1.1 From 15305514184875728a545204db893a3c5157fc65 Mon Sep 17 00:00:00 2001 From: "Matthew R. Ochs" Date: Wed, 21 Oct 2015 15:12:10 -0500 Subject: cxlflash: Make functions static Found during code inspection, that the following functions are not being used outside of the file where they are defined. Make them static. int cxlflash_send_cmd(struct afu *, struct afu_cmd *); void cxlflash_wait_resp(struct afu *, struct afu_cmd *); int cxlflash_afu_reset(struct cxlflash_cfg *); struct afu_cmd *cxlflash_cmd_checkout(struct afu *); void cxlflash_cmd_checkin(struct afu_cmd *); void init_pcr(struct cxlflash_cfg *); int init_global(struct cxlflash_cfg *); Signed-off-by: Matthew R. Ochs Signed-off-by: Manoj N. Kumar Reviewed-by: Brian King Reviewed-by: Tomas Henzl Signed-off-by: James Bottomley --- drivers/scsi/cxlflash/common.h | 5 - drivers/scsi/cxlflash/main.c | 1018 ++++++++++++++++++++-------------------- 2 files changed, 509 insertions(+), 514 deletions(-) diff --git a/drivers/scsi/cxlflash/common.h b/drivers/scsi/cxlflash/common.h index 11318de..b038ac7 100644 --- a/drivers/scsi/cxlflash/common.h +++ b/drivers/scsi/cxlflash/common.h @@ -192,11 +192,6 @@ static inline u64 lun_to_lunid(u64 lun) return swab64(lun_id); } -int cxlflash_send_cmd(struct afu *, struct afu_cmd *); -void cxlflash_wait_resp(struct afu *, struct afu_cmd *); -int cxlflash_afu_reset(struct cxlflash_cfg *); -struct afu_cmd *cxlflash_cmd_checkout(struct afu *); -void cxlflash_cmd_checkin(struct afu_cmd *); int cxlflash_afu_sync(struct afu *, ctx_hndl_t, res_hndl_t, u8); void cxlflash_list_init(void); void cxlflash_term_global_luns(void); diff --git a/drivers/scsi/cxlflash/main.c b/drivers/scsi/cxlflash/main.c index 8940336..226cefe 100644 --- a/drivers/scsi/cxlflash/main.c +++ b/drivers/scsi/cxlflash/main.c @@ -36,7 +36,7 @@ MODULE_LICENSE("GPL"); /** - * cxlflash_cmd_checkout() - checks out an AFU command + * cmd_checkout() - checks out an AFU command * @afu: AFU to checkout from. * * Commands are checked out in a round-robin fashion. Note that since @@ -47,7 +47,7 @@ MODULE_LICENSE("GPL"); * * Return: The checked out command or NULL when command pool is empty. */ -struct afu_cmd *cxlflash_cmd_checkout(struct afu *afu) +static struct afu_cmd *cmd_checkout(struct afu *afu) { int k, dec = CXLFLASH_NUM_CMDS; struct afu_cmd *cmd; @@ -70,7 +70,7 @@ struct afu_cmd *cxlflash_cmd_checkout(struct afu *afu) } /** - * cxlflash_cmd_checkin() - checks in an AFU command + * cmd_checkin() - checks in an AFU command * @cmd: AFU command to checkin. * * Safe to pass commands that have already been checked in. Several @@ -79,7 +79,7 @@ struct afu_cmd *cxlflash_cmd_checkout(struct afu *afu) * to avoid clobbering values in the event that the command is checked * out right away. */ -void cxlflash_cmd_checkin(struct afu_cmd *cmd) +static void cmd_checkin(struct afu_cmd *cmd) { cmd->rcb.scp = NULL; cmd->rcb.timeout = 0; @@ -238,7 +238,7 @@ static void cmd_complete(struct afu_cmd *cmd) resid = cmd->sa.resid; cmd_is_tmf = cmd->cmd_tmf; - cxlflash_cmd_checkin(cmd); /* Don't use cmd after here */ + cmd_checkin(cmd); /* Don't use cmd after here */ pr_debug("%s: calling scsi_set_resid, scp=%p " "result=%X resid=%d\n", __func__, @@ -260,6 +260,146 @@ static void cmd_complete(struct afu_cmd *cmd) } /** + * context_reset() - timeout handler for AFU commands + * @cmd: AFU command that timed out. + * + * Sends a reset to the AFU. + */ +static void context_reset(struct afu_cmd *cmd) +{ + int nretry = 0; + u64 rrin = 0x1; + u64 room = 0; + struct afu *afu = cmd->parent; + ulong lock_flags; + + pr_debug("%s: cmd=%p\n", __func__, cmd); + + spin_lock_irqsave(&cmd->slock, lock_flags); + + /* Already completed? */ + if (cmd->sa.host_use_b[0] & B_DONE) { + spin_unlock_irqrestore(&cmd->slock, lock_flags); + return; + } + + cmd->sa.host_use_b[0] |= (B_DONE | B_ERROR | B_TIMEOUT); + spin_unlock_irqrestore(&cmd->slock, lock_flags); + + /* + * We really want to send this reset at all costs, so spread + * out wait time on successive retries for available room. + */ + do { + room = readq_be(&afu->host_map->cmd_room); + atomic64_set(&afu->room, room); + if (room) + goto write_rrin; + udelay(nretry); + } while (nretry++ < MC_ROOM_RETRY_CNT); + + pr_err("%s: no cmd_room to send reset\n", __func__); + return; + +write_rrin: + nretry = 0; + writeq_be(rrin, &afu->host_map->ioarrin); + do { + rrin = readq_be(&afu->host_map->ioarrin); + if (rrin != 0x1) + break; + /* Double delay each time */ + udelay(2 ^ nretry); + } while (nretry++ < MC_ROOM_RETRY_CNT); +} + +/** + * send_cmd() - sends an AFU command + * @afu: AFU associated with the host. + * @cmd: AFU command to send. + * + * Return: + * 0 on success or SCSI_MLQUEUE_HOST_BUSY + */ +static int send_cmd(struct afu *afu, struct afu_cmd *cmd) +{ + struct cxlflash_cfg *cfg = afu->parent; + struct device *dev = &cfg->dev->dev; + int nretry = 0; + int rc = 0; + u64 room; + long newval; + + /* + * This routine is used by critical users such an AFU sync and to + * send a task management function (TMF). Thus we want to retry a + * bit before returning an error. To avoid the performance penalty + * of MMIO, we spread the update of 'room' over multiple commands. + */ +retry: + newval = atomic64_dec_if_positive(&afu->room); + if (!newval) { + do { + room = readq_be(&afu->host_map->cmd_room); + atomic64_set(&afu->room, room); + if (room) + goto write_ioarrin; + udelay(nretry); + } while (nretry++ < MC_ROOM_RETRY_CNT); + + dev_err(dev, "%s: no cmd_room to send 0x%X\n", + __func__, cmd->rcb.cdb[0]); + + goto no_room; + } else if (unlikely(newval < 0)) { + /* This should be rare. i.e. Only if two threads race and + * decrement before the MMIO read is done. In this case + * just benefit from the other thread having updated + * afu->room. + */ + if (nretry++ < MC_ROOM_RETRY_CNT) { + udelay(nretry); + goto retry; + } + + goto no_room; + } + +write_ioarrin: + writeq_be((u64)&cmd->rcb, &afu->host_map->ioarrin); +out: + pr_devel("%s: cmd=%p len=%d ea=%p rc=%d\n", __func__, cmd, + cmd->rcb.data_len, (void *)cmd->rcb.data_ea, rc); + return rc; + +no_room: + afu->read_room = true; + schedule_work(&cfg->work_q); + rc = SCSI_MLQUEUE_HOST_BUSY; + goto out; +} + +/** + * wait_resp() - polls for a response or timeout to a sent AFU command + * @afu: AFU associated with the host. + * @cmd: AFU command that was sent. + */ +static void wait_resp(struct afu *afu, struct afu_cmd *cmd) +{ + ulong timeout = msecs_to_jiffies(cmd->rcb.timeout * 2 * 1000); + + timeout = wait_for_completion_timeout(&cmd->cevent, timeout); + if (!timeout) + context_reset(cmd); + + if (unlikely(cmd->sa.ioasc != 0)) + pr_err("%s: CMD 0x%X failed, IOASC: flags 0x%X, afu_rc 0x%X, " + "scsi_rc 0x%X, fc_rc 0x%X\n", __func__, cmd->rcb.cdb[0], + cmd->sa.rc.flags, cmd->sa.rc.afu_rc, cmd->sa.rc.scsi_rc, + cmd->sa.rc.fc_rc); +} + +/** * send_tmf() - sends a Task Management Function (TMF) * @afu: AFU to checkout from. * @scp: SCSI command from stack. @@ -280,7 +420,7 @@ static int send_tmf(struct afu *afu, struct scsi_cmnd *scp, u64 tmfcmd) ulong lock_flags; int rc = 0; - cmd = cxlflash_cmd_checkout(afu); + cmd = cmd_checkout(afu); if (unlikely(!cmd)) { pr_err("%s: could not get a free command\n", __func__); rc = SCSI_MLQUEUE_HOST_BUSY; @@ -313,9 +453,9 @@ static int send_tmf(struct afu *afu, struct scsi_cmnd *scp, u64 tmfcmd) memcpy(cmd->rcb.cdb, &tmfcmd, sizeof(tmfcmd)); /* Send the command */ - rc = cxlflash_send_cmd(afu, cmd); + rc = send_cmd(afu, cmd); if (unlikely(rc)) { - cxlflash_cmd_checkin(cmd); + cmd_checkin(cmd); spin_lock_irqsave(&cfg->tmf_waitq.lock, lock_flags); cfg->tmf_active = false; spin_unlock_irqrestore(&cfg->tmf_waitq.lock, lock_flags); @@ -398,7 +538,7 @@ static int cxlflash_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scp) break; } - cmd = cxlflash_cmd_checkout(afu); + cmd = cmd_checkout(afu); if (unlikely(!cmd)) { pr_err("%s: could not get a free command\n", __func__); rc = SCSI_MLQUEUE_HOST_BUSY; @@ -438,9 +578,9 @@ static int cxlflash_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scp) memcpy(cmd->rcb.cdb, scp->cmnd, sizeof(cmd->rcb.cdb)); /* Send the command */ - rc = cxlflash_send_cmd(afu, cmd); + rc = send_cmd(afu, cmd); if (unlikely(rc)) { - cxlflash_cmd_checkin(cmd); + cmd_checkin(cmd); scsi_dma_unmap(scp); } @@ -449,369 +589,55 @@ out: } /** - * cxlflash_eh_device_reset_handler() - reset a single LUN - * @scp: SCSI command to send. - * - * Return: - * SUCCESS as defined in scsi/scsi.h - * FAILED as defined in scsi/scsi.h + * cxlflash_wait_for_pci_err_recovery() - wait for error recovery during probe + * @cxlflash: Internal structure associated with the host. */ -static int cxlflash_eh_device_reset_handler(struct scsi_cmnd *scp) +static void cxlflash_wait_for_pci_err_recovery(struct cxlflash_cfg *cfg) { - int rc = SUCCESS; - struct Scsi_Host *host = scp->device->host; - struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)host->hostdata; - struct afu *afu = cfg->afu; - int rcr = 0; - - pr_debug("%s: (scp=%p) %d/%d/%d/%llu " - "cdb=(%08X-%08X-%08X-%08X)\n", __func__, scp, - host->host_no, scp->device->channel, - scp->device->id, scp->device->lun, - get_unaligned_be32(&((u32 *)scp->cmnd)[0]), - get_unaligned_be32(&((u32 *)scp->cmnd)[1]), - get_unaligned_be32(&((u32 *)scp->cmnd)[2]), - get_unaligned_be32(&((u32 *)scp->cmnd)[3])); - - switch (cfg->state) { - case STATE_NORMAL: - rcr = send_tmf(afu, scp, TMF_LUN_RESET); - if (unlikely(rcr)) - rc = FAILED; - break; - case STATE_RESET: - wait_event(cfg->reset_waitq, cfg->state != STATE_RESET); - if (cfg->state == STATE_NORMAL) - break; - /* fall through */ - default: - rc = FAILED; - break; - } + struct pci_dev *pdev = cfg->dev; - pr_debug("%s: returning rc=%d\n", __func__, rc); - return rc; + if (pci_channel_offline(pdev)) + wait_event_timeout(cfg->reset_waitq, + !pci_channel_offline(pdev), + CXLFLASH_PCI_ERROR_RECOVERY_TIMEOUT); } /** - * cxlflash_eh_host_reset_handler() - reset the host adapter - * @scp: SCSI command from stack identifying host. - * - * Return: - * SUCCESS as defined in scsi/scsi.h - * FAILED as defined in scsi/scsi.h + * free_mem() - free memory associated with the AFU + * @cxlflash: Internal structure associated with the host. */ -static int cxlflash_eh_host_reset_handler(struct scsi_cmnd *scp) +static void free_mem(struct cxlflash_cfg *cfg) { - int rc = SUCCESS; - int rcr = 0; - struct Scsi_Host *host = scp->device->host; - struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)host->hostdata; + int i; + char *buf = NULL; + struct afu *afu = cfg->afu; - pr_debug("%s: (scp=%p) %d/%d/%d/%llu " - "cdb=(%08X-%08X-%08X-%08X)\n", __func__, scp, - host->host_no, scp->device->channel, - scp->device->id, scp->device->lun, - get_unaligned_be32(&((u32 *)scp->cmnd)[0]), - get_unaligned_be32(&((u32 *)scp->cmnd)[1]), - get_unaligned_be32(&((u32 *)scp->cmnd)[2]), - get_unaligned_be32(&((u32 *)scp->cmnd)[3])); + if (cfg->afu) { + for (i = 0; i < CXLFLASH_NUM_CMDS; i++) { + buf = afu->cmd[i].buf; + if (!((u64)buf & (PAGE_SIZE - 1))) + free_page((ulong)buf); + } - switch (cfg->state) { - case STATE_NORMAL: - cfg->state = STATE_RESET; - scsi_block_requests(cfg->host); - cxlflash_mark_contexts_error(cfg); - rcr = cxlflash_afu_reset(cfg); - if (rcr) { - rc = FAILED; - cfg->state = STATE_FAILTERM; - } else - cfg->state = STATE_NORMAL; - wake_up_all(&cfg->reset_waitq); - scsi_unblock_requests(cfg->host); - break; - case STATE_RESET: - wait_event(cfg->reset_waitq, cfg->state != STATE_RESET); - if (cfg->state == STATE_NORMAL) - break; - /* fall through */ - default: - rc = FAILED; - break; + free_pages((ulong)afu, get_order(sizeof(struct afu))); + cfg->afu = NULL; } - - pr_debug("%s: returning rc=%d\n", __func__, rc); - return rc; } /** - * cxlflash_change_queue_depth() - change the queue depth for the device - * @sdev: SCSI device destined for queue depth change. - * @qdepth: Requested queue depth value to set. - * - * The requested queue depth is capped to the maximum supported value. + * stop_afu() - stops the AFU command timers and unmaps the MMIO space + * @cxlflash: Internal structure associated with the host. * - * Return: The actual queue depth set. + * Safe to call with AFU in a partially allocated/initialized state. */ -static int cxlflash_change_queue_depth(struct scsi_device *sdev, int qdepth) +static void stop_afu(struct cxlflash_cfg *cfg) { + int i; + struct afu *afu = cfg->afu; - if (qdepth > CXLFLASH_MAX_CMDS_PER_LUN) - qdepth = CXLFLASH_MAX_CMDS_PER_LUN; - - scsi_change_queue_depth(sdev, qdepth); - return sdev->queue_depth; -} - -/** - * cxlflash_show_port_status() - queries and presents the current port status - * @dev: Generic device associated with the host owning the port. - * @attr: Device attribute representing the port. - * @buf: Buffer of length PAGE_SIZE to report back port status in ASCII. - * - * Return: The size of the ASCII string returned in @buf. - */ -static ssize_t cxlflash_show_port_status(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)shost->hostdata; - struct afu *afu = cfg->afu; - - char *disp_status; - int rc; - u32 port; - u64 status; - u64 *fc_regs; - - rc = kstrtouint((attr->attr.name + 4), 10, &port); - if (rc || (port >= NUM_FC_PORTS)) - return 0; - - fc_regs = &afu->afu_map->global.fc_regs[port][0]; - status = - (readq_be(&fc_regs[FC_MTIP_STATUS / 8]) & FC_MTIP_STATUS_MASK); - - if (status == FC_MTIP_STATUS_ONLINE) - disp_status = "online"; - else if (status == FC_MTIP_STATUS_OFFLINE) - disp_status = "offline"; - else - disp_status = "unknown"; - - return snprintf(buf, PAGE_SIZE, "%s\n", disp_status); -} - -/** - * cxlflash_show_lun_mode() - presents the current LUN mode of the host - * @dev: Generic device associated with the host. - * @attr: Device attribute representing the lun mode. - * @buf: Buffer of length PAGE_SIZE to report back the LUN mode in ASCII. - * - * Return: The size of the ASCII string returned in @buf. - */ -static ssize_t cxlflash_show_lun_mode(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)shost->hostdata; - struct afu *afu = cfg->afu; - - return snprintf(buf, PAGE_SIZE, "%u\n", afu->internal_lun); -} - -/** - * cxlflash_store_lun_mode() - sets the LUN mode of the host - * @dev: Generic device associated with the host. - * @attr: Device attribute representing the lun mode. - * @buf: Buffer of length PAGE_SIZE containing the LUN mode in ASCII. - * @count: Length of data resizing in @buf. - * - * The CXL Flash AFU supports a dummy LUN mode where the external - * links and storage are not required. Space on the FPGA is used - * to create 1 or 2 small LUNs which are presented to the system - * as if they were a normal storage device. This feature is useful - * during development and also provides manufacturing with a way - * to test the AFU without an actual device. - * - * 0 = external LUN[s] (default) - * 1 = internal LUN (1 x 64K, 512B blocks, id 0) - * 2 = internal LUN (1 x 64K, 4K blocks, id 0) - * 3 = internal LUN (2 x 32K, 512B blocks, ids 0,1) - * 4 = internal LUN (2 x 32K, 4K blocks, ids 0,1) - * - * Return: The size of the ASCII string returned in @buf. - */ -static ssize_t cxlflash_store_lun_mode(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)shost->hostdata; - struct afu *afu = cfg->afu; - int rc; - u32 lun_mode; - - rc = kstrtouint(buf, 10, &lun_mode); - if (!rc && (lun_mode < 5) && (lun_mode != afu->internal_lun)) { - afu->internal_lun = lun_mode; - cxlflash_afu_reset(cfg); - scsi_scan_host(cfg->host); - } - - return count; -} - -/** - * cxlflash_show_ioctl_version() - presents the current ioctl version of the host - * @dev: Generic device associated with the host. - * @attr: Device attribute representing the ioctl version. - * @buf: Buffer of length PAGE_SIZE to report back the ioctl version. - * - * Return: The size of the ASCII string returned in @buf. - */ -static ssize_t cxlflash_show_ioctl_version(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - return scnprintf(buf, PAGE_SIZE, "%u\n", DK_CXLFLASH_VERSION_0); -} - -/** - * cxlflash_show_dev_mode() - presents the current mode of the device - * @dev: Generic device associated with the device. - * @attr: Device attribute representing the device mode. - * @buf: Buffer of length PAGE_SIZE to report back the dev mode in ASCII. - * - * Return: The size of the ASCII string returned in @buf. - */ -static ssize_t cxlflash_show_dev_mode(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct scsi_device *sdev = to_scsi_device(dev); - - return snprintf(buf, PAGE_SIZE, "%s\n", - sdev->hostdata ? "superpipe" : "legacy"); -} - -/** - * cxlflash_wait_for_pci_err_recovery() - wait for error recovery during probe - * @cxlflash: Internal structure associated with the host. - */ -static void cxlflash_wait_for_pci_err_recovery(struct cxlflash_cfg *cfg) -{ - struct pci_dev *pdev = cfg->dev; - - if (pci_channel_offline(pdev)) - wait_event_timeout(cfg->reset_waitq, - !pci_channel_offline(pdev), - CXLFLASH_PCI_ERROR_RECOVERY_TIMEOUT); -} - -/* - * Host attributes - */ -static DEVICE_ATTR(port0, S_IRUGO, cxlflash_show_port_status, NULL); -static DEVICE_ATTR(port1, S_IRUGO, cxlflash_show_port_status, NULL); -static DEVICE_ATTR(lun_mode, S_IRUGO | S_IWUSR, cxlflash_show_lun_mode, - cxlflash_store_lun_mode); -static DEVICE_ATTR(ioctl_version, S_IRUGO, cxlflash_show_ioctl_version, NULL); - -static struct device_attribute *cxlflash_host_attrs[] = { - &dev_attr_port0, - &dev_attr_port1, - &dev_attr_lun_mode, - &dev_attr_ioctl_version, - NULL -}; - -/* - * Device attributes - */ -static DEVICE_ATTR(mode, S_IRUGO, cxlflash_show_dev_mode, NULL); - -static struct device_attribute *cxlflash_dev_attrs[] = { - &dev_attr_mode, - NULL -}; - -/* - * Host template - */ -static struct scsi_host_template driver_template = { - .module = THIS_MODULE, - .name = CXLFLASH_ADAPTER_NAME, - .info = cxlflash_driver_info, - .ioctl = cxlflash_ioctl, - .proc_name = CXLFLASH_NAME, - .queuecommand = cxlflash_queuecommand, - .eh_device_reset_handler = cxlflash_eh_device_reset_handler, - .eh_host_reset_handler = cxlflash_eh_host_reset_handler, - .change_queue_depth = cxlflash_change_queue_depth, - .cmd_per_lun = 16, - .can_queue = CXLFLASH_MAX_CMDS, - .this_id = -1, - .sg_tablesize = SG_NONE, /* No scatter gather support. */ - .max_sectors = CXLFLASH_MAX_SECTORS, - .use_clustering = ENABLE_CLUSTERING, - .shost_attrs = cxlflash_host_attrs, - .sdev_attrs = cxlflash_dev_attrs, -}; - -/* - * Device dependent values - */ -static struct dev_dependent_vals dev_corsa_vals = { CXLFLASH_MAX_SECTORS }; - -/* - * PCI device binding table - */ -static struct pci_device_id cxlflash_pci_table[] = { - {PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CORSA, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, (kernel_ulong_t)&dev_corsa_vals}, - {} -}; - -MODULE_DEVICE_TABLE(pci, cxlflash_pci_table); - -/** - * free_mem() - free memory associated with the AFU - * @cxlflash: Internal structure associated with the host. - */ -static void free_mem(struct cxlflash_cfg *cfg) -{ - int i; - char *buf = NULL; - struct afu *afu = cfg->afu; - - if (cfg->afu) { - for (i = 0; i < CXLFLASH_NUM_CMDS; i++) { - buf = afu->cmd[i].buf; - if (!((u64)buf & (PAGE_SIZE - 1))) - free_page((ulong)buf); - } - - free_pages((ulong)afu, get_order(sizeof(struct afu))); - cfg->afu = NULL; - } -} - -/** - * stop_afu() - stops the AFU command timers and unmaps the MMIO space - * @cxlflash: Internal structure associated with the host. - * - * Safe to call with AFU in a partially allocated/initialized state. - */ -static void stop_afu(struct cxlflash_cfg *cfg) -{ - int i; - struct afu *afu = cfg->afu; - - if (likely(afu)) { - for (i = 0; i < CXLFLASH_NUM_CMDS; i++) - complete(&afu->cmd[i].cevent); + if (likely(afu)) { + for (i = 0; i < CXLFLASH_NUM_CMDS; i++) + complete(&afu->cmd[i].cevent); if (likely(afu->afu_map)) { cxl_psa_unmap((void *)afu->afu_map); @@ -1631,67 +1457,13 @@ out: } /** - * cxlflash_context_reset() - timeout handler for AFU commands - * @cmd: AFU command that timed out. + * init_pcr() - initialize the provisioning and control registers + * @cxlflash: Internal structure associated with the host. * - * Sends a reset to the AFU. + * Also sets up fast access to the mapped registers and initializes AFU + * command fields that never change. */ -void cxlflash_context_reset(struct afu_cmd *cmd) -{ - int nretry = 0; - u64 rrin = 0x1; - u64 room = 0; - struct afu *afu = cmd->parent; - ulong lock_flags; - - pr_debug("%s: cmd=%p\n", __func__, cmd); - - spin_lock_irqsave(&cmd->slock, lock_flags); - - /* Already completed? */ - if (cmd->sa.host_use_b[0] & B_DONE) { - spin_unlock_irqrestore(&cmd->slock, lock_flags); - return; - } - - cmd->sa.host_use_b[0] |= (B_DONE | B_ERROR | B_TIMEOUT); - spin_unlock_irqrestore(&cmd->slock, lock_flags); - - /* - * We really want to send this reset at all costs, so spread - * out wait time on successive retries for available room. - */ - do { - room = readq_be(&afu->host_map->cmd_room); - atomic64_set(&afu->room, room); - if (room) - goto write_rrin; - udelay(nretry); - } while (nretry++ < MC_ROOM_RETRY_CNT); - - pr_err("%s: no cmd_room to send reset\n", __func__); - return; - -write_rrin: - nretry = 0; - writeq_be(rrin, &afu->host_map->ioarrin); - do { - rrin = readq_be(&afu->host_map->ioarrin); - if (rrin != 0x1) - break; - /* Double delay each time */ - udelay(2 ^ nretry); - } while (nretry++ < MC_ROOM_RETRY_CNT); -} - -/** - * init_pcr() - initialize the provisioning and control registers - * @cxlflash: Internal structure associated with the host. - * - * Also sets up fast access to the mapped registers and initializes AFU - * command fields that never change. - */ -void init_pcr(struct cxlflash_cfg *cfg) +static void init_pcr(struct cxlflash_cfg *cfg) { struct afu *afu = cfg->afu; struct sisl_ctrl_map *ctrl_map; @@ -1727,7 +1499,7 @@ void init_pcr(struct cxlflash_cfg *cfg) * init_global() - initialize AFU global registers * @cxlflash: Internal structure associated with the host. */ -int init_global(struct cxlflash_cfg *cfg) +static int init_global(struct cxlflash_cfg *cfg) { struct afu *afu = cfg->afu; u64 wwpn[NUM_FC_PORTS]; /* wwpn of AFU ports */ @@ -1998,92 +1770,6 @@ err1: } /** - * cxlflash_send_cmd() - sends an AFU command - * @afu: AFU associated with the host. - * @cmd: AFU command to send. - * - * Return: - * 0 on success - * -1 on failure - */ -int cxlflash_send_cmd(struct afu *afu, struct afu_cmd *cmd) -{ - struct cxlflash_cfg *cfg = afu->parent; - int nretry = 0; - int rc = 0; - u64 room; - long newval; - - /* - * This routine is used by critical users such an AFU sync and to - * send a task management function (TMF). Thus we want to retry a - * bit before returning an error. To avoid the performance penalty - * of MMIO, we spread the update of 'room' over multiple commands. - */ -retry: - newval = atomic64_dec_if_positive(&afu->room); - if (!newval) { - do { - room = readq_be(&afu->host_map->cmd_room); - atomic64_set(&afu->room, room); - if (room) - goto write_ioarrin; - udelay(nretry); - } while (nretry++ < MC_ROOM_RETRY_CNT); - - pr_err("%s: no cmd_room to send 0x%X\n", - __func__, cmd->rcb.cdb[0]); - - goto no_room; - } else if (unlikely(newval < 0)) { - /* This should be rare. i.e. Only if two threads race and - * decrement before the MMIO read is done. In this case - * just benefit from the other thread having updated - * afu->room. - */ - if (nretry++ < MC_ROOM_RETRY_CNT) { - udelay(nretry); - goto retry; - } - - goto no_room; - } - -write_ioarrin: - writeq_be((u64)&cmd->rcb, &afu->host_map->ioarrin); -out: - pr_debug("%s: cmd=%p len=%d ea=%p rc=%d\n", __func__, cmd, - cmd->rcb.data_len, (void *)cmd->rcb.data_ea, rc); - return rc; - -no_room: - afu->read_room = true; - schedule_work(&cfg->work_q); - rc = SCSI_MLQUEUE_HOST_BUSY; - goto out; -} - -/** - * cxlflash_wait_resp() - polls for a response or timeout to a sent AFU command - * @afu: AFU associated with the host. - * @cmd: AFU command that was sent. - */ -void cxlflash_wait_resp(struct afu *afu, struct afu_cmd *cmd) -{ - ulong timeout = jiffies + (cmd->rcb.timeout * 2 * HZ); - - timeout = wait_for_completion_timeout(&cmd->cevent, timeout); - if (!timeout) - cxlflash_context_reset(cmd); - - if (unlikely(cmd->sa.ioasc != 0)) - pr_err("%s: CMD 0x%X failed, IOASC: flags 0x%X, afu_rc 0x%X, " - "scsi_rc 0x%X, fc_rc 0x%X\n", __func__, cmd->rcb.cdb[0], - cmd->sa.rc.flags, cmd->sa.rc.afu_rc, cmd->sa.rc.scsi_rc, - cmd->sa.rc.fc_rc); -} - -/** * cxlflash_afu_sync() - builds and sends an AFU sync command * @afu: AFU associated with the host. * @ctx_hndl_u: Identifies context requesting sync. @@ -2121,7 +1807,7 @@ int cxlflash_afu_sync(struct afu *afu, ctx_hndl_t ctx_hndl_u, mutex_lock(&sync_active); retry: - cmd = cxlflash_cmd_checkout(afu); + cmd = cmd_checkout(afu); if (unlikely(!cmd)) { retry_cnt++; udelay(1000 * retry_cnt); @@ -2150,11 +1836,11 @@ retry: *((u16 *)&cmd->rcb.cdb[2]) = swab16(ctx_hndl_u); *((u32 *)&cmd->rcb.cdb[4]) = swab32(res_hndl_u); - rc = cxlflash_send_cmd(afu, cmd); + rc = send_cmd(afu, cmd); if (unlikely(rc)) goto out; - cxlflash_wait_resp(afu, cmd); + wait_resp(afu, cmd); /* set on timeout */ if (unlikely((cmd->sa.ioasc != 0) || @@ -2163,20 +1849,20 @@ retry: out: mutex_unlock(&sync_active); if (cmd) - cxlflash_cmd_checkin(cmd); + cmd_checkin(cmd); pr_debug("%s: returning rc=%d\n", __func__, rc); return rc; } /** - * cxlflash_afu_reset() - resets the AFU - * @cxlflash: Internal structure associated with the host. + * afu_reset() - resets the AFU + * @cfg: Internal structure associated with the host. * * Return: * 0 on success * A failure value from internal services. */ -int cxlflash_afu_reset(struct cxlflash_cfg *cfg) +static int afu_reset(struct cxlflash_cfg *cfg) { int rc = 0; /* Stop the context before the reset. Since the context is @@ -2192,6 +1878,320 @@ int cxlflash_afu_reset(struct cxlflash_cfg *cfg) } /** + * cxlflash_eh_device_reset_handler() - reset a single LUN + * @scp: SCSI command to send. + * + * Return: + * SUCCESS as defined in scsi/scsi.h + * FAILED as defined in scsi/scsi.h + */ +static int cxlflash_eh_device_reset_handler(struct scsi_cmnd *scp) +{ + int rc = SUCCESS; + struct Scsi_Host *host = scp->device->host; + struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)host->hostdata; + struct afu *afu = cfg->afu; + int rcr = 0; + + pr_debug("%s: (scp=%p) %d/%d/%d/%llu " + "cdb=(%08X-%08X-%08X-%08X)\n", __func__, scp, + host->host_no, scp->device->channel, + scp->device->id, scp->device->lun, + get_unaligned_be32(&((u32 *)scp->cmnd)[0]), + get_unaligned_be32(&((u32 *)scp->cmnd)[1]), + get_unaligned_be32(&((u32 *)scp->cmnd)[2]), + get_unaligned_be32(&((u32 *)scp->cmnd)[3])); + + switch (cfg->state) { + case STATE_NORMAL: + rcr = send_tmf(afu, scp, TMF_LUN_RESET); + if (unlikely(rcr)) + rc = FAILED; + break; + case STATE_RESET: + wait_event(cfg->reset_waitq, cfg->state != STATE_RESET); + if (cfg->state == STATE_NORMAL) + break; + /* fall through */ + default: + rc = FAILED; + break; + } + + pr_debug("%s: returning rc=%d\n", __func__, rc); + return rc; +} + +/** + * cxlflash_eh_host_reset_handler() - reset the host adapter + * @scp: SCSI command from stack identifying host. + * + * Return: + * SUCCESS as defined in scsi/scsi.h + * FAILED as defined in scsi/scsi.h + */ +static int cxlflash_eh_host_reset_handler(struct scsi_cmnd *scp) +{ + int rc = SUCCESS; + int rcr = 0; + struct Scsi_Host *host = scp->device->host; + struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)host->hostdata; + + pr_debug("%s: (scp=%p) %d/%d/%d/%llu " + "cdb=(%08X-%08X-%08X-%08X)\n", __func__, scp, + host->host_no, scp->device->channel, + scp->device->id, scp->device->lun, + get_unaligned_be32(&((u32 *)scp->cmnd)[0]), + get_unaligned_be32(&((u32 *)scp->cmnd)[1]), + get_unaligned_be32(&((u32 *)scp->cmnd)[2]), + get_unaligned_be32(&((u32 *)scp->cmnd)[3])); + + switch (cfg->state) { + case STATE_NORMAL: + cfg->state = STATE_RESET; + scsi_block_requests(cfg->host); + cxlflash_mark_contexts_error(cfg); + rcr = afu_reset(cfg); + if (rcr) { + rc = FAILED; + cfg->state = STATE_FAILTERM; + } else + cfg->state = STATE_NORMAL; + wake_up_all(&cfg->reset_waitq); + scsi_unblock_requests(cfg->host); + break; + case STATE_RESET: + wait_event(cfg->reset_waitq, cfg->state != STATE_RESET); + if (cfg->state == STATE_NORMAL) + break; + /* fall through */ + default: + rc = FAILED; + break; + } + + pr_debug("%s: returning rc=%d\n", __func__, rc); + return rc; +} + +/** + * cxlflash_change_queue_depth() - change the queue depth for the device + * @sdev: SCSI device destined for queue depth change. + * @qdepth: Requested queue depth value to set. + * + * The requested queue depth is capped to the maximum supported value. + * + * Return: The actual queue depth set. + */ +static int cxlflash_change_queue_depth(struct scsi_device *sdev, int qdepth) +{ + + if (qdepth > CXLFLASH_MAX_CMDS_PER_LUN) + qdepth = CXLFLASH_MAX_CMDS_PER_LUN; + + scsi_change_queue_depth(sdev, qdepth); + return sdev->queue_depth; +} + +/** + * cxlflash_show_port_status() - queries and presents the current port status + * @dev: Generic device associated with the host owning the port. + * @attr: Device attribute representing the port. + * @buf: Buffer of length PAGE_SIZE to report back port status in ASCII. + * + * Return: The size of the ASCII string returned in @buf. + */ +static ssize_t cxlflash_show_port_status(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct Scsi_Host *shost = class_to_shost(dev); + struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)shost->hostdata; + struct afu *afu = cfg->afu; + + char *disp_status; + int rc; + u32 port; + u64 status; + u64 *fc_regs; + + rc = kstrtouint((attr->attr.name + 4), 10, &port); + if (rc || (port >= NUM_FC_PORTS)) + return 0; + + fc_regs = &afu->afu_map->global.fc_regs[port][0]; + status = + (readq_be(&fc_regs[FC_MTIP_STATUS / 8]) & FC_MTIP_STATUS_MASK); + + if (status == FC_MTIP_STATUS_ONLINE) + disp_status = "online"; + else if (status == FC_MTIP_STATUS_OFFLINE) + disp_status = "offline"; + else + disp_status = "unknown"; + + return snprintf(buf, PAGE_SIZE, "%s\n", disp_status); +} + +/** + * cxlflash_show_lun_mode() - presents the current LUN mode of the host + * @dev: Generic device associated with the host. + * @attr: Device attribute representing the lun mode. + * @buf: Buffer of length PAGE_SIZE to report back the LUN mode in ASCII. + * + * Return: The size of the ASCII string returned in @buf. + */ +static ssize_t cxlflash_show_lun_mode(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct Scsi_Host *shost = class_to_shost(dev); + struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)shost->hostdata; + struct afu *afu = cfg->afu; + + return snprintf(buf, PAGE_SIZE, "%u\n", afu->internal_lun); +} + +/** + * cxlflash_store_lun_mode() - sets the LUN mode of the host + * @dev: Generic device associated with the host. + * @attr: Device attribute representing the lun mode. + * @buf: Buffer of length PAGE_SIZE containing the LUN mode in ASCII. + * @count: Length of data resizing in @buf. + * + * The CXL Flash AFU supports a dummy LUN mode where the external + * links and storage are not required. Space on the FPGA is used + * to create 1 or 2 small LUNs which are presented to the system + * as if they were a normal storage device. This feature is useful + * during development and also provides manufacturing with a way + * to test the AFU without an actual device. + * + * 0 = external LUN[s] (default) + * 1 = internal LUN (1 x 64K, 512B blocks, id 0) + * 2 = internal LUN (1 x 64K, 4K blocks, id 0) + * 3 = internal LUN (2 x 32K, 512B blocks, ids 0,1) + * 4 = internal LUN (2 x 32K, 4K blocks, ids 0,1) + * + * Return: The size of the ASCII string returned in @buf. + */ +static ssize_t cxlflash_store_lun_mode(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct Scsi_Host *shost = class_to_shost(dev); + struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)shost->hostdata; + struct afu *afu = cfg->afu; + int rc; + u32 lun_mode; + + rc = kstrtouint(buf, 10, &lun_mode); + if (!rc && (lun_mode < 5) && (lun_mode != afu->internal_lun)) { + afu->internal_lun = lun_mode; + afu_reset(cfg); + scsi_scan_host(cfg->host); + } + + return count; +} + +/** + * cxlflash_show_ioctl_version() - presents the hosts current ioctl version + * @dev: Generic device associated with the host. + * @attr: Device attribute representing the ioctl version. + * @buf: Buffer of length PAGE_SIZE to report back the ioctl version. + * + * Return: The size of the ASCII string returned in @buf. + */ +static ssize_t cxlflash_show_ioctl_version(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return scnprintf(buf, PAGE_SIZE, "%u\n", DK_CXLFLASH_VERSION_0); +} + +/** + * cxlflash_show_dev_mode() - presents the current mode of the device + * @dev: Generic device associated with the device. + * @attr: Device attribute representing the device mode. + * @buf: Buffer of length PAGE_SIZE to report back the dev mode in ASCII. + * + * Return: The size of the ASCII string returned in @buf. + */ +static ssize_t cxlflash_show_dev_mode(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct scsi_device *sdev = to_scsi_device(dev); + + return snprintf(buf, PAGE_SIZE, "%s\n", + sdev->hostdata ? "superpipe" : "legacy"); +} + +/* + * Host attributes + */ +static DEVICE_ATTR(port0, S_IRUGO, cxlflash_show_port_status, NULL); +static DEVICE_ATTR(port1, S_IRUGO, cxlflash_show_port_status, NULL); +static DEVICE_ATTR(lun_mode, S_IRUGO | S_IWUSR, cxlflash_show_lun_mode, + cxlflash_store_lun_mode); +static DEVICE_ATTR(ioctl_version, S_IRUGO, cxlflash_show_ioctl_version, NULL); + +static struct device_attribute *cxlflash_host_attrs[] = { + &dev_attr_port0, + &dev_attr_port1, + &dev_attr_lun_mode, + &dev_attr_ioctl_version, + NULL +}; + +/* + * Device attributes + */ +static DEVICE_ATTR(mode, S_IRUGO, cxlflash_show_dev_mode, NULL); + +static struct device_attribute *cxlflash_dev_attrs[] = { + &dev_attr_mode, + NULL +}; + +/* + * Host template + */ +static struct scsi_host_template driver_template = { + .module = THIS_MODULE, + .name = CXLFLASH_ADAPTER_NAME, + .info = cxlflash_driver_info, + .ioctl = cxlflash_ioctl, + .proc_name = CXLFLASH_NAME, + .queuecommand = cxlflash_queuecommand, + .eh_device_reset_handler = cxlflash_eh_device_reset_handler, + .eh_host_reset_handler = cxlflash_eh_host_reset_handler, + .change_queue_depth = cxlflash_change_queue_depth, + .cmd_per_lun = 16, + .can_queue = CXLFLASH_MAX_CMDS, + .this_id = -1, + .sg_tablesize = SG_NONE, /* No scatter gather support. */ + .max_sectors = CXLFLASH_MAX_SECTORS, + .use_clustering = ENABLE_CLUSTERING, + .shost_attrs = cxlflash_host_attrs, + .sdev_attrs = cxlflash_dev_attrs, +}; + +/* + * Device dependent values + */ +static struct dev_dependent_vals dev_corsa_vals = { CXLFLASH_MAX_SECTORS }; + +/* + * PCI device binding table + */ +static struct pci_device_id cxlflash_pci_table[] = { + {PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CORSA, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, (kernel_ulong_t)&dev_corsa_vals}, + {} +}; + +MODULE_DEVICE_TABLE(pci, cxlflash_pci_table); + +/** * cxlflash_worker_thread() - work thread handler for the AFU * @work: Work structure contained within cxlflash associated with host. * -- cgit v1.1 From e0f01a21c423c9e58874a9392a69354b7927fca2 Mon Sep 17 00:00:00 2001 From: "Matthew R. Ochs" Date: Wed, 21 Oct 2015 15:12:39 -0500 Subject: cxlflash: Refine host/device attributes Implement the following suggestions and add two new attributes to allow for debugging the port LUN table. - use scnprintf() instead of snprintf() - use DEVICE_ATTR_RO and DEVICE_ATTR_RW Suggested-by: Shane Seymour Signed-off-by: Matthew R. Ochs Signed-off-by: Manoj N. Kumar Reviewed-by: Brian King Reviewed-by: Tomas Henzl Signed-off-by: James Bottomley --- drivers/scsi/cxlflash/main.c | 180 +++++++++++++++++++++++++++++++++---------- 1 file changed, 138 insertions(+), 42 deletions(-) diff --git a/drivers/scsi/cxlflash/main.c b/drivers/scsi/cxlflash/main.c index 226cefe..b44212b 100644 --- a/drivers/scsi/cxlflash/main.c +++ b/drivers/scsi/cxlflash/main.c @@ -1995,33 +1995,24 @@ static int cxlflash_change_queue_depth(struct scsi_device *sdev, int qdepth) /** * cxlflash_show_port_status() - queries and presents the current port status - * @dev: Generic device associated with the host owning the port. - * @attr: Device attribute representing the port. + * @port: Desired port for status reporting. + * @afu: AFU owning the specified port. * @buf: Buffer of length PAGE_SIZE to report back port status in ASCII. * * Return: The size of the ASCII string returned in @buf. */ -static ssize_t cxlflash_show_port_status(struct device *dev, - struct device_attribute *attr, - char *buf) +static ssize_t cxlflash_show_port_status(u32 port, struct afu *afu, char *buf) { - struct Scsi_Host *shost = class_to_shost(dev); - struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)shost->hostdata; - struct afu *afu = cfg->afu; - char *disp_status; - int rc; - u32 port; u64 status; - u64 *fc_regs; + __be64 __iomem *fc_regs; - rc = kstrtouint((attr->attr.name + 4), 10, &port); - if (rc || (port >= NUM_FC_PORTS)) + if (port >= NUM_FC_PORTS) return 0; fc_regs = &afu->afu_map->global.fc_regs[port][0]; - status = - (readq_be(&fc_regs[FC_MTIP_STATUS / 8]) & FC_MTIP_STATUS_MASK); + status = readq_be(&fc_regs[FC_MTIP_STATUS / 8]); + status &= FC_MTIP_STATUS_MASK; if (status == FC_MTIP_STATUS_ONLINE) disp_status = "online"; @@ -2030,31 +2021,69 @@ static ssize_t cxlflash_show_port_status(struct device *dev, else disp_status = "unknown"; - return snprintf(buf, PAGE_SIZE, "%s\n", disp_status); + return scnprintf(buf, PAGE_SIZE, "%s\n", disp_status); +} + +/** + * port0_show() - queries and presents the current status of port 0 + * @dev: Generic device associated with the host owning the port. + * @attr: Device attribute representing the port. + * @buf: Buffer of length PAGE_SIZE to report back port status in ASCII. + * + * Return: The size of the ASCII string returned in @buf. + */ +static ssize_t port0_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct Scsi_Host *shost = class_to_shost(dev); + struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)shost->hostdata; + struct afu *afu = cfg->afu; + + return cxlflash_show_port_status(0, afu, buf); } /** - * cxlflash_show_lun_mode() - presents the current LUN mode of the host + * port1_show() - queries and presents the current status of port 1 + * @dev: Generic device associated with the host owning the port. + * @attr: Device attribute representing the port. + * @buf: Buffer of length PAGE_SIZE to report back port status in ASCII. + * + * Return: The size of the ASCII string returned in @buf. + */ +static ssize_t port1_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct Scsi_Host *shost = class_to_shost(dev); + struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)shost->hostdata; + struct afu *afu = cfg->afu; + + return cxlflash_show_port_status(1, afu, buf); +} + +/** + * lun_mode_show() - presents the current LUN mode of the host * @dev: Generic device associated with the host. - * @attr: Device attribute representing the lun mode. + * @attr: Device attribute representing the LUN mode. * @buf: Buffer of length PAGE_SIZE to report back the LUN mode in ASCII. * * Return: The size of the ASCII string returned in @buf. */ -static ssize_t cxlflash_show_lun_mode(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t lun_mode_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct Scsi_Host *shost = class_to_shost(dev); struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)shost->hostdata; struct afu *afu = cfg->afu; - return snprintf(buf, PAGE_SIZE, "%u\n", afu->internal_lun); + return scnprintf(buf, PAGE_SIZE, "%u\n", afu->internal_lun); } /** - * cxlflash_store_lun_mode() - sets the LUN mode of the host + * lun_mode_store() - sets the LUN mode of the host * @dev: Generic device associated with the host. - * @attr: Device attribute representing the lun mode. + * @attr: Device attribute representing the LUN mode. * @buf: Buffer of length PAGE_SIZE containing the LUN mode in ASCII. * @count: Length of data resizing in @buf. * @@ -2073,9 +2102,9 @@ static ssize_t cxlflash_show_lun_mode(struct device *dev, * * Return: The size of the ASCII string returned in @buf. */ -static ssize_t cxlflash_store_lun_mode(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t lun_mode_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { struct Scsi_Host *shost = class_to_shost(dev); struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)shost->hostdata; @@ -2094,58 +2123,125 @@ static ssize_t cxlflash_store_lun_mode(struct device *dev, } /** - * cxlflash_show_ioctl_version() - presents the hosts current ioctl version + * ioctl_version_show() - presents the current ioctl version of the host * @dev: Generic device associated with the host. * @attr: Device attribute representing the ioctl version. * @buf: Buffer of length PAGE_SIZE to report back the ioctl version. * * Return: The size of the ASCII string returned in @buf. */ -static ssize_t cxlflash_show_ioctl_version(struct device *dev, - struct device_attribute *attr, - char *buf) +static ssize_t ioctl_version_show(struct device *dev, + struct device_attribute *attr, char *buf) { return scnprintf(buf, PAGE_SIZE, "%u\n", DK_CXLFLASH_VERSION_0); } /** - * cxlflash_show_dev_mode() - presents the current mode of the device + * cxlflash_show_port_lun_table() - queries and presents the port LUN table + * @port: Desired port for status reporting. + * @afu: AFU owning the specified port. + * @buf: Buffer of length PAGE_SIZE to report back port status in ASCII. + * + * Return: The size of the ASCII string returned in @buf. + */ +static ssize_t cxlflash_show_port_lun_table(u32 port, + struct afu *afu, + char *buf) +{ + int i; + ssize_t bytes = 0; + __be64 __iomem *fc_port; + + if (port >= NUM_FC_PORTS) + return 0; + + fc_port = &afu->afu_map->global.fc_port[port][0]; + + for (i = 0; i < CXLFLASH_NUM_VLUNS; i++) + bytes += scnprintf(buf + bytes, PAGE_SIZE - bytes, + "%03d: %016llX\n", i, readq_be(&fc_port[i])); + return bytes; +} + +/** + * port0_lun_table_show() - presents the current LUN table of port 0 + * @dev: Generic device associated with the host owning the port. + * @attr: Device attribute representing the port. + * @buf: Buffer of length PAGE_SIZE to report back port status in ASCII. + * + * Return: The size of the ASCII string returned in @buf. + */ +static ssize_t port0_lun_table_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct Scsi_Host *shost = class_to_shost(dev); + struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)shost->hostdata; + struct afu *afu = cfg->afu; + + return cxlflash_show_port_lun_table(0, afu, buf); +} + +/** + * port1_lun_table_show() - presents the current LUN table of port 1 + * @dev: Generic device associated with the host owning the port. + * @attr: Device attribute representing the port. + * @buf: Buffer of length PAGE_SIZE to report back port status in ASCII. + * + * Return: The size of the ASCII string returned in @buf. + */ +static ssize_t port1_lun_table_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct Scsi_Host *shost = class_to_shost(dev); + struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)shost->hostdata; + struct afu *afu = cfg->afu; + + return cxlflash_show_port_lun_table(1, afu, buf); +} + +/** + * mode_show() - presents the current mode of the device * @dev: Generic device associated with the device. * @attr: Device attribute representing the device mode. * @buf: Buffer of length PAGE_SIZE to report back the dev mode in ASCII. * * Return: The size of the ASCII string returned in @buf. */ -static ssize_t cxlflash_show_dev_mode(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t mode_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct scsi_device *sdev = to_scsi_device(dev); - return snprintf(buf, PAGE_SIZE, "%s\n", - sdev->hostdata ? "superpipe" : "legacy"); + return scnprintf(buf, PAGE_SIZE, "%s\n", + sdev->hostdata ? "superpipe" : "legacy"); } /* * Host attributes */ -static DEVICE_ATTR(port0, S_IRUGO, cxlflash_show_port_status, NULL); -static DEVICE_ATTR(port1, S_IRUGO, cxlflash_show_port_status, NULL); -static DEVICE_ATTR(lun_mode, S_IRUGO | S_IWUSR, cxlflash_show_lun_mode, - cxlflash_store_lun_mode); -static DEVICE_ATTR(ioctl_version, S_IRUGO, cxlflash_show_ioctl_version, NULL); +static DEVICE_ATTR_RO(port0); +static DEVICE_ATTR_RO(port1); +static DEVICE_ATTR_RW(lun_mode); +static DEVICE_ATTR_RO(ioctl_version); +static DEVICE_ATTR_RO(port0_lun_table); +static DEVICE_ATTR_RO(port1_lun_table); static struct device_attribute *cxlflash_host_attrs[] = { &dev_attr_port0, &dev_attr_port1, &dev_attr_lun_mode, &dev_attr_ioctl_version, + &dev_attr_port0_lun_table, + &dev_attr_port1_lun_table, NULL }; /* * Device attributes */ -static DEVICE_ATTR(mode, S_IRUGO, cxlflash_show_dev_mode, NULL); +static DEVICE_ATTR_RO(mode); static struct device_attribute *cxlflash_dev_attrs[] = { &dev_attr_mode, -- cgit v1.1 From 4392ba49eb248868afb412ea147ab16e2e606d66 Mon Sep 17 00:00:00 2001 From: "Matthew R. Ochs" Date: Wed, 21 Oct 2015 15:13:11 -0500 Subject: cxlflash: Fix to avoid spamming the kernel log During run-time the driver can be very chatty and spam the system kernel log. Various print statements can be limited and/or moved to development-only mode. Additionally, numerous prints can be converted to trace the corresponding device. Lastly, one spelling correction was made: 'entra' to 'extra'. The following changes were made: - pr_debug to pr_devel - pr_debug to pr_debug_ratelimited - pr_err to dev_err - pr_debug to dev_dbg Signed-off-by: Matthew R. Ochs Signed-off-by: Manoj N. Kumar Reviewed-by: Brian King Reviewed-by: Andrew Donnellan Reviewed-by: Tomas Henzl Signed-off-by: James Bottomley --- drivers/scsi/cxlflash/main.c | 109 +++++++++++++++++++++++-------------------- 1 file changed, 59 insertions(+), 50 deletions(-) diff --git a/drivers/scsi/cxlflash/main.c b/drivers/scsi/cxlflash/main.c index b44212b..527ff85 100644 --- a/drivers/scsi/cxlflash/main.c +++ b/drivers/scsi/cxlflash/main.c @@ -58,8 +58,8 @@ static struct afu_cmd *cmd_checkout(struct afu *afu) cmd = &afu->cmd[k]; if (!atomic_dec_if_positive(&cmd->free)) { - pr_debug("%s: returning found index=%d\n", - __func__, cmd->slot); + pr_devel("%s: returning found index=%d cmd=%p\n", + __func__, cmd->slot, cmd); memset(cmd->buf, 0, CMD_BUFSIZE); memset(cmd->rcb.cdb, 0, sizeof(cmd->rcb.cdb)); return cmd; @@ -93,7 +93,7 @@ static void cmd_checkin(struct afu_cmd *cmd) return; } - pr_debug("%s: released cmd %p index=%d\n", __func__, cmd, cmd->slot); + pr_devel("%s: released cmd %p index=%d\n", __func__, cmd, cmd->slot); } /** @@ -127,7 +127,7 @@ static void process_cmd_err(struct afu_cmd *cmd, struct scsi_cmnd *scp) } pr_debug("%s: cmd failed afu_rc=%d scsi_rc=%d fc_rc=%d " - "afu_extra=0x%X, scsi_entra=0x%X, fc_extra=0x%X\n", + "afu_extra=0x%X, scsi_extra=0x%X, fc_extra=0x%X\n", __func__, ioasa->rc.afu_rc, ioasa->rc.scsi_rc, ioasa->rc.fc_rc, ioasa->afu_extra, ioasa->scsi_extra, ioasa->fc_extra); @@ -240,9 +240,9 @@ static void cmd_complete(struct afu_cmd *cmd) cmd_is_tmf = cmd->cmd_tmf; cmd_checkin(cmd); /* Don't use cmd after here */ - pr_debug("%s: calling scsi_set_resid, scp=%p " - "result=%X resid=%d\n", __func__, - scp, scp->result, resid); + pr_debug_ratelimited("%s: calling scsi_done scp=%p result=%X " + "ioasc=%d\n", __func__, scp, scp->result, + cmd->sa.ioasc); scsi_set_resid(scp, resid); scsi_dma_unmap(scp); @@ -417,12 +417,13 @@ static int send_tmf(struct afu *afu, struct scsi_cmnd *scp, u64 tmfcmd) short lflag = 0; struct Scsi_Host *host = scp->device->host; struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)host->hostdata; + struct device *dev = &cfg->dev->dev; ulong lock_flags; int rc = 0; cmd = cmd_checkout(afu); if (unlikely(!cmd)) { - pr_err("%s: could not get a free command\n", __func__); + dev_err(dev, "%s: could not get a free command\n", __func__); rc = SCSI_MLQUEUE_HOST_BUSY; goto out; } @@ -493,7 +494,7 @@ static int cxlflash_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scp) { struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)host->hostdata; struct afu *afu = cfg->afu; - struct pci_dev *pdev = cfg->dev; + struct device *dev = &cfg->dev->dev; struct afu_cmd *cmd; u32 port_sel = scp->device->channel + 1; int nseg, i, ncount; @@ -502,13 +503,14 @@ static int cxlflash_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scp) short lflag = 0; int rc = 0; - pr_debug("%s: (scp=%p) %d/%d/%d/%llu cdb=(%08X-%08X-%08X-%08X)\n", - __func__, scp, host->host_no, scp->device->channel, - scp->device->id, scp->device->lun, - get_unaligned_be32(&((u32 *)scp->cmnd)[0]), - get_unaligned_be32(&((u32 *)scp->cmnd)[1]), - get_unaligned_be32(&((u32 *)scp->cmnd)[2]), - get_unaligned_be32(&((u32 *)scp->cmnd)[3])); + dev_dbg_ratelimited(dev, "%s: (scp=%p) %d/%d/%d/%llu " + "cdb=(%08X-%08X-%08X-%08X)\n", + __func__, scp, host->host_no, scp->device->channel, + scp->device->id, scp->device->lun, + get_unaligned_be32(&((u32 *)scp->cmnd)[0]), + get_unaligned_be32(&((u32 *)scp->cmnd)[1]), + get_unaligned_be32(&((u32 *)scp->cmnd)[2]), + get_unaligned_be32(&((u32 *)scp->cmnd)[3])); /* If a Task Management Function is active, wait for it to complete * before continuing with regular commands. @@ -523,13 +525,11 @@ static int cxlflash_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scp) switch (cfg->state) { case STATE_RESET: - dev_dbg_ratelimited(&cfg->dev->dev, "%s: device is in reset!\n", - __func__); + dev_dbg_ratelimited(dev, "%s: device is in reset!\n", __func__); rc = SCSI_MLQUEUE_HOST_BUSY; goto out; case STATE_FAILTERM: - dev_dbg_ratelimited(&cfg->dev->dev, "%s: device has failed!\n", - __func__); + dev_dbg_ratelimited(dev, "%s: device has failed!\n", __func__); scp->result = (DID_NO_CONNECT << 16); scp->scsi_done(scp); rc = 0; @@ -540,7 +540,7 @@ static int cxlflash_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scp) cmd = cmd_checkout(afu); if (unlikely(!cmd)) { - pr_err("%s: could not get a free command\n", __func__); + dev_err(dev, "%s: could not get a free command\n", __func__); rc = SCSI_MLQUEUE_HOST_BUSY; goto out; } @@ -562,7 +562,7 @@ static int cxlflash_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scp) nseg = scsi_dma_map(scp); if (unlikely(nseg < 0)) { - dev_err(&pdev->dev, "%s: Fail DMA map! nseg=%d\n", + dev_err(dev, "%s: Fail DMA map! nseg=%d\n", __func__, nseg); rc = SCSI_MLQUEUE_HOST_BUSY; goto out; @@ -585,6 +585,7 @@ static int cxlflash_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scp) } out: + pr_devel("%s: returning rc=%d\n", __func__, rc); return rc; } @@ -657,9 +658,10 @@ static void term_mc(struct cxlflash_cfg *cfg, enum undo_level level) { int rc = 0; struct afu *afu = cfg->afu; + struct device *dev = &cfg->dev->dev; if (!afu || !cfg->mcctx) { - pr_err("%s: returning from term_mc with NULL afu or MC\n", + dev_err(dev, "%s: returning from term_mc with NULL afu or MC\n", __func__); return; } @@ -755,6 +757,7 @@ static int alloc_mem(struct cxlflash_cfg *cfg) int rc = 0; int i; char *buf = NULL; + struct device *dev = &cfg->dev->dev; /* This allocation is about 12K, i.e. only 1 64k page * and upto 4 4k pages @@ -762,8 +765,8 @@ static int alloc_mem(struct cxlflash_cfg *cfg) cfg->afu = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, get_order(sizeof(struct afu))); if (unlikely(!cfg->afu)) { - pr_err("%s: cannot get %d free pages\n", - __func__, get_order(sizeof(struct afu))); + dev_err(dev, "%s: cannot get %d free pages\n", + __func__, get_order(sizeof(struct afu))); rc = -ENOMEM; goto out; } @@ -774,7 +777,8 @@ static int alloc_mem(struct cxlflash_cfg *cfg) if (!((u64)buf & (PAGE_SIZE - 1))) { buf = (void *)__get_free_page(GFP_KERNEL | __GFP_ZERO); if (unlikely(!buf)) { - pr_err("%s: Allocate command buffers fail!\n", + dev_err(dev, + "%s: Allocate command buffers fail!\n", __func__); rc = -ENOMEM; free_mem(cfg); @@ -1280,7 +1284,8 @@ static irqreturn_t cxlflash_rrq_irq(int irq, void *data) static irqreturn_t cxlflash_async_err_irq(int irq, void *data) { struct afu *afu = (struct afu *)data; - struct cxlflash_cfg *cfg; + struct cxlflash_cfg *cfg = afu->parent; + struct device *dev = &cfg->dev->dev; u64 reg_unmasked; const struct asyc_intr_info *info; struct sisl_global_map *global = &afu->afu_map->global; @@ -1288,14 +1293,12 @@ static irqreturn_t cxlflash_async_err_irq(int irq, void *data) u8 port; int i; - cfg = afu->parent; - reg = readq_be(&global->regs.aintr_status); reg_unmasked = (reg & SISL_ASTATUS_UNMASK); if (reg_unmasked == 0) { - pr_err("%s: spurious interrupt, aintr_status 0x%016llX\n", - __func__, reg); + dev_err(dev, "%s: spurious interrupt, aintr_status 0x%016llX\n", + __func__, reg); goto out; } @@ -1310,8 +1313,8 @@ static irqreturn_t cxlflash_async_err_irq(int irq, void *data) port = info->port; - pr_err("%s: FC Port %d -> %s, fc_status 0x%08llX\n", - __func__, port, info->desc, + dev_err(dev, "%s: FC Port %d -> %s, fc_status 0x%08llX\n", + __func__, port, info->desc, readq_be(&global->fc_regs[port][FC_STATUS / 8])); /* @@ -1319,8 +1322,8 @@ static irqreturn_t cxlflash_async_err_irq(int irq, void *data) * again if cleared before or w/o a reset */ if (info->action & LINK_RESET) { - pr_err("%s: FC Port %d: resetting link\n", - __func__, port); + dev_err(dev, "%s: FC Port %d: resetting link\n", + __func__, port); cfg->lr_state = LINK_RESET_REQUIRED; cfg->lr_port = port; schedule_work(&cfg->work_q); @@ -1334,8 +1337,8 @@ static irqreturn_t cxlflash_async_err_irq(int irq, void *data) * should be the same and tracing one is sufficient. */ - pr_err("%s: fc %d: clearing fc_error 0x%08llX\n", - __func__, port, reg); + dev_err(dev, "%s: fc %d: clearing fc_error 0x%08llX\n", + __func__, port, reg); writeq_be(reg, &global->fc_regs[port][FC_ERROR / 8]); writeq_be(0, &global->fc_regs[port][FC_ERRCAP / 8]); @@ -1343,7 +1346,7 @@ static irqreturn_t cxlflash_async_err_irq(int irq, void *data) } out: - pr_debug("%s: returning rc=%d, afu=%p\n", __func__, IRQ_HANDLED, afu); + dev_dbg(dev, "%s: returning IRQ_HANDLED, afu=%p\n", __func__, afu); return IRQ_HANDLED; } @@ -1387,7 +1390,7 @@ static int read_vpd(struct cxlflash_cfg *cfg, u64 wwpn[]) /* Get the VPD data from the device */ vpd_size = pci_read_vpd(dev, 0, sizeof(vpd_data), vpd_data); if (unlikely(vpd_size <= 0)) { - pr_err("%s: Unable to read VPD (size = %ld)\n", + dev_err(&dev->dev, "%s: Unable to read VPD (size = %ld)\n", __func__, vpd_size); rc = -ENODEV; goto out; @@ -1397,7 +1400,8 @@ static int read_vpd(struct cxlflash_cfg *cfg, u64 wwpn[]) ro_start = pci_vpd_find_tag(vpd_data, 0, vpd_size, PCI_VPD_LRDT_RO_DATA); if (unlikely(ro_start < 0)) { - pr_err("%s: VPD Read-only data not found\n", __func__); + dev_err(&dev->dev, "%s: VPD Read-only data not found\n", + __func__); rc = -ENODEV; goto out; } @@ -1426,8 +1430,8 @@ static int read_vpd(struct cxlflash_cfg *cfg, u64 wwpn[]) i = pci_vpd_find_info_keyword(vpd_data, i, j, wwpn_vpd_tags[k]); if (unlikely(i < 0)) { - pr_err("%s: Port %d WWPN not found in VPD\n", - __func__, k); + dev_err(&dev->dev, "%s: Port %d WWPN not found " + "in VPD\n", __func__, k); rc = -ENODEV; goto out; } @@ -1435,7 +1439,8 @@ static int read_vpd(struct cxlflash_cfg *cfg, u64 wwpn[]) j = pci_vpd_info_field_size(&vpd_data[i]); i += PCI_VPD_INFO_FLD_HDR_SIZE; if (unlikely((i + j > vpd_size) || (j != WWPN_LEN))) { - pr_err("%s: Port %d WWPN incomplete or VPD corrupt\n", + dev_err(&dev->dev, "%s: Port %d WWPN incomplete or " + "VPD corrupt\n", __func__, k); rc = -ENODEV; goto out; @@ -1444,8 +1449,8 @@ static int read_vpd(struct cxlflash_cfg *cfg, u64 wwpn[]) memcpy(tmp_buf, &vpd_data[i], WWPN_LEN); rc = kstrtoul(tmp_buf, WWPN_LEN, (ulong *)&wwpn[k]); if (unlikely(rc)) { - pr_err("%s: Fail to convert port %d WWPN to integer\n", - __func__, k); + dev_err(&dev->dev, "%s: Fail to convert port %d WWPN " + "to integer\n", __func__, k); rc = -ENODEV; goto out; } @@ -1502,6 +1507,7 @@ static void init_pcr(struct cxlflash_cfg *cfg) static int init_global(struct cxlflash_cfg *cfg) { struct afu *afu = cfg->afu; + struct device *dev = &cfg->dev->dev; u64 wwpn[NUM_FC_PORTS]; /* wwpn of AFU ports */ int i = 0, num_ports = 0; int rc = 0; @@ -1509,7 +1515,7 @@ static int init_global(struct cxlflash_cfg *cfg) rc = read_vpd(cfg, &wwpn[0]); if (rc) { - pr_err("%s: could not read vpd rc=%d\n", __func__, rc); + dev_err(dev, "%s: could not read vpd rc=%d\n", __func__, rc); goto out; } @@ -1552,7 +1558,7 @@ static int init_global(struct cxlflash_cfg *cfg) afu_set_wwpn(afu, i, &afu->afu_map->global.fc_regs[i][0], wwpn[i])) { - pr_err("%s: failed to set WWPN on port %d\n", + dev_err(dev, "%s: failed to set WWPN on port %d\n", __func__, i); rc = -EIO; goto out; @@ -1795,6 +1801,7 @@ int cxlflash_afu_sync(struct afu *afu, ctx_hndl_t ctx_hndl_u, res_hndl_t res_hndl_u, u8 mode) { struct cxlflash_cfg *cfg = afu->parent; + struct device *dev = &cfg->dev->dev; struct afu_cmd *cmd = NULL; int rc = 0; int retry_cnt = 0; @@ -1813,7 +1820,7 @@ retry: udelay(1000 * retry_cnt); if (retry_cnt < MC_RETRY_CNT) goto retry; - pr_err("%s: could not get a free command\n", __func__); + dev_err(dev, "%s: could not get a free command\n", __func__); rc = -1; goto out; } @@ -2301,6 +2308,7 @@ static void cxlflash_worker_thread(struct work_struct *work) struct cxlflash_cfg *cfg = container_of(work, struct cxlflash_cfg, work_q); struct afu *afu = cfg->afu; + struct device *dev = &cfg->dev->dev; int port; ulong lock_flags; @@ -2314,7 +2322,8 @@ static void cxlflash_worker_thread(struct work_struct *work) if (cfg->lr_state == LINK_RESET_REQUIRED) { port = cfg->lr_port; if (port < 0) - pr_err("%s: invalid port index %d\n", __func__, port); + dev_err(dev, "%s: invalid port index %d\n", + __func__, port); else { spin_unlock_irqrestore(cfg->host->host_lock, lock_flags); @@ -2419,7 +2428,7 @@ static int cxlflash_probe(struct pci_dev *pdev, */ phys_dev = cxl_get_phys_dev(pdev); if (!dev_is_pci(phys_dev)) { - pr_err("%s: not a pci dev\n", __func__); + dev_err(&pdev->dev, "%s: not a pci dev\n", __func__); rc = -ENODEV; goto out_remove; } -- cgit v1.1 From 018d1dc9558e748e271cd1600c698f68cba3fb09 Mon Sep 17 00:00:00 2001 From: "Matthew R. Ochs" Date: Wed, 21 Oct 2015 15:13:21 -0500 Subject: cxlflash: Fix to avoid stall while waiting on TMF Borrowing the TMF waitq's spinlock causes a stall condition when waiting for the TMF to complete. To remedy, introduce our own spin lock to serialize TMF and use the appropriate wait services. Also add a timeout while waiting for a TMF completion. When a TMF times out, report back a failure such that a bigger hammer reset can occur. Signed-off-by: Matthew R. Ochs Signed-off-by: Manoj N. Kumar Reviewed-by: Brian King Reviewed-by: Tomas Henzl Signed-off-by: James Bottomley --- drivers/scsi/cxlflash/common.h | 1 + drivers/scsi/cxlflash/main.c | 55 +++++++++++++++++++++++++----------------- 2 files changed, 34 insertions(+), 22 deletions(-) diff --git a/drivers/scsi/cxlflash/common.h b/drivers/scsi/cxlflash/common.h index b038ac7..7a0cb5c 100644 --- a/drivers/scsi/cxlflash/common.h +++ b/drivers/scsi/cxlflash/common.h @@ -124,6 +124,7 @@ struct cxlflash_cfg { struct list_head lluns; /* list of llun_info structs */ wait_queue_head_t tmf_waitq; + spinlock_t tmf_slock; bool tmf_active; wait_queue_head_t reset_waitq; enum cxlflash_state state; diff --git a/drivers/scsi/cxlflash/main.c b/drivers/scsi/cxlflash/main.c index 527ff85..110037d 100644 --- a/drivers/scsi/cxlflash/main.c +++ b/drivers/scsi/cxlflash/main.c @@ -249,11 +249,10 @@ static void cmd_complete(struct afu_cmd *cmd) scp->scsi_done(scp); if (cmd_is_tmf) { - spin_lock_irqsave(&cfg->tmf_waitq.lock, lock_flags); + spin_lock_irqsave(&cfg->tmf_slock, lock_flags); cfg->tmf_active = false; wake_up_all_locked(&cfg->tmf_waitq); - spin_unlock_irqrestore(&cfg->tmf_waitq.lock, - lock_flags); + spin_unlock_irqrestore(&cfg->tmf_slock, lock_flags); } } else complete(&cmd->cevent); @@ -420,6 +419,7 @@ static int send_tmf(struct afu *afu, struct scsi_cmnd *scp, u64 tmfcmd) struct device *dev = &cfg->dev->dev; ulong lock_flags; int rc = 0; + ulong to; cmd = cmd_checkout(afu); if (unlikely(!cmd)) { @@ -428,15 +428,15 @@ static int send_tmf(struct afu *afu, struct scsi_cmnd *scp, u64 tmfcmd) goto out; } - /* If a Task Management Function is active, do not send one more. - */ - spin_lock_irqsave(&cfg->tmf_waitq.lock, lock_flags); + /* When Task Management Function is active do not send another */ + spin_lock_irqsave(&cfg->tmf_slock, lock_flags); if (cfg->tmf_active) - wait_event_interruptible_locked_irq(cfg->tmf_waitq, - !cfg->tmf_active); + wait_event_interruptible_lock_irq(cfg->tmf_waitq, + !cfg->tmf_active, + cfg->tmf_slock); cfg->tmf_active = true; cmd->cmd_tmf = true; - spin_unlock_irqrestore(&cfg->tmf_waitq.lock, lock_flags); + spin_unlock_irqrestore(&cfg->tmf_slock, lock_flags); cmd->rcb.ctx_id = afu->ctx_hndl; cmd->rcb.port_sel = port_sel; @@ -457,15 +457,24 @@ static int send_tmf(struct afu *afu, struct scsi_cmnd *scp, u64 tmfcmd) rc = send_cmd(afu, cmd); if (unlikely(rc)) { cmd_checkin(cmd); - spin_lock_irqsave(&cfg->tmf_waitq.lock, lock_flags); + spin_lock_irqsave(&cfg->tmf_slock, lock_flags); cfg->tmf_active = false; - spin_unlock_irqrestore(&cfg->tmf_waitq.lock, lock_flags); + spin_unlock_irqrestore(&cfg->tmf_slock, lock_flags); goto out; } - spin_lock_irqsave(&cfg->tmf_waitq.lock, lock_flags); - wait_event_interruptible_locked_irq(cfg->tmf_waitq, !cfg->tmf_active); - spin_unlock_irqrestore(&cfg->tmf_waitq.lock, lock_flags); + spin_lock_irqsave(&cfg->tmf_slock, lock_flags); + to = msecs_to_jiffies(5000); + to = wait_event_interruptible_lock_irq_timeout(cfg->tmf_waitq, + !cfg->tmf_active, + cfg->tmf_slock, + to); + if (!to) { + cfg->tmf_active = false; + dev_err(dev, "%s: TMF timed out!\n", __func__); + rc = -1; + } + spin_unlock_irqrestore(&cfg->tmf_slock, lock_flags); out: return rc; } @@ -512,16 +521,17 @@ static int cxlflash_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scp) get_unaligned_be32(&((u32 *)scp->cmnd)[2]), get_unaligned_be32(&((u32 *)scp->cmnd)[3])); - /* If a Task Management Function is active, wait for it to complete + /* + * If a Task Management Function is active, wait for it to complete * before continuing with regular commands. */ - spin_lock_irqsave(&cfg->tmf_waitq.lock, lock_flags); + spin_lock_irqsave(&cfg->tmf_slock, lock_flags); if (cfg->tmf_active) { - spin_unlock_irqrestore(&cfg->tmf_waitq.lock, lock_flags); + spin_unlock_irqrestore(&cfg->tmf_slock, lock_flags); rc = SCSI_MLQUEUE_HOST_BUSY; goto out; } - spin_unlock_irqrestore(&cfg->tmf_waitq.lock, lock_flags); + spin_unlock_irqrestore(&cfg->tmf_slock, lock_flags); switch (cfg->state) { case STATE_RESET: @@ -713,11 +723,12 @@ static void cxlflash_remove(struct pci_dev *pdev) /* If a Task Management Function is active, wait for it to complete * before continuing with remove. */ - spin_lock_irqsave(&cfg->tmf_waitq.lock, lock_flags); + spin_lock_irqsave(&cfg->tmf_slock, lock_flags); if (cfg->tmf_active) - wait_event_interruptible_locked_irq(cfg->tmf_waitq, - !cfg->tmf_active); - spin_unlock_irqrestore(&cfg->tmf_waitq.lock, lock_flags); + wait_event_interruptible_lock_irq(cfg->tmf_waitq, + !cfg->tmf_active, + cfg->tmf_slock); + spin_unlock_irqrestore(&cfg->tmf_slock, lock_flags); cfg->state = STATE_FAILTERM; cxlflash_stop_term_user_contexts(cfg); -- cgit v1.1 From 8396012ff77affe4def5f0e5757b6c4e8107b33e Mon Sep 17 00:00:00 2001 From: "Matthew R. Ochs" Date: Wed, 21 Oct 2015 15:13:29 -0500 Subject: cxlflash: Fix location of setting resid The resid is incorrectly set which can lead to unnecessary retry attempts by the stack. This is due to resid _always_ being set using a value returned from the adapter. Instead, the value should only be interpreted and set when in an underrun scenario. Signed-off-by: Matthew R. Ochs Signed-off-by: Manoj N. Kumar Reviewed-by: Brian King Reviewed-by: Tomas Henzl Signed-off-by: James Bottomley --- drivers/scsi/cxlflash/main.c | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/drivers/scsi/cxlflash/main.c b/drivers/scsi/cxlflash/main.c index 110037d..5503a40 100644 --- a/drivers/scsi/cxlflash/main.c +++ b/drivers/scsi/cxlflash/main.c @@ -107,6 +107,7 @@ static void process_cmd_err(struct afu_cmd *cmd, struct scsi_cmnd *scp) { struct sisl_ioarcb *ioarcb; struct sisl_ioasa *ioasa; + u32 resid; if (unlikely(!cmd)) return; @@ -115,9 +116,10 @@ static void process_cmd_err(struct afu_cmd *cmd, struct scsi_cmnd *scp) ioasa = &(cmd->sa); if (ioasa->rc.flags & SISL_RC_FLAGS_UNDERRUN) { - pr_debug("%s: cmd underrun cmd = %p scp = %p\n", - __func__, cmd, scp); - scp->result = (DID_ERROR << 16); + resid = ioasa->resid; + scsi_set_resid(scp, resid); + pr_debug("%s: cmd underrun cmd = %p scp = %p, resid = %d\n", + __func__, cmd, scp, resid); } if (ioasa->rc.flags & SISL_RC_FLAGS_OVERRUN) { @@ -158,8 +160,7 @@ static void process_cmd_err(struct afu_cmd *cmd, struct scsi_cmnd *scp) /* If the SISL_RC_FLAGS_OVERRUN flag was set, * then we will handle this error else where. * If not then we must handle it here. - * This is probably an AFU bug. We will - * attempt a retry to see if that resolves it. + * This is probably an AFU bug. */ scp->result = (DID_ERROR << 16); } @@ -183,7 +184,7 @@ static void process_cmd_err(struct afu_cmd *cmd, struct scsi_cmnd *scp) /* We have an AFU error */ switch (ioasa->rc.afu_rc) { case SISL_AFU_RC_NO_CHANNELS: - scp->result = (DID_MEDIUM_ERROR << 16); + scp->result = (DID_NO_CONNECT << 16); break; case SISL_AFU_RC_DATA_DMA_ERR: switch (ioasa->afu_extra) { @@ -217,7 +218,6 @@ static void process_cmd_err(struct afu_cmd *cmd, struct scsi_cmnd *scp) static void cmd_complete(struct afu_cmd *cmd) { struct scsi_cmnd *scp; - u32 resid; ulong lock_flags; struct afu *afu = cmd->parent; struct cxlflash_cfg *cfg = afu->parent; @@ -229,14 +229,11 @@ static void cmd_complete(struct afu_cmd *cmd) if (cmd->rcb.scp) { scp = cmd->rcb.scp; - if (unlikely(cmd->sa.rc.afu_rc || - cmd->sa.rc.scsi_rc || - cmd->sa.rc.fc_rc)) + if (unlikely(cmd->sa.ioasc)) process_cmd_err(cmd, scp); else scp->result = (DID_OK << 16); - resid = cmd->sa.resid; cmd_is_tmf = cmd->cmd_tmf; cmd_checkin(cmd); /* Don't use cmd after here */ @@ -244,7 +241,6 @@ static void cmd_complete(struct afu_cmd *cmd) "ioasc=%d\n", __func__, scp, scp->result, cmd->sa.ioasc); - scsi_set_resid(scp, resid); scsi_dma_unmap(scp); scp->scsi_done(scp); -- cgit v1.1 From ef51074a4efef50873fb8939e7feba5dd55488da Mon Sep 17 00:00:00 2001 From: "Matthew R. Ochs" Date: Wed, 21 Oct 2015 15:13:37 -0500 Subject: cxlflash: Fix host link up event handling Following a link up event, the LUNs available to the host may have changed. Without rescanning the host, the LUN topology is unknown to the user. In such a state, the user would be unable to locate provisioned resources. To remedy, the host should be rescanned after a link up event. Signed-off-by: Matthew R. Ochs Signed-off-by: Manoj N. Kumar Reviewed-by: Brian King Reviewed-by: Tomas Henzl Signed-off-by: James Bottomley --- drivers/scsi/cxlflash/common.h | 1 + drivers/scsi/cxlflash/main.c | 17 +++++++++++++---- drivers/scsi/cxlflash/main.h | 1 + 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/cxlflash/common.h b/drivers/scsi/cxlflash/common.h index 7a0cb5c..faf7f56 100644 --- a/drivers/scsi/cxlflash/common.h +++ b/drivers/scsi/cxlflash/common.h @@ -102,6 +102,7 @@ struct cxlflash_cfg { enum cxlflash_init_state init_state; enum cxlflash_lr_state lr_state; int lr_port; + atomic_t scan_host_needed; struct cxl_afu *cxl_afu; diff --git a/drivers/scsi/cxlflash/main.c b/drivers/scsi/cxlflash/main.c index 5503a40..98fdac1 100644 --- a/drivers/scsi/cxlflash/main.c +++ b/drivers/scsi/cxlflash/main.c @@ -1119,17 +1119,17 @@ static const struct asyc_intr_info ainfo[] = { {SISL_ASTATUS_FC0_CRC_T, "CRC threshold exceeded", 0, LINK_RESET}, {SISL_ASTATUS_FC0_LOGI_R, "login timed out, retrying", 0, 0}, {SISL_ASTATUS_FC0_LOGI_F, "login failed", 0, CLR_FC_ERROR}, - {SISL_ASTATUS_FC0_LOGI_S, "login succeeded", 0, 0}, + {SISL_ASTATUS_FC0_LOGI_S, "login succeeded", 0, SCAN_HOST}, {SISL_ASTATUS_FC0_LINK_DN, "link down", 0, 0}, - {SISL_ASTATUS_FC0_LINK_UP, "link up", 0, 0}, + {SISL_ASTATUS_FC0_LINK_UP, "link up", 0, SCAN_HOST}, {SISL_ASTATUS_FC1_OTHER, "other error", 1, CLR_FC_ERROR | LINK_RESET}, {SISL_ASTATUS_FC1_LOGO, "target initiated LOGO", 1, 0}, {SISL_ASTATUS_FC1_CRC_T, "CRC threshold exceeded", 1, LINK_RESET}, {SISL_ASTATUS_FC1_LOGI_R, "login timed out, retrying", 1, 0}, {SISL_ASTATUS_FC1_LOGI_F, "login failed", 1, CLR_FC_ERROR}, - {SISL_ASTATUS_FC1_LOGI_S, "login succeeded", 1, 0}, + {SISL_ASTATUS_FC1_LOGI_S, "login succeeded", 1, SCAN_HOST}, {SISL_ASTATUS_FC1_LINK_DN, "link down", 1, 0}, - {SISL_ASTATUS_FC1_LINK_UP, "link up", 1, 0}, + {SISL_ASTATUS_FC1_LINK_UP, "link up", 1, SCAN_HOST}, {0x0, "", 0, 0} /* terminator */ }; @@ -1350,6 +1350,11 @@ static irqreturn_t cxlflash_async_err_irq(int irq, void *data) writeq_be(reg, &global->fc_regs[port][FC_ERROR / 8]); writeq_be(0, &global->fc_regs[port][FC_ERRCAP / 8]); } + + if (info->action & SCAN_HOST) { + atomic_inc(&cfg->scan_host_needed); + schedule_work(&cfg->work_q); + } } out: @@ -2309,6 +2314,7 @@ MODULE_DEVICE_TABLE(pci, cxlflash_pci_table); * - Link reset which cannot be performed on interrupt context due to * blocking up to a few seconds * - Read AFU command room + * - Rescan the host */ static void cxlflash_worker_thread(struct work_struct *work) { @@ -2351,6 +2357,9 @@ static void cxlflash_worker_thread(struct work_struct *work) } spin_unlock_irqrestore(cfg->host->host_lock, lock_flags); + + if (atomic_dec_if_positive(&cfg->scan_host_needed) >= 0) + scsi_scan_host(cfg->host); } /** diff --git a/drivers/scsi/cxlflash/main.h b/drivers/scsi/cxlflash/main.h index cf0e809..6032456 100644 --- a/drivers/scsi/cxlflash/main.h +++ b/drivers/scsi/cxlflash/main.h @@ -99,6 +99,7 @@ struct asyc_intr_info { u8 action; #define CLR_FC_ERROR 0x01 #define LINK_RESET 0x02 +#define SCAN_HOST 0x04 }; #ifndef CONFIG_CXL_EEH -- cgit v1.1 From 16798d3448d33af336e89f8cc6e72a0a3d04e230 Mon Sep 17 00:00:00 2001 From: "Matthew R. Ochs" Date: Wed, 21 Oct 2015 15:13:45 -0500 Subject: cxlflash: Fix async interrupt bypass logic A bug was introduced earlier in the development cycle when cleaning up logic statements. Instead of skipping bits that are not set, set bits are skipped, causing async interrupts to not be handled correctly. To fix, simply add back in the proper evaluation for an unset bit. Signed-off-by: Matthew R. Ochs Signed-off-by: Manoj N. Kumar Reviewed-by: Brian King Reviewed-by: Andrew Donnellan Reviewed-by: Tomas Henzl Signed-off-by: James Bottomley --- drivers/scsi/cxlflash/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/cxlflash/main.c b/drivers/scsi/cxlflash/main.c index 98fdac1..ed9fd8c 100644 --- a/drivers/scsi/cxlflash/main.c +++ b/drivers/scsi/cxlflash/main.c @@ -1315,7 +1315,7 @@ static irqreturn_t cxlflash_async_err_irq(int irq, void *data) /* check each bit that is on */ for (i = 0; reg_unmasked; i++, reg_unmasked = (reg_unmasked >> 1)) { info = find_ainfo(1ULL << i); - if ((reg_unmasked & 0x1) || !info) + if (((reg_unmasked & 0x1) == 0) || !info) continue; port = info->port; -- cgit v1.1 From 964497b3bf3fed0a1db9dabe9fe080853230e5a7 Mon Sep 17 00:00:00 2001 From: "Matthew R. Ochs" Date: Wed, 21 Oct 2015 15:13:54 -0500 Subject: cxlflash: Remove dual port online dependency At present, both ports must be online for the device to configure properly. Remove this dependency and the unnecessary internal LUN override logic as well. Additionally, as a refactoring measure, change the return code variable name to match that used throughout the driver. With this change, the card will be able to configure even when the link is down. At some later point when the link is transitioned to 'up', a link state change interrupt will trigger the port configuration. Note that despite its void-like behavior, the function was left with a return code for right now in case its behavior needs to be altered again in the near future based on testing. Signed-off-by: Matthew R. Ochs Signed-off-by: Manoj N. Kumar Reviewed-by: Brian King Reviewed-by: Daniel Axtens Reviewed-by: Tomas Henzl Signed-off-by: James Bottomley --- drivers/scsi/cxlflash/main.c | 27 ++++++++++----------------- 1 file changed, 10 insertions(+), 17 deletions(-) diff --git a/drivers/scsi/cxlflash/main.c b/drivers/scsi/cxlflash/main.c index ed9fd8c..c25efc3 100644 --- a/drivers/scsi/cxlflash/main.c +++ b/drivers/scsi/cxlflash/main.c @@ -1030,7 +1030,7 @@ static int wait_port_offline(u64 *fc_regs, u32 delay_us, u32 nretry) */ static int afu_set_wwpn(struct afu *afu, int port, u64 *fc_regs, u64 wwpn) { - int ret = 0; + int rc = 0; set_port_offline(fc_regs); @@ -1038,33 +1038,26 @@ static int afu_set_wwpn(struct afu *afu, int port, u64 *fc_regs, u64 wwpn) FC_PORT_STATUS_RETRY_CNT)) { pr_debug("%s: wait on port %d to go offline timed out\n", __func__, port); - ret = -1; /* but continue on to leave the port back online */ + rc = -1; /* but continue on to leave the port back online */ } - if (ret == 0) + if (rc == 0) writeq_be(wwpn, &fc_regs[FC_PNAME / 8]); + /* Always return success after programming WWPN */ + rc = 0; + set_port_online(fc_regs); if (!wait_port_online(fc_regs, FC_PORT_STATUS_RETRY_INTERVAL_US, FC_PORT_STATUS_RETRY_CNT)) { - pr_debug("%s: wait on port %d to go online timed out\n", - __func__, port); - ret = -1; - - /* - * Override for internal lun!!! - */ - if (afu->internal_lun) { - pr_debug("%s: Overriding port %d online timeout!!!\n", - __func__, port); - ret = 0; - } + pr_err("%s: wait on port %d to go online timed out\n", + __func__, port); } - pr_debug("%s: returning rc=%d\n", __func__, ret); + pr_debug("%s: returning rc=%d\n", __func__, rc); - return ret; + return rc; } /** -- cgit v1.1 From e5ce067b7b6e123a88929a18a8a58811ffcec279 Mon Sep 17 00:00:00 2001 From: "Matthew R. Ochs" Date: Wed, 21 Oct 2015 15:14:01 -0500 Subject: cxlflash: Fix AFU version access/storage and add check The AFU version is stored as a non-terminated string of bytes within a 64-bit little-endian register. Presently the value is read directly (no MMIO accessor) and is stored in a buffer that is not big enough to contain a NULL terminator. Additionally the version obtained is not evaluated against a known value to prevent usage with unsupported AFUs. All of these deficiencies can lead to a variety of problems. To remedy, use the correct MMIO accessor to read the version value into a null-terminated buffer and add a check to prevent an incompatible AFU from being used with this driver. Signed-off-by: Matthew R. Ochs Signed-off-by: Manoj N. Kumar Reviewed-by: Brian King Reviewed-by: Daniel Axtens Reviewed-by: Tomas Henzl Signed-off-by: James Bottomley --- drivers/scsi/cxlflash/common.h | 2 +- drivers/scsi/cxlflash/main.c | 18 ++++++++++++------ drivers/scsi/cxlflash/sislite.h | 2 +- 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/drivers/scsi/cxlflash/common.h b/drivers/scsi/cxlflash/common.h index faf7f56..3be5754 100644 --- a/drivers/scsi/cxlflash/common.h +++ b/drivers/scsi/cxlflash/common.h @@ -179,7 +179,7 @@ struct afu { u32 cmd_couts; /* Number of command checkouts */ u32 internal_lun; /* User-desired LUN mode for this AFU */ - char version[8]; + char version[16]; u64 interface_version; struct cxlflash_cfg *parent; /* Pointer back to parent cxlflash_cfg */ diff --git a/drivers/scsi/cxlflash/main.c b/drivers/scsi/cxlflash/main.c index c25efc3..c1d5c88 100644 --- a/drivers/scsi/cxlflash/main.c +++ b/drivers/scsi/cxlflash/main.c @@ -1751,14 +1751,20 @@ static int init_afu(struct cxlflash_cfg *cfg) goto err1; } - /* don't byte reverse on reading afu_version, else the string form */ - /* will be backwards */ - reg = afu->afu_map->global.regs.afu_version; - memcpy(afu->version, ®, 8); + /* No byte reverse on reading afu_version or string will be backwards */ + reg = readq(&afu->afu_map->global.regs.afu_version); + memcpy(afu->version, ®, sizeof(reg)); afu->interface_version = readq_be(&afu->afu_map->global.regs.interface_version); - pr_debug("%s: afu version %s, interface version 0x%llX\n", - __func__, afu->version, afu->interface_version); + if ((afu->interface_version + 1) == 0) { + pr_err("Back level AFU, please upgrade. AFU version %s " + "interface version 0x%llx\n", afu->version, + afu->interface_version); + rc = -EINVAL; + goto err1; + } else + pr_debug("%s: afu version %s, interface version 0x%llX\n", + __func__, afu->version, afu->interface_version); rc = start_afu(cfg); if (rc) { diff --git a/drivers/scsi/cxlflash/sislite.h b/drivers/scsi/cxlflash/sislite.h index 63bf394..8425d1a 100644 --- a/drivers/scsi/cxlflash/sislite.h +++ b/drivers/scsi/cxlflash/sislite.h @@ -340,7 +340,7 @@ struct sisl_global_regs { #define SISL_AFUCONF_MBOX_CLR_READ 0x0010ULL __be64 afu_config; __be64 rsvd[0xf8]; - __be64 afu_version; + __le64 afu_version; __be64 interface_version; }; -- cgit v1.1 From 8b5b1e871a736e93e6ef1b048c276975e7421e04 Mon Sep 17 00:00:00 2001 From: "Matthew R. Ochs" Date: Wed, 21 Oct 2015 15:14:09 -0500 Subject: cxlflash: Correct usage of scsi_host_put() Currently, scsi_host_put() is being called prematurely in the remove path and is missing entirely in an error cleanup path. The former can lead to memory being freed too early with subsequent access potentially corrupting data whilst the former would result in a memory leak. Move the usage on remove to be the last cleanup action taken and introduce a call to scsi_host_put() in the one initialization error path that does not use remove to cleanup. Signed-off-by: Matthew R. Ochs Signed-off-by: Manoj N. Kumar Reviewed-by: Brian King Reviewed-by: Tomas Henzl Signed-off-by: James Bottomley --- drivers/scsi/cxlflash/main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/cxlflash/main.c b/drivers/scsi/cxlflash/main.c index c1d5c88..6b8b159 100644 --- a/drivers/scsi/cxlflash/main.c +++ b/drivers/scsi/cxlflash/main.c @@ -733,7 +733,6 @@ static void cxlflash_remove(struct pci_dev *pdev) case INIT_STATE_SCSI: cxlflash_term_local_luns(cfg); scsi_remove_host(cfg->host); - scsi_host_put(cfg->host); /* Fall through */ case INIT_STATE_AFU: term_afu(cfg); @@ -743,6 +742,7 @@ static void cxlflash_remove(struct pci_dev *pdev) case INIT_STATE_NONE: flush_work(&cfg->work_q); free_mem(cfg); + scsi_host_put(cfg->host); break; } @@ -2404,6 +2404,7 @@ static int cxlflash_probe(struct pci_dev *pdev, dev_err(&pdev->dev, "%s: call to scsi_host_alloc failed!\n", __func__); rc = -ENOMEM; + scsi_host_put(cfg->host); goto out; } -- cgit v1.1 From d804621d0275da84caedcf2d6cf03fbe3c9ac3aa Mon Sep 17 00:00:00 2001 From: "Matthew R. Ochs" Date: Wed, 21 Oct 2015 15:14:17 -0500 Subject: cxlflash: Fix to prevent workq from accessing freed memory The workq can process work in parallel with a remove event, leading to a condition where the workq handler can access freed memory. To remedy, the workq should be terminated prior to freeing memory. Move the termination call earlier in remove and use cancel_work_sync() instead of flush_work() as there is not a need to process any scheduled work when shutting down. Signed-off-by: Matthew R. Ochs Signed-off-by: Manoj N. Kumar Reviewed-by: Brian King Reviewed-by: Tomas Henzl Signed-off-by: James Bottomley --- drivers/scsi/cxlflash/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/cxlflash/main.c b/drivers/scsi/cxlflash/main.c index 6b8b159..d0b9972 100644 --- a/drivers/scsi/cxlflash/main.c +++ b/drivers/scsi/cxlflash/main.c @@ -736,11 +736,11 @@ static void cxlflash_remove(struct pci_dev *pdev) /* Fall through */ case INIT_STATE_AFU: term_afu(cfg); + cancel_work_sync(&cfg->work_q); case INIT_STATE_PCI: pci_release_regions(cfg->dev); pci_disable_device(pdev); case INIT_STATE_NONE: - flush_work(&cfg->work_q); free_mem(cfg); scsi_host_put(cfg->host); break; -- cgit v1.1 From ed486daad27afdcb24cee4ea0b1c9f44281e74fc Mon Sep 17 00:00:00 2001 From: "Matthew R. Ochs" Date: Wed, 21 Oct 2015 15:14:24 -0500 Subject: cxlflash: Correct behavior in device reset handler following EEH When the device reset handler is entered while a reset operation is taking place, the handler exits without actually sending a reset (TMF) to the targeted device. This behavior is incorrect as the device is not reset. Further complicating matters is the fact that a success is returned even when the TMF was not sent. To fix, the state is rechecked after coming out of the reset state. When the state is normal, a TMF will be sent out. Signed-off-by: Matthew R. Ochs Signed-off-by: Manoj N. Kumar Reviewed-by: Brian King Reviewed-by: Tomas Henzl Signed-off-by: James Bottomley --- drivers/scsi/cxlflash/main.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/cxlflash/main.c b/drivers/scsi/cxlflash/main.c index d0b9972..89bd4c3 100644 --- a/drivers/scsi/cxlflash/main.c +++ b/drivers/scsi/cxlflash/main.c @@ -1920,6 +1920,7 @@ static int cxlflash_eh_device_reset_handler(struct scsi_cmnd *scp) get_unaligned_be32(&((u32 *)scp->cmnd)[2]), get_unaligned_be32(&((u32 *)scp->cmnd)[3])); +retry: switch (cfg->state) { case STATE_NORMAL: rcr = send_tmf(afu, scp, TMF_LUN_RESET); @@ -1928,9 +1929,7 @@ static int cxlflash_eh_device_reset_handler(struct scsi_cmnd *scp) break; case STATE_RESET: wait_event(cfg->reset_waitq, cfg->state != STATE_RESET); - if (cfg->state == STATE_NORMAL) - break; - /* fall through */ + goto retry; default: rc = FAILED; break; -- cgit v1.1 From 6ef6f94060dc435742a4ff5feae2b2c4b2e57077 Mon Sep 17 00:00:00 2001 From: "Matthew R. Ochs" Date: Wed, 21 Oct 2015 15:14:32 -0500 Subject: cxlflash: Remove unnecessary scsi_block_requests The host reset handler is called with I/O already blocked, thus there is no need to explicitly block and unblock I/O in the handler. Signed-off-by: Matthew R. Ochs Signed-off-by: Manoj N. Kumar Reviewed-by: Brian King Reviewed-by: Tomas Henzl Signed-off-by: James Bottomley --- drivers/scsi/cxlflash/main.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/scsi/cxlflash/main.c b/drivers/scsi/cxlflash/main.c index 89bd4c3..441e897 100644 --- a/drivers/scsi/cxlflash/main.c +++ b/drivers/scsi/cxlflash/main.c @@ -1966,7 +1966,6 @@ static int cxlflash_eh_host_reset_handler(struct scsi_cmnd *scp) switch (cfg->state) { case STATE_NORMAL: cfg->state = STATE_RESET; - scsi_block_requests(cfg->host); cxlflash_mark_contexts_error(cfg); rcr = afu_reset(cfg); if (rcr) { @@ -1975,7 +1974,6 @@ static int cxlflash_eh_host_reset_handler(struct scsi_cmnd *scp) } else cfg->state = STATE_NORMAL; wake_up_all(&cfg->reset_waitq); - scsi_unblock_requests(cfg->host); break; case STATE_RESET: wait_event(cfg->reset_waitq, cfg->state != STATE_RESET); -- cgit v1.1 From 1284fb0cff10fcc3df1e9a50a795868d346fa647 Mon Sep 17 00:00:00 2001 From: "Matthew R. Ochs" Date: Wed, 21 Oct 2015 15:14:40 -0500 Subject: cxlflash: Fix function prolog parameters and return codes Several function prologs have incorrect parameter names and return code descriptions. This can lead to confusion when reviewing the source and creates inaccurate documentation. To remedy, update the function prologs to properly reflect parameter names and return codes. Signed-off-by: Matthew R. Ochs Signed-off-by: Manoj N. Kumar Reviewed-by: Brian King Reviewed-by: Andrew Donnellan Reviewed-by: Tomas Henzl Signed-off-by: James Bottomley --- drivers/scsi/cxlflash/main.c | 70 ++++++++++++++++---------------------------- 1 file changed, 26 insertions(+), 44 deletions(-) diff --git a/drivers/scsi/cxlflash/main.c b/drivers/scsi/cxlflash/main.c index 441e897..f37e968 100644 --- a/drivers/scsi/cxlflash/main.c +++ b/drivers/scsi/cxlflash/main.c @@ -314,7 +314,7 @@ write_rrin: * @cmd: AFU command to send. * * Return: - * 0 on success or SCSI_MLQUEUE_HOST_BUSY + * 0 on success, SCSI_MLQUEUE_HOST_BUSY on failure */ static int send_cmd(struct afu *afu, struct afu_cmd *cmd) { @@ -401,8 +401,7 @@ static void wait_resp(struct afu *afu, struct afu_cmd *cmd) * @tmfcmd: TMF command to send. * * Return: - * 0 on success - * SCSI_MLQUEUE_HOST_BUSY when host is busy + * 0 on success, SCSI_MLQUEUE_HOST_BUSY on failure */ static int send_tmf(struct afu *afu, struct scsi_cmnd *scp, u64 tmfcmd) { @@ -491,9 +490,7 @@ static const char *cxlflash_driver_info(struct Scsi_Host *host) * @host: SCSI host associated with device. * @scp: SCSI command to send. * - * Return: - * 0 on success - * SCSI_MLQUEUE_HOST_BUSY when host is busy + * Return: 0 on success, SCSI_MLQUEUE_HOST_BUSY on failure */ static int cxlflash_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scp) { @@ -597,7 +594,7 @@ out: /** * cxlflash_wait_for_pci_err_recovery() - wait for error recovery during probe - * @cxlflash: Internal structure associated with the host. + * @cfg: Internal structure associated with the host. */ static void cxlflash_wait_for_pci_err_recovery(struct cxlflash_cfg *cfg) { @@ -611,7 +608,7 @@ static void cxlflash_wait_for_pci_err_recovery(struct cxlflash_cfg *cfg) /** * free_mem() - free memory associated with the AFU - * @cxlflash: Internal structure associated with the host. + * @cfg: Internal structure associated with the host. */ static void free_mem(struct cxlflash_cfg *cfg) { @@ -633,7 +630,7 @@ static void free_mem(struct cxlflash_cfg *cfg) /** * stop_afu() - stops the AFU command timers and unmaps the MMIO space - * @cxlflash: Internal structure associated with the host. + * @cfg: Internal structure associated with the host. * * Safe to call with AFU in a partially allocated/initialized state. */ @@ -655,7 +652,7 @@ static void stop_afu(struct cxlflash_cfg *cfg) /** * term_mc() - terminates the master context - * @cxlflash: Internal structure associated with the host. + * @cfg: Internal structure associated with the host. * @level: Depth of allocation, where to begin waterfall tear down. * * Safe to call with AFU/MC in partially allocated/initialized state. @@ -691,7 +688,7 @@ static void term_mc(struct cxlflash_cfg *cfg, enum undo_level level) /** * term_afu() - terminates the AFU - * @cxlflash: Internal structure associated with the host. + * @cfg: Internal structure associated with the host. * * Safe to call with AFU/MC in partially allocated/initialized state. */ @@ -751,7 +748,7 @@ static void cxlflash_remove(struct pci_dev *pdev) /** * alloc_mem() - allocates the AFU and its command pool - * @cxlflash: Internal structure associated with the host. + * @cfg: Internal structure associated with the host. * * A partially allocated state remains on failure. * @@ -804,12 +801,9 @@ out: /** * init_pci() - initializes the host as a PCI device - * @cxlflash: Internal structure associated with the host. + * @cfg: Internal structure associated with the host. * - * Return: - * 0 on success - * -EIO on unable to communicate with device - * A return code from the PCI sub-routines + * Return: 0 on success, -errno on failure */ static int init_pci(struct cxlflash_cfg *cfg) { @@ -889,11 +883,9 @@ out_release_regions: /** * init_scsi() - adds the host to the SCSI stack and kicks off host scan - * @cxlflash: Internal structure associated with the host. + * @cfg: Internal structure associated with the host. * - * Return: - * 0 on success - * A return code from adding the host + * Return: 0 on success, -errno on failure */ static int init_scsi(struct cxlflash_cfg *cfg) { @@ -1357,7 +1349,7 @@ out: /** * start_context() - starts the master context - * @cxlflash: Internal structure associated with the host. + * @cfg: Internal structure associated with the host. * * Return: A success or failure value from CXL services. */ @@ -1375,12 +1367,10 @@ static int start_context(struct cxlflash_cfg *cfg) /** * read_vpd() - obtains the WWPNs from VPD - * @cxlflash: Internal structure associated with the host. + * @cfg: Internal structure associated with the host. * @wwpn: Array of size NUM_FC_PORTS to pass back WWPNs * - * Return: - * 0 on success - * -ENODEV when VPD or WWPN keywords not found + * Return: 0 on success, -errno on failure */ static int read_vpd(struct cxlflash_cfg *cfg, u64 wwpn[]) { @@ -1468,7 +1458,7 @@ out: /** * init_pcr() - initialize the provisioning and control registers - * @cxlflash: Internal structure associated with the host. + * @cfg: Internal structure associated with the host. * * Also sets up fast access to the mapped registers and initializes AFU * command fields that never change. @@ -1507,7 +1497,7 @@ static void init_pcr(struct cxlflash_cfg *cfg) /** * init_global() - initialize AFU global registers - * @cxlflash: Internal structure associated with the host. + * @cfg: Internal structure associated with the host. */ static int init_global(struct cxlflash_cfg *cfg) { @@ -1592,7 +1582,7 @@ out: /** * start_afu() - initializes and starts the AFU - * @cxlflash: Internal structure associated with the host. + * @cfg: Internal structure associated with the host. */ static int start_afu(struct cxlflash_cfg *cfg) { @@ -1626,12 +1616,9 @@ static int start_afu(struct cxlflash_cfg *cfg) /** * init_mc() - create and register as the master context - * @cxlflash: Internal structure associated with the host. + * @cfg: Internal structure associated with the host. * - * Return: - * 0 on success - * -ENOMEM when unable to obtain a context from CXL services - * A failure value from CXL services. + * Return: 0 on success, -errno on failure */ static int init_mc(struct cxlflash_cfg *cfg) { @@ -1715,15 +1702,12 @@ out: /** * init_afu() - setup as master context and start AFU - * @cxlflash: Internal structure associated with the host. + * @cfg: Internal structure associated with the host. * * This routine is a higher level of control for configuring the * AFU on probe and reset paths. * - * Return: - * 0 on success - * -ENOMEM when unable to map the AFU MMIO space - * A failure value from internal services. + * Return: 0 on success, -errno on failure */ static int init_afu(struct cxlflash_cfg *cfg) { @@ -1876,9 +1860,7 @@ out: * afu_reset() - resets the AFU * @cfg: Internal structure associated with the host. * - * Return: - * 0 on success - * A failure value from internal services. + * Return: 0 on success, -errno on failure */ static int afu_reset(struct cxlflash_cfg *cfg) { @@ -2363,7 +2345,7 @@ static void cxlflash_worker_thread(struct work_struct *work) * @pdev: PCI device associated with the host. * @dev_id: PCI device id associated with device. * - * Return: 0 on success / non-zero on failure + * Return: 0 on success, -errno on failure */ static int cxlflash_probe(struct pci_dev *pdev, const struct pci_device_id *dev_id) @@ -2597,7 +2579,7 @@ static struct pci_driver cxlflash_driver = { /** * init_cxlflash() - module entry point * - * Return: 0 on success / non-zero on failure + * Return: 0 on success, -errno on failure */ static int __init init_cxlflash(void) { -- cgit v1.1 From 1786f4a0933198632c5e4d27f25e1d467e1fd032 Mon Sep 17 00:00:00 2001 From: "Matthew R. Ochs" Date: Wed, 21 Oct 2015 15:14:48 -0500 Subject: cxlflash: Fix MMIO and endianness errors Sparse uncovered several errors with MMIO operations (accessing directly) and handling endianness. These can cause issues when running in different environments. Introduce __iomem and proper endianness tags/swaps where appropriate to make driver sparse clean. Signed-off-by: Matthew R. Ochs Signed-off-by: Manoj N. Kumar Reviewed-by: Brian King Reviewed-by: Andrew Donnellan Reviewed-by: Tomas Henzl Signed-off-by: James Bottomley --- drivers/scsi/cxlflash/common.h | 10 +++++----- drivers/scsi/cxlflash/main.c | 25 +++++++++++++------------ drivers/scsi/cxlflash/superpipe.c | 6 +++--- drivers/scsi/cxlflash/superpipe.h | 2 +- drivers/scsi/cxlflash/vlun.c | 4 ++-- 5 files changed, 24 insertions(+), 23 deletions(-) diff --git a/drivers/scsi/cxlflash/common.h b/drivers/scsi/cxlflash/common.h index 3be5754..a810585 100644 --- a/drivers/scsi/cxlflash/common.h +++ b/drivers/scsi/cxlflash/common.h @@ -164,9 +164,9 @@ struct afu { /* AFU HW */ struct cxl_ioctl_start_work work; - struct cxlflash_afu_map *afu_map; /* entire MMIO map */ - struct sisl_host_map *host_map; /* MC host map */ - struct sisl_ctrl_map *ctrl_map; /* MC control map */ + struct cxlflash_afu_map __iomem *afu_map; /* entire MMIO map */ + struct sisl_host_map __iomem *host_map; /* MC host map */ + struct sisl_ctrl_map __iomem *ctrl_map; /* MC control map */ ctx_hndl_t ctx_hndl; /* master's context handle */ u64 *hrrq_start; @@ -188,10 +188,10 @@ struct afu { static inline u64 lun_to_lunid(u64 lun) { - u64 lun_id; + __be64 lun_id; int_to_scsilun(lun, (struct scsi_lun *)&lun_id); - return swab64(lun_id); + return be64_to_cpu(lun_id); } int cxlflash_afu_sync(struct afu *, ctx_hndl_t, res_hndl_t, u8); diff --git a/drivers/scsi/cxlflash/main.c b/drivers/scsi/cxlflash/main.c index f37e968..14fb9b4 100644 --- a/drivers/scsi/cxlflash/main.c +++ b/drivers/scsi/cxlflash/main.c @@ -644,7 +644,7 @@ static void stop_afu(struct cxlflash_cfg *cfg) complete(&afu->cmd[i].cevent); if (likely(afu->afu_map)) { - cxl_psa_unmap((void *)afu->afu_map); + cxl_psa_unmap((void __iomem *)afu->afu_map); afu->afu_map = NULL; } } @@ -914,7 +914,7 @@ out: * that the FC link layer has synced, completed the handshaking process, and * is ready for login to start. */ -static void set_port_online(u64 *fc_regs) +static void set_port_online(__be64 __iomem *fc_regs) { u64 cmdcfg; @@ -930,7 +930,7 @@ static void set_port_online(u64 *fc_regs) * * The provided MMIO region must be mapped prior to call. */ -static void set_port_offline(u64 *fc_regs) +static void set_port_offline(__be64 __iomem *fc_regs) { u64 cmdcfg; @@ -954,7 +954,7 @@ static void set_port_offline(u64 *fc_regs) * FALSE (0) when the specified port fails to come online after timeout * -EINVAL when @delay_us is less than 1000 */ -static int wait_port_online(u64 *fc_regs, u32 delay_us, u32 nretry) +static int wait_port_online(__be64 __iomem *fc_regs, u32 delay_us, u32 nretry) { u64 status; @@ -985,7 +985,7 @@ static int wait_port_online(u64 *fc_regs, u32 delay_us, u32 nretry) * FALSE (0) when the specified port fails to go offline after timeout * -EINVAL when @delay_us is less than 1000 */ -static int wait_port_offline(u64 *fc_regs, u32 delay_us, u32 nretry) +static int wait_port_offline(__be64 __iomem *fc_regs, u32 delay_us, u32 nretry) { u64 status; @@ -1020,7 +1020,8 @@ static int wait_port_offline(u64 *fc_regs, u32 delay_us, u32 nretry) * 0 when the WWPN is successfully written and the port comes back online * -1 when the port fails to go offline or come back up online */ -static int afu_set_wwpn(struct afu *afu, int port, u64 *fc_regs, u64 wwpn) +static int afu_set_wwpn(struct afu *afu, int port, __be64 __iomem *fc_regs, + u64 wwpn) { int rc = 0; @@ -1065,7 +1066,7 @@ static int afu_set_wwpn(struct afu *afu, int port, u64 *fc_regs, u64 wwpn) * the alternate port exclusively while the reset takes place. * failure to come online is overridden. */ -static void afu_link_reset(struct afu *afu, int port, u64 *fc_regs) +static void afu_link_reset(struct afu *afu, int port, __be64 __iomem *fc_regs) { u64 port_sel; @@ -1280,7 +1281,7 @@ static irqreturn_t cxlflash_async_err_irq(int irq, void *data) struct device *dev = &cfg->dev->dev; u64 reg_unmasked; const struct asyc_intr_info *info; - struct sisl_global_map *global = &afu->afu_map->global; + struct sisl_global_map __iomem *global = &afu->afu_map->global; u64 reg; u8 port; int i; @@ -1466,7 +1467,7 @@ out: static void init_pcr(struct cxlflash_cfg *cfg) { struct afu *afu = cfg->afu; - struct sisl_ctrl_map *ctrl_map; + struct sisl_ctrl_map __iomem *ctrl_map; int i; for (i = 0; i < MAX_CONTEXT; i++) { @@ -1755,7 +1756,7 @@ static int init_afu(struct cxlflash_cfg *cfg) dev_err(dev, "%s: call to start_afu failed, rc=%d!\n", __func__, rc); term_mc(cfg, UNDO_START); - cxl_psa_unmap((void *)afu->afu_map); + cxl_psa_unmap((void __iomem *)afu->afu_map); afu->afu_map = NULL; goto err1; } @@ -1835,8 +1836,8 @@ retry: cmd->rcb.cdb[1] = mode; /* The cdb is aligned, no unaligned accessors required */ - *((u16 *)&cmd->rcb.cdb[2]) = swab16(ctx_hndl_u); - *((u32 *)&cmd->rcb.cdb[4]) = swab32(res_hndl_u); + *((__be16 *)&cmd->rcb.cdb[2]) = cpu_to_be16(ctx_hndl_u); + *((__be32 *)&cmd->rcb.cdb[4]) = cpu_to_be32(res_hndl_u); rc = send_cmd(afu, cmd); if (unlikely(rc)) diff --git a/drivers/scsi/cxlflash/superpipe.c b/drivers/scsi/cxlflash/superpipe.c index 577aa25..e99a0eb 100644 --- a/drivers/scsi/cxlflash/superpipe.c +++ b/drivers/scsi/cxlflash/superpipe.c @@ -253,7 +253,7 @@ static int afu_attach(struct cxlflash_cfg *cfg, struct ctx_info *ctxi) { struct device *dev = &cfg->dev->dev; struct afu *afu = cfg->afu; - struct sisl_ctrl_map *ctrl_map = ctxi->ctrl_map; + struct sisl_ctrl_map __iomem *ctrl_map = ctxi->ctrl_map; int rc = 0; u64 val; @@ -365,8 +365,8 @@ retry: * as the buffer is allocated on an aligned boundary. */ mutex_lock(&gli->mutex); - gli->max_lba = be64_to_cpu(*((u64 *)&cmd_buf[0])); - gli->blk_len = be32_to_cpu(*((u32 *)&cmd_buf[8])); + gli->max_lba = be64_to_cpu(*((__be64 *)&cmd_buf[0])); + gli->blk_len = be32_to_cpu(*((__be32 *)&cmd_buf[8])); mutex_unlock(&gli->mutex); out: diff --git a/drivers/scsi/cxlflash/superpipe.h b/drivers/scsi/cxlflash/superpipe.h index 7947091..7df88ee 100644 --- a/drivers/scsi/cxlflash/superpipe.h +++ b/drivers/scsi/cxlflash/superpipe.h @@ -91,7 +91,7 @@ enum ctx_ctrl { #define DECODE_CTXID(_val) (_val & 0xFFFFFFFF) struct ctx_info { - struct sisl_ctrl_map *ctrl_map; /* initialized at startup */ + struct sisl_ctrl_map __iomem *ctrl_map; /* initialized at startup */ struct sisl_rht_entry *rht_start; /* 1 page (req'd for alignment), alloc/free on attach/detach */ u32 rht_out; /* Number of checked out RHT entries */ diff --git a/drivers/scsi/cxlflash/vlun.c b/drivers/scsi/cxlflash/vlun.c index 96b074f..f91b5b3 100644 --- a/drivers/scsi/cxlflash/vlun.c +++ b/drivers/scsi/cxlflash/vlun.c @@ -786,7 +786,7 @@ void cxlflash_restore_luntable(struct cxlflash_cfg *cfg) u32 chan; u32 lind; struct afu *afu = cfg->afu; - struct sisl_global_map *agm = &afu->afu_map->global; + struct sisl_global_map __iomem *agm = &afu->afu_map->global; mutex_lock(&global.mutex); @@ -831,7 +831,7 @@ static int init_luntable(struct cxlflash_cfg *cfg, struct llun_info *lli) u32 lind; int rc = 0; struct afu *afu = cfg->afu; - struct sisl_global_map *agm = &afu->afu_map->global; + struct sisl_global_map __iomem *agm = &afu->afu_map->global; mutex_lock(&global.mutex); -- cgit v1.1 From 8e78262328ecfbe9d72ac40328ecf5e7ff6fc3bf Mon Sep 17 00:00:00 2001 From: "Matthew R. Ochs" Date: Wed, 21 Oct 2015 15:14:56 -0500 Subject: cxlflash: Fix to prevent EEH recovery failure The process_sense() routine can perform a read capacity which can take some time to complete. If an EEH occurs while waiting on the read capacity, the EEH handler will wait to obtain the context's mutex in order to put the context in an error state. The EEH handler will sit and wait until the context is free, but this wait can potentially last forever (deadlock) if the scsi_execute() that performs the read capacity experiences a timeout and calls into the reset callback. When that occurs, the reset callback sees that the device is already being reset and waits for the reset to complete. This leaves two threads waiting on the other. To address this issue, make the context unavailable to new, non-system owned threads and release the context while calling into process_sense(). After returning from process_sense() the context mutex is reacquired and the context is made available again. The context can be safely moved to the error state if needed during the unavailable window as no other threads will hold its reference. Signed-off-by: Matthew R. Ochs Signed-off-by: Manoj N. Kumar Reviewed-by: Brian King Reviewed-by: Daniel Axtens Reviewed-by: Tomas Henzl Signed-off-by: James Bottomley --- drivers/scsi/cxlflash/superpipe.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/scsi/cxlflash/superpipe.c b/drivers/scsi/cxlflash/superpipe.c index e99a0eb..d2309af 100644 --- a/drivers/scsi/cxlflash/superpipe.c +++ b/drivers/scsi/cxlflash/superpipe.c @@ -1787,12 +1787,21 @@ static int cxlflash_disk_verify(struct scsi_device *sdev, * inquiry (i.e. the Unit attention is due to the WWN changing). */ if (verify->hint & DK_CXLFLASH_VERIFY_HINT_SENSE) { + /* Can't hold mutex across process_sense/read_cap16, + * since we could have an intervening EEH event. + */ + ctxi->unavail = true; + mutex_unlock(&ctxi->mutex); rc = process_sense(sdev, verify); if (unlikely(rc)) { dev_err(dev, "%s: Failed to validate sense data (%d)\n", __func__, rc); + mutex_lock(&ctxi->mutex); + ctxi->unavail = false; goto out; } + mutex_lock(&ctxi->mutex); + ctxi->unavail = false; } switch (gli->mode) { -- cgit v1.1 From f15fbf8d4eb0c20b7c70096788161d69e23f1a9d Mon Sep 17 00:00:00 2001 From: "Matthew R. Ochs" Date: Wed, 21 Oct 2015 15:15:06 -0500 Subject: cxlflash: Correct spelling, grammar, and alignment mistakes There are several spelling and grammar mistakes throughout the driver. Additionally there are a handful of places where there are extra lines and unnecessary variables/statements. These are a nuisance and pollute the driver. Fix spelling and grammar issues. Update some comments for clarity and consistency. Remove extra lines and a few unneeded variables/statements. Signed-off-by: Matthew R. Ochs Signed-off-by: Manoj N. Kumar Reviewed-by: Brian King Reviewed-by: Andrew Donnellan Reviewed-by: Tomas Henzl Signed-off-by: James Bottomley --- drivers/scsi/cxlflash/common.h | 2 -- drivers/scsi/cxlflash/main.c | 62 +++++++++++++++++---------------------- drivers/scsi/cxlflash/sislite.h | 6 ++-- drivers/scsi/cxlflash/superpipe.c | 2 +- drivers/scsi/cxlflash/vlun.c | 14 ++++----- 5 files changed, 38 insertions(+), 48 deletions(-) diff --git a/drivers/scsi/cxlflash/common.h b/drivers/scsi/cxlflash/common.h index a810585..bbfe711 100644 --- a/drivers/scsi/cxlflash/common.h +++ b/drivers/scsi/cxlflash/common.h @@ -105,8 +105,6 @@ struct cxlflash_cfg { atomic_t scan_host_needed; struct cxl_afu *cxl_afu; - - struct pci_pool *cxlflash_cmd_pool; struct pci_dev *parent_dev; atomic_t recovery_threads; diff --git a/drivers/scsi/cxlflash/main.c b/drivers/scsi/cxlflash/main.c index 14fb9b4..eeb1c47 100644 --- a/drivers/scsi/cxlflash/main.c +++ b/drivers/scsi/cxlflash/main.c @@ -34,7 +34,6 @@ MODULE_AUTHOR("Manoj N. Kumar "); MODULE_AUTHOR("Matthew R. Ochs "); MODULE_LICENSE("GPL"); - /** * cmd_checkout() - checks out an AFU command * @afu: AFU to checkout from. @@ -730,7 +729,7 @@ static void cxlflash_remove(struct pci_dev *pdev) case INIT_STATE_SCSI: cxlflash_term_local_luns(cfg); scsi_remove_host(cfg->host); - /* Fall through */ + /* fall through */ case INIT_STATE_AFU: term_afu(cfg); cancel_work_sync(&cfg->work_q); @@ -763,9 +762,7 @@ static int alloc_mem(struct cxlflash_cfg *cfg) char *buf = NULL; struct device *dev = &cfg->dev->dev; - /* This allocation is about 12K, i.e. only 1 64k page - * and upto 4 4k pages - */ + /* AFU is ~12k, i.e. only one 64k page or up to four 4k pages */ cfg->afu = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, get_order(sizeof(struct afu))); if (unlikely(!cfg->afu)) { @@ -1295,10 +1292,10 @@ static irqreturn_t cxlflash_async_err_irq(int irq, void *data) goto out; } - /* it is OK to clear AFU status before FC_ERROR */ + /* FYI, it is 'okay' to clear AFU status before FC_ERROR */ writeq_be(reg_unmasked, &global->regs.aintr_clear); - /* check each bit that is on */ + /* Check each bit that is on */ for (i = 0; reg_unmasked; i++, reg_unmasked = (reg_unmasked >> 1)) { info = find_ainfo(1ULL << i); if (((reg_unmasked & 0x1) == 0) || !info) @@ -1311,7 +1308,7 @@ static irqreturn_t cxlflash_async_err_irq(int irq, void *data) readq_be(&global->fc_regs[port][FC_STATUS / 8])); /* - * do link reset first, some OTHER errors will set FC_ERROR + * Do link reset first, some OTHER errors will set FC_ERROR * again if cleared before or w/o a reset */ if (info->action & LINK_RESET) { @@ -1326,7 +1323,7 @@ static irqreturn_t cxlflash_async_err_irq(int irq, void *data) reg = readq_be(&global->fc_regs[port][FC_ERROR / 8]); /* - * since all errors are unmasked, FC_ERROR and FC_ERRCAP + * Since all errors are unmasked, FC_ERROR and FC_ERRCAP * should be the same and tracing one is sufficient. */ @@ -1472,23 +1469,22 @@ static void init_pcr(struct cxlflash_cfg *cfg) for (i = 0; i < MAX_CONTEXT; i++) { ctrl_map = &afu->afu_map->ctrls[i].ctrl; - /* disrupt any clients that could be running */ - /* e. g. clients that survived a master restart */ + /* Disrupt any clients that could be running */ + /* e.g. clients that survived a master restart */ writeq_be(0, &ctrl_map->rht_start); writeq_be(0, &ctrl_map->rht_cnt_id); writeq_be(0, &ctrl_map->ctx_cap); } - /* copy frequently used fields into afu */ + /* Copy frequently used fields into afu */ afu->ctx_hndl = (u16) cxl_process_element(cfg->mcctx); - /* ctx_hndl is 16 bits in CAIA */ afu->host_map = &afu->afu_map->hosts[afu->ctx_hndl].host; afu->ctrl_map = &afu->afu_map->ctrls[afu->ctx_hndl].ctrl; /* Program the Endian Control for the master context */ writeq_be(SISL_ENDIAN_CTRL, &afu->host_map->endian_ctrl); - /* initialize cmd fields that never change */ + /* Initialize cmd fields that never change */ for (i = 0; i < CXLFLASH_NUM_CMDS; i++) { afu->cmd[i].rcb.ctx_id = afu->ctx_hndl; afu->cmd[i].rcb.msi = SISL_MSI_RRQ_UPDATED; @@ -1517,7 +1513,7 @@ static int init_global(struct cxlflash_cfg *cfg) pr_debug("%s: wwpn0=0x%llX wwpn1=0x%llX\n", __func__, wwpn[0], wwpn[1]); - /* set up RRQ in AFU for master issued cmds */ + /* Set up RRQ in AFU for master issued cmds */ writeq_be((u64) afu->hrrq_start, &afu->host_map->rrq_start); writeq_be((u64) afu->hrrq_end, &afu->host_map->rrq_end); @@ -1530,9 +1526,9 @@ static int init_global(struct cxlflash_cfg *cfg) /* checker on if dual afu */ writeq_be(reg, &afu->afu_map->global.regs.afu_config); - /* global port select: select either port */ + /* Global port select: select either port */ if (afu->internal_lun) { - /* only use port 0 */ + /* Only use port 0 */ writeq_be(PORT0, &afu->afu_map->global.regs.afu_port_sel); num_ports = NUM_FC_PORTS - 1; } else { @@ -1541,15 +1537,15 @@ static int init_global(struct cxlflash_cfg *cfg) } for (i = 0; i < num_ports; i++) { - /* unmask all errors (but they are still masked at AFU) */ + /* Unmask all errors (but they are still masked at AFU) */ writeq_be(0, &afu->afu_map->global.fc_regs[i][FC_ERRMSK / 8]); - /* clear CRC error cnt & set a threshold */ + /* Clear CRC error cnt & set a threshold */ (void)readq_be(&afu->afu_map->global. fc_regs[i][FC_CNT_CRCERR / 8]); writeq_be(MC_CRC_THRESH, &afu->afu_map->global.fc_regs[i] [FC_CRC_THRESH / 8]); - /* set WWPNs. If already programmed, wwpn[i] is 0 */ + /* Set WWPNs. If already programmed, wwpn[i] is 0 */ if (wwpn[i] != 0 && afu_set_wwpn(afu, i, &afu->afu_map->global.fc_regs[i][0], @@ -1563,18 +1559,17 @@ static int init_global(struct cxlflash_cfg *cfg) * offline/online transitions and a PLOGI */ msleep(100); - } - /* set up master's own CTX_CAP to allow real mode, host translation */ - /* tbls, afu cmds and read/write GSCSI cmds. */ + /* Set up master's own CTX_CAP to allow real mode, host translation */ + /* tables, afu cmds and read/write GSCSI cmds. */ /* First, unlock ctx_cap write by reading mbox */ (void)readq_be(&afu->ctrl_map->mbox_r); /* unlock ctx_cap */ writeq_be((SISL_CTX_CAP_REAL_MODE | SISL_CTX_CAP_HOST_XLATE | SISL_CTX_CAP_READ_CMD | SISL_CTX_CAP_WRITE_CMD | SISL_CTX_CAP_AFU_CMD | SISL_CTX_CAP_GSCSI_CMD), &afu->ctrl_map->ctx_cap); - /* init heartbeat */ + /* Initialize heartbeat */ afu->hb = readq_be(&afu->afu_map->global.regs.afu_hb); out: @@ -1603,7 +1598,7 @@ static int start_afu(struct cxlflash_cfg *cfg) init_pcr(cfg); - /* initialize RRQ pointers */ + /* Initialize RRQ pointers */ afu->hrrq_start = &afu->rrq_entry[0]; afu->hrrq_end = &afu->rrq_entry[NUM_RRQ_ENTRY - 1]; afu->hrrq_curr = afu->hrrq_start; @@ -1726,8 +1721,7 @@ static int init_afu(struct cxlflash_cfg *cfg) goto err1; } - /* Map the entire MMIO space of the AFU. - */ + /* Map the entire MMIO space of the AFU */ afu->afu_map = cxl_psa_map(cfg->mcctx); if (!afu->afu_map) { rc = -ENOMEM; @@ -1779,7 +1773,7 @@ err1: * @mode: Type of sync to issue (lightweight, heavyweight, global). * * The AFU can only take 1 sync command at a time. This routine enforces this - * limitation by using a mutex to provide exlusive access to the AFU during + * limitation by using a mutex to provide exclusive access to the AFU during * the sync. This design point requires calling threads to not be on interrupt * context due to the possibility of sleeping during concurrent sync operations. * @@ -1845,7 +1839,7 @@ retry: wait_resp(afu, cmd); - /* set on timeout */ + /* Set on timeout */ if (unlikely((cmd->sa.ioasc != 0) || (cmd->sa.host_use_b[0] & B_ERROR))) rc = -1; @@ -2262,7 +2256,7 @@ static struct scsi_host_template driver_template = { .cmd_per_lun = 16, .can_queue = CXLFLASH_MAX_CMDS, .this_id = -1, - .sg_tablesize = SG_NONE, /* No scatter gather support. */ + .sg_tablesize = SG_NONE, /* No scatter gather support */ .max_sectors = CXLFLASH_MAX_SECTORS, .use_clustering = ENABLE_CLUSTERING, .shost_attrs = cxlflash_host_attrs, @@ -2322,8 +2316,7 @@ static void cxlflash_worker_thread(struct work_struct *work) /* The reset can block... */ afu_link_reset(afu, port, - &afu->afu_map-> - global.fc_regs[port][0]); + &afu->afu_map->global.fc_regs[port][0]); spin_lock_irqsave(cfg->host->host_lock, lock_flags); } @@ -2402,7 +2395,6 @@ static int cxlflash_probe(struct pci_dev *pdev, cfg->last_lun_index[1] = CXLFLASH_NUM_VLUNS/2 - 1; cfg->dev_id = (struct pci_device_id *)dev_id; - cfg->mcctx = NULL; init_waitqueue_head(&cfg->tmf_waitq); init_waitqueue_head(&cfg->reset_waitq); @@ -2418,7 +2410,8 @@ static int cxlflash_probe(struct pci_dev *pdev, pci_set_drvdata(pdev, cfg); - /* Use the special service provided to look up the physical + /* + * Use the special service provided to look up the physical * PCI device, since we are called on the probe of the virtual * PCI host bus (vphb) */ @@ -2448,7 +2441,6 @@ static int cxlflash_probe(struct pci_dev *pdev, } cfg->init_state = INIT_STATE_AFU; - rc = init_scsi(cfg); if (rc) { dev_err(&pdev->dev, "%s: call to init_scsi " diff --git a/drivers/scsi/cxlflash/sislite.h b/drivers/scsi/cxlflash/sislite.h index 8425d1a..0b3366f 100644 --- a/drivers/scsi/cxlflash/sislite.h +++ b/drivers/scsi/cxlflash/sislite.h @@ -146,7 +146,7 @@ struct sisl_rc { #define SISL_FC_RC_ABORTFAIL 0x59 /* pending abort completed w/fail */ #define SISL_FC_RC_RESID 0x5A /* ioasa underrun/overrun flags set */ #define SISL_FC_RC_RESIDERR 0x5B /* actual data len does not match SCSI - reported len, possbly due to dropped + reported len, possibly due to dropped frames */ #define SISL_FC_RC_TGTABORT 0x5C /* command aborted by target */ }; @@ -258,7 +258,7 @@ struct sisl_host_map { __be64 rrq_start; /* start & end are both inclusive */ __be64 rrq_end; /* write sequence: start followed by end */ __be64 cmd_room; - __be64 ctx_ctrl; /* least signiifcant byte or b56:63 is LISN# */ + __be64 ctx_ctrl; /* least significant byte or b56:63 is LISN# */ __be64 mbox_w; /* restricted use */ }; @@ -290,7 +290,7 @@ struct sisl_global_regs { #define SISL_ASTATUS_FC0_LOGO 0x4000ULL /* b49, target sent FLOGI/PLOGI/LOGO while logged in */ #define SISL_ASTATUS_FC0_CRC_T 0x2000ULL /* b50, CRC threshold exceeded */ -#define SISL_ASTATUS_FC0_LOGI_R 0x1000ULL /* b51, login state mechine timed out +#define SISL_ASTATUS_FC0_LOGI_R 0x1000ULL /* b51, login state machine timed out and retrying */ #define SISL_ASTATUS_FC0_LOGI_F 0x0800ULL /* b52, login failed, FC_ERROR[19:0] */ diff --git a/drivers/scsi/cxlflash/superpipe.c b/drivers/scsi/cxlflash/superpipe.c index d2309af..b5eeeff 100644 --- a/drivers/scsi/cxlflash/superpipe.c +++ b/drivers/scsi/cxlflash/superpipe.c @@ -76,7 +76,7 @@ void cxlflash_free_errpage(void) * * When the host needs to go down, all users must be quiesced and their * memory freed. This is accomplished by putting the contexts in error - * state which will notify the user and let them 'drive' the tear-down. + * state which will notify the user and let them 'drive' the tear down. * Meanwhile, this routine camps until all user contexts have been removed. */ void cxlflash_stop_term_user_contexts(struct cxlflash_cfg *cfg) diff --git a/drivers/scsi/cxlflash/vlun.c b/drivers/scsi/cxlflash/vlun.c index f91b5b3..b0eaf55 100644 --- a/drivers/scsi/cxlflash/vlun.c +++ b/drivers/scsi/cxlflash/vlun.c @@ -132,7 +132,7 @@ static int ba_init(struct ba_lun *ba_lun) return -ENOMEM; } - /* Pass the allocated lun info as a handle to the user */ + /* Pass the allocated LUN info as a handle to the user */ ba_lun->ba_lun_handle = bali; pr_debug("%s: Successfully initialized the LUN: " @@ -165,7 +165,7 @@ static int find_free_range(u32 low, num_bits = (sizeof(*lam) * BITS_PER_BYTE); bit_pos = find_first_bit(lam, num_bits); - pr_devel("%s: Found free bit %llX in lun " + pr_devel("%s: Found free bit %llX in LUN " "map entry %llX at bitmap index = %X\n", __func__, bit_pos, bali->lun_alloc_map[i], i); @@ -682,14 +682,14 @@ out: } /** - * _cxlflash_vlun_resize() - changes the size of a virtual lun + * _cxlflash_vlun_resize() - changes the size of a virtual LUN * @sdev: SCSI device associated with LUN owning virtual LUN. * @ctxi: Context owning resources. * @resize: Resize ioctl data structure. * * On successful return, the user is informed of the new size (in blocks) - * of the virtual lun in last LBA format. When the size of the virtual - * lun is zero, the last LBA is reflected as -1. See comment in the + * of the virtual LUN in last LBA format. When the size of the virtual + * LUN is zero, the last LBA is reflected as -1. See comment in the * prologue for _cxlflash_disk_release() regarding AFU syncs and contexts * on the error recovery list. * @@ -886,8 +886,8 @@ out: * @arg: UVirtual ioctl data structure. * * On successful return, the user is informed of the resource handle - * to be used to identify the virtual lun and the size (in blocks) of - * the virtual lun in last LBA format. When the size of the virtual lun + * to be used to identify the virtual LUN and the size (in blocks) of + * the virtual LUN in last LBA format. When the size of the virtual LUN * is zero, the last LBA is reflected as -1. * * Return: 0 on success, -errno on failure -- cgit v1.1 From af10483e5e1201e1dcf5836207879e6eb5eb9fd5 Mon Sep 17 00:00:00 2001 From: "Matthew R. Ochs" Date: Wed, 21 Oct 2015 15:15:14 -0500 Subject: cxlflash: Fix to prevent stale AFU RRQ Following an adapter reset, the AFU RRQ that resides in host memory holds stale data. This can lead to a condition where the RRQ interrupt handler tries to process stale entries and/or endlessly loops due to an out of sync generation bit. To fix, the AFU RRQ in host memory needs to be cleared after each reset. Signed-off-by: Matthew R. Ochs Signed-off-by: Manoj N. Kumar Reviewed-by: Brian King Reviewed-by: Daniel Axtens Reviewed-by: Tomas Henzl Signed-off-by: James Bottomley --- drivers/scsi/cxlflash/main.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/scsi/cxlflash/main.c b/drivers/scsi/cxlflash/main.c index eeb1c47..c77cb92 100644 --- a/drivers/scsi/cxlflash/main.c +++ b/drivers/scsi/cxlflash/main.c @@ -1598,6 +1598,9 @@ static int start_afu(struct cxlflash_cfg *cfg) init_pcr(cfg); + /* After an AFU reset, RRQ entries are stale, clear them */ + memset(&afu->rrq_entry, 0, sizeof(afu->rrq_entry)); + /* Initialize RRQ pointers */ afu->hrrq_start = &afu->rrq_entry[0]; afu->hrrq_end = &afu->rrq_entry[NUM_RRQ_ENTRY - 1]; -- cgit v1.1 From 11f43ae7735a04994ef3c33295d386ef4e5529b7 Mon Sep 17 00:00:00 2001 From: "Matthew R. Ochs" Date: Wed, 21 Oct 2015 15:15:22 -0500 Subject: MAINTAINERS: Add cxlflash driver Add stanza for cxlflash SCSI driver. Signed-off-by: Matthew R. Ochs Signed-off-by: Manoj N. Kumar Reviewed-by: Brian King Reviewed-by: Andrew Donnellan Signed-off-by: James Bottomley --- MAINTAINERS | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index d382b61..e0c09ce 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3153,6 +3153,15 @@ F: Documentation/powerpc/cxl.txt F: Documentation/powerpc/cxl.txt F: Documentation/ABI/testing/sysfs-class-cxl +CXLFLASH (IBM Coherent Accelerator Processor Interface CAPI Flash) SCSI DRIVER +M: Manoj N. Kumar +M: Matthew R. Ochs +L: linux-scsi@vger.kernel.org +S: Supported +F: drivers/scsi/cxlflash/ +F: include/uapi/scsi/cxlflash_ioctls.h +F: Documentation/powerpc/cxlflash.txt + STMMAC ETHERNET DRIVER M: Giuseppe Cavallaro L: netdev@vger.kernel.org -- cgit v1.1 From b22b4037a013e9ce77cec79d95fdcdc9bece0955 Mon Sep 17 00:00:00 2001 From: Manoj Kumar Date: Wed, 21 Oct 2015 15:15:30 -0500 Subject: cxlflash: Fix to double the delay each time The operator used to double the master context response delay is incorrect and does not result in delay doubling. To fix, use a left shift instead of the XOR operator. Reported-by: Tomas Henzl Signed-off-by: Matthew R. Ochs Signed-off-by: Manoj N. Kumar Reviewed-by: Brian King Reviewed-by: Andrew Donnellan Reviewed-by: Tomas Henzl Signed-off-by: James Bottomley --- drivers/scsi/cxlflash/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/cxlflash/main.c b/drivers/scsi/cxlflash/main.c index c77cb92..51883be 100644 --- a/drivers/scsi/cxlflash/main.c +++ b/drivers/scsi/cxlflash/main.c @@ -303,7 +303,7 @@ write_rrin: if (rrin != 0x1) break; /* Double delay each time */ - udelay(2 ^ nretry); + udelay(2 << nretry); } while (nretry++ < MC_ROOM_RETRY_CNT); } -- cgit v1.1 From 17ead26f23e99ab0bb14e0876adab0ee151711f7 Mon Sep 17 00:00:00 2001 From: "Matthew R. Ochs" Date: Wed, 21 Oct 2015 15:15:37 -0500 Subject: cxlflash: Fix to avoid corrupting adapter fops The fops owned by the adapter can be corrupted in certain scenarios, opening a window where certain fops are temporarily NULLed before being reset to their proper value. This can potentially lead software to make incorrect decisions, leaving the user with the inability to function as intended. An example of this behavior can be observed when there are a number of users with a high rate of turn around (attach to LUN, perform an I/O, detach from LUN, repeat). Every so often a user is given a valid context and adapter file descriptor, but the file associated with the descriptor lacks the correct read permission bit (FMODE_CAN_READ) and thus the read system call bails before calling the valid read fop. Background: The fops is stored in the adapter structure to provide the ability to lookup the adapter structure from within the fop handler. CXL services use the file's private_data and at present, the CXL context does not have a private section. In an effort to limit areas of the cxlflash driver with code specific the superpipe function, a design choice was made to keep the details of the fops situated away from the legacy portions of the driver. This drove the behavior that the adapter fops is set at the beginning of the disk attach ioctl handler when there are no users present. The corruption that this fix remedies is due to the fact that the fops is initially defaulted to values found within a static structure. When the fops is handed down to the CXL services later in the attach path, certain services are patched. The fops structure remains correct until the user count drops to 0 and the fops is reset, triggering the process to repeat again. The user counts are tightly coupled with the creation and deletion of the user context. If multiple users perform a disk attach at the same time, when the user count is currently 0, some users can be in the middle of obtaining a file descriptor and have not yet reached the context creation code that [in addition to creating the context] increments the user count. Subsequent users coming in to perform the attach see that the user count is still 0, and reinitialize the fops, temporarily removing the patched fops. The users that are in the middle obtaining their file descriptor may then receive an invalid descriptor. The fix simply removes the user count altogether and moves the fops initialization to probe time such that it is only performed one time for the life of the adapter. In the future, if the CXL services adopt a private member for their context, that could be used to store the adapter structure reference and cxlflash could revert to a model that does not require an embedded fops. Signed-off-by: Matthew R. Ochs Signed-off-by: Manoj N. Kumar Reviewed-by: Brian King Reviewed-by: Andrew Donnellan Reviewed-by: Daniel Axtens Reviewed-by: Tomas Henzl Signed-off-by: James Bottomley --- drivers/scsi/cxlflash/common.h | 3 +-- drivers/scsi/cxlflash/main.c | 1 + drivers/scsi/cxlflash/superpipe.c | 11 +---------- 3 files changed, 3 insertions(+), 12 deletions(-) diff --git a/drivers/scsi/cxlflash/common.h b/drivers/scsi/cxlflash/common.h index bbfe711..c11cd19 100644 --- a/drivers/scsi/cxlflash/common.h +++ b/drivers/scsi/cxlflash/common.h @@ -21,6 +21,7 @@ #include #include +extern const struct file_operations cxlflash_cxl_fops; #define MAX_CONTEXT CXLFLASH_MAX_CONTEXT /* num contexts per afu */ @@ -115,8 +116,6 @@ struct cxlflash_cfg { struct list_head ctx_err_recovery; /* contexts w/ recovery pending */ struct file_operations cxl_fops; - atomic_t num_user_contexts; - /* Parameters that are LUN table related */ int last_lun_index[CXLFLASH_NUM_FC_PORTS]; int promote_lun_index; diff --git a/drivers/scsi/cxlflash/main.c b/drivers/scsi/cxlflash/main.c index 51883be..3f43879 100644 --- a/drivers/scsi/cxlflash/main.c +++ b/drivers/scsi/cxlflash/main.c @@ -2386,6 +2386,7 @@ static int cxlflash_probe(struct pci_dev *pdev, cfg->init_state = INIT_STATE_NONE; cfg->dev = pdev; + cfg->cxl_fops = cxlflash_cxl_fops; /* * The promoted LUNs move to the top of the LUN table. The rest stay diff --git a/drivers/scsi/cxlflash/superpipe.c b/drivers/scsi/cxlflash/superpipe.c index b5eeeff..34acb58 100644 --- a/drivers/scsi/cxlflash/superpipe.c +++ b/drivers/scsi/cxlflash/superpipe.c @@ -712,7 +712,6 @@ static void destroy_context(struct cxlflash_cfg *cfg, kfree(ctxi->rht_needs_ws); kfree(ctxi->rht_lun); kfree(ctxi); - atomic_dec_if_positive(&cfg->num_user_contexts); } /** @@ -769,7 +768,6 @@ static struct ctx_info *create_context(struct cxlflash_cfg *cfg, INIT_LIST_HEAD(&ctxi->luns); INIT_LIST_HEAD(&ctxi->list); /* initialize for list_empty() */ - atomic_inc(&cfg->num_user_contexts); mutex_lock(&ctxi->mutex); out: return ctxi; @@ -1164,10 +1162,7 @@ out: return rc; } -/* - * Local fops for adapter file descriptor - */ -static const struct file_operations cxlflash_cxl_fops = { +const struct file_operations cxlflash_cxl_fops = { .owner = THIS_MODULE, .mmap = cxlflash_cxl_mmap, .release = cxlflash_cxl_release, @@ -1286,10 +1281,6 @@ static int cxlflash_disk_attach(struct scsi_device *sdev, int fd = -1; - /* On first attach set fileops */ - if (atomic_read(&cfg->num_user_contexts) == 0) - cfg->cxl_fops = cxlflash_cxl_fops; - if (attach->num_interrupts > 4) { dev_dbg(dev, "%s: Cannot support this many interrupts %llu\n", __func__, attach->num_interrupts); -- cgit v1.1 From fa3f2c6eb1eb69a9023d648c5bafbf4f062ab84d Mon Sep 17 00:00:00 2001 From: "Matthew R. Ochs" Date: Wed, 21 Oct 2015 15:15:45 -0500 Subject: cxlflash: Correct trace string The trace following the failure of alloc_mem() incorrectly identifies which function failed. This can lead to misdiagnosing a failure. Fix the string to correctly indicate that alloc_mem() failed. Reported-by: Brian King Signed-off-by: Matthew R. Ochs Signed-off-by: Manoj N. Kumar Reviewed-by: Brian King Reviewed-by: Andrew Donnellan Reviewed-by: Tomas Henzl Signed-off-by: James Bottomley --- drivers/scsi/cxlflash/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/cxlflash/main.c b/drivers/scsi/cxlflash/main.c index 3f43879..998373e 100644 --- a/drivers/scsi/cxlflash/main.c +++ b/drivers/scsi/cxlflash/main.c @@ -2377,7 +2377,7 @@ static int cxlflash_probe(struct pci_dev *pdev, cfg->host = host; rc = alloc_mem(cfg); if (rc) { - dev_err(&pdev->dev, "%s: call to scsi_host_alloc failed!\n", + dev_err(&pdev->dev, "%s: call to alloc_mem failed!\n", __func__); rc = -ENOMEM; scsi_host_put(cfg->host); -- cgit v1.1 From aacb4ff69eea4ac47a7389f90ea7a896abbe92f5 Mon Sep 17 00:00:00 2001 From: "Matthew R. Ochs" Date: Wed, 21 Oct 2015 15:15:52 -0500 Subject: cxlflash: Fix to avoid potential deadlock on EEH Ioctl threads that use scsi_execute() can run for an excessive amount of time due to the fact that they have lengthy timeouts and retry logic built in. Under normal operation this is not an issue. However, once EEH enters the picture, a long execution time coupled with the possibility that a timeout can trigger entry to the driver via registered reset callbacks becomes a liability. In particular, a deadlock can occur when an EEH event is encountered while in running in scsi_execute(). As part of the recovery, the EEH handler drains all currently running ioctls, waiting until they have completed before proceeding with a reset. As the scsi_execute()'s are situated on the ioctl path, the EEH handler will wait until they (and the remainder of the ioctl handler they're associated with) have completed. Normally this would not be much of an issue aside from the longer recovery period. Unfortunately, the scsi_execute() triggers a reset when it times out. The reset handler will see that the device is already being reset and wait until that reset completed. This creates a condition where the EEH handler becomes stuck, infinitely waiting for the ioctl thread to complete. To avoid this behavior, temporarily unmark the scsi_execute() threads as an ioctl thread by releasing the ioctl read semaphore. This allows the EEH handler to proceed with a recovery while the thread is still running. Once the scsi_execute() returns, the ioctl read semaphore is reacquired and the adapter state is rechecked in case it changed while inside of scsi_execute(). The state check will wait if the adapter is still being recovered or returns a failure if the recovery failed. In the event that the adapter reset failed, the failure is simply returned as the ioctl would be unable to continue. Reported-by: Brian King Signed-off-by: Matthew R. Ochs Signed-off-by: Manoj N. Kumar Reviewed-by: Brian King Reviewed-by: Daniel Axtens Reviewed-by: Tomas Henzl Signed-off-by: James Bottomley --- drivers/scsi/cxlflash/superpipe.c | 30 +++++++++++++++++++++++++++++- drivers/scsi/cxlflash/superpipe.h | 2 ++ drivers/scsi/cxlflash/vlun.c | 29 +++++++++++++++++++++++++++++ 3 files changed, 60 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/cxlflash/superpipe.c b/drivers/scsi/cxlflash/superpipe.c index 34acb58..18a5e11 100644 --- a/drivers/scsi/cxlflash/superpipe.c +++ b/drivers/scsi/cxlflash/superpipe.c @@ -283,6 +283,24 @@ out: * @sdev: SCSI device associated with LUN. * @lli: LUN destined for capacity request. * + * The READ_CAP16 can take quite a while to complete. Should an EEH occur while + * in scsi_execute(), the EEH handler will attempt to recover. As part of the + * recovery, the handler drains all currently running ioctls, waiting until they + * have completed before proceeding with a reset. As this routine is used on the + * ioctl path, this can create a condition where the EEH handler becomes stuck, + * infinitely waiting for this ioctl thread. To avoid this behavior, temporarily + * unmark this thread as an ioctl thread by releasing the ioctl read semaphore. + * This will allow the EEH handler to proceed with a recovery while this thread + * is still running. Once the scsi_execute() returns, reacquire the ioctl read + * semaphore and check the adapter state in case it changed while inside of + * scsi_execute(). The state check will wait if the adapter is still being + * recovered or return a failure if the recovery failed. In the event that the + * adapter reset failed, simply return the failure as the ioctl would be unable + * to continue. + * + * Note that the above puts a requirement on this routine to only be called on + * an ioctl thread. + * * Return: 0 on success, -errno on failure */ static int read_cap16(struct scsi_device *sdev, struct llun_info *lli) @@ -314,8 +332,18 @@ retry: dev_dbg(dev, "%s: %ssending cmd(0x%x)\n", __func__, retry_cnt ? "re" : "", scsi_cmd[0]); + /* Drop the ioctl read semahpore across lengthy call */ + up_read(&cfg->ioctl_rwsem); result = scsi_execute(sdev, scsi_cmd, DMA_FROM_DEVICE, cmd_buf, CMD_BUFSIZE, sense_buf, to, CMD_RETRIES, 0, NULL); + down_read(&cfg->ioctl_rwsem); + rc = check_state(cfg); + if (rc) { + dev_err(dev, "%s: Failed state! result=0x08%X\n", + __func__, result); + rc = -ENODEV; + goto out; + } if (driver_byte(result) == DRIVER_SENSE) { result &= ~(0xFF<<24); /* DRIVER_SENSE is not an error */ @@ -1221,7 +1249,7 @@ static const struct file_operations null_fops = { * * Return: 0 on success, -errno on failure */ -static int check_state(struct cxlflash_cfg *cfg) +int check_state(struct cxlflash_cfg *cfg) { struct device *dev = &cfg->dev->dev; int rc = 0; diff --git a/drivers/scsi/cxlflash/superpipe.h b/drivers/scsi/cxlflash/superpipe.h index 7df88ee..06a805a 100644 --- a/drivers/scsi/cxlflash/superpipe.h +++ b/drivers/scsi/cxlflash/superpipe.h @@ -147,4 +147,6 @@ void cxlflash_ba_terminate(struct ba_lun *); int cxlflash_manage_lun(struct scsi_device *, struct dk_cxlflash_manage_lun *); +int check_state(struct cxlflash_cfg *); + #endif /* ifndef _CXLFLASH_SUPERPIPE_H */ diff --git a/drivers/scsi/cxlflash/vlun.c b/drivers/scsi/cxlflash/vlun.c index b0eaf55..a53f583 100644 --- a/drivers/scsi/cxlflash/vlun.c +++ b/drivers/scsi/cxlflash/vlun.c @@ -400,6 +400,24 @@ static int init_vlun(struct llun_info *lli) * @lba: Logical block address to start write same. * @nblks: Number of logical blocks to write same. * + * The SCSI WRITE_SAME16 can take quite a while to complete. Should an EEH occur + * while in scsi_execute(), the EEH handler will attempt to recover. As part of + * the recovery, the handler drains all currently running ioctls, waiting until + * they have completed before proceeding with a reset. As this routine is used + * on the ioctl path, this can create a condition where the EEH handler becomes + * stuck, infinitely waiting for this ioctl thread. To avoid this behavior, + * temporarily unmark this thread as an ioctl thread by releasing the ioctl read + * semaphore. This will allow the EEH handler to proceed with a recovery while + * this thread is still running. Once the scsi_execute() returns, reacquire the + * ioctl read semaphore and check the adapter state in case it changed while + * inside of scsi_execute(). The state check will wait if the adapter is still + * being recovered or return a failure if the recovery failed. In the event that + * the adapter reset failed, simply return the failure as the ioctl would be + * unable to continue. + * + * Note that the above puts a requirement on this routine to only be called on + * an ioctl thread. + * * Return: 0 on success, -errno on failure */ static int write_same16(struct scsi_device *sdev, @@ -433,9 +451,20 @@ static int write_same16(struct scsi_device *sdev, put_unaligned_be32(ws_limit < left ? ws_limit : left, &scsi_cmd[10]); + /* Drop the ioctl read semahpore across lengthy call */ + up_read(&cfg->ioctl_rwsem); result = scsi_execute(sdev, scsi_cmd, DMA_TO_DEVICE, cmd_buf, CMD_BUFSIZE, sense_buf, to, CMD_RETRIES, 0, NULL); + down_read(&cfg->ioctl_rwsem); + rc = check_state(cfg); + if (rc) { + dev_err(dev, "%s: Failed state! result=0x08%X\n", + __func__, result); + rc = -ENODEV; + goto out; + } + if (result) { dev_err_ratelimited(dev, "%s: command failed for " "offset %lld result=0x%x\n", -- cgit v1.1 From ee3491ba8f1f7e7cc1302d727ee7055e5c748524 Mon Sep 17 00:00:00 2001 From: "Matthew R. Ochs" Date: Wed, 21 Oct 2015 15:16:00 -0500 Subject: cxlflash: Fix to avoid leaving dangling interrupt resources When running with an unsupported AFU, the cxlflash driver fails the probe. When the driver is removed, the following Oops is encountered on a show_interrupts() thread: Call Trace: [c000001fba5a7a10] [0000000000000003] 0x3 (unreliable) [c000001fba5a7a60] [c00000000053dcf4] vsnprintf+0x204/0x4c0 [c000001fba5a7ae0] [c00000000030045c] seq_vprintf+0x5c/0xd0 [c000001fba5a7b20] [c00000000030051c] seq_printf+0x4c/0x60 [c000001fba5a7b50] [c00000000013e140] show_interrupts+0x370/0x4f0 [c000001fba5a7c10] [c0000000002ff898] seq_read+0xe8/0x530 [c000001fba5a7ca0] [c00000000035d5c0] proc_reg_read+0xb0/0x110 [c000001fba5a7cf0] [c0000000002ca74c] __vfs_read+0x6c/0x180 [c000001fba5a7d90] [c0000000002cb464] vfs_read+0xa4/0x1c0 [c000001fba5a7de0] [c0000000002cc51c] SyS_read+0x6c/0x110 [c000001fba5a7e30] [c000000000009204] system_call+0x38/0xb4 The Oops is due to not cleaning up correctly on the unsupported AFU error path, leaving various allocated and registered resources. In this case, interrupts are in a semi-allocated/registered state, which the show_interrupts() thread attempts to use. To fix, the cleanup logic in init_afu() is consolidated to error gates at the bottom of the function and the appropriate goto is added to each error path. As a mini side fix while refactoring in this routine, the else statement following the AFU version evaluation is eliminated as it is not needed. Signed-off-by: Matthew R. Ochs Acked-by: Manoj Kumar Reviewed-by: Andrew Donnellan Reviewed-by: Tomas Henzl Signed-off-by: James Bottomley --- drivers/scsi/cxlflash/main.c | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/drivers/scsi/cxlflash/main.c b/drivers/scsi/cxlflash/main.c index 998373e..c152703 100644 --- a/drivers/scsi/cxlflash/main.c +++ b/drivers/scsi/cxlflash/main.c @@ -1721,15 +1721,14 @@ static int init_afu(struct cxlflash_cfg *cfg) if (rc) { dev_err(dev, "%s: call to init_mc failed, rc=%d!\n", __func__, rc); - goto err1; + goto out; } /* Map the entire MMIO space of the AFU */ afu->afu_map = cxl_psa_map(cfg->mcctx); if (!afu->afu_map) { - rc = -ENOMEM; - term_mc(cfg, UNDO_START); dev_err(dev, "%s: call to cxl_psa_map failed!\n", __func__); + rc = -ENOMEM; goto err1; } @@ -1743,19 +1742,17 @@ static int init_afu(struct cxlflash_cfg *cfg) "interface version 0x%llx\n", afu->version, afu->interface_version); rc = -EINVAL; - goto err1; - } else - pr_debug("%s: afu version %s, interface version 0x%llX\n", - __func__, afu->version, afu->interface_version); + goto err2; + } + + pr_debug("%s: afu version %s, interface version 0x%llX\n", __func__, + afu->version, afu->interface_version); rc = start_afu(cfg); if (rc) { dev_err(dev, "%s: call to start_afu failed, rc=%d!\n", __func__, rc); - term_mc(cfg, UNDO_START); - cxl_psa_unmap((void __iomem *)afu->afu_map); - afu->afu_map = NULL; - goto err1; + goto err2; } afu_err_intr_init(cfg->afu); @@ -1763,9 +1760,16 @@ static int init_afu(struct cxlflash_cfg *cfg) /* Restore the LUN mappings */ cxlflash_restore_luntable(cfg); -err1: +out: pr_debug("%s: returning rc=%d\n", __func__, rc); return rc; + +err2: + cxl_psa_unmap((void __iomem *)afu->afu_map); + afu->afu_map = NULL; +err1: + term_mc(cfg, UNDO_START); + goto out; } /** -- cgit v1.1 From e6e6df3f71a0b567e55d17b08f5bad8f1043afa3 Mon Sep 17 00:00:00 2001 From: Manoj Kumar Date: Wed, 21 Oct 2015 15:16:07 -0500 Subject: cxlflash: Fix to escalate to LINK_RESET on login timeout A 'login timed out' asynchronous error interrupt is generated if no response is seen to a FLOGI within 2 seconds. If the time out error is not escalated to a LINK_RESET the port will not be available for use. This fix provides the required escalation. Signed-off-by: Manoj N. Kumar Acked-by: Matthew R. Ochs Reviewed-by: Brian King Reviewed-by: Tomas Henzl Signed-off-by: James Bottomley --- drivers/scsi/cxlflash/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/cxlflash/main.c b/drivers/scsi/cxlflash/main.c index c152703..afaf533 100644 --- a/drivers/scsi/cxlflash/main.c +++ b/drivers/scsi/cxlflash/main.c @@ -1100,7 +1100,7 @@ static const struct asyc_intr_info ainfo[] = { {SISL_ASTATUS_FC0_OTHER, "other error", 0, CLR_FC_ERROR | LINK_RESET}, {SISL_ASTATUS_FC0_LOGO, "target initiated LOGO", 0, 0}, {SISL_ASTATUS_FC0_CRC_T, "CRC threshold exceeded", 0, LINK_RESET}, - {SISL_ASTATUS_FC0_LOGI_R, "login timed out, retrying", 0, 0}, + {SISL_ASTATUS_FC0_LOGI_R, "login timed out, retrying", 0, LINK_RESET}, {SISL_ASTATUS_FC0_LOGI_F, "login failed", 0, CLR_FC_ERROR}, {SISL_ASTATUS_FC0_LOGI_S, "login succeeded", 0, SCAN_HOST}, {SISL_ASTATUS_FC0_LINK_DN, "link down", 0, 0}, -- cgit v1.1 From 1a47401bb397183e0500db2c7d5f8d2a3506598e Mon Sep 17 00:00:00 2001 From: "Matthew R. Ochs" Date: Wed, 21 Oct 2015 15:16:15 -0500 Subject: cxlflash: Fix to avoid corrupting port selection mask The port selection mask of a LUN can be corrupted when the manage LUN ioctl (DK_CXLFLASH_MANAGE_LUN) is issued more than once for any device. This mask indicates to the AFU which port[s] can be used for a data transfer to/from a particular LUN. The mask is critical to ensuring the correct behavior when using the virtual LUN function of this adapter. When the mask is configured for both ports, an I/O may be sent to either port as the AFU assumes that each port has access to the same physical device (specified by LUN ID in the port LUN table). In a situation where the mask becomes incorrectly configured to reflect access to both ports when in fact there is only access through a single port, an I/O can be targeted to the wrong physical device. This can lead to data corruption among other ill effects (e.g. security leaks). The cause for this corruption is the assumption that the ioctl will only be called a second time for a LUN when it is being configured for access via a second port. A boolean 'newly_created' variable is used to differentiate between a LUN that was created (and subsequently configured for single port access) and one that is destined for access across both ports. While initially set to 'true', this sticky boolean is toggled to the 'false' state during a lookup on any next ioctl performed on a device with a matching WWN/WWID. The code fails to realize that the match could in fact be the same device calling in again. From here, an assumption is made that any LUN with 'newly_created' set to 'false' is configured for access over both ports and the port selection mask is set to reflect this. Any future attempts to use this LUN for hosting a virtual LUN will result in the port LUN table being incorrectly programmed. As a remedy, the 'newly_created' concept was removed entirely and replaced with code that always constructs the port selection mask based upon the SCSI channel of the LUN being accessed. The bits remain sticky, therefore allowing for a device to be accessed over both ports when that is in fact the correct physical configuration. Also included in this commit are a few minor related changes to enhance the fix and provide better debug information for port selection mask and port LUN table bugs in the future. These include renaming refresh_local() to lookup_local(), tracing the WWN/WWID as a big-endian entity, and tracing the port selection mask, SCSI channel, and LUN ID each time the port LUN table is programmed. Signed-off-by: Matthew R. Ochs Acked-by: Manoj Kumar Reviewed-by: Andrew Donnellan Signed-off-by: James Bottomley --- drivers/scsi/cxlflash/lunmgt.c | 36 ++++++++++++++++++------------------ drivers/scsi/cxlflash/superpipe.h | 1 - 2 files changed, 18 insertions(+), 19 deletions(-) diff --git a/drivers/scsi/cxlflash/lunmgt.c b/drivers/scsi/cxlflash/lunmgt.c index 8c372fc..a0923ca 100644 --- a/drivers/scsi/cxlflash/lunmgt.c +++ b/drivers/scsi/cxlflash/lunmgt.c @@ -41,7 +41,6 @@ static struct llun_info *create_local(struct scsi_device *sdev, u8 *wwid) } lli->sdev = sdev; - lli->newly_created = true; lli->host_no = sdev->host->host_no; lli->in_table = false; @@ -74,24 +73,19 @@ out: } /** - * refresh_local() - find and update local LUN information structure by WWID + * lookup_local() - find a local LUN information structure by WWID * @cfg: Internal structure associated with the host. * @wwid: WWID associated with LUN. * - * When the LUN is found, mark it by updating it's newly_created field. - * * Return: Found local lun_info structure on success, NULL on failure - * If a LUN with the WWID is found in the list, refresh it's state. */ -static struct llun_info *refresh_local(struct cxlflash_cfg *cfg, u8 *wwid) +static struct llun_info *lookup_local(struct cxlflash_cfg *cfg, u8 *wwid) { struct llun_info *lli, *temp; list_for_each_entry_safe(lli, temp, &cfg->lluns, list) - if (!memcmp(lli->wwid, wwid, DK_CXLFLASH_MANAGE_LUN_WWID_LEN)) { - lli->newly_created = false; + if (!memcmp(lli->wwid, wwid, DK_CXLFLASH_MANAGE_LUN_WWID_LEN)) return lli; - } return NULL; } @@ -143,7 +137,7 @@ static struct llun_info *find_and_create_lun(struct scsi_device *sdev, u8 *wwid) if (unlikely(!wwid)) goto out; - lli = refresh_local(cfg, wwid); + lli = lookup_local(cfg, wwid); if (lli) goto out; @@ -239,8 +233,8 @@ int cxlflash_manage_lun(struct scsi_device *sdev, mutex_lock(&global.mutex); lli = find_and_create_lun(sdev, manage->wwid); pr_debug("%s: ENTER: WWID = %016llX%016llX, flags = %016llX li = %p\n", - __func__, get_unaligned_le64(&manage->wwid[0]), - get_unaligned_le64(&manage->wwid[8]), + __func__, get_unaligned_be64(&manage->wwid[0]), + get_unaligned_be64(&manage->wwid[8]), manage->hdr.flags, lli); if (unlikely(!lli)) { rc = -ENOMEM; @@ -248,20 +242,26 @@ int cxlflash_manage_lun(struct scsi_device *sdev, } if (flags & DK_CXLFLASH_MANAGE_LUN_ENABLE_SUPERPIPE) { - if (lli->newly_created) - lli->port_sel = CHAN2PORT(chan); - else - lli->port_sel = BOTH_PORTS; - /* Store off lun in unpacked, AFU-friendly format */ + /* + * Update port selection mask based upon channel, store off LUN + * in unpacked, AFU-friendly format, and hang LUN reference in + * the sdev. + */ + lli->port_sel |= CHAN2PORT(chan); lli->lun_id[chan] = lun_to_lunid(sdev->lun); sdev->hostdata = lli; } else if (flags & DK_CXLFLASH_MANAGE_LUN_DISABLE_SUPERPIPE) { if (lli->parent->mode != MODE_NONE) rc = -EBUSY; - else + else { sdev->hostdata = NULL; + lli->port_sel &= ~CHAN2PORT(chan); + } } + pr_debug("%s: port_sel = %08X chan = %u lun_id = %016llX\n", __func__, + lli->port_sel, chan, lli->lun_id[chan]); + out: mutex_unlock(&global.mutex); pr_debug("%s: returning rc=%d\n", __func__, rc); diff --git a/drivers/scsi/cxlflash/superpipe.h b/drivers/scsi/cxlflash/superpipe.h index 06a805a..bede574 100644 --- a/drivers/scsi/cxlflash/superpipe.h +++ b/drivers/scsi/cxlflash/superpipe.h @@ -63,7 +63,6 @@ struct llun_info { u32 lun_index; /* Index in the LUN table */ u32 host_no; /* host_no from Scsi_host */ u32 port_sel; /* What port to use for this LUN */ - bool newly_created; /* Whether the LUN was just discovered */ bool in_table; /* Whether a LUN table entry was created */ u8 wwid[16]; /* Keep a duplicate copy here? */ -- cgit v1.1 From 0d73122c3229a332286f3a256ba098d124aba066 Mon Sep 17 00:00:00 2001 From: "Matthew R. Ochs" Date: Wed, 21 Oct 2015 15:16:24 -0500 Subject: cxlflash: Fix to avoid lock instrumentation rejection When running with lock instrumentation (e.g. lockdep), some of the instrumentation can become disabled at probe time for a cxlflash adapter. This is due to a missing lock registration for the tmf_slock. The fix is to call spin_lock_init() for the tmf_slock during probe. Signed-off-by: Matthew R. Ochs Acked-by: Manoj Kumar Reviewed-by: Andrew Donnellan Signed-off-by: James Bottomley --- drivers/scsi/cxlflash/main.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/scsi/cxlflash/main.c b/drivers/scsi/cxlflash/main.c index afaf533..1e5bf0c 100644 --- a/drivers/scsi/cxlflash/main.c +++ b/drivers/scsi/cxlflash/main.c @@ -2410,6 +2410,7 @@ static int cxlflash_probe(struct pci_dev *pdev, INIT_WORK(&cfg->work_q, cxlflash_worker_thread); cfg->lr_state = LINK_RESET_INVALID; cfg->lr_port = -1; + spin_lock_init(&cfg->tmf_slock); mutex_init(&cfg->ctx_tbl_list_mutex); mutex_init(&cfg->ctx_recovery_mutex); init_rwsem(&cfg->ioctl_rwsem); -- cgit v1.1 From a82544c7baccf2d8a12cee46110cc7d356d3edf0 Mon Sep 17 00:00:00 2001 From: "Matthew R. Ochs" Date: Wed, 21 Oct 2015 15:16:32 -0500 Subject: cxlflash: Fix to avoid bypassing context cleanup Contexts may be skipped over for cleanup in situations where contention for the adapter's table-list mutex is experienced in the presence of a signal during the execution of the release handler. This can lead to two known issues: - A hang condition on remove as that path tries to wait for users to cleanup - something that will never complete should this scenario play out as the user has already cleaned up from their perspective. - An Oops in the unmap_mapping_range() call that is made as part of the user waiting mechanism that is invoked on remove when contexts are found to still exist. The root cause of this issue can be found in get_context() and how the table-list mutex is acquired. As this code path is shared by several different access points within the driver, a decision was made during the development cycle to acquire this mutex in this location using the interruptible version of the mutex locking service. In almost all of the use-cases and environmental scenarios this holds up, even when the mutex is contended. However, for critical system threads (such as the release handler), failing to acquire the mutex and bailing with the intention of the user being able to try again later is unacceptable. In such a scenario, the context _must_ be derived as it is on an irreversible path to being freed. Without being able to derive the context, the code mistakenly assumes that it has already been freed and proceeds to free up the underlying CXL context resources. From this point on, any usage of [the now stale] CXL context resources will result in undefined behavior. This is root cause of the Oops mentioned as the second known issue as the mapping passed to the unmap_mapping_range() service is owned by the CXL context. To fix this problem, acquisition of the table-list mutex within get_context() is simply changed to use the uninterruptible version of the mutex locking service. This is safe as the timing windows for holding this mutex are short and also protected against blocking. Signed-off-by: Matthew R. Ochs Acked-by: Manoj Kumar Reviewed-by: Andrew Donnellan Signed-off-by: James Bottomley --- drivers/scsi/cxlflash/superpipe.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/scsi/cxlflash/superpipe.c b/drivers/scsi/cxlflash/superpipe.c index 18a5e11..cac2e6a 100644 --- a/drivers/scsi/cxlflash/superpipe.c +++ b/drivers/scsi/cxlflash/superpipe.c @@ -162,10 +162,7 @@ struct ctx_info *get_context(struct cxlflash_cfg *cfg, u64 rctxid, if (likely(ctxid < MAX_CONTEXT)) { while (true) { - rc = mutex_lock_interruptible(&cfg->ctx_tbl_list_mutex); - if (rc) - goto out; - + mutex_lock(&cfg->ctx_tbl_list_mutex); ctxi = cfg->ctx_tbl[ctxid]; if (ctxi) if ((file && (ctxi->file != file)) || -- cgit v1.1