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