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
ibmf_i_client_add_msg(ibmf_client_t * clientp,ibmf_msg_impl_t * msgimplp)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
ibmf_i_client_rem_msg(ibmf_client_t * clientp,ibmf_msg_impl_t * msgimplp,uint_t * refcnt)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 *
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)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
ibmf_i_find_msg_client(ibmf_client_t * clp,ibmf_msg_impl_t * msgimplp,boolean_t inc_refcnt)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
ibmf_setup_recvbuf_on_error(ibmf_msg_impl_t * msgimplp,uchar_t * mad)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