Commit ed957684 authored by James Smart's avatar James Smart Committed by James Bottomley
Browse files

[SCSI] lpfc: NPIV: add SLI-3 interface



NPIV support is only available via new adapter interface extensions,
termed SLI-3. This interface changes some of the basic behaviors such
as command and response ring element sizes and data structures, as
well as a change in buffer posting.  Note: the new firmware extensions
are found only on our mid-range and enterprise 4Gig adapters - so NPIV
support is available only on these newer adapters. The latest firmware
can be downloaded from the Emulex support page.

Signed-off-by: default avatarJames Smart <James.Smart@emulex.com>
Signed-off-by: default avatarJames Bottomley <James.Bottomley@SteelEye.com>
parent 2e0fef85
Loading
Loading
Loading
Loading
+33 −2
Original line number Diff line number Diff line
@@ -63,6 +63,11 @@ struct lpfc_dma_pool {
	uint32_t    current_count;
};

struct hbq_dmabuf {
	struct lpfc_dmabuf dbuf;
	uint32_t tag;
};

/* Priority bit.  Set value to exceed low water mark in lpfc_mem. */
#define MEM_PRI		0x100

@@ -276,8 +281,25 @@ struct lpfc_vport {

};


struct hbq_s {
	uint16_t entry_count;	  /* Current number of HBQ slots */
	uint32_t next_hbqPutIdx;  /* Index to next HBQ slot to use */
	uint32_t hbqPutIdx;	  /* HBQ slot to use */
	uint32_t local_hbqGetIdx; /* Local copy of Get index from Port */
};

#define MAX_HBQS  16

struct lpfc_hba {
	struct lpfc_sli sli;
	uint32_t sli_rev;		/* SLI2 or SLI3 */
	uint32_t sli3_options;		/* Mask of enabled SLI3 options */
#define LPFC_SLI3_ENABLED	0x01
#define LPFC_SLI3_HBQ_ENABLED	0x02
#define LPFC_SLI3_INB_ENABLED	0x04
	uint32_t iocb_cmd_size;
	uint32_t iocb_rsp_size;

