usr/src/uts/common/io/ib/clients/ibd/ibd_cm.c
changeset 11642 5c24335364eb
parent 11534 9e690526d933
child 12163 f0cf0084e756
--- a/usr/src/uts/common/io/ib/clients/ibd/ibd_cm.c	Tue Feb 09 15:21:27 2010 -0800
+++ b/usr/src/uts/common/io/ib/clients/ibd/ibd_cm.c	Wed Feb 10 14:16:37 2010 +0800
@@ -54,6 +54,7 @@
 
 #include <sys/ib/clients/ibd/ibd.h>
 
+extern ibd_global_state_t ibd_gstate;
 
 /* Per-interface tunables (for developers) */
 extern uint_t ibd_rc_tx_copy_thresh;
@@ -168,6 +169,7 @@
 /* Receive Functions */
 static int ibd_rc_post_srq(ibd_state_t *, ibd_rwqe_t *);
 static void ibd_rc_srq_freemsg_cb(char *);
+static void ibd_rc_srq_free_rwqe(ibd_state_t *, ibd_rwqe_t *);
 
 static int ibd_rc_post_rwqe(ibd_rc_chan_t *, ibd_rwqe_t *);
 static void ibd_rc_freemsg_cb(char *);
@@ -1016,7 +1018,12 @@
 		    &rwqe->w_freemsg_cb)) == NULL) {
 			DPRINT(40, "ibd_rc_init_srq_list : desballoc() failed");
 			rwqe->rwqe_copybuf.ic_bufaddr = NULL;
+			if (atomic_dec_32_nv(&state->id_running) != 0) {
+				cmn_err(CE_WARN, "ibd_rc_init_srq_list: "
+				    "id_running was not 1\n");
+			}
 			ibd_rc_fini_srq_list(state);
+			atomic_inc_32(&state->id_running);
 			return (DDI_FAILURE);
 		}
 
@@ -1031,6 +1038,11 @@
 		(void) ibd_rc_post_srq(state, rwqe);
 	}
 
+	mutex_enter(&state->rc_srq_free_list.dl_mutex);
+	state->rc_srq_free_list.dl_head = NULL;
+	state->rc_srq_free_list.dl_cnt = 0;
+	mutex_exit(&state->rc_srq_free_list.dl_mutex);
+
 	return (DDI_SUCCESS);
 }
 
@@ -1044,6 +1056,7 @@
 	int i;
 	ibt_status_t ret;
 
