Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 24 Nov 2015 02:37:17 +0000 (UTC)
From:      Navdeep Parhar <np@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-projects@freebsd.org
Subject:   svn commit: r291232 - in projects/cxl_iscsi/sys/dev/cxgbe: cxgbei tom
Message-ID:  <201511240237.tAO2bHZG016097@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: np
Date: Tue Nov 24 02:37:16 2015
New Revision: 291232
URL: https://svnweb.freebsd.org/changeset/base/291232

Log:
  cxgbe/cxgbei: Various changes in the rx path.
  
  - In the iSCSI CPL handlers, do not rely on the ulpcb/icl_conn when in
    the middle of assembling a PDU.  This is so we don't have to grab
    various locks and evaluate the kernel state of the connection multiple
    times.  Instead, the state is evaluated once after the entire PDU is
    received.  This requires another ULP specific item in toepcb (ulpcb2).
  
  - If there is data in the so_rcv sockbuf of a connection in iSCSI ULP
    mode it must be from before the connection got promoted to ULP mode.
    Convert the contents of the sockbuf to PDUs and deliver them to ICL.
    Do this before delivering the PDUs received on the "normal" ULP path.
  
  - The receive path within ICL is allowed to sleep so it's not
    appropriate to deliver PDUs to ICL from the driver's ithread, or from
    any other thread with any mutex held.  Use worker threads (created
    back in r285650 but unused till now) to dispatch received PDUs to ICL.
    Assign a worker thread to each connection.  For now everything goes to
    the first thread.
  
  - Prevent various bad races that are possible when more than one of
    a) rx ithread, b) worker thread, and c) icl_conn_close are active at
    the same time.

Modified:
  projects/cxl_iscsi/sys/dev/cxgbe/cxgbei/cxgbei.c
  projects/cxl_iscsi/sys/dev/cxgbe/cxgbei/cxgbei.h
  projects/cxl_iscsi/sys/dev/cxgbe/cxgbei/icl_cxgbei.c
  projects/cxl_iscsi/sys/dev/cxgbe/tom/t4_tom.h

Modified: projects/cxl_iscsi/sys/dev/cxgbe/cxgbei/cxgbei.c
==============================================================================
--- projects/cxl_iscsi/sys/dev/cxgbe/cxgbei/cxgbei.c	Tue Nov 24 02:30:59 2015	(r291231)
+++ projects/cxl_iscsi/sys/dev/cxgbe/cxgbei/cxgbei.c	Tue Nov 24 02:37:16 2015	(r291232)
@@ -93,6 +93,7 @@ __FBSDID("$FreeBSD$");
 /* XXXNP some header instead. */
 struct icl_pdu *icl_cxgbei_new_pdu(int);
 void icl_cxgbei_new_pdu_set_conn(struct icl_pdu *, struct icl_conn *);
+void icl_cxgbei_conn_pdu_free(struct icl_conn *, struct icl_pdu *);
 
 /*
  * Direct Data Placement -
@@ -530,27 +531,23 @@ do_rx_iscsi_hdr(struct sge_iq *iq, const
 	struct cpl_iscsi_hdr *cpl = mtod(m, struct cpl_iscsi_hdr *);
 	u_int tid = GET_TID(cpl);
 	struct toepcb *toep = lookup_tid(sc, tid);
-	struct icl_cxgbei_conn *icc = toep->ulpcb;
 	struct icl_pdu *ip;
 	struct icl_cxgbei_pdu *icp;
 
-	MPASS(icc != NULL);
-	MPASS(icc->icc_signature == CXGBEI_CONN_SIGNATURE);
 	M_ASSERTPKTHDR(m);
 
 	ip = icl_cxgbei_new_pdu(M_NOWAIT);
 	if (ip == NULL)
 		CXGBE_UNIMPLEMENTED("PDU allocation failure");
-	icl_cxgbei_new_pdu_set_conn(ip, &icc->ic);
 	icp = ip_to_icp(ip);
 	bcopy(mtod(m, caddr_t) + sizeof(*cpl), icp->ip.ip_bhs, sizeof(struct
 	    iscsi_bhs));
+	icp->pdu_seq = ntohl(cpl->seq);
 	icp->pdu_flags = SBUF_ULP_FLAG_HDR_RCVD;
 
 	/* This is the start of a new PDU.  There should be no old state. */