	enum hba_state link_state;
	uint32_t link_flag;	/* link state flags */
@@ -286,8 +308,6 @@ struct lpfc_hba {
					/* INIT_LINK mailbox command */
#define LS_IGNORE_ERATT         0x80000	/* intr handler should ignore ERATT */

	uint32_t pgpOffset; /* PGP offset within host memory */

	struct lpfc_sli2_slim *slim2p;
	struct lpfc_dmabuf hbqslimp;

@@ -371,6 +391,12 @@ struct lpfc_hba {
	wait_queue_head_t    *work_wait;
	struct task_struct   *worker_thread;

	struct   hbq_dmabuf *hbq_buffer_pool;
	uint32_t hbq_buffer_count;
	uint32_t hbq_buff_count; 	/* Current hbq buffers */
	uint32_t hbq_count;	        /* Count of configured HBQs */
	struct hbq_s hbqs[MAX_HBQS];    /* local copy of hbq indicies  */

	unsigned long pci_bar0_map;     /* Physical address for PCI BAR0 */
	unsigned long pci_bar2_map;     /* Physical address for PCI BAR2 */
	void __iomem *slim_memmap_p;	/* Kernel memory mapped address for
@@ -385,6 +411,10 @@ struct lpfc_hba {
					   reg */
	void __iomem *HCregaddr;	/* virtual address for host ctl reg */

	struct lpfc_hgp __iomem *host_gp; /* Host side get/put pointers */
	uint32_t __iomem  *hbq_put;     /* Address in SLIM to HBQ put ptrs */
	uint32_t __iomem  *hbq_get;     /* Address in SLIM to HBQ get ptrs */

	int brd_no;			/* FC board number */

	char SerialNumber[32];		/* adapter Serial Number */
@@ -425,6 +455,7 @@ struct lpfc_hba {
	/* pci_mem_pools */
	struct pci_pool *lpfc_scsi_dma_buf_pool;
	struct pci_pool *lpfc_mbuf_pool;
	struct pci_pool *lpfc_hbq_pool;
	struct lpfc_dma_pool lpfc_mbuf_safety_pool;

	mempool_t *mbox_mem_pool;
+14 −0
Original line number Diff line number Diff line
@@ -138,6 +138,10 @@ void lpfc_mbox_put(struct lpfc_hba *, LPFC_MBOXQ_t *);
LPFC_MBOXQ_t *lpfc_mbox_get(struct lpfc_hba *);
int lpfc_mbox_tmo_val(struct lpfc_hba *, int);

void lpfc_config_hbq(struct lpfc_hba *, struct lpfc_hbq_init *, uint32_t ,
		     LPFC_MBOXQ_t *);
struct lpfc_hbq_entry * lpfc_sli_next_hbq_slot(struct lpfc_hba *, uint32_t);

int lpfc_mem_alloc(struct lpfc_hba *);
void lpfc_mem_free(struct lpfc_hba *);

@@ -172,6 +176,12 @@ int lpfc_sli_ringpostbuf_put(struct lpfc_hba *, struct lpfc_sli_ring *,
struct lpfc_dmabuf *lpfc_sli_ringpostbuf_get(struct lpfc_hba *,
					     struct lpfc_sli_ring *,
					     dma_addr_t);
int lpfc_sli_hbqbuf_fill_hbq(struct lpfc_hba *);
void lpfc_sli_hbqbuf_free(struct lpfc_hba *, void *, dma_addr_t);
void lpfc_sli_hbqbuf_free_all(struct lpfc_hba *);
struct hbq_dmabuf *lpfc_sli_hbqbuf_find(struct lpfc_hba *, uint32_t);
void lpfc_sli_free_hbq(struct lpfc_hba *, struct hbq_dmabuf *);
int lpfc_sli_hbq_size(void);
int lpfc_sli_issue_abort_iotag(struct lpfc_hba *, struct lpfc_sli_ring *,
			       struct lpfc_iocbq *);
int lpfc_sli_sum_iocb(struct lpfc_hba *, struct lpfc_sli_ring *, uint16_t,
@@ -198,6 +208,9 @@ void lpfc_sli_abort_fcp_cmpl(struct lpfc_hba * phba,
			     struct lpfc_iocbq * cmdiocb,
			     struct lpfc_iocbq * rspiocb);

void *lpfc_hbq_alloc(struct lpfc_hba *, int, dma_addr_t *);
void lpfc_hbq_free(struct lpfc_hba *, void *, dma_addr_t);

void *lpfc_mbuf_alloc(struct lpfc_hba *, int, dma_addr_t *);
void __lpfc_mbuf_free(struct lpfc_hba *, void *, dma_addr_t);
void lpfc_mbuf_free(struct lpfc_hba *, void *, dma_addr_t);
@@ -213,6 +226,7 @@ void lpfc_free_sysfs_attr(struct lpfc_vport *);
extern struct class_device_attribute *lpfc_hba_attrs[];
extern struct scsi_host_template lpfc_template;
extern struct fc_function_template lpfc_transport_functions;
extern int lpfc_sli_mode;

void lpfc_get_hba_sym_node_name(struct lpfc_hba *phba, uint8_t *symbp);
void lpfc_terminate_rport_io(struct fc_rport *);
+107 −76
Original line number Diff line number Diff line
@@ -58,24 +58,65 @@ static char *lpfc_release_version = LPFC_DRIVER_VERSION;
/*
 * lpfc_ct_unsol_event
 */
static void
lpfc_ct_unsol_buffer(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq,
		     struct lpfc_dmabuf *mp, uint32_t size)
{
	if (!mp) {
		printk(KERN_ERR "%s (%d): Unsolited CT, no buffer, "
		       "piocbq = %p, status = x%x, mp = %p, size = %d\n",
		       __FUNCTION__, __LINE__,
		       piocbq, piocbq->iocb.ulpStatus, mp, size);
	}

	printk(KERN_ERR "%s (%d): Ignoring unsolicted CT piocbq = %p, "
	       "buffer = %p, size = %d, status = x%x\n",
	       __FUNCTION__, __LINE__,
	       piocbq, mp, size,
	       piocbq->iocb.ulpStatus);
}

static void
lpfc_ct_ignore_hbq_buffer(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq,
			  struct hbq_dmabuf *sp, uint32_t size)
{
	struct lpfc_dmabuf *mp = NULL;

	mp = sp ? &sp->dbuf : NULL;
	if (!mp) {
		printk(KERN_ERR "%s (%d): Unsolited CT, no "
		       "HBQ buffer, piocbq = %p, status = x%x\n",
		       __FUNCTION__, __LINE__,
		       piocbq, piocbq->iocb.ulpStatus);
	} else {
		lpfc_ct_unsol_buffer(phba, piocbq, mp, size);
		printk(KERN_ERR "%s (%d): Ignoring unsolicted CT "
		       "piocbq = %p, buffer = %p, size = %d, "
		       "status = x%x\n",
		       __FUNCTION__, __LINE__,
		       piocbq, mp, size, piocbq->iocb.ulpStatus);
	}
}

void
lpfc_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
		    struct lpfc_iocbq *piocbq)
{

	struct lpfc_iocbq *next_piocbq;
	struct lpfc_dmabuf *pmbuf = NULL;
	struct lpfc_dmabuf *matp = NULL, *next_matp;
	uint32_t ctx = 0, size = 0, cnt = 0;
	struct lpfc_dmabuf *mp = NULL;
	struct hbq_dmabuf  *sp = NULL;
	IOCB_t *icmd = &piocbq->iocb;
	IOCB_t *save_icmd = icmd;
	int i, go_exit = 0;
	struct list_head head;
	int i;
	struct lpfc_iocbq *iocbq;
	dma_addr_t paddr;
	uint32_t size;

	if ((icmd->ulpStatus == IOSTAT_LOCAL_REJECT) &&
	    ((icmd->un.ulpWord[4] & 0xff) == IOERR_RCV_BUFFER_WAITING)) {
		/* Not enough posted buffers; Try posting more buffers */
		phba->fc_stat.NoRcvBuf++;
		if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED)
			lpfc_sli_hbqbuf_fill_hbq(phba);
		else
			lpfc_post_buffer(phba, pring, 0, 1);
		return;
	}
@@ -86,62 +127,62 @@ lpfc_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
	if (icmd->ulpBdeCount == 0)
		return;

	INIT_LIST_HEAD(&head);
	list_add_tail(&head, &piocbq->list);

	list_for_each_entry_safe(piocbq, next_piocbq, &head, list) {
		icmd = &piocbq->iocb;
		if (ctx == 0)
			ctx = (uint32_t) (icmd->ulpContext);
		if (icmd->ulpBdeCount == 0)
	if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) {
		list_for_each_entry(iocbq, &piocbq->list, list) {
			icmd = &iocbq->iocb;
			if (icmd->ulpBdeCount == 0) {
				printk(KERN_ERR "%s (%d): Unsolited CT, no "
				       "BDE, iocbq = %p, status = x%x\n",
				       __FUNCTION__, __LINE__,
				       iocbq, iocbq->iocb.ulpStatus);
				continue;

		for (i = 0; i < icmd->ulpBdeCount; i++) {
			matp = lpfc_sli_ringpostbuf_get(phba, pring,
							getPaddr(icmd->un.
								 cont64[i].
								 addrHigh,
								 icmd->un.
								 cont64[i].
								 addrLow));
			if (!matp) {
				/* Insert lpfc log message here */
				lpfc_post_buffer(phba, pring, cnt, 1);
				go_exit = 1;
				goto ct_unsol_event_exit_piocbq;
			}

			/* Typically for Unsolicited CT requests */
			if (!pmbuf) {
				pmbuf = matp;
				INIT_LIST_HEAD(&pmbuf->list);
			} else
				list_add_tail(&matp->list, &pmbuf->list);

			size += icmd->un.cont64[i].tus.f.bdeSize;
			cnt++;
			size  = icmd->un.cont64[0].tus.f.bdeSize;
			sp = lpfc_sli_hbqbuf_find(phba, icmd->un.ulpWord[3]);
			if (sp)
				phba->hbq_buff_count--;
			lpfc_ct_ignore_hbq_buffer(phba, iocbq, sp, size);
			lpfc_sli_free_hbq(phba, sp);
			if (icmd->ulpBdeCount == 2) {
				sp = lpfc_sli_hbqbuf_find(phba,
							  icmd->un.ulpWord[15]);
				if (sp)
					phba->hbq_buff_count--;
				lpfc_ct_ignore_hbq_buffer(phba, iocbq, sp,
							  size);
				lpfc_sli_free_hbq(phba, sp);
			}

		icmd->ulpBdeCount = 0;
		}

	lpfc_post_buffer(phba, pring, cnt, 1);
	if (save_icmd->ulpStatus) {
		go_exit = 1;
		lpfc_sli_hbqbuf_fill_hbq(phba);
	} else {
		struct lpfc_iocbq  *next;

		list_for_each_entry_safe(iocbq, next, &piocbq->list, list) {
			icmd = &iocbq->iocb;
			if (icmd->ulpBdeCount == 0) {
				printk(KERN_ERR "%s (%d): Unsolited CT, no "
				       "BDE, iocbq = %p, status = x%x\n",
				       __FUNCTION__, __LINE__,
				       iocbq, iocbq->iocb.ulpStatus);
				continue;
			}

ct_unsol_event_exit_piocbq:
	list_del(&head);
	if (pmbuf) {
		list_for_each_entry_safe(matp, next_matp, &pmbuf->list, list) {
			lpfc_mbuf_free(phba, matp->virt, matp->phys);
			list_del(&matp->list);
			kfree(matp);
			for (i = 0; i < icmd->ulpBdeCount; i++) {
				paddr = getPaddr(icmd->un.cont64[i].addrHigh,
						 icmd->un.cont64[i].addrLow);
				mp = lpfc_sli_ringpostbuf_get(phba, pring,
							      paddr);
				size = icmd->un.cont64[i].tus.f.bdeSize;
				lpfc_ct_unsol_buffer(phba, piocbq, mp, size);
				lpfc_mbuf_free(phba, mp->virt, mp->phys);
				kfree(mp);
			}
			list_del(&iocbq->list);
			lpfc_sli_release_iocbq(phba, iocbq);
		}
		lpfc_mbuf_free(phba, pmbuf->virt, pmbuf->phys);
		kfree(pmbuf);
	}
	return;
}

static void
@@ -364,9 +405,7 @@ lpfc_ns_rsp(struct lpfc_vport *vport, struct lpfc_dmabuf *mp, uint32_t Size)
						vport->fc_flag,
						vport->fc_rscn_id_cnt);
			} else {
				lpfc_printf_log(phba,
						KERN_INFO,
						LOG_DISCOVERY,
				lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
						"%d:0239 Skip x%x NameServer "
						"Rsp Data: x%x x%x x%x\n",
						phba->brd_no,
@@ -717,12 +756,9 @@ lpfc_cmpl_ct_cmd_fdmi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
	ndlp = lpfc_findnode_did(vport, FDMI_DID);
	if (fdmi_rsp == be16_to_cpu(SLI_CT_RESPONSE_FS_RJT)) {
		/* FDMI rsp failed */
		lpfc_printf_log(phba,
			        KERN_INFO,
			        LOG_DISCOVERY,
		lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
				"%d:0220 FDMI rsp failed Data: x%x\n",
			        phba->brd_no,
			       be16_to_cpu(fdmi_cmd));
				phba->brd_no, be16_to_cpu(fdmi_cmd));
	}

	switch (be16_to_cpu(fdmi_cmd)) {
@@ -791,9 +827,7 @@ lpfc_fdmi_cmd(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, int cmdcode)
	INIT_LIST_HEAD(&bmp->list);

	/* FDMI request */
	lpfc_printf_log(phba,
		        KERN_INFO,
		        LOG_DISCOVERY,
	lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
		        "%d:0218 FDMI Request Data: x%x x%x x%x\n",
		        phba->brd_no,
			vport->fc_flag, vport->port_state, cmdcode);
@@ -1120,12 +1154,9 @@ fdmi_cmd_free_mp:
	kfree(mp);
fdmi_cmd_exit:
	/* Issue FDMI request failed */
	lpfc_printf_log(phba,
		        KERN_INFO,
		        LOG_DISCOVERY,
	lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
		        "%d:0244 Issue FDMI request failed Data: x%x\n",
		        phba->brd_no,
			cmdcode);
		        phba->brd_no, cmdcode);
	return 1;
}

+146 −127
Original line number Diff line number Diff line
@@ -45,9 +45,7 @@ lpfc_els_chk_latt(struct lpfc_vport *vport)
{
	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
	struct lpfc_hba  *phba = vport->phba;
	LPFC_MBOXQ_t *mbox;
	uint32_t ha_copy;
	int rc;

	if (vport->port_state >= LPFC_VPORT_READY ||
	    phba->link_state == LPFC_LINK_DOWN)
@@ -76,20 +74,7 @@ lpfc_els_chk_latt(struct lpfc_vport *vport)
	spin_unlock_irq(shost->host_lock);

	if (phba->link_state != LPFC_CLEAR_LA) {
		if ((mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL))) {
			phba->link_state = LPFC_CLEAR_LA;
			lpfc_clear_la(phba, mbox);
			mbox->mbox_cmpl = lpfc_mbx_cmpl_clear_la;
			mbox->vport = vport;
			printk(KERN_ERR "%s (%d): do clear_la\n",
			       __FUNCTION__, __LINE__);
			rc = lpfc_sli_issue_mbox(phba, mbox,
						 (MBX_NOWAIT | MBX_STOP_IOCB));
			if (rc == MBX_NOT_FINISHED) {
				mempool_free(mbox, phba->mbox_mem_pool);
				phba->link_state = LPFC_HBA_ERROR;
			}
		}
		lpfc_issue_clear_la(phba, vport);
	}

	return 1;
@@ -289,6 +274,7 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
	vport->port_state = LPFC_FABRIC_CFG_LINK;
	lpfc_config_link(phba, mbox);
	mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
	mbox->vport = vport;

	rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT | MBX_STOP_IOCB);
	if (rc == MBX_NOT_FINISHED)
@@ -364,6 +350,7 @@ lpfc_cmpl_els_flogi_nport(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
		lpfc_config_link(phba, mbox);

		mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
		mbox->vport = vport;
		rc = lpfc_sli_issue_mbox(phba, mbox,
				MBX_NOWAIT | MBX_STOP_IOCB);
		if (rc == MBX_NOT_FINISHED) {
@@ -714,8 +701,10 @@ lpfc_cmpl_els_plogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,

	irsp = &rspiocb->iocb;
	ndlp = lpfc_findnode_did(vport, irsp->un.elsreq64.remoteID);
	if (!ndlp)

	if (!ndlp) {
		goto out;
	}

	/* Since ndlp can be freed in the disc state machine, note if this node
	 * is being used during discovery.
@@ -1110,9 +1099,8 @@ lpfc_cmpl_els_adisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
			/* If we get here, there is nothing left to wait for */
			if (vport->port_state < LPFC_VPORT_READY &&
			    phba->link_state != LPFC_CLEAR_LA) {
				if (vport->port_type == LPFC_PHYSICAL_PORT) {
				if (vport->port_type == LPFC_PHYSICAL_PORT)
					lpfc_issue_clear_la(phba, vport);
				}
			} else {
				lpfc_rscn_disc(vport);
			}
@@ -1420,6 +1408,27 @@ lpfc_issue_els_farpr(struct lpfc_vport *vport, uint32_t nportid, uint8_t retry)
	return 0;
}

static void
lpfc_end_rscn(struct lpfc_vport *vport)
{
	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);

	if (vport->fc_flag & FC_RSCN_MODE) {
		/*
		 * Check to see if more RSCNs came in while we were
		 * processing this one.
		 */
		if (vport->fc_rscn_id_cnt ||
		    (vport->fc_flag & FC_RSCN_DISCOVERY) != 0)
			lpfc_els_handle_rscn(vport);
		else {
			spin_lock_irq(shost->host_lock);
			vport->fc_flag &= ~FC_RSCN_MODE;
			spin_unlock_irq(shost->host_lock);
		}
	}
}

void
lpfc_cancel_retry_delay_tmo(struct lpfc_vport *vport, struct lpfc_nodelist *nlp)
{
@@ -1449,24 +1458,7 @@ lpfc_cancel_retry_delay_tmo(struct lpfc_vport *vport, struct lpfc_nodelist *nlp)
				vport->fc_flag &= ~FC_NDISC_ACTIVE;
				spin_unlock_irq(shost->host_lock);
				lpfc_can_disctmo(vport);
				if (vport->fc_flag & FC_RSCN_MODE) {
					/*
					 * Check to see if more RSCNs
					 * came in while we were
					 * processing this one.
					 */
					if (!vport->fc_rscn_id_cnt &&
					    !(vport->fc_flag &
					      FC_RSCN_DISCOVERY)) {
						spin_lock_irq(shost->host_lock);
						vport->fc_flag &= ~FC_RSCN_MODE;
						spin_unlock_irq(
							shost->host_lock);
					}
					else {
						lpfc_els_handle_rscn(vport);
					}
				}
				lpfc_end_rscn(vport);
			}
		}
	}
@@ -1689,6 +1681,9 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
		retry = 0;
	}

	if ((vport->load_flag & FC_UNLOADING) != 0)
		retry = 0;

	if (retry) {

		/* Retry ELS command <elsCmd> to remote NPORT <did> */
@@ -2141,9 +2136,7 @@ lpfc_els_rsp_prli_acc(struct lpfc_vport *vport, struct lpfc_iocbq *oldiocb,

	cmdsize = sizeof (uint32_t) + sizeof (PRLI);
	elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, oldiocb->retry, ndlp,
				     ndlp->nlp_DID,
				     (ELS_CMD_ACC |
				      (ELS_CMD_PRLI & ~ELS_RSP_MASK)));
	     ndlp->nlp_DID, (ELS_CMD_ACC | (ELS_CMD_PRLI & ~ELS_RSP_MASK)));
	if (!elsiocb)
		return 1;

@@ -2361,8 +2354,12 @@ lpfc_els_flush_rscn(struct lpfc_vport *vport)

	for (i = 0; i < vport->fc_rscn_id_cnt; i++) {
		mp = vport->fc_rscn_id_list[i];
		if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED)
			lpfc_sli_hbqbuf_free(phba, mp->virt, mp->phys);
		else {
			lpfc_mbuf_free(phba, mp->virt, mp->phys);
			kfree(mp);
		}
		vport->fc_rscn_id_list[i] = NULL;
	}
	spin_lock_irq(shost->host_lock);
@@ -2486,9 +2483,7 @@ lpfc_els_rcv_rscn(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
	cmd &= ELS_CMD_MASK;

	/* RSCN received */
	lpfc_printf_log(phba,
			KERN_INFO,
			LOG_DISCOVERY,
	lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
			"%d:0214 RSCN received Data: x%x x%x x%x x%x\n",
			phba->brd_no, vport->fc_flag, payload_len, *lp,
			vport->fc_rscn_id_cnt);
@@ -2581,9 +2576,7 @@ lpfc_els_handle_rscn(struct lpfc_vport *vport)
	lpfc_set_disctmo(vport);

	/* RSCN processed */
	lpfc_printf_log(phba,
			KERN_INFO,
			LOG_DISCOVERY,
	lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
			"%d:0215 RSCN processed Data: x%x x%x x%x x%x\n",
			phba->brd_no,
			vport->fc_flag, 0, vport->fc_rscn_id_cnt,
@@ -2683,6 +2676,7 @@ lpfc_els_rcv_flogi(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
				       phba->cfg_link_speed);
			mbox->mb.un.varInitLnk.lipsr_AL_PA = 0;
			mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
			mbox->vport = vport;
			rc = lpfc_sli_issue_mbox
				(phba, mbox, (MBX_NOWAIT | MBX_STOP_IOCB));
			lpfc_set_loopback_flag(phba);
@@ -2837,10 +2831,8 @@ lpfc_els_rsp_rps_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)

	elsiocb->iocb_cmpl = lpfc_cmpl_els_acc;
	phba->fc_stat.elsXmitACC++;

	if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) {
	if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR)
		lpfc_els_free_iocb(phba, elsiocb);
	}
	return;
}

