Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

[SCSI] lpfc 8.2.4 : Fix Unsolicited Data items



Fix Drivers Unsolicited CT command handling - we did not handle multiframe
  sequences well.
Fix error due to delay in replenishing buffers for unsolicited data.

Signed-off-by: default avatarJames Smart <James.Smart@emulex.com>
Signed-off-by: default avatarJames Bottomley <James.Bottomley@HansenPartnership.com>
parent 83108bd3
Loading
Loading
Loading
Loading
+34 −58
Original line number Diff line number Diff line
@@ -57,45 +57,27 @@

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,
lpfc_ct_ignore_hbq_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,
		lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
				"0146 Ignoring unsolicted CT No HBQ "
				"status = x%x\n",
				piocbq->iocb.ulpStatus);

	}
	lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
			"0145 Ignoring unsolicted CT HBQ Size:%d "
			"status = x%x\n",
			size, piocbq->iocb.ulpStatus);
}

static void
lpfc_ct_ignore_hbq_buffer(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq,
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 "
		       "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);
	}
	lpfc_ct_ignore_hbq_buffer(phba, piocbq, mp, size);
}

void
@@ -109,11 +91,8 @@ lpfc_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
	struct lpfc_iocbq *iocbq;
	dma_addr_t paddr;
	uint32_t size;
	struct lpfc_dmabuf *bdeBuf1 = piocbq->context2;
	struct lpfc_dmabuf *bdeBuf2 = piocbq->context3;

	piocbq->context2 = NULL;
	piocbq->context3 = NULL;
	struct list_head head;
	struct lpfc_dmabuf *bdeBuf;

	if (unlikely(icmd->ulpStatus == IOSTAT_NEED_BUFFER)) {
		lpfc_sli_hbqbuf_add_hbqs(phba, LPFC_ELS_HBQ);
@@ -122,7 +101,7 @@ lpfc_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
		/* Not enough posted buffers; Try posting more buffers */
		phba->fc_stat.NoRcvBuf++;
		if (!(phba->sli3_options & LPFC_SLI3_HBQ_ENABLED))
			lpfc_post_buffer(phba, pring, 0, 1);
			lpfc_post_buffer(phba, pring, 2, 1);
		return;
	}

@@ -133,38 +112,34 @@ lpfc_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
		return;

	if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) {
		list_for_each_entry(iocbq, &piocbq->list, list) {
		INIT_LIST_HEAD(&head);
		list_add_tail(&head, &piocbq->list);
		list_for_each_entry(iocbq, &head, 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);
			if (icmd->ulpBdeCount == 0)
				continue;
			}

			bdeBuf = iocbq->context2;
			iocbq->context2 = NULL;
			size  = icmd->un.cont64[0].tus.f.bdeSize;
			lpfc_ct_ignore_hbq_buffer(phba, piocbq, bdeBuf1, size);
			lpfc_in_buf_free(phba, bdeBuf1);
			lpfc_ct_unsol_buffer(phba, piocbq, bdeBuf, size);
			lpfc_in_buf_free(phba, bdeBuf);
			if (icmd->ulpBdeCount == 2) {
				lpfc_ct_ignore_hbq_buffer(phba, piocbq, bdeBuf2,
				bdeBuf = iocbq->context3;
				iocbq->context3 = NULL;
				size  = icmd->unsli3.rcvsli3.bde2.tus.f.bdeSize;
				lpfc_ct_unsol_buffer(phba, piocbq, bdeBuf,
						     size);
				lpfc_in_buf_free(phba, bdeBuf2);
				lpfc_in_buf_free(phba, bdeBuf);
			}
		}
		list_del(&head);
	} 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;
			}

			if (icmd->ulpBdeCount == 0)
				lpfc_ct_unsol_buffer(phba, piocbq, NULL, 0);
			for (i = 0; i < icmd->ulpBdeCount; i++) {
				paddr = getPaddr(icmd->un.cont64[i].addrHigh,
						 icmd->un.cont64[i].addrLow);
@@ -176,6 +151,7 @@ lpfc_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
			}
			list_del(&iocbq->list);
			lpfc_sli_release_iocbq(phba, iocbq);
			lpfc_post_buffer(phba, pring, i, 1);
		}
	}
}
+29 −0
Original line number Diff line number Diff line
@@ -2994,6 +2994,34 @@ typedef struct {
#endif
} RCV_ELS_REQ64;

/* IOCB Command template for RCV_SEQ64 */
struct rcv_seq64 {
	struct ulp_bde64 elsReq;
	uint32_t hbq_1;
	uint32_t parmRo;
#ifdef __BIG_ENDIAN_BITFIELD
	uint32_t rctl:8;
	uint32_t type:8;
	uint32_t dfctl:8;
	uint32_t ls:1;
	uint32_t fs:1;
	uint32_t rsvd2:3;
	uint32_t si:1;
	uint32_t bc:1;
	uint32_t rsvd3:1;
#else	/*  __LITTLE_ENDIAN_BITFIELD */
	uint32_t rsvd3:1;
	uint32_t bc:1;
	uint32_t si:1;
	uint32_t rsvd2:3;
	uint32_t fs:1;
	uint32_t ls:1;
	uint32_t dfctl:8;
	uint32_t type:8;
	uint32_t rctl:8;
#endif
};

/* IOCB Command template for all 64 bit FCP Initiator commands */
typedef struct {
	ULP_BDL bdl;
@@ -3085,6 +3113,7 @@ typedef struct _IOCB { /* IOCB structure */
		FCPT_FIELDS64 fcpt64;	/* FCP 64 bit target template */
		ASYNCSTAT_FIELDS asyncstat; /* async_status iocb */
		QUE_XRI64_CX_FIELDS quexri64cx; /* que_xri64_cx fields */
		struct rcv_seq64 rcvseq64;	/* RCV_SEQ64 and RCV_CONT64 */

		uint32_t ulpWord[IOCB_WORD_SZ - 2];	/* generic 6 'words' */
	} un;
+56 −53
Original line number Diff line number Diff line
@@ -955,6 +955,8 @@ lpfc_sli_process_unsol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
	match = 0;
	irsp = &(saveq->iocb);

	if (irsp->ulpStatus == IOSTAT_NEED_BUFFER)
		return 1;
	if (irsp->ulpCommand == CMD_ASYNC_STATUS) {
		if (pring->lpfc_sli_rcv_async_status)
			pring->lpfc_sli_rcv_async_status(phba, pring, saveq);
@@ -970,36 +972,7 @@ lpfc_sli_process_unsol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
		return 1;
	}

	if ((irsp->ulpCommand == CMD_RCV_ELS_REQ64_CX)
	    || (irsp->ulpCommand == CMD_RCV_ELS_REQ_CX)
	    || (irsp->ulpCommand == CMD_IOCB_RCV_ELS64_CX)
	    || (irsp->ulpCommand == CMD_IOCB_RCV_CONT64_CX)) {
		Rctl = FC_ELS_REQ;
		Type = FC_ELS_DATA;
	} else {
		w5p =
		    (WORD5 *) & (saveq->iocb.un.
				 ulpWord[5]);
		Rctl = w5p->hcsw.Rctl;
		Type = w5p->hcsw.Type;

		/* Firmware Workaround */
		if ((Rctl == 0) && (pring->ringno == LPFC_ELS_RING) &&
			(irsp->ulpCommand == CMD_RCV_SEQUENCE64_CX ||
			 irsp->ulpCommand == CMD_IOCB_RCV_SEQ64_CX)) {
			Rctl = FC_ELS_REQ;
			Type = FC_ELS_DATA;
			w5p->hcsw.Rctl = Rctl;
			w5p->hcsw.Type = Type;
		}
	}

	if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) {
		struct lpfc_hbq_entry *hbqe_1, *hbqe_2;
		hbqe_1 = (struct lpfc_hbq_entry *) &saveq->iocb.un.ulpWord[0];
		hbqe_2 = (struct lpfc_hbq_entry *) &saveq->iocb.
				unsli3.sli3Words[4];

		if (irsp->ulpBdeCount != 0) {
			saveq->context2 = lpfc_sli_get_buff(phba, pring,
						irsp->un.ulpWord[3]);
@@ -1011,7 +984,6 @@ lpfc_sli_process_unsol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
					"an unsolicited iocb. tag 0x%x\n",
					pring->ringno,
					irsp->un.ulpWord[3]);

		}
		if (irsp->ulpBdeCount == 2) {
			saveq->context3 = lpfc_sli_get_buff(phba, pring,
@@ -1026,16 +998,11 @@ lpfc_sli_process_unsol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
					irsp->unsli3.sli3Words[7]);
		}
		list_for_each_entry(iocbq, &saveq->list, list) {
			hbqe_1 = (struct lpfc_hbq_entry *) &iocbq->iocb.
				un.ulpWord[0];
			hbqe_2 = (struct lpfc_hbq_entry *) &iocbq->iocb.
				unsli3.sli3Words[4];
			irsp = &(iocbq->iocb);

			if (irsp->ulpBdeCount != 0) {
				iocbq->context2 = lpfc_sli_get_buff(phba, pring,
							irsp->un.ulpWord[3]);
				if (!saveq->context2)
				if (!iocbq->context2)
					lpfc_printf_log(phba,
						KERN_ERR,
						LOG_SLI,
@@ -1047,7 +1014,7 @@ lpfc_sli_process_unsol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
			if (irsp->ulpBdeCount == 2) {
				iocbq->context3 = lpfc_sli_get_buff(phba, pring,
						irsp->unsli3.sli3Words[7]);
				if (!saveq->context3)
				if (!iocbq->context3)
					lpfc_printf_log(phba,
						KERN_ERR,
						LOG_SLI,
@@ -1059,6 +1026,49 @@ lpfc_sli_process_unsol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
			}
		}
	}
	if (irsp->ulpBdeCount != 0 &&
	    (irsp->ulpCommand == CMD_IOCB_RCV_CONT64_CX ||
	     irsp->ulpStatus == IOSTAT_INTERMED_RSP)) {
		int found = 0;

		/* search continue save q for same XRI */
		list_for_each_entry(iocbq, &pring->iocb_continue_saveq, clist) {
			if (iocbq->iocb.ulpContext == saveq->iocb.ulpContext) {
				list_add_tail(&saveq->list, &iocbq->list);
				found = 1;
				break;
			}
		}
		if (!found)
			list_add_tail(&saveq->clist,
				      &pring->iocb_continue_saveq);
		if (saveq->iocb.ulpStatus != IOSTAT_INTERMED_RSP) {
			list_del_init(&iocbq->clist);
			saveq = iocbq;
			irsp = &(saveq->iocb);
		} else
			return 0;
	}
	if ((irsp->ulpCommand == CMD_RCV_ELS_REQ64_CX) ||
	    (irsp->ulpCommand == CMD_RCV_ELS_REQ_CX) ||
	    (irsp->ulpCommand == CMD_IOCB_RCV_ELS64_CX)) {
		Rctl = FC_ELS_REQ;
		Type = FC_ELS_DATA;
	} else {
		w5p = (WORD5 *)&(saveq->iocb.un.ulpWord[5]);
		Rctl = w5p->hcsw.Rctl;
		Type = w5p->hcsw.Type;

		/* Firmware Workaround */
		if ((Rctl == 0) && (pring->ringno == LPFC_ELS_RING) &&
			(irsp->ulpCommand == CMD_RCV_SEQUENCE64_CX ||
			 irsp->ulpCommand == CMD_IOCB_RCV_SEQ64_CX)) {
			Rctl = FC_ELS_REQ;
			Type = FC_ELS_DATA;
			w5p->hcsw.Rctl = Rctl;
			w5p->hcsw.Type = Type;
		}
	}

	/* unSolicited Responses */
	if (pring->prt[0].profile) {
@@ -1069,12 +1079,9 @@ lpfc_sli_process_unsol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
	} else {
		/* We must search, based on rctl / type
		   for the right routine */
		for (i = 0; i < pring->num_mask;
		     i++) {
			if ((pring->prt[i].rctl ==
			     Rctl)
			    && (pring->prt[i].
				type == Type)) {
		for (i = 0; i < pring->num_mask; i++) {
			if ((pring->prt[i].rctl == Rctl)
			    && (pring->prt[i].type == Type)) {
				if (pring->prt[i].lpfc_sli_rcv_unsol_event)
					(pring->prt[i].lpfc_sli_rcv_unsol_event)
							(phba, pring, saveq);
@@ -1641,12 +1648,7 @@ lpfc_sli_handle_slow_ring_event(struct lpfc_hba *phba,

		writel(pring->rspidx, &phba->host_gp[pring->ringno].rspGetInx);

		if (list_empty(&(pring->iocb_continueq))) {
			list_add(&rspiocbp->list, &(pring->iocb_continueq));
		} else {
			list_add_tail(&rspiocbp->list,
				      &(pring->iocb_continueq));
		}
		list_add_tail(&rspiocbp->list, &(pring->iocb_continueq));

		pring->iocb_continueq_cnt++;
		if (irsp->ulpLe) {
@@ -1711,17 +1713,17 @@ lpfc_sli_handle_slow_ring_event(struct lpfc_hba *phba,
			iocb_cmd_type = irsp->ulpCommand & CMD_IOCB_MASK;
			type = lpfc_sli_iocb_cmd_type(iocb_cmd_type);
			if (type == LPFC_SOL_IOCB) {
				spin_unlock_irqrestore(&phba->hbalock,
						       iflag);
				spin_unlock_irqrestore(&phba->hbalock, iflag);
				rc = lpfc_sli_process_sol_iocb(phba, pring,
							       saveq);
				spin_lock_irqsave(&phba->hbalock, iflag);
			} else if (type == LPFC_UNSOL_IOCB) {
				spin_unlock_irqrestore(&phba->hbalock,
						       iflag);
				spin_unlock_irqrestore(&phba->hbalock, iflag);
				rc = lpfc_sli_process_unsol_iocb(phba, pring,
								 saveq);
				spin_lock_irqsave(&phba->hbalock, iflag);
				if (!rc)
					free_saveq = 0;
			} else if (type == LPFC_ABORT_IOCB) {
				if ((irsp->ulpCommand != CMD_XRI_ABORTED_CX) &&
				    ((cmdiocbp =
@@ -3238,6 +3240,7 @@ lpfc_sli_queue_setup(struct lpfc_hba *phba)
		INIT_LIST_HEAD(&pring->txq);
		INIT_LIST_HEAD(&pring->txcmplq);
		INIT_LIST_HEAD(&pring->iocb_continueq);
		INIT_LIST_HEAD(&pring->iocb_continue_saveq);
		INIT_LIST_HEAD(&pring->postbufq);
	}
	spin_unlock_irq(&phba->hbalock);
+2 −0
Original line number Diff line number Diff line
@@ -33,6 +33,7 @@ typedef enum _lpfc_ctx_cmd {
struct lpfc_iocbq {
	/* lpfc_iocbqs are used in double linked lists */
	struct list_head list;
	struct list_head clist;
	uint16_t iotag;         /* pre-assigned IO tag */
	uint16_t rsvd1;

@@ -160,6 +161,7 @@ struct lpfc_sli_ring {
	struct list_head iocb_continueq;
	uint16_t iocb_continueq_cnt;	/* current length of queue */
	uint16_t iocb_continueq_max;	/* max length */
	struct list_head iocb_continue_saveq;

	struct lpfc_sli_ring_mask prt[LPFC_MAX_RING_MASK];
	uint32_t num_mask;	/* number of mask entries in prt array */