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
35extern int ibmf_trace_level;
36
37/*
38 * ibmf_i_client_add_msg():
39 *	Add the message to the client message list
40 */
41void
42ibmf_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 */
116void
117ibmf_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 */
214ibmf_msg_impl_t *
215ibmf_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 */
511boolean_t
512ibmf_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 */
605int
606ibmf_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