diff options
Diffstat (limited to 'drivers/scsi/lpfc')
| -rw-r--r-- | drivers/scsi/lpfc/lpfc.h | 15 | ||||
| -rw-r--r-- | drivers/scsi/lpfc/lpfc_attr.c | 161 | ||||
| -rw-r--r-- | drivers/scsi/lpfc/lpfc_bsg.c | 89 | ||||
| -rw-r--r-- | drivers/scsi/lpfc/lpfc_crtn.h | 12 | ||||
| -rw-r--r-- | drivers/scsi/lpfc/lpfc_debugfs.c | 1357 | ||||
| -rw-r--r-- | drivers/scsi/lpfc/lpfc_debugfs.h | 125 | ||||
| -rw-r--r-- | drivers/scsi/lpfc/lpfc_els.c | 105 | ||||
| -rw-r--r-- | drivers/scsi/lpfc/lpfc_hbadisc.c | 222 | ||||
| -rw-r--r-- | drivers/scsi/lpfc/lpfc_hw.h | 15 | ||||
| -rw-r--r-- | drivers/scsi/lpfc/lpfc_hw4.h | 30 | ||||
| -rw-r--r-- | drivers/scsi/lpfc/lpfc_init.c | 90 | ||||
| -rw-r--r-- | drivers/scsi/lpfc/lpfc_mbox.c | 2 | ||||
| -rw-r--r-- | drivers/scsi/lpfc/lpfc_scsi.c | 97 | ||||
| -rw-r--r-- | drivers/scsi/lpfc/lpfc_sli.c | 399 | ||||
| -rw-r--r-- | drivers/scsi/lpfc/lpfc_sli4.h | 29 | ||||
| -rw-r--r-- | drivers/scsi/lpfc/lpfc_version.h | 2 | 
16 files changed, 2410 insertions, 340 deletions
| diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index 8ec2c86a49d4..c088a36d1f33 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h @@ -20,6 +20,11 @@   *******************************************************************/  #include <scsi/scsi_host.h> + +#if defined(CONFIG_DEBUG_FS) && !defined(CONFIG_SCSI_LPFC_DEBUG_FS) +#define CONFIG_SCSI_LPFC_DEBUG_FS +#endif +  struct lpfc_sli2_slim;  #define LPFC_PCI_DEV_LP		0x1 @@ -465,9 +470,10 @@ enum intr_type_t {  struct unsol_rcv_ct_ctx {  	uint32_t ctxt_id;  	uint32_t SID; -	uint32_t oxid;  	uint32_t flags;  #define UNSOL_VALID	0x00000001 +	uint16_t oxid; +	uint16_t rxid;  };  #define LPFC_USER_LINK_SPEED_AUTO	0	/* auto select (default)*/ @@ -674,6 +680,9 @@ struct lpfc_hba {  	uint32_t cfg_enable_rrq;  	uint32_t cfg_topology;  	uint32_t cfg_link_speed; +#define LPFC_FCF_FOV 1		/* Fast fcf failover */ +#define LPFC_FCF_PRIORITY 2	/* Priority fcf failover */ +	uint32_t cfg_fcf_failover_policy;  	uint32_t cfg_cr_delay;  	uint32_t cfg_cr_count;  	uint32_t cfg_multi_ring_support; @@ -845,9 +854,13 @@ struct lpfc_hba {  	/* iDiag debugfs sub-directory */  	struct dentry *idiag_root;  	struct dentry *idiag_pci_cfg; +	struct dentry *idiag_bar_acc;  	struct dentry *idiag_que_info;  	struct dentry *idiag_que_acc;  	struct dentry *idiag_drb_acc; +	struct dentry *idiag_ctl_acc; +	struct dentry *idiag_mbx_acc; +	struct dentry *idiag_ext_acc;  #endif  	/* Used for deferred freeing of ELS data buffers */ diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index 135a53baa735..2542f1f8bf86 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -755,6 +755,47 @@ lpfc_issue_reset(struct device *dev, struct device_attribute *attr,  }  /** + * lpfc_sli4_pdev_status_reg_wait - Wait for pdev status register for readyness + * @phba: lpfc_hba pointer. + * + * Description: + * SLI4 interface type-2 device to wait on the sliport status register for + * the readyness after performing a firmware reset. + * + * Returns: + * zero for success + **/ +static int +lpfc_sli4_pdev_status_reg_wait(struct lpfc_hba *phba) +{ +	struct lpfc_register portstat_reg; +	int i; + + +	lpfc_readl(phba->sli4_hba.u.if_type2.STATUSregaddr, +		   &portstat_reg.word0); + +	/* wait for the SLI port firmware ready after firmware reset */ +	for (i = 0; i < LPFC_FW_RESET_MAXIMUM_WAIT_10MS_CNT; i++) { +		msleep(10); +		lpfc_readl(phba->sli4_hba.u.if_type2.STATUSregaddr, +			   &portstat_reg.word0); +		if (!bf_get(lpfc_sliport_status_err, &portstat_reg)) +			continue; +		if (!bf_get(lpfc_sliport_status_rn, &portstat_reg)) +			continue; +		if (!bf_get(lpfc_sliport_status_rdy, &portstat_reg)) +			continue; +		break; +	} + +	if (i < LPFC_FW_RESET_MAXIMUM_WAIT_10MS_CNT) +		return 0; +	else +		return -EIO; +} + +/**   * lpfc_sli4_pdev_reg_request - Request physical dev to perform a register acc   * @phba: lpfc_hba pointer.   * @@ -769,6 +810,7 @@ static ssize_t  lpfc_sli4_pdev_reg_request(struct lpfc_hba *phba, uint32_t opcode)  {  	struct completion online_compl; +	struct pci_dev *pdev = phba->pcidev;  	uint32_t reg_val;  	int status = 0;  	int rc; @@ -781,6 +823,14 @@ lpfc_sli4_pdev_reg_request(struct lpfc_hba *phba, uint32_t opcode)  	     LPFC_SLI_INTF_IF_TYPE_2))  		return -EPERM; +	if (!pdev->is_physfn) +		return -EPERM; + +	/* Disable SR-IOV virtual functions if enabled */ +	if (phba->cfg_sriov_nr_virtfn) { +		pci_disable_sriov(pdev); +		phba->cfg_sriov_nr_virtfn = 0; +	}  	status = lpfc_do_offline(phba, LPFC_EVT_OFFLINE);  	if (status != 0) @@ -805,7 +855,10 @@ lpfc_sli4_pdev_reg_request(struct lpfc_hba *phba, uint32_t opcode)  	readl(phba->sli4_hba.conf_regs_memmap_p + LPFC_CTL_PDEV_CTL_OFFSET);  	/* delay driver action following IF_TYPE_2 reset */ -	msleep(100); +	rc = lpfc_sli4_pdev_status_reg_wait(phba); + +	if (rc) +		return -EIO;  	init_completion(&online_compl);  	rc = lpfc_workq_post_event(phba, &status, &online_compl, @@ -895,6 +948,10 @@ lpfc_board_mode_store(struct device *dev, struct device_attribute *attr,  	if (!phba->cfg_enable_hba_reset)  		return -EACCES; + +	lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, +		"3050 lpfc_board_mode set to %s\n", buf); +  	init_completion(&online_compl);  	if(strncmp(buf, "online", sizeof("online") - 1) == 0) { @@ -1290,6 +1347,10 @@ lpfc_poll_store(struct device *dev, struct device_attribute *attr,  	if (phba->sli_rev == LPFC_SLI_REV4)  		val = 0; +	lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, +		"3051 lpfc_poll changed from %d to %d\n", +		phba->cfg_poll, val); +  	spin_lock_irq(&phba->hbalock);  	old_val = phba->cfg_poll; @@ -1414,80 +1475,10 @@ lpfc_sriov_hw_max_virtfn_show(struct device *dev,  	struct Scsi_Host *shost = class_to_shost(dev);  	struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;  	struct lpfc_hba *phba = vport->phba; -	struct pci_dev *pdev = phba->pcidev; -	union  lpfc_sli4_cfg_shdr *shdr; -	uint32_t shdr_status, shdr_add_status; -	LPFC_MBOXQ_t *mboxq; -	struct lpfc_mbx_get_prof_cfg *get_prof_cfg; -	struct lpfc_rsrc_desc_pcie *desc; -	uint32_t max_nr_virtfn; -	uint32_t desc_count; -	int length, rc, i; - -	if ((phba->sli_rev < LPFC_SLI_REV4) || -	    (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) != -	     LPFC_SLI_INTF_IF_TYPE_2)) -		return -EPERM; - -	if (!pdev->is_physfn) -		return snprintf(buf, PAGE_SIZE, "%d\n", 0); - -	mboxq = (LPFC_MBOXQ_t *)mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); -	if (!mboxq) -		return -ENOMEM; - -	/* get the maximum number of virtfn support by physfn */ -	length = (sizeof(struct lpfc_mbx_get_prof_cfg) - -		  sizeof(struct lpfc_sli4_cfg_mhdr)); -	lpfc_sli4_config(phba, mboxq, LPFC_MBOX_SUBSYSTEM_COMMON, -			 LPFC_MBOX_OPCODE_GET_PROFILE_CONFIG, -			 length, LPFC_SLI4_MBX_EMBED); -	shdr = (union lpfc_sli4_cfg_shdr *) -		&mboxq->u.mqe.un.sli4_config.header.cfg_shdr; -	bf_set(lpfc_mbox_hdr_pf_num, &shdr->request, -	       phba->sli4_hba.iov.pf_number + 1); - -	get_prof_cfg = &mboxq->u.mqe.un.get_prof_cfg; -	bf_set(lpfc_mbx_get_prof_cfg_prof_tp, &get_prof_cfg->u.request, -	       LPFC_CFG_TYPE_CURRENT_ACTIVE); - -	rc = lpfc_sli_issue_mbox_wait(phba, mboxq, -				lpfc_mbox_tmo_val(phba, MBX_SLI4_CONFIG)); - -	if (rc != MBX_TIMEOUT) { -		/* check return status */ -		shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); -		shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, -					 &shdr->response); -		if (shdr_status || shdr_add_status || rc) -			goto error_out; - -	} else -		goto error_out; - -	desc_count = get_prof_cfg->u.response.prof_cfg.rsrc_desc_count; - -	for (i = 0; i < LPFC_RSRC_DESC_MAX_NUM; i++) { -		desc = (struct lpfc_rsrc_desc_pcie *) -			&get_prof_cfg->u.response.prof_cfg.desc[i]; -		if (LPFC_RSRC_DESC_TYPE_PCIE == -		    bf_get(lpfc_rsrc_desc_pcie_type, desc)) { -			max_nr_virtfn = bf_get(lpfc_rsrc_desc_pcie_nr_virtfn, -					       desc); -			break; -		} -	} - -	if (i < LPFC_RSRC_DESC_MAX_NUM) { -		if (rc != MBX_TIMEOUT) -			mempool_free(mboxq, phba->mbox_mem_pool); -		return snprintf(buf, PAGE_SIZE, "%d\n", max_nr_virtfn); -	} +	uint16_t max_nr_virtfn; -error_out: -	if (rc != MBX_TIMEOUT) -		mempool_free(mboxq, phba->mbox_mem_pool); -	return -EIO; +	max_nr_virtfn = lpfc_sli_sriov_nr_virtfn_get(phba); +	return snprintf(buf, PAGE_SIZE, "%d\n", max_nr_virtfn);  }  /** @@ -1605,6 +1596,9 @@ static int \  lpfc_##attr##_set(struct lpfc_hba *phba, uint val) \  { \  	if (val >= minval && val <= maxval) {\ +		lpfc_printf_log(phba, KERN_ERR, LOG_INIT, \ +			"3052 lpfc_" #attr " changed from %d to %d\n", \ +			phba->cfg_##attr, val); \  		phba->cfg_##attr = val;\  		return 0;\  	}\ @@ -1762,6 +1756,9 @@ static int \  lpfc_##attr##_set(struct lpfc_vport *vport, uint val) \  { \  	if (val >= minval && val <= maxval) {\ +		lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, \ +			"3053 lpfc_" #attr " changed from %d to %d\n", \ +			vport->cfg_##attr, val); \  		vport->cfg_##attr = val;\  		return 0;\  	}\ @@ -2196,6 +2193,9 @@ lpfc_param_show(enable_npiv);  lpfc_param_init(enable_npiv, 1, 0, 1);  static DEVICE_ATTR(lpfc_enable_npiv, S_IRUGO, lpfc_enable_npiv_show, NULL); +LPFC_ATTR_R(fcf_failover_policy, 1, 1, 2, +	"FCF Fast failover=1 Priority failover=2"); +  int lpfc_enable_rrq;  module_param(lpfc_enable_rrq, int, S_IRUGO);  MODULE_PARM_DESC(lpfc_enable_rrq, "Enable RRQ functionality"); @@ -2678,6 +2678,9 @@ lpfc_topology_store(struct device *dev, struct device_attribute *attr,  		if (nolip)  			return strlen(buf); +		lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, +			"3054 lpfc_topology changed from %d to %d\n", +			prev_val, val);  		err = lpfc_issue_lip(lpfc_shost_from_vport(phba->pport));  		if (err) {  			phba->cfg_topology = prev_val; @@ -3101,6 +3104,10 @@ lpfc_link_speed_store(struct device *dev, struct device_attribute *attr,  	if (sscanf(val_buf, "%i", &val) != 1)  		return -EINVAL; +	lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, +		"3055 lpfc_link_speed changed from %d to %d %s\n", +		phba->cfg_link_speed, val, nolip ? "(nolip)" : "(lip)"); +  	if (((val == LPFC_USER_LINK_SPEED_1G) && !(phba->lmt & LMT_1Gb)) ||  	    ((val == LPFC_USER_LINK_SPEED_2G) && !(phba->lmt & LMT_2Gb)) ||  	    ((val == LPFC_USER_LINK_SPEED_4G) && !(phba->lmt & LMT_4Gb)) || @@ -3678,7 +3685,9 @@ LPFC_ATTR_R(enable_bg, 0, 0, 1, "Enable BlockGuard Support");  #	- Default will result in registering capabilities for all profiles.  #  */ -unsigned int lpfc_prot_mask = SHOST_DIF_TYPE1_PROTECTION; +unsigned int lpfc_prot_mask = SHOST_DIF_TYPE1_PROTECTION | +			      SHOST_DIX_TYPE0_PROTECTION | +			      SHOST_DIX_TYPE1_PROTECTION;  module_param(lpfc_prot_mask, uint, S_IRUGO);  MODULE_PARM_DESC(lpfc_prot_mask, "host protection mask"); @@ -3769,6 +3778,7 @@ struct device_attribute *lpfc_hba_attrs[] = {  	&dev_attr_lpfc_fdmi_on,  	&dev_attr_lpfc_max_luns,  	&dev_attr_lpfc_enable_npiv, +	&dev_attr_lpfc_fcf_failover_policy,  	&dev_attr_lpfc_enable_rrq,  	&dev_attr_nport_evt_cnt,  	&dev_attr_board_mode, @@ -4989,6 +4999,7 @@ lpfc_get_cfgparam(struct lpfc_hba *phba)  	lpfc_link_speed_init(phba, lpfc_link_speed);  	lpfc_poll_tmo_init(phba, lpfc_poll_tmo);  	lpfc_enable_npiv_init(phba, lpfc_enable_npiv); +	lpfc_fcf_failover_policy_init(phba, lpfc_fcf_failover_policy);  	lpfc_enable_rrq_init(phba, lpfc_enable_rrq);  	lpfc_use_msi_init(phba, lpfc_use_msi);  	lpfc_fcp_imax_init(phba, lpfc_fcp_imax); diff --git a/drivers/scsi/lpfc/lpfc_bsg.c b/drivers/scsi/lpfc/lpfc_bsg.c index 7fb0ba4cbfa7..6760c69f5253 100644 --- a/drivers/scsi/lpfc/lpfc_bsg.c +++ b/drivers/scsi/lpfc/lpfc_bsg.c @@ -42,6 +42,7 @@  #include "lpfc.h"  #include "lpfc_logmsg.h"  #include "lpfc_crtn.h" +#include "lpfc_debugfs.h"  #include "lpfc_vport.h"  #include "lpfc_version.h" @@ -960,8 +961,10 @@ lpfc_bsg_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,  						    evt_dat->immed_dat].oxid,  						phba->ct_ctx[  						    evt_dat->immed_dat].SID); +			phba->ct_ctx[evt_dat->immed_dat].rxid = +				piocbq->iocb.ulpContext;  			phba->ct_ctx[evt_dat->immed_dat].oxid = -						piocbq->iocb.ulpContext; +				piocbq->iocb.unsli3.rcvsli3.ox_id;  			phba->ct_ctx[evt_dat->immed_dat].SID =  				piocbq->iocb.un.rcvels.remoteID;  			phba->ct_ctx[evt_dat->immed_dat].flags = UNSOL_VALID; @@ -1312,7 +1315,8 @@ lpfc_issue_ct_rsp(struct lpfc_hba *phba, struct fc_bsg_job *job, uint32_t tag,  			rc = IOCB_ERROR;  			goto issue_ct_rsp_exit;  		} -		icmd->ulpContext = phba->ct_ctx[tag].oxid; +		icmd->ulpContext = phba->ct_ctx[tag].rxid; +		icmd->unsli3.rcvsli3.ox_id = phba->ct_ctx[tag].oxid;  		ndlp = lpfc_findnode_did(phba->pport, phba->ct_ctx[tag].SID);  		if (!ndlp) {  			lpfc_printf_log(phba, KERN_WARNING, LOG_ELS, @@ -1337,9 +1341,7 @@ lpfc_issue_ct_rsp(struct lpfc_hba *phba, struct fc_bsg_job *job, uint32_t tag,  			goto issue_ct_rsp_exit;  		} -		icmd->un.ulpWord[3] = ndlp->nlp_rpi; -		if (phba->sli_rev == LPFC_SLI_REV4) -			icmd->ulpContext = +		icmd->un.ulpWord[3] =  				phba->sli4_hba.rpi_ids[ndlp->nlp_rpi];  		/* The exchange is done, mark the entry as invalid */ @@ -1351,8 +1353,8 @@ lpfc_issue_ct_rsp(struct lpfc_hba *phba, struct fc_bsg_job *job, uint32_t tag,  	/* Xmit CT response on exchange <xid> */  	lpfc_printf_log(phba, KERN_INFO, LOG_ELS, -			"2722 Xmit CT response on exchange x%x Data: x%x x%x\n", -			icmd->ulpContext, icmd->ulpIoTag, phba->link_state); +		"2722 Xmit CT response on exchange x%x Data: x%x x%x x%x\n", +		icmd->ulpContext, icmd->ulpIoTag, tag, phba->link_state);  	ctiocb->iocb_cmpl = NULL;  	ctiocb->iocb_flag |= LPFC_IO_LIBDFC; @@ -1471,13 +1473,12 @@ send_mgmt_rsp_exit:  /**   * lpfc_bsg_diag_mode_enter - process preparing into device diag loopback mode   * @phba: Pointer to HBA context object. - * @job: LPFC_BSG_VENDOR_DIAG_MODE   *   * This function is responsible for preparing driver for diag loopback   * on device.   */  static int -lpfc_bsg_diag_mode_enter(struct lpfc_hba *phba, struct fc_bsg_job *job) +lpfc_bsg_diag_mode_enter(struct lpfc_hba *phba)  {  	struct lpfc_vport **vports;  	struct Scsi_Host *shost; @@ -1521,7 +1522,6 @@ lpfc_bsg_diag_mode_enter(struct lpfc_hba *phba, struct fc_bsg_job *job)  /**   * lpfc_bsg_diag_mode_exit - exit process from device diag loopback mode   * @phba: Pointer to HBA context object. - * @job: LPFC_BSG_VENDOR_DIAG_MODE   *   * This function is responsible for driver exit processing of setting up   * diag loopback mode on device. @@ -1567,7 +1567,7 @@ lpfc_sli3_bsg_diag_loopback_mode(struct lpfc_hba *phba, struct fc_bsg_job *job)  	uint32_t link_flags;  	uint32_t timeout;  	LPFC_MBOXQ_t *pmboxq; -	int mbxstatus; +	int mbxstatus = MBX_SUCCESS;  	int i = 0;  	int rc = 0; @@ -1586,7 +1586,7 @@ lpfc_sli3_bsg_diag_loopback_mode(struct lpfc_hba *phba, struct fc_bsg_job *job)  		goto job_error;  	} -	rc = lpfc_bsg_diag_mode_enter(phba, job); +	rc = lpfc_bsg_diag_mode_enter(phba);  	if (rc)  		goto job_error; @@ -1741,7 +1741,7 @@ lpfc_sli4_bsg_diag_loopback_mode(struct lpfc_hba *phba, struct fc_bsg_job *job)  	uint32_t link_flags, timeout, req_len, alloc_len;  	struct lpfc_mbx_set_link_diag_loopback *link_diag_loopback;  	LPFC_MBOXQ_t *pmboxq = NULL; -	int mbxstatus, i, rc = 0; +	int mbxstatus = MBX_SUCCESS, i, rc = 0;  	/* no data to return just the return code */  	job->reply->reply_payload_rcv_len = 0; @@ -1758,7 +1758,7 @@ lpfc_sli4_bsg_diag_loopback_mode(struct lpfc_hba *phba, struct fc_bsg_job *job)  		goto job_error;  	} -	rc = lpfc_bsg_diag_mode_enter(phba, job); +	rc = lpfc_bsg_diag_mode_enter(phba);  	if (rc)  		goto job_error; @@ -1982,7 +1982,7 @@ lpfc_sli4_bsg_link_diag_test(struct fc_bsg_job *job)  		goto job_error;  	} -	rc = lpfc_bsg_diag_mode_enter(phba, job); +	rc = lpfc_bsg_diag_mode_enter(phba);  	if (rc)  		goto job_error; @@ -3178,6 +3178,11 @@ lpfc_bsg_issue_mbox_ext_handle_job(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq)  				"(x%x/x%x) complete bsg job done, bsize:%d\n",  				phba->mbox_ext_buf_ctx.nembType,  				phba->mbox_ext_buf_ctx.mboxType, size); +		lpfc_idiag_mbxacc_dump_bsg_mbox(phba, +					phba->mbox_ext_buf_ctx.nembType, +					phba->mbox_ext_buf_ctx.mboxType, +					dma_ebuf, sta_pos_addr, +					phba->mbox_ext_buf_ctx.mbx_dmabuf, 0);  	} else  		spin_unlock_irqrestore(&phba->ct_ev_lock, flags); @@ -3430,6 +3435,10 @@ lpfc_bsg_sli_cfg_read_cmd_ext(struct lpfc_hba *phba, struct fc_bsg_job *job,  				"ext_buf_cnt:%d\n", ext_buf_cnt);  	} +	/* before dma descriptor setup */ +	lpfc_idiag_mbxacc_dump_bsg_mbox(phba, nemb_tp, mbox_rd, dma_mbox, +					sta_pre_addr, dmabuf, ext_buf_cnt); +  	/* reject non-embedded mailbox command with none external buffer */  	if (ext_buf_cnt == 0) {  		rc = -EPERM; @@ -3477,6 +3486,10 @@ lpfc_bsg_sli_cfg_read_cmd_ext(struct lpfc_hba *phba, struct fc_bsg_job *job,  		}  	} +	/* after dma descriptor setup */ +	lpfc_idiag_mbxacc_dump_bsg_mbox(phba, nemb_tp, mbox_rd, dma_mbox, +					sta_pos_addr, dmabuf, ext_buf_cnt); +  	/* construct base driver mbox command */  	pmb = &pmboxq->u.mb;  	pmbx = (uint8_t *)dmabuf->virt; @@ -3511,7 +3524,7 @@ lpfc_bsg_sli_cfg_read_cmd_ext(struct lpfc_hba *phba, struct fc_bsg_job *job,  		lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,  				"2947 Issued SLI_CONFIG ext-buffer "  				"maibox command, rc:x%x\n", rc); -		return 1; +		return SLI_CONFIG_HANDLED;  	}  	lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC,  			"2948 Failed to issue SLI_CONFIG ext-buffer " @@ -3549,7 +3562,7 @@ lpfc_bsg_sli_cfg_write_cmd_ext(struct lpfc_hba *phba, struct fc_bsg_job *job,  	LPFC_MBOXQ_t *pmboxq = NULL;  	MAILBOX_t *pmb;  	uint8_t *mbx; -	int rc = 0, i; +	int rc = SLI_CONFIG_NOT_HANDLED, i;  	mbox_req =  	   (struct dfc_mbox_req *)job->request->rqst_data.h_vendor.vendor_cmd; @@ -3591,12 +3604,20 @@ lpfc_bsg_sli_cfg_write_cmd_ext(struct lpfc_hba *phba, struct fc_bsg_job *job,  				"ext_buf_cnt:%d\n", ext_buf_cnt);  	} +	/* before dma buffer descriptor setup */ +	lpfc_idiag_mbxacc_dump_bsg_mbox(phba, nemb_tp, mbox_wr, dma_mbox, +					sta_pre_addr, dmabuf, ext_buf_cnt); +  	if (ext_buf_cnt == 0)  		return -EPERM;  	/* for the first external buffer */  	lpfc_bsg_sli_cfg_dma_desc_setup(phba, nemb_tp, 0, dmabuf, dmabuf); +	/* after dma descriptor setup */ +	lpfc_idiag_mbxacc_dump_bsg_mbox(phba, nemb_tp, mbox_wr, dma_mbox, +					sta_pos_addr, dmabuf, ext_buf_cnt); +  	/* log for looking forward */  	for (i = 1; i < ext_buf_cnt; i++) {  		if (nemb_tp == nemb_mse) @@ -3660,7 +3681,7 @@ lpfc_bsg_sli_cfg_write_cmd_ext(struct lpfc_hba *phba, struct fc_bsg_job *job,  			lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,  					"2955 Issued SLI_CONFIG ext-buffer "  					"maibox command, rc:x%x\n", rc); -			return 1; +			return SLI_CONFIG_HANDLED;  		}  		lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC,  				"2956 Failed to issue SLI_CONFIG ext-buffer " @@ -3668,6 +3689,11 @@ lpfc_bsg_sli_cfg_write_cmd_ext(struct lpfc_hba *phba, struct fc_bsg_job *job,  		rc = -EPIPE;  	} +	/* wait for additoinal external buffers */ +	job->reply->result = 0; +	job->job_done(job); +	return SLI_CONFIG_HANDLED; +  job_error:  	if (pmboxq)  		mempool_free(pmboxq, phba->mbox_mem_pool); @@ -3840,6 +3866,12 @@ lpfc_bsg_read_ebuf_get(struct lpfc_hba *phba, struct fc_bsg_job *job)  	dmabuf = list_first_entry(&phba->mbox_ext_buf_ctx.ext_dmabuf_list,  				  struct lpfc_dmabuf, list);  	list_del_init(&dmabuf->list); + +	/* after dma buffer descriptor setup */ +	lpfc_idiag_mbxacc_dump_bsg_mbox(phba, phba->mbox_ext_buf_ctx.nembType, +					mbox_rd, dma_ebuf, sta_pos_addr, +					dmabuf, index); +  	pbuf = (uint8_t *)dmabuf->virt;  	job->reply->reply_payload_rcv_len =  		sg_copy_from_buffer(job->reply_payload.sg_list, @@ -3922,6 +3954,11 @@ lpfc_bsg_write_ebuf_set(struct lpfc_hba *phba, struct fc_bsg_job *job,  					dmabuf);  	list_add_tail(&dmabuf->list, &phba->mbox_ext_buf_ctx.ext_dmabuf_list); +	/* after write dma buffer */ +	lpfc_idiag_mbxacc_dump_bsg_mbox(phba, phba->mbox_ext_buf_ctx.nembType, +					mbox_wr, dma_ebuf, sta_pos_addr, +					dmabuf, index); +  	if (phba->mbox_ext_buf_ctx.seqNum == phba->mbox_ext_buf_ctx.numBuf) {  		lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,  				"2968 SLI_CONFIG ext-buffer wr all %d " @@ -3959,7 +3996,7 @@ lpfc_bsg_write_ebuf_set(struct lpfc_hba *phba, struct fc_bsg_job *job,  			lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,  					"2969 Issued SLI_CONFIG ext-buffer "  					"maibox command, rc:x%x\n", rc); -			return 1; +			return SLI_CONFIG_HANDLED;  		}  		lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC,  				"2970 Failed to issue SLI_CONFIG ext-buffer " @@ -4039,14 +4076,14 @@ lpfc_bsg_handle_sli_cfg_ext(struct lpfc_hba *phba, struct fc_bsg_job *job,  			    struct lpfc_dmabuf *dmabuf)  {  	struct dfc_mbox_req *mbox_req; -	int rc; +	int rc = SLI_CONFIG_NOT_HANDLED;  	mbox_req =  	   (struct dfc_mbox_req *)job->request->rqst_data.h_vendor.vendor_cmd;  	/* mbox command with/without single external buffer */  	if (mbox_req->extMboxTag == 0 && mbox_req->extSeqNum == 0) -		return SLI_CONFIG_NOT_HANDLED; +		return rc;  	/* mbox command and first external buffer */  	if (phba->mbox_ext_buf_ctx.state == LPFC_BSG_MBOX_IDLE) { @@ -4249,7 +4286,7 @@ lpfc_bsg_issue_mbox(struct lpfc_hba *phba, struct fc_bsg_job *job,  		 * mailbox extension size  		 */  		if ((transmit_length > receive_length) || -			(transmit_length > MAILBOX_EXT_SIZE)) { +			(transmit_length > BSG_MBOX_SIZE - sizeof(MAILBOX_t))) {  			rc = -ERANGE;  			goto job_done;  		} @@ -4272,7 +4309,7 @@ lpfc_bsg_issue_mbox(struct lpfc_hba *phba, struct fc_bsg_job *job,  		/* receive length cannot be greater than mailbox  		 * extension size  		 */ -		if (receive_length > MAILBOX_EXT_SIZE) { +		if (receive_length > BSG_MBOX_SIZE - sizeof(MAILBOX_t)) {  			rc = -ERANGE;  			goto job_done;  		} @@ -4306,7 +4343,8 @@ lpfc_bsg_issue_mbox(struct lpfc_hba *phba, struct fc_bsg_job *job,  			bde = (struct ulp_bde64 *)&pmb->un.varWords[4];  			/* bde size cannot be greater than mailbox ext size */ -			if (bde->tus.f.bdeSize > MAILBOX_EXT_SIZE) { +			if (bde->tus.f.bdeSize > +			    BSG_MBOX_SIZE - sizeof(MAILBOX_t)) {  				rc = -ERANGE;  				goto job_done;  			} @@ -4332,7 +4370,8 @@ lpfc_bsg_issue_mbox(struct lpfc_hba *phba, struct fc_bsg_job *job,  				 * mailbox extension size  				 */  				if ((receive_length == 0) || -				    (receive_length > MAILBOX_EXT_SIZE)) { +				    (receive_length > +				     BSG_MBOX_SIZE - sizeof(MAILBOX_t))) {  					rc = -ERANGE;  					goto job_done;  				} diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h index fc20c247f36b..a6db6aef1331 100644 --- a/drivers/scsi/lpfc/lpfc_crtn.h +++ b/drivers/scsi/lpfc/lpfc_crtn.h @@ -235,9 +235,11 @@ int lpfc_sli4_redisc_fcf_table(struct lpfc_hba *);  void lpfc_fcf_redisc_wait_start_timer(struct lpfc_hba *);  void lpfc_sli4_fcf_dead_failthrough(struct lpfc_hba *);  uint16_t lpfc_sli4_fcf_rr_next_index_get(struct lpfc_hba *); +void lpfc_sli4_set_fcf_flogi_fail(struct lpfc_hba *, uint16_t);  int lpfc_sli4_fcf_rr_index_set(struct lpfc_hba *, uint16_t);  void lpfc_sli4_fcf_rr_index_clear(struct lpfc_hba *, uint16_t);  int lpfc_sli4_fcf_rr_next_proc(struct lpfc_vport *, uint16_t); +void lpfc_sli4_clear_fcf_rr_bmask(struct lpfc_hba *);  int lpfc_mem_alloc(struct lpfc_hba *, int align);  void lpfc_mem_free(struct lpfc_hba *); @@ -371,6 +373,10 @@ extern struct lpfc_hbq_init *lpfc_hbq_defs[];  /* SLI4 if_type 2 externs. */  int lpfc_sli4_alloc_resource_identifiers(struct lpfc_hba *);  int lpfc_sli4_dealloc_resource_identifiers(struct lpfc_hba *); +int lpfc_sli4_get_allocated_extnts(struct lpfc_hba *, uint16_t, +				   uint16_t *, uint16_t *); +int lpfc_sli4_get_avail_extnt_rsrc(struct lpfc_hba *, uint16_t, +					  uint16_t *, uint16_t *);  /* externs BlockGuard */  extern char *_dump_buf_data; @@ -432,10 +438,16 @@ void lpfc_handle_rrq_active(struct lpfc_hba *);  int lpfc_send_rrq(struct lpfc_hba *, struct lpfc_node_rrq *);  int lpfc_set_rrq_active(struct lpfc_hba *, struct lpfc_nodelist *,  	uint16_t, uint16_t, uint16_t); +uint16_t lpfc_sli4_xri_inrange(struct lpfc_hba *, uint16_t);  void lpfc_cleanup_wt_rrqs(struct lpfc_hba *);  void lpfc_cleanup_vports_rrqs(struct lpfc_vport *, struct lpfc_nodelist *);  struct lpfc_node_rrq *lpfc_get_active_rrq(struct lpfc_vport *, uint16_t,  	uint32_t); +void lpfc_idiag_mbxacc_dump_bsg_mbox(struct lpfc_hba *, enum nemb_type, +	enum mbox_type, enum dma_type, enum sta_type, +	struct lpfc_dmabuf *, uint32_t); +void lpfc_idiag_mbxacc_dump_issue_mbox(struct lpfc_hba *, MAILBOX_t *);  int lpfc_wr_object(struct lpfc_hba *, struct list_head *, uint32_t, uint32_t *);  /* functions to support SR-IOV */  int lpfc_sli_probe_sriov_nr_virtfn(struct lpfc_hba *, int); +uint16_t lpfc_sli_sriov_nr_virtfn_get(struct lpfc_hba *); diff --git a/drivers/scsi/lpfc/lpfc_debugfs.c b/drivers/scsi/lpfc/lpfc_debugfs.c index ffe82d169b40..a0424dd90e40 100644 --- a/drivers/scsi/lpfc/lpfc_debugfs.c +++ b/drivers/scsi/lpfc/lpfc_debugfs.c @@ -48,6 +48,7 @@  #include "lpfc_version.h"  #include "lpfc_compat.h"  #include "lpfc_debugfs.h" +#include "lpfc_bsg.h"  #ifdef CONFIG_SCSI_LPFC_DEBUG_FS  /* @@ -135,7 +136,11 @@ lpfc_debugfs_disc_trc_data(struct lpfc_vport *vport, char *buf, int size)  	int i, index, len, enable;  	uint32_t ms;  	struct lpfc_debugfs_trc *dtp; -	char buffer[LPFC_DEBUG_TRC_ENTRY_SIZE]; +	char *buffer; + +	buffer = kmalloc(LPFC_DEBUG_TRC_ENTRY_SIZE, GFP_KERNEL); +	if (!buffer) +		return 0;  	enable = lpfc_debugfs_enable;  	lpfc_debugfs_enable = 0; @@ -167,6 +172,8 @@ lpfc_debugfs_disc_trc_data(struct lpfc_vport *vport, char *buf, int size)  	}  	lpfc_debugfs_enable = enable; +	kfree(buffer); +  	return len;  } @@ -195,8 +202,11 @@ lpfc_debugfs_slow_ring_trc_data(struct lpfc_hba *phba, char *buf, int size)  	int i, index, len, enable;  	uint32_t ms;  	struct lpfc_debugfs_trc *dtp; -	char buffer[LPFC_DEBUG_TRC_ENTRY_SIZE]; +	char *buffer; +	buffer = kmalloc(LPFC_DEBUG_TRC_ENTRY_SIZE, GFP_KERNEL); +	if (!buffer) +		return 0;  	enable = lpfc_debugfs_enable;  	lpfc_debugfs_enable = 0; @@ -228,6 +238,8 @@ lpfc_debugfs_slow_ring_trc_data(struct lpfc_hba *phba, char *buf, int size)  	}  	lpfc_debugfs_enable = enable; +	kfree(buffer); +  	return len;  } @@ -378,7 +390,11 @@ lpfc_debugfs_dumpHBASlim_data(struct lpfc_hba *phba, char *buf, int size)  	int len = 0;  	int i, off;  	uint32_t *ptr; -	char buffer[1024]; +	char *buffer; + +	buffer = kmalloc(1024, GFP_KERNEL); +	if (!buffer) +		return 0;  	off = 0;  	spin_lock_irq(&phba->hbalock); @@ -407,6 +423,8 @@ lpfc_debugfs_dumpHBASlim_data(struct lpfc_hba *phba, char *buf, int size)  	}  	spin_unlock_irq(&phba->hbalock); +	kfree(buffer); +  	return len;  } @@ -1147,7 +1165,8 @@ static int lpfc_idiag_cmd_get(const char __user *buf, size_t nbytes,  {  	char mybuf[64];  	char *pbuf, *step_str; -	int bsize, i; +	int i; +	size_t bsize;  	/* Protect copy from user */  	if (!access_ok(VERIFY_READ, buf, nbytes)) @@ -1326,8 +1345,8 @@ lpfc_idiag_pcicfg_read(struct file *file, char __user *buf, size_t nbytes,  		return 0;  	if (idiag.cmd.opcode == LPFC_IDIAG_CMD_PCICFG_RD) { -		where = idiag.cmd.data[0]; -		count = idiag.cmd.data[1]; +		where = idiag.cmd.data[IDIAG_PCICFG_WHERE_INDX]; +		count = idiag.cmd.data[IDIAG_PCICFG_COUNT_INDX];  	} else  		return 0; @@ -1372,6 +1391,11 @@ pcicfg_browse:  		len += snprintf(pbuffer+len, LPFC_PCI_CFG_SIZE-len,  				"%08x ", u32val);  		offset += sizeof(uint32_t); +		if (offset >= LPFC_PCI_CFG_SIZE) { +			len += snprintf(pbuffer+len, +					LPFC_PCI_CFG_SIZE-len, "\n"); +			break; +		}  		index -= sizeof(uint32_t);  		if (!index)  			len += snprintf(pbuffer+len, LPFC_PCI_CFG_SIZE-len, @@ -1384,8 +1408,11 @@ pcicfg_browse:  	}  	/* Set up the offset for next portion of pci cfg read */ -	idiag.offset.last_rd += LPFC_PCI_CFG_RD_SIZE; -	if (idiag.offset.last_rd >= LPFC_PCI_CFG_SIZE) +	if (index == 0) { +		idiag.offset.last_rd += LPFC_PCI_CFG_RD_SIZE; +		if (idiag.offset.last_rd >= LPFC_PCI_CFG_SIZE) +			idiag.offset.last_rd = 0; +	} else  		idiag.offset.last_rd = 0;  	return simple_read_from_buffer(buf, nbytes, ppos, pbuffer, len); @@ -1438,8 +1465,8 @@ lpfc_idiag_pcicfg_write(struct file *file, const char __user *buf,  		if (rc != LPFC_PCI_CFG_RD_CMD_ARG)  			goto error_out;  		/* Read command from PCI config space, set up command fields */ -		where = idiag.cmd.data[0]; -		count = idiag.cmd.data[1]; +		where = idiag.cmd.data[IDIAG_PCICFG_WHERE_INDX]; +		count = idiag.cmd.data[IDIAG_PCICFG_COUNT_INDX];  		if (count == LPFC_PCI_CFG_BROWSE) {  			if (where % sizeof(uint32_t))  				goto error_out; @@ -1474,9 +1501,9 @@ lpfc_idiag_pcicfg_write(struct file *file, const char __user *buf,  		if (rc != LPFC_PCI_CFG_WR_CMD_ARG)  			goto error_out;  		/* Write command to PCI config space, read-modify-write */ -		where = idiag.cmd.data[0]; -		count = idiag.cmd.data[1]; -		value = idiag.cmd.data[2]; +		where = idiag.cmd.data[IDIAG_PCICFG_WHERE_INDX]; +		count = idiag.cmd.data[IDIAG_PCICFG_COUNT_INDX]; +		value = idiag.cmd.data[IDIAG_PCICFG_VALUE_INDX];  		/* Sanity checks */  		if ((count != sizeof(uint8_t)) &&  		    (count != sizeof(uint16_t)) && @@ -1569,6 +1596,292 @@ error_out:  }  /** + * lpfc_idiag_baracc_read - idiag debugfs pci bar access read + * @file: The file pointer to read from. + * @buf: The buffer to copy the data to. + * @nbytes: The number of bytes to read. + * @ppos: The position in the file to start reading from. + * + * Description: + * This routine reads data from the @phba pci bar memory mapped space + * according to the idiag command, and copies to user @buf. + * + * Returns: + * This function returns the amount of data that was read (this could be less + * than @nbytes if the end of the file was reached) or a negative error value. + **/ +static ssize_t +lpfc_idiag_baracc_read(struct file *file, char __user *buf, size_t nbytes, +		       loff_t *ppos) +{ +	struct lpfc_debug *debug = file->private_data; +	struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private; +	int offset_label, offset, offset_run, len = 0, index; +	int bar_num, acc_range, bar_size; +	char *pbuffer; +	void __iomem *mem_mapped_bar; +	uint32_t if_type; +	struct pci_dev *pdev; +	uint32_t u32val; + +	pdev = phba->pcidev; +	if (!pdev) +		return 0; + +	/* This is a user read operation */ +	debug->op = LPFC_IDIAG_OP_RD; + +	if (!debug->buffer) +		debug->buffer = kmalloc(LPFC_PCI_BAR_RD_BUF_SIZE, GFP_KERNEL); +	if (!debug->buffer) +		return 0; +	pbuffer = debug->buffer; + +	if (*ppos) +		return 0; + +	if (idiag.cmd.opcode == LPFC_IDIAG_CMD_BARACC_RD) { +		bar_num   = idiag.cmd.data[IDIAG_BARACC_BAR_NUM_INDX]; +		offset    = idiag.cmd.data[IDIAG_BARACC_OFF_SET_INDX]; +		acc_range = idiag.cmd.data[IDIAG_BARACC_ACC_MOD_INDX]; +		bar_size = idiag.cmd.data[IDIAG_BARACC_BAR_SZE_INDX]; +	} else +		return 0; + +	if (acc_range == 0) +		return 0; + +	if_type = bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf); +	if (if_type == LPFC_SLI_INTF_IF_TYPE_0) { +		if (bar_num == IDIAG_BARACC_BAR_0) +			mem_mapped_bar = phba->sli4_hba.conf_regs_memmap_p; +		else if (bar_num == IDIAG_BARACC_BAR_1) +			mem_mapped_bar = phba->sli4_hba.ctrl_regs_memmap_p; +		else if (bar_num == IDIAG_BARACC_BAR_2) +			mem_mapped_bar = phba->sli4_hba.drbl_regs_memmap_p; +		else +			return 0; +	} else if (if_type == LPFC_SLI_INTF_IF_TYPE_2) { +		if (bar_num == IDIAG_BARACC_BAR_0) +			mem_mapped_bar = phba->sli4_hba.conf_regs_memmap_p; +		else +			return 0; +	} else +		return 0; + +	/* Read single PCI bar space register */ +	if (acc_range == SINGLE_WORD) { +		offset_run = offset; +		u32val = readl(mem_mapped_bar + offset_run); +		len += snprintf(pbuffer+len, LPFC_PCI_BAR_RD_BUF_SIZE-len, +				"%05x: %08x\n", offset_run, u32val); +	} else +		goto baracc_browse; + +	return simple_read_from_buffer(buf, nbytes, ppos, pbuffer, len); + +baracc_browse: + +	/* Browse all PCI bar space registers */ +	offset_label = idiag.offset.last_rd; +	offset_run = offset_label; + +	/* Read PCI bar memory mapped space */ +	len += snprintf(pbuffer+len, LPFC_PCI_BAR_RD_BUF_SIZE-len, +			"%05x: ", offset_label); +	index = LPFC_PCI_BAR_RD_SIZE; +	while (index > 0) { +		u32val = readl(mem_mapped_bar + offset_run); +		len += snprintf(pbuffer+len, LPFC_PCI_BAR_RD_BUF_SIZE-len, +				"%08x ", u32val); +		offset_run += sizeof(uint32_t); +		if (acc_range == LPFC_PCI_BAR_BROWSE) { +			if (offset_run >= bar_size) { +				len += snprintf(pbuffer+len, +					LPFC_PCI_BAR_RD_BUF_SIZE-len, "\n"); +				break; +			} +		} else { +			if (offset_run >= offset + +			    (acc_range * sizeof(uint32_t))) { +				len += snprintf(pbuffer+len, +					LPFC_PCI_BAR_RD_BUF_SIZE-len, "\n"); +				break; +			} +		} +		index -= sizeof(uint32_t); +		if (!index) +			len += snprintf(pbuffer+len, +					LPFC_PCI_BAR_RD_BUF_SIZE-len, "\n"); +		else if (!(index % (8 * sizeof(uint32_t)))) { +			offset_label += (8 * sizeof(uint32_t)); +			len += snprintf(pbuffer+len, +					LPFC_PCI_BAR_RD_BUF_SIZE-len, +					"\n%05x: ", offset_label); +		} +	} + +	/* Set up the offset for next portion of pci bar read */ +	if (index == 0) { +		idiag.offset.last_rd += LPFC_PCI_BAR_RD_SIZE; +		if (acc_range == LPFC_PCI_BAR_BROWSE) { +			if (idiag.offset.last_rd >= bar_size) +				idiag.offset.last_rd = 0; +		} else { +			if (offset_run >= offset + +			    (acc_range * sizeof(uint32_t))) +				idiag.offset.last_rd = offset; +		} +	} else { +		if (acc_range == LPFC_PCI_BAR_BROWSE) +			idiag.offset.last_rd = 0; +		else +			idiag.offset.last_rd = offset; +	} + +	return simple_read_from_buffer(buf, nbytes, ppos, pbuffer, len); +} + +/** + * lpfc_idiag_baracc_write - Syntax check and set up idiag bar access commands + * @file: The file pointer to read from. + * @buf: The buffer to copy the user data from. + * @nbytes: The number of bytes to get. + * @ppos: The position in the file to start reading from. + * + * This routine get the debugfs idiag command struct from user space and + * then perform the syntax check for PCI bar memory mapped space read or + * write command accordingly. In the case of PCI bar memory mapped space + * read command, it sets up the command in the idiag command struct for + * the debugfs read operation. In the case of PCI bar memorpy mapped space + * write operation, it executes the write operation into the PCI bar memory + * mapped space accordingly. + * + * It returns the @nbytges passing in from debugfs user space when successful. + * In case of error conditions, it returns proper error code back to the user + * space. + */ +static ssize_t +lpfc_idiag_baracc_write(struct file *file, const char __user *buf, +			size_t nbytes, loff_t *ppos) +{ +	struct lpfc_debug *debug = file->private_data; +	struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private; +	uint32_t bar_num, bar_size, offset, value, acc_range; +	struct pci_dev *pdev; +	void __iomem *mem_mapped_bar; +	uint32_t if_type; +	uint32_t u32val; +	int rc; + +	pdev = phba->pcidev; +	if (!pdev) +		return -EFAULT; + +	/* This is a user write operation */ +	debug->op = LPFC_IDIAG_OP_WR; + +	rc = lpfc_idiag_cmd_get(buf, nbytes, &idiag.cmd); +	if (rc < 0) +		return rc; + +	if_type = bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf); +	bar_num = idiag.cmd.data[IDIAG_BARACC_BAR_NUM_INDX]; + +	if (if_type == LPFC_SLI_INTF_IF_TYPE_0) { +		if ((bar_num != IDIAG_BARACC_BAR_0) && +		    (bar_num != IDIAG_BARACC_BAR_1) && +		    (bar_num != IDIAG_BARACC_BAR_2)) +			goto error_out; +	} else if (if_type == LPFC_SLI_INTF_IF_TYPE_2) { +		if (bar_num != IDIAG_BARACC_BAR_0) +			goto error_out; +	} else +		goto error_out; + +	if (if_type == LPFC_SLI_INTF_IF_TYPE_0) { +		if (bar_num == IDIAG_BARACC_BAR_0) { +			idiag.cmd.data[IDIAG_BARACC_BAR_SZE_INDX] = +				LPFC_PCI_IF0_BAR0_SIZE; +			mem_mapped_bar = phba->sli4_hba.conf_regs_memmap_p; +		} else if (bar_num == IDIAG_BARACC_BAR_1) { +			idiag.cmd.data[IDIAG_BARACC_BAR_SZE_INDX] = +				LPFC_PCI_IF0_BAR1_SIZE; +			mem_mapped_bar = phba->sli4_hba.ctrl_regs_memmap_p; +		} else if (bar_num == IDIAG_BARACC_BAR_2) { +			idiag.cmd.data[IDIAG_BARACC_BAR_SZE_INDX] = +				LPFC_PCI_IF0_BAR2_SIZE; +			mem_mapped_bar = phba->sli4_hba.drbl_regs_memmap_p; +		} else +			goto error_out; +	} else if (if_type == LPFC_SLI_INTF_IF_TYPE_2) { +		if (bar_num == IDIAG_BARACC_BAR_0) { +			idiag.cmd.data[IDIAG_BARACC_BAR_SZE_INDX] = +				LPFC_PCI_IF2_BAR0_SIZE; +			mem_mapped_bar = phba->sli4_hba.conf_regs_memmap_p; +		} else +			goto error_out; +	} else +		goto error_out; + +	offset = idiag.cmd.data[IDIAG_BARACC_OFF_SET_INDX]; +	if (offset % sizeof(uint32_t)) +		goto error_out; + +	bar_size = idiag.cmd.data[IDIAG_BARACC_BAR_SZE_INDX]; +	if (idiag.cmd.opcode == LPFC_IDIAG_CMD_BARACC_RD) { +		/* Sanity check on PCI config read command line arguments */ +		if (rc != LPFC_PCI_BAR_RD_CMD_ARG) +			goto error_out; +		acc_range = idiag.cmd.data[IDIAG_BARACC_ACC_MOD_INDX]; +		if (acc_range == LPFC_PCI_BAR_BROWSE) { +			if (offset > bar_size - sizeof(uint32_t)) +				goto error_out; +			/* Starting offset to browse */ +			idiag.offset.last_rd = offset; +		} else if (acc_range > SINGLE_WORD) { +			if (offset + acc_range * sizeof(uint32_t) > bar_size) +				goto error_out; +			/* Starting offset to browse */ +			idiag.offset.last_rd = offset; +		} else if (acc_range != SINGLE_WORD) +			goto error_out; +	} else if (idiag.cmd.opcode == LPFC_IDIAG_CMD_BARACC_WR || +		   idiag.cmd.opcode == LPFC_IDIAG_CMD_BARACC_ST || +		   idiag.cmd.opcode == LPFC_IDIAG_CMD_BARACC_CL) { +		/* Sanity check on PCI bar write command line arguments */ +		if (rc != LPFC_PCI_BAR_WR_CMD_ARG) +			goto error_out; +		/* Write command to PCI bar space, read-modify-write */ +		acc_range = SINGLE_WORD; +		value = idiag.cmd.data[IDIAG_BARACC_REG_VAL_INDX]; +		if (idiag.cmd.opcode == LPFC_IDIAG_CMD_BARACC_WR) { +			writel(value, mem_mapped_bar + offset); +			readl(mem_mapped_bar + offset); +		} +		if (idiag.cmd.opcode == LPFC_IDIAG_CMD_BARACC_ST) { +			u32val = readl(mem_mapped_bar + offset); +			u32val |= value; +			writel(u32val, mem_mapped_bar + offset); +			readl(mem_mapped_bar + offset); +		} +		if (idiag.cmd.opcode == LPFC_IDIAG_CMD_BARACC_CL) { +			u32val = readl(mem_mapped_bar + offset); +			u32val &= ~value; +			writel(u32val, mem_mapped_bar + offset); +			readl(mem_mapped_bar + offset); +		} +	} else +		/* All other opecodes are illegal for now */ +		goto error_out; + +	return nbytes; +error_out: +	memset(&idiag, 0, sizeof(idiag)); +	return -EINVAL; +} + +/**   * lpfc_idiag_queinfo_read - idiag debugfs read queue information   * @file: The file pointer to read from.   * @buf: The buffer to copy the data to. @@ -1870,8 +2183,8 @@ lpfc_idiag_queacc_read(struct file *file, char __user *buf, size_t nbytes,  		return 0;  	if (idiag.cmd.opcode == LPFC_IDIAG_CMD_QUEACC_RD) { -		index = idiag.cmd.data[2]; -		count = idiag.cmd.data[3]; +		index = idiag.cmd.data[IDIAG_QUEACC_INDEX_INDX]; +		count = idiag.cmd.data[IDIAG_QUEACC_COUNT_INDX];  		pque = (struct lpfc_queue *)idiag.ptr_private;  	} else  		return 0; @@ -1943,12 +2256,12 @@ lpfc_idiag_queacc_write(struct file *file, const char __user *buf,  		return rc;  	/* Get and sanity check on command feilds */ -	quetp  = idiag.cmd.data[0]; -	queid  = idiag.cmd.data[1]; -	index  = idiag.cmd.data[2]; -	count  = idiag.cmd.data[3]; -	offset = idiag.cmd.data[4]; -	value  = idiag.cmd.data[5]; +	quetp  = idiag.cmd.data[IDIAG_QUEACC_QUETP_INDX]; +	queid  = idiag.cmd.data[IDIAG_QUEACC_QUEID_INDX]; +	index  = idiag.cmd.data[IDIAG_QUEACC_INDEX_INDX]; +	count  = idiag.cmd.data[IDIAG_QUEACC_COUNT_INDX]; +	offset = idiag.cmd.data[IDIAG_QUEACC_OFFST_INDX]; +	value  = idiag.cmd.data[IDIAG_QUEACC_VALUE_INDX];  	/* Sanity check on command line arguments */  	if (idiag.cmd.opcode == LPFC_IDIAG_CMD_QUEACC_WR || @@ -2217,7 +2530,7 @@ lpfc_idiag_drbacc_read(struct file *file, char __user *buf, size_t nbytes,  		return 0;  	if (idiag.cmd.opcode == LPFC_IDIAG_CMD_DRBACC_RD) -		drb_reg_id = idiag.cmd.data[0]; +		drb_reg_id = idiag.cmd.data[IDIAG_DRBACC_REGID_INDX];  	else  		return 0; @@ -2256,7 +2569,7 @@ lpfc_idiag_drbacc_write(struct file *file, const char __user *buf,  {  	struct lpfc_debug *debug = file->private_data;  	struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private; -	uint32_t drb_reg_id, value, reg_val; +	uint32_t drb_reg_id, value, reg_val = 0;  	void __iomem *drb_reg;  	int rc; @@ -2268,8 +2581,8 @@ lpfc_idiag_drbacc_write(struct file *file, const char __user *buf,  		return rc;  	/* Sanity check on command line arguments */ -	drb_reg_id = idiag.cmd.data[0]; -	value = idiag.cmd.data[1]; +	drb_reg_id = idiag.cmd.data[IDIAG_DRBACC_REGID_INDX]; +	value = idiag.cmd.data[IDIAG_DRBACC_VALUE_INDX];  	if (idiag.cmd.opcode == LPFC_IDIAG_CMD_DRBACC_WR ||  	    idiag.cmd.opcode == LPFC_IDIAG_CMD_DRBACC_ST || @@ -2329,6 +2642,679 @@ error_out:  	return -EINVAL;  } +/** + * lpfc_idiag_ctlacc_read_reg - idiag debugfs read a control registers + * @phba: The pointer to hba structure. + * @pbuffer: The pointer to the buffer to copy the data to. + * @len: The lenght of bytes to copied. + * @drbregid: The id to doorbell registers. + * + * Description: + * This routine reads a control register and copies its content to the + * user buffer pointed to by @pbuffer. + * + * Returns: + * This function returns the amount of data that was copied into @pbuffer. + **/ +static int +lpfc_idiag_ctlacc_read_reg(struct lpfc_hba *phba, char *pbuffer, +			   int len, uint32_t ctlregid) +{ + +	if (!pbuffer) +		return 0; + +	switch (ctlregid) { +	case LPFC_CTL_PORT_SEM: +		len += snprintf(pbuffer+len, LPFC_CTL_ACC_BUF_SIZE-len, +				"Port SemReg:   0x%08x\n", +				readl(phba->sli4_hba.conf_regs_memmap_p + +				      LPFC_CTL_PORT_SEM_OFFSET)); +		break; +	case LPFC_CTL_PORT_STA: +		len += snprintf(pbuffer+len, LPFC_CTL_ACC_BUF_SIZE-len, +				"Port StaReg:   0x%08x\n", +				readl(phba->sli4_hba.conf_regs_memmap_p + +				      LPFC_CTL_PORT_STA_OFFSET)); +		break; +	case LPFC_CTL_PORT_CTL: +		len += snprintf(pbuffer+len, LPFC_CTL_ACC_BUF_SIZE-len, +				"Port CtlReg:   0x%08x\n", +				readl(phba->sli4_hba.conf_regs_memmap_p + +				      LPFC_CTL_PORT_CTL_OFFSET)); +		break; +	case LPFC_CTL_PORT_ER1: +		len += snprintf(pbuffer+len, LPFC_CTL_ACC_BUF_SIZE-len, +				"Port Er1Reg:   0x%08x\n", +				readl(phba->sli4_hba.conf_regs_memmap_p + +				      LPFC_CTL_PORT_ER1_OFFSET)); +		break; +	case LPFC_CTL_PORT_ER2: +		len += snprintf(pbuffer+len, LPFC_CTL_ACC_BUF_SIZE-len, +				"Port Er2Reg:   0x%08x\n", +				readl(phba->sli4_hba.conf_regs_memmap_p + +				      LPFC_CTL_PORT_ER2_OFFSET)); +		break; +	case LPFC_CTL_PDEV_CTL: +		len += snprintf(pbuffer+len, LPFC_CTL_ACC_BUF_SIZE-len, +				"PDev CtlReg:   0x%08x\n", +				readl(phba->sli4_hba.conf_regs_memmap_p + +				      LPFC_CTL_PDEV_CTL_OFFSET)); +		break; +	default: +		break; +	} +	return len; +} + +/** + * lpfc_idiag_ctlacc_read - idiag debugfs read port and device control register + * @file: The file pointer to read from. + * @buf: The buffer to copy the data to. + * @nbytes: The number of bytes to read. + * @ppos: The position in the file to start reading from. + * + * Description: + * This routine reads data from the @phba port and device registers according + * to the idiag command, and copies to user @buf. + * + * Returns: + * This function returns the amount of data that was read (this could be less + * than @nbytes if the end of the file was reached) or a negative error value. + **/ +static ssize_t +lpfc_idiag_ctlacc_read(struct file *file, char __user *buf, size_t nbytes, +		       loff_t *ppos) +{ +	struct lpfc_debug *debug = file->private_data; +	struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private; +	uint32_t ctl_reg_id, i; +	char *pbuffer; +	int len = 0; + +	/* This is a user read operation */ +	debug->op = LPFC_IDIAG_OP_RD; + +	if (!debug->buffer) +		debug->buffer = kmalloc(LPFC_CTL_ACC_BUF_SIZE, GFP_KERNEL); +	if (!debug->buffer) +		return 0; +	pbuffer = debug->buffer; + +	if (*ppos) +		return 0; + +	if (idiag.cmd.opcode == LPFC_IDIAG_CMD_CTLACC_RD) +		ctl_reg_id = idiag.cmd.data[IDIAG_CTLACC_REGID_INDX]; +	else +		return 0; + +	if (ctl_reg_id == LPFC_CTL_ACC_ALL) +		for (i = 1; i <= LPFC_CTL_MAX; i++) +			len = lpfc_idiag_ctlacc_read_reg(phba, +							 pbuffer, len, i); +	else +		len = lpfc_idiag_ctlacc_read_reg(phba, +						 pbuffer, len, ctl_reg_id); + +	return simple_read_from_buffer(buf, nbytes, ppos, pbuffer, len); +} + +/** + * lpfc_idiag_ctlacc_write - Syntax check and set up idiag ctlacc commands + * @file: The file pointer to read from. + * @buf: The buffer to copy the user data from. + * @nbytes: The number of bytes to get. + * @ppos: The position in the file to start reading from. + * + * This routine get the debugfs idiag command struct from user space and then + * perform the syntax check for port and device control register read (dump) + * or write (set) command accordingly. + * + * It returns the @nbytges passing in from debugfs user space when successful. + * In case of error conditions, it returns proper error code back to the user + * space. + **/ +static ssize_t +lpfc_idiag_ctlacc_write(struct file *file, const char __user *buf, +			size_t nbytes, loff_t *ppos) +{ +	struct lpfc_debug *debug = file->private_data; +	struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private; +	uint32_t ctl_reg_id, value, reg_val = 0; +	void __iomem *ctl_reg; +	int rc; + +	/* This is a user write operation */ +	debug->op = LPFC_IDIAG_OP_WR; + +	rc = lpfc_idiag_cmd_get(buf, nbytes, &idiag.cmd); +	if (rc < 0) +		return rc; + +	/* Sanity check on command line arguments */ +	ctl_reg_id = idiag.cmd.data[IDIAG_CTLACC_REGID_INDX]; +	value = idiag.cmd.data[IDIAG_CTLACC_VALUE_INDX]; + +	if (idiag.cmd.opcode == LPFC_IDIAG_CMD_CTLACC_WR || +	    idiag.cmd.opcode == LPFC_IDIAG_CMD_CTLACC_ST || +	    idiag.cmd.opcode == LPFC_IDIAG_CMD_CTLACC_CL) { +		if (rc != LPFC_CTL_ACC_WR_CMD_ARG) +			goto error_out; +		if (ctl_reg_id > LPFC_CTL_MAX) +			goto error_out; +	} else if (idiag.cmd.opcode == LPFC_IDIAG_CMD_CTLACC_RD) { +		if (rc != LPFC_CTL_ACC_RD_CMD_ARG) +			goto error_out; +		if ((ctl_reg_id > LPFC_CTL_MAX) && +		    (ctl_reg_id != LPFC_CTL_ACC_ALL)) +			goto error_out; +	} else +		goto error_out; + +	/* Perform the write access operation */ +	if (idiag.cmd.opcode == LPFC_IDIAG_CMD_CTLACC_WR || +	    idiag.cmd.opcode == LPFC_IDIAG_CMD_CTLACC_ST || +	    idiag.cmd.opcode == LPFC_IDIAG_CMD_CTLACC_CL) { +		switch (ctl_reg_id) { +		case LPFC_CTL_PORT_SEM: +			ctl_reg = phba->sli4_hba.conf_regs_memmap_p + +					LPFC_CTL_PORT_SEM_OFFSET; +			break; +		case LPFC_CTL_PORT_STA: +			ctl_reg = phba->sli4_hba.conf_regs_memmap_p + +					LPFC_CTL_PORT_STA_OFFSET; +			break; +		case LPFC_CTL_PORT_CTL: +			ctl_reg = phba->sli4_hba.conf_regs_memmap_p + +					LPFC_CTL_PORT_CTL_OFFSET; +			break; +		case LPFC_CTL_PORT_ER1: +			ctl_reg = phba->sli4_hba.conf_regs_memmap_p + +					LPFC_CTL_PORT_ER1_OFFSET; +			break; +		case LPFC_CTL_PORT_ER2: +			ctl_reg = phba->sli4_hba.conf_regs_memmap_p + +					LPFC_CTL_PORT_ER2_OFFSET; +			break; +		case LPFC_CTL_PDEV_CTL: +			ctl_reg = phba->sli4_hba.conf_regs_memmap_p + +					LPFC_CTL_PDEV_CTL_OFFSET; +			break; +		default: +			goto error_out; +		} + +		if (idiag.cmd.opcode == LPFC_IDIAG_CMD_CTLACC_WR) +			reg_val = value; +		if (idiag.cmd.opcode == LPFC_IDIAG_CMD_CTLACC_ST) { +			reg_val = readl(ctl_reg); +			reg_val |= value; +		} +		if (idiag.cmd.opcode == LPFC_IDIAG_CMD_CTLACC_CL) { +			reg_val = readl(ctl_reg); +			reg_val &= ~value; +		} +		writel(reg_val, ctl_reg); +		readl(ctl_reg); /* flush */ +	} +	return nbytes; + +error_out: +	/* Clean out command structure on command error out */ +	memset(&idiag, 0, sizeof(idiag)); +	return -EINVAL; +} + +/** + * lpfc_idiag_mbxacc_get_setup - idiag debugfs get mailbox access setup + * @phba: Pointer to HBA context object. + * @pbuffer: Pointer to data buffer. + * + * Description: + * This routine gets the driver mailbox access debugfs setup information. + * + * Returns: + * This function returns the amount of data that was read (this could be less + * than @nbytes if the end of the file was reached) or a negative error value. + **/ +static int +lpfc_idiag_mbxacc_get_setup(struct lpfc_hba *phba, char *pbuffer) +{ +	uint32_t mbx_dump_map, mbx_dump_cnt, mbx_word_cnt, mbx_mbox_cmd; +	int len = 0; + +	mbx_mbox_cmd = idiag.cmd.data[IDIAG_MBXACC_MBCMD_INDX]; +	mbx_dump_map = idiag.cmd.data[IDIAG_MBXACC_DPMAP_INDX]; +	mbx_dump_cnt = idiag.cmd.data[IDIAG_MBXACC_DPCNT_INDX]; +	mbx_word_cnt = idiag.cmd.data[IDIAG_MBXACC_WDCNT_INDX]; + +	len += snprintf(pbuffer+len, LPFC_MBX_ACC_BUF_SIZE-len, +			"mbx_dump_map: 0x%08x\n", mbx_dump_map); +	len += snprintf(pbuffer+len, LPFC_MBX_ACC_BUF_SIZE-len, +			"mbx_dump_cnt: %04d\n", mbx_dump_cnt); +	len += snprintf(pbuffer+len, LPFC_MBX_ACC_BUF_SIZE-len, +			"mbx_word_cnt: %04d\n", mbx_word_cnt); +	len += snprintf(pbuffer+len, LPFC_MBX_ACC_BUF_SIZE-len, +			"mbx_mbox_cmd: 0x%02x\n", mbx_mbox_cmd); + +	return len; +} + +/** + * lpfc_idiag_mbxacc_read - idiag debugfs read on mailbox access + * @file: The file pointer to read from. + * @buf: The buffer to copy the data to. + * @nbytes: The number of bytes to read. + * @ppos: The position in the file to start reading from. + * + * Description: + * This routine reads data from the @phba driver mailbox access debugfs setup + * information. + * + * Returns: + * This function returns the amount of data that was read (this could be less + * than @nbytes if the end of the file was reached) or a negative error value. + **/ +static ssize_t +lpfc_idiag_mbxacc_read(struct file *file, char __user *buf, size_t nbytes, +		       loff_t *ppos) +{ +	struct lpfc_debug *debug = file->private_data; +	struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private; +	char *pbuffer; +	int len = 0; + +	/* This is a user read operation */ +	debug->op = LPFC_IDIAG_OP_RD; + +	if (!debug->buffer) +		debug->buffer = kmalloc(LPFC_MBX_ACC_BUF_SIZE, GFP_KERNEL); +	if (!debug->buffer) +		return 0; +	pbuffer = debug->buffer; + +	if (*ppos) +		return 0; + +	if ((idiag.cmd.opcode != LPFC_IDIAG_CMD_MBXACC_DP) && +	    (idiag.cmd.opcode != LPFC_IDIAG_BSG_MBXACC_DP)) +		return 0; + +	len = lpfc_idiag_mbxacc_get_setup(phba, pbuffer); + +	return simple_read_from_buffer(buf, nbytes, ppos, pbuffer, len); +} + +/** + * lpfc_idiag_mbxacc_write - Syntax check and set up idiag mbxacc commands + * @file: The file pointer to read from. + * @buf: The buffer to copy the user data from. + * @nbytes: The number of bytes to get. + * @ppos: The position in the file to start reading from. + * + * This routine get the debugfs idiag command struct from user space and then + * perform the syntax check for driver mailbox command (dump) and sets up the + * necessary states in the idiag command struct accordingly. + * + * It returns the @nbytges passing in from debugfs user space when successful. + * In case of error conditions, it returns proper error code back to the user + * space. + **/ +static ssize_t +lpfc_idiag_mbxacc_write(struct file *file, const char __user *buf, +			size_t nbytes, loff_t *ppos) +{ +	struct lpfc_debug *debug = file->private_data; +	uint32_t mbx_dump_map, mbx_dump_cnt, mbx_word_cnt, mbx_mbox_cmd; +	int rc; + +	/* This is a user write operation */ +	debug->op = LPFC_IDIAG_OP_WR; + +	rc = lpfc_idiag_cmd_get(buf, nbytes, &idiag.cmd); +	if (rc < 0) +		return rc; + +	/* Sanity check on command line arguments */ +	mbx_mbox_cmd = idiag.cmd.data[IDIAG_MBXACC_MBCMD_INDX]; +	mbx_dump_map = idiag.cmd.data[IDIAG_MBXACC_DPMAP_INDX]; +	mbx_dump_cnt = idiag.cmd.data[IDIAG_MBXACC_DPCNT_INDX]; +	mbx_word_cnt = idiag.cmd.data[IDIAG_MBXACC_WDCNT_INDX]; + +	if (idiag.cmd.opcode == LPFC_IDIAG_CMD_MBXACC_DP) { +		if (!(mbx_dump_map & LPFC_MBX_DMP_MBX_ALL)) +			goto error_out; +		if ((mbx_dump_map & ~LPFC_MBX_DMP_MBX_ALL) && +		    (mbx_dump_map != LPFC_MBX_DMP_ALL)) +			goto error_out; +		if (mbx_word_cnt > sizeof(MAILBOX_t)) +			goto error_out; +	} else if (idiag.cmd.opcode == LPFC_IDIAG_BSG_MBXACC_DP) { +		if (!(mbx_dump_map & LPFC_BSG_DMP_MBX_ALL)) +			goto error_out; +		if ((mbx_dump_map & ~LPFC_BSG_DMP_MBX_ALL) && +		    (mbx_dump_map != LPFC_MBX_DMP_ALL)) +			goto error_out; +		if (mbx_word_cnt > (BSG_MBOX_SIZE)/4) +			goto error_out; +		if (mbx_mbox_cmd != 0x9b) +			goto error_out; +	} else +		goto error_out; + +	if (mbx_word_cnt == 0) +		goto error_out; +	if (rc != LPFC_MBX_DMP_ARG) +		goto error_out; +	if (mbx_mbox_cmd & ~0xff) +		goto error_out; + +	/* condition for stop mailbox dump */ +	if (mbx_dump_cnt == 0) +		goto reset_out; + +	return nbytes; + +reset_out: +	/* Clean out command structure on command error out */ +	memset(&idiag, 0, sizeof(idiag)); +	return nbytes; + +error_out: +	/* Clean out command structure on command error out */ +	memset(&idiag, 0, sizeof(idiag)); +	return -EINVAL; +} + +/** + * lpfc_idiag_extacc_avail_get - get the available extents information + * @phba: pointer to lpfc hba data structure. + * @pbuffer: pointer to internal buffer. + * @len: length into the internal buffer data has been copied. + * + * Description: + * This routine is to get the available extent information. + * + * Returns: + * overall lenth of the data read into the internal buffer. + **/ +static int +lpfc_idiag_extacc_avail_get(struct lpfc_hba *phba, char *pbuffer, int len) +{ +	uint16_t ext_cnt, ext_size; + +	len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, +			"\nAvailable Extents Information:\n"); + +	len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, +			"\tPort Available VPI extents: "); +	lpfc_sli4_get_avail_extnt_rsrc(phba, LPFC_RSC_TYPE_FCOE_VPI, +				       &ext_cnt, &ext_size); +	len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, +			"Count %3d, Size %3d\n", ext_cnt, ext_size); + +	len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, +			"\tPort Available VFI extents: "); +	lpfc_sli4_get_avail_extnt_rsrc(phba, LPFC_RSC_TYPE_FCOE_VFI, +				       &ext_cnt, &ext_size); +	len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, +			"Count %3d, Size %3d\n", ext_cnt, ext_size); + +	len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, +			"\tPort Available RPI extents: "); +	lpfc_sli4_get_avail_extnt_rsrc(phba, LPFC_RSC_TYPE_FCOE_RPI, +				       &ext_cnt, &ext_size); +	len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, +			"Count %3d, Size %3d\n", ext_cnt, ext_size); + +	len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, +			"\tPort Available XRI extents: "); +	lpfc_sli4_get_avail_extnt_rsrc(phba, LPFC_RSC_TYPE_FCOE_XRI, +				       &ext_cnt, &ext_size); +	len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, +			"Count %3d, Size %3d\n", ext_cnt, ext_size); + +	return len; +} + +/** + * lpfc_idiag_extacc_alloc_get - get the allocated extents information + * @phba: pointer to lpfc hba data structure. + * @pbuffer: pointer to internal buffer. + * @len: length into the internal buffer data has been copied. + * + * Description: + * This routine is to get the allocated extent information. + * + * Returns: + * overall lenth of the data read into the internal buffer. + **/ +static int +lpfc_idiag_extacc_alloc_get(struct lpfc_hba *phba, char *pbuffer, int len) +{ +	uint16_t ext_cnt, ext_size; +	int rc; + +	len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, +			"\nAllocated Extents Information:\n"); + +	len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, +			"\tHost Allocated VPI extents: "); +	rc = lpfc_sli4_get_allocated_extnts(phba, LPFC_RSC_TYPE_FCOE_VPI, +					    &ext_cnt, &ext_size); +	if (!rc) +		len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, +				"Port %d Extent %3d, Size %3d\n", +				phba->brd_no, ext_cnt, ext_size); +	else +		len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, +				"N/A\n"); + +	len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, +			"\tHost Allocated VFI extents: "); +	rc = lpfc_sli4_get_allocated_extnts(phba, LPFC_RSC_TYPE_FCOE_VFI, +					    &ext_cnt, &ext_size); +	if (!rc) +		len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, +				"Port %d Extent %3d, Size %3d\n", +				phba->brd_no, ext_cnt, ext_size); +	else +		len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, +				"N/A\n"); + +	len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, +			"\tHost Allocated RPI extents: "); +	rc = lpfc_sli4_get_allocated_extnts(phba, LPFC_RSC_TYPE_FCOE_RPI, +					    &ext_cnt, &ext_size); +	if (!rc) +		len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, +				"Port %d Extent %3d, Size %3d\n", +				phba->brd_no, ext_cnt, ext_size); +	else +		len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, +				"N/A\n"); + +	len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, +			"\tHost Allocated XRI extents: "); +	rc = lpfc_sli4_get_allocated_extnts(phba, LPFC_RSC_TYPE_FCOE_XRI, +					    &ext_cnt, &ext_size); +	if (!rc) +		len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, +				"Port %d Extent %3d, Size %3d\n", +				phba->brd_no, ext_cnt, ext_size); +	else +		len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, +				"N/A\n"); + +	return len; +} + +/** + * lpfc_idiag_extacc_drivr_get - get driver extent information + * @phba: pointer to lpfc hba data structure. + * @pbuffer: pointer to internal buffer. + * @len: length into the internal buffer data has been copied. + * + * Description: + * This routine is to get the driver extent information. + * + * Returns: + * overall lenth of the data read into the internal buffer. + **/ +static int +lpfc_idiag_extacc_drivr_get(struct lpfc_hba *phba, char *pbuffer, int len) +{ +	struct lpfc_rsrc_blks *rsrc_blks; +	int index; + +	len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, +			"\nDriver Extents Information:\n"); + +	len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, +			"\tVPI extents:\n"); +	index = 0; +	list_for_each_entry(rsrc_blks, &phba->lpfc_vpi_blk_list, list) { +		len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, +				"\t\tBlock %3d: Start %4d, Count %4d\n", +				index, rsrc_blks->rsrc_start, +				rsrc_blks->rsrc_size); +		index++; +	} +	len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, +			"\tVFI extents:\n"); +	index = 0; +	list_for_each_entry(rsrc_blks, &phba->sli4_hba.lpfc_vfi_blk_list, +			    list) { +		len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, +				"\t\tBlock %3d: Start %4d, Count %4d\n", +				index, rsrc_blks->rsrc_start, +				rsrc_blks->rsrc_size); +		index++; +	} + +	len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, +			"\tRPI extents:\n"); +	index = 0; +	list_for_each_entry(rsrc_blks, &phba->sli4_hba.lpfc_rpi_blk_list, +			    list) { +		len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, +				"\t\tBlock %3d: Start %4d, Count %4d\n", +				index, rsrc_blks->rsrc_start, +				rsrc_blks->rsrc_size); +		index++; +	} + +	len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, +			"\tXRI extents:\n"); +	index = 0; +	list_for_each_entry(rsrc_blks, &phba->sli4_hba.lpfc_xri_blk_list, +			    list) { +		len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, +				"\t\tBlock %3d: Start %4d, Count %4d\n", +				index, rsrc_blks->rsrc_start, +				rsrc_blks->rsrc_size); +		index++; +	} + +	return len; +} + +/** + * lpfc_idiag_extacc_write - Syntax check and set up idiag extacc commands + * @file: The file pointer to read from. + * @buf: The buffer to copy the user data from. + * @nbytes: The number of bytes to get. + * @ppos: The position in the file to start reading from. + * + * This routine get the debugfs idiag command struct from user space and then + * perform the syntax check for extent information access commands and sets + * up the necessary states in the idiag command struct accordingly. + * + * It returns the @nbytges passing in from debugfs user space when successful. + * In case of error conditions, it returns proper error code back to the user + * space. + **/ +static ssize_t +lpfc_idiag_extacc_write(struct file *file, const char __user *buf, +			size_t nbytes, loff_t *ppos) +{ +	struct lpfc_debug *debug = file->private_data; +	uint32_t ext_map; +	int rc; + +	/* This is a user write operation */ +	debug->op = LPFC_IDIAG_OP_WR; + +	rc = lpfc_idiag_cmd_get(buf, nbytes, &idiag.cmd); +	if (rc < 0) +		return rc; + +	ext_map = idiag.cmd.data[IDIAG_EXTACC_EXMAP_INDX]; + +	if (idiag.cmd.opcode != LPFC_IDIAG_CMD_EXTACC_RD) +		goto error_out; +	if (rc != LPFC_EXT_ACC_CMD_ARG) +		goto error_out; +	if (!(ext_map & LPFC_EXT_ACC_ALL)) +		goto error_out; + +	return nbytes; +error_out: +	/* Clean out command structure on command error out */ +	memset(&idiag, 0, sizeof(idiag)); +	return -EINVAL; +} + +/** + * lpfc_idiag_extacc_read - idiag debugfs read access to extent information + * @file: The file pointer to read from. + * @buf: The buffer to copy the data to. + * @nbytes: The number of bytes to read. + * @ppos: The position in the file to start reading from. + * + * Description: + * This routine reads data from the proper extent information according to + * the idiag command, and copies to user @buf. + * + * Returns: + * This function returns the amount of data that was read (this could be less + * than @nbytes if the end of the file was reached) or a negative error value. + **/ +static ssize_t +lpfc_idiag_extacc_read(struct file *file, char __user *buf, size_t nbytes, +		       loff_t *ppos) +{ +	struct lpfc_debug *debug = file->private_data; +	struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private; +	char *pbuffer; +	uint32_t ext_map; +	int len = 0; + +	/* This is a user read operation */ +	debug->op = LPFC_IDIAG_OP_RD; + +	if (!debug->buffer) +		debug->buffer = kmalloc(LPFC_EXT_ACC_BUF_SIZE, GFP_KERNEL); +	if (!debug->buffer) +		return 0; +	pbuffer = debug->buffer; +	if (*ppos) +		return 0; +	if (idiag.cmd.opcode != LPFC_IDIAG_CMD_EXTACC_RD) +		return 0; + +	ext_map = idiag.cmd.data[IDIAG_EXTACC_EXMAP_INDX]; +	if (ext_map & LPFC_EXT_ACC_AVAIL) +		len = lpfc_idiag_extacc_avail_get(phba, pbuffer, len); +	if (ext_map & LPFC_EXT_ACC_ALLOC) +		len = lpfc_idiag_extacc_alloc_get(phba, pbuffer, len); +	if (ext_map & LPFC_EXT_ACC_DRIVR) +		len = lpfc_idiag_extacc_drivr_get(phba, pbuffer, len); + +	return simple_read_from_buffer(buf, nbytes, ppos, pbuffer, len); +} +  #undef lpfc_debugfs_op_disc_trc  static const struct file_operations lpfc_debugfs_op_disc_trc = {  	.owner =        THIS_MODULE, @@ -2419,6 +3405,16 @@ static const struct file_operations lpfc_idiag_op_pciCfg = {  	.release =      lpfc_idiag_cmd_release,  }; +#undef lpfc_idiag_op_barAcc +static const struct file_operations lpfc_idiag_op_barAcc = { +	.owner =        THIS_MODULE, +	.open =         lpfc_idiag_open, +	.llseek =       lpfc_debugfs_lseek, +	.read =         lpfc_idiag_baracc_read, +	.write =        lpfc_idiag_baracc_write, +	.release =      lpfc_idiag_cmd_release, +}; +  #undef lpfc_idiag_op_queInfo  static const struct file_operations lpfc_idiag_op_queInfo = {  	.owner =        THIS_MODULE, @@ -2427,7 +3423,7 @@ static const struct file_operations lpfc_idiag_op_queInfo = {  	.release =      lpfc_idiag_release,  }; -#undef lpfc_idiag_op_queacc +#undef lpfc_idiag_op_queAcc  static const struct file_operations lpfc_idiag_op_queAcc = {  	.owner =        THIS_MODULE,  	.open =         lpfc_idiag_open, @@ -2437,7 +3433,7 @@ static const struct file_operations lpfc_idiag_op_queAcc = {  	.release =      lpfc_idiag_cmd_release,  }; -#undef lpfc_idiag_op_drbacc +#undef lpfc_idiag_op_drbAcc  static const struct file_operations lpfc_idiag_op_drbAcc = {  	.owner =        THIS_MODULE,  	.open =         lpfc_idiag_open, @@ -2447,8 +3443,234 @@ static const struct file_operations lpfc_idiag_op_drbAcc = {  	.release =      lpfc_idiag_cmd_release,  }; +#undef lpfc_idiag_op_ctlAcc +static const struct file_operations lpfc_idiag_op_ctlAcc = { +	.owner =        THIS_MODULE, +	.open =         lpfc_idiag_open, +	.llseek =       lpfc_debugfs_lseek, +	.read =         lpfc_idiag_ctlacc_read, +	.write =        lpfc_idiag_ctlacc_write, +	.release =      lpfc_idiag_cmd_release, +}; + +#undef lpfc_idiag_op_mbxAcc +static const struct file_operations lpfc_idiag_op_mbxAcc = { +	.owner =        THIS_MODULE, +	.open =         lpfc_idiag_open, +	.llseek =       lpfc_debugfs_lseek, +	.read =         lpfc_idiag_mbxacc_read, +	.write =        lpfc_idiag_mbxacc_write, +	.release =      lpfc_idiag_cmd_release, +}; + +#undef lpfc_idiag_op_extAcc +static const struct file_operations lpfc_idiag_op_extAcc = { +	.owner =        THIS_MODULE, +	.open =         lpfc_idiag_open, +	.llseek =       lpfc_debugfs_lseek, +	.read =         lpfc_idiag_extacc_read, +	.write =        lpfc_idiag_extacc_write, +	.release =      lpfc_idiag_cmd_release, +}; +  #endif +/* lpfc_idiag_mbxacc_dump_bsg_mbox - idiag debugfs dump bsg mailbox command + * @phba: Pointer to HBA context object. + * @dmabuf: Pointer to a DMA buffer descriptor. + * + * Description: + * This routine dump a bsg pass-through non-embedded mailbox command with + * external buffer. + **/ +void +lpfc_idiag_mbxacc_dump_bsg_mbox(struct lpfc_hba *phba, enum nemb_type nemb_tp, +				enum mbox_type mbox_tp, enum dma_type dma_tp, +				enum sta_type sta_tp, +				struct lpfc_dmabuf *dmabuf, uint32_t ext_buf) +{ +#ifdef CONFIG_SCSI_LPFC_DEBUG_FS +	uint32_t *mbx_mbox_cmd, *mbx_dump_map, *mbx_dump_cnt, *mbx_word_cnt; +	char line_buf[LPFC_MBX_ACC_LBUF_SZ]; +	int len = 0; +	uint32_t do_dump = 0; +	uint32_t *pword; +	uint32_t i; + +	if (idiag.cmd.opcode != LPFC_IDIAG_BSG_MBXACC_DP) +		return; + +	mbx_mbox_cmd = &idiag.cmd.data[IDIAG_MBXACC_MBCMD_INDX]; +	mbx_dump_map = &idiag.cmd.data[IDIAG_MBXACC_DPMAP_INDX]; +	mbx_dump_cnt = &idiag.cmd.data[IDIAG_MBXACC_DPCNT_INDX]; +	mbx_word_cnt = &idiag.cmd.data[IDIAG_MBXACC_WDCNT_INDX]; + +	if (!(*mbx_dump_map & LPFC_MBX_DMP_ALL) || +	    (*mbx_dump_cnt == 0) || +	    (*mbx_word_cnt == 0)) +		return; + +	if (*mbx_mbox_cmd != 0x9B) +		return; + +	if ((mbox_tp == mbox_rd) && (dma_tp == dma_mbox)) { +		if (*mbx_dump_map & LPFC_BSG_DMP_MBX_RD_MBX) { +			do_dump |= LPFC_BSG_DMP_MBX_RD_MBX; +			printk(KERN_ERR "\nRead mbox command (x%x), " +			       "nemb:0x%x, extbuf_cnt:%d:\n", +			       sta_tp, nemb_tp, ext_buf); +		} +	} +	if ((mbox_tp == mbox_rd) && (dma_tp == dma_ebuf)) { +		if (*mbx_dump_map & LPFC_BSG_DMP_MBX_RD_BUF) { +			do_dump |= LPFC_BSG_DMP_MBX_RD_BUF; +			printk(KERN_ERR "\nRead mbox buffer (x%x), " +			       "nemb:0x%x, extbuf_seq:%d:\n", +			       sta_tp, nemb_tp, ext_buf); +		} +	} +	if ((mbox_tp == mbox_wr) && (dma_tp == dma_mbox)) { +		if (*mbx_dump_map & LPFC_BSG_DMP_MBX_WR_MBX) { +			do_dump |= LPFC_BSG_DMP_MBX_WR_MBX; +			printk(KERN_ERR "\nWrite mbox command (x%x), " +			       "nemb:0x%x, extbuf_cnt:%d:\n", +			       sta_tp, nemb_tp, ext_buf); +		} +	} +	if ((mbox_tp == mbox_wr) && (dma_tp == dma_ebuf)) { +		if (*mbx_dump_map & LPFC_BSG_DMP_MBX_WR_BUF) { +			do_dump |= LPFC_BSG_DMP_MBX_WR_BUF; +			printk(KERN_ERR "\nWrite mbox buffer (x%x), " +			       "nemb:0x%x, extbuf_seq:%d:\n", +			       sta_tp, nemb_tp, ext_buf); +		} +	} + +	/* dump buffer content */ +	if (do_dump) { +		pword = (uint32_t *)dmabuf->virt; +		for (i = 0; i < *mbx_word_cnt; i++) { +			if (!(i % 8)) { +				if (i != 0) +					printk(KERN_ERR "%s\n", line_buf); +				len = 0; +				len += snprintf(line_buf+len, +						LPFC_MBX_ACC_LBUF_SZ-len, +						"%03d: ", i); +			} +			len += snprintf(line_buf+len, LPFC_MBX_ACC_LBUF_SZ-len, +					"%08x ", (uint32_t)*pword); +			pword++; +		} +		if ((i - 1) % 8) +			printk(KERN_ERR "%s\n", line_buf); +		(*mbx_dump_cnt)--; +	} + +	/* Clean out command structure on reaching dump count */ +	if (*mbx_dump_cnt == 0) +		memset(&idiag, 0, sizeof(idiag)); +	return; +#endif +} + +/* lpfc_idiag_mbxacc_dump_issue_mbox - idiag debugfs dump issue mailbox command + * @phba: Pointer to HBA context object. + * @dmabuf: Pointer to a DMA buffer descriptor. + * + * Description: + * This routine dump a pass-through non-embedded mailbox command from issue + * mailbox command. + **/ +void +lpfc_idiag_mbxacc_dump_issue_mbox(struct lpfc_hba *phba, MAILBOX_t *pmbox) +{ +#ifdef CONFIG_SCSI_LPFC_DEBUG_FS +	uint32_t *mbx_dump_map, *mbx_dump_cnt, *mbx_word_cnt, *mbx_mbox_cmd; +	char line_buf[LPFC_MBX_ACC_LBUF_SZ]; +	int len = 0; +	uint32_t *pword; +	uint8_t *pbyte; +	uint32_t i, j; + +	if (idiag.cmd.opcode != LPFC_IDIAG_CMD_MBXACC_DP) +		return; + +	mbx_mbox_cmd = &idiag.cmd.data[IDIAG_MBXACC_MBCMD_INDX]; +	mbx_dump_map = &idiag.cmd.data[IDIAG_MBXACC_DPMAP_INDX]; +	mbx_dump_cnt = &idiag.cmd.data[IDIAG_MBXACC_DPCNT_INDX]; +	mbx_word_cnt = &idiag.cmd.data[IDIAG_MBXACC_WDCNT_INDX]; + +	if (!(*mbx_dump_map & LPFC_MBX_DMP_MBX_ALL) || +	    (*mbx_dump_cnt == 0) || +	    (*mbx_word_cnt == 0)) +		return; + +	if ((*mbx_mbox_cmd != LPFC_MBX_ALL_CMD) && +	    (*mbx_mbox_cmd != pmbox->mbxCommand)) +		return; + +	/* dump buffer content */ +	if (*mbx_dump_map & LPFC_MBX_DMP_MBX_WORD) { +		printk(KERN_ERR "Mailbox command:0x%x dump by word:\n", +		       pmbox->mbxCommand); +		pword = (uint32_t *)pmbox; +		for (i = 0; i < *mbx_word_cnt; i++) { +			if (!(i % 8)) { +				if (i != 0) +					printk(KERN_ERR "%s\n", line_buf); +				len = 0; +				memset(line_buf, 0, LPFC_MBX_ACC_LBUF_SZ); +				len += snprintf(line_buf+len, +						LPFC_MBX_ACC_LBUF_SZ-len, +						"%03d: ", i); +			} +			len += snprintf(line_buf+len, LPFC_MBX_ACC_LBUF_SZ-len, +					"%08x ", +					((uint32_t)*pword) & 0xffffffff); +			pword++; +		} +		if ((i - 1) % 8) +			printk(KERN_ERR "%s\n", line_buf); +		printk(KERN_ERR "\n"); +	} +	if (*mbx_dump_map & LPFC_MBX_DMP_MBX_BYTE) { +		printk(KERN_ERR "Mailbox command:0x%x dump by byte:\n", +		       pmbox->mbxCommand); +		pbyte = (uint8_t *)pmbox; +		for (i = 0; i < *mbx_word_cnt; i++) { +			if (!(i % 8)) { +				if (i != 0) +					printk(KERN_ERR "%s\n", line_buf); +				len = 0; +				memset(line_buf, 0, LPFC_MBX_ACC_LBUF_SZ); +				len += snprintf(line_buf+len, +						LPFC_MBX_ACC_LBUF_SZ-len, +						"%03d: ", i); +			} +			for (j = 0; j < 4; j++) { +				len += snprintf(line_buf+len, +						LPFC_MBX_ACC_LBUF_SZ-len, +						"%02x", +						((uint8_t)*pbyte) & 0xff); +				pbyte++; +			} +			len += snprintf(line_buf+len, +					LPFC_MBX_ACC_LBUF_SZ-len, " "); +		} +		if ((i - 1) % 8) +			printk(KERN_ERR "%s\n", line_buf); +		printk(KERN_ERR "\n"); +	} +	(*mbx_dump_cnt)--; + +	/* Clean out command structure on reaching dump count */ +	if (*mbx_dump_cnt == 0) +		memset(&idiag, 0, sizeof(idiag)); +	return; +#endif +} +  /**   * lpfc_debugfs_initialize - Initialize debugfs for a vport   * @vport: The vport pointer to initialize. @@ -2672,7 +3894,7 @@ lpfc_debugfs_initialize(struct lpfc_vport *vport)  				 vport, &lpfc_debugfs_op_nodelist);  	if (!vport->debug_nodelist) {  		lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, -				 "0409 Can't create debugfs nodelist\n"); +				 "2985 Can't create debugfs nodelist\n");  		goto debug_failed;  	} @@ -2709,6 +3931,20 @@ lpfc_debugfs_initialize(struct lpfc_vport *vport)  		idiag.offset.last_rd = 0;  	} +	/* iDiag PCI BAR access */ +	snprintf(name, sizeof(name), "barAcc"); +	if (!phba->idiag_bar_acc) { +		phba->idiag_bar_acc = +			debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, +				phba->idiag_root, phba, &lpfc_idiag_op_barAcc); +		if (!phba->idiag_bar_acc) { +			lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, +					"3056 Can't create idiag debugfs\n"); +			goto debug_failed; +		} +		idiag.offset.last_rd = 0; +	} +  	/* iDiag get PCI function queue information */  	snprintf(name, sizeof(name), "queInfo");  	if (!phba->idiag_que_info) { @@ -2748,6 +3984,50 @@ lpfc_debugfs_initialize(struct lpfc_vport *vport)  		}  	} +	/* iDiag access PCI function control registers */ +	snprintf(name, sizeof(name), "ctlAcc"); +	if (!phba->idiag_ctl_acc) { +		phba->idiag_ctl_acc = +			debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, +				phba->idiag_root, phba, &lpfc_idiag_op_ctlAcc); +		if (!phba->idiag_ctl_acc) { +			lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, +					 "2981 Can't create idiag debugfs\n"); +			goto debug_failed; +		} +	} + +	/* iDiag access mbox commands */ +	snprintf(name, sizeof(name), "mbxAcc"); +	if (!phba->idiag_mbx_acc) { +		phba->idiag_mbx_acc = +			debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, +				phba->idiag_root, phba, &lpfc_idiag_op_mbxAcc); +		if (!phba->idiag_mbx_acc) { +			lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, +					"2980 Can't create idiag debugfs\n"); +			goto debug_failed; +		} +	} + +	/* iDiag extents access commands */ +	if (phba->sli4_hba.extents_in_use) { +		snprintf(name, sizeof(name), "extAcc"); +		if (!phba->idiag_ext_acc) { +			phba->idiag_ext_acc = +				debugfs_create_file(name, +						    S_IFREG|S_IRUGO|S_IWUSR, +						    phba->idiag_root, phba, +						    &lpfc_idiag_op_extAcc); +			if (!phba->idiag_ext_acc) { +				lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, +						"2986 Cant create " +						"idiag debugfs\n"); +				goto debug_failed; +			} +		} +	} +  debug_failed:  	return;  #endif @@ -2782,7 +4062,6 @@ lpfc_debugfs_terminate(struct lpfc_vport *vport)  		debugfs_remove(vport->debug_nodelist); /* nodelist */  		vport->debug_nodelist = NULL;  	} -  	if (vport->vport_debugfs_root) {  		debugfs_remove(vport->vport_debugfs_root); /* vportX */  		vport->vport_debugfs_root = NULL; @@ -2826,6 +4105,21 @@ lpfc_debugfs_terminate(struct lpfc_vport *vport)  		 * iDiag release  		 */  		if (phba->sli_rev == LPFC_SLI_REV4) { +			if (phba->idiag_ext_acc) { +				/* iDiag extAcc */ +				debugfs_remove(phba->idiag_ext_acc); +				phba->idiag_ext_acc = NULL; +			} +			if (phba->idiag_mbx_acc) { +				/* iDiag mbxAcc */ +				debugfs_remove(phba->idiag_mbx_acc); +				phba->idiag_mbx_acc = NULL; +			} +			if (phba->idiag_ctl_acc) { +				/* iDiag ctlAcc */ +				debugfs_remove(phba->idiag_ctl_acc); +				phba->idiag_ctl_acc = NULL; +			}  			if (phba->idiag_drb_acc) {  				/* iDiag drbAcc */  				debugfs_remove(phba->idiag_drb_acc); @@ -2841,6 +4135,11 @@ lpfc_debugfs_terminate(struct lpfc_vport *vport)  				debugfs_remove(phba->idiag_que_info);  				phba->idiag_que_info = NULL;  			} +			if (phba->idiag_bar_acc) { +				/* iDiag barAcc */ +				debugfs_remove(phba->idiag_bar_acc); +				phba->idiag_bar_acc = NULL; +			}  			if (phba->idiag_pci_cfg) {  				/* iDiag pciCfg */  				debugfs_remove(phba->idiag_pci_cfg); diff --git a/drivers/scsi/lpfc/lpfc_debugfs.h b/drivers/scsi/lpfc/lpfc_debugfs.h index 6525a5e62d27..f83bd944edd8 100644 --- a/drivers/scsi/lpfc/lpfc_debugfs.h +++ b/drivers/scsi/lpfc/lpfc_debugfs.h @@ -39,14 +39,51 @@  /* hbqinfo output buffer size */  #define LPFC_HBQINFO_SIZE 8192 +/* + * For SLI4 iDiag debugfs diagnostics tool + */ +  /* pciConf */  #define LPFC_PCI_CFG_BROWSE 0xffff  #define LPFC_PCI_CFG_RD_CMD_ARG 2  #define LPFC_PCI_CFG_WR_CMD_ARG 3  #define LPFC_PCI_CFG_SIZE 4096 -#define LPFC_PCI_CFG_RD_BUF_SIZE (LPFC_PCI_CFG_SIZE/2)  #define LPFC_PCI_CFG_RD_SIZE (LPFC_PCI_CFG_SIZE/4) +#define IDIAG_PCICFG_WHERE_INDX 0 +#define IDIAG_PCICFG_COUNT_INDX 1 +#define IDIAG_PCICFG_VALUE_INDX 2 + +/* barAcc */ +#define LPFC_PCI_BAR_BROWSE 0xffff +#define LPFC_PCI_BAR_RD_CMD_ARG 3 +#define LPFC_PCI_BAR_WR_CMD_ARG 3 + +#define LPFC_PCI_IF0_BAR0_SIZE (1024 *  16) +#define LPFC_PCI_IF0_BAR1_SIZE (1024 * 128) +#define LPFC_PCI_IF0_BAR2_SIZE (1024 * 128) +#define LPFC_PCI_IF2_BAR0_SIZE (1024 *  32) + +#define LPFC_PCI_BAR_RD_BUF_SIZE 4096 +#define LPFC_PCI_BAR_RD_SIZE (LPFC_PCI_BAR_RD_BUF_SIZE/4) + +#define LPFC_PCI_IF0_BAR0_RD_SIZE (LPFC_PCI_IF0_BAR0_SIZE/4) +#define LPFC_PCI_IF0_BAR1_RD_SIZE (LPFC_PCI_IF0_BAR1_SIZE/4) +#define LPFC_PCI_IF0_BAR2_RD_SIZE (LPFC_PCI_IF0_BAR2_SIZE/4) +#define LPFC_PCI_IF2_BAR0_RD_SIZE (LPFC_PCI_IF2_BAR0_SIZE/4) + +#define IDIAG_BARACC_BAR_NUM_INDX 0 +#define IDIAG_BARACC_OFF_SET_INDX 1 +#define IDIAG_BARACC_ACC_MOD_INDX 2 +#define IDIAG_BARACC_REG_VAL_INDX 2 +#define IDIAG_BARACC_BAR_SZE_INDX 3 + +#define IDIAG_BARACC_BAR_0 0 +#define IDIAG_BARACC_BAR_1 1 +#define IDIAG_BARACC_BAR_2 2 + +#define SINGLE_WORD 1 +  /* queue info */  #define LPFC_QUE_INFO_GET_BUF_SIZE 4096 @@ -63,7 +100,14 @@  #define LPFC_IDIAG_WQ 4  #define LPFC_IDIAG_RQ 5 -/* doorbell acc */ +#define IDIAG_QUEACC_QUETP_INDX 0 +#define IDIAG_QUEACC_QUEID_INDX 1 +#define IDIAG_QUEACC_INDEX_INDX 2 +#define IDIAG_QUEACC_COUNT_INDX 3 +#define IDIAG_QUEACC_OFFST_INDX 4 +#define IDIAG_QUEACC_VALUE_INDX 5 + +/* doorbell register acc */  #define LPFC_DRB_ACC_ALL 0xffff  #define LPFC_DRB_ACC_RD_CMD_ARG 1  #define LPFC_DRB_ACC_WR_CMD_ARG 2 @@ -76,6 +120,67 @@  #define LPFC_DRB_MAX  4 +#define IDIAG_DRBACC_REGID_INDX 0 +#define IDIAG_DRBACC_VALUE_INDX 1 + +/* control register acc */ +#define LPFC_CTL_ACC_ALL 0xffff +#define LPFC_CTL_ACC_RD_CMD_ARG 1 +#define LPFC_CTL_ACC_WR_CMD_ARG 2 +#define LPFC_CTL_ACC_BUF_SIZE 256 + +#define LPFC_CTL_PORT_SEM  1 +#define LPFC_CTL_PORT_STA  2 +#define LPFC_CTL_PORT_CTL  3 +#define LPFC_CTL_PORT_ER1  4 +#define LPFC_CTL_PORT_ER2  5 +#define LPFC_CTL_PDEV_CTL  6 + +#define LPFC_CTL_MAX  6 + +#define IDIAG_CTLACC_REGID_INDX 0 +#define IDIAG_CTLACC_VALUE_INDX 1 + +/* mailbox access */ +#define LPFC_MBX_DMP_ARG 4 + +#define LPFC_MBX_ACC_BUF_SIZE 512 +#define LPFC_MBX_ACC_LBUF_SZ 128 + +#define LPFC_MBX_DMP_MBX_WORD 0x00000001 +#define LPFC_MBX_DMP_MBX_BYTE 0x00000002 +#define LPFC_MBX_DMP_MBX_ALL (LPFC_MBX_DMP_MBX_WORD | LPFC_MBX_DMP_MBX_BYTE) + +#define LPFC_BSG_DMP_MBX_RD_MBX 0x00000001 +#define LPFC_BSG_DMP_MBX_RD_BUF 0x00000002 +#define LPFC_BSG_DMP_MBX_WR_MBX 0x00000004 +#define LPFC_BSG_DMP_MBX_WR_BUF 0x00000008 +#define LPFC_BSG_DMP_MBX_ALL (LPFC_BSG_DMP_MBX_RD_MBX | \ +			      LPFC_BSG_DMP_MBX_RD_BUF | \ +			      LPFC_BSG_DMP_MBX_WR_MBX | \ +			      LPFC_BSG_DMP_MBX_WR_BUF) + +#define LPFC_MBX_DMP_ALL 0xffff +#define LPFC_MBX_ALL_CMD 0xff + +#define IDIAG_MBXACC_MBCMD_INDX 0 +#define IDIAG_MBXACC_DPMAP_INDX 1 +#define IDIAG_MBXACC_DPCNT_INDX 2 +#define IDIAG_MBXACC_WDCNT_INDX 3 + +/* extents access */ +#define LPFC_EXT_ACC_CMD_ARG 1 +#define LPFC_EXT_ACC_BUF_SIZE 4096 + +#define LPFC_EXT_ACC_AVAIL 0x1 +#define LPFC_EXT_ACC_ALLOC 0x2 +#define LPFC_EXT_ACC_DRIVR 0x4 +#define LPFC_EXT_ACC_ALL   (LPFC_EXT_ACC_DRIVR | \ +			    LPFC_EXT_ACC_AVAIL | \ +			    LPFC_EXT_ACC_ALLOC) + +#define IDIAG_EXTACC_EXMAP_INDX 0 +  #define SIZE_U8  sizeof(uint8_t)  #define SIZE_U16 sizeof(uint16_t)  #define SIZE_U32 sizeof(uint32_t) @@ -110,6 +215,11 @@ struct lpfc_idiag_cmd {  #define LPFC_IDIAG_CMD_PCICFG_ST 0x00000003  #define LPFC_IDIAG_CMD_PCICFG_CL 0x00000004 +#define LPFC_IDIAG_CMD_BARACC_RD 0x00000008 +#define LPFC_IDIAG_CMD_BARACC_WR 0x00000009 +#define LPFC_IDIAG_CMD_BARACC_ST 0x0000000a +#define LPFC_IDIAG_CMD_BARACC_CL 0x0000000b +  #define LPFC_IDIAG_CMD_QUEACC_RD 0x00000011  #define LPFC_IDIAG_CMD_QUEACC_WR 0x00000012  #define LPFC_IDIAG_CMD_QUEACC_ST 0x00000013 @@ -119,6 +229,17 @@ struct lpfc_idiag_cmd {  #define LPFC_IDIAG_CMD_DRBACC_WR 0x00000022  #define LPFC_IDIAG_CMD_DRBACC_ST 0x00000023  #define LPFC_IDIAG_CMD_DRBACC_CL 0x00000024 + +#define LPFC_IDIAG_CMD_CTLACC_RD 0x00000031 +#define LPFC_IDIAG_CMD_CTLACC_WR 0x00000032 +#define LPFC_IDIAG_CMD_CTLACC_ST 0x00000033 +#define LPFC_IDIAG_CMD_CTLACC_CL 0x00000034 + +#define LPFC_IDIAG_CMD_MBXACC_DP 0x00000041 +#define LPFC_IDIAG_BSG_MBXACC_DP 0x00000042 + +#define LPFC_IDIAG_CMD_EXTACC_RD 0x00000051 +  	uint32_t data[LPFC_IDIAG_CMD_DATA_SIZE];  }; diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index 32a084534f3e..023da0e00d38 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -647,21 +647,15 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,  		}  		lpfc_cleanup_pending_mbox(vport); -		if (phba->sli_rev == LPFC_SLI_REV4) +		if (phba->sli_rev == LPFC_SLI_REV4) {  			lpfc_sli4_unreg_all_rpis(vport); - -		if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) {  			lpfc_mbx_unreg_vpi(vport);  			spin_lock_irq(shost->host_lock);  			vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI; -			spin_unlock_irq(shost->host_lock); -		} -		/* -		 * If VPI is unreged, driver need to do INIT_VPI -		 * before re-registering -		 */ -		if (phba->sli_rev == LPFC_SLI_REV4) { -			spin_lock_irq(shost->host_lock); +			/* +			* If VPI is unreged, driver need to do INIT_VPI +			* before re-registering +			*/  			vport->fc_flag |= FC_VPORT_NEEDS_INIT_VPI;  			spin_unlock_irq(shost->host_lock);  		} @@ -880,6 +874,8 @@ lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,  					phba->fcf.current_rec.fcf_indx,  					irsp->ulpStatus, irsp->un.ulpWord[4],  					irsp->ulpTimeout); +			lpfc_sli4_set_fcf_flogi_fail(phba, +					phba->fcf.current_rec.fcf_indx);  			fcf_index = lpfc_sli4_fcf_rr_next_index_get(phba);  			rc = lpfc_sli4_fcf_rr_next_proc(vport, fcf_index);  			if (rc) @@ -1096,11 +1092,14 @@ lpfc_issue_els_flogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,  			/* Set the fcfi to the fcfi we registered with */  			elsiocb->iocb.ulpContext = phba->fcf.fcfi;  		} -	} else if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) { -		sp->cmn.request_multiple_Nport = 1; -		/* For FLOGI, Let FLOGI rsp set the NPortID for VPI 0 */ -		icmd->ulpCt_h = 1; -		icmd->ulpCt_l = 0; +	} else { +		if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) { +			sp->cmn.request_multiple_Nport = 1; +			/* For FLOGI, Let FLOGI rsp set the NPortID for VPI 0 */ +			icmd->ulpCt_h = 1; +			icmd->ulpCt_l = 0; +		} else +			sp->cmn.request_multiple_Nport = 0;  	}  	if (phba->fc_topology != LPFC_TOPOLOGY_LOOP) { @@ -3656,7 +3655,8 @@ lpfc_els_rsp_acc(struct lpfc_vport *vport, uint32_t flag,  		}  		icmd = &elsiocb->iocb; -		icmd->ulpContext = oldcmd->ulpContext;	/* Xri */ +		icmd->ulpContext = oldcmd->ulpContext;	/* Xri / rx_id */ +		icmd->unsli3.rcvsli3.ox_id = oldcmd->unsli3.rcvsli3.ox_id;  		pcmd = (((struct lpfc_dmabuf *) elsiocb->context2)->virt);  		*((uint32_t *) (pcmd)) = ELS_CMD_ACC;  		pcmd += sizeof(uint32_t); @@ -3673,7 +3673,8 @@ lpfc_els_rsp_acc(struct lpfc_vport *vport, uint32_t flag,  			return 1;  		icmd = &elsiocb->iocb; -		icmd->ulpContext = oldcmd->ulpContext;	/* Xri */ +		icmd->ulpContext = oldcmd->ulpContext;	/* Xri / rx_id */ +		icmd->unsli3.rcvsli3.ox_id = oldcmd->unsli3.rcvsli3.ox_id;  		pcmd = (((struct lpfc_dmabuf *) elsiocb->context2)->virt);  		if (mbox) @@ -3695,7 +3696,8 @@ lpfc_els_rsp_acc(struct lpfc_vport *vport, uint32_t flag,  			return 1;  		icmd = &elsiocb->iocb; -		icmd->ulpContext = oldcmd->ulpContext; /* Xri */ +		icmd->ulpContext = oldcmd->ulpContext;	/* Xri / rx_id */ +		icmd->unsli3.rcvsli3.ox_id = oldcmd->unsli3.rcvsli3.ox_id;  		pcmd = (((struct lpfc_dmabuf *) elsiocb->context2)->virt);  		memcpy(pcmd, ((struct lpfc_dmabuf *) oldiocb->context2)->virt, @@ -3781,7 +3783,8 @@ lpfc_els_rsp_reject(struct lpfc_vport *vport, uint32_t rejectError,  	icmd = &elsiocb->iocb;  	oldcmd = &oldiocb->iocb; -	icmd->ulpContext = oldcmd->ulpContext;	/* Xri */ +	icmd->ulpContext = oldcmd->ulpContext;	/* Xri / rx_id */ +	icmd->unsli3.rcvsli3.ox_id = oldcmd->unsli3.rcvsli3.ox_id;  	pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);  	*((uint32_t *) (pcmd)) = ELS_CMD_LS_RJT; @@ -3853,7 +3856,8 @@ lpfc_els_rsp_adisc_acc(struct lpfc_vport *vport, struct lpfc_iocbq *oldiocb,  	icmd = &elsiocb->iocb;  	oldcmd = &oldiocb->iocb; -	icmd->ulpContext = oldcmd->ulpContext;	/* Xri */ +	icmd->ulpContext = oldcmd->ulpContext;	/* Xri / rx_id */ +	icmd->unsli3.rcvsli3.ox_id = oldcmd->unsli3.rcvsli3.ox_id;  	/* Xmit ADISC ACC response tag <ulpIoTag> */  	lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, @@ -3931,7 +3935,9 @@ lpfc_els_rsp_prli_acc(struct lpfc_vport *vport, struct lpfc_iocbq *oldiocb,  	icmd = &elsiocb->iocb;  	oldcmd = &oldiocb->iocb; -	icmd->ulpContext = oldcmd->ulpContext;	/* Xri */ +	icmd->ulpContext = oldcmd->ulpContext;	/* Xri / rx_id */ +	icmd->unsli3.rcvsli3.ox_id = oldcmd->unsli3.rcvsli3.ox_id; +  	/* Xmit PRLI ACC response tag <ulpIoTag> */  	lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,  			 "0131 Xmit PRLI ACC response tag x%x xri x%x, " @@ -4035,7 +4041,9 @@ lpfc_els_rsp_rnid_acc(struct lpfc_vport *vport, uint8_t format,  	icmd = &elsiocb->iocb;  	oldcmd = &oldiocb->iocb; -	icmd->ulpContext = oldcmd->ulpContext;	/* Xri */ +	icmd->ulpContext = oldcmd->ulpContext;	/* Xri / rx_id */ +	icmd->unsli3.rcvsli3.ox_id = oldcmd->unsli3.rcvsli3.ox_id; +  	/* Xmit RNID ACC response tag <ulpIoTag> */  	lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,  			 "0132 Xmit RNID ACC response tag x%x xri x%x\n", @@ -4163,7 +4171,9 @@ lpfc_els_rsp_echo_acc(struct lpfc_vport *vport, uint8_t *data,  	if (!elsiocb)  		return 1; -	elsiocb->iocb.ulpContext = oldiocb->iocb.ulpContext;	/* Xri */ +	elsiocb->iocb.ulpContext = oldiocb->iocb.ulpContext;  /* Xri / rx_id */ +	elsiocb->iocb.unsli3.rcvsli3.ox_id = oldiocb->iocb.unsli3.rcvsli3.ox_id; +  	/* Xmit ECHO ACC response tag <ulpIoTag> */  	lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,  			 "2876 Xmit ECHO ACC response tag x%x xri x%x\n", @@ -5054,13 +5064,15 @@ lpfc_els_rsp_rls_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)  	uint8_t *pcmd;  	struct lpfc_iocbq *elsiocb;  	struct lpfc_nodelist *ndlp; -	uint16_t xri; +	uint16_t oxid; +	uint16_t rxid;  	uint32_t cmdsize;  	mb = &pmb->u.mb;  	ndlp = (struct lpfc_nodelist *) pmb->context2; -	xri = (uint16_t) ((unsigned long)(pmb->context1)); +	rxid = (uint16_t) ((unsigned long)(pmb->context1) & 0xffff); +	oxid = (uint16_t) (((unsigned long)(pmb->context1) >> 16) & 0xffff);  	pmb->context1 = NULL;  	pmb->context2 = NULL; @@ -5082,7 +5094,8 @@ lpfc_els_rsp_rls_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)  		return;  	icmd = &elsiocb->iocb; -	icmd->ulpContext = xri; +	icmd->ulpContext = rxid; +	icmd->unsli3.rcvsli3.ox_id = oxid;  	pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);  	*((uint32_t *) (pcmd)) = ELS_CMD_ACC; @@ -5137,13 +5150,16 @@ lpfc_els_rsp_rps_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)  	uint8_t *pcmd;  	struct lpfc_iocbq *elsiocb;  	struct lpfc_nodelist *ndlp; -	uint16_t xri, status; +	uint16_t status; +	uint16_t oxid; +	uint16_t rxid;  	uint32_t cmdsize;  	mb = &pmb->u.mb;  	ndlp = (struct lpfc_nodelist *) pmb->context2; -	xri = (uint16_t) ((unsigned long)(pmb->context1)); +	rxid = (uint16_t) ((unsigned long)(pmb->context1) & 0xffff); +	oxid = (uint16_t) (((unsigned long)(pmb->context1) >> 16) & 0xffff);  	pmb->context1 = NULL;  	pmb->context2 = NULL; @@ -5165,7 +5181,8 @@ lpfc_els_rsp_rps_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)  		return;  	icmd = &elsiocb->iocb; -	icmd->ulpContext = xri; +	icmd->ulpContext = rxid; +	icmd->unsli3.rcvsli3.ox_id = oxid;  	pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);  	*((uint32_t *) (pcmd)) = ELS_CMD_ACC; @@ -5238,8 +5255,9 @@ lpfc_els_rcv_rls(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,  	mbox = mempool_alloc(phba->mbox_mem_pool, GFP_ATOMIC);  	if (mbox) {  		lpfc_read_lnk_stat(phba, mbox); -		mbox->context1 = -		    (void *)((unsigned long) cmdiocb->iocb.ulpContext); +		mbox->context1 = (void *)((unsigned long) +			((cmdiocb->iocb.unsli3.rcvsli3.ox_id << 16) | +			cmdiocb->iocb.ulpContext)); /* rx_id */  		mbox->context2 = lpfc_nlp_get(ndlp);  		mbox->vport = vport;  		mbox->mbox_cmpl = lpfc_els_rsp_rls_acc; @@ -5314,7 +5332,8 @@ lpfc_els_rcv_rtv(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,  	pcmd += sizeof(uint32_t); /* Skip past command */  	/* use the command's xri in the response */ -	elsiocb->iocb.ulpContext = cmdiocb->iocb.ulpContext; +	elsiocb->iocb.ulpContext = cmdiocb->iocb.ulpContext;  /* Xri / rx_id */ +	elsiocb->iocb.unsli3.rcvsli3.ox_id = cmdiocb->iocb.unsli3.rcvsli3.ox_id;  	rtv_rsp = (struct RTV_RSP *)pcmd; @@ -5399,8 +5418,9 @@ lpfc_els_rcv_rps(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,  		mbox = mempool_alloc(phba->mbox_mem_pool, GFP_ATOMIC);  		if (mbox) {  			lpfc_read_lnk_stat(phba, mbox); -			mbox->context1 = -			    (void *)((unsigned long) cmdiocb->iocb.ulpContext); +			mbox->context1 = (void *)((unsigned long) +				((cmdiocb->iocb.unsli3.rcvsli3.ox_id << 16) | +				cmdiocb->iocb.ulpContext)); /* rx_id */  			mbox->context2 = lpfc_nlp_get(ndlp);  			mbox->vport = vport;  			mbox->mbox_cmpl = lpfc_els_rsp_rps_acc; @@ -5554,7 +5574,8 @@ lpfc_els_rsp_rpl_acc(struct lpfc_vport *vport, uint16_t cmdsize,  	icmd = &elsiocb->iocb;  	oldcmd = &oldiocb->iocb; -	icmd->ulpContext = oldcmd->ulpContext;	/* Xri */ +	icmd->ulpContext = oldcmd->ulpContext;	/* Xri / rx_id */ +	icmd->unsli3.rcvsli3.ox_id = oldcmd->unsli3.rcvsli3.ox_id;  	pcmd = (((struct lpfc_dmabuf *) elsiocb->context2)->virt);  	*((uint32_t *) (pcmd)) = ELS_CMD_ACC; @@ -6586,7 +6607,7 @@ lpfc_find_vport_by_vpid(struct lpfc_hba *phba, uint16_t vpi)  {  	struct lpfc_vport *vport;  	unsigned long flags; -	int i; +	int i = 0;  	/* The physical ports are always vpi 0 - translate is unnecessary. */  	if (vpi > 0) { @@ -6609,7 +6630,7 @@ lpfc_find_vport_by_vpid(struct lpfc_hba *phba, uint16_t vpi)  	spin_lock_irqsave(&phba->hbalock, flags);  	list_for_each_entry(vport, &phba->port_list, listentry) { -		if (vport->vpi == vpi) { +		if (vport->vpi == i) {  			spin_unlock_irqrestore(&phba->hbalock, flags);  			return vport;  		} @@ -7787,6 +7808,7 @@ lpfc_sli4_els_xri_aborted(struct lpfc_hba *phba,  {  	uint16_t xri = bf_get(lpfc_wcqe_xa_xri, axri);  	uint16_t rxid = bf_get(lpfc_wcqe_xa_remote_xid, axri); +	uint16_t lxri = 0;  	struct lpfc_sglq *sglq_entry = NULL, *sglq_next = NULL;  	unsigned long iflag = 0; @@ -7815,7 +7837,12 @@ lpfc_sli4_els_xri_aborted(struct lpfc_hba *phba,  		}  	}  	spin_unlock(&phba->sli4_hba.abts_sgl_list_lock); -	sglq_entry = __lpfc_get_active_sglq(phba, xri); +	lxri = lpfc_sli4_xri_inrange(phba, xri); +	if (lxri == NO_XRI) { +		spin_unlock_irqrestore(&phba->hbalock, iflag); +		return; +	} +	sglq_entry = __lpfc_get_active_sglq(phba, lxri);  	if (!sglq_entry || (sglq_entry->sli4_xritag != xri)) {  		spin_unlock_irqrestore(&phba->hbalock, iflag);  		return; diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index 18d0dbfda2bc..0b47adf9fee8 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -1109,6 +1109,28 @@ out:  	return;  } +/** + * lpfc_sli4_clear_fcf_rr_bmask + * @phba pointer to the struct lpfc_hba for this port. + * This fucnction resets the round robin bit mask and clears the + * fcf priority list. The list deletions are done while holding the + * hbalock. The ON_LIST flag and the FLOGI_FAILED flags are cleared + * from the lpfc_fcf_pri record. + **/ +void +lpfc_sli4_clear_fcf_rr_bmask(struct lpfc_hba *phba) +{ +	struct lpfc_fcf_pri *fcf_pri; +	struct lpfc_fcf_pri *next_fcf_pri; +	memset(phba->fcf.fcf_rr_bmask, 0, sizeof(*phba->fcf.fcf_rr_bmask)); +	spin_lock_irq(&phba->hbalock); +	list_for_each_entry_safe(fcf_pri, next_fcf_pri, +				&phba->fcf.fcf_pri_list, list) { +		list_del_init(&fcf_pri->list); +		fcf_pri->fcf_rec.flag = 0; +	} +	spin_unlock_irq(&phba->hbalock); +}  static void  lpfc_mbx_cmpl_reg_fcfi(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)  { @@ -1130,7 +1152,8 @@ lpfc_mbx_cmpl_reg_fcfi(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)  	spin_unlock_irq(&phba->hbalock);  	/* If there is a pending FCoE event, restart FCF table scan. */ -	if (lpfc_check_pending_fcoe_event(phba, LPFC_UNREG_FCF)) +	if ((!(phba->hba_flag & FCF_RR_INPROG)) && +		lpfc_check_pending_fcoe_event(phba, LPFC_UNREG_FCF))  		goto fail_out;  	/* Mark successful completion of FCF table scan */ @@ -1250,6 +1273,30 @@ lpfc_vlan_id_match(uint16_t curr_vlan_id, uint16_t new_vlan_id)  }  /** + * lpfc_update_fcf_record - Update driver fcf record + * __lpfc_update_fcf_record_pri - update the lpfc_fcf_pri record. + * @phba: pointer to lpfc hba data structure. + * @fcf_index: Index for the lpfc_fcf_record. + * @new_fcf_record: pointer to hba fcf record. + * + * This routine updates the driver FCF priority record from the new HBA FCF + * record. This routine is called with the host lock held. + **/ +static void +__lpfc_update_fcf_record_pri(struct lpfc_hba *phba, uint16_t fcf_index, +				 struct fcf_record *new_fcf_record +				 ) +{ +	struct lpfc_fcf_pri *fcf_pri; + +	fcf_pri = &phba->fcf.fcf_pri[fcf_index]; +	fcf_pri->fcf_rec.fcf_index = fcf_index; +	/* FCF record priority */ +	fcf_pri->fcf_rec.priority = new_fcf_record->fip_priority; + +} + +/**   * lpfc_copy_fcf_record - Copy fcf information to lpfc_hba.   * @fcf: pointer to driver fcf record.   * @new_fcf_record: pointer to fcf record. @@ -1332,6 +1379,9 @@ __lpfc_update_fcf_record(struct lpfc_hba *phba, struct lpfc_fcf_rec *fcf_rec,  	fcf_rec->addr_mode = addr_mode;  	fcf_rec->vlan_id = vlan_id;  	fcf_rec->flag |= (flag | RECORD_VALID); +	__lpfc_update_fcf_record_pri(phba, +		bf_get(lpfc_fcf_record_fcf_index, new_fcf_record), +				 new_fcf_record);  }  /** @@ -1834,6 +1884,8 @@ lpfc_sli4_fcf_record_match(struct lpfc_hba *phba,  		return false;  	if (!lpfc_fab_name_match(fcf_rec->fabric_name, new_fcf_record))  		return false; +	if (fcf_rec->priority != new_fcf_record->fip_priority) +		return false;  	return true;  } @@ -1897,6 +1949,152 @@ stop_flogi_current_fcf:  }  /** + * lpfc_sli4_fcf_pri_list_del + * @phba: pointer to lpfc hba data structure. + * @fcf_index the index of the fcf record to delete + * This routine checks the on list flag of the fcf_index to be deleted. + * If it is one the list then it is removed from the list, and the flag + * is cleared. This routine grab the hbalock before removing the fcf + * record from the list. + **/ +static void lpfc_sli4_fcf_pri_list_del(struct lpfc_hba *phba, +			uint16_t fcf_index) +{ +	struct lpfc_fcf_pri *new_fcf_pri; + +	new_fcf_pri = &phba->fcf.fcf_pri[fcf_index]; +	lpfc_printf_log(phba, KERN_INFO, LOG_FIP, +		"3058 deleting idx x%x pri x%x flg x%x\n", +		fcf_index, new_fcf_pri->fcf_rec.priority, +		 new_fcf_pri->fcf_rec.flag); +	spin_lock_irq(&phba->hbalock); +	if (new_fcf_pri->fcf_rec.flag & LPFC_FCF_ON_PRI_LIST) { +		if (phba->fcf.current_rec.priority == +				new_fcf_pri->fcf_rec.priority) +			phba->fcf.eligible_fcf_cnt--; +		list_del_init(&new_fcf_pri->list); +		new_fcf_pri->fcf_rec.flag &= ~LPFC_FCF_ON_PRI_LIST; +	} +	spin_unlock_irq(&phba->hbalock); +} + +/** + * lpfc_sli4_set_fcf_flogi_fail + * @phba: pointer to lpfc hba data structure. + * @fcf_index the index of the fcf record to update + * This routine acquires the hbalock and then set the LPFC_FCF_FLOGI_FAILED + * flag so the the round robin slection for the particular priority level + * will try a different fcf record that does not have this bit set. + * If the fcf record is re-read for any reason this flag is cleared brfore + * adding it to the priority list. + **/ +void +lpfc_sli4_set_fcf_flogi_fail(struct lpfc_hba *phba, uint16_t fcf_index) +{ +	struct lpfc_fcf_pri *new_fcf_pri; +	new_fcf_pri = &phba->fcf.fcf_pri[fcf_index]; +	spin_lock_irq(&phba->hbalock); +	new_fcf_pri->fcf_rec.flag |= LPFC_FCF_FLOGI_FAILED; +	spin_unlock_irq(&phba->hbalock); +} + +/** + * lpfc_sli4_fcf_pri_list_add + * @phba: pointer to lpfc hba data structure. + * @fcf_index the index of the fcf record to add + * This routine checks the priority of the fcf_index to be added. + * If it is a lower priority than the current head of the fcf_pri list + * then it is added to the list in the right order. + * If it is the same priority as the current head of the list then it + * is added to the head of the list and its bit in the rr_bmask is set. + * If the fcf_index to be added is of a higher priority than the current + * head of the list then the rr_bmask is cleared, its bit is set in the + * rr_bmask and it is added to the head of the list. + * returns: + * 0=success 1=failure + **/ +int lpfc_sli4_fcf_pri_list_add(struct lpfc_hba *phba, uint16_t fcf_index, +	struct fcf_record *new_fcf_record) +{ +	uint16_t current_fcf_pri; +	uint16_t last_index; +	struct lpfc_fcf_pri *fcf_pri; +	struct lpfc_fcf_pri *next_fcf_pri; +	struct lpfc_fcf_pri *new_fcf_pri; +	int ret; + +	new_fcf_pri = &phba->fcf.fcf_pri[fcf_index]; +	lpfc_printf_log(phba, KERN_INFO, LOG_FIP, +		"3059 adding idx x%x pri x%x flg x%x\n", +		fcf_index, new_fcf_record->fip_priority, +		 new_fcf_pri->fcf_rec.flag); +	spin_lock_irq(&phba->hbalock); +	if (new_fcf_pri->fcf_rec.flag & LPFC_FCF_ON_PRI_LIST) +		list_del_init(&new_fcf_pri->list); +	new_fcf_pri->fcf_rec.fcf_index = fcf_index; +	new_fcf_pri->fcf_rec.priority = new_fcf_record->fip_priority; +	if (list_empty(&phba->fcf.fcf_pri_list)) { +		list_add(&new_fcf_pri->list, &phba->fcf.fcf_pri_list); +		ret = lpfc_sli4_fcf_rr_index_set(phba, +				new_fcf_pri->fcf_rec.fcf_index); +		goto out; +	} + +	last_index = find_first_bit(phba->fcf.fcf_rr_bmask, +				LPFC_SLI4_FCF_TBL_INDX_MAX); +	if (last_index >= LPFC_SLI4_FCF_TBL_INDX_MAX) { +		ret = 0; /* Empty rr list */ +		goto out; +	} +	current_fcf_pri = phba->fcf.fcf_pri[last_index].fcf_rec.priority; +	if (new_fcf_pri->fcf_rec.priority <=  current_fcf_pri) { +		list_add(&new_fcf_pri->list, &phba->fcf.fcf_pri_list); +		if (new_fcf_pri->fcf_rec.priority <  current_fcf_pri) { +			memset(phba->fcf.fcf_rr_bmask, 0, +				sizeof(*phba->fcf.fcf_rr_bmask)); +			/* fcfs_at_this_priority_level = 1; */ +			phba->fcf.eligible_fcf_cnt = 1; +		} else +			/* fcfs_at_this_priority_level++; */ +			phba->fcf.eligible_fcf_cnt++; +		ret = lpfc_sli4_fcf_rr_index_set(phba, +				new_fcf_pri->fcf_rec.fcf_index); +		goto out; +	} + +	list_for_each_entry_safe(fcf_pri, next_fcf_pri, +				&phba->fcf.fcf_pri_list, list) { +		if (new_fcf_pri->fcf_rec.priority <= +				fcf_pri->fcf_rec.priority) { +			if (fcf_pri->list.prev == &phba->fcf.fcf_pri_list) +				list_add(&new_fcf_pri->list, +						&phba->fcf.fcf_pri_list); +			else +				list_add(&new_fcf_pri->list, +					 &((struct lpfc_fcf_pri *) +					fcf_pri->list.prev)->list); +			ret = 0; +			goto out; +		} else if (fcf_pri->list.next == &phba->fcf.fcf_pri_list +			|| new_fcf_pri->fcf_rec.priority < +				next_fcf_pri->fcf_rec.priority) { +			list_add(&new_fcf_pri->list, &fcf_pri->list); +			ret = 0; +			goto out; +		} +		if (new_fcf_pri->fcf_rec.priority > fcf_pri->fcf_rec.priority) +			continue; + +	} +	ret = 1; +out: +	/* we use = instead of |= to clear the FLOGI_FAILED flag. */ +	new_fcf_pri->fcf_rec.flag = LPFC_FCF_ON_PRI_LIST; +	spin_unlock_irq(&phba->hbalock); +	return ret; +} + +/**   * lpfc_mbx_cmpl_fcf_scan_read_fcf_rec - fcf scan read_fcf mbox cmpl handler.   * @phba: pointer to lpfc hba data structure.   * @mboxq: pointer to mailbox object. @@ -1958,6 +2156,9 @@ lpfc_mbx_cmpl_fcf_scan_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)  	 * record for roundrobin FCF failover.  	 */  	if (!rc) { +		lpfc_sli4_fcf_pri_list_del(phba, +					bf_get(lpfc_fcf_record_fcf_index, +					       new_fcf_record));  		lpfc_printf_log(phba, KERN_WARNING, LOG_FIP,  				"2781 FCF (x%x) failed connection "  				"list check: (x%x/x%x)\n", @@ -2005,7 +2206,8 @@ lpfc_mbx_cmpl_fcf_scan_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)  		goto read_next_fcf;  	} else {  		fcf_index = bf_get(lpfc_fcf_record_fcf_index, new_fcf_record); -		rc = lpfc_sli4_fcf_rr_index_set(phba, fcf_index); +		rc = lpfc_sli4_fcf_pri_list_add(phba, fcf_index, +							new_fcf_record);  		if (rc)  			goto read_next_fcf;  	} @@ -2018,7 +2220,8 @@ lpfc_mbx_cmpl_fcf_scan_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)  	 */  	spin_lock_irq(&phba->hbalock);  	if (phba->fcf.fcf_flag & FCF_IN_USE) { -		if (lpfc_sli4_fcf_record_match(phba, &phba->fcf.current_rec, +		if (phba->cfg_fcf_failover_policy == LPFC_FCF_FOV && +			lpfc_sli4_fcf_record_match(phba, &phba->fcf.current_rec,  		    new_fcf_record, vlan_id)) {  			if (bf_get(lpfc_fcf_record_fcf_index, new_fcf_record) ==  			    phba->fcf.current_rec.fcf_indx) { @@ -2232,7 +2435,8 @@ read_next_fcf:  			    (phba->fcf.fcf_flag & FCF_REDISC_PEND))  				return; -			if (phba->fcf.fcf_flag & FCF_IN_USE) { +			if (phba->cfg_fcf_failover_policy == LPFC_FCF_FOV && +				phba->fcf.fcf_flag & FCF_IN_USE) {  				/*  				 * In case the current in-use FCF record no  				 * longer existed during FCF discovery that @@ -2247,7 +2451,6 @@ read_next_fcf:  				spin_lock_irq(&phba->hbalock);  				phba->fcf.fcf_flag |= FCF_REDISC_FOV;  				spin_unlock_irq(&phba->hbalock); -				lpfc_sli4_mbox_cmd_free(phba, mboxq);  				lpfc_sli4_fcf_scan_read_fcf_rec(phba,  						LPFC_FCOE_FCF_GET_FIRST);  				return; @@ -2424,7 +2627,8 @@ lpfc_mbx_cmpl_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)  	/* Update the eligible FCF record index bmask */  	fcf_index = bf_get(lpfc_fcf_record_fcf_index, new_fcf_record); -	rc = lpfc_sli4_fcf_rr_index_set(phba, fcf_index); + +	rc = lpfc_sli4_fcf_pri_list_add(phba, fcf_index, new_fcf_record);  out:  	lpfc_sli4_mbox_cmd_free(phba, mboxq); @@ -2645,6 +2849,7 @@ lpfc_mbx_cmpl_reg_vfi(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)  	vport->vpi_state |= LPFC_VPI_REGISTERED;  	vport->fc_flag |= FC_VFI_REGISTERED;  	vport->fc_flag &= ~FC_VPORT_NEEDS_REG_VPI; +	vport->fc_flag &= ~FC_VPORT_NEEDS_INIT_VPI;  	spin_unlock_irq(shost->host_lock);  	if (vport->port_state == LPFC_FABRIC_CFG_LINK) { @@ -2893,8 +3098,7 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, struct lpfc_mbx_read_top *la)  			goto out;  		}  		/* Reset FCF roundrobin bmask for new discovery */ -		memset(phba->fcf.fcf_rr_bmask, 0, -		       sizeof(*phba->fcf.fcf_rr_bmask)); +		lpfc_sli4_clear_fcf_rr_bmask(phba);  	}  	return; @@ -5592,7 +5796,7 @@ lpfc_unregister_fcf_rescan(struct lpfc_hba *phba)  	spin_unlock_irq(&phba->hbalock);  	/* Reset FCF roundrobin bmask for new discovery */ -	memset(phba->fcf.fcf_rr_bmask, 0, sizeof(*phba->fcf.fcf_rr_bmask)); +	lpfc_sli4_clear_fcf_rr_bmask(phba);  	rc = lpfc_sli4_fcf_scan_read_fcf_rec(phba, LPFC_FCOE_FCF_GET_FIRST); diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h index 9059524cf225..046edc4ab35f 100644 --- a/drivers/scsi/lpfc/lpfc_hw.h +++ b/drivers/scsi/lpfc/lpfc_hw.h @@ -2955,18 +2955,18 @@ typedef struct _SLI2_RDSC {  typedef struct _PCB {  #ifdef __BIG_ENDIAN_BITFIELD  	uint32_t type:8; -#define TYPE_NATIVE_SLI2       0x01; +#define TYPE_NATIVE_SLI2       0x01  	uint32_t feature:8; -#define FEATURE_INITIAL_SLI2   0x01; +#define FEATURE_INITIAL_SLI2   0x01  	uint32_t rsvd:12;  	uint32_t maxRing:4;  #else	/*  __LITTLE_ENDIAN_BITFIELD */  	uint32_t maxRing:4;  	uint32_t rsvd:12;  	uint32_t feature:8; -#define FEATURE_INITIAL_SLI2   0x01; +#define FEATURE_INITIAL_SLI2   0x01  	uint32_t type:8; -#define TYPE_NATIVE_SLI2       0x01; +#define TYPE_NATIVE_SLI2       0x01  #endif  	uint32_t mailBoxSize; @@ -3470,11 +3470,16 @@ typedef struct {     or CMD_IOCB_RCV_SEQ64_CX (0xB5) */  struct rcv_sli3 { -	uint32_t word8Rsvd;  #ifdef __BIG_ENDIAN_BITFIELD +	uint16_t ox_id; +	uint16_t seq_cnt; +  	uint16_t vpi;  	uint16_t word9Rsvd;  #else  /*  __LITTLE_ENDIAN */ +	uint16_t seq_cnt; +	uint16_t ox_id; +  	uint16_t word9Rsvd;  	uint16_t vpi;  #endif diff --git a/drivers/scsi/lpfc/lpfc_hw4.h b/drivers/scsi/lpfc/lpfc_hw4.h index 11e26a26b5d1..7f8003b5181e 100644 --- a/drivers/scsi/lpfc/lpfc_hw4.h +++ b/drivers/scsi/lpfc/lpfc_hw4.h @@ -170,15 +170,8 @@ struct lpfc_sli_intf {  #define LPFC_PCI_FUNC3		3  #define LPFC_PCI_FUNC4		4 -/* SLI4 interface type-2 control register offsets */ -#define LPFC_CTL_PORT_SEM_OFFSET	0x400 -#define LPFC_CTL_PORT_STA_OFFSET	0x404 -#define LPFC_CTL_PORT_CTL_OFFSET	0x408 -#define LPFC_CTL_PORT_ER1_OFFSET	0x40C -#define LPFC_CTL_PORT_ER2_OFFSET	0x410 +/* SLI4 interface type-2 PDEV_CTL register */  #define LPFC_CTL_PDEV_CTL_OFFSET	0x414 - -/* Some SLI4 interface type-2 PDEV_CTL register bits */  #define LPFC_CTL_PDEV_CTL_DRST		0x00000001  #define LPFC_CTL_PDEV_CTL_FRST		0x00000002  #define LPFC_CTL_PDEV_CTL_DD		0x00000004 @@ -337,6 +330,7 @@ struct lpfc_cqe {  #define CQE_CODE_RELEASE_WQE		0x2  #define CQE_CODE_RECEIVE		0x4  #define CQE_CODE_XRI_ABORTED		0x5 +#define CQE_CODE_RECEIVE_V1		0x9  /* completion queue entry for wqe completions */  struct lpfc_wcqe_complete { @@ -440,7 +434,10 @@ struct lpfc_rcqe {  #define FC_STATUS_RQ_BUF_LEN_EXCEEDED 	0x11 /* payload truncated */  #define FC_STATUS_INSUFF_BUF_NEED_BUF 	0x12 /* Insufficient buffers */  #define FC_STATUS_INSUFF_BUF_FRM_DISC 	0x13 /* Frame Discard */ -	uint32_t reserved1; +	uint32_t word1; +#define lpfc_rcqe_fcf_id_v1_SHIFT	0 +#define lpfc_rcqe_fcf_id_v1_MASK	0x0000003F +#define lpfc_rcqe_fcf_id_v1_WORD	word1  	uint32_t word2;  #define lpfc_rcqe_length_SHIFT		16  #define lpfc_rcqe_length_MASK		0x0000FFFF @@ -451,6 +448,9 @@ struct lpfc_rcqe {  #define lpfc_rcqe_fcf_id_SHIFT		0  #define lpfc_rcqe_fcf_id_MASK		0x0000003F  #define lpfc_rcqe_fcf_id_WORD		word2 +#define lpfc_rcqe_rq_id_v1_SHIFT	0 +#define lpfc_rcqe_rq_id_v1_MASK		0x0000FFFF +#define lpfc_rcqe_rq_id_v1_WORD		word2  	uint32_t word3;  #define lpfc_rcqe_valid_SHIFT		lpfc_cqe_valid_SHIFT  #define lpfc_rcqe_valid_MASK		lpfc_cqe_valid_MASK @@ -515,7 +515,7 @@ struct lpfc_register {  /* The following BAR0 register sets are defined for if_type 0 and 2 UCNAs. */  #define LPFC_SLI_INTF			0x0058 -#define LPFC_SLIPORT_IF2_SMPHR		0x0400 +#define LPFC_CTL_PORT_SEM_OFFSET	0x400  #define lpfc_port_smphr_perr_SHIFT	31  #define lpfc_port_smphr_perr_MASK	0x1  #define lpfc_port_smphr_perr_WORD	word0 @@ -575,7 +575,7 @@ struct lpfc_register {  #define LPFC_POST_STAGE_PORT_READY			0xC000  #define LPFC_POST_STAGE_PORT_UE 			0xF000 -#define LPFC_SLIPORT_STATUS		0x0404 +#define LPFC_CTL_PORT_STA_OFFSET	0x404  #define lpfc_sliport_status_err_SHIFT	31  #define lpfc_sliport_status_err_MASK	0x1  #define lpfc_sliport_status_err_WORD	word0 @@ -593,7 +593,7 @@ struct lpfc_register {  #define lpfc_sliport_status_rdy_WORD	word0  #define MAX_IF_TYPE_2_RESETS	1000 -#define LPFC_SLIPORT_CNTRL		0x0408 +#define LPFC_CTL_PORT_CTL_OFFSET	0x408  #define lpfc_sliport_ctrl_end_SHIFT	30  #define lpfc_sliport_ctrl_end_MASK	0x1  #define lpfc_sliport_ctrl_end_WORD	word0 @@ -604,8 +604,8 @@ struct lpfc_register {  #define lpfc_sliport_ctrl_ip_WORD	word0  #define LPFC_SLIPORT_INIT_PORT	1 -#define LPFC_SLIPORT_ERR_1		0x040C -#define LPFC_SLIPORT_ERR_2		0x0410 +#define LPFC_CTL_PORT_ER1_OFFSET	0x40C +#define LPFC_CTL_PORT_ER2_OFFSET	0x410  /* The following Registers apply to SLI4 if_type 0 UCNAs. They typically   * reside in BAR 2. @@ -3198,6 +3198,8 @@ struct lpfc_grp_hdr {  #define lpfc_grp_hdr_id_MASK		0x000000FF  #define lpfc_grp_hdr_id_WORD		word2  	uint8_t rev_name[128]; +	uint8_t date[12]; +	uint8_t revision[32];  };  #define FCP_COMMAND 0x0 diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 148b98ddbb1d..a3c820083c36 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -2927,6 +2927,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_16Gb) +		fc_host_supported_speeds(shost) |= FC_PORTSPEED_16GBIT;  	if (phba->lmt & LMT_10Gb)  		fc_host_supported_speeds(shost) |= FC_PORTSPEED_10GBIT;  	if (phba->lmt & LMT_8Gb) @@ -3632,8 +3634,7 @@ lpfc_sli4_async_fip_evt(struct lpfc_hba *phba,  			lpfc_sli4_fcf_dead_failthrough(phba);  		} else {  			/* Reset FCF roundrobin bmask for new discovery */ -			memset(phba->fcf.fcf_rr_bmask, 0, -			       sizeof(*phba->fcf.fcf_rr_bmask)); +			lpfc_sli4_clear_fcf_rr_bmask(phba);  			/*  			 * Handling fast FCF failover to a DEAD FCF event is  			 * considered equalivant to receiving CVL to all vports. @@ -3647,7 +3648,7 @@ lpfc_sli4_async_fip_evt(struct lpfc_hba *phba,  			" tag 0x%x\n", acqe_fip->index, acqe_fip->event_tag);  		vport = lpfc_find_vport_by_vpid(phba, -				acqe_fip->index - phba->vpi_base); +						acqe_fip->index);  		ndlp = lpfc_sli4_perform_vport_cvl(vport);  		if (!ndlp)  			break; @@ -3719,8 +3720,7 @@ lpfc_sli4_async_fip_evt(struct lpfc_hba *phba,  				 * Reset FCF roundrobin bmask for new  				 * discovery.  				 */ -				memset(phba->fcf.fcf_rr_bmask, 0, -				       sizeof(*phba->fcf.fcf_rr_bmask)); +				lpfc_sli4_clear_fcf_rr_bmask(phba);  		}  		break;  	default: @@ -4035,6 +4035,34 @@ lpfc_reset_hba(struct lpfc_hba *phba)  }  /** + * lpfc_sli_sriov_nr_virtfn_get - Get the number of sr-iov virtual functions + * @phba: pointer to lpfc hba data structure. + * + * This function enables the PCI SR-IOV virtual functions to a physical + * function. It invokes the PCI SR-IOV api with the @nr_vfn provided to + * enable the number of virtual functions to the physical function. As + * not all devices support SR-IOV, the return code from the pci_enable_sriov() + * API call does not considered as an error condition for most of the device. + **/ +uint16_t +lpfc_sli_sriov_nr_virtfn_get(struct lpfc_hba *phba) +{ +	struct pci_dev *pdev = phba->pcidev; +	uint16_t nr_virtfn; +	int pos; + +	if (!pdev->is_physfn) +		return 0; + +	pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_SRIOV); +	if (pos == 0) +		return 0; + +	pci_read_config_word(pdev, pos + PCI_SRIOV_TOTAL_VF, &nr_virtfn); +	return nr_virtfn; +} + +/**   * lpfc_sli_probe_sriov_nr_virtfn - Enable a number of sr-iov virtual functions   * @phba: pointer to lpfc hba data structure.   * @nr_vfn: number of virtual functions to be enabled. @@ -4049,8 +4077,17 @@ int  lpfc_sli_probe_sriov_nr_virtfn(struct lpfc_hba *phba, int nr_vfn)  {  	struct pci_dev *pdev = phba->pcidev; +	uint16_t max_nr_vfn;  	int rc; +	max_nr_vfn = lpfc_sli_sriov_nr_virtfn_get(phba); +	if (nr_vfn > max_nr_vfn) { +		lpfc_printf_log(phba, KERN_ERR, LOG_INIT, +				"3057 Requested vfs (%d) greater than " +				"supported vfs (%d)", nr_vfn, max_nr_vfn); +		return -EINVAL; +	} +  	rc = pci_enable_sriov(pdev, nr_vfn);  	if (rc) {  		lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, @@ -4516,7 +4553,7 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)  		}  	} -	return rc; +	return 0;  out_free_fcp_eq_hdl:  	kfree(phba->sli4_hba.fcp_eq_hdl); @@ -4966,17 +5003,14 @@ out_free_mem:   * @phba: pointer to lpfc hba data structure.   *   * This routine is invoked to post rpi header templates to the - * HBA consistent with the SLI-4 interface spec.  This routine + * port for those SLI4 ports that do not support extents.  This routine   * posts a PAGE_SIZE memory region to the port to hold up to - * PAGE_SIZE modulo 64 rpi context headers. - * No locks are held here because this is an initialization routine - * called only from probe or lpfc_online when interrupts are not - * enabled and the driver is reinitializing the device. + * PAGE_SIZE modulo 64 rpi context headers.  This is an initialization routine + * and should be called only when interrupts are disabled.   *   * Return codes   * 	0 - successful - * 	-ENOMEM - No available memory - *      -EIO - The mailbox failed to complete successfully. + *	-ERROR - otherwise.   **/  int  lpfc_sli4_init_rpi_hdrs(struct lpfc_hba *phba) @@ -5687,17 +5721,22 @@ lpfc_sli4_bar0_register_memmap(struct lpfc_hba *phba, uint32_t if_type)  		break;  	case LPFC_SLI_INTF_IF_TYPE_2:  		phba->sli4_hba.u.if_type2.ERR1regaddr = -			phba->sli4_hba.conf_regs_memmap_p + LPFC_SLIPORT_ERR_1; +			phba->sli4_hba.conf_regs_memmap_p + +						LPFC_CTL_PORT_ER1_OFFSET;  		phba->sli4_hba.u.if_type2.ERR2regaddr = -			phba->sli4_hba.conf_regs_memmap_p + LPFC_SLIPORT_ERR_2; +			phba->sli4_hba.conf_regs_memmap_p + +						LPFC_CTL_PORT_ER2_OFFSET;  		phba->sli4_hba.u.if_type2.CTRLregaddr = -			phba->sli4_hba.conf_regs_memmap_p + LPFC_SLIPORT_CNTRL; +			phba->sli4_hba.conf_regs_memmap_p + +						LPFC_CTL_PORT_CTL_OFFSET;  		phba->sli4_hba.u.if_type2.STATUSregaddr = -			phba->sli4_hba.conf_regs_memmap_p + LPFC_SLIPORT_STATUS; +			phba->sli4_hba.conf_regs_memmap_p + +						LPFC_CTL_PORT_STA_OFFSET;  		phba->sli4_hba.SLIINTFregaddr =  			phba->sli4_hba.conf_regs_memmap_p + LPFC_SLI_INTF;  		phba->sli4_hba.PSMPHRregaddr = -		     phba->sli4_hba.conf_regs_memmap_p + LPFC_SLIPORT_IF2_SMPHR; +			phba->sli4_hba.conf_regs_memmap_p + +						LPFC_CTL_PORT_SEM_OFFSET;  		phba->sli4_hba.RQDBregaddr =  			phba->sli4_hba.conf_regs_memmap_p + LPFC_RQ_DOORBELL;  		phba->sli4_hba.WQDBregaddr = @@ -8859,11 +8898,11 @@ lpfc_write_firmware(struct lpfc_hba *phba, const struct firmware *fw)  		return -EINVAL;  	}  	lpfc_decode_firmware_rev(phba, fwrev, 1); -	if (strncmp(fwrev, image->rev_name, strnlen(fwrev, 16))) { +	if (strncmp(fwrev, image->revision, strnlen(image->revision, 16))) {  		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,  				"3023 Updating Firmware. Current Version:%s "  				"New Version:%s\n", -				fwrev, image->rev_name); +				fwrev, image->revision);  		for (i = 0; i < LPFC_MBX_WR_CONFIG_MAX_BDE; i++) {  			dmabuf = kzalloc(sizeof(struct lpfc_dmabuf),  					 GFP_KERNEL); @@ -8892,9 +8931,9 @@ lpfc_write_firmware(struct lpfc_hba *phba, const struct firmware *fw)  					       fw->size - offset);  					break;  				} -				temp_offset += SLI4_PAGE_SIZE;  				memcpy(dmabuf->virt, fw->data + temp_offset,  				       SLI4_PAGE_SIZE); +				temp_offset += SLI4_PAGE_SIZE;  			}  			rc = lpfc_wr_object(phba, &dma_buffer_list,  				    (fw->size - offset), &offset); @@ -9005,6 +9044,7 @@ lpfc_pci_probe_one_s4(struct pci_dev *pdev, const struct pci_device_id *pid)  	}  	INIT_LIST_HEAD(&phba->active_rrq_list); +	INIT_LIST_HEAD(&phba->fcf.fcf_pri_list);  	/* Set up common device driver resources */  	error = lpfc_setup_driver_resource_phase2(phba); @@ -9112,7 +9152,6 @@ lpfc_pci_probe_one_s4(struct pci_dev *pdev, const struct pci_device_id *pid)  	/* Check if there are static vports to be created. */  	lpfc_create_static_vport(phba); -  	return 0;  out_disable_intr: @@ -9483,6 +9522,13 @@ lpfc_io_slot_reset_s4(struct pci_dev *pdev)  	}  	pci_restore_state(pdev); + +	/* +	 * As the new kernel behavior of pci_restore_state() API call clears +	 * device saved_state flag, need to save the restored state again. +	 */ +	pci_save_state(pdev); +  	if (pdev->is_busmaster)  		pci_set_master(pdev); diff --git a/drivers/scsi/lpfc/lpfc_mbox.c b/drivers/scsi/lpfc/lpfc_mbox.c index 556767028353..83450cc5c4d3 100644 --- a/drivers/scsi/lpfc/lpfc_mbox.c +++ b/drivers/scsi/lpfc/lpfc_mbox.c @@ -2031,7 +2031,7 @@ lpfc_init_vfi(struct lpfcMboxq *mbox, struct lpfc_vport *vport)  	bf_set(lpfc_init_vfi_vp, init_vfi, 1);  	bf_set(lpfc_init_vfi_vfi, init_vfi,  	       vport->phba->sli4_hba.vfi_ids[vport->vfi]); -	bf_set(lpfc_init_vpi_vpi, init_vfi, +	bf_set(lpfc_init_vfi_vpi, init_vfi,  	       vport->phba->vpi_ids[vport->vpi]);  	bf_set(lpfc_init_vfi_fcfi, init_vfi,  	       vport->phba->fcf.fcfi); diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index 3ccc97496ebf..eadd241eeff1 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -1302,13 +1302,13 @@ lpfc_sc_to_bg_opcodes(struct lpfc_hba *phba, struct scsi_cmnd *sc,  		case SCSI_PROT_NORMAL:  		default:  			lpfc_printf_log(phba, KERN_ERR, LOG_BG, -				"9063 BLKGRD: Bad op/guard:%d/%d combination\n", -					scsi_get_prot_op(sc), guard_type); +				"9063 BLKGRD: Bad op/guard:%d/IP combination\n", +					scsi_get_prot_op(sc));  			ret = 1;  			break;  		} -	} else if (guard_type == SHOST_DIX_GUARD_CRC) { +	} else {  		switch (scsi_get_prot_op(sc)) {  		case SCSI_PROT_READ_STRIP:  		case SCSI_PROT_WRITE_INSERT: @@ -1324,17 +1324,18 @@ lpfc_sc_to_bg_opcodes(struct lpfc_hba *phba, struct scsi_cmnd *sc,  		case SCSI_PROT_READ_INSERT:  		case SCSI_PROT_WRITE_STRIP: +			*txop = BG_OP_IN_CRC_OUT_NODIF; +			*rxop = BG_OP_IN_NODIF_OUT_CRC; +			break; +  		case SCSI_PROT_NORMAL:  		default:  			lpfc_printf_log(phba, KERN_ERR, LOG_BG, -				"9075 BLKGRD: Bad op/guard:%d/%d combination\n", -					scsi_get_prot_op(sc), guard_type); +				"9075 BLKGRD: Bad op/guard:%d/CRC combination\n", +					scsi_get_prot_op(sc));  			ret = 1;  			break;  		} -	} else { -		/* unsupported format */ -		BUG();  	}  	return ret; @@ -1352,45 +1353,6 @@ lpfc_cmd_blksize(struct scsi_cmnd *sc)  	return sc->device->sector_size;  } -/** - * lpfc_get_cmd_dif_parms - Extract DIF parameters from SCSI command - * @sc:             in: SCSI command - * @apptagmask:     out: app tag mask - * @apptagval:      out: app tag value - * @reftag:         out: ref tag (reference tag) - * - * Description: - *   Extract DIF parameters from the command if possible.  Otherwise, - *   use default parameters. - * - **/ -static inline void -lpfc_get_cmd_dif_parms(struct scsi_cmnd *sc, uint16_t *apptagmask, -		uint16_t *apptagval, uint32_t *reftag) -{ -	struct  scsi_dif_tuple *spt; -	unsigned char op = scsi_get_prot_op(sc); -	unsigned int protcnt = scsi_prot_sg_count(sc); -	static int cnt; - -	if (protcnt && (op == SCSI_PROT_WRITE_STRIP || -				op == SCSI_PROT_WRITE_PASS)) { - -		cnt++; -		spt = page_address(sg_page(scsi_prot_sglist(sc))) + -			scsi_prot_sglist(sc)[0].offset; -		*apptagmask = 0; -		*apptagval = 0; -		*reftag = cpu_to_be32(spt->ref_tag); - -	} else { -		/* SBC defines ref tag to be lower 32bits of LBA */ -		*reftag = (uint32_t) (0xffffffff & scsi_get_lba(sc)); -		*apptagmask = 0; -		*apptagval = 0; -	} -} -  /*   * This function sets up buffer list for protection groups of   * type LPFC_PG_TYPE_NO_DIF @@ -1427,9 +1389,8 @@ lpfc_bg_setup_bpl(struct lpfc_hba *phba, struct scsi_cmnd *sc,  	dma_addr_t physaddr;  	int i = 0, num_bde = 0, status;  	int datadir = sc->sc_data_direction; -	unsigned blksize;  	uint32_t reftag; -	uint16_t apptagmask, apptagval; +	unsigned blksize;  	uint8_t txop, rxop;  	status  = lpfc_sc_to_bg_opcodes(phba, sc, &txop, &rxop); @@ -1438,17 +1399,16 @@ lpfc_bg_setup_bpl(struct lpfc_hba *phba, struct scsi_cmnd *sc,  	/* extract some info from the scsi command for pde*/  	blksize = lpfc_cmd_blksize(sc); -	lpfc_get_cmd_dif_parms(sc, &apptagmask, &apptagval, &reftag); +	reftag = scsi_get_lba(sc) & 0xffffffff;  	/* setup PDE5 with what we have */  	pde5 = (struct lpfc_pde5 *) bpl;  	memset(pde5, 0, sizeof(struct lpfc_pde5));  	bf_set(pde5_type, pde5, LPFC_PDE5_DESCRIPTOR); -	pde5->reftag = reftag;  	/* Endianness conversion if necessary for PDE5 */  	pde5->word0 = cpu_to_le32(pde5->word0); -	pde5->reftag = cpu_to_le32(pde5->reftag); +	pde5->reftag = cpu_to_le32(reftag);  	/* advance bpl and increment bde count */  	num_bde++; @@ -1463,10 +1423,10 @@ lpfc_bg_setup_bpl(struct lpfc_hba *phba, struct scsi_cmnd *sc,  	if (datadir == DMA_FROM_DEVICE) {  		bf_set(pde6_ce, pde6, 1);  		bf_set(pde6_re, pde6, 1); -		bf_set(pde6_ae, pde6, 1);  	}  	bf_set(pde6_ai, pde6, 1); -	bf_set(pde6_apptagval, pde6, apptagval); +	bf_set(pde6_ae, pde6, 0); +	bf_set(pde6_apptagval, pde6, 0);  	/* Endianness conversion if necessary for PDE6 */  	pde6->word0 = cpu_to_le32(pde6->word0); @@ -1551,7 +1511,6 @@ lpfc_bg_setup_bpl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc,  	unsigned char pgdone = 0, alldone = 0;  	unsigned blksize;  	uint32_t reftag; -	uint16_t apptagmask, apptagval;  	uint8_t txop, rxop;  	int num_bde = 0; @@ -1571,7 +1530,7 @@ lpfc_bg_setup_bpl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc,  	/* extract some info from the scsi command */  	blksize = lpfc_cmd_blksize(sc); -	lpfc_get_cmd_dif_parms(sc, &apptagmask, &apptagval, &reftag); +	reftag = scsi_get_lba(sc) & 0xffffffff;  	split_offset = 0;  	do { @@ -1579,11 +1538,10 @@ lpfc_bg_setup_bpl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc,  		pde5 = (struct lpfc_pde5 *) bpl;  		memset(pde5, 0, sizeof(struct lpfc_pde5));  		bf_set(pde5_type, pde5, LPFC_PDE5_DESCRIPTOR); -		pde5->reftag = reftag;  		/* Endianness conversion if necessary for PDE5 */  		pde5->word0 = cpu_to_le32(pde5->word0); -		pde5->reftag = cpu_to_le32(pde5->reftag); +		pde5->reftag = cpu_to_le32(reftag);  		/* advance bpl and increment bde count */  		num_bde++; @@ -1597,9 +1555,9 @@ lpfc_bg_setup_bpl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc,  		bf_set(pde6_oprx, pde6, rxop);  		bf_set(pde6_ce, pde6, 1);  		bf_set(pde6_re, pde6, 1); -		bf_set(pde6_ae, pde6, 1);  		bf_set(pde6_ai, pde6, 1); -		bf_set(pde6_apptagval, pde6, apptagval); +		bf_set(pde6_ae, pde6, 0); +		bf_set(pde6_apptagval, pde6, 0);  		/* Endianness conversion if necessary for PDE6 */  		pde6->word0 = cpu_to_le32(pde6->word0); @@ -1621,8 +1579,8 @@ lpfc_bg_setup_bpl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc,  		memset(pde7, 0, sizeof(struct lpfc_pde7));  		bf_set(pde7_type, pde7, LPFC_PDE7_DESCRIPTOR); -		pde7->addrHigh = le32_to_cpu(putPaddrLow(protphysaddr)); -		pde7->addrLow = le32_to_cpu(putPaddrHigh(protphysaddr)); +		pde7->addrHigh = le32_to_cpu(putPaddrHigh(protphysaddr)); +		pde7->addrLow = le32_to_cpu(putPaddrLow(protphysaddr));  		protgrp_blks = protgroup_len / 8;  		protgrp_bytes = protgrp_blks * blksize; @@ -1632,7 +1590,7 @@ lpfc_bg_setup_bpl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc,  			protgroup_remainder = 0x1000 - (pde7->addrLow & 0xfff);  			protgroup_offset += protgroup_remainder;  			protgrp_blks = protgroup_remainder / 8; -			protgrp_bytes = protgroup_remainder * blksize; +			protgrp_bytes = protgrp_blks * blksize;  		} else {  			protgroup_offset = 0;  			curr_prot++; @@ -2006,16 +1964,21 @@ lpfc_parse_bg_err(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd,  	if (lpfc_bgs_get_hi_water_mark_present(bgstat)) {  		/*  		 * setup sense data descriptor 0 per SPC-4 as an information -		 * field, and put the failing LBA in it +		 * field, and put the failing LBA in it. +		 * This code assumes there was also a guard/app/ref tag error +		 * indication.  		 */ -		cmd->sense_buffer[8] = 0;     /* Information */ -		cmd->sense_buffer[9] = 0xa;   /* Add. length */ +		cmd->sense_buffer[7] = 0xc;   /* Additional sense length */ +		cmd->sense_buffer[8] = 0;     /* Information descriptor type */ +		cmd->sense_buffer[9] = 0xa;   /* Additional descriptor length */ +		cmd->sense_buffer[10] = 0x80; /* Validity bit */  		bghm /= cmd->device->sector_size;  		failing_sector = scsi_get_lba(cmd);  		failing_sector += bghm; -		put_unaligned_be64(failing_sector, &cmd->sense_buffer[10]); +		/* Descriptor Information */ +		put_unaligned_be64(failing_sector, &cmd->sense_buffer[12]);  	}  	if (!ret) { diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 98999bbd8cbf..8b799f047a99 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -560,7 +560,7 @@ __lpfc_set_rrq_active(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp,  	rrq = mempool_alloc(phba->rrq_pool, GFP_KERNEL);  	if (rrq) {  		rrq->send_rrq = send_rrq; -		rrq->xritag = phba->sli4_hba.xri_ids[xritag]; +		rrq->xritag = xritag;  		rrq->rrq_stop_time = jiffies + HZ * (phba->fc_ratov + 1);  		rrq->ndlp = ndlp;  		rrq->nlp_DID = ndlp->nlp_DID; @@ -2452,7 +2452,8 @@ lpfc_sli_process_unsol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,  		/* search continue save q for same XRI */  		list_for_each_entry(iocbq, &pring->iocb_continue_saveq, clist) { -			if (iocbq->iocb.ulpContext == saveq->iocb.ulpContext) { +			if (iocbq->iocb.unsli3.rcvsli3.ox_id == +				saveq->iocb.unsli3.rcvsli3.ox_id) {  				list_add_tail(&saveq->list, &iocbq->list);  				found = 1;  				break; @@ -3355,6 +3356,7 @@ lpfc_sli_handle_slow_ring_event_s4(struct lpfc_hba *phba,  							   irspiocbq);  			break;  		case CQE_CODE_RECEIVE: +		case CQE_CODE_RECEIVE_V1:  			dmabuf = container_of(cq_event, struct hbq_dmabuf,  					      cq_event);  			lpfc_sli4_handle_received_buffer(phba, dmabuf); @@ -4712,10 +4714,15 @@ lpfc_sli4_arm_cqeq_intr(struct lpfc_hba *phba)   * lpfc_sli4_get_avail_extnt_rsrc - Get available resource extent count.   * @phba: Pointer to HBA context object.   * @type: The resource extent type. + * @extnt_count: buffer to hold port available extent count. + * @extnt_size: buffer to hold element count per extent.   * - * This function allocates all SLI4 resource identifiers. + * This function calls the port and retrievs the number of available + * extents and their size for a particular extent type. + * + * Returns: 0 if successful.  Nonzero otherwise.   **/ -static int +int  lpfc_sli4_get_avail_extnt_rsrc(struct lpfc_hba *phba, uint16_t type,  			       uint16_t *extnt_count, uint16_t *extnt_size)  { @@ -4892,7 +4899,7 @@ lpfc_sli4_cfg_post_extnts(struct lpfc_hba *phba, uint16_t *extnt_cnt,  				     req_len, *emb);  	if (alloc_len < req_len) {  		lpfc_printf_log(phba, KERN_ERR, LOG_INIT, -			"9000 Allocated DMA memory size (x%x) is " +			"2982 Allocated DMA memory size (x%x) is "  			"less than the requested DMA memory "  			"size (x%x)\n", alloc_len, req_len);  		return -ENOMEM; @@ -5506,6 +5513,154 @@ lpfc_sli4_dealloc_resource_identifiers(struct lpfc_hba *phba)  }  /** + * lpfc_sli4_get_allocated_extnts - Get the port's allocated extents. + * @phba: Pointer to HBA context object. + * @type: The resource extent type. + * @extnt_count: buffer to hold port extent count response + * @extnt_size: buffer to hold port extent size response. + * + * This function calls the port to read the host allocated extents + * for a particular type. + **/ +int +lpfc_sli4_get_allocated_extnts(struct lpfc_hba *phba, uint16_t type, +			       uint16_t *extnt_cnt, uint16_t *extnt_size) +{ +	bool emb; +	int rc = 0; +	uint16_t curr_blks = 0; +	uint32_t req_len, emb_len; +	uint32_t alloc_len, mbox_tmo; +	struct list_head *blk_list_head; +	struct lpfc_rsrc_blks *rsrc_blk; +	LPFC_MBOXQ_t *mbox; +	void *virtaddr = NULL; +	struct lpfc_mbx_nembed_rsrc_extent *n_rsrc; +	struct lpfc_mbx_alloc_rsrc_extents *rsrc_ext; +	union  lpfc_sli4_cfg_shdr *shdr; + +	switch (type) { +	case LPFC_RSC_TYPE_FCOE_VPI: +		blk_list_head = &phba->lpfc_vpi_blk_list; +		break; +	case LPFC_RSC_TYPE_FCOE_XRI: +		blk_list_head = &phba->sli4_hba.lpfc_xri_blk_list; +		break; +	case LPFC_RSC_TYPE_FCOE_VFI: +		blk_list_head = &phba->sli4_hba.lpfc_vfi_blk_list; +		break; +	case LPFC_RSC_TYPE_FCOE_RPI: +		blk_list_head = &phba->sli4_hba.lpfc_rpi_blk_list; +		break; +	default: +		return -EIO; +	} + +	/* Count the number of extents currently allocatd for this type. */ +	list_for_each_entry(rsrc_blk, blk_list_head, list) { +		if (curr_blks == 0) { +			/* +			 * The GET_ALLOCATED mailbox does not return the size, +			 * just the count.  The size should be just the size +			 * stored in the current allocated block and all sizes +			 * for an extent type are the same so set the return +			 * value now. +			 */ +			*extnt_size = rsrc_blk->rsrc_size; +		} +		curr_blks++; +	} + +	/* Calculate the total requested length of the dma memory. */ +	req_len = curr_blks * sizeof(uint16_t); + +	/* +	 * Calculate the size of an embedded mailbox.  The uint32_t +	 * accounts for extents-specific word. +	 */ +	emb_len = sizeof(MAILBOX_t) - sizeof(struct mbox_header) - +		sizeof(uint32_t); + +	/* +	 * Presume the allocation and response will fit into an embedded +	 * mailbox.  If not true, reconfigure to a non-embedded mailbox. +	 */ +	emb = LPFC_SLI4_MBX_EMBED; +	req_len = emb_len; +	if (req_len > emb_len) { +		req_len = curr_blks * sizeof(uint16_t) + +			sizeof(union lpfc_sli4_cfg_shdr) + +			sizeof(uint32_t); +		emb = LPFC_SLI4_MBX_NEMBED; +	} + +	mbox = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); +	if (!mbox) +		return -ENOMEM; +	memset(mbox, 0, sizeof(LPFC_MBOXQ_t)); + +	alloc_len = lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_COMMON, +				     LPFC_MBOX_OPCODE_GET_ALLOC_RSRC_EXTENT, +				     req_len, emb); +	if (alloc_len < req_len) { +		lpfc_printf_log(phba, KERN_ERR, LOG_INIT, +			"2983 Allocated DMA memory size (x%x) is " +			"less than the requested DMA memory " +			"size (x%x)\n", alloc_len, req_len); +		rc = -ENOMEM; +		goto err_exit; +	} +	rc = lpfc_sli4_mbox_rsrc_extent(phba, mbox, curr_blks, type, emb); +	if (unlikely(rc)) { +		rc = -EIO; +		goto err_exit; +	} + +	if (!phba->sli4_hba.intr_enable) +		rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL); +	else { +		mbox_tmo = lpfc_mbox_tmo_val(phba, MBX_SLI4_CONFIG); +		rc = lpfc_sli_issue_mbox_wait(phba, mbox, mbox_tmo); +	} + +	if (unlikely(rc)) { +		rc = -EIO; +		goto err_exit; +	} + +	/* +	 * Figure out where the response is located.  Then get local pointers +	 * to the response data.  The port does not guarantee to respond to +	 * all extents counts request so update the local variable with the +	 * allocated count from the port. +	 */ +	if (emb == LPFC_SLI4_MBX_EMBED) { +		rsrc_ext = &mbox->u.mqe.un.alloc_rsrc_extents; +		shdr = &rsrc_ext->header.cfg_shdr; +		*extnt_cnt = bf_get(lpfc_mbx_rsrc_cnt, &rsrc_ext->u.rsp); +	} else { +		virtaddr = mbox->sge_array->addr[0]; +		n_rsrc = (struct lpfc_mbx_nembed_rsrc_extent *) virtaddr; +		shdr = &n_rsrc->cfg_shdr; +		*extnt_cnt = bf_get(lpfc_mbx_rsrc_cnt, n_rsrc); +	} + +	if (bf_get(lpfc_mbox_hdr_status, &shdr->response)) { +		lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_INIT, +			"2984 Failed to read allocated resources " +			"for type %d - Status 0x%x Add'l Status 0x%x.\n", +			type, +			bf_get(lpfc_mbox_hdr_status, &shdr->response), +			bf_get(lpfc_mbox_hdr_add_status, &shdr->response)); +		rc = -EIO; +		goto err_exit; +	} + err_exit: +	lpfc_sli4_mbox_cmd_free(phba, mbox); +	return rc; +} + +/**   * lpfc_sli4_hba_setup - SLI4 device intialization PCI function   * @phba: Pointer to HBA context object.   * @@ -5837,6 +5992,7 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba)  					"Advanced Error Reporting (AER)\n");  			phba->cfg_aer_support = 0;  		} +		rc = 0;  	}  	if (!(phba->hba_flag & HBA_FCOE_MODE)) { @@ -6634,6 +6790,9 @@ lpfc_sli_issue_mbox_s4(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq,  	unsigned long iflags;  	int rc; +	/* dump from issue mailbox command if setup */ +	lpfc_idiag_mbxacc_dump_issue_mbox(phba, &mboxq->u.mb); +  	rc = lpfc_mbox_dev_check(phba);  	if (unlikely(rc)) {  		lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, @@ -7318,12 +7477,12 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,  		bf_set(wqe_qosd, &wqe->els_req.wqe_com, 1);  		bf_set(wqe_lenloc, &wqe->els_req.wqe_com, LPFC_WQE_LENLOC_NONE);  		bf_set(wqe_ebde_cnt, &wqe->els_req.wqe_com, 0); -	break; +		break;  	case CMD_XMIT_SEQUENCE64_CX:  		bf_set(wqe_ctxt_tag, &wqe->xmit_sequence.wqe_com,  		       iocbq->iocb.un.ulpWord[3]);  		bf_set(wqe_rcvoxid, &wqe->xmit_sequence.wqe_com, -		       iocbq->iocb.ulpContext); +		       iocbq->iocb.unsli3.rcvsli3.ox_id);  		/* The entire sequence is transmitted for this IOCB */  		xmit_len = total_len;  		cmnd = CMD_XMIT_SEQUENCE64_CR; @@ -7341,7 +7500,7 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,  		bf_set(wqe_ebde_cnt, &wqe->xmit_sequence.wqe_com, 0);  		wqe->xmit_sequence.xmit_len = xmit_len;  		command_type = OTHER_COMMAND; -	break; +		break;  	case CMD_XMIT_BCAST64_CN:  		/* word3 iocb=iotag32 wqe=seq_payload_len */  		wqe->xmit_bcast64.seq_payload_len = xmit_len; @@ -7355,7 +7514,7 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,  		bf_set(wqe_lenloc, &wqe->xmit_bcast64.wqe_com,  		       LPFC_WQE_LENLOC_WORD3);  		bf_set(wqe_ebde_cnt, &wqe->xmit_bcast64.wqe_com, 0); -	break; +		break;  	case CMD_FCP_IWRITE64_CR:  		command_type = FCP_COMMAND_DATA_OUT;  		/* word3 iocb=iotag wqe=payload_offset_len */ @@ -7375,7 +7534,7 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,  		       LPFC_WQE_LENLOC_WORD4);  		bf_set(wqe_ebde_cnt, &wqe->fcp_iwrite.wqe_com, 0);  		bf_set(wqe_pu, &wqe->fcp_iwrite.wqe_com, iocbq->iocb.ulpPU); -	break; +		break;  	case CMD_FCP_IREAD64_CR:  		/* word3 iocb=iotag wqe=payload_offset_len */  		/* Add the FCP_CMD and FCP_RSP sizes to get the offset */ @@ -7394,7 +7553,7 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,  		       LPFC_WQE_LENLOC_WORD4);  		bf_set(wqe_ebde_cnt, &wqe->fcp_iread.wqe_com, 0);  		bf_set(wqe_pu, &wqe->fcp_iread.wqe_com, iocbq->iocb.ulpPU); -	break; +		break;  	case CMD_FCP_ICMND64_CR:  		/* word3 iocb=IO_TAG wqe=reserved */  		wqe->fcp_icmd.rsrvd3 = 0; @@ -7407,7 +7566,7 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,  		bf_set(wqe_lenloc, &wqe->fcp_icmd.wqe_com,  		       LPFC_WQE_LENLOC_NONE);  		bf_set(wqe_ebde_cnt, &wqe->fcp_icmd.wqe_com, 0); -	break; +		break;  	case CMD_GEN_REQUEST64_CR:  		/* For this command calculate the xmit length of the  		 * request bde. @@ -7442,7 +7601,7 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,  		bf_set(wqe_lenloc, &wqe->gen_req.wqe_com, LPFC_WQE_LENLOC_NONE);  		bf_set(wqe_ebde_cnt, &wqe->gen_req.wqe_com, 0);  		command_type = OTHER_COMMAND; -	break; +		break;  	case CMD_XMIT_ELS_RSP64_CX:  		ndlp = (struct lpfc_nodelist *)iocbq->context1;  		/* words0-2 BDE memcpy */ @@ -7457,7 +7616,7 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,  		       ((iocbq->iocb.ulpCt_h << 1) | iocbq->iocb.ulpCt_l));  		bf_set(wqe_pu, &wqe->xmit_els_rsp.wqe_com, iocbq->iocb.ulpPU);  		bf_set(wqe_rcvoxid, &wqe->xmit_els_rsp.wqe_com, -		       iocbq->iocb.ulpContext); +		       iocbq->iocb.unsli3.rcvsli3.ox_id);  		if (!iocbq->iocb.ulpCt_h && iocbq->iocb.ulpCt_l)  			bf_set(wqe_ctxt_tag, &wqe->xmit_els_rsp.wqe_com,  			       phba->vpi_ids[iocbq->vport->vpi]); @@ -7470,7 +7629,7 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,  		bf_set(wqe_rsp_temp_rpi, &wqe->xmit_els_rsp,  		       phba->sli4_hba.rpi_ids[ndlp->nlp_rpi]);  		command_type = OTHER_COMMAND; -	break; +		break;  	case CMD_CLOSE_XRI_CN:  	case CMD_ABORT_XRI_CN:  	case CMD_ABORT_XRI_CX: @@ -7509,7 +7668,7 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,  		cmnd = CMD_ABORT_XRI_CX;  		command_type = OTHER_COMMAND;  		xritag = 0; -	break; +		break;  	case CMD_XMIT_BLS_RSP64_CX:  		/* As BLS ABTS RSP WQE is very different from other WQEs,  		 * we re-construct this WQE here based on information in @@ -7553,7 +7712,7 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,  			       bf_get(lpfc_rsn_code, &iocbq->iocb.un.bls_rsp));  		} -	break; +		break;  	case CMD_XRI_ABORTED_CX:  	case CMD_CREATE_XRI_CR: /* Do we expect to use this? */  	case CMD_IOCB_FCP_IBIDIR64_CR: /* bidirectional xfer */ @@ -7565,7 +7724,7 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,  				"2014 Invalid command 0x%x\n",  				iocbq->iocb.ulpCommand);  		return IOCB_ERROR; -	break; +		break;  	}  	bf_set(wqe_xri_tag, &wqe->generic.wqe_com, xritag); @@ -10481,10 +10640,14 @@ lpfc_sli4_sp_handle_rcqe(struct lpfc_hba *phba, struct lpfc_rcqe *rcqe)  	struct lpfc_queue *hrq = phba->sli4_hba.hdr_rq;  	struct lpfc_queue *drq = phba->sli4_hba.dat_rq;  	struct hbq_dmabuf *dma_buf; -	uint32_t status; +	uint32_t status, rq_id;  	unsigned long iflags; -	if (bf_get(lpfc_rcqe_rq_id, rcqe) != hrq->queue_id) +	if (bf_get(lpfc_cqe_code, rcqe) == CQE_CODE_RECEIVE_V1) +		rq_id = bf_get(lpfc_rcqe_rq_id_v1, rcqe); +	else +		rq_id = bf_get(lpfc_rcqe_rq_id, rcqe); +	if (rq_id != hrq->queue_id)  		goto out;  	status = bf_get(lpfc_rcqe_status, rcqe); @@ -10563,6 +10726,7 @@ lpfc_sli4_sp_handle_cqe(struct lpfc_hba *phba, struct lpfc_queue *cq,  				(struct sli4_wcqe_xri_aborted *)&cqevt);  		break;  	case CQE_CODE_RECEIVE: +	case CQE_CODE_RECEIVE_V1:  		/* Process the RQ event */  		phba->last_completion_time = jiffies;  		workposted = lpfc_sli4_sp_handle_rcqe(phba, @@ -12345,19 +12509,18 @@ lpfc_sli4_post_sgl(struct lpfc_hba *phba,  }  /** - * lpfc_sli4_init_rpi_hdrs - Post the rpi header memory region to the port + * lpfc_sli4_alloc_xri - Get an available rpi in the device's range   * @phba: pointer to lpfc hba data structure.   *   * This routine is invoked to post rpi header templates to the - * port for those SLI4 ports that do not support extents.  This routine - * posts a PAGE_SIZE memory region to the port to hold up to - * PAGE_SIZE modulo 64 rpi context headers.  This is an initialization routine - * and should be called only when interrupts are disabled. + * HBA consistent with the SLI-4 interface spec.  This routine + * posts a SLI4_PAGE_SIZE memory region to the port to hold up to + * SLI4_PAGE_SIZE modulo 64 rpi context headers.   * - * Return codes - *	0 - successful - *	-ERROR - otherwise. - */ + * Returns + *	A nonzero rpi defined as rpi_base <= rpi < max_rpi if successful + *	LPFC_RPI_ALLOC_ERROR if no rpis are available. + **/  uint16_t  lpfc_sli4_alloc_xri(struct lpfc_hba *phba)  { @@ -13406,7 +13569,7 @@ lpfc_sli4_seq_abort_rsp_cmpl(struct lpfc_hba *phba,   * This function validates the xri maps to the known range of XRIs allocated an   * used by the driver.   **/ -static uint16_t +uint16_t  lpfc_sli4_xri_inrange(struct lpfc_hba *phba,  		      uint16_t xri)  { @@ -13643,10 +13806,12 @@ lpfc_seq_complete(struct hbq_dmabuf *dmabuf)  static struct lpfc_iocbq *  lpfc_prep_seq(struct lpfc_vport *vport, struct hbq_dmabuf *seq_dmabuf)  { +	struct hbq_dmabuf *hbq_buf;  	struct lpfc_dmabuf *d_buf, *n_buf;  	struct lpfc_iocbq *first_iocbq, *iocbq;  	struct fc_frame_header *fc_hdr;  	uint32_t sid; +	uint32_t len, tot_len;  	struct ulp_bde64 *pbde;  	fc_hdr = (struct fc_frame_header *)seq_dmabuf->hbuf.virt; @@ -13655,6 +13820,7 @@ lpfc_prep_seq(struct lpfc_vport *vport, struct hbq_dmabuf *seq_dmabuf)  	lpfc_update_rcv_time_stamp(vport);  	/* get the Remote Port's SID */  	sid = sli4_sid_from_fc_hdr(fc_hdr); +	tot_len = 0;  	/* Get an iocbq struct to fill in. */  	first_iocbq = lpfc_sli_get_iocbq(vport->phba);  	if (first_iocbq) { @@ -13662,9 +13828,12 @@ lpfc_prep_seq(struct lpfc_vport *vport, struct hbq_dmabuf *seq_dmabuf)  		first_iocbq->iocb.unsli3.rcvsli3.acc_len = 0;  		first_iocbq->iocb.ulpStatus = IOSTAT_SUCCESS;  		first_iocbq->iocb.ulpCommand = CMD_IOCB_RCV_SEQ64_CX; -		first_iocbq->iocb.ulpContext = be16_to_cpu(fc_hdr->fh_ox_id); -		/* iocbq is prepped for internal consumption.  Logical vpi. */ -		first_iocbq->iocb.unsli3.rcvsli3.vpi = vport->vpi; +		first_iocbq->iocb.ulpContext = NO_XRI; +		first_iocbq->iocb.unsli3.rcvsli3.ox_id = +			be16_to_cpu(fc_hdr->fh_ox_id); +		/* iocbq is prepped for internal consumption.  Physical vpi. */ +		first_iocbq->iocb.unsli3.rcvsli3.vpi = +			vport->phba->vpi_ids[vport->vpi];  		/* put the first buffer into the first IOCBq */  		first_iocbq->context2 = &seq_dmabuf->dbuf;  		first_iocbq->context3 = NULL; @@ -13672,9 +13841,9 @@ lpfc_prep_seq(struct lpfc_vport *vport, struct hbq_dmabuf *seq_dmabuf)  		first_iocbq->iocb.un.cont64[0].tus.f.bdeSize =  							LPFC_DATA_BUF_SIZE;  		first_iocbq->iocb.un.rcvels.remoteID = sid; -		first_iocbq->iocb.unsli3.rcvsli3.acc_len += -				bf_get(lpfc_rcqe_length, +		tot_len = bf_get(lpfc_rcqe_length,  				       &seq_dmabuf->cq_event.cqe.rcqe_cmpl); +		first_iocbq->iocb.unsli3.rcvsli3.acc_len = tot_len;  	}  	iocbq = first_iocbq;  	/* @@ -13692,9 +13861,13 @@ lpfc_prep_seq(struct lpfc_vport *vport, struct hbq_dmabuf *seq_dmabuf)  			pbde = (struct ulp_bde64 *)  					&iocbq->iocb.unsli3.sli3Words[4];  			pbde->tus.f.bdeSize = LPFC_DATA_BUF_SIZE; -			first_iocbq->iocb.unsli3.rcvsli3.acc_len += -				bf_get(lpfc_rcqe_length, -				       &seq_dmabuf->cq_event.cqe.rcqe_cmpl); + +			/* We need to get the size out of the right CQE */ +			hbq_buf = container_of(d_buf, struct hbq_dmabuf, dbuf); +			len = bf_get(lpfc_rcqe_length, +				       &hbq_buf->cq_event.cqe.rcqe_cmpl); +			iocbq->iocb.unsli3.rcvsli3.acc_len += len; +			tot_len += len;  		} else {  			iocbq = lpfc_sli_get_iocbq(vport->phba);  			if (!iocbq) { @@ -13712,9 +13885,14 @@ lpfc_prep_seq(struct lpfc_vport *vport, struct hbq_dmabuf *seq_dmabuf)  			iocbq->iocb.ulpBdeCount = 1;  			iocbq->iocb.un.cont64[0].tus.f.bdeSize =  							LPFC_DATA_BUF_SIZE; -			first_iocbq->iocb.unsli3.rcvsli3.acc_len += -				bf_get(lpfc_rcqe_length, -				       &seq_dmabuf->cq_event.cqe.rcqe_cmpl); + +			/* We need to get the size out of the right CQE */ +			hbq_buf = container_of(d_buf, struct hbq_dmabuf, dbuf); +			len = bf_get(lpfc_rcqe_length, +				       &hbq_buf->cq_event.cqe.rcqe_cmpl); +			tot_len += len; +			iocbq->iocb.unsli3.rcvsli3.acc_len = tot_len; +  			iocbq->iocb.un.rcvels.remoteID = sid;  			list_add_tail(&iocbq->list, &first_iocbq->list);  		} @@ -13787,7 +13965,13 @@ lpfc_sli4_handle_received_buffer(struct lpfc_hba *phba,  		lpfc_in_buf_free(phba, &dmabuf->dbuf);  		return;  	} -	fcfi = bf_get(lpfc_rcqe_fcf_id, &dmabuf->cq_event.cqe.rcqe_cmpl); +	if ((bf_get(lpfc_cqe_code, +		    &dmabuf->cq_event.cqe.rcqe_cmpl) == CQE_CODE_RECEIVE_V1)) +		fcfi = bf_get(lpfc_rcqe_fcf_id_v1, +			      &dmabuf->cq_event.cqe.rcqe_cmpl); +	else +		fcfi = bf_get(lpfc_rcqe_fcf_id, +			      &dmabuf->cq_event.cqe.rcqe_cmpl);  	vport = lpfc_fc_frame_to_vport(phba, fc_hdr, fcfi);  	if (!vport || !(vport->vpi_state & LPFC_VPI_REGISTERED)) {  		/* throw out the frame */ @@ -14451,6 +14635,92 @@ fail_fcf_read:  }  /** + * lpfc_check_next_fcf_pri + * phba pointer to the lpfc_hba struct for this port. + * This routine is called from the lpfc_sli4_fcf_rr_next_index_get + * routine when the rr_bmask is empty. The FCF indecies are put into the + * rr_bmask based on their priority level. Starting from the highest priority + * to the lowest. The most likely FCF candidate will be in the highest + * priority group. When this routine is called it searches the fcf_pri list for + * next lowest priority group and repopulates the rr_bmask with only those + * fcf_indexes. + * returns: + * 1=success 0=failure + **/ +int +lpfc_check_next_fcf_pri_level(struct lpfc_hba *phba) +{ +	uint16_t next_fcf_pri; +	uint16_t last_index; +	struct lpfc_fcf_pri *fcf_pri; +	int rc; +	int ret = 0; + +	last_index = find_first_bit(phba->fcf.fcf_rr_bmask, +			LPFC_SLI4_FCF_TBL_INDX_MAX); +	lpfc_printf_log(phba, KERN_INFO, LOG_FIP, +			"3060 Last IDX %d\n", last_index); +	if (list_empty(&phba->fcf.fcf_pri_list)) { +		lpfc_printf_log(phba, KERN_ERR, LOG_FIP, +			"3061 Last IDX %d\n", last_index); +		return 0; /* Empty rr list */ +	} +	next_fcf_pri = 0; +	/* +	 * Clear the rr_bmask and set all of the bits that are at this +	 * priority. +	 */ +	memset(phba->fcf.fcf_rr_bmask, 0, +			sizeof(*phba->fcf.fcf_rr_bmask)); +	spin_lock_irq(&phba->hbalock); +	list_for_each_entry(fcf_pri, &phba->fcf.fcf_pri_list, list) { +		if (fcf_pri->fcf_rec.flag & LPFC_FCF_FLOGI_FAILED) +			continue; +		/* +		 * the 1st priority that has not FLOGI failed +		 * will be the highest. +		 */ +		if (!next_fcf_pri) +			next_fcf_pri = fcf_pri->fcf_rec.priority; +		spin_unlock_irq(&phba->hbalock); +		if (fcf_pri->fcf_rec.priority == next_fcf_pri) { +			rc = lpfc_sli4_fcf_rr_index_set(phba, +						fcf_pri->fcf_rec.fcf_index); +			if (rc) +				return 0; +		} +		spin_lock_irq(&phba->hbalock); +	} +	/* +	 * if next_fcf_pri was not set above and the list is not empty then +	 * we have failed flogis on all of them. So reset flogi failed +	 * and start at the begining. +	 */ +	if (!next_fcf_pri && !list_empty(&phba->fcf.fcf_pri_list)) { +		list_for_each_entry(fcf_pri, &phba->fcf.fcf_pri_list, list) { +			fcf_pri->fcf_rec.flag &= ~LPFC_FCF_FLOGI_FAILED; +			/* +			 * the 1st priority that has not FLOGI failed +			 * will be the highest. +			 */ +			if (!next_fcf_pri) +				next_fcf_pri = fcf_pri->fcf_rec.priority; +			spin_unlock_irq(&phba->hbalock); +			if (fcf_pri->fcf_rec.priority == next_fcf_pri) { +				rc = lpfc_sli4_fcf_rr_index_set(phba, +						fcf_pri->fcf_rec.fcf_index); +				if (rc) +					return 0; +			} +			spin_lock_irq(&phba->hbalock); +		} +	} else +		ret = 1; +	spin_unlock_irq(&phba->hbalock); + +	return ret; +} +/**   * lpfc_sli4_fcf_rr_next_index_get - Get next eligible fcf record index   * @phba: pointer to lpfc hba data structure.   * @@ -14466,6 +14736,7 @@ lpfc_sli4_fcf_rr_next_index_get(struct lpfc_hba *phba)  	uint16_t next_fcf_index;  	/* Search start from next bit of currently registered FCF index */ +next_priority:  	next_fcf_index = (phba->fcf.current_rec.fcf_indx + 1) %  					LPFC_SLI4_FCF_TBL_INDX_MAX;  	next_fcf_index = find_next_bit(phba->fcf.fcf_rr_bmask, @@ -14473,17 +14744,46 @@ lpfc_sli4_fcf_rr_next_index_get(struct lpfc_hba *phba)  				       next_fcf_index);  	/* Wrap around condition on phba->fcf.fcf_rr_bmask */ -	if (next_fcf_index >= LPFC_SLI4_FCF_TBL_INDX_MAX) +	if (next_fcf_index >= LPFC_SLI4_FCF_TBL_INDX_MAX) { +		/* +		 * If we have wrapped then we need to clear the bits that +		 * have been tested so that we can detect when we should +		 * change the priority level. +		 */  		next_fcf_index = find_next_bit(phba->fcf.fcf_rr_bmask,  					       LPFC_SLI4_FCF_TBL_INDX_MAX, 0); +	} +  	/* Check roundrobin failover list empty condition */ -	if (next_fcf_index >= LPFC_SLI4_FCF_TBL_INDX_MAX) { +	if (next_fcf_index >= LPFC_SLI4_FCF_TBL_INDX_MAX || +		next_fcf_index == phba->fcf.current_rec.fcf_indx) { +		/* +		 * If next fcf index is not found check if there are lower +		 * Priority level fcf's in the fcf_priority list. +		 * Set up the rr_bmask with all of the avaiable fcf bits +		 * at that level and continue the selection process. +		 */ +		if (lpfc_check_next_fcf_pri_level(phba)) +			goto next_priority;  		lpfc_printf_log(phba, KERN_WARNING, LOG_FIP,  				"2844 No roundrobin failover FCF available\n"); -		return LPFC_FCOE_FCF_NEXT_NONE; +		if (next_fcf_index >= LPFC_SLI4_FCF_TBL_INDX_MAX) +			return LPFC_FCOE_FCF_NEXT_NONE; +		else { +			lpfc_printf_log(phba, KERN_WARNING, LOG_FIP, +				"3063 Only FCF available idx %d, flag %x\n", +				next_fcf_index, +			phba->fcf.fcf_pri[next_fcf_index].fcf_rec.flag); +			return next_fcf_index; +		}  	} +	if (next_fcf_index < LPFC_SLI4_FCF_TBL_INDX_MAX && +		phba->fcf.fcf_pri[next_fcf_index].fcf_rec.flag & +		LPFC_FCF_FLOGI_FAILED) +		goto next_priority; +  	lpfc_printf_log(phba, KERN_INFO, LOG_FIP,  			"2845 Get next roundrobin failover FCF (x%x)\n",  			next_fcf_index); @@ -14535,6 +14835,7 @@ lpfc_sli4_fcf_rr_index_set(struct lpfc_hba *phba, uint16_t fcf_index)  void  lpfc_sli4_fcf_rr_index_clear(struct lpfc_hba *phba, uint16_t fcf_index)  { +	struct lpfc_fcf_pri *fcf_pri;  	if (fcf_index >= LPFC_SLI4_FCF_TBL_INDX_MAX) {  		lpfc_printf_log(phba, KERN_ERR, LOG_FIP,  				"2762 FCF (x%x) reached driver's book " @@ -14543,6 +14844,14 @@ lpfc_sli4_fcf_rr_index_clear(struct lpfc_hba *phba, uint16_t fcf_index)  		return;  	}  	/* Clear the eligible FCF record index bmask */ +	spin_lock_irq(&phba->hbalock); +	list_for_each_entry(fcf_pri, &phba->fcf.fcf_pri_list, list) { +		if (fcf_pri->fcf_rec.fcf_index == fcf_index) { +			list_del_init(&fcf_pri->list); +			break; +		} +	} +	spin_unlock_irq(&phba->hbalock);  	clear_bit(fcf_index, phba->fcf.fcf_rr_bmask);  	lpfc_printf_log(phba, KERN_INFO, LOG_FIP, diff --git a/drivers/scsi/lpfc/lpfc_sli4.h b/drivers/scsi/lpfc/lpfc_sli4.h index 4b1703554a26..19bb87ae8597 100644 --- a/drivers/scsi/lpfc/lpfc_sli4.h +++ b/drivers/scsi/lpfc/lpfc_sli4.h @@ -81,6 +81,8 @@  	 (fc_hdr)->fh_f_ctl[1] <<  8 | \  	 (fc_hdr)->fh_f_ctl[2]) +#define LPFC_FW_RESET_MAXIMUM_WAIT_10MS_CNT 12000 +  enum lpfc_sli4_queue_type {  	LPFC_EQ,  	LPFC_GCQ, @@ -157,6 +159,25 @@ struct lpfc_fcf_rec {  #define RECORD_VALID	0x02  }; +struct lpfc_fcf_pri_rec { +	uint16_t fcf_index; +#define LPFC_FCF_ON_PRI_LIST 0x0001 +#define LPFC_FCF_FLOGI_FAILED 0x0002 +	uint16_t flag; +	uint32_t priority; +}; + +struct lpfc_fcf_pri { +	struct list_head list; +	struct lpfc_fcf_pri_rec fcf_rec; +}; + +/* + * Maximum FCF table index, it is for driver internal book keeping, it + * just needs to be no less than the supported HBA's FCF table size. + */ +#define LPFC_SLI4_FCF_TBL_INDX_MAX	32 +  struct lpfc_fcf {  	uint16_t fcfi;  	uint32_t fcf_flag; @@ -176,15 +197,13 @@ struct lpfc_fcf {  	uint32_t eligible_fcf_cnt;  	struct lpfc_fcf_rec current_rec;  	struct lpfc_fcf_rec failover_rec; +	struct list_head fcf_pri_list; +	struct lpfc_fcf_pri fcf_pri[LPFC_SLI4_FCF_TBL_INDX_MAX]; +	uint32_t current_fcf_scan_pri;  	struct timer_list redisc_wait;  	unsigned long *fcf_rr_bmask; /* Eligible FCF indexes for RR failover */  }; -/* - * Maximum FCF table index, it is for driver internal book keeping, it - * just needs to be no less than the supported HBA's FCF table size. - */ -#define LPFC_SLI4_FCF_TBL_INDX_MAX	32  #define LPFC_REGION23_SIGNATURE "RG23"  #define LPFC_REGION23_VERSION	1 diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h index c03921b1232c..c1e0ae94d9f4 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 "8.3.23" +#define LPFC_DRIVER_VERSION "8.3.25"  #define LPFC_DRIVER_NAME		"lpfc"  #define LPFC_SP_DRIVER_HANDLER_NAME	"lpfc:sp"  #define LPFC_FP_DRIVER_HANDLER_NAME	"lpfc:fp" | 