@@ -3015,9 +3007,7 @@ lpfc_els_rcv_farp(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
	fp = (FARP *) lp;

	/* FARP-REQ received from DID <did> */
	lpfc_printf_log(phba,
			 KERN_INFO,
			 LOG_ELS,
	lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
			 "%d:0601 FARP-REQ received from DID x%x\n",
			 phba->brd_no, did);

@@ -3077,12 +3067,9 @@ lpfc_els_rcv_farpr(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,

	cmd = *lp++;
	/* FARP-RSP received from DID <did> */
	lpfc_printf_log(phba,
			 KERN_INFO,
			 LOG_ELS,
	lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
			 "%d:0600 FARP-RSP received from DID x%x\n",
			 phba->brd_no, did);

	/* ACCEPT the Farp resp request */
	lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL, 0);

@@ -3102,7 +3089,8 @@ lpfc_els_rcv_fan(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
	struct lpfc_hba *phba = vport->phba;

	/* FAN received */
	lpfc_printf_log(phba, KERN_INFO, LOG_ELS, "%d:0265 FAN received\n",
	lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
			"%d:0265 FAN received\n",
			phba->brd_no);

	icmd = &cmdiocb->iocb;
@@ -3332,79 +3320,40 @@ lpfc_els_flush_cmd(struct lpfc_vport *vport)
	return;
}

void
lpfc_els_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
static void
lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
		      struct lpfc_vport *vport, struct lpfc_dmabuf *mp,
		      struct lpfc_iocbq *elsiocb)
{
	struct lpfc_sli *psli;
	struct lpfc_nodelist *ndlp;
	struct lpfc_dmabuf *mp = NULL;
	uint32_t *lp;
	IOCB_t *icmd;
	struct ls_rjt stat;
	uint32_t *lp;
	uint32_t cmd, did, newnode, rjt_err = 0;
	uint32_t drop_cmd = 0;	/* by default do NOT drop received cmd */
	struct lpfc_vport *vport = NULL;