+	ASSERT(state->id_running == 0);
 	ret = ibt_free_srq(state->rc_srq_hdl);
 	if (ret != IBT_SUCCESS) {
 		ibd_print_warn(state, "ibd_rc_fini_srq_list: "
@@ -1063,10 +1076,52 @@
 	ibd_rc_free_srq_copybufs(state);
 }
 
+/* Repost the elements in state->ib_rc_free_list */
+int
+ibd_rc_repost_srq_free_list(ibd_state_t *state)
+{
+	ibd_rwqe_t *rwqe;
+	ibd_wqe_t *list;
+	uint_t len;
+
+	mutex_enter(&state->rc_srq_free_list.dl_mutex);
+	if (state->rc_srq_free_list.dl_head != NULL) {
+		/* repost them */
+		len = state->rc_mtu + IPOIB_GRH_SIZE;
+		list = state->rc_srq_free_list.dl_head;
+		state->rc_srq_free_list.dl_head = NULL;
+		state->rc_srq_free_list.dl_cnt = 0;
+		mutex_exit(&state->rc_srq_free_list.dl_mutex);
+		while (list != NULL) {
+			rwqe = WQE_TO_RWQE(list);
+			if ((rwqe->rwqe_im_mblk == NULL) &&
+			    ((rwqe->rwqe_im_mblk = desballoc(
+			    rwqe->rwqe_copybuf.ic_bufaddr, len, 0,
+			    &rwqe->w_freemsg_cb)) == NULL)) {
+				DPRINT(40, "ibd_rc_repost_srq_free_list: "
+				    "failed in desballoc()");
+				do {
+					ibd_rc_srq_free_rwqe(state, rwqe);
+					list = list->w_next;
+					rwqe = WQE_TO_RWQE(list);
+				} while (list != NULL);
+				return (DDI_FAILURE);
+			}
+			if (ibd_rc_post_srq(state, rwqe) == DDI_FAILURE) {
+				ibd_rc_srq_free_rwqe(state, rwqe);
+			}
+			list = list->w_next;
+		}
+		return (DDI_SUCCESS);
+	}
+	mutex_exit(&state->rc_srq_free_list.dl_mutex);
+	return (DDI_SUCCESS);
+}
+
 /*
  * Free an allocated recv wqe.
  */
-void
+static void
 ibd_rc_srq_free_rwqe(ibd_state_t *state, ibd_rwqe_t *rwqe)
 {
 	/*
@@ -1094,13 +1149,23 @@
 	ASSERT(state->rc_enable_srq);
 
 	/*
-	 * If the wqe is being destructed, do not attempt recycling.
+	 * If the driver is stopped, just free the rwqe.
 	 */
-	if (rwqe->w_freeing_wqe == B_TRUE) {
+	if (atomic_add_32_nv(&state->id_running, 0) == 0) {
+		if (!rwqe->w_freeing_wqe) {
+			atomic_dec_32(
+			    &state->rc_srq_rwqe_list.dl_bufs_outstanding);
+			DPRINT(6, "ibd_rc_srq_freemsg_cb: wqe being freed");
+			rwqe->rwqe_im_mblk = NULL;
+			ibd_rc_srq_free_rwqe(state, rwqe);
+		}
 		return;
 	}
 
+	atomic_dec_32(&state->rc_srq_rwqe_list.dl_bufs_outstanding);
+
 	ASSERT(state->rc_srq_rwqe_list.dl_cnt < state->rc_srq_size);
+	ASSERT(!rwqe->w_freeing_wqe);
 
 	/*
 	 * Upper layer has released held mblk, so we have
@@ -1116,11 +1181,11 @@
 	}
 
 	if (ibd_rc_post_srq(state, rwqe) == DDI_FAILURE) {
+		ibd_print_warn(state, "ibd_rc_srq_freemsg_cb: ibd_rc_post_srq"
+		    " failed");
 		ibd_rc_srq_free_rwqe(state, rwqe);
 		return;
 	}
-
-	atomic_add_32(&state->rc_srq_rwqe_list.dl_bufs_outstanding, -1);
 }
 
 /*
@@ -2260,6 +2325,65 @@
 	return (DDI_INTR_CLAIMED);
 }
 
+static ibt_status_t
+ibd_register_service(ibt_srv_desc_t *srv, ib_svc_id_t sid,
+    int num_sids, ibt_srv_hdl_t *srv_hdl, ib_svc_id_t *ret_sid)
+{
+	ibd_service_t *p;
+	ibt_status_t status;
+
+	mutex_enter(&ibd_gstate.ig_mutex);
+	for (p = ibd_gstate.ig_service_list; p != NULL; p = p->is_link) {
+		if (p->is_sid == sid) {
+			p->is_ref_cnt++;
+			*srv_hdl = p->is_srv_hdl;
+			*ret_sid = sid;
+			mutex_exit(&ibd_gstate.ig_mutex);
+			return (IBT_SUCCESS);
+		}
+	}
+	status = ibt_register_service(ibd_gstate.ig_ibt_hdl, srv, sid,
+	    num_sids, srv_hdl, ret_sid);
+	if (status == IBT_SUCCESS) {
+		p = kmem_alloc(sizeof (*p), KM_SLEEP);
+		p->is_srv_hdl = *srv_hdl;
+		p->is_sid = sid;
+		p->is_ref_cnt = 1;
+		p->is_link = ibd_gstate.ig_service_list;
+		ibd_gstate.ig_service_list = p;
+	}
+	mutex_exit(&ibd_gstate.ig_mutex);
+	return (status);
+}
+
+static ibt_status_t
+ibd_deregister_service(ibt_srv_hdl_t srv_hdl)
+{
+	ibd_service_t *p, **pp;
+	ibt_status_t status;
+
+	mutex_enter(&ibd_gstate.ig_mutex);
+	for (pp = &ibd_gstate.ig_service_list; *pp != NULL;
+	    pp = &((*pp)->is_link)) {
+		p = *pp;
+		if (p->is_srv_hdl == srv_hdl) {	/* Found it */
+			if (--p->is_ref_cnt == 0) {
+				status = ibt_deregister_service(
+				    ibd_gstate.ig_ibt_hdl, srv_hdl);
+				*pp = p->is_link; /* link prev to next */
+				kmem_free(p, sizeof (*p));
+			} else {
+				status = IBT_SUCCESS;
+			}
+			mutex_exit(&ibd_gstate.ig_mutex);
+			return (status);
+		}
+	}
+	/* Should not ever get here */
+	mutex_exit(&ibd_gstate.ig_mutex);
+	return (IBT_FAILURE);
+}
+
 /* Listen with corresponding service ID */
 ibt_status_t
 ibd_rc_listen(ibd_state_t *state)
