Print this page
8368 remove warlock leftovers from usr/src/uts
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/common/io/ib/adapters/hermon/hermon_agents.c
+++ new/usr/src/uts/common/io/ib/adapters/hermon/hermon_agents.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21
22 22 /*
23 23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 24 * Use is subject to license terms.
25 25 */
26 26
27 27 /*
28 28 * hermon_agents.c
29 29 * Hermon InfiniBand Management Agent (SMA, PMA, BMA) routines
30 30 *
31 31 * Implements all the routines necessary for initializing, handling,
32 32 * and (later) tearing down all the infrastructure necessary for Hermon
33 33 * MAD processing.
34 34 */
35 35
36 36 #include <sys/types.h>
37 37 #include <sys/conf.h>
38 38 #include <sys/ddi.h>
39 39 #include <sys/sunddi.h>
40 40 #include <sys/modctl.h>
41 41
42 42 #include <sys/ib/adapters/hermon/hermon.h>
43 43 #include <sys/ib/mgt/ibmf/ibmf.h>
44 44 #include <sys/disp.h>
45 45
46 46 static void hermon_agent_request_cb(ibmf_handle_t ibmf_handle,
47 47 ibmf_msg_t *msgp, void *args);
48 48 static void hermon_agent_handle_req(void *cb_args);
49 49 static void hermon_agent_response_cb(ibmf_handle_t ibmf_handle,
50 50 ibmf_msg_t *msgp, void *args);
51 51 static int hermon_agent_list_init(hermon_state_t *state);
52 52 static void hermon_agent_list_fini(hermon_state_t *state);
53 53 static int hermon_agent_register_all(hermon_state_t *state);
54 54 static int hermon_agent_unregister_all(hermon_state_t *state, int num_reg);
55 55 static void hermon_agent_mad_resp_handling(hermon_state_t *state,
56 56 ibmf_msg_t *msgp, uint_t port);
57 57
58 58 /*
59 59 * hermon_agent_handlers_init()
60 60 * Context: Only called from attach() and/or detach() path contexts
61 61 */
62 62 int
63 63 hermon_agent_handlers_init(hermon_state_t *state)
64 64 {
65 65 int status;
66 66 char *rsrc_name;
67 67
68 68 /* Determine if we need to register any agents with the IBMF */
69 69 if ((state->hs_cfg_profile->cp_qp0_agents_in_fw) &&
70 70 (state->hs_cfg_profile->cp_qp1_agents_in_fw)) {
71 71 return (DDI_SUCCESS);
72 72 }
73 73
74 74 /*
75 75 * Build a unique name for the Hermon task queue from the Hermon driver
76 76 * instance number and HERMON_TASKQ_NAME
77 77 */
78 78 rsrc_name = (char *)kmem_zalloc(HERMON_RSRC_NAME_MAXLEN, KM_SLEEP);
79 79 HERMON_RSRC_NAME(rsrc_name, HERMON_TASKQ_NAME);
80 80
81 81 /* Initialize the Hermon IB management agent list */
82 82 status = hermon_agent_list_init(state);
83 83 if (status != DDI_SUCCESS) {
84 84 goto agentsinit_fail;
85 85 }
86 86
87 87 /*
88 88 * Initialize the agent handling task queue. Note: We set the task
89 89 * queue priority to the minimum system priority. At this point this
90 90 * is considered acceptable because MADs are unreliable datagrams
91 91 * and could get lost (in general) anyway.
92 92 */
93 93 state->hs_taskq_agents = ddi_taskq_create(state->hs_dip,
94 94 rsrc_name, HERMON_TASKQ_NTHREADS, TASKQ_DEFAULTPRI, 0);
95 95 if (state->hs_taskq_agents == NULL) {
96 96 hermon_agent_list_fini(state);
97 97 goto agentsinit_fail;
98 98 }
99 99
100 100 /* Now attempt to register all of the agents with the IBMF */
101 101 status = hermon_agent_register_all(state);
102 102 if (status != DDI_SUCCESS) {
103 103 ddi_taskq_destroy(state->hs_taskq_agents);
104 104 hermon_agent_list_fini(state);
105 105 goto agentsinit_fail;
106 106 }
107 107
108 108 kmem_free(rsrc_name, HERMON_RSRC_NAME_MAXLEN);
109 109 return (DDI_SUCCESS);
110 110
111 111 agentsinit_fail:
112 112 kmem_free(rsrc_name, HERMON_RSRC_NAME_MAXLEN);
113 113 return (status);
114 114 }
115 115
116 116
117 117 /*
118 118 * hermon_agent_handlers_fini()
119 119 * Context: Only called from detach() path context
120 120 */
121 121 int
122 122 hermon_agent_handlers_fini(hermon_state_t *state)
123 123 {
124 124 int status;
125 125
126 126 /* Determine if we need to unregister any agents from the IBMF */
127 127 if ((state->hs_cfg_profile->cp_qp0_agents_in_fw) &&
128 128 (state->hs_cfg_profile->cp_qp1_agents_in_fw)) {
129 129 return (DDI_SUCCESS);
130 130 }
131 131
132 132 /* Now attempt to unregister all of the agents from the IBMF */
133 133 status = hermon_agent_unregister_all(state, state->hs_num_agents);
134 134 if (status != DDI_SUCCESS) {
135 135 return (DDI_FAILURE);
136 136 }
137 137
138 138 /*
139 139 * Destroy the task queue. The task queue destroy is guaranteed to
140 140 * wait until any scheduled tasks have completed. We are able to
141 141 * guarantee that no _new_ tasks will be added the task queue while
142 142 * we are in the ddi_taskq_destroy() call because we have
143 143 * (at this point) successfully unregistered from IBMF (in
144 144 * hermon_agent_unregister_all() above).
145 145 */
146 146 ddi_taskq_destroy(state->hs_taskq_agents);
147 147
148 148 /* Teardown the Hermon IB management agent list */
149 149 hermon_agent_list_fini(state);
150 150
151 151 return (DDI_SUCCESS);
152 152 }
153 153
154 154
155 155 /*
156 156 * hermon_agent_request_cb()
157 157 * Context: Called from the IBMF context
158 158 */
159 159 static void
160 160 hermon_agent_request_cb(ibmf_handle_t ibmf_handle, ibmf_msg_t *msgp,
161 161 void *args)
162 162 {
163 163 hermon_agent_handler_arg_t *cb_args;
164 164 hermon_agent_list_t *curr;
165 165 hermon_state_t *state;
166 166 int status;
167 167
168 168 curr = (hermon_agent_list_t *)args;
169 169 state = curr->agl_state;
170 170
171 171 /*
172 172 * Allocate space to hold the callback args (for passing to the
↓ open down ↓ |
172 lines elided |
↑ open up ↑ |
173 173 * task queue). Note: If we are unable to allocate space for the
174 174 * the callback args here, then we just return. But we must ensure
175 175 * that we call ibmf_free_msg() to free up the message.
176 176 */
177 177 cb_args = (hermon_agent_handler_arg_t *)kmem_zalloc(
178 178 sizeof (hermon_agent_handler_arg_t), KM_NOSLEEP);
179 179 if (cb_args == NULL) {
180 180 (void) ibmf_free_msg(ibmf_handle, &msgp);
181 181 return;
182 182 }
183 - _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*cb_args))
184 183
185 184 /* Fill in the callback args */
186 185 cb_args->ahd_ibmfhdl = ibmf_handle;
187 186 cb_args->ahd_ibmfmsg = msgp;
188 187 cb_args->ahd_agentlist = args;
189 188
190 189 /*
191 190 * Dispatch the message to the task queue. Note: Just like above,
192 191 * if this request fails for any reason then make sure to free up
193 192 * the IBMF message and then return
194 193 */
195 194 status = ddi_taskq_dispatch(state->hs_taskq_agents,
196 195 hermon_agent_handle_req, cb_args, DDI_NOSLEEP);
197 196 if (status == DDI_FAILURE) {
198 197 kmem_free(cb_args, sizeof (hermon_agent_handler_arg_t));
199 198 (void) ibmf_free_msg(ibmf_handle, &msgp);
200 199 }
201 200 }
202 201
203 202 /*
204 203 * hermon_get_smlid()
205 204 * Simple helper function for hermon_agent_handle_req() below.
206 205 * Get the portinfo and extract the smlid.
207 206 */
208 207 static ib_lid_t
209 208 hermon_get_smlid(hermon_state_t *state, uint_t port)
210 209 {
211 210 sm_portinfo_t portinfo;
212 211 int status;
213 212
214 213 status = hermon_getportinfo_cmd_post(state, port,
215 214 HERMON_SLEEPFLAG_FOR_CONTEXT(), &portinfo);
216 215 if (status != HERMON_CMD_SUCCESS) {
217 216 cmn_err(CE_CONT, "Hermon: GetPortInfo (port %02d) command "
218 217 "failed: %08x\n", port, status);
219 218 return (0);
220 219 }
221 220 return (portinfo.MasterSMLID);
222 221 }
223 222
224 223 /*
225 224 * hermon_get_port_change_flags()
226 225 * Helper function to determine the changes in the incoming MAD's portinfo
227 226 * for the Port Change event.
228 227 */
229 228 static ibt_port_change_t
230 229 hermon_port_change_flags(sm_portinfo_t *curpinfo, sm_portinfo_t *madpinfo)
231 230 {
232 231 int SMDisabled, ReregSuppd;
233 232 ibt_port_change_t flags = 0;
234 233
235 234 SMDisabled = curpinfo->CapabilityMask & SM_CAP_MASK_IS_SM_DISABLED;
236 235 ReregSuppd = curpinfo->CapabilityMask & SM_CAP_MASK_IS_CLNT_REREG_SUPPD;
237 236
238 237 if (curpinfo->MasterSMLID != madpinfo->MasterSMLID) {
239 238 flags |= IBT_PORT_CHANGE_SM_LID;
240 239 }
241 240 if (curpinfo->MasterSMSL != madpinfo->MasterSMSL) {
242 241 flags |= IBT_PORT_CHANGE_SM_SL;
243 242 }
244 243 if (curpinfo->SubnetTimeOut != madpinfo->SubnetTimeOut) {
245 244 flags |= IBT_PORT_CHANGE_SUB_TIMEOUT;
246 245 }
247 246 if ((madpinfo->CapabilityMask & SM_CAP_MASK_IS_SM_DISABLED)
248 247 ^ SMDisabled) {
249 248 flags |= IBT_PORT_CHANGE_SM_FLAG;
250 249 }
251 250 if ((madpinfo->CapabilityMask & SM_CAP_MASK_IS_CLNT_REREG_SUPPD)
252 251 ^ ReregSuppd) {
253 252 flags |= IBT_PORT_CHANGE_REREG;
254 253 }
255 254 return (flags);
256 255 }
257 256
258 257 int
259 258 hermon_set_port_capability(hermon_state_t *state, uint8_t port,
260 259 sm_portinfo_t *portinfo, ibt_port_change_t flags)
261 260 {
262 261 uint32_t capmask;
263 262 int status;
264 263 hermon_hw_set_port_t set_port;
265 264
266 265 bzero(&set_port, sizeof (set_port));
267 266
268 267 /* Validate that specified port number is legal */
269 268 if (!hermon_portnum_is_valid(state, port)) {
270 269 return (IBT_HCA_PORT_INVALID);
271 270 }
272 271
273 272 /*
274 273 * Convert InfiniBand-defined port capability flags to the format
275 274 * specified by the IBTF. Specifically, we modify the capability
276 275 * mask based on the specified values.
277 276 */
278 277 capmask = portinfo->CapabilityMask;
279 278
280 279 if (flags & IBT_PORT_CHANGE_SM_FLAG)
281 280 capmask ^= SM_CAP_MASK_IS_SM;
282 281
283 282 if (flags & IBT_PORT_CHANGE_REREG)
284 283 capmask ^= SM_CAP_MASK_IS_CLNT_REREG_SUPPD;
285 284 set_port.cap_mask = capmask;
286 285
287 286 /*
288 287 * Use the Hermon SET_PORT command to update the capability mask and
289 288 * (possibly) reset the QKey violation counter for the specified port.
290 289 * Note: In general, this operation shouldn't fail. If it does, then
291 290 * it is an indication that something (probably in HW, but maybe in
292 291 * SW) has gone seriously wrong.
293 292 */
294 293 status = hermon_set_port_cmd_post(state, &set_port, port,
295 294 HERMON_SLEEPFLAG_FOR_CONTEXT());
296 295 if (status != HERMON_CMD_SUCCESS) {
297 296 HERMON_WARNING(state, "failed to modify port capabilities");
298 297 cmn_err(CE_CONT, "Hermon: SET_IB (port %02d) command failed: "
299 298 "%08x\n", port, status);
300 299 return (DDI_FAILURE);
301 300 }
302 301
303 302 return (DDI_SUCCESS);
304 303 }
305 304
306 305 /*
307 306 * hermon_agent_handle_req()
308 307 * Context: Called with priority of taskQ thread
309 308 */
310 309 static void
311 310 hermon_agent_handle_req(void *cb_args)
312 311 {
313 312 hermon_agent_handler_arg_t *agent_args;
314 313 hermon_agent_list_t *curr;
315 314 ibc_async_event_t event;
316 315 ibt_async_code_t type, code;
317 316 sm_portinfo_t curpinfo, tmadpinfo;
318 317 sm_portinfo_t *madpinfop;
↓ open down ↓ |
125 lines elided |
↑ open up ↑ |
319 318 hermon_state_t *state;
320 319 ibmf_handle_t ibmf_handle;
321 320 ibmf_msg_t *msgp;
322 321 ibmf_msg_bufs_t *recv_msgbufp;
323 322 ibmf_msg_bufs_t *send_msgbufp;
324 323 ib_mad_hdr_t *madhdrp;
325 324 ibmf_retrans_t retrans;
326 325 uint_t port;
327 326 int status;
328 327
329 - _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*((sm_portinfo_t *)madpinfop)))
330 - _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(curpinfo))
331 - _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(tmadpinfo))
332 328 /* Extract the necessary info from the callback args parameter */
333 329 agent_args = (hermon_agent_handler_arg_t *)cb_args;
334 330 ibmf_handle = agent_args->ahd_ibmfhdl;
335 331 msgp = agent_args->ahd_ibmfmsg;
336 332 curr = agent_args->ahd_agentlist;
337 333 state = curr->agl_state;
338 334 port = curr->agl_port;
339 335
340 336 /*
341 337 * Set the message send buffer pointers to the message receive buffer
342 338 * pointers to reuse the IBMF provided buffers for the sender
343 339 * information.
344 340 */
345 341 recv_msgbufp = &msgp->im_msgbufs_recv;
346 342 send_msgbufp = &msgp->im_msgbufs_send;
347 343 bcopy(recv_msgbufp, send_msgbufp, sizeof (ibmf_msg_bufs_t));
348 344
349 345 /*
350 346 * Check if the incoming packet is a special "Hermon Trap" MAD. If it
351 347 * is, then do the special handling. If it isn't, then simply pass it
352 348 * on to the firmware and forward the response back to the IBMF.
↓ open down ↓ |
11 lines elided |
↑ open up ↑ |
353 349 *
354 350 * Note: Hermon has a unique method for handling internally generated
355 351 * Traps. All internally detected/generated Trap messages are
356 352 * automatically received by the IBMF (as receive completions on QP0),
357 353 * which (because all Hermon Trap MADs have SLID == 0) detects it as a
358 354 * special "Hermon Trap" and forwards it here to the driver's SMA.
359 355 * It is then our responsibility here to fill in the Trap MAD's DLID
360 356 * for forwarding to the real Master SM (as programmed in the port's
361 357 * PortInfo.MasterSMLID field.)
362 358 */
363 - _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(msgp->im_local_addr))
364 359 if (HERMON_IS_SPECIAL_TRAP_MAD(msgp)) {
365 360 msgp->im_local_addr.ia_remote_lid =
366 361 hermon_get_smlid(state, port);
367 362 } else {
368 363 int isSMSet, isReregSuppd;
369 364 uint_t attr_id, method, mgmt_class;
370 365
371 366 madhdrp = recv_msgbufp->im_bufs_mad_hdr;
372 367 method = madhdrp->R_Method;
373 368 attr_id = b2h16(madhdrp->AttributeID);
374 369 mgmt_class = madhdrp->MgmtClass;
375 370
376 371 /*
377 372 * Is this a Subnet Manager MAD with SET method ? If so
378 373 * we will have to get the current portinfo to generate
379 374 * events based on what has changed in portinfo.
380 375 */
381 376 isSMSet = (((mgmt_class == MAD_MGMT_CLASS_SUBN_LID_ROUTED)||
382 377 (mgmt_class == MAD_MGMT_CLASS_SUBN_DIRECT_ROUTE)) &&
383 378 (method == MAD_METHOD_SET));
384 379
385 380 /*
386 381 * Get the current portinfo to compare with the portinfo
387 382 * received in the MAD for PortChange event.
388 383 */
389 384 if (isSMSet && (attr_id == SM_PORTINFO_ATTRID) ||
390 385 (attr_id == SM_PKEY_TABLE_ATTRID) ||
391 386 (attr_id == SM_GUIDINFO_ATTRID)) {
392 387 madpinfop = recv_msgbufp->im_bufs_cl_data;
393 388 tmadpinfo = *madpinfop;
394 389 HERMON_GETPORTINFO_SWAP(&tmadpinfo);
395 390 status = hermon_getportinfo_cmd_post(state, port,
396 391 HERMON_SLEEPFLAG_FOR_CONTEXT(), &curpinfo);
397 392 if (status != HERMON_CMD_SUCCESS) {
398 393 cmn_err(CE_CONT, "Hermon: GetPortInfo "
399 394 "(port %02d) command failed: %08x\n", port,
400 395 status);
401 396 goto hermon_agent_handle_req_skip_response;
402 397 }
403 398 }
404 399
405 400 /*
406 401 * Post the command to the firmware (using the MAD_IFC
407 402 * command). Note: We also reuse the command that was passed
408 403 * in. We pass the pointer to the original MAD payload as if
409 404 * it were both the source of the incoming MAD as well as the
410 405 * destination for the response. This is acceptable and saves
411 406 * us the step of one additional copy. Note: If this command
412 407 * fails for any reason other than HERMON_CMD_BAD_PKT, it
413 408 * probably indicates a serious problem.
414 409 */
415 410 status = hermon_mad_ifc_cmd_post(state, port,
416 411 HERMON_CMD_SLEEP_NOSPIN,
417 412 (uint32_t *)recv_msgbufp->im_bufs_mad_hdr,
418 413 (uint32_t *)send_msgbufp->im_bufs_mad_hdr);
419 414 if (status != HERMON_CMD_SUCCESS) {
420 415 if ((status != HERMON_CMD_BAD_PKT) &&
421 416 (status != HERMON_CMD_INSUFF_RSRC)) {
422 417 cmn_err(CE_CONT, "Hermon: MAD_IFC (port %02d) "
423 418 "command failed: %08x\n", port, status);
424 419 }
425 420
426 421 /* finish cleanup */
427 422 goto hermon_agent_handle_req_skip_response;
428 423 }
429 424
430 425 if (isSMSet) {
431 426 event.ev_port_flags = 0;
432 427 type = 0;
433 428 event.ev_port = (uint8_t)port;
434 429
435 430 switch (attr_id) {
436 431 case SM_PORTINFO_ATTRID:
437 432 /*
438 433 * This is a SM SET method with portinfo
439 434 * attribute. If ClientRereg bit was set in
440 435 * the MADs portinfo this is a REREG event
441 436 * (see section 14.4.11 in IB Spec 1.2.1). Else
442 437 * compare the current (before MAD_IFC command)
443 438 * portinfo with the portinfo in the MAD and
444 439 * signal PORT_CHANGE event with the proper
445 440 * ev_port_flags.
446 441 *
447 442 */
448 443 isReregSuppd = curpinfo.CapabilityMask &
449 444 SM_CAP_MASK_IS_CLNT_REREG_SUPPD;
450 445
451 446 madpinfop = recv_msgbufp->im_bufs_cl_data;
452 447 if (tmadpinfo.ClientRereg && isReregSuppd) {
453 448 type |= IBT_CLNT_REREG_EVENT;
454 449 }
455 450
456 451 type |= IBT_PORT_CHANGE_EVENT;
457 452 event.ev_port_flags = hermon_port_change_flags(
458 453 &curpinfo, &tmadpinfo);
459 454 if (event.ev_port_flags &
460 455 (IBT_PORT_CHANGE_REREG |
461 456 IBT_PORT_CHANGE_SM_FLAG)) {
462 457 if (hermon_set_port_capability(state,
463 458 port, &curpinfo,
464 459 event.ev_port_flags)
465 460 != DDI_SUCCESS) {
466 461 cmn_err(CE_CONT, "HERMON: Port "
467 462 "%d capability reset "
468 463 "failed\n", port);
469 464 }
470 465 }
471 466
472 467 /*
473 468 * If we have a SMLID change event but
474 469 * capability mask doesn't have Rereg support
475 470 * bit set, we have to do the Rereg part too.
476 471 */
477 472 if ((event.ev_port_flags &
478 473 IBT_PORT_CHANGE_SM_LID) && !isReregSuppd)
479 474 type |= IBT_CLNT_REREG_EVENT;
480 475 break;
481 476 case SM_PKEY_TABLE_ATTRID:
482 477 type |= IBT_PORT_CHANGE_EVENT;
483 478 event.ev_port_flags = IBT_PORT_CHANGE_PKEY;
484 479 break;
485 480 case SM_GUIDINFO_ATTRID:
486 481 type |= IBT_PORT_CHANGE_EVENT;
487 482 event.ev_port_flags = IBT_PORT_CHANGE_SGID;
488 483 break;
489 484 default:
490 485 break;
491 486
492 487 }
493 488
494 489 /*
495 490 * NOTE: here we call ibc_async_handler directly without
496 491 * using the HERMON_DO_IBTF_ASYNC_CALLB, since hermon
497 492 * can not be unloaded till ibmf_unregiter is done and
498 493 * this thread (hs_taskq_agents) will be destroyed
499 494 * before ibmf_uregister is called.
500 495 *
501 496 * The hermon event queue based hs_in_evcallb flag
502 497 * assumes that we will pick one event after another
503 498 * and dispatch them sequentially. If we use
504 499 * HERMON_DO_IBTF_ASYNC_CALLB, we will break this
505 500 * assumption make hs_in_evcallb inconsistent.
506 501 */
507 502 while (type != 0) {
508 503 if (type & IBT_PORT_CHANGE_EVENT) {
509 504 code = IBT_PORT_CHANGE_EVENT;
510 505 type &= ~IBT_PORT_CHANGE_EVENT;
511 506 } else {
512 507 code = IBT_CLNT_REREG_EVENT;
513 508 type = 0;
514 509 }
515 510 ibc_async_handler(state->hs_ibtfpriv, code,
516 511 &event);
517 512 }
518 513 }
519 514 }
520 515
521 516 /*
522 517 * If incoming MAD was "TrapRepress", then no response is necessary.
523 518 * Free the IBMF message and return.
524 519 */
525 520 if (HERMON_IS_TRAP_REPRESS_MAD(msgp)) {
526 521 goto hermon_agent_handle_req_skip_response;
527 522 }
528 523
529 524 /*
530 525 * Modify the response MAD as necessary (for any special cases).
531 526 * Specifically, if this MAD was a directed route MAD, then some
532 527 * additional packet manipulation may be necessary because the Hermon
533 528 * firmware does not do all the required steps to respond to the
534 529 * MAD.
535 530 */
536 531 hermon_agent_mad_resp_handling(state, msgp, port);
537 532
538 533 /*
539 534 * Send response (or forwarded "Trap" MAD) back to IBMF. We use the
540 535 * "response callback" to indicate when it is appropriate (later) to
541 536 * free the IBMF msg.
542 537 */
543 538 status = ibmf_msg_transport(ibmf_handle, IBMF_QP_HANDLE_DEFAULT,
544 539 msgp, &retrans, hermon_agent_response_cb, state, 0);
545 540 if (status != IBMF_SUCCESS) {
546 541 goto hermon_agent_handle_req_skip_response;
547 542 }
548 543
549 544 /* Free up the callback args parameter */
550 545 kmem_free(agent_args, sizeof (hermon_agent_handler_arg_t));
551 546 return;
552 547
553 548 hermon_agent_handle_req_skip_response:
554 549 /* Free up the ibmf message */
555 550 (void) ibmf_free_msg(ibmf_handle, &msgp);
556 551
557 552 /* Free up the callback args parameter */
558 553 kmem_free(agent_args, sizeof (hermon_agent_handler_arg_t));
559 554 }
560 555
561 556
562 557 /*
563 558 * hermon_agent_response_cb()
564 559 * Context: Called from the IBMF context
565 560 */
566 561 /* ARGSUSED */
567 562 static void
568 563 hermon_agent_response_cb(ibmf_handle_t ibmf_handle, ibmf_msg_t *msgp,
569 564 void *args)
570 565 {
571 566 /*
572 567 * It is the responsibility of each IBMF callback recipient to free
573 568 * the packets that it has been given. Now that we are in the
574 569 * response callback, we can be assured that it is safe to do so.
575 570 */
576 571 (void) ibmf_free_msg(ibmf_handle, &msgp);
577 572 }
578 573
579 574
580 575 /*
581 576 * hermon_agent_list_init()
582 577 * Context: Only called from attach() path context
583 578 */
584 579 static int
585 580 hermon_agent_list_init(hermon_state_t *state)
586 581 {
587 582 hermon_agent_list_t *curr;
588 583 uint_t num_ports, num_agents, num_agents_per_port;
589 584 uint_t num_sma_agents = 0;
590 585 uint_t num_pma_agents = 0;
591 586 uint_t num_bma_agents = 0;
592 587 uint_t do_qp0, do_qp1;
593 588 int i, j, indx;
594 589
595 590 /*
596 591 * Calculate the number of registered agents for each port
597 592 * (SMA, PMA, and BMA) and determine whether or not to register
598 593 * a given agent with the IBMF (or whether to let the Hermon firmware
599 594 * handle it)
600 595 */
601 596 num_ports = state->hs_cfg_profile->cp_num_ports;
602 597 num_agents = 0;
603 598 num_agents_per_port = 0;
604 599 do_qp0 = state->hs_cfg_profile->cp_qp0_agents_in_fw;
605 600 do_qp1 = state->hs_cfg_profile->cp_qp1_agents_in_fw;
606 601 if (do_qp0 == 0) {
607 602 num_agents += (num_ports * HERMON_NUM_QP0_AGENTS_PER_PORT);
608 603 num_agents_per_port += HERMON_NUM_QP0_AGENTS_PER_PORT;
609 604 num_sma_agents = num_ports;
610 605 }
611 606 if (do_qp1 == 0) {
612 607 num_agents += (num_ports * HERMON_NUM_QP1_AGENTS_PER_PORT);
613 608 num_agents_per_port += HERMON_NUM_QP1_AGENTS_PER_PORT;
614 609 num_pma_agents = num_ports;
615 610 /*
616 611 * The following line is commented out because the Hermon
617 612 * firmware does not currently support a BMA. If it did,
618 613 * then we would want to register the agent with the IBMF.
619 614 * (We would also need to have HERMON_NUM_QP1_AGENTS_PER_PORT
620 615 * set to 2, instead of 1.)
621 616 *
622 617 * num_bma_agents = num_ports;
623 618 */
624 619 }
625 620
626 621 state->hs_num_agents = num_agents;
627 622
628 623 /*
629 624 * Allocate the memory for all of the agent list entries
630 625 */
631 626 state->hs_agents = (hermon_agent_list_t *)kmem_zalloc(num_agents *
632 627 sizeof (hermon_agent_list_t), KM_SLEEP);
633 628 if (state->hs_agents == NULL) {
634 629 return (DDI_FAILURE);
635 630 }
636 631
637 632 /*
638 633 * Fill in each of the agent list entries with the agent's
639 634 * MgmtClass, port number, and Hermon softstate pointer
640 635 */
641 636 indx = 0;
642 637 for (i = 0; i < num_agents_per_port; i++) {
643 638 for (j = 0; j < num_ports; j++) {
644 639 curr = &state->hs_agents[indx];
645 640 curr->agl_state = state;
646 641 curr->agl_port = j + 1;
647 642
648 643 if ((do_qp0 == 0) && num_sma_agents) {
649 644 curr->agl_mgmtclass = SUBN_AGENT;
650 645 num_sma_agents--;
651 646 indx++;
652 647 } else if ((do_qp1 == 0) && (num_pma_agents)) {
653 648 curr->agl_mgmtclass = PERF_AGENT;
654 649 num_pma_agents--;
655 650 indx++;
656 651 } else if ((do_qp1 == 0) && (num_bma_agents)) {
657 652 curr->agl_mgmtclass = BM_AGENT;
658 653 num_bma_agents--;
659 654 indx++;
660 655 }
661 656 }
662 657 }
663 658
664 659 return (DDI_SUCCESS);
665 660 }
666 661
667 662
668 663 /*
669 664 * hermon_agent_list_fini()
670 665 * Context: Only called from attach() and/or detach() path contexts
671 666 */
672 667 static void
673 668 hermon_agent_list_fini(hermon_state_t *state)
674 669 {
675 670 /* Free up the memory for the agent list entries */
676 671 kmem_free(state->hs_agents,
677 672 state->hs_num_agents * sizeof (hermon_agent_list_t));
678 673 }
679 674
680 675
681 676 /*
682 677 * hermon_agent_register_all()
683 678 * Context: Only called from attach() path context
684 679 */
685 680 static int
686 681 hermon_agent_register_all(hermon_state_t *state)
687 682 {
688 683 hermon_agent_list_t *curr;
689 684 ibmf_register_info_t ibmf_reg;
690 685 ibmf_impl_caps_t impl_caps;
691 686 ib_guid_t nodeguid;
692 687 int i, status, num_registered;
693 688
694 689 /* Get the Hermon NodeGUID from the softstate */
695 690 nodeguid = state->hs_ibtfinfo.hca_attr->hca_node_guid;
696 691
697 692 /*
698 693 * Register each of the agents with the IBMF (and add callbacks for
699 694 * each to the hermon_agent_request_cb() routine). Note: If we
700 695 * fail somewhere along the line here, we attempt to cleanup as much
701 696 * of the mess as we can and then jump to hermon_agent_unregister_all()
702 697 * to cleanup the rest.
703 698 */
704 699 num_registered = 0;
705 700
706 701 if (state->hs_num_agents == 0) {
707 702 return (DDI_SUCCESS);
708 703 }
709 704
710 705 for (i = 0; i < state->hs_num_agents; i++) {
711 706 /* Register each agent with the IBMF */
712 707 curr = &state->hs_agents[i];
713 708 ibmf_reg.ir_ci_guid = nodeguid;
714 709 ibmf_reg.ir_port_num = curr->agl_port;
715 710 ibmf_reg.ir_client_class = curr->agl_mgmtclass;
716 711
717 712 status = ibmf_register(&ibmf_reg, IBMF_VERSION, 0,
718 713 NULL, NULL, &curr->agl_ibmfhdl, &impl_caps);
719 714 if (status != IBMF_SUCCESS) {
720 715 goto agents_reg_fail;
721 716 }
722 717
723 718 /* Setup callbacks with the IBMF */
724 719 status = ibmf_setup_async_cb(curr->agl_ibmfhdl,
725 720 IBMF_QP_HANDLE_DEFAULT, hermon_agent_request_cb, curr, 0);
726 721 if (status != IBMF_SUCCESS) {
727 722 (void) ibmf_unregister(&curr->agl_ibmfhdl, 0);
728 723 goto agents_reg_fail;
729 724 }
730 725 num_registered++;
731 726 }
732 727
733 728 return (DDI_SUCCESS);
734 729
735 730 agents_reg_fail:
736 731 (void) hermon_agent_unregister_all(state, num_registered);
737 732 return (DDI_FAILURE);
738 733 }
739 734
740 735
741 736 /*
742 737 * hermon_agent_unregister_all()
743 738 * Context: Only called from detach() path context
744 739 */
745 740 static int
746 741 hermon_agent_unregister_all(hermon_state_t *state, int num_reg)
747 742 {
748 743 hermon_agent_list_t *curr;
749 744 int i, status;
750 745
751 746 if (num_reg == 0) {
752 747 return (DDI_SUCCESS);
753 748 }
754 749
755 750 /*
756 751 * For each registered agent in the agent list, teardown the
757 752 * callbacks from the IBMF and unregister.
758 753 */
759 754 for (i = 0; i < num_reg; i++) {
760 755 curr = &state->hs_agents[i];
761 756
762 757 /* Teardown the IBMF callback */
763 758 status = ibmf_tear_down_async_cb(curr->agl_ibmfhdl,
764 759 IBMF_QP_HANDLE_DEFAULT, 0);
765 760 if (status != IBMF_SUCCESS) {
766 761 return (DDI_FAILURE);
767 762 }
768 763
769 764 /* Unregister the agent from the IBMF */
770 765 status = ibmf_unregister(&curr->agl_ibmfhdl, 0);
771 766 if (status != IBMF_SUCCESS) {
772 767 return (DDI_FAILURE);
773 768 }
774 769 }
775 770
776 771 return (DDI_SUCCESS);
777 772 }
778 773
779 774
780 775 /*
781 776 * hermon_agent_mad_resp_handling()
782 777 * Context: Called with priority of taskQ thread
783 778 */
784 779 /* ARGSUSED */
785 780 static void
786 781 hermon_agent_mad_resp_handling(hermon_state_t *state, ibmf_msg_t *msgp,
787 782 uint_t port)
788 783 {
789 784 ib_mad_hdr_t *rmadhdrp = msgp->im_msgbufs_recv.im_bufs_mad_hdr;
790 785 ib_mad_hdr_t *smadhdrp = msgp->im_msgbufs_send.im_bufs_mad_hdr;
791 786 uint_t hop_count, hop_point;
792 787 uchar_t *resp, *ret_path;
793 788
794 789 resp = (uchar_t *)msgp->im_msgbufs_send.im_bufs_cl_data;
↓ open down ↓ |
421 lines elided |
↑ open up ↑ |
795 790
796 791 /*
797 792 * Handle directed route MADs as a special case. Hermon firmware
798 793 * does not update the "direction" bit, "hop pointer", "Return
799 794 * Path" or, in fact, any of the "directed route" parameters. So
800 795 * the responsibility falls on Hermon driver software to inspect the
801 796 * MADs and update those fields as appropriate (see section 14.2.2
802 797 * of the IBA specification, rev 1.1)
803 798 */
804 799 if (HERMON_MAD_IS_DR(rmadhdrp)) {
805 -
806 - _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*((sm_dr_mad_hdr_t *)rmadhdrp)))
807 - _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*((sm_dr_mad_hdr_t *)smadhdrp)))
808 -
809 800 /*
810 801 * Set the "Direction" bit to one. This indicates that this
811 802 * is now directed route response
812 803 */
813 804 HERMON_DRMAD_SET_DIRECTION(rmadhdrp);
814 805
815 806 /* Extract the "hop pointer" and "hop count" from the MAD */
816 807 hop_count = HERMON_DRMAD_GET_HOPCOUNT(rmadhdrp);
817 808 hop_point = HERMON_DRMAD_GET_HOPPOINTER(rmadhdrp);
818 809
819 810 /* Append the port we came in on to the "Return Path" */
820 811 if ((hop_count != 0) && ((hop_point == hop_count) ||
821 812 (hop_point == hop_count + 1))) {
822 813 ret_path = &resp[HERMON_DRMAD_RETURN_PATH_OFFSET];
823 814 ret_path[hop_point] = (uchar_t)port;
824 815 }
825 816
826 817 /* Then increment the "hop pointer" in the MAD */
827 818 hop_point++;
828 819 HERMON_DRMAD_SET_HOPPOINTER(smadhdrp, (uint8_t)hop_point);
829 820 }
830 821 }
↓ open down ↓ |
12 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX