xref: /illumos-gate/usr/src/uts/common/io/ib/mgt/ibmf/ibmf_msg.c (revision 581cede61ac9c14d8d4ea452562a567189eead78)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 /*
30  * This file implements the IBMF message related functions.
31  */
32 
33 #include <sys/ib/mgt/ibmf/ibmf_impl.h>
34 
35 extern int ibmf_trace_level;
36 
37 /*
38  * ibmf_i_client_add_msg():
39  *	Add the message to the client message list
40  */
41 void
42 ibmf_i_client_add_msg(ibmf_client_t *clientp, ibmf_msg_impl_t *msgimplp)
43 {
44 	IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L4,
45 	    ibmf_i_client_add_msg_start, IBMF_TNF_TRACE, "",
46 	    "ibmf_i_client_add_msg(): clientp = 0x%p, msgp = 0x%p\n",
47 	    tnf_opaque, clientp, clientp, tnf_opaque, msg, msgimplp);
48 
49 	ASSERT(MUTEX_NOT_HELD(&msgimplp->im_mutex));
50 
51 	mutex_enter(&clientp->ic_msg_mutex);
52 
53 	/*
54 	 * If this is a termination message, add the message to
55 	 * the termination message list else add the message
56 	 * to the regular message list.
57 	 */
58 	mutex_enter(&msgimplp->im_mutex);
59 	if (msgimplp->im_flags & IBMF_MSG_FLAGS_TERMINATION) {
60 
61 		mutex_exit(&msgimplp->im_mutex);
62 		/* Put the message on the list */
63 		if (clientp->ic_term_msg_list == NULL) {
64 			clientp->ic_term_msg_list = clientp->ic_term_msg_last =
65 			    msgimplp;
66 		} else {
67 			msgimplp->im_msg_prev = clientp->ic_term_msg_last;
68 			clientp->ic_term_msg_last->im_msg_next = msgimplp;
69 			clientp->ic_term_msg_last = msgimplp;
70 		}
71 	} else {
72 
73 		mutex_exit(&msgimplp->im_mutex);
74 		/*
75 		 * Increment the counter and kstats for active messages
76 		 */
77 		clientp->ic_msgs_active++;
78 		mutex_enter(&clientp->ic_kstat_mutex);
79 		IBMF_ADD32_KSTATS(clientp, msgs_active, 1);
80 		mutex_exit(&clientp->ic_kstat_mutex);
81 
82 		/* Put the message on the list */
83 		if (clientp->ic_msg_list == NULL) {
84 			clientp->ic_msg_list = clientp->ic_msg_last = msgimplp;
85 		} else {
86 			msgimplp->im_msg_prev = clientp->ic_msg_last;
87 			clientp->ic_msg_last->im_msg_next = msgimplp;
88 			clientp->ic_msg_last = msgimplp;
89 		}
90 	}
91 
92 	msgimplp->im_msg_next = NULL;
93 
94 	/* Set the message flags to indicate the message is on the list */
95 	mutex_enter(&msgimplp->im_mutex);
96 	msgimplp->im_flags |= IBMF_MSG_FLAGS_ON_LIST;
97 	mutex_exit(&msgimplp->im_mutex);
98 
99 	mutex_exit(&clientp->ic_msg_mutex);
100 
101 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
102 	    ibmf_i_client_add_msg_end, IBMF_TNF_TRACE, "",
103 	    "ibmf_i_client_add_msg() exit\n");
104 }
105 
106 /*
107  * ibmf_i_client_rem_msg():
108  *	Remove the message from the client's message list
109  *	The refcnt will hold the message reference count at the time
110  *	the message was removed from the message list. Any packets
111  *	arriving after this point for the message will be dropped.
112  *	The message reference count is used by the threads processing
113  *	the message to decide which one should notify the client
114  *	(the one that decrements the reference count to zero).
115  */
116 void
117 ibmf_i_client_rem_msg(ibmf_client_t *clientp, ibmf_msg_impl_t *msgimplp,
118     uint_t *refcnt)
119 {
120 	ibmf_msg_impl_t *tmpmsg, *prevmsg = NULL;
121 
122 	ASSERT(MUTEX_NOT_HELD(&msgimplp->im_mutex));
123 
124 	IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L4,
125 	    ibmf_i_client_rem_msg_start, IBMF_TNF_TRACE, "",
126 	    "ibmf_i_client_rem_msg(): clientp = 0x%p, msgp = 0x%p\n",
127 	    tnf_opaque, clientp, clientp, tnf_opaque, msg, msgimplp);
128 
129 	mutex_enter(&clientp->ic_msg_mutex);
130 
131 	/*
132 	 * If this is a termination message, remove the message from
133 	 * the termination message list else remove the message
134 	 * from the regular message list.
135 	 */
136 	mutex_enter(&msgimplp->im_mutex);
137 	if (msgimplp->im_flags & IBMF_MSG_FLAGS_TERMINATION) {
138 
139 		mutex_exit(&msgimplp->im_mutex);
140 		tmpmsg = clientp->ic_term_msg_list;
141 
142 		while (tmpmsg != NULL) {
143 			if (tmpmsg == msgimplp)
144 				break;
145 			prevmsg = tmpmsg;
146 			tmpmsg = tmpmsg->im_msg_next;
147 		}
148 
149 		ASSERT(tmpmsg != NULL);
150 
151 		if (tmpmsg->im_msg_next == NULL)
152 			clientp->ic_term_msg_last = prevmsg;
153 		else
154 			tmpmsg->im_msg_next->im_msg_prev = prevmsg;
155 
156 		if (prevmsg != NULL)
157 			prevmsg->im_msg_next = tmpmsg->im_msg_next;
158 		else
159 			clientp->ic_term_msg_list = tmpmsg->im_msg_next;
160 	} else {
161 
162 		mutex_exit(&msgimplp->im_mutex);
163 		/*
164 		 * Decrement the counter and kstats for active messages
165 		 */
166 		ASSERT(clientp->ic_msgs_active != 0);
167 		clientp->ic_msgs_active--;
168 		mutex_enter(&clientp->ic_kstat_mutex);
169 		IBMF_SUB32_KSTATS(clientp, msgs_active, 1);
170 		mutex_exit(&clientp->ic_kstat_mutex);
171 
172 		tmpmsg = clientp->ic_msg_list;
173 
174 		while (tmpmsg != NULL) {
175 			if (tmpmsg == msgimplp)
176 				break;
177 			prevmsg = tmpmsg;
178 			tmpmsg = tmpmsg->im_msg_next;
179 		}
180 
181 		ASSERT(tmpmsg != NULL);
182 
183 		if (tmpmsg->im_msg_next == NULL)
184 			clientp->ic_msg_last = prevmsg;
185 		else
186 			tmpmsg->im_msg_next->im_msg_prev = prevmsg;
187 
188 		if (prevmsg != NULL)
189 			prevmsg->im_msg_next = tmpmsg->im_msg_next;
190 		else
191 			clientp->ic_msg_list = tmpmsg->im_msg_next;
192 	}
193 
194 	/* Save away the message reference count and clear the list flag */
195 	mutex_enter(&msgimplp->im_mutex);
196 	*refcnt = msgimplp->im_ref_count;
197 	msgimplp->im_flags &= ~IBMF_MSG_FLAGS_ON_LIST;
198 	mutex_exit(&msgimplp->im_mutex);
199 
200 	mutex_exit(&clientp->ic_msg_mutex);
201 
202 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
203 	    ibmf_i_client_rem_msg_end, IBMF_TNF_TRACE, "",
204 	    "ibmf_i_client_rem_msg() exit\n");
205 }
206 
207 /*
208  * ibmf_i_find_msg():
209  *	Walk the client message list for the message corresponding to
210  *	the parameters specified
211  *	The msg_list parameter should be either IBMF_REG_MSG_LIST
212  *	or IBMF_TERM_MSG_LIST for the termination message list.
213  */
214 ibmf_msg_impl_t *
215 ibmf_i_find_msg(ibmf_client_t *clientp, uint64_t tid, uint8_t mgt_class,
216     uint8_t r_method, ib_lid_t lid, ib_gid_t *gid, boolean_t gid_pr,
217     ibmf_rmpp_hdr_t *rmpp_hdr, boolean_t msg_list)
218 {
219 	ibmf_msg_impl_t *msgimplp;
220 	ib_gid_t	*ctx_gidp;
221 	int		msg_found;
222 
223 	IBMF_TRACE_5(IBMF_TNF_DEBUG, DPRINT_L4,
224 	    ibmf_i_find_msg_start, IBMF_TNF_TRACE, "",
225 	    "ibmf_i_find_msg(): clientp = 0x%p, tid = 0x%p, mgmt_class = 0x%x, "
226 	    "lid = 0x%x, gidp = 0x%p\n", tnf_opaque, clientp, clientp,
227 	    tnf_opaque, tid, tid, tnf_opaque, mgt_class, mgt_class,
228 	    tnf_opaque, lid, lid, tnf_opaque, gid, gid);
229 
230 	msg_found = B_FALSE;
231 
232 	mutex_enter(&clientp->ic_msg_mutex);
233 
234 	if (msg_list == IBMF_REG_MSG_LIST)
235 		msgimplp = clientp->ic_msg_list;
236 	else
237 		msgimplp = clientp->ic_term_msg_list;
238 
239 	/*
240 	 * Look for a transaction (message) context that matches the
241 	 * transaction ID, gid or lid, and management class of the
242 	 * incoming packet.
243 	 *
244 	 * If the client decides to do a non-rmpp or rmpp send only,
245 	 * despite expecting a response, then the response should check
246 	 * if the message context for the send still exists.
247 	 * If it does, it should be skipped.
248 	 */
249 	while (msgimplp != NULL) {
250 
251 		if (gid_pr == B_TRUE) {
252 
253 			ctx_gidp = &msgimplp->im_global_addr.ig_sender_gid;
254 
255 			/* first match gid */
256 			if ((ctx_gidp->gid_prefix != gid->gid_prefix) ||
257 			    (ctx_gidp->gid_guid != gid->gid_guid)) {
258 
259 				msgimplp = msgimplp->im_msg_next;
260 				continue;
261 			}
262 		} else  {
263 
264 			IBMF_TRACE_5(IBMF_TNF_DEBUG, DPRINT_L3,
265 			    ibmf_i_find_msg, IBMF_TNF_TRACE, "",
266 			    "ibmf_i_find_msg(): %s, msgp = 0x%p, tid = 0x%p, "
267 			    "remote_lid = 0x%x, mgmt_class = 0x%x\n",
268 			    tnf_string, msg, "Comparing to msg",
269 			    tnf_opaque, msg, msgimplp,
270 			    tnf_opaque, tid, msgimplp->im_tid,
271 			    tnf_opaque, remote_lid,
272 			    msgimplp->im_local_addr.ia_remote_lid,
273 			    tnf_opaque, class, msgimplp->im_mgt_class);
274 
275 			/* first match lid */
276 			if (msgimplp->im_local_addr.ia_remote_lid != lid) {
277 				msgimplp = msgimplp->im_msg_next;
278 				continue;
279 			}
280 		}
281 
282 		/* next match tid and class */
283 		if ((msgimplp->im_tid != tid) ||
284 		    (msgimplp->im_mgt_class != mgt_class)) {
285 
286 			msgimplp = msgimplp->im_msg_next;
287 			continue;
288 		}
289 
290 		/*
291 		 * For unsolicited transactions, the message is found
292 		 * if the method matches, but,
293 		 * If the response is an ACK, and the transaction is
294 		 * in RMPP receiver mode, then skip this message.
295 		 */
296 		if (msgimplp->im_unsolicited == B_TRUE) {
297 			ibmf_rmpp_ctx_t *rmpp_ctx;
298 			ibmf_msg_bufs_t *msgbufp;
299 
300 			mutex_enter(&msgimplp->im_mutex);
301 			rmpp_ctx = &msgimplp->im_rmpp_ctx;
302 
303 			if ((msgimplp->im_flags & IBMF_MSG_FLAGS_RECV_RMPP) &&
304 			    ((rmpp_ctx->rmpp_state ==
305 			    IBMF_RMPP_STATE_RECEVR_ACTIVE) ||
306 			    (rmpp_ctx->rmpp_state ==
307 			    IBMF_RMPP_STATE_RECEVR_TERMINATE))) {
308 				/* Continue if ACK packet */
309 				if (rmpp_hdr->rmpp_type == IBMF_RMPP_TYPE_ACK) {
310 					mutex_exit(&msgimplp->im_mutex);
311 					msgimplp = msgimplp->im_msg_next;
312 					continue;
313 				}
314 			}
315 
316 			if (msgimplp->im_trans_state_flags ==
317 			    IBMF_TRANS_STATE_FLAG_RECV_ACTIVE) {
318 				msgbufp = &msgimplp->im_msgbufs_recv;
319 				if (msgbufp->im_bufs_mad_hdr->R_Method ==
320 				    r_method) {
321 					mutex_exit(&msgimplp->im_mutex);
322 					msg_found = B_TRUE;
323 					break;
324 				}
325 			}
326 
327 			mutex_exit(&msgimplp->im_mutex);
328 		}
329 
330 		/*
331 		 * if this was an unsequenced, non-RMPP transaction there should
332 		 * be no incoming packets
333 		 */
334 		if ((!(msgimplp->im_transp_op_flags &
335 		    IBMF_MSG_TRANS_FLAG_RMPP)) &&
336 		    (!(msgimplp->im_transp_op_flags &
337 		    IBMF_MSG_TRANS_FLAG_SEQ))) {
338 
339 			msgimplp = msgimplp->im_msg_next;
340 			continue;
341 		}
342 
343 
344 		/*
345 		 * if this is a sequenced transaction,
346 		 * (the send and response may or may not be RMPP)
347 		 * and the method of the incoming MAD is the same as the
348 		 * method in the send message context with the response bit
349 		 * set then this message matches.
350 		 */
351 		if (msgimplp->im_transp_op_flags & IBMF_MSG_TRANS_FLAG_SEQ) {
352 			ibmf_msg_bufs_t *msgbufp;
353 
354 			mutex_enter(&msgimplp->im_mutex);
355 
356 			msgbufp = &msgimplp->im_msgbufs_send;
357 
358 			if ((msgbufp->im_bufs_mad_hdr->R_Method |
359 			    IBMF_RMPP_METHOD_RESP_BIT) == r_method) {
360 				mutex_exit(&msgimplp->im_mutex);
361 				msg_found = B_TRUE;
362 				break;
363 			}
364 
365 			mutex_exit(&msgimplp->im_mutex);
366 		}
367 
368 		/*
369 		 * if this is an RMPP SEND transaction there should only
370 		 * be ACK, STOP, and ABORTS RMPP packets.
371 		 * The response data packets would have been detected in
372 		 * the check above.
373 		 */
374 		if (msgimplp->im_transp_op_flags & IBMF_MSG_TRANS_FLAG_RMPP) {
375 			ibmf_rmpp_ctx_t *rmpp_ctx = &msgimplp->im_rmpp_ctx;
376 			ibmf_msg_bufs_t *msgbufp;
377 
378 			_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*rmpp_ctx))
379 
380 			if ((rmpp_hdr != NULL) &&
381 			    (rmpp_hdr->rmpp_flags & IBMF_RMPP_FLAGS_ACTIVE)) {
382 
383 				/*
384 				 * If non-sequenced, then there should be
385 				 * no DATA packets incoming for this transaction
386 				 */
387 				if (!(msgimplp->im_transp_op_flags &
388 				    IBMF_MSG_TRANS_FLAG_SEQ)) {
389 					/* Continue if DATA packet */
390 					if (rmpp_hdr->rmpp_type ==
391 					    IBMF_RMPP_TYPE_DATA) {
392 						msgimplp =
393 						    msgimplp->im_msg_next;
394 						continue;
395 					}
396 				}
397 
398 
399 				/* Skip if R_Method does not match */
400 				if ((rmpp_ctx->rmpp_state ==
401 				    IBMF_RMPP_STATE_SENDER_ACTIVE) ||
402 				    (rmpp_ctx->rmpp_state ==
403 				    IBMF_RMPP_STATE_SENDER_SWITCH)) {
404 					/* Continue if DATA packet */
405 					if (rmpp_hdr->rmpp_type ==
406 					    IBMF_RMPP_TYPE_DATA) {
407 						msgimplp =
408 						    msgimplp->im_msg_next;
409 						continue;
410 					}
411 
412 					/*
413 					 * Continue if method does not match
414 					 * Ignore response bit during match.
415 					 */
416 					msgbufp = &msgimplp->im_msgbufs_send;
417 					if ((msgbufp->im_bufs_mad_hdr->
418 					    R_Method & MAD_METHOD_MASK) !=
419 					    (r_method & MAD_METHOD_MASK)) {
420 						msgimplp = msgimplp->
421 						    im_msg_next;
422 						continue;
423 					}
424 				}
425 
426 				/* Skip if R_Method does not match */
427 				if ((rmpp_ctx->rmpp_state ==
428 				    IBMF_RMPP_STATE_RECEVR_ACTIVE) ||
429 				    (rmpp_ctx->rmpp_state ==
430 				    IBMF_RMPP_STATE_RECEVR_TERMINATE)) {
431 					/* Continue if ACK packet */
432 					if (rmpp_hdr->rmpp_type ==
433 					    IBMF_RMPP_TYPE_ACK) {
434 						msgimplp =
435 						    msgimplp->im_msg_next;
436 						continue;
437 					}
438 
439 					/* Continue if method does not match */
440 					msgbufp = &msgimplp->im_msgbufs_recv;
441 					if (msgbufp->im_bufs_mad_hdr->
442 					    R_Method != r_method) {
443 						msgimplp = msgimplp->
444 						    im_msg_next;
445 						continue;
446 					}
447 				}
448 			}
449 		}
450 
451 		/*
452 		 * For a sequenced non-RMPP transaction, if the
453 		 * TID/LID/MgtClass are the same, and if the method
454 		 * of the incoming MAD and the message context are the
455 		 * same, then the MAD is likely to be a new request from
456 		 * the remote entity, so skip this message.
457 		 */
458 		if ((msgimplp->im_transp_op_flags & IBMF_MSG_TRANS_FLAG_SEQ) &&
459 		    !(msgimplp->im_transp_op_flags &
460 		    IBMF_MSG_TRANS_FLAG_RMPP)) {
461 			ibmf_msg_bufs_t *msgbufp;
462 
463 			mutex_enter(&msgimplp->im_mutex);
464 
465 			msgbufp = &msgimplp->im_msgbufs_send;
466 
467 			mutex_exit(&msgimplp->im_mutex);
468 
469 			/* Continue if method is the same */
470 			if (msgbufp->im_bufs_mad_hdr->
471 			    R_Method == r_method) {
472 				msgimplp = msgimplp-> im_msg_next;
473 				continue;
474 			}
475 		}
476 
477 		/* everything matches, found the correct message */
478 		msg_found = B_TRUE;
479 		break;
480 	}
481 
482 	if (msg_found == B_TRUE) {
483 
484 		mutex_enter(&msgimplp->im_mutex);
485 
486 		IBMF_MSG_INCR_REFCNT(msgimplp);
487 
488 		IBMF_TRACE_3(IBMF_TNF_DEBUG, DPRINT_L3,
489 		    ibmf_i_find_msg, IBMF_TNF_TRACE, "",
490 		    "ibmf_i_find_msg(): %s, msgp = 0x%p, ref_cnt = 0x%d\n",
491 		    tnf_string, msg, "Found message. Inc ref count",
492 		    tnf_opaque, msgimplp, msgimplp,
493 		    tnf_uint, ref_count, msgimplp->im_ref_count);
494 
495 		mutex_exit(&msgimplp->im_mutex);
496 	}
497 
498 	mutex_exit(&clientp->ic_msg_mutex);
499 
500 	IBMF_TRACE_1(IBMF_TNF_DEBUG, DPRINT_L4,
501 	    ibmf_i_find_msg_end, IBMF_TNF_TRACE, "",
502 	    "ibmf_i_find_msg() exit, msgp = 0x%p\n", tnf_opaque, msg, msgimplp);
503 
504 	return (msgimplp);
505 }
506 
507 /*
508  * ibmf_i_find_msg_client():
509  *	Walk the client message list to find the specified message
510  */
511 boolean_t
512 ibmf_i_find_msg_client(ibmf_client_t *clp, ibmf_msg_impl_t *msgimplp,
513     boolean_t inc_refcnt)
514 {
515 	ibmf_msg_impl_t	*msgp;
516 	boolean_t	found = B_FALSE;
517 
518 	IBMF_TRACE_2(IBMF_TNF_DEBUG, DPRINT_L4,
519 	    ibmf_i_find_msg_client_start, IBMF_TNF_TRACE, "",
520 	    "ibmf_i_find_msg_client(): clientp = 0x%p, msgp = 0x%p\n",
521 	    tnf_opaque, clientp, clp, tnf_opaque, msg, msgimplp);
522 
523 	mutex_enter(&clp->ic_msg_mutex);
524 
525 	msgp = clp->ic_msg_list;
526 	while (msgp != NULL) {
527 
528 		if (msgp == msgimplp) {
529 
530 			/* grab the mutex */
531 			mutex_enter(&msgimplp->im_mutex);
532 
533 			if (inc_refcnt == B_TRUE)
534 				IBMF_MSG_INCR_REFCNT(msgimplp);
535 
536 			IBMF_TRACE_3(IBMF_TNF_DEBUG, DPRINT_L3,
537 			    ibmf_i_find_msg_client, IBMF_TNF_TRACE, "",
538 			    "ibmf_i_find_msg_client(): %s, msgp = 0x%p, "
539 			    "ref_cnt = 0x%d\n",
540 			    tnf_string, msg, "Found message. Inc ref count",
541 			    tnf_opaque, msgimplp, msgimplp,
542 			    tnf_uint, ref_count, msgimplp->im_ref_count);
543 
544 			mutex_exit(&msgimplp->im_mutex);
545 
546 			found = B_TRUE;
547 
548 			break;
549 		}
550 		msgp = msgp->im_msg_next;
551 	}
552 
553 	/*
554 	 * If not found on the regular message list,
555 	 * look in the termination list.
556 	 */
557 	if (found == B_FALSE) {
558 		msgp = clp->ic_term_msg_list;
559 		while (msgp != NULL) {
560 			if (msgp == msgimplp) {
561 
562 				/* grab the mutex */
563 				mutex_enter(&msgimplp->im_mutex);
564 
565 				if (inc_refcnt == B_TRUE)
566 					IBMF_MSG_INCR_REFCNT(msgimplp);
567 
568 				IBMF_TRACE_3(IBMF_TNF_DEBUG, DPRINT_L3,
569 				    ibmf_i_find_msg_client, IBMF_TNF_TRACE, "",
570 				    "ibmf_i_find_msg_client(): %s, "
571 				    "msgp = 0x%p, ref_cnt = 0x%d\n", tnf_string,
572 				    msg, "Found message. Inc ref count",
573 				    tnf_opaque, msgimplp, msgimplp, tnf_uint,
574 				    ref_count, msgimplp->im_ref_count);
575 
576 				mutex_exit(&msgimplp->im_mutex);
577 				found = B_TRUE;
578 				break;
579 			}
580 			msgp = msgp->im_msg_next;
581 		}
582 	}
583 
584 	mutex_exit(&clp->ic_msg_mutex);
585 
586 	IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
587 	    ibmf_i_find_msg_client_end, IBMF_TNF_TRACE, "",
588 	    "ibmf_i_find_msg_client() exit\n");
589 
590 	return (found);
591 }
592 
593 /*
594  * ibmf_setup_recvbuf_on_error():
595  *
596  * This function is used to set up the receive buffers to provide
597  * a context for sending ABORT MADs in cases where the protocol
598  * fails before the receive buffers have been setup. This can happen
599  * if the initial receive MAD has a bad version, or an unexpected
600  * segment number, for example.
601  * We allocate IBMF_MAD_SIZE memory as we only need the information
602  * stored in the MAD header and the class header to be able to send
603  * the ABORT.
604  */
605 int
606 ibmf_setup_recvbuf_on_error(ibmf_msg_impl_t *msgimplp, uchar_t *mad)
607 {
608 	size_t		offset;
609 	uint32_t	cl_hdr_sz, cl_hdr_off;
610 	ib_mad_hdr_t	*mad_hdr;
611 	uchar_t		*msgbufp;
612 	ibmf_client_t	*clientp = (ibmf_client_t *)msgimplp->im_client;
613 
614 	ASSERT(msgimplp->im_msgbufs_recv.im_bufs_mad_hdr == NULL);
615 
616 	/*
617 	 * Allocate enough memory for the MAD headers only.
618 	 */
619 	msgimplp->im_msgbufs_recv.im_bufs_mad_hdr =
620 	    (ib_mad_hdr_t *)kmem_zalloc(IBMF_MAD_SIZE, KM_NOSLEEP);
621 	if (msgimplp->im_msgbufs_recv.im_bufs_mad_hdr == NULL) {
622 		IBMF_TRACE_1(IBMF_TNF_NODEBUG, DPRINT_L1,
623 		    ibmf_setup_recvbuf_on_error, IBMF_TNF_ERROR, "",
624 		    "ibmf_setup_recvbuf_on_error(): %s\n", tnf_string, msg,
625 		    "recv buf mem allocation failure");
626 		IBMF_TRACE_0(IBMF_TNF_DEBUG, DPRINT_L4,
627 		    ibmf_setup_recvbuf_on_error_end, IBMF_TNF_TRACE, "",
628 		    "ibmf_setup_recvbuf_on_error() exit\n");
629 		return (IBMF_NO_RESOURCES);
630 	}
631 
632 	mutex_enter(&clientp->ic_kstat_mutex);
633 	IBMF_ADD32_KSTATS(clientp, recv_bufs_alloced, 1);
634 	mutex_exit(&clientp->ic_kstat_mutex);
635 
636 	mad_hdr = (ib_mad_hdr_t *)mad;
637 
638 	/* Get the class header size and offset */
639 	ibmf_i_mgt_class_to_hdr_sz_off(mad_hdr->MgmtClass, &cl_hdr_sz,
640 	    &cl_hdr_off);
641 
642 	msgbufp = (uchar_t *)msgimplp->im_msgbufs_recv.im_bufs_mad_hdr;
643 
644 	/* copy the MAD and class header */
645 	bcopy((const void *)mad, (void *)msgbufp,
646 	    sizeof (ib_mad_hdr_t) + cl_hdr_off + cl_hdr_sz);
647 
648 	/* offset of the class header */
649 	offset = sizeof (ib_mad_hdr_t) + cl_hdr_off;
650 
651 	/* initialize class header pointer */
652 	if (cl_hdr_sz == 0) {
653 		msgimplp->im_msgbufs_recv.im_bufs_cl_hdr = NULL;
654 	} else {
655 		msgimplp->im_msgbufs_recv.im_bufs_cl_hdr =
656 		    (void *)(msgbufp + offset);
657 	}
658 
659 	/* Set the class header length */
660 	msgimplp->im_msgbufs_recv.im_bufs_cl_hdr_len = cl_hdr_sz;
661 
662 	/* offset of the class data */
663 	offset += cl_hdr_sz;
664 
665 	/* initialize data area pointer */
666 	msgimplp->im_msgbufs_recv.im_bufs_cl_data = (void *)(msgbufp + offset);
667 	msgimplp->im_msgbufs_recv.im_bufs_cl_data_len = IBMF_MAD_SIZE -
668 	    sizeof (ib_mad_hdr_t) - cl_hdr_off - cl_hdr_sz;
669 
670 	return (IBMF_SUCCESS);
671 }
672