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

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

[SCSI] lpfc 8.2.3 : Internal loopback fixes



Internal loopback fixes:
- Use HBQs rather than Q_RING_BUFF
- Correct HBQs continuation entries
- Update CT handler to SLI3 iocbs

Signed-off-by: default avatarJames Smart <James.Smart@emulex.com>
Signed-off-by: default avatarJames Bottomley <James.Bottomley@HansenPartnership.com>
parent a8adb832
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -68,6 +68,7 @@ struct lpfc_dmabuf {
	struct list_head list;
	void *virt;		/* virtual address ptr */
	dma_addr_t phys;	/* mapped address */
	uint32_t   buffer_tag;	/* used for tagged queue ring */
};

struct lpfc_dma_pool {
@@ -582,6 +583,12 @@ struct lpfc_hba {
	unsigned long last_completion_time;
	struct timer_list hb_tmofunc;
	uint8_t hb_outstanding;
	/*
	 * Following bit will be set for all buffer tags which are not
	 * associated with any HBQ.
	 */
#define QUE_BUFTAG_BIT  (1<<31)
	uint32_t buffer_tag_count;
};

static inline struct Scsi_Host *
+5 −0
Original line number Diff line number Diff line
@@ -211,6 +211,11 @@ 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);

uint32_t lpfc_sli_get_buffer_tag(struct lpfc_hba *);
struct lpfc_dmabuf * lpfc_sli_ring_taggedbuf_get(struct lpfc_hba *,
			struct lpfc_sli_ring *, uint32_t );