@@ -2282,7 +2406,7 @@
 	 * Register the service with service id
 	 * Incoming connection requests should arrive on this service id.
 	 */
-	status = ibt_register_service(state->id_ibt_hdl, &srvdesc,
+	status = ibd_register_service(&srvdesc,
 	    IBD_RC_QPN_TO_SID(state->id_qpnum),
 	    1, &state->rc_listen_hdl, &ret_sid);
 	if (status != IBT_SUCCESS) {
@@ -2299,8 +2423,7 @@
 	if (status != IBT_SUCCESS) {
 		DPRINT(40, "ibd_rc_listen:"
 		    " fail to bind port: <%d>", status);
-		(void) ibt_deregister_service(state->id_ibt_hdl,
-		    state->rc_listen_hdl);
+		(void) ibd_deregister_service(state->rc_listen_hdl);
 		return (status);
 	}
 
@@ -2319,7 +2442,7 @@
 	 * Register the service with service id
 	 * Incoming connection requests should arrive on this service id.
 	 */
-	status = ibt_register_service(state->id_ibt_hdl, &srvdesc,
+	status = ibd_register_service(&srvdesc,
 	    IBD_RC_QPN_TO_SID_OFED_INTEROP(state->id_qpnum),
 	    1, &state->rc_listen_hdl_OFED_interop, &ret_sid);
 	if (status != IBT_SUCCESS) {
@@ -2328,8 +2451,7 @@
 		    "Failed %d", status);
 		(void) ibt_unbind_service(state->rc_listen_hdl,
 		    state->rc_listen_bind);
-		(void) ibt_deregister_service(state->id_ibt_hdl,
-		    state->rc_listen_hdl);
+		(void) ibd_deregister_service(state->rc_listen_hdl);
 		return (status);
 	}
 
@@ -2341,12 +2463,11 @@
 	if (status != IBT_SUCCESS) {
 		DPRINT(40, "ibd_rc_listen: fail to bind port: <%d> for "
 		    "Legacy OFED listener", status);
-		(void) ibt_deregister_service(state->id_ibt_hdl,
+		(void) ibd_deregister_service(
 		    state->rc_listen_hdl_OFED_interop);
 		(void) ibt_unbind_service(state->rc_listen_hdl,
 		    state->rc_listen_bind);
-		(void) ibt_deregister_service(state->id_ibt_hdl,
-		    state->rc_listen_hdl);
+		(void) ibd_deregister_service(state->rc_listen_hdl);
 		return (status);
 	}
 
@@ -2365,11 +2486,10 @@
 			DPRINT(40, "ibd_rc_stop_listen:"
 			    "ibt_unbind_all_services() failed, ret=%d", ret);
 		}
-		ret = ibt_deregister_service(state->id_ibt_hdl,
-		    state->rc_listen_hdl);
+		ret = ibd_deregister_service(state->rc_listen_hdl);
 		if (ret != 0) {
 			DPRINT(40, "ibd_rc_stop_listen:"
-			    "ibt_deregister_service() failed, ret=%d", ret);
+			    "ibd_deregister_service() failed, ret=%d", ret);
 		} else {
 			state->rc_listen_hdl = NULL;
 		}
@@ -2383,21 +2503,20 @@
 			DPRINT(40, "ibd_rc_stop_listen:"
 			    "ibt_unbind_all_services() failed: %d", ret);
 		}