	psli = &phba->sli;
	icmd = &elsiocb->iocb;

	if ((icmd->ulpStatus == IOSTAT_LOCAL_REJECT) &&
		((icmd->un.ulpWord[4] & 0xff) == IOERR_RCV_BUFFER_WAITING)) {
		phba->fc_stat.NoRcvBuf++;
		/* Not enough posted buffers; Try posting more buffers */
		lpfc_post_buffer(phba, pring, 0, 1);
		return;
	}

	/* If there are no BDEs associated with this IOCB,
	 * there is nothing to do.
	 */
	if (icmd->ulpBdeCount == 0)
		return;
	IOCB_t *icmd = &elsiocb->iocb;

		/* type of ELS cmd is first 32bit word in packet */
	mp = lpfc_sli_ringpostbuf_get(phba, pring,
				      getPaddr(icmd->un.cont64[0].addrHigh,
					       icmd->un.cont64[0].addrLow));
	if (mp == 0) {
		drop_cmd = 1;
	if (!vport || !mp)
		goto dropit;
	}

	vport = phba->pport;

	newnode = 0;
	lp = (uint32_t *) mp->virt;
	cmd = *lp++;
	lpfc_post_buffer(phba, &psli->ring[LPFC_ELS_RING], 1, 1);
	if ((phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) == 0)
		lpfc_post_buffer(phba, pring, 1, 1);

