--- old/usr/src/uts/common/io/cxgbe/t4nex/t4_sge.c	Mon Aug  5 17:28:10 2019
+++ new/usr/src/uts/common/io/cxgbe/t4nex/t4_sge.c	Mon Aug  5 17:28:10 2019
@@ -693,7 +693,6 @@
 uint_t
 t4_intr(caddr_t arg1, caddr_t arg2)
 {
-	/* LINTED: E_BAD_PTR_CAST_ALIGN */
 	struct sge_iq *iq = (struct sge_iq *)arg2;
 	int state;
 
@@ -776,10 +775,8 @@
 					goto done;
 
 				m = get_fl_payload(sc, fl, lq, &fl_bufs_used);
-				if (m == NULL) {
-					panic("%s: line %d.", __func__,
-					    __LINE__);
-				}
+				if (m == NULL)
+					goto done;
 
 				iq->intr_next = iq->intr_params;
 				m->b_rptr += sc->sge.pktshift;
@@ -809,10 +806,9 @@
 			}
 
 			m = get_fl_payload(sc, fl, lq, &fl_bufs_used);
-			if (m == NULL) {
-				panic("%s: line %d.", __func__,
-				    __LINE__);
-			}
+			if (m == NULL)
+				goto done;
+			/* FALLTHROUGH */
 
 		case X_RSPD_TYPE_CPL:
 			ASSERT(rss->opcode < NUM_CPL_CMDS);
@@ -861,6 +857,7 @@
 	int ndescs = 0, limit, fl_bufs_used = 0;
 	int rsp_type;
 	uint32_t lq;
+	int starved;
 	mblk_t *m;
 	STAILQ_HEAD(, sge_iq) iql = STAILQ_HEAD_INITIALIZER(iql);
 
@@ -887,8 +884,23 @@
 
 				m = get_fl_payload(sc, fl, lq, &fl_bufs_used);
 				if (m == NULL) {
-					panic("%s: line %d.", __func__,
-					    __LINE__);
+					/*
+					 * Rearm the iq with a
+					 * longer-than-default timer
+					 */
+					t4_write_reg(sc, MYPF_REG(A_SGE_PF_GTS), V_CIDXINC(ndescs) |
+							V_INGRESSQID((u32)iq->cntxt_id) |
+							V_SEINTARM(V_QINTR_TIMER_IDX(SGE_NTIMERS-1)));
+					if (fl_bufs_used > 0) {
+						ASSERT(iq->flags & IQ_HAS_FL);
+						FL_LOCK(fl);
+						fl->needed += fl_bufs_used;
+						starved = refill_fl(sc, fl, fl->cap / 8);
+						FL_UNLOCK(fl);
+						if (starved)
+							add_fl_to_sfl(sc, fl);
+					}
+					return (0);
 				}
 
 			/* FALLTHRU */
@@ -968,7 +980,6 @@
 	    V_INGRESSQID((u32)iq->cntxt_id) | V_SEINTARM(iq->intr_next));
 
 	if (iq->flags & IQ_HAS_FL) {
-		int starved;
 
 		FL_LOCK(fl);
 		fl->needed += fl_bufs_used;
@@ -1253,6 +1264,7 @@
 {
 
 	fl->qsize = qsize;
+	fl->allocb_fail = 0;
 }
 
 static inline void
@@ -1687,7 +1699,8 @@
 	    V_FW_EQ_ETH_CMD_VFN(0));
 	c.alloc_to_len16 = BE_32(F_FW_EQ_ETH_CMD_ALLOC |
 	    F_FW_EQ_ETH_CMD_EQSTART | FW_LEN16(c));
-	c.autoequiqe_to_viid = BE_32(V_FW_EQ_ETH_CMD_VIID(pi->viid));
+	c.autoequiqe_to_viid = BE_32(F_FW_EQ_ETH_CMD_AUTOEQUIQE |
+	    F_FW_EQ_ETH_CMD_AUTOEQUEQE | V_FW_EQ_ETH_CMD_VIID(pi->viid));
 	c.fetchszm_to_iqid =
 	    BE_32(V_FW_EQ_ETH_CMD_HOSTFCMODE(X_HOSTFCMODE_STATUS_PAGE) |
 	    V_FW_EQ_ETH_CMD_PCIECHN(eq->tx_chan) | F_FW_EQ_ETH_CMD_FETCHRO |
@@ -2330,7 +2343,7 @@
 	struct rxbuf *rxb;
 	mblk_t *m = NULL;
 	uint_t nbuf = 0, len, copy, n;
-	uint32_t cidx, offset;
+	uint32_t cidx, offset, rcidx, roffset;
 
 	/*
 	 * The SGE won't pack a new frame into the current buffer if the entire
@@ -2337,6 +2350,8 @@
 	 * payload doesn't fit in the remaining space.  Move on to the next buf
 	 * in that case.
 	 */
+	rcidx = fl->cidx;
+	roffset = fl->offset;
 	if (fl->offset > 0 && len_newbuf & F_RSPD_NEWBUF) {
 		fl->offset = 0;
 		if (++fl->cidx == fl->cap)
@@ -2350,8 +2365,15 @@
 	copy = (len <= fl->copy_threshold);
 	if (copy != 0) {
 		frame.head = m = allocb(len, BPRI_HI);
-		if (m == NULL)
+		if (m == NULL) {
+			fl->allocb_fail++;
+			cmn_err(CE_WARN,"%s: mbuf allocation failure "
+					"count = %llu", __func__,
+					(unsigned long long)fl->allocb_fail);
+			fl->cidx = rcidx;
+			fl->offset = roffset;
 			return (NULL);
+		}
 	}
 
 	while (len) {
@@ -2367,7 +2389,15 @@
 			m = desballoc((unsigned char *)rxb->va + offset, n,
 			    BPRI_HI, &rxb->freefunc);
 			if (m == NULL) {
-				freemsg(frame.head);
+				fl->allocb_fail++;
+				cmn_err(CE_WARN,
+					"%s: mbuf allocation failure "
+					"count = %llu", __func__,
+					(unsigned long long)fl->allocb_fail);
+				if (frame.head)
+					freemsgchain(frame.head);
+				fl->cidx = rcidx;
+				fl->offset = roffset;
 				return (NULL);
 			}
 			atomic_inc_uint(&rxb->ref_cnt);
@@ -3346,6 +3376,16 @@
 	fl->pending -= ndesc * 8;
 }
 
+static void
+tx_reclaim_task(void *arg)
+{
+	struct sge_txq *txq = arg;
+
+	TXQ_LOCK(txq);
+	reclaim_tx_descs(txq, txq->eq.qsize);
+	TXQ_UNLOCK(txq);
+}
+
 /* ARGSUSED */
 static int
 handle_sge_egr_update(struct sge_iq *iq, const struct rss_header *rss,
@@ -3355,12 +3395,17 @@
 	unsigned int qid = G_EGR_QID(ntohl(cpl->opcode_qid));
 	struct adapter *sc = iq->adapter;
 	struct sge *s = &sc->sge;
+	struct sge_eq *eq;
 	struct sge_txq *txq;
 
 	txq = (void *)s->eqmap[qid - s->eq_start];
+	eq = &txq->eq;
 	txq->qflush++;
 	t4_mac_tx_update(txq->port, txq);
 
+	ddi_taskq_dispatch(sc->tq[eq->tx_chan], tx_reclaim_task,
+		(void *)txq, DDI_NOSLEEP);
+
 	return (0);
 }
 