int lpfc_sli_hbq_count(void);
int lpfc_sli_hbqbuf_init_hbqs(struct lpfc_hba *, uint32_t);
int lpfc_sli_hbqbuf_add_hbqs(struct lpfc_hba *, uint32_t);
+25 −6
Original line number Diff line number Diff line
@@ -1373,6 +1373,7 @@ typedef struct { /* FireFly BIU registers */
#define CMD_FCP_TRECEIVE64_CX   0xA1
#define CMD_FCP_TRSP64_CX       0xA3

#define CMD_QUE_XRI64_CX	0xB3
#define CMD_IOCB_RCV_SEQ64_CX	0xB5
#define CMD_IOCB_RCV_ELS64_CX	0xB7
#define CMD_IOCB_RCV_CONT64_CX	0xBB
@@ -3039,7 +3040,26 @@ struct rcv_sli3 {
	struct ulp_bde64 bde2;
};

/* Structure used for a single HBQ entry */
struct lpfc_hbq_entry {
	struct ulp_bde64 bde;
	uint32_t buffer_tag;
};

/* IOCB Command template for QUE_XRI64_CX (0xB3) command */
typedef struct {
	struct lpfc_hbq_entry   buff;
	uint32_t                rsvd;
	uint32_t		rsvd1;
} QUE_XRI64_CX_FIELDS;

struct que_xri64cx_ext_fields {
	uint32_t	iotag64_low;
	uint32_t	iotag64_high;
	uint32_t	ebde_count;
	uint32_t	rsvd;
	struct lpfc_hbq_entry	buff[5];
};

typedef struct _IOCB {	/* IOCB structure */
	union {
@@ -3064,6 +3084,7 @@ typedef struct _IOCB { /* IOCB structure */
		FCPI_FIELDS64 fcpi64;	/* FCP 64 bit Initiator template */
		FCPT_FIELDS64 fcpt64;	/* FCP 64 bit target template */
		ASYNCSTAT_FIELDS asyncstat; /* async_status iocb */
		QUE_XRI64_CX_FIELDS quexri64cx; /* que_xri64_cx fields */

		uint32_t ulpWord[IOCB_WORD_SZ - 2];	/* generic 6 'words' */
	} un;
@@ -3121,6 +3142,10 @@ typedef struct _IOCB { /* IOCB structure */

	union {
		struct rcv_sli3 rcvsli3; /* words 8 - 15 */

		/* words 8-31 used for que_xri_cx iocb */
		struct que_xri64cx_ext_fields que_xri64cx_ext_words;

		uint32_t sli3Words[24]; /* 96 extra bytes for SLI-3 */
	} unsli3;

@@ -3160,12 +3185,6 @@ typedef struct _IOCB { /* IOCB structure */

} IOCB_t;

/* Structure used for a single HBQ entry */
struct lpfc_hbq_entry {
	struct ulp_bde64 bde;
	uint32_t buffer_tag;
};


#define SLI1_SLIM_SIZE   (4 * 1024)

+116 −7
Original line number Diff line number Diff line
@@ -931,6 +931,16 @@ lpfc_sli_replace_hbqbuff(struct lpfc_hba *phba, uint32_t tag)
	return &new_hbq_entry->dbuf;
}

static struct lpfc_dmabuf *
lpfc_sli_get_buff(struct lpfc_hba *phba,
			struct lpfc_sli_ring *pring,
			uint32_t tag)
{
	if (tag & QUE_BUFTAG_BIT)
		return lpfc_sli_ring_taggedbuf_get(phba, pring, tag);
	else
		return lpfc_sli_replace_hbqbuff(phba, tag);
}

static int
lpfc_sli_process_unsol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
@@ -940,6 +950,7 @@ lpfc_sli_process_unsol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
	WORD5            * w5p;
	uint32_t           Rctl, Type;
	uint32_t           match, i;
	struct lpfc_iocbq *iocbq;

	match = 0;
	irsp = &(saveq->iocb);
@@ -984,13 +995,70 @@ lpfc_sli_process_unsol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
	}

	if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) {
		if (irsp->ulpBdeCount != 0)
			saveq->context2 = lpfc_sli_replace_hbqbuff(phba,
		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]);
			if (!saveq->context2)
				lpfc_printf_log(phba,
					KERN_ERR,
					LOG_SLI,
					"0341 Ring %d Cannot find buffer for "
					"an unsolicited iocb. tag 0x%x\n",
					pring->ringno,
					irsp->un.ulpWord[3]);
		if (irsp->ulpBdeCount == 2)
			saveq->context3 = lpfc_sli_replace_hbqbuff(phba,

		}
		if (irsp->ulpBdeCount == 2) {
			saveq->context3 = lpfc_sli_get_buff(phba, pring,
						irsp->unsli3.sli3Words[7]);
			if (!saveq->context3)
				lpfc_printf_log(phba,
					KERN_ERR,
					LOG_SLI,
					"0342 Ring %d Cannot find buffer for an"
					" unsolicited iocb. tag 0x%x\n",
					pring->ringno,
					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)
					lpfc_printf_log(phba,
						KERN_ERR,
						LOG_SLI,
						"0343 Ring %d Cannot find "
						"buffer for an unsolicited iocb"
						". tag 0x%x\n", pring->ringno,
						irsp->un.ulpWord[3]);
			}
			if (irsp->ulpBdeCount == 2) {
				iocbq->context3 = lpfc_sli_get_buff(phba, pring,
						irsp->unsli3.sli3Words[7]);
				if (!saveq->context3)
					lpfc_printf_log(phba,
						KERN_ERR,
						LOG_SLI,
						"0344 Ring %d Cannot find "
						"buffer for an unsolicited "
						"iocb. tag 0x%x\n",
						pring->ringno,
						irsp->unsli3.sli3Words[7]);
			}
		}
	}

	/* unSolicited Responses */
	if (pring->prt[0].profile) {
@@ -2480,7 +2548,7 @@ lpfc_mbox_timeout_handler(struct lpfc_hba *phba)
	lpfc_sli_abort_iocb_ring(phba, pring);

	lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI,
			"0316 Resetting board due to mailbox timeout\n");
			"0345 Resetting board due to mailbox timeout\n");
	/*
	 * lpfc_offline calls lpfc_sli_hba_down which will clean up
	 * on oustanding mailbox commands.
@@ -2975,7 +3043,7 @@ lpfc_sli_async_event_handler(struct lpfc_hba * phba,
		lpfc_printf_log(phba,
			KERN_ERR,
			LOG_SLI,
			"0327 Ring %d handler: unexpected ASYNC_STATUS"
			"0346 Ring %d handler: unexpected ASYNC_STATUS"
			" evt_code 0x%x\n",
			pring->ringno,
			icmd->un.asyncstat.evt_code);
@@ -2988,7 +3056,7 @@ lpfc_sli_async_event_handler(struct lpfc_hba * phba,
		lpfc_printf_log(phba,
				KERN_WARNING,
				LOG_TEMP,
				"0339 Adapter is very hot, please take "
				"0347 Adapter is very hot, please take "
				"corrective action. temperature : %d Celsius\n",
				temp);
	}
@@ -3314,6 +3382,47 @@ lpfc_sli_ringpostbuf_put(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
	return 0;
}

uint32_t
lpfc_sli_get_buffer_tag(struct lpfc_hba *phba)
{
	spin_lock_irq(&phba->hbalock);
	phba->buffer_tag_count++;
	/*
	 * Always set the QUE_BUFTAG_BIT to distiguish between
	 * a tag assigned by HBQ.
	 */
	phba->buffer_tag_count |= QUE_BUFTAG_BIT;
	spin_unlock_irq(&phba->hbalock);
	return phba->buffer_tag_count;
}

struct lpfc_dmabuf *
lpfc_sli_ring_taggedbuf_get(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
			uint32_t tag)
{
	struct lpfc_dmabuf *mp, *next_mp;
	struct list_head *slp = &pring->postbufq;

	/* Search postbufq, from the begining, looking for a match on tag */
	spin_lock_irq(&phba->hbalock);
	list_for_each_entry_safe(mp, next_mp, &pring->postbufq, list) {
		if (mp->buffer_tag == tag) {
			list_del_init(&mp->list);
			pring->postbufq_cnt--;
			spin_unlock_irq(&phba->hbalock);
			return mp;
		}
	}

	spin_unlock_irq(&phba->hbalock);
	lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
			"0410 Cannot find virtual addr for buffer tag on "
			"ring %d Data x%lx x%p x%p x%x\n",
			pring->ringno, (unsigned long) tag,
			slp->next, slp->prev, pring->postbufq_cnt);

	return NULL;
}

struct lpfc_dmabuf *
lpfc_sli_ringpostbuf_get(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,