	if (icmd->ulpStatus) {
		lpfc_mbuf_free(phba, mp->virt, mp->phys);
		kfree(mp);
		drop_cmd = 1;
	if (icmd->ulpStatus)
		goto dropit;
	}

	/* Check to see if link went down during discovery */
	if (lpfc_els_chk_latt(vport)) {
		lpfc_mbuf_free(phba, mp->virt, mp->phys);
		kfree(mp);
		drop_cmd = 1;
	if (lpfc_els_chk_latt(vport))
		goto dropit;
	}

	did = icmd->un.rcvels.remoteID;
	ndlp = lpfc_findnode_did(vport, did);
	if (!ndlp) {
		/* Cannot find existing Fabric ndlp, so allocate a new one */
		ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL);
		if (!ndlp) {
			lpfc_mbuf_free(phba, mp->virt, mp->phys);
			kfree(mp);
			drop_cmd = 1;
		if (!ndlp)
			goto dropit;
		}

		lpfc_nlp_init(vport, ndlp, did);
		newnode = 1;
@@ -3537,8 +3486,9 @@ lpfc_els_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,

		/* Unknown ELS command <elsCmd> received from NPORT <did> */
		lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
				"%d:0115 Unknown ELS command x%x received from "
				"NPORT x%x\n", phba->brd_no, cmd, did);
				"%d:0115 Unknown ELS command x%x "
				"received from NPORT x%x\n",
				phba->brd_no, cmd, did);
		if (newnode)
			lpfc_drop_node(vport, ndlp);
		break;