-	MPASS(icc->icp == NULL);
-	icc->icp = icp;
-	icc->pdu_seq = ntohl(cpl->seq);
+	MPASS(toep->ulpcb2 == NULL);
+	toep->ulpcb2 = icp;
 
 #if 0
 	CTR4(KTR_CXGBE, "%s: tid %u, cpl->len hlen %u, m->m_len hlen %u",
@@ -568,11 +565,8 @@ do_rx_iscsi_data(struct sge_iq *iq, cons
 	struct cpl_iscsi_data *cpl =  mtod(m, struct cpl_iscsi_data *);
 	u_int tid = GET_TID(cpl);
 	struct toepcb *toep = lookup_tid(sc, tid);
-	struct icl_cxgbei_conn *icc = toep->ulpcb;
-	struct icl_cxgbei_pdu *icp = icc->icp;
+	struct icl_cxgbei_pdu *icp = toep->ulpcb2;
 
-	MPASS(icc != NULL);
-	MPASS(icc->icc_signature == CXGBEI_CONN_SIGNATURE);
 	M_ASSERTPKTHDR(m);
 
 	/* Must already have received the header (but not the data). */
@@ -603,29 +597,49 @@ do_rx_iscsi_ddp(struct sge_iq *iq, const
 	u_int tid = GET_TID(cpl);
 	struct toepcb *toep = lookup_tid(sc, tid);
 	struct inpcb *inp = toep->inp;
+	struct socket *so;
+	struct sockbuf *sb;
 	struct tcpcb *tp;
-	struct icl_cxgbei_conn *icc = toep->ulpcb;
-	struct icl_conn *ic = &icc->ic;
-	struct icl_cxgbei_pdu *icp = icc->icp;
+	struct icl_cxgbei_conn *icc;
+	struct icl_conn *ic;
+	struct icl_cxgbei_pdu *icp = toep->ulpcb2;
+	struct icl_pdu *ip;
 	u_int pdu_len, val;
 
-	MPASS(icc != NULL);
-	MPASS(icc->icc_signature == CXGBEI_CONN_SIGNATURE);
 	MPASS(m == NULL);
 
 	/* Must already be assembling a PDU. */
 	MPASS(icp != NULL);
 	MPASS(icp->pdu_flags & SBUF_ULP_FLAG_HDR_RCVD);	/* Data is optional. */
-
+	ip = &icp->ip;
 	icp->pdu_flags |= SBUF_ULP_FLAG_STATUS_RCVD;
-
+	val = ntohl(cpl->ddpvld);
+	if (val & F_DDP_PADDING_ERR)
+		icp->pdu_flags |= SBUF_ULP_FLAG_PAD_ERROR;
+	if (val & F_DDP_HDRCRC_ERR)
+		icp->pdu_flags |= SBUF_ULP_FLAG_HCRC_ERROR;
+	if (val & F_DDP_DATACRC_ERR)
+		icp->pdu_flags |= SBUF_ULP_FLAG_DCRC_ERROR;
+	if (ip->ip_data_mbuf == NULL) {
+		/* XXXNP: what should ip->ip_data_len be, and why? */
+		icp->pdu_flags |= SBUF_ULP_FLAG_DATA_DDPED;
+	}
 	pdu_len = ntohs(cpl->len);	/* includes everything. */
 
 	INP_WLOCK(inp);
-	/* XXXNP: check inp for dropped etc., and toep for abort in progress. */
+	if (__predict_false(inp->inp_flags & (INP_DROPPED | INP_TIMEWAIT))) {
+		CTR4(KTR_CXGBE, "%s: tid %u, rx (%d bytes), inp_flags 0x%x",
+		    __func__, tid, pdu_len, inp->inp_flags);
+		INP_WUNLOCK(inp);
+		icl_cxgbei_conn_pdu_free(NULL, ip);
+#ifdef INVARIANTS
+		toep->ulpcb2 = NULL;
+#endif
+		return (0);
+	}
 
 	tp = intotcpcb(inp);
-	MPASS(icc->pdu_seq == tp->rcv_nxt);
+	MPASS(icp->pdu_seq == tp->rcv_nxt);
 	MPASS(tp->rcv_wnd >= pdu_len);
 	tp->rcv_nxt += pdu_len;
 	tp->rcv_wnd -= pdu_len;
@@ -634,25 +648,93 @@ do_rx_iscsi_ddp(struct sge_iq *iq, const
 	/* update rx credits */
 	toep->rx_credits += pdu_len;
 	t4_rcvd(&toep->td->tod, tp);	/* XXX: sc->tom_softc.tod */
-	INP_WUNLOCK(inp);
 
-	val = ntohl(cpl->ddpvld);
-	if (val & F_DDP_PADDING_ERR)
-		icp->pdu_flags |= SBUF_ULP_FLAG_PAD_ERROR;
-	if (val & F_DDP_HDRCRC_ERR)
-		icp->pdu_flags |= SBUF_ULP_FLAG_HCRC_ERROR;
-	if (val & F_DDP_DATACRC_ERR)
-		icp->pdu_flags |= SBUF_ULP_FLAG_DCRC_ERROR;
-	if (icp->ip.ip_data_mbuf == NULL)
-		icp->pdu_flags |= SBUF_ULP_FLAG_DATA_DDPED;
+	so = inp->inp_socket;
+	sb = &so->so_rcv;
+	SOCKBUF_LOCK(sb);
+
+	icc = toep->ulpcb;
+	if (__predict_false(icc == NULL || sb->sb_state & SBS_CANTRCVMORE)) {
+		CTR5(KTR_CXGBE,
+		    "%s: tid %u, excess rx (%d bytes), icc %p, sb_state 0x%x",
+		    __func__, tid, pdu_len, icc, sb->sb_state);
+		SOCKBUF_UNLOCK(sb);
+		INP_WUNLOCK(inp);
+
+		INP_INFO_RLOCK(&V_tcbinfo);
+		INP_WLOCK(inp);
+		tp = tcp_drop(tp, ECONNRESET);
+		if (tp)
+			INP_WUNLOCK(inp);
+		INP_INFO_RUNLOCK(&V_tcbinfo);
+
+		icl_cxgbei_conn_pdu_free(NULL, ip);
+#ifdef INVARIANTS
+		toep->ulpcb2 = NULL;
+#endif
+		return (0);
+	}
+	MPASS(icc->icc_signature == CXGBEI_CONN_SIGNATURE);
+	ic = &icc->ic;
+	icl_cxgbei_new_pdu_set_conn(ip, ic);
+
+	MPASS(m == NULL); /* was unused, we'll use it now. */
+	m = sbcut_locked(sb, sbused(sb)); /* XXXNP: toep->sb_cc accounting? */
+	if (__predict_false(m != NULL)) {
+		int len = m_length(m, NULL);
+
+		/*
+		 * PDUs were received before the tid transitioned to ULP mode.
+		 * Convert them to icl_cxgbei_pdus and send them to ICL before
+		 * the PDU in icp/ip.
+		 */
+		CTR3(KTR_CXGBE, "%s: tid %u, %u bytes in so_rcv", __func__, tid,
+		    len);
+
+		/* XXXNP: needs to be rewritten. */
+		if (len == sizeof(struct iscsi_bhs) || len == 4 + sizeof(struct
+		    iscsi_bhs)) {
+			struct icl_cxgbei_pdu *icp0;
+			struct icl_pdu *ip0;
+
+			ip0 = icl_cxgbei_new_pdu(M_NOWAIT);
+			icl_cxgbei_new_pdu_set_conn(ip0, ic);
+			if (ip0 == NULL)
+				CXGBE_UNIMPLEMENTED("PDU allocation failure");
+			icp0 = ip_to_icp(ip0);
+			icp0->pdu_seq = 0; /* XXX */
+			icp0->pdu_flags = SBUF_ULP_FLAG_HDR_RCVD |
+			    SBUF_ULP_FLAG_STATUS_RCVD;
+			m_copydata(m, 0, sizeof(struct iscsi_bhs), (void *)ip0->ip_bhs);
+			STAILQ_INSERT_TAIL(&icc->rcvd_pdus, ip0, ip_next);
+		}
+		m_freem(m);
+	}
 
 #if 0
 	CTR4(KTR_CXGBE, "%s: tid %u, pdu_len %u, pdu_flags 0x%x",
 	    __func__, tid, pdu_len, icp->pdu_flags);
 #endif
 
-	icc->icp = NULL;
-	ic->ic_receive(&icp->ip);
+	STAILQ_INSERT_TAIL(&icc->rcvd_pdus, ip, ip_next);
+	if ((icc->rx_flags & RXF_ACTIVE) == 0) {
+		struct cxgbei_worker_thread_softc *cwt = icc->cwt;
+
+		mtx_lock(&cwt->cwt_lock);
+		icc->rx_flags |= RXF_ACTIVE;
+		TAILQ_INSERT_TAIL(&cwt->rx_head, icc, rx_link);
+		if (cwt->cwt_state == CWT_SLEEPING) {
+			cwt->cwt_state = CWT_RUNNING;
+			cv_signal(&cwt->cwt_cv);
+		}
+		mtx_unlock(&cwt->cwt_lock);
+	}
+	SOCKBUF_UNLOCK(sb);
+	INP_WUNLOCK(inp);
+
+#ifdef INVARIANTS
+	toep->ulpcb2 = NULL;
+#endif
 
 	return (0);
 }
@@ -802,19 +884,7 @@ static struct uld_info cxgbei_uld_info =
 	.deactivate = cxgbei_deactivate,
 };
 
-enum {
-	CWT_RUNNING = 1,
-	CWT_STOP = 2,
-	CWT_STOPPED = 3,
-};
-
-struct cxgbei_worker_thread_softc {
-	struct mtx	cwt_lock;
-	struct cv	cwt_cv;
-	volatile int	cwt_state;
-} __aligned(CACHE_LINE_SIZE);
-
-int worker_thread_count;
+static int worker_thread_count;
 static struct cxgbei_worker_thread_softc *cwt_softc;
 static struct proc *cxgbei_proc;
 
@@ -822,6 +892,11 @@ static void
 cwt_main(void *arg)
 {
 	struct cxgbei_worker_thread_softc *cwt = arg;
+	struct icl_cxgbei_conn *icc = NULL;
+	struct icl_conn *ic;
+	struct icl_pdu *ip;
+	struct sockbuf *sb;
+	STAILQ_HEAD(, icl_pdu) rx_pdus = STAILQ_HEAD_INITIALIZER(rx_pdus);
 
 	MPASS(cwt != NULL);
 
@@ -829,12 +904,61 @@ cwt_main(void *arg)
 	MPASS(cwt->cwt_state == 0);
 	cwt->cwt_state = CWT_RUNNING;
 	cv_signal(&cwt->cwt_cv);
-	for (;;) {
-		cv_wait(&cwt->cwt_cv, &cwt->cwt_lock);
-		if (cwt->cwt_state == CWT_STOP)
+
+	while (__predict_true(cwt->cwt_state != CWT_STOP)) {
+		cwt->cwt_state = CWT_RUNNING;
+		while ((icc = TAILQ_FIRST(&cwt->rx_head)) != NULL) {
+			TAILQ_REMOVE(&cwt->rx_head, icc, rx_link);
+			mtx_unlock(&cwt->cwt_lock);
+
+			ic = &icc->ic;
+			sb = &ic->ic_socket->so_rcv;
+
+			SOCKBUF_LOCK(sb);
+			MPASS(icc->rx_flags & RXF_ACTIVE);
+			if (__predict_true(!(sb->sb_state & SBS_CANTRCVMORE))) {
+				MPASS(STAILQ_EMPTY(&rx_pdus));
+				STAILQ_SWAP(&icc->rcvd_pdus, &rx_pdus, icl_pdu);
+				SOCKBUF_UNLOCK(sb);
+
+				/* Hand over PDUs to ICL. */
+				while ((ip = STAILQ_FIRST(&rx_pdus)) != NULL) {
+					STAILQ_REMOVE_HEAD(&rx_pdus, ip_next);
+					ic->ic_receive(ip);
+				}
+
+				SOCKBUF_LOCK(sb);
+				MPASS(STAILQ_EMPTY(&rx_pdus));
+			}
+			MPASS(icc->rx_flags & RXF_ACTIVE);
+			if (STAILQ_EMPTY(&icc->rcvd_pdus) ||
+			    __predict_false(sb->sb_state & SBS_CANTRCVMORE)) {
+				icc->rx_flags &= ~RXF_ACTIVE;
+			} else {
+				/*
+				 * More PDUs were received while we were busy
+				 * handing over the previous batch to ICL.
+				 * Re-add this connection to the end of the
+				 * queue.
+				 */
+				mtx_lock(&cwt->cwt_lock);
+				TAILQ_INSERT_TAIL(&cwt->rx_head, icc,
+				    rx_link);
+				mtx_unlock(&cwt->cwt_lock);
+			}
+			SOCKBUF_UNLOCK(sb);
+
+			mtx_lock(&cwt->cwt_lock);
+		}
+
+		/* Inner loop doesn't check for CWT_STOP, do that first. */
+		if (__predict_false(cwt->cwt_state == CWT_STOP))
 			break;
+		cwt->cwt_state = CWT_SLEEPING;
+		cv_wait(&cwt->cwt_cv, &cwt->cwt_lock);
 	}
 
+	MPASS(TAILQ_FIRST(&cwt->rx_head) == NULL);
 	mtx_assert(&cwt->cwt_lock, MA_OWNED);
 	cwt->cwt_state = CWT_STOPPED;
 	cv_signal(&cwt->cwt_cv);
@@ -856,6 +980,7 @@ start_worker_threads(void)
 	for (i = 0, cwt = &cwt_softc[0]; i < worker_thread_count; i++, cwt++) {
 		mtx_init(&cwt->cwt_lock, "cwt lock", NULL, MTX_DEF);
 		cv_init(&cwt->cwt_cv, "cwt cv");
+		TAILQ_INIT(&cwt->rx_head);
 		rc = kproc_kthread_add(cwt_main, cwt, &cxgbei_proc, NULL, 0, 0,
 		    "cxgbei", "%d", i);
 		if (rc != 0) {
@@ -879,7 +1004,7 @@ start_worker_threads(void)
 
 		/* Wait for thread to start before moving on to the next one. */
 		mtx_lock(&cwt->cwt_lock);
-		while (cwt->cwt_state != CWT_RUNNING)
+		while (cwt->cwt_state == 0)
 			cv_wait(&cwt->cwt_cv, &cwt->cwt_lock);
 		mtx_unlock(&cwt->cwt_lock);
 	}
@@ -899,7 +1024,8 @@ stop_worker_threads(void)
 
 	for (i = 0, cwt = &cwt_softc[0]; i < worker_thread_count; i++, cwt++) {
 		mtx_lock(&cwt->cwt_lock);
-		MPASS(cwt->cwt_state == CWT_RUNNING);
+		MPASS(cwt->cwt_state == CWT_RUNNING ||
+		    cwt->cwt_state == CWT_SLEEPING);
 		cwt->cwt_state = CWT_STOP;
 		cv_signal(&cwt->cwt_cv);
 		do {

Modified: projects/cxl_iscsi/sys/dev/cxgbe/cxgbei/cxgbei.h
==============================================================================
--- projects/cxl_iscsi/sys/dev/cxgbe/cxgbei/cxgbei.h	Tue Nov 24 02:30:59 2015	(r291231)
+++ projects/cxl_iscsi/sys/dev/cxgbe/cxgbei/cxgbei.h	Tue Nov 24 02:37:16 2015	(r291232)
@@ -29,8 +29,27 @@
 
 #include <dev/iscsi/icl.h>
 
+enum {
+	CWT_SLEEPING	= 1,
+	CWT_RUNNING	= 2,
+	CWT_STOP	= 3,
+	CWT_STOPPED	= 4,
+};
+
+struct cxgbei_worker_thread_softc {
+	struct mtx	cwt_lock;
+	struct cv	cwt_cv;
+	volatile int	cwt_state;
+
+	TAILQ_HEAD(, icl_cxgbei_conn) rx_head;
+} __aligned(CACHE_LINE_SIZE);
+
 #define CXGBEI_CONN_SIGNATURE 0x56788765
 
+enum {
+	RXF_ACTIVE	= 1 << 0,	/* In the worker thread's queue */
+};
+
 struct icl_cxgbei_conn {
 	struct icl_conn ic;
 
@@ -40,10 +59,11 @@ struct icl_cxgbei_conn {
 	struct adapter *sc;
 	struct toepcb *toep;
 
-	/* PDU currently being assembled. */
-	/* XXXNP: maybe just use ic->ic_receive_pdu instead? */
-	struct icl_cxgbei_pdu *icp;
-	uint32_t pdu_seq;		/* For debug only */
+	/* Receive related. */
+	u_int rx_flags;				/* protected by so_rcv lock */
+	STAILQ_HEAD(, icl_pdu) rcvd_pdus;	/* protected by so_rcv lock */
+	TAILQ_ENTRY(icl_cxgbei_conn) rx_link;	/* protected by cwt lock */
+	struct cxgbei_worker_thread_softc *cwt;
 };
 
 static inline struct icl_cxgbei_conn *
@@ -60,6 +80,7 @@ struct icl_cxgbei_pdu {
 
 	/* cxgbei specific stuff goes here. */
 	uint32_t icp_signature;
+	uint32_t pdu_seq;	/* For debug only */
 	u_int pdu_flags;
 };
 

Modified: projects/cxl_iscsi/sys/dev/cxgbe/cxgbei/icl_cxgbei.c
==============================================================================
--- projects/cxl_iscsi/sys/dev/cxgbe/cxgbei/icl_cxgbei.c	Tue Nov 24 02:30:59 2015	(r291231)
+++ projects/cxl_iscsi/sys/dev/cxgbe/cxgbei/icl_cxgbei.c	Tue Nov 24 02:37:16 2015	(r291232)
@@ -101,7 +101,7 @@ struct icl_pdu *icl_cxgbei_new_pdu(int);
 void icl_cxgbei_new_pdu_set_conn(struct icl_pdu *, struct icl_conn *);
 
 static icl_conn_new_pdu_t	icl_cxgbei_conn_new_pdu;
-static icl_conn_pdu_free_t	icl_cxgbei_conn_pdu_free;
+icl_conn_pdu_free_t	icl_cxgbei_conn_pdu_free;
 static icl_conn_pdu_data_segment_length_t
 				    icl_cxgbei_conn_pdu_data_segment_length;
 static icl_conn_pdu_append_data_t	icl_cxgbei_conn_pdu_append_data;
@@ -141,7 +141,7 @@ DEFINE_CLASS(icl_cxgbei, icl_cxgbei_meth
 #define CXGBEI_MAX_PDU 16224
 #define CXGBEI_MAX_DSL (CXGBEI_MAX_PDU - sizeof(struct iscsi_bhs) - 8)
 
-static void
+void
 icl_cxgbei_conn_pdu_free(struct icl_conn *ic, struct icl_pdu *ip)
 {
 #ifdef INVARIANTS
@@ -157,7 +157,7 @@ icl_cxgbei_conn_pdu_free(struct icl_conn
 	m_freem(ip->ip_bhs_mbuf);	/* storage for icl_cxgbei_pdu itself */
 
 #ifdef DIAGNOSTIC
-	if (ic != NULL)
+	if (__predict_true(ic != NULL))
 		refcount_release(&ic->ic_outstanding_pdus);
 #endif
 }
@@ -417,6 +417,7 @@ icl_cxgbei_new_conn(const char *name, st
 	icc = (struct icl_cxgbei_conn *)kobj_create(&icl_cxgbei_class, M_CXGBE,
 	    M_WAITOK | M_ZERO);
 	icc->icc_signature = CXGBEI_CONN_SIGNATURE;
+	STAILQ_INIT(&icc->rcvd_pdus);
 
 	ic = &icc->ic;
 	ic->ic_lock = lock;
@@ -560,6 +561,9 @@ set_ulp_mode_iscsi(struct adapter *sc, s
 	t4_set_tcb_field(sc, toep, 1, 0, 0xfff, val);
 }
 
+/* XXXNP */
+extern struct cxgbei_worker_thread_softc *cwt_softc;
+
 /*
  * XXXNP: Who is responsible for cleaning up the socket if this returns with an
  * error?  Review all error paths.
@@ -641,6 +645,7 @@ icl_cxgbei_conn_handoff(struct icl_conn 
 
 		toep = tp->t_toe;
 		icc->toep = toep;
+		icc->cwt = &cwt_softc[0]; /* XXXNP */
 		icc->ulp_submode = 0;
 		if (ic->ic_header_crc32c)
 			icc->ulp_submode |= ULP_CRC_HEADER;
@@ -663,25 +668,25 @@ void
 icl_cxgbei_conn_close(struct icl_conn *ic)
 {
 	struct icl_cxgbei_conn *icc = ic_to_icc(ic);
+	struct icl_pdu *ip;
 	struct socket *so;
+	struct sockbuf *sb;
+	struct inpcb *inp;
 	struct toepcb *toep = icc->toep;
 
 	MPASS(icc->icc_signature == CXGBEI_CONN_SIGNATURE);
 	ICL_CONN_LOCK_ASSERT_NOT(ic);
 
-	CTR3(KTR_CXGBE, "%s: tid %u, icc %p", __func__, toep->tid, icc);
-
 	ICL_CONN_LOCK(ic);
 	so = ic->ic_socket;
-	if (so == NULL) {
+	if (ic->ic_disconnecting || so == NULL) {
+		CTR4(KTR_CXGBE, "%s: icc %p (disconnecting = %d), so %p",
+		    __func__, icc, ic->ic_disconnecting, so);
 		ICL_CONN_UNLOCK(ic);
 		return;
 	}
-	ic->ic_socket = NULL;
 	ic->ic_disconnecting = true;
 
-	mbufq_drain(&toep->ulp_pduq);
-
 	/* These are unused in this driver right now. */
 	MPASS(STAILQ_EMPTY(&ic->ic_to_send));
 	MPASS(ic->ic_receive_pdu == NULL);
@@ -693,6 +698,41 @@ icl_cxgbei_conn_close(struct icl_conn *i
 #endif
 	ICL_CONN_UNLOCK(ic);
 
+	CTR3(KTR_CXGBE, "%s: tid %d, icc %p", __func__, toep ? toep->tid : -1,
+	    icc);
+	inp = sotoinpcb(so);
+	sb = &so->so_rcv;
+	INP_WLOCK(inp);
+	if (toep != NULL) {	/* NULL if connection was never offloaded. */
+		toep->ulpcb = NULL;
+		mbufq_drain(&toep->ulp_pduq);
+		SOCKBUF_LOCK(sb);
+		if (icc->rx_flags & RXF_ACTIVE) {
+			volatile u_int *p = &icc->rx_flags;
+
+			SOCKBUF_UNLOCK(sb);
+			INP_WUNLOCK(inp);
+
+			while (*p & RXF_ACTIVE)
+				pause("conclo", 1);
+
+			INP_WLOCK(inp);
+			SOCKBUF_LOCK(sb);
+		}
+
+		while (!STAILQ_EMPTY(&icc->rcvd_pdus)) {
+			ip = STAILQ_FIRST(&icc->rcvd_pdus);
+			STAILQ_REMOVE_HEAD(&icc->rcvd_pdus, ip_next);
+			icl_cxgbei_conn_pdu_free(ic, ip);
+		}
+		SOCKBUF_UNLOCK(sb);
+	}
+	INP_WUNLOCK(inp);
+
+	ICL_CONN_LOCK(ic);
+	ic->ic_socket = NULL;
+	ICL_CONN_UNLOCK(ic);
+
 	/*
 	 * XXXNP: we should send RST instead of FIN when PDUs held in various
 	 * queues were purged instead of delivered reliably but soabort isn't

Modified: projects/cxl_iscsi/sys/dev/cxgbe/tom/t4_tom.h
==============================================================================
--- projects/cxl_iscsi/sys/dev/cxgbe/tom/t4_tom.h	Tue Nov 24 02:30:59 2015	(r291231)
+++ projects/cxl_iscsi/sys/dev/cxgbe/tom/t4_tom.h	Tue Nov 24 02:37:16 2015	(r291232)
@@ -116,6 +116,7 @@ struct toepcb {
 
 	u_int ulp_mode;	/* ULP mode */
 	void *ulpcb;
+	void *ulpcb2;
 	struct mbufq ulp_pduq;	/* PDUs waiting to be sent out. */
 	struct mbufq ulp_pdu_reclaimq;
 



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201511240237.tAO2bHZG016097>