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