@@ -3553,20 +3503,89 @@ lpfc_els_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
		lpfc_els_rsp_reject(vport, stat.un.lsRjtError, elsiocb, ndlp);
	}

	lpfc_nlp_put(elsiocb->context1);
	elsiocb->context1 = NULL;
	if (elsiocb->context2) {
		lpfc_mbuf_free(phba, mp->virt, mp->phys);
		kfree(mp);
	}
	return;

dropit:
	/* check if need to drop received ELS cmd */
	if (drop_cmd == 1) {
	lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
			"%d:0111 Dropping received ELS cmd "
				"Data: x%x x%x x%x\n", phba->brd_no,
			"Data: x%x x%x x%x\n",
			phba->brd_no,
			icmd->ulpStatus, icmd->un.ulpWord[4],
			icmd->ulpTimeout);
	phba->fc_stat.elsRcvDrop++;
}


void
lpfc_els_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
		     struct lpfc_iocbq *elsiocb)
{
	struct lpfc_vport *vport = phba->pport;
	struct lpfc_dmabuf *mp = NULL;
	IOCB_t *icmd = &elsiocb->iocb;
	struct hbq_dmabuf *sp = NULL;
	dma_addr_t paddr;

	if ((icmd->ulpStatus == IOSTAT_LOCAL_REJECT) &&
	    ((icmd->un.ulpWord[4] & 0xff) == IOERR_RCV_BUFFER_WAITING)) {
		phba->fc_stat.NoRcvBuf++;
		/* Not enough posted buffers; Try posting more buffers */
		if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED)
			lpfc_sli_hbqbuf_fill_hbq(phba);
		else
			lpfc_post_buffer(phba, pring, 0, 1);
		return;
	}

	/* If there are no BDEs associated with this IOCB,
	 * there is nothing to do.
	 */
	if (icmd->ulpBdeCount == 0)
		return;

	/* type of ELS cmd is first 32bit word in packet */
	if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) {
		paddr = getPaddr(icmd->un.cont64[0].addrHigh,
				 icmd->un.cont64[0].addrLow);
		sp = lpfc_sli_hbqbuf_find(phba, icmd->un.ulpWord[3]);
		if (sp)
			phba->hbq_buff_count--;
		mp = sp ? &sp->dbuf : NULL;
	} else {
		paddr = getPaddr(icmd->un.cont64[0].addrHigh,
				 icmd->un.cont64[0].addrLow);
		mp = lpfc_sli_ringpostbuf_get(phba, pring, paddr);
	}

	lpfc_els_unsol_buffer(phba, pring, vport, mp, elsiocb);

	lpfc_nlp_put(elsiocb->context1);
	elsiocb->context1 = NULL;
	if (elsiocb->context2) {
		if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED)
			lpfc_sli_free_hbq(phba, sp);
		else {
			lpfc_mbuf_free(phba, mp->virt, mp->phys);
			kfree(mp);
		}
	}

	/* RCV_ELS64_CX provide for 2 BDEs - process 2nd if included */
	if ((phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) != 0 &&
	    icmd->ulpBdeCount == 2) {
		sp = lpfc_sli_hbqbuf_find(phba, icmd->un.ulpWord[15]);
		if (sp)
			phba->hbq_buff_count--;
		mp = sp ? &sp->dbuf : NULL;
		lpfc_els_unsol_buffer(phba, pring, vport, mp, elsiocb);
		/* free mp if we are done with it */
		if (elsiocb->context2) {
			if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED)
				lpfc_sli_free_hbq(phba, sp);
			else {
				lpfc_mbuf_free(phba, mp->virt, mp->phys);
				kfree(mp);
			}
		}
	}
}
+20 −59

File changed.

Preview size limit exceeded, changes collapsed.

Loading