-		ret = ibt_deregister_service(state->id_ibt_hdl,
-		    state->rc_listen_hdl_OFED_interop);
+		ret = ibd_deregister_service(state->rc_listen_hdl_OFED_interop);
 		if (ret != 0) {
 			DPRINT(40, "ibd_rc_stop_listen:"
-			    "ibt_deregister_service() failed: %d", ret);
+			    "ibd_deregister_service() failed: %d", ret);
 		} else {
 			state->rc_listen_hdl_OFED_interop = NULL;
 		}
 	}
 }
 
-int
+void
 ibd_rc_close_all_chan(ibd_state_t *state)
 {
-	ibd_rc_chan_t *rc_chan, *rc_chan1;
+	ibd_rc_chan_t *rc_chan;
 	ibd_ace_t *ace;
 	uint_t attempts;
 
@@ -2411,7 +2530,7 @@
 	mutex_exit(&state->rc_pass_chan_list.chan_list_mutex);
 
 	if (state->rc_enable_srq) {
-		attempts = 50;
+		attempts = 10;
 		while (state->rc_srq_rwqe_list.dl_bufs_outstanding > 0) {
 			DPRINT(30, "ibd_rc_close_all_chan: outstanding > 0");
 			delay(drv_usectohz(100000));
@@ -2424,19 +2543,7 @@
 				 * we turned off the notification and
 				 * return failure.
 				 */
-				mutex_enter(
-				    &state->rc_pass_chan_list.chan_list_mutex);
-				rc_chan = state->rc_pass_chan_list.chan_list;
-				while (rc_chan != NULL) {
-					ibd_rc_poll_rcq
-					    (rc_chan, rc_chan->rcq_hdl);
-					ibt_set_cq_handler(rc_chan->rcq_hdl,
-					    ibd_rc_rcq_handler, rc_chan);
-					rc_chan = rc_chan->next;
-				}
-				mutex_exit(
-				    &state->rc_pass_chan_list.chan_list_mutex);
-				return (DDI_FAILURE);
+				break;
 			}
 		}
 	}
@@ -2444,22 +2551,7 @@
 	/* Close all passive RC channels */
 	rc_chan = ibd_rc_rm_header_chan_list(&state->rc_pass_chan_list);
 	while (rc_chan != NULL) {
-		if (ibd_rc_pas_close(rc_chan) != DDI_SUCCESS) {
-			mutex_enter(&state->rc_pass_chan_list.chan_list_mutex);
-			rc_chan1 = state->rc_pass_chan_list.chan_list;
-			while (rc_chan1 != NULL) {
-				ibd_rc_poll_rcq(rc_chan1, rc_chan1->rcq_hdl);
-				ibt_set_cq_handler(rc_chan1->rcq_hdl,
-				    ibd_rc_rcq_handler, rc_chan1);
-				rc_chan1 = rc_chan1->next;
-			}
-			mutex_exit(&state->rc_pass_chan_list.chan_list_mutex);
-			ibd_rc_add_to_chan_list(&state->rc_pass_chan_list,
-			    rc_chan);
-			DPRINT(40, "ibd_rc_close_all_chan: ibd_rc_pas_close() "
-			    "failed");
-			return (DDI_FAILURE);
-		}
+		(void) ibd_rc_pas_close(rc_chan);
 		rc_chan = ibd_rc_rm_header_chan_list(&state->rc_pass_chan_list);
 	}
 
@@ -2484,7 +2576,6 @@
 		rc_chan = ibd_rc_rm_header_chan_list(
 		    &state->rc_obs_act_chan_list);
 	}
-	return (DDI_SUCCESS);
 }
 
 void