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 (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
23 */
24
25 /*
26 * ibdm.c
27 *
28 * This file contains the InifiniBand Device Manager (IBDM) support functions.
29 * IB nexus driver will only be the client for the IBDM module.
30 *
31 * IBDM registers with IBTF for HCA arrival/removal notification.
32 * IBDM registers with SA access to send DM MADs to discover the IOC's behind
33 * the IOU's.
34 *
35 * IB nexus driver registers with IBDM to find the information about the
36 * HCA's and IOC's (behind the IOU) present on the IB fabric.
37 */
38
39 #include <sys/systm.h>
40 #include <sys/taskq.h>
41 #include <sys/ib/mgt/ibdm/ibdm_impl.h>
42 #include <sys/ib/mgt/ibmf/ibmf_impl.h>
43 #include <sys/ib/ibtl/impl/ibtl_ibnex.h>
44 #include <sys/modctl.h>
45
46 /* Function Prototype declarations */
47 static int ibdm_free_iou_info(ibdm_dp_gidinfo_t *, ibdm_iou_info_t **);
48 static int ibdm_fini(void);
49 static int ibdm_init(void);
50 static int ibdm_get_reachable_ports(ibdm_port_attr_t *,
51 ibdm_hca_list_t *);
52 static ibdm_dp_gidinfo_t *ibdm_check_dgid(ib_guid_t, ib_sn_prefix_t);
53 static ibdm_dp_gidinfo_t *ibdm_check_dest_nodeguid(ibdm_dp_gidinfo_t *);
54 static boolean_t ibdm_is_cisco(ib_guid_t);
55 static boolean_t ibdm_is_cisco_switch(ibdm_dp_gidinfo_t *);
56 static void ibdm_wait_cisco_probe_completion(ibdm_dp_gidinfo_t *);
57 static int ibdm_set_classportinfo(ibdm_dp_gidinfo_t *);
58 static int ibdm_send_classportinfo(ibdm_dp_gidinfo_t *);
59 static int ibdm_send_iounitinfo(ibdm_dp_gidinfo_t *);
60 static int ibdm_is_dev_mgt_supported(ibdm_dp_gidinfo_t *);
61 static int ibdm_get_node_port_guids(ibmf_saa_handle_t, ib_lid_t,
62 ib_guid_t *, ib_guid_t *);
63 static int ibdm_retry_command(ibdm_timeout_cb_args_t *);
64 static int ibdm_get_diagcode(ibdm_dp_gidinfo_t *, int);
65 static int ibdm_verify_mad_status(ib_mad_hdr_t *);
66 static int ibdm_handle_redirection(ibmf_msg_t *,
67 ibdm_dp_gidinfo_t *, int *);
68 static void ibdm_wait_probe_completion(void);
69 static void ibdm_sweep_fabric(int);
70 static void ibdm_probe_gid_thread(void *);
71 static void ibdm_wakeup_probe_gid_cv(void);
72 static void ibdm_port_attr_ibmf_init(ibdm_port_attr_t *, ib_pkey_t, int);
73 static int ibdm_port_attr_ibmf_fini(ibdm_port_attr_t *, int);
74 static void ibdm_update_port_attr(ibdm_port_attr_t *);
75 static void ibdm_handle_hca_attach(ib_guid_t);
76 static void ibdm_handle_srventry_mad(ibmf_msg_t *,
77 ibdm_dp_gidinfo_t *, int *);
78 static void ibdm_ibmf_recv_cb(ibmf_handle_t, ibmf_msg_t *, void *);
79 static void ibdm_recv_incoming_mad(void *);
80 static void ibdm_process_incoming_mad(ibmf_handle_t, ibmf_msg_t *, void *);
81 static void ibdm_ibmf_send_cb(ibmf_handle_t, ibmf_msg_t *, void *);
82 static void ibdm_pkt_timeout_hdlr(void *arg);
83 static void ibdm_initialize_port(ibdm_port_attr_t *);
84 static void ibdm_update_port_pkeys(ibdm_port_attr_t *port);
85 static void ibdm_handle_diagcode(ibmf_msg_t *, ibdm_dp_gidinfo_t *, int *);
86 static void ibdm_probe_gid(ibdm_dp_gidinfo_t *);
87 static void ibdm_alloc_send_buffers(ibmf_msg_t *);
88 static void ibdm_free_send_buffers(ibmf_msg_t *);
89 static void ibdm_handle_hca_detach(ib_guid_t);
90 static void ibdm_handle_port_change_event(ibt_async_event_t *);
91 static int ibdm_fini_port(ibdm_port_attr_t *);
92 static int ibdm_uninit_hca(ibdm_hca_list_t *);
93 static void ibdm_handle_setclassportinfo(ibmf_handle_t, ibmf_msg_t *,
94 ibdm_dp_gidinfo_t *, int *);
95 static void ibdm_handle_iounitinfo(ibmf_handle_t,
96 ibmf_msg_t *, ibdm_dp_gidinfo_t *, int *);
97 static void ibdm_handle_ioc_profile(ibmf_handle_t,
98 ibmf_msg_t *, ibdm_dp_gidinfo_t *, int *);
99 static void ibdm_event_hdlr(void *, ibt_hca_hdl_t,
100 ibt_async_code_t, ibt_async_event_t *);
101 static void ibdm_handle_classportinfo(ibmf_handle_t,
102 ibmf_msg_t *, ibdm_dp_gidinfo_t *, int *);
103 static void ibdm_update_ioc_port_gidlist(ibdm_ioc_info_t *,
104 ibdm_dp_gidinfo_t *);
105
106 static ibdm_hca_list_t *ibdm_dup_hca_attr(ibdm_hca_list_t *);
107 static ibdm_ioc_info_t *ibdm_dup_ioc_info(ibdm_ioc_info_t *,
108 ibdm_dp_gidinfo_t *gid_list);
109 static void ibdm_probe_ioc(ib_guid_t, ib_guid_t, int);
110 static ibdm_ioc_info_t *ibdm_is_ioc_present(ib_guid_t,
111 ibdm_dp_gidinfo_t *, int *);
112 static ibdm_port_attr_t *ibdm_get_port_attr(ibt_async_event_t *,
113 ibdm_hca_list_t **);
114 static sa_node_record_t *ibdm_get_node_records(ibmf_saa_handle_t,
115 size_t *, ib_guid_t);
116 static int ibdm_get_node_record_by_port(ibmf_saa_handle_t,
117 ib_guid_t, sa_node_record_t **, size_t *);
118 static sa_portinfo_record_t *ibdm_get_portinfo(ibmf_saa_handle_t, size_t *,
119 ib_lid_t);
120 static ibdm_dp_gidinfo_t *ibdm_create_gid_info(ibdm_port_attr_t *,
121 ib_gid_t, ib_gid_t);
122 static ibdm_dp_gidinfo_t *ibdm_find_gid(ib_guid_t, ib_guid_t);
123 static int ibdm_send_ioc_profile(ibdm_dp_gidinfo_t *, uint8_t);
124 static ibdm_ioc_info_t *ibdm_update_ioc_gidlist(ibdm_dp_gidinfo_t *, int);
125 static void ibdm_saa_event_cb(ibmf_saa_handle_t, ibmf_saa_subnet_event_t,
126 ibmf_saa_event_details_t *, void *);
127 static void ibdm_reprobe_update_port_srv(ibdm_ioc_info_t *,
128 ibdm_dp_gidinfo_t *);
129 static ibdm_dp_gidinfo_t *ibdm_handle_gid_rm(ibdm_dp_gidinfo_t *);
130 static void ibdm_rmfrom_glgid_list(ibdm_dp_gidinfo_t *,
131 ibdm_dp_gidinfo_t *);
132 static void ibdm_addto_gidlist(ibdm_gid_t **, ibdm_gid_t *);
133 static void ibdm_free_gid_list(ibdm_gid_t *);
134 static void ibdm_rescan_gidlist(ib_guid_t *ioc_guid);
135 static void ibdm_notify_newgid_iocs(ibdm_dp_gidinfo_t *);
136 static void ibdm_saa_event_taskq(void *);
137 static void ibdm_free_saa_event_arg(ibdm_saa_event_arg_t *);
138 static void ibdm_get_next_port(ibdm_hca_list_t **,
139 ibdm_port_attr_t **, int);
140 static void ibdm_add_to_gl_gid(ibdm_dp_gidinfo_t *,
141 ibdm_dp_gidinfo_t *);
142 static void ibdm_addto_glhcalist(ibdm_dp_gidinfo_t *,
143 ibdm_hca_list_t *);
144 static void ibdm_delete_glhca_list(ibdm_dp_gidinfo_t *);
145 static void ibdm_saa_handle_new_gid(void *);
146 static void ibdm_reset_all_dgids(ibmf_saa_handle_t);
147 static void ibdm_reset_gidinfo(ibdm_dp_gidinfo_t *);
148 static void ibdm_delete_gidinfo(ibdm_dp_gidinfo_t *);
149 static void ibdm_fill_srv_attr_mod(ib_mad_hdr_t *, ibdm_timeout_cb_args_t *);
150 static void ibdm_bump_transactionID(ibdm_dp_gidinfo_t *);
151 static ibdm_ioc_info_t *ibdm_handle_prev_iou();
152 static int ibdm_serv_cmp(ibdm_srvents_info_t *, ibdm_srvents_info_t *,
153 int);
154 static ibdm_ioc_info_t *ibdm_get_ioc_info_with_gid(ib_guid_t,
155 ibdm_dp_gidinfo_t **);
156
157 int ibdm_dft_timeout = IBDM_DFT_TIMEOUT;
158 int ibdm_dft_retry_cnt = IBDM_DFT_NRETRIES;
159 #ifdef DEBUG
160 int ibdm_ignore_saa_event = 0;
161 #endif
162 int ibdm_enumerate_iocs = 0;
163
164 /* Modload support */
165 static struct modlmisc ibdm_modlmisc = {
166 &mod_miscops,
167 "InfiniBand Device Manager"
168 };
169
170 struct modlinkage ibdm_modlinkage = {
171 MODREV_1,
172 (void *)&ibdm_modlmisc,
173 NULL
174 };
175
176 static ibt_clnt_modinfo_t ibdm_ibt_modinfo = {
177 IBTI_V_CURR,
178 IBT_DM,
179 ibdm_event_hdlr,
180 NULL,
181 "ibdm"
182 };
183
184 /* Global variables */
185 ibdm_t ibdm;
186 int ibdm_taskq_enable = IBDM_ENABLE_TASKQ_HANDLING;
187 char *ibdm_string = "ibdm";
188
189 _NOTE(SCHEME_PROTECTS_DATA("Serialized access by cv",
190 ibdm.ibdm_dp_gidlist_head))
191
192 /*
193 * _init
194 * Loadable module init, called before any other module.
195 * Initialize mutex
196 * Register with IBTF
197 */
198 int
_init(void)199 _init(void)
200 {
201 int err;
202
203 IBTF_DPRINTF_L4("ibdm", "\t_init: addr of ibdm %p", &ibdm);
204
205 if ((err = ibdm_init()) != IBDM_SUCCESS) {
206 IBTF_DPRINTF_L2("ibdm", "_init: ibdm_init failed 0x%x", err);
207 (void) ibdm_fini();
208 return (DDI_FAILURE);
209 }
210
211 if ((err = mod_install(&ibdm_modlinkage)) != 0) {
212 IBTF_DPRINTF_L2("ibdm", "_init: mod_install failed 0x%x", err);
213 (void) ibdm_fini();
214 }
215 return (err);
216 }
217
218
219 int
_fini(void)220 _fini(void)
221 {
222 int err;
223
224 if ((err = ibdm_fini()) != IBDM_SUCCESS) {
225 IBTF_DPRINTF_L2("ibdm", "_fini: ibdm_fini failed 0x%x", err);
226 (void) ibdm_init();
227 return (EBUSY);
228 }
229
230 if ((err = mod_remove(&ibdm_modlinkage)) != 0) {
231 IBTF_DPRINTF_L2("ibdm", "_fini: mod_remove failed 0x%x", err);
232 (void) ibdm_init();
233 }
234 return (err);
235 }
236
237
238 int
_info(struct modinfo * modinfop)239 _info(struct modinfo *modinfop)
240 {
241 return (mod_info(&ibdm_modlinkage, modinfop));
242 }
243
244
245 /*
246 * ibdm_init():
247 * Register with IBTF
248 * Allocate memory for the HCAs
249 * Allocate minor-nodes for the HCAs
250 */
251 static int
ibdm_init(void)252 ibdm_init(void)
253 {
254 int i, hca_count;
255 ib_guid_t *hca_guids;
256 ibt_status_t status;
257
258 IBTF_DPRINTF_L4("ibdm", "\tibdm_init:");
259 if (!(ibdm.ibdm_state & IBDM_LOCKS_ALLOCED)) {
260 mutex_init(&ibdm.ibdm_mutex, NULL, MUTEX_DEFAULT, NULL);
261 mutex_init(&ibdm.ibdm_hl_mutex, NULL, MUTEX_DEFAULT, NULL);
262 mutex_init(&ibdm.ibdm_ibnex_mutex, NULL, MUTEX_DEFAULT, NULL);
263 cv_init(&ibdm.ibdm_port_settle_cv, NULL, CV_DRIVER, NULL);
264 mutex_enter(&ibdm.ibdm_mutex);
265 ibdm.ibdm_state |= IBDM_LOCKS_ALLOCED;
266 }
267
268 if (!(ibdm.ibdm_state & IBDM_IBT_ATTACHED)) {
269 if ((status = ibt_attach(&ibdm_ibt_modinfo, NULL, NULL,
270 (void *)&ibdm.ibdm_ibt_clnt_hdl)) != IBT_SUCCESS) {
271 IBTF_DPRINTF_L2("ibdm", "ibdm_init: ibt_attach "
272 "failed %x", status);
273 mutex_exit(&ibdm.ibdm_mutex);
274 return (IBDM_FAILURE);
275 }
276
277 ibdm.ibdm_state |= IBDM_IBT_ATTACHED;
278 mutex_exit(&ibdm.ibdm_mutex);
279 }
280
281
282 if (!(ibdm.ibdm_state & IBDM_HCA_ATTACHED)) {
283 hca_count = ibt_get_hca_list(&hca_guids);
284 IBTF_DPRINTF_L4("ibdm", "ibdm_init: num_hcas = %d", hca_count);
285 for (i = 0; i < hca_count; i++)
286 (void) ibdm_handle_hca_attach(hca_guids[i]);
287 if (hca_count)
288 ibt_free_hca_list(hca_guids, hca_count);
289
290 mutex_enter(&ibdm.ibdm_mutex);
291 ibdm.ibdm_state |= IBDM_HCA_ATTACHED;
292 mutex_exit(&ibdm.ibdm_mutex);
293 }
294
295 if (!(ibdm.ibdm_state & IBDM_CVS_ALLOCED)) {
296 cv_init(&ibdm.ibdm_probe_cv, NULL, CV_DRIVER, NULL);
297 cv_init(&ibdm.ibdm_busy_cv, NULL, CV_DRIVER, NULL);
298 mutex_enter(&ibdm.ibdm_mutex);
299 ibdm.ibdm_state |= IBDM_CVS_ALLOCED;
300 mutex_exit(&ibdm.ibdm_mutex);
301 }
302 return (IBDM_SUCCESS);
303 }
304
305
306 static int
ibdm_free_iou_info(ibdm_dp_gidinfo_t * gid_info,ibdm_iou_info_t ** ioup)307 ibdm_free_iou_info(ibdm_dp_gidinfo_t *gid_info, ibdm_iou_info_t **ioup)
308 {
309 int ii, k, niocs;
310 size_t size;
311 ibdm_gid_t *delete, *head;
312 timeout_id_t timeout_id;
313 ibdm_ioc_info_t *ioc;
314 ibdm_iou_info_t *gl_iou = *ioup;
315
316 ASSERT(mutex_owned(&gid_info->gl_mutex));
317 if (gl_iou == NULL) {
318 IBTF_DPRINTF_L4("ibdm", "\tibdm_free_iou_info: No IOU");
319 return (0);
320 }
321
322 niocs = gl_iou->iou_info.iou_num_ctrl_slots;
323 IBTF_DPRINTF_L4("ibdm", "\tfree_iou_info: gid_info = %p, niocs %d",
324 gid_info, niocs);
325
326 for (ii = 0; ii < niocs; ii++) {
327 ioc = (ibdm_ioc_info_t *)&gl_iou->iou_ioc_info[ii];
328
329 /* handle the case where an ioc_timeout_id is scheduled */
330 if (ioc->ioc_timeout_id) {
331 timeout_id = ioc->ioc_timeout_id;
332 ioc->ioc_timeout_id = 0;
333 mutex_exit(&gid_info->gl_mutex);
334 IBTF_DPRINTF_L5("ibdm", "free_iou_info: "
335 "ioc_timeout_id = 0x%x", timeout_id);
336 if (untimeout(timeout_id) == -1) {
337 IBTF_DPRINTF_L2("ibdm", "free_iou_info: "
338 "untimeout ioc_timeout_id failed");
339 mutex_enter(&gid_info->gl_mutex);
340 return (-1);
341 }
342 mutex_enter(&gid_info->gl_mutex);
343 }
344
345 /* handle the case where an ioc_dc_timeout_id is scheduled */
346 if (ioc->ioc_dc_timeout_id) {
347 timeout_id = ioc->ioc_dc_timeout_id;
348 ioc->ioc_dc_timeout_id = 0;
349 mutex_exit(&gid_info->gl_mutex);
350 IBTF_DPRINTF_L5("ibdm", "free_iou_info: "
351 "ioc_dc_timeout_id = 0x%x", timeout_id);
352 if (untimeout(timeout_id) == -1) {
353 IBTF_DPRINTF_L2("ibdm", "free_iou_info: "
354 "untimeout ioc_dc_timeout_id failed");
355 mutex_enter(&gid_info->gl_mutex);
356 return (-1);
357 }
358 mutex_enter(&gid_info->gl_mutex);
359 }
360
361 /* handle the case where serv[k].se_timeout_id is scheduled */
362 for (k = 0; k < ioc->ioc_profile.ioc_service_entries; k++) {
363 if (ioc->ioc_serv[k].se_timeout_id) {
364 timeout_id = ioc->ioc_serv[k].se_timeout_id;
365 ioc->ioc_serv[k].se_timeout_id = 0;
366 mutex_exit(&gid_info->gl_mutex);
367 IBTF_DPRINTF_L5("ibdm", "free_iou_info: "
368 "ioc->ioc_serv[%d].se_timeout_id = 0x%x",
369 k, timeout_id);
370 if (untimeout(timeout_id) == -1) {
371 IBTF_DPRINTF_L2("ibdm", "free_iou_info:"
372 " untimeout se_timeout_id failed");
373 mutex_enter(&gid_info->gl_mutex);
374 return (-1);
375 }
376 mutex_enter(&gid_info->gl_mutex);
377 }
378 }
379
380 /* delete GID list in IOC */
381 head = ioc->ioc_gid_list;
382 while (head) {
383 IBTF_DPRINTF_L4("ibdm", "\tibdm_free_iou_info: "
384 "Deleting gid_list struct %p", head);
385 delete = head;
386 head = head->gid_next;
387 kmem_free(delete, sizeof (ibdm_gid_t));
388 }
389 ioc->ioc_gid_list = NULL;
390
391 /* delete ioc_serv */
392 size = ioc->ioc_profile.ioc_service_entries *
393 sizeof (ibdm_srvents_info_t);
394 if (ioc->ioc_serv && size) {
395 kmem_free(ioc->ioc_serv, size);
396 ioc->ioc_serv = NULL;
397 }
398 }
399 /*
400 * Clear the IBDM_CISCO_PROBE_DONE flag to get the IO Unit information
401 * via the switch during the probe process.
402 */
403 gid_info->gl_flag &= ~IBDM_CISCO_PROBE_DONE;
404
405 IBTF_DPRINTF_L4("ibdm", "\tibdm_free_iou_info: deleting IOU & IOC");
406 size = sizeof (ibdm_iou_info_t) + niocs * sizeof (ibdm_ioc_info_t);
407 kmem_free(gl_iou, size);
408 *ioup = NULL;
409 return (0);
410 }
411
412
413 /*
414 * ibdm_fini():
415 * Un-register with IBTF
416 * De allocate memory for the GID info
417 */
418 static int
ibdm_fini()419 ibdm_fini()
420 {
421 int ii;
422 ibdm_hca_list_t *hca_list, *temp;
423 ibdm_dp_gidinfo_t *gid_info, *tmp;
424 ibdm_gid_t *head, *delete;
425
426 IBTF_DPRINTF_L4("ibdm", "\tibdm_fini");
427
428 mutex_enter(&ibdm.ibdm_hl_mutex);
429 if (ibdm.ibdm_state & IBDM_IBT_ATTACHED) {
430 if (ibt_detach(ibdm.ibdm_ibt_clnt_hdl) != IBT_SUCCESS) {
431 IBTF_DPRINTF_L2("ibdm", "\t_fini: ibt_detach failed");
432 mutex_exit(&ibdm.ibdm_hl_mutex);
433 return (IBDM_FAILURE);
434 }
435 ibdm.ibdm_state &= ~IBDM_IBT_ATTACHED;
436 ibdm.ibdm_ibt_clnt_hdl = NULL;
437 }
438
439 hca_list = ibdm.ibdm_hca_list_head;
440 IBTF_DPRINTF_L4("ibdm", "\tibdm_fini: nhcas %d", ibdm.ibdm_hca_count);
441 for (ii = 0; ii < ibdm.ibdm_hca_count; ii++) {
442 temp = hca_list;
443 hca_list = hca_list->hl_next;
444 IBTF_DPRINTF_L4("ibdm", "\tibdm_fini: hca %p", temp);
445 if (ibdm_uninit_hca(temp) != IBDM_SUCCESS) {
446 IBTF_DPRINTF_L2("ibdm", "\tibdm_fini: "
447 "uninit_hca %p failed", temp);
448 mutex_exit(&ibdm.ibdm_hl_mutex);
449 return (IBDM_FAILURE);
450 }
451 }
452 mutex_exit(&ibdm.ibdm_hl_mutex);
453
454 mutex_enter(&ibdm.ibdm_mutex);
455 if (ibdm.ibdm_state & IBDM_HCA_ATTACHED)
456 ibdm.ibdm_state &= ~IBDM_HCA_ATTACHED;
457
458 gid_info = ibdm.ibdm_dp_gidlist_head;
459 while (gid_info) {
460 mutex_enter(&gid_info->gl_mutex);
461 (void) ibdm_free_iou_info(gid_info, &gid_info->gl_iou);
462 mutex_exit(&gid_info->gl_mutex);
463 ibdm_delete_glhca_list(gid_info);
464
465 tmp = gid_info;
466 gid_info = gid_info->gl_next;
467 mutex_destroy(&tmp->gl_mutex);
468 head = tmp->gl_gid;
469 while (head) {
470 IBTF_DPRINTF_L4("ibdm",
471 "\tibdm_fini: Deleting gid structs");
472 delete = head;
473 head = head->gid_next;
474 kmem_free(delete, sizeof (ibdm_gid_t));
475 }
476 kmem_free(tmp, sizeof (ibdm_dp_gidinfo_t));
477 }
478 mutex_exit(&ibdm.ibdm_mutex);
479
480 if (ibdm.ibdm_state & IBDM_LOCKS_ALLOCED) {
481 ibdm.ibdm_state &= ~IBDM_LOCKS_ALLOCED;
482 mutex_destroy(&ibdm.ibdm_mutex);
483 mutex_destroy(&ibdm.ibdm_hl_mutex);
484 mutex_destroy(&ibdm.ibdm_ibnex_mutex);
485 cv_destroy(&ibdm.ibdm_port_settle_cv);
486 }
487 if (ibdm.ibdm_state & IBDM_CVS_ALLOCED) {
488 ibdm.ibdm_state &= ~IBDM_CVS_ALLOCED;
489 cv_destroy(&ibdm.ibdm_probe_cv);
490 cv_destroy(&ibdm.ibdm_busy_cv);
491 }
492 return (IBDM_SUCCESS);
493 }
494
495
496 /*
497 * ibdm_event_hdlr()
498 *
499 * IBDM registers this asynchronous event handler at the time of
500 * ibt_attach. IBDM support the following async events. For other
501 * event, simply returns success.
502 * IBT_HCA_ATTACH_EVENT:
503 * Retrieves the information about all the port that are
504 * present on this HCA, allocates the port attributes
505 * structure and calls IB nexus callback routine with
506 * the port attributes structure as an input argument.
507 * IBT_HCA_DETACH_EVENT:
508 * Retrieves the information about all the ports that are
509 * present on this HCA and calls IB nexus callback with
510 * port guid as an argument
511 * IBT_EVENT_PORT_UP:
512 * Register with IBMF and SA access
513 * Setup IBMF receive callback routine
514 * IBT_EVENT_PORT_DOWN:
515 * Un-Register with IBMF and SA access
516 * Teardown IBMF receive callback routine
517 */
518 /*ARGSUSED*/
519 static void
ibdm_event_hdlr(void * clnt_hdl,ibt_hca_hdl_t hca_hdl,ibt_async_code_t code,ibt_async_event_t * event)520 ibdm_event_hdlr(void *clnt_hdl,
521 ibt_hca_hdl_t hca_hdl, ibt_async_code_t code, ibt_async_event_t *event)
522 {
523 ibdm_hca_list_t *hca_list;
524 ibdm_port_attr_t *port;
525 ibmf_saa_handle_t port_sa_hdl;
526
527 IBTF_DPRINTF_L4("ibdm", "\tevent_hdlr: async code 0x%x", code);
528
529 switch (code) {
530 case IBT_HCA_ATTACH_EVENT: /* New HCA registered with IBTF */
531 ibdm_handle_hca_attach(event->ev_hca_guid);
532 break;
533
534 case IBT_HCA_DETACH_EVENT: /* HCA unregistered with IBTF */
535 ibdm_handle_hca_detach(event->ev_hca_guid);
536 mutex_enter(&ibdm.ibdm_ibnex_mutex);
537 if (ibdm.ibdm_ibnex_callback != NULL) {
538 (*ibdm.ibdm_ibnex_callback)((void *)
539 &event->ev_hca_guid, IBDM_EVENT_HCA_REMOVED);
540 }
541 mutex_exit(&ibdm.ibdm_ibnex_mutex);
542 break;
543
544 case IBT_EVENT_PORT_UP:
545 IBTF_DPRINTF_L4("ibdm", "\tevent_hdlr: PORT_UP");
546 mutex_enter(&ibdm.ibdm_hl_mutex);
547 port = ibdm_get_port_attr(event, &hca_list);
548 if (port == NULL) {
549 IBTF_DPRINTF_L2("ibdm",
550 "\tevent_hdlr: HCA not present");
551 mutex_exit(&ibdm.ibdm_hl_mutex);
552 break;
553 }
554 ibdm_initialize_port(port);
555 hca_list->hl_nports_active++;
556 cv_broadcast(&ibdm.ibdm_port_settle_cv);
557 mutex_exit(&ibdm.ibdm_hl_mutex);
558
559 /* Inform IB nexus driver */
560 mutex_enter(&ibdm.ibdm_ibnex_mutex);
561 if (ibdm.ibdm_ibnex_callback != NULL) {
562 (*ibdm.ibdm_ibnex_callback)((void *)
563 &event->ev_hca_guid, IBDM_EVENT_PORT_UP);
564 }
565 mutex_exit(&ibdm.ibdm_ibnex_mutex);
566 break;
567
568 case IBT_ERROR_PORT_DOWN:
569 IBTF_DPRINTF_L4("ibdm", "\tevent_hdlr: PORT_DOWN");
570 mutex_enter(&ibdm.ibdm_hl_mutex);
571 port = ibdm_get_port_attr(event, &hca_list);
572 if (port == NULL) {
573 IBTF_DPRINTF_L2("ibdm",
574 "\tevent_hdlr: HCA not present");
575 mutex_exit(&ibdm.ibdm_hl_mutex);
576 break;
577 }
578 hca_list->hl_nports_active--;
579 port_sa_hdl = port->pa_sa_hdl;
580 (void) ibdm_fini_port(port);
581 port->pa_state = IBT_PORT_DOWN;
582 cv_broadcast(&ibdm.ibdm_port_settle_cv);
583 mutex_exit(&ibdm.ibdm_hl_mutex);
584 ibdm_reset_all_dgids(port_sa_hdl);
585 break;
586
587 case IBT_PORT_CHANGE_EVENT:
588 IBTF_DPRINTF_L4("ibdm", "\tevent_hdlr: PORT_CHANGE");
589 if (event->ev_port_flags & IBT_PORT_CHANGE_PKEY)
590 ibdm_handle_port_change_event(event);
591 break;
592
593 default: /* Ignore all other events/errors */
594 break;
595 }
596 }
597
598 static void
ibdm_handle_port_change_event(ibt_async_event_t * event)599 ibdm_handle_port_change_event(ibt_async_event_t *event)
600 {
601 ibdm_port_attr_t *port;
602 ibdm_hca_list_t *hca_list;
603
604 IBTF_DPRINTF_L2("ibdm", "\tibdm_handle_port_change_event:"
605 " HCA guid %llx", event->ev_hca_guid);
606 mutex_enter(&ibdm.ibdm_hl_mutex);
607 port = ibdm_get_port_attr(event, &hca_list);
608 if (port == NULL) {
609 IBTF_DPRINTF_L2("ibdm", "\tevent_hdlr: HCA not present");
610 mutex_exit(&ibdm.ibdm_hl_mutex);
611 return;
612 }
613 ibdm_update_port_pkeys(port);
614 cv_broadcast(&ibdm.ibdm_port_settle_cv);
615 mutex_exit(&ibdm.ibdm_hl_mutex);
616
617 /* Inform IB nexus driver */
618 mutex_enter(&ibdm.ibdm_ibnex_mutex);
619 if (ibdm.ibdm_ibnex_callback != NULL) {
620 (*ibdm.ibdm_ibnex_callback)((void *)
621 &event->ev_hca_guid, IBDM_EVENT_PORT_PKEY_CHANGE);
622 }
623 mutex_exit(&ibdm.ibdm_ibnex_mutex);
624 }
625
626 /*
627 * ibdm_update_port_pkeys()
628 * Update the pkey table
629 * Update the port attributes
630 */
631 static void
ibdm_update_port_pkeys(ibdm_port_attr_t * port)632 ibdm_update_port_pkeys(ibdm_port_attr_t *port)
633 {
634 uint_t nports, size;
635 uint_t pkey_idx, opkey_idx;
636 uint16_t npkeys;
637 ibt_hca_portinfo_t *pinfop;
638 ib_pkey_t pkey;
639 ibdm_pkey_tbl_t *pkey_tbl;
640 ibdm_port_attr_t newport;
641
642 IBTF_DPRINTF_L4("ibdm", "\tupdate_port_pkeys:");
643 ASSERT(MUTEX_HELD(&ibdm.ibdm_hl_mutex));
644
645 /* Check whether the port is active */
646 if (ibt_get_port_state(port->pa_hca_hdl, port->pa_port_num, NULL,
647 NULL) != IBT_SUCCESS)
648 return;
649
650 if (ibt_query_hca_ports(port->pa_hca_hdl, port->pa_port_num,
651 &pinfop, &nports, &size) != IBT_SUCCESS) {
652 /* This should not occur */
653 port->pa_npkeys = 0;
654 port->pa_pkey_tbl = NULL;
655 return;
656 }
657
658 npkeys = pinfop->p_pkey_tbl_sz;
659 pkey_tbl = kmem_zalloc(npkeys * sizeof (ibdm_pkey_tbl_t), KM_SLEEP);
660 newport.pa_pkey_tbl = pkey_tbl;
661 newport.pa_ibmf_hdl = port->pa_ibmf_hdl;
662
663 for (pkey_idx = 0; pkey_idx < npkeys; pkey_idx++) {
664 pkey = pkey_tbl[pkey_idx].pt_pkey =
665 pinfop->p_pkey_tbl[pkey_idx];
666 /*
667 * Is this pkey present in the current table ?
668 */
669 for (opkey_idx = 0; opkey_idx < port->pa_npkeys; opkey_idx++) {
670 if (pkey == port->pa_pkey_tbl[opkey_idx].pt_pkey) {
671 pkey_tbl[pkey_idx].pt_qp_hdl =
672 port->pa_pkey_tbl[opkey_idx].pt_qp_hdl;
673 port->pa_pkey_tbl[opkey_idx].pt_qp_hdl = NULL;
674 break;
675 }
676 }
677
678 if (opkey_idx == port->pa_npkeys) {
679 pkey = pkey_tbl[pkey_idx].pt_pkey;
680 if (IBDM_INVALID_PKEY(pkey)) {
681 pkey_tbl[pkey_idx].pt_qp_hdl = NULL;
682 continue;
683 }
684 ibdm_port_attr_ibmf_init(&newport, pkey, pkey_idx);
685 }
686 }
687
688 for (opkey_idx = 0; opkey_idx < port->pa_npkeys; opkey_idx++) {
689 if (port->pa_pkey_tbl[opkey_idx].pt_qp_hdl != NULL) {
690 if (ibdm_port_attr_ibmf_fini(port, opkey_idx) !=
691 IBDM_SUCCESS) {
692 IBTF_DPRINTF_L2("ibdm", "\tupdate_port_pkeys: "
693 "ibdm_port_attr_ibmf_fini failed for "
694 "port pkey 0x%x",
695 port->pa_pkey_tbl[opkey_idx].pt_pkey);
696 }
697 }
698 }
699
700 if (port->pa_pkey_tbl != NULL) {
701 kmem_free(port->pa_pkey_tbl,
702 port->pa_npkeys * sizeof (ibdm_pkey_tbl_t));
703 }
704
705 port->pa_npkeys = npkeys;
706 port->pa_pkey_tbl = pkey_tbl;
707 port->pa_sn_prefix = pinfop->p_sgid_tbl[0].gid_prefix;
708 port->pa_state = pinfop->p_linkstate;
709 ibt_free_portinfo(pinfop, size);
710 }
711
712 /*
713 * ibdm_initialize_port()
714 * Register with IBMF
715 * Register with SA access
716 * Register a receive callback routine with IBMF. IBMF invokes
717 * this routine whenever a MAD arrives at this port.
718 * Update the port attributes
719 */
720 static void
ibdm_initialize_port(ibdm_port_attr_t * port)721 ibdm_initialize_port(ibdm_port_attr_t *port)
722 {
723 int ii;
724 uint_t nports, size;
725 uint_t pkey_idx;
726 ib_pkey_t pkey;
727 ibt_hca_portinfo_t *pinfop;
728 ibmf_register_info_t ibmf_reg;
729 ibmf_saa_subnet_event_args_t event_args;
730
731 IBTF_DPRINTF_L4("ibdm", "\tinitialize_port:");
732 ASSERT(MUTEX_HELD(&ibdm.ibdm_hl_mutex));
733
734 /* Check whether the port is active */
735 if (ibt_get_port_state(port->pa_hca_hdl, port->pa_port_num, NULL,
736 NULL) != IBT_SUCCESS)
737 return;
738
739 if (port->pa_sa_hdl != NULL || port->pa_pkey_tbl != NULL)
740 return;
741
742 if (ibt_query_hca_ports(port->pa_hca_hdl, port->pa_port_num,
743 &pinfop, &nports, &size) != IBT_SUCCESS) {
744 /* This should not occur */
745 port->pa_npkeys = 0;
746 port->pa_pkey_tbl = NULL;
747 return;
748 }
749 port->pa_sn_prefix = pinfop->p_sgid_tbl[0].gid_prefix;
750
751 port->pa_state = pinfop->p_linkstate;
752 port->pa_npkeys = pinfop->p_pkey_tbl_sz;
753 port->pa_pkey_tbl = (ibdm_pkey_tbl_t *)kmem_zalloc(
754 port->pa_npkeys * sizeof (ibdm_pkey_tbl_t), KM_SLEEP);
755
756 for (pkey_idx = 0; pkey_idx < port->pa_npkeys; pkey_idx++)
757 port->pa_pkey_tbl[pkey_idx].pt_pkey =
758 pinfop->p_pkey_tbl[pkey_idx];
759
760 ibt_free_portinfo(pinfop, size);
761
762 if (ibdm_enumerate_iocs) {
763 event_args.is_event_callback = ibdm_saa_event_cb;
764 event_args.is_event_callback_arg = port;
765 if (ibmf_sa_session_open(port->pa_port_guid, 0, &event_args,
766 IBMF_VERSION, 0, &port->pa_sa_hdl) != IBMF_SUCCESS) {
767 IBTF_DPRINTF_L2("ibdm", "\tinitialize_port: "
768 "sa access registration failed");
769 (void) ibdm_fini_port(port);
770 return;
771 }
772
773 ibmf_reg.ir_ci_guid = port->pa_hca_guid;
774 ibmf_reg.ir_port_num = port->pa_port_num;
775 ibmf_reg.ir_client_class = DEV_MGT_MANAGER;
776
777 if (ibmf_register(&ibmf_reg, IBMF_VERSION, 0, NULL, NULL,
778 &port->pa_ibmf_hdl, &port->pa_ibmf_caps) != IBMF_SUCCESS) {
779 IBTF_DPRINTF_L2("ibdm", "\tinitialize_port: "
780 "IBMF registration failed");
781 (void) ibdm_fini_port(port);
782 return;
783 }
784
785 if (ibmf_setup_async_cb(port->pa_ibmf_hdl,
786 IBMF_QP_HANDLE_DEFAULT,
787 ibdm_ibmf_recv_cb, 0, 0) != IBMF_SUCCESS) {
788 IBTF_DPRINTF_L2("ibdm", "\tinitialize_port: "
789 "IBMF setup recv cb failed");
790 (void) ibdm_fini_port(port);
791 return;
792 }
793 } else {
794 port->pa_sa_hdl = NULL;
795 port->pa_ibmf_hdl = NULL;
796 }
797
798 for (ii = 0; ii < port->pa_npkeys; ii++) {
799 pkey = port->pa_pkey_tbl[ii].pt_pkey;
800 if (IBDM_INVALID_PKEY(pkey)) {
801 port->pa_pkey_tbl[ii].pt_qp_hdl = NULL;
802 continue;
803 }
804 ibdm_port_attr_ibmf_init(port, pkey, ii);
805 }
806 }
807
808
809 /*
810 * ibdm_port_attr_ibmf_init:
811 * With IBMF - Alloc QP Handle and Setup Async callback
812 */
813 static void
ibdm_port_attr_ibmf_init(ibdm_port_attr_t * port,ib_pkey_t pkey,int ii)814 ibdm_port_attr_ibmf_init(ibdm_port_attr_t *port, ib_pkey_t pkey, int ii)
815 {
816 int ret;
817
818 if (ibdm_enumerate_iocs == 0) {
819 port->pa_pkey_tbl[ii].pt_qp_hdl = NULL;
820 return;
821 }
822
823 if ((ret = ibmf_alloc_qp(port->pa_ibmf_hdl, pkey, IB_GSI_QKEY,
824 IBMF_ALT_QP_MAD_NO_RMPP, &port->pa_pkey_tbl[ii].pt_qp_hdl)) !=
825 IBMF_SUCCESS) {
826 IBTF_DPRINTF_L2("ibdm", "\tport_attr_ibmf_init: "
827 "IBMF failed to alloc qp %d", ret);
828 port->pa_pkey_tbl[ii].pt_qp_hdl = NULL;
829 return;
830 }
831
832 IBTF_DPRINTF_L4("ibdm", "\tport_attr_ibmf_init: QP handle is %p",
833 port->pa_ibmf_hdl);
834
835 if ((ret = ibmf_setup_async_cb(port->pa_ibmf_hdl,
836 port->pa_pkey_tbl[ii].pt_qp_hdl, ibdm_ibmf_recv_cb, 0, 0)) !=
837 IBMF_SUCCESS) {
838 IBTF_DPRINTF_L2("ibdm", "\tport_attr_ibmf_init: "
839 "IBMF setup recv cb failed %d", ret);
840 (void) ibmf_free_qp(port->pa_ibmf_hdl,
841 &port->pa_pkey_tbl[ii].pt_qp_hdl, 0);
842 port->pa_pkey_tbl[ii].pt_qp_hdl = NULL;
843 }
844 }
845
846
847 /*
848 * ibdm_get_port_attr()
849 * Get port attributes from HCA guid and port number
850 * Return pointer to ibdm_port_attr_t on Success
851 * and NULL on failure
852 */
853 static ibdm_port_attr_t *
ibdm_get_port_attr(ibt_async_event_t * event,ibdm_hca_list_t ** retval)854 ibdm_get_port_attr(ibt_async_event_t *event, ibdm_hca_list_t **retval)
855 {
856 ibdm_hca_list_t *hca_list;
857 ibdm_port_attr_t *port_attr;
858 int ii;
859
860 IBTF_DPRINTF_L4("ibdm", "\tget_port_attr: port# %d", event->ev_port);
861 ASSERT(MUTEX_HELD(&ibdm.ibdm_hl_mutex));
862 hca_list = ibdm.ibdm_hca_list_head;
863 while (hca_list) {
864 if (hca_list->hl_hca_guid == event->ev_hca_guid) {
865 for (ii = 0; ii < hca_list->hl_nports; ii++) {
866 port_attr = &hca_list->hl_port_attr[ii];
867 if (port_attr->pa_port_num == event->ev_port) {
868 *retval = hca_list;
869 return (port_attr);
870 }
871 }
872 }
873 hca_list = hca_list->hl_next;
874 }
875 return (NULL);
876 }
877
878
879 /*
880 * ibdm_update_port_attr()
881 * Update the port attributes
882 */
883 static void
ibdm_update_port_attr(ibdm_port_attr_t * port)884 ibdm_update_port_attr(ibdm_port_attr_t *port)
885 {
886 uint_t nports, size;
887 uint_t pkey_idx;
888 ibt_hca_portinfo_t *portinfop;
889
890 IBTF_DPRINTF_L4("ibdm", "\tupdate_port_attr: Begin");
891 if (ibt_query_hca_ports(port->pa_hca_hdl,
892 port->pa_port_num, &portinfop, &nports, &size) != IBT_SUCCESS) {
893 /* This should not occur */
894 port->pa_npkeys = 0;
895 port->pa_pkey_tbl = NULL;
896 return;
897 }
898 port->pa_sn_prefix = portinfop->p_sgid_tbl[0].gid_prefix;
899
900 port->pa_state = portinfop->p_linkstate;
901
902 /*
903 * PKey information in portinfo valid only if port is
904 * ACTIVE. Bail out if not.
905 */
906 if (port->pa_state != IBT_PORT_ACTIVE) {
907 port->pa_npkeys = 0;
908 port->pa_pkey_tbl = NULL;
909 ibt_free_portinfo(portinfop, size);
910 return;
911 }
912
913 port->pa_npkeys = portinfop->p_pkey_tbl_sz;
914 port->pa_pkey_tbl = (ibdm_pkey_tbl_t *)kmem_zalloc(
915 port->pa_npkeys * sizeof (ibdm_pkey_tbl_t), KM_SLEEP);
916
917 for (pkey_idx = 0; pkey_idx < port->pa_npkeys; pkey_idx++) {
918 port->pa_pkey_tbl[pkey_idx].pt_pkey =
919 portinfop->p_pkey_tbl[pkey_idx];
920 }
921 ibt_free_portinfo(portinfop, size);
922 }
923
924
925 /*
926 * ibdm_handle_hca_attach()
927 */
928 static void
ibdm_handle_hca_attach(ib_guid_t hca_guid)929 ibdm_handle_hca_attach(ib_guid_t hca_guid)
930 {
931 uint_t size;
932 uint_t ii, nports;
933 ibt_status_t status;
934 ibt_hca_hdl_t hca_hdl;
935 ibt_hca_attr_t *hca_attr;
936 ibdm_hca_list_t *hca_list, *temp;
937 ibdm_port_attr_t *port_attr;
938 ibt_hca_portinfo_t *portinfop;
939
940 IBTF_DPRINTF_L4("ibdm",
941 "\thandle_hca_attach: hca_guid = 0x%llX", hca_guid);
942
943 /* open the HCA first */
944 if ((status = ibt_open_hca(ibdm.ibdm_ibt_clnt_hdl, hca_guid,
945 &hca_hdl)) != IBT_SUCCESS) {
946 IBTF_DPRINTF_L2("ibdm", "\thandle_hca_attach: "
947 "open_hca failed, status 0x%x", status);
948 return;
949 }
950
951 hca_attr = (ibt_hca_attr_t *)
952 kmem_alloc(sizeof (ibt_hca_attr_t), KM_SLEEP);
953 /* ibt_query_hca always returns IBT_SUCCESS */
954 (void) ibt_query_hca(hca_hdl, hca_attr);
955
956 IBTF_DPRINTF_L4("ibdm", "\tvid: 0x%x, pid: 0x%x, ver: 0x%x,"
957 " #ports: %d", hca_attr->hca_vendor_id, hca_attr->hca_device_id,
958 hca_attr->hca_version_id, hca_attr->hca_nports);
959
960 if ((status = ibt_query_hca_ports(hca_hdl, 0, &portinfop, &nports,
961 &size)) != IBT_SUCCESS) {
962 IBTF_DPRINTF_L2("ibdm", "\thandle_hca_attach: "
963 "ibt_query_hca_ports failed, status 0x%x", status);
964 kmem_free(hca_attr, sizeof (ibt_hca_attr_t));
965 (void) ibt_close_hca(hca_hdl);
966 return;
967 }
968 hca_list = (ibdm_hca_list_t *)
969 kmem_zalloc((sizeof (ibdm_hca_list_t)), KM_SLEEP);
970 hca_list->hl_port_attr = (ibdm_port_attr_t *)kmem_zalloc(
971 (sizeof (ibdm_port_attr_t) * hca_attr->hca_nports), KM_SLEEP);
972 hca_list->hl_hca_guid = hca_attr->hca_node_guid;
973 hca_list->hl_nports = hca_attr->hca_nports;
974 hca_list->hl_attach_time = ddi_get_time();
975 hca_list->hl_hca_hdl = hca_hdl;
976
977 /*
978 * Init a dummy port attribute for the HCA node
979 * This is for Per-HCA Node. Initialize port_attr :
980 * hca_guid & port_guid -> hca_guid
981 * npkeys, pkey_tbl is NULL
982 * port_num, sn_prefix is 0
983 * vendorid, product_id, dev_version from HCA
984 * pa_state is IBT_PORT_ACTIVE
985 */
986 hca_list->hl_hca_port_attr = (ibdm_port_attr_t *)kmem_zalloc(
987 sizeof (ibdm_port_attr_t), KM_SLEEP);
988 port_attr = hca_list->hl_hca_port_attr;
989 port_attr->pa_vendorid = hca_attr->hca_vendor_id;
990 port_attr->pa_productid = hca_attr->hca_device_id;
991 port_attr->pa_dev_version = hca_attr->hca_version_id;
992 port_attr->pa_hca_guid = hca_attr->hca_node_guid;
993 port_attr->pa_hca_hdl = hca_list->hl_hca_hdl;
994 port_attr->pa_port_guid = hca_attr->hca_node_guid;
995 port_attr->pa_state = IBT_PORT_ACTIVE;
996
997
998 for (ii = 0; ii < nports; ii++) {
999 port_attr = &hca_list->hl_port_attr[ii];
1000 port_attr->pa_vendorid = hca_attr->hca_vendor_id;
1001 port_attr->pa_productid = hca_attr->hca_device_id;
1002 port_attr->pa_dev_version = hca_attr->hca_version_id;
1003 port_attr->pa_hca_guid = hca_attr->hca_node_guid;
1004 port_attr->pa_hca_hdl = hca_list->hl_hca_hdl;
1005 port_attr->pa_port_guid = portinfop[ii].p_sgid_tbl->gid_guid;
1006 port_attr->pa_sn_prefix = portinfop[ii].p_sgid_tbl->gid_prefix;
1007 port_attr->pa_port_num = portinfop[ii].p_port_num;
1008 port_attr->pa_state = portinfop[ii].p_linkstate;
1009
1010 /*
1011 * Register with IBMF, SA access when the port is in
1012 * ACTIVE state. Also register a callback routine
1013 * with IBMF to receive incoming DM MAD's.
1014 * The IBDM event handler takes care of registration of
1015 * port which are not active.
1016 */
1017 IBTF_DPRINTF_L4("ibdm",
1018 "\thandle_hca_attach: port guid %llx Port state 0x%x",
1019 port_attr->pa_port_guid, portinfop[ii].p_linkstate);
1020
1021 if (portinfop[ii].p_linkstate == IBT_PORT_ACTIVE) {
1022 mutex_enter(&ibdm.ibdm_hl_mutex);
1023 hca_list->hl_nports_active++;
1024 ibdm_initialize_port(port_attr);
1025 cv_broadcast(&ibdm.ibdm_port_settle_cv);
1026 mutex_exit(&ibdm.ibdm_hl_mutex);
1027 }
1028 }
1029 mutex_enter(&ibdm.ibdm_hl_mutex);
1030 for (temp = ibdm.ibdm_hca_list_head; temp; temp = temp->hl_next) {
1031 if (temp->hl_hca_guid == hca_guid) {
1032 IBTF_DPRINTF_L2("ibdm", "hca_attach: HCA %llX "
1033 "already seen by IBDM", hca_guid);
1034 mutex_exit(&ibdm.ibdm_hl_mutex);
1035 (void) ibdm_uninit_hca(hca_list);
1036 return;
1037 }
1038 }
1039 ibdm.ibdm_hca_count++;
1040 if (ibdm.ibdm_hca_list_head == NULL) {
1041 ibdm.ibdm_hca_list_head = hca_list;
1042 ibdm.ibdm_hca_list_tail = hca_list;
1043 } else {
1044 ibdm.ibdm_hca_list_tail->hl_next = hca_list;
1045 ibdm.ibdm_hca_list_tail = hca_list;
1046 }
1047 mutex_exit(&ibdm.ibdm_hl_mutex);
1048 mutex_enter(&ibdm.ibdm_ibnex_mutex);
1049 if (ibdm.ibdm_ibnex_callback != NULL) {
1050 (*ibdm.ibdm_ibnex_callback)((void *)
1051 &hca_guid, IBDM_EVENT_HCA_ADDED);
1052 }
1053 mutex_exit(&ibdm.ibdm_ibnex_mutex);
1054
1055 kmem_free(hca_attr, sizeof (ibt_hca_attr_t));
1056 ibt_free_portinfo(portinfop, size);
1057 }
1058
1059
1060 /*
1061 * ibdm_handle_hca_detach()
1062 */
1063 static void
ibdm_handle_hca_detach(ib_guid_t hca_guid)1064 ibdm_handle_hca_detach(ib_guid_t hca_guid)
1065 {
1066 ibdm_hca_list_t *head, *prev = NULL;
1067 size_t len;
1068 ibdm_dp_gidinfo_t *gidinfo;
1069 ibdm_port_attr_t *port_attr;
1070 int i;
1071
1072 IBTF_DPRINTF_L4("ibdm",
1073 "\thandle_hca_detach: hca_guid = 0x%llx", hca_guid);
1074
1075 /* Make sure no probes are running */
1076 mutex_enter(&ibdm.ibdm_mutex);
1077 while (ibdm.ibdm_busy & IBDM_BUSY)
1078 cv_wait(&ibdm.ibdm_busy_cv, &ibdm.ibdm_mutex);
1079 ibdm.ibdm_busy |= IBDM_BUSY;
1080 mutex_exit(&ibdm.ibdm_mutex);
1081
1082 mutex_enter(&ibdm.ibdm_hl_mutex);
1083 head = ibdm.ibdm_hca_list_head;
1084 while (head) {
1085 if (head->hl_hca_guid == hca_guid) {
1086 if (prev == NULL)
1087 ibdm.ibdm_hca_list_head = head->hl_next;
1088 else
1089 prev->hl_next = head->hl_next;
1090 if (ibdm.ibdm_hca_list_tail == head)
1091 ibdm.ibdm_hca_list_tail = prev;
1092 ibdm.ibdm_hca_count--;
1093 break;
1094 }
1095 prev = head;
1096 head = head->hl_next;
1097 }
1098 mutex_exit(&ibdm.ibdm_hl_mutex);
1099 if (ibdm_uninit_hca(head) != IBDM_SUCCESS)
1100 (void) ibdm_handle_hca_attach(hca_guid);
1101
1102 #ifdef DEBUG
1103 if (ibdm_enumerate_iocs == 0) {
1104 ASSERT(ibdm.ibdm_dp_gidlist_head == NULL);
1105 }
1106 #endif
1107
1108 /*
1109 * Now clean up the HCA lists in the gidlist.
1110 */
1111 for (gidinfo = ibdm.ibdm_dp_gidlist_head; gidinfo; gidinfo =
1112 gidinfo->gl_next) {
1113 prev = NULL;
1114 head = gidinfo->gl_hca_list;
1115 while (head) {
1116 if (head->hl_hca_guid == hca_guid) {
1117 if (prev == NULL)
1118 gidinfo->gl_hca_list =
1119 head->hl_next;
1120 else
1121 prev->hl_next = head->hl_next;
1122 for (i = 0; i < head->hl_nports; i++) {
1123 port_attr = &head->hl_port_attr[i];
1124 if (port_attr->pa_pkey_tbl != NULL)
1125 kmem_free(
1126 port_attr->pa_pkey_tbl,
1127 port_attr->pa_npkeys *
1128 sizeof (ibdm_pkey_tbl_t));
1129 }
1130 len = sizeof (ibdm_hca_list_t) +
1131 (head->hl_nports *
1132 sizeof (ibdm_port_attr_t));
1133 kmem_free(head, len);
1134
1135 break;
1136 }
1137 prev = head;
1138 head = head->hl_next;
1139 }
1140 }
1141
1142 mutex_enter(&ibdm.ibdm_mutex);
1143 ibdm.ibdm_busy &= ~IBDM_BUSY;
1144 cv_broadcast(&ibdm.ibdm_busy_cv);
1145 mutex_exit(&ibdm.ibdm_mutex);
1146 }
1147
1148
1149 static int
ibdm_uninit_hca(ibdm_hca_list_t * head)1150 ibdm_uninit_hca(ibdm_hca_list_t *head)
1151 {
1152 int ii;
1153 ibdm_port_attr_t *port_attr;
1154
1155 for (ii = 0; ii < head->hl_nports; ii++) {
1156 port_attr = &head->hl_port_attr[ii];
1157 if (ibdm_fini_port(port_attr) != IBDM_SUCCESS) {
1158 IBTF_DPRINTF_L2("ibdm", "uninit_hca: HCA %p port 0x%x "
1159 "ibdm_fini_port() failed", head, ii);
1160 return (IBDM_FAILURE);
1161 }
1162 }
1163 if (head->hl_hca_hdl)
1164 if (ibt_close_hca(head->hl_hca_hdl) != IBT_SUCCESS) {
1165 IBTF_DPRINTF_L2("ibdm", "uninit_hca: "
1166 "ibt_close_hca() failed");
1167 return (IBDM_FAILURE);
1168 }
1169 kmem_free(head->hl_port_attr,
1170 head->hl_nports * sizeof (ibdm_port_attr_t));
1171 kmem_free(head->hl_hca_port_attr, sizeof (ibdm_port_attr_t));
1172 kmem_free(head, sizeof (ibdm_hca_list_t));
1173 return (IBDM_SUCCESS);
1174 }
1175
1176
1177 /*
1178 * For each port on the HCA,
1179 * 1) Teardown IBMF receive callback function
1180 * 2) Unregister with IBMF
1181 * 3) Unregister with SA access
1182 */
1183 static int
ibdm_fini_port(ibdm_port_attr_t * port_attr)1184 ibdm_fini_port(ibdm_port_attr_t *port_attr)
1185 {
1186 int ii, ibmf_status;
1187
1188 for (ii = 0; ii < port_attr->pa_npkeys; ii++) {
1189 if (port_attr->pa_pkey_tbl == NULL)
1190 break;
1191 if (!port_attr->pa_pkey_tbl[ii].pt_qp_hdl)
1192 continue;
1193 if (ibdm_port_attr_ibmf_fini(port_attr, ii) != IBDM_SUCCESS) {
1194 IBTF_DPRINTF_L4("ibdm", "\tfini_port: "
1195 "ibdm_port_attr_ibmf_fini failed for "
1196 "port pkey 0x%x", ii);
1197 return (IBDM_FAILURE);
1198 }
1199 }
1200
1201 if (port_attr->pa_ibmf_hdl) {
1202 ibmf_status = ibmf_tear_down_async_cb(port_attr->pa_ibmf_hdl,
1203 IBMF_QP_HANDLE_DEFAULT, 0);
1204 if (ibmf_status != IBMF_SUCCESS) {
1205 IBTF_DPRINTF_L4("ibdm", "\tfini_port: "
1206 "ibmf_tear_down_async_cb failed %d", ibmf_status);
1207 return (IBDM_FAILURE);
1208 }
1209
1210 ibmf_status = ibmf_unregister(&port_attr->pa_ibmf_hdl, 0);
1211 if (ibmf_status != IBMF_SUCCESS) {
1212 IBTF_DPRINTF_L2("ibdm", "\tfini_port: "
1213 "ibmf_unregister failed %d", ibmf_status);
1214 return (IBDM_FAILURE);
1215 }
1216
1217 port_attr->pa_ibmf_hdl = NULL;
1218 }
1219
1220 if (port_attr->pa_sa_hdl) {
1221 ibmf_status = ibmf_sa_session_close(&port_attr->pa_sa_hdl, 0);
1222 if (ibmf_status != IBMF_SUCCESS) {
1223 IBTF_DPRINTF_L2("ibdm", "\tfini_port: "
1224 "ibmf_sa_session_close failed %d", ibmf_status);
1225 return (IBDM_FAILURE);
1226 }
1227 port_attr->pa_sa_hdl = NULL;
1228 }
1229
1230 if (port_attr->pa_pkey_tbl != NULL) {
1231 kmem_free(port_attr->pa_pkey_tbl,
1232 port_attr->pa_npkeys * sizeof (ibdm_pkey_tbl_t));
1233 port_attr->pa_pkey_tbl = NULL;
1234 port_attr->pa_npkeys = 0;
1235 }
1236
1237 return (IBDM_SUCCESS);
1238 }
1239
1240
1241 /*
1242 * ibdm_port_attr_ibmf_fini:
1243 * With IBMF - Tear down Async callback and free QP Handle
1244 */
1245 static int
ibdm_port_attr_ibmf_fini(ibdm_port_attr_t * port_attr,int ii)1246 ibdm_port_attr_ibmf_fini(ibdm_port_attr_t *port_attr, int ii)
1247 {
1248 int ibmf_status;
1249
1250 IBTF_DPRINTF_L5("ibdm", "\tport_attr_ibmf_fini:");
1251
1252 if (ibdm_enumerate_iocs == 0) {
1253 ASSERT(port_attr->pa_pkey_tbl[ii].pt_qp_hdl == NULL);
1254 return (IBDM_SUCCESS);
1255 }
1256
1257 if (port_attr->pa_pkey_tbl[ii].pt_qp_hdl) {
1258 ibmf_status = ibmf_tear_down_async_cb(port_attr->pa_ibmf_hdl,
1259 port_attr->pa_pkey_tbl[ii].pt_qp_hdl, 0);
1260 if (ibmf_status != IBMF_SUCCESS) {
1261 IBTF_DPRINTF_L4("ibdm", "\tport_attr_ibmf_fini: "
1262 "ibmf_tear_down_async_cb failed %d", ibmf_status);
1263 return (IBDM_FAILURE);
1264 }
1265 ibmf_status = ibmf_free_qp(port_attr->pa_ibmf_hdl,
1266 &port_attr->pa_pkey_tbl[ii].pt_qp_hdl, 0);
1267 if (ibmf_status != IBMF_SUCCESS) {
1268 IBTF_DPRINTF_L4("ibdm", "\tport_attr_ibmf_fini: "
1269 "ibmf_free_qp failed %d", ibmf_status);
1270 return (IBDM_FAILURE);
1271 }
1272 port_attr->pa_pkey_tbl[ii].pt_qp_hdl = NULL;
1273 }
1274 return (IBDM_SUCCESS);
1275 }
1276
1277
1278 /*
1279 * ibdm_gid_decr_pending:
1280 * decrement gl_pending_cmds. If zero wakeup sleeping threads
1281 */
1282 static void
ibdm_gid_decr_pending(ibdm_dp_gidinfo_t * gidinfo)1283 ibdm_gid_decr_pending(ibdm_dp_gidinfo_t *gidinfo)
1284 {
1285 mutex_enter(&ibdm.ibdm_mutex);
1286 mutex_enter(&gidinfo->gl_mutex);
1287 if (--gidinfo->gl_pending_cmds == 0) {
1288 /*
1289 * Handle DGID getting removed.
1290 */
1291 if (gidinfo->gl_disconnected) {
1292 mutex_exit(&gidinfo->gl_mutex);
1293 mutex_exit(&ibdm.ibdm_mutex);
1294
1295 IBTF_DPRINTF_L3(ibdm_string, "\tgid_decr_pending: "
1296 "gidinfo %p hot removal", gidinfo);
1297 ibdm_delete_gidinfo(gidinfo);
1298
1299 mutex_enter(&ibdm.ibdm_mutex);
1300 ibdm.ibdm_ngid_probes_in_progress--;
1301 ibdm_wait_probe_completion();
1302 mutex_exit(&ibdm.ibdm_mutex);
1303 return;
1304 }
1305 mutex_exit(&gidinfo->gl_mutex);
1306 mutex_exit(&ibdm.ibdm_mutex);
1307 ibdm_notify_newgid_iocs(gidinfo);
1308 mutex_enter(&ibdm.ibdm_mutex);
1309 mutex_enter(&gidinfo->gl_mutex);
1310
1311 ibdm.ibdm_ngid_probes_in_progress--;
1312 ibdm_wait_probe_completion();
1313 }
1314 mutex_exit(&gidinfo->gl_mutex);
1315 mutex_exit(&ibdm.ibdm_mutex);
1316 }
1317
1318
1319 /*
1320 * ibdm_wait_probe_completion:
1321 * wait for probing to complete
1322 */
1323 static void
ibdm_wait_probe_completion(void)1324 ibdm_wait_probe_completion(void)
1325 {
1326 ASSERT(MUTEX_HELD(&ibdm.ibdm_mutex));
1327 if (ibdm.ibdm_ngid_probes_in_progress) {
1328 IBTF_DPRINTF_L4("ibdm", "\twait for probe complete");
1329 ibdm.ibdm_busy |= IBDM_PROBE_IN_PROGRESS;
1330 while (ibdm.ibdm_busy & IBDM_PROBE_IN_PROGRESS)
1331 cv_wait(&ibdm.ibdm_probe_cv, &ibdm.ibdm_mutex);
1332 }
1333 }
1334
1335
1336 /*
1337 * ibdm_wait_cisco_probe_completion:
1338 * wait for the reply from the Cisco FC GW switch after a setclassportinfo
1339 * request is sent. This wait can be achieved on each gid.
1340 */
1341 static void
ibdm_wait_cisco_probe_completion(ibdm_dp_gidinfo_t * gidinfo)1342 ibdm_wait_cisco_probe_completion(ibdm_dp_gidinfo_t *gidinfo)
1343 {
1344 ASSERT(MUTEX_HELD(&gidinfo->gl_mutex));
1345 IBTF_DPRINTF_L4("ibdm", "\twait for cisco probe complete");
1346 gidinfo->gl_flag |= IBDM_CISCO_PROBE;
1347 while (gidinfo->gl_flag & IBDM_CISCO_PROBE)
1348 cv_wait(&gidinfo->gl_probe_cv, &gidinfo->gl_mutex);
1349 }
1350
1351
1352 /*
1353 * ibdm_wakeup_probe_gid_cv:
1354 * wakeup waiting threads (based on ibdm_ngid_probes_in_progress)
1355 */
1356 static void
ibdm_wakeup_probe_gid_cv(void)1357 ibdm_wakeup_probe_gid_cv(void)
1358 {
1359 ASSERT(MUTEX_HELD(&ibdm.ibdm_mutex));
1360 if (!ibdm.ibdm_ngid_probes_in_progress) {
1361 IBTF_DPRINTF_L4("ibdm", "wakeup_probe_gid_thread: Wakeup");
1362 ibdm.ibdm_busy &= ~IBDM_PROBE_IN_PROGRESS;
1363 cv_broadcast(&ibdm.ibdm_probe_cv);
1364 }
1365
1366 }
1367
1368
1369 /*
1370 * ibdm_sweep_fabric(reprobe_flag)
1371 * Find all possible Managed IOU's and their IOC's that are visible
1372 * to the host. The algorithm used is as follows
1373 *
1374 * Send a "bus walk" request for each port on the host HCA to SA access
1375 * SA returns complete set of GID's that are reachable from
1376 * source port. This is done in parallel.
1377 *
1378 * Initialize GID state to IBDM_GID_PROBE_NOT_DONE
1379 *
1380 * Sort the GID list and eliminate duplicate GID's
1381 * 1) Use DGID for sorting
1382 * 2) use PortGuid for sorting
1383 * Send SA query to retrieve NodeRecord and
1384 * extract PortGuid from that.
1385 *
1386 * Set GID state to IBDM_GID_PROBE_FAILED to all the ports that dont
1387 * support DM MAD's
1388 * Send a "Portinfo" query to get the port capabilities and
1389 * then check for DM MAD's support
1390 *
1391 * Send "ClassPortInfo" request for all the GID's in parallel,
1392 * set the GID state to IBDM_GET_CLASSPORTINFO and wait on the
1393 * cv_signal to complete.
1394 *
1395 * When DM agent on the remote GID sends back the response, IBMF
1396 * invokes DM callback routine.
1397 *
1398 * If the response is proper, send "IOUnitInfo" request and set
1399 * GID state to IBDM_GET_IOUNITINFO.
1400 *
1401 * If the response is proper, send "IocProfileInfo" request to
1402 * all the IOC simultaneously and set GID state to IBDM_GET_IOC_DETAILS.
1403 *
1404 * Send request to get Service entries simultaneously
1405 *
1406 * Signal the waiting thread when received response for all the commands.
1407 *
1408 * Set the GID state to IBDM_GID_PROBE_FAILED when received a error
1409 * response during the probing period.
1410 *
1411 * Note:
1412 * ibdm.ibdm_ngid_probes_in_progress and ibdm_gid_list_t:gl_pending_cmds
1413 * keep track of number commands in progress at any point of time.
1414 * MAD transaction ID is used to identify a particular GID
1415 * TBD: Consider registering the IBMF receive callback on demand
1416 *
1417 * Note: This routine must be called with ibdm.ibdm_mutex held
1418 * TBD: Re probe the failure GID (for certain failures) when requested
1419 * for fabric sweep next time
1420 *
1421 * Parameters : If reprobe_flag is set, All IOCs will be reprobed.
1422 */
1423 static void
ibdm_sweep_fabric(int reprobe_flag)1424 ibdm_sweep_fabric(int reprobe_flag)
1425 {
1426 int ii;
1427 int new_paths = 0;
1428 uint8_t niocs;
1429 taskqid_t tid;
1430 ibdm_ioc_info_t *ioc;
1431 ibdm_hca_list_t *hca_list = NULL;
1432 ibdm_port_attr_t *port = NULL;
1433 ibdm_dp_gidinfo_t *gid_info;
1434
1435 IBTF_DPRINTF_L4("ibdm", "\tsweep_fabric: Enter");
1436 ASSERT(MUTEX_HELD(&ibdm.ibdm_mutex));
1437
1438 /*
1439 * Check whether a sweep already in progress. If so, just
1440 * wait for the fabric sweep to complete
1441 */
1442 while (ibdm.ibdm_busy & IBDM_BUSY)
1443 cv_wait(&ibdm.ibdm_busy_cv, &ibdm.ibdm_mutex);
1444 ibdm.ibdm_busy |= IBDM_BUSY;
1445 mutex_exit(&ibdm.ibdm_mutex);
1446
1447 ibdm_dump_sweep_fabric_timestamp(0);
1448
1449 /* Rescan the GID list for any removed GIDs for reprobe */
1450 if (reprobe_flag)
1451 ibdm_rescan_gidlist(NULL);
1452
1453 /*
1454 * Get list of all the ports reachable from the local known HCA
1455 * ports which are active
1456 */
1457 mutex_enter(&ibdm.ibdm_hl_mutex);
1458 for (ibdm_get_next_port(&hca_list, &port, 1); port;
1459 ibdm_get_next_port(&hca_list, &port, 1)) {
1460 /*
1461 * Get PATHS to all the reachable ports from
1462 * SGID and update the global ibdm structure.
1463 */
1464 new_paths = ibdm_get_reachable_ports(port, hca_list);
1465 ibdm.ibdm_ngids += new_paths;
1466 }
1467 mutex_exit(&ibdm.ibdm_hl_mutex);
1468
1469 mutex_enter(&ibdm.ibdm_mutex);
1470 ibdm.ibdm_ngid_probes_in_progress += ibdm.ibdm_ngids;
1471 mutex_exit(&ibdm.ibdm_mutex);
1472
1473 /* Send a request to probe GIDs asynchronously. */
1474 for (gid_info = ibdm.ibdm_dp_gidlist_head; gid_info;
1475 gid_info = gid_info->gl_next) {
1476 mutex_enter(&gid_info->gl_mutex);
1477 gid_info->gl_reprobe_flag = reprobe_flag;
1478 mutex_exit(&gid_info->gl_mutex);
1479
1480 /* process newly encountered GIDs */
1481 tid = taskq_dispatch(system_taskq, ibdm_probe_gid_thread,
1482 (void *)gid_info, TQ_NOSLEEP);
1483 IBTF_DPRINTF_L4("ibdm", "\tsweep_fabric: gid_info = %p"
1484 " taskq_id = %x", gid_info, tid);
1485 /* taskq failed to dispatch call it directly */
1486 if (tid == NULL)
1487 ibdm_probe_gid_thread((void *)gid_info);
1488 }
1489
1490 mutex_enter(&ibdm.ibdm_mutex);
1491 ibdm_wait_probe_completion();
1492
1493 /*
1494 * Update the properties, if reprobe_flag is set
1495 * Skip if gl_reprobe_flag is set, this will be
1496 * a re-inserted / new GID, for which notifications
1497 * have already been send.
1498 */
1499 if (reprobe_flag) {
1500 for (gid_info = ibdm.ibdm_dp_gidlist_head; gid_info;
1501 gid_info = gid_info->gl_next) {
1502 if (gid_info->gl_iou == NULL)
1503 continue;
1504 if (gid_info->gl_reprobe_flag) {
1505 gid_info->gl_reprobe_flag = 0;
1506 continue;
1507 }
1508
1509 niocs = gid_info->gl_iou->iou_info.iou_num_ctrl_slots;
1510 for (ii = 0; ii < niocs; ii++) {
1511 ioc = IBDM_GIDINFO2IOCINFO(gid_info, ii);
1512 if (ioc)
1513 ibdm_reprobe_update_port_srv(ioc,
1514 gid_info);
1515 }
1516 }
1517 } else if (ibdm.ibdm_prev_iou) {
1518 ibdm_ioc_info_t *ioc_list;
1519
1520 /*
1521 * Get the list of IOCs which have changed.
1522 * If any IOCs have changed, Notify IBNexus
1523 */
1524 ibdm.ibdm_prev_iou = 0;
1525 ioc_list = ibdm_handle_prev_iou();
1526 if (ioc_list) {
1527 if (ibdm.ibdm_ibnex_callback != NULL) {
1528 (*ibdm.ibdm_ibnex_callback)(
1529 (void *)ioc_list,
1530 IBDM_EVENT_IOC_PROP_UPDATE);
1531 }
1532 }
1533 }
1534
1535 ibdm_dump_sweep_fabric_timestamp(1);
1536
1537 ibdm.ibdm_busy &= ~IBDM_BUSY;
1538 cv_broadcast(&ibdm.ibdm_busy_cv);
1539 IBTF_DPRINTF_L5("ibdm", "\tsweep_fabric: EXIT");
1540 }
1541
1542
1543 /*
1544 * ibdm_is_cisco:
1545 * Check if this is a Cisco device or not.
1546 */
1547 static boolean_t
ibdm_is_cisco(ib_guid_t guid)1548 ibdm_is_cisco(ib_guid_t guid)
1549 {
1550 if ((guid >> IBDM_OUI_GUID_SHIFT) == IBDM_CISCO_COMPANY_ID)
1551 return (B_TRUE);
1552 return (B_FALSE);
1553 }
1554
1555
1556 /*
1557 * ibdm_is_cisco_switch:
1558 * Check if this switch is a CISCO switch or not.
1559 * Note that if this switch is already activated, ibdm_is_cisco_switch()
1560 * returns B_FALSE not to re-activate it again.
1561 */
1562 static boolean_t
ibdm_is_cisco_switch(ibdm_dp_gidinfo_t * gid_info)1563 ibdm_is_cisco_switch(ibdm_dp_gidinfo_t *gid_info)
1564 {
1565 int company_id, device_id;
1566 ASSERT(gid_info != 0);
1567 ASSERT(MUTEX_HELD(&gid_info->gl_mutex));
1568
1569 /*
1570 * If this switch is already activated, don't re-activate it.
1571 */
1572 if (gid_info->gl_flag & IBDM_CISCO_PROBE_DONE)
1573 return (B_FALSE);
1574
1575 /*
1576 * Check if this switch is a Cisco FC GW or not.
1577 * Use the node guid (the OUI part) instead of the vendor id
1578 * since the vendor id is zero in practice.
1579 */
1580 company_id = gid_info->gl_nodeguid >> IBDM_OUI_GUID_SHIFT;
1581 device_id = gid_info->gl_devid;
1582
1583 if (company_id == IBDM_CISCO_COMPANY_ID &&
1584 device_id == IBDM_CISCO_DEVICE_ID)
1585 return (B_TRUE);
1586 return (B_FALSE);
1587 }
1588
1589
1590 /*
1591 * ibdm_probe_gid_thread:
1592 * thread that does the actual work for sweeping the fabric
1593 * for a given GID
1594 */
1595 static void
ibdm_probe_gid_thread(void * args)1596 ibdm_probe_gid_thread(void *args)
1597 {
1598 int reprobe_flag;
1599 ib_guid_t node_guid;
1600 ib_guid_t port_guid;
1601 ibdm_dp_gidinfo_t *gid_info;
1602
1603 gid_info = (ibdm_dp_gidinfo_t *)args;
1604 reprobe_flag = gid_info->gl_reprobe_flag;
1605 IBTF_DPRINTF_L4("ibdm", "\tprobe_gid_thread: gid_info = %p, flag = %d",
1606 gid_info, reprobe_flag);
1607 ASSERT(gid_info != NULL);
1608 ASSERT(gid_info->gl_pending_cmds == 0);
1609
1610 if (gid_info->gl_state != IBDM_GID_PROBE_NOT_DONE &&
1611 reprobe_flag == 0) {
1612 /*
1613 * This GID may have been already probed. Send
1614 * in a CLP to check if IOUnitInfo changed?
1615 * Explicitly set gl_reprobe_flag to 0 so that
1616 * IBnex is not notified on completion
1617 */
1618 if (gid_info->gl_state == IBDM_GID_PROBING_COMPLETE) {
1619 IBTF_DPRINTF_L4("ibdm", "\tprobe_gid_thread: "
1620 "get new IOCs information");
1621 mutex_enter(&gid_info->gl_mutex);
1622 gid_info->gl_pending_cmds++;
1623 gid_info->gl_state = IBDM_GET_IOUNITINFO;
1624 gid_info->gl_reprobe_flag = 0;
1625 mutex_exit(&gid_info->gl_mutex);
1626 if (ibdm_send_iounitinfo(gid_info) != IBDM_SUCCESS) {
1627 mutex_enter(&gid_info->gl_mutex);
1628 --gid_info->gl_pending_cmds;
1629 mutex_exit(&gid_info->gl_mutex);
1630 mutex_enter(&ibdm.ibdm_mutex);
1631 --ibdm.ibdm_ngid_probes_in_progress;
1632 ibdm_wakeup_probe_gid_cv();
1633 mutex_exit(&ibdm.ibdm_mutex);
1634 }
1635 } else {
1636 mutex_enter(&ibdm.ibdm_mutex);
1637 --ibdm.ibdm_ngid_probes_in_progress;
1638 ibdm_wakeup_probe_gid_cv();
1639 mutex_exit(&ibdm.ibdm_mutex);
1640 }
1641 return;
1642 } else if (reprobe_flag && gid_info->gl_state ==
1643 IBDM_GID_PROBING_COMPLETE) {
1644 /*
1645 * Reprobe all IOCs for the GID which has completed
1646 * probe. Skip other port GIDs to same IOU.
1647 * Explicitly set gl_reprobe_flag to 0 so that
1648 * IBnex is not notified on completion
1649 */
1650 ibdm_ioc_info_t *ioc_info;
1651 uint8_t niocs, ii;
1652
1653 ASSERT(gid_info->gl_iou);
1654 mutex_enter(&gid_info->gl_mutex);
1655 niocs = gid_info->gl_iou->iou_info.iou_num_ctrl_slots;
1656 gid_info->gl_state = IBDM_GET_IOC_DETAILS;
1657 gid_info->gl_pending_cmds += niocs;
1658 gid_info->gl_reprobe_flag = 0;
1659 mutex_exit(&gid_info->gl_mutex);
1660 for (ii = 0; ii < niocs; ii++) {
1661 uchar_t slot_info;
1662 ib_dm_io_unitinfo_t *giou_info;
1663
1664 /*
1665 * Check whether IOC is present in the slot
1666 * Series of nibbles (in the field
1667 * iou_ctrl_list) represents a slot in the
1668 * IOU.
1669 * Byte format: 76543210
1670 * Bits 0-3 of first byte represent Slot 2
1671 * bits 4-7 of first byte represent slot 1,
1672 * bits 0-3 of second byte represent slot 4
1673 * and so on
1674 * Each 4-bit nibble has the following meaning
1675 * 0x0 : IOC not installed
1676 * 0x1 : IOC is present
1677 * 0xf : Slot does not exist
1678 * and all other values are reserved.
1679 */
1680 ioc_info = IBDM_GIDINFO2IOCINFO(gid_info, ii);
1681 giou_info = &gid_info->gl_iou->iou_info;
1682 slot_info = giou_info->iou_ctrl_list[(ii/2)];
1683 if ((ii % 2) == 0)
1684 slot_info = (slot_info >> 4);
1685
1686 if ((slot_info & 0xf) != 1) {
1687 ioc_info->ioc_state =
1688 IBDM_IOC_STATE_PROBE_FAILED;
1689 ibdm_gid_decr_pending(gid_info);
1690 continue;
1691 }
1692
1693 if (ibdm_send_ioc_profile(gid_info, ii) !=
1694 IBDM_SUCCESS) {
1695 ibdm_gid_decr_pending(gid_info);
1696 }
1697 }
1698
1699 return;
1700 } else if (gid_info->gl_state != IBDM_GID_PROBE_NOT_DONE) {
1701 mutex_enter(&ibdm.ibdm_mutex);
1702 --ibdm.ibdm_ngid_probes_in_progress;
1703 ibdm_wakeup_probe_gid_cv();
1704 mutex_exit(&ibdm.ibdm_mutex);
1705 return;
1706 }
1707
1708 /*
1709 * Check whether the destination GID supports DM agents. If
1710 * not, stop probing the GID and continue with the next GID
1711 * in the list.
1712 */
1713 if (ibdm_is_dev_mgt_supported(gid_info) != IBDM_SUCCESS) {
1714 mutex_enter(&gid_info->gl_mutex);
1715 gid_info->gl_state = IBDM_GID_PROBING_FAILED;
1716 gid_info->gl_is_dm_capable = B_FALSE;
1717 mutex_exit(&gid_info->gl_mutex);
1718 ibdm_delete_glhca_list(gid_info);
1719 mutex_enter(&ibdm.ibdm_mutex);
1720 --ibdm.ibdm_ngid_probes_in_progress;
1721 ibdm_wakeup_probe_gid_cv();
1722 mutex_exit(&ibdm.ibdm_mutex);
1723 return;
1724 }
1725
1726 /*
1727 * This GID is Device management capable
1728 */
1729 mutex_enter(&gid_info->gl_mutex);
1730 gid_info->gl_is_dm_capable = B_TRUE;
1731 mutex_exit(&gid_info->gl_mutex);
1732
1733 /* Get the nodeguid and portguid of the port */
1734 if (ibdm_get_node_port_guids(gid_info->gl_sa_hdl, gid_info->gl_dlid,
1735 &node_guid, &port_guid) != IBDM_SUCCESS) {
1736 mutex_enter(&gid_info->gl_mutex);
1737 gid_info->gl_state = IBDM_GID_PROBING_FAILED;
1738 mutex_exit(&gid_info->gl_mutex);
1739 ibdm_delete_glhca_list(gid_info);
1740 mutex_enter(&ibdm.ibdm_mutex);
1741 --ibdm.ibdm_ngid_probes_in_progress;
1742 ibdm_wakeup_probe_gid_cv();
1743 mutex_exit(&ibdm.ibdm_mutex);
1744 return;
1745 }
1746
1747 /*
1748 * Check whether we already knew about this NodeGuid
1749 * If so, do not probe the GID and continue with the
1750 * next GID in the gid list. Set the GID state to
1751 * probing done.
1752 */
1753 mutex_enter(&ibdm.ibdm_mutex);
1754 gid_info->gl_nodeguid = node_guid;
1755 gid_info->gl_portguid = port_guid;
1756 if (ibdm_check_dest_nodeguid(gid_info) != NULL) {
1757 mutex_exit(&ibdm.ibdm_mutex);
1758 mutex_enter(&gid_info->gl_mutex);
1759 gid_info->gl_state = IBDM_GID_PROBING_SKIPPED;
1760 mutex_exit(&gid_info->gl_mutex);
1761 ibdm_delete_glhca_list(gid_info);
1762 mutex_enter(&ibdm.ibdm_mutex);
1763 --ibdm.ibdm_ngid_probes_in_progress;
1764 ibdm_wakeup_probe_gid_cv();
1765 mutex_exit(&ibdm.ibdm_mutex);
1766 return;
1767 }
1768 ibdm_add_to_gl_gid(gid_info, gid_info);
1769 mutex_exit(&ibdm.ibdm_mutex);
1770
1771 /*
1772 * New or reinserted GID : Enable notification to IBnex
1773 */
1774 mutex_enter(&gid_info->gl_mutex);
1775 gid_info->gl_reprobe_flag = 1;
1776
1777 /*
1778 * A Cisco FC GW needs the special handling to get IOUnitInfo.
1779 */
1780 if (ibdm_is_cisco_switch(gid_info)) {
1781 gid_info->gl_pending_cmds++;
1782 gid_info->gl_state = IBDM_SET_CLASSPORTINFO;
1783 mutex_exit(&gid_info->gl_mutex);
1784
1785 if (ibdm_set_classportinfo(gid_info) != IBDM_SUCCESS) {
1786 mutex_enter(&gid_info->gl_mutex);
1787 gid_info->gl_state = IBDM_GID_PROBING_FAILED;
1788 --gid_info->gl_pending_cmds;
1789 mutex_exit(&gid_info->gl_mutex);
1790
1791 /* free the hca_list on this gid_info */
1792 ibdm_delete_glhca_list(gid_info);
1793
1794 mutex_enter(&ibdm.ibdm_mutex);
1795 --ibdm.ibdm_ngid_probes_in_progress;
1796 ibdm_wakeup_probe_gid_cv();
1797 mutex_exit(&ibdm.ibdm_mutex);
1798
1799 return;
1800 }
1801
1802 mutex_enter(&gid_info->gl_mutex);
1803 ibdm_wait_cisco_probe_completion(gid_info);
1804
1805 IBTF_DPRINTF_L4("ibdm", "\tibdm_probe_gid_thread: "
1806 "CISCO Wakeup signal received");
1807 }
1808
1809 /* move on to the 'GET_CLASSPORTINFO' stage */
1810 gid_info->gl_pending_cmds++;
1811 gid_info->gl_state = IBDM_GET_CLASSPORTINFO;
1812 mutex_exit(&gid_info->gl_mutex);
1813
1814 IBTF_DPRINTF_L3(ibdm_string, "\tibdm_probe_gid_thread: "
1815 "%d: gid_info %p gl_state %d pending_cmds %d",
1816 __LINE__, gid_info, gid_info->gl_state,
1817 gid_info->gl_pending_cmds);
1818
1819 /*
1820 * Send ClassPortInfo request to the GID asynchronously.
1821 */
1822 if (ibdm_send_classportinfo(gid_info) != IBDM_SUCCESS) {
1823
1824 mutex_enter(&gid_info->gl_mutex);
1825 gid_info->gl_state = IBDM_GID_PROBING_FAILED;
1826 --gid_info->gl_pending_cmds;
1827 mutex_exit(&gid_info->gl_mutex);
1828
1829 /* free the hca_list on this gid_info */
1830 ibdm_delete_glhca_list(gid_info);
1831
1832 mutex_enter(&ibdm.ibdm_mutex);
1833 --ibdm.ibdm_ngid_probes_in_progress;
1834 ibdm_wakeup_probe_gid_cv();
1835 mutex_exit(&ibdm.ibdm_mutex);
1836
1837 return;
1838 }
1839 }
1840
1841
1842 /*
1843 * ibdm_check_dest_nodeguid
1844 * Searches for the NodeGuid in the GID list
1845 * Returns matching gid_info if found and otherwise NULL
1846 *
1847 * This function is called to handle new GIDs discovered
1848 * during device sweep / probe or for GID_AVAILABLE event.
1849 *
1850 * Parameter :
1851 * gid_info GID to check
1852 */
1853 static ibdm_dp_gidinfo_t *
ibdm_check_dest_nodeguid(ibdm_dp_gidinfo_t * gid_info)1854 ibdm_check_dest_nodeguid(ibdm_dp_gidinfo_t *gid_info)
1855 {
1856 ibdm_dp_gidinfo_t *gid_list;
1857 ibdm_gid_t *tmp;
1858
1859 IBTF_DPRINTF_L4("ibdm", "\tcheck_dest_nodeguid");
1860
1861 gid_list = ibdm.ibdm_dp_gidlist_head;
1862 while (gid_list) {
1863 if ((gid_list != gid_info) &&
1864 (gid_info->gl_nodeguid == gid_list->gl_nodeguid)) {
1865 IBTF_DPRINTF_L4("ibdm",
1866 "\tcheck_dest_nodeguid: NodeGuid is present");
1867
1868 /* Add to gid_list */
1869 tmp = kmem_zalloc(sizeof (ibdm_gid_t),
1870 KM_SLEEP);
1871 tmp->gid_dgid_hi = gid_info->gl_dgid_hi;
1872 tmp->gid_dgid_lo = gid_info->gl_dgid_lo;
1873 tmp->gid_next = gid_list->gl_gid;
1874 gid_list->gl_gid = tmp;
1875 gid_list->gl_ngids++;
1876 return (gid_list);
1877 }
1878
1879 gid_list = gid_list->gl_next;
1880 }
1881
1882 return (NULL);
1883 }
1884
1885
1886 /*
1887 * ibdm_is_dev_mgt_supported
1888 * Get the PortInfo attribute (SA Query)
1889 * Check "CompatabilityMask" field in the Portinfo.
1890 * Return IBDM_SUCCESS if DM MAD's supported (if bit 19 set)
1891 * by the port, otherwise IBDM_FAILURE
1892 */
1893 static int
ibdm_is_dev_mgt_supported(ibdm_dp_gidinfo_t * gid_info)1894 ibdm_is_dev_mgt_supported(ibdm_dp_gidinfo_t *gid_info)
1895 {
1896 int ret;
1897 size_t length = 0;
1898 sa_portinfo_record_t req, *resp = NULL;
1899 ibmf_saa_access_args_t qargs;
1900
1901 bzero(&req, sizeof (sa_portinfo_record_t));
1902 req.EndportLID = gid_info->gl_dlid;
1903
1904 qargs.sq_attr_id = SA_PORTINFORECORD_ATTRID;
1905 qargs.sq_access_type = IBMF_SAA_RETRIEVE;
1906 qargs.sq_component_mask = SA_PORTINFO_COMPMASK_PORTLID;
1907 qargs.sq_template = &req;
1908 qargs.sq_callback = NULL;
1909 qargs.sq_callback_arg = NULL;
1910
1911 ret = ibmf_sa_access(gid_info->gl_sa_hdl,
1912 &qargs, 0, &length, (void **)&resp);
1913
1914 if ((ret != IBMF_SUCCESS) || (length == 0) || (resp == NULL)) {
1915 IBTF_DPRINTF_L2("ibdm", "\tis_dev_mgt_supported:"
1916 "failed to get PORTINFO attribute %d", ret);
1917 return (IBDM_FAILURE);
1918 }
1919
1920 if (resp->PortInfo.CapabilityMask & SM_CAP_MASK_IS_DM_SUPPD) {
1921 IBTF_DPRINTF_L4("ibdm", "\tis_dev_mgt_supported: SUPPD !!");
1922 ret = IBDM_SUCCESS;
1923 } else {
1924 IBTF_DPRINTF_L4("ibdm", "\tis_dev_mgt_supported: "
1925 "Not SUPPD !!, cap 0x%x", resp->PortInfo.CapabilityMask);
1926 ret = IBDM_FAILURE;
1927 }
1928 kmem_free(resp, length);
1929 return (ret);
1930 }
1931
1932
1933 /*
1934 * ibdm_get_node_port_guids()
1935 * Get the NodeInfoRecord of the port
1936 * Save NodeGuid and PortGUID values in the GID list structure.
1937 * Return IBDM_SUCCESS/IBDM_FAILURE
1938 */
1939 static int
ibdm_get_node_port_guids(ibmf_saa_handle_t sa_hdl,ib_lid_t dlid,ib_guid_t * node_guid,ib_guid_t * port_guid)1940 ibdm_get_node_port_guids(ibmf_saa_handle_t sa_hdl, ib_lid_t dlid,
1941 ib_guid_t *node_guid, ib_guid_t *port_guid)
1942 {
1943 int ret;
1944 size_t length = 0;
1945 sa_node_record_t req, *resp = NULL;
1946 ibmf_saa_access_args_t qargs;
1947
1948 IBTF_DPRINTF_L4("ibdm", "\tget_node_port_guids");
1949
1950 bzero(&req, sizeof (sa_node_record_t));
1951 req.LID = dlid;
1952
1953 qargs.sq_attr_id = SA_NODERECORD_ATTRID;
1954 qargs.sq_access_type = IBMF_SAA_RETRIEVE;
1955 qargs.sq_component_mask = SA_NODEINFO_COMPMASK_NODELID;
1956 qargs.sq_template = &req;
1957 qargs.sq_callback = NULL;
1958 qargs.sq_callback_arg = NULL;
1959
1960 ret = ibmf_sa_access(sa_hdl, &qargs, 0, &length, (void **)&resp);
1961 if ((ret != IBMF_SUCCESS) || (length == 0) || (resp == NULL)) {
1962 IBTF_DPRINTF_L2("ibdm", "\tget_node_port_guids:"
1963 " SA Retrieve Failed: %d", ret);
1964 return (IBDM_FAILURE);
1965 }
1966 IBTF_DPRINTF_L4("ibdm", "\tget_node_port_guids: NodeGuid %llx Port"
1967 "GUID %llx", resp->NodeInfo.NodeGUID, resp->NodeInfo.NodeGUID);
1968
1969 *node_guid = resp->NodeInfo.NodeGUID;
1970 *port_guid = resp->NodeInfo.PortGUID;
1971 kmem_free(resp, length);
1972 return (IBDM_SUCCESS);
1973 }
1974
1975
1976 /*
1977 * ibdm_get_reachable_ports()
1978 * Get list of the destination GID (and its path records) by
1979 * querying the SA access.
1980 *
1981 * Returns Number paths
1982 */
1983 static int
ibdm_get_reachable_ports(ibdm_port_attr_t * portinfo,ibdm_hca_list_t * hca)1984 ibdm_get_reachable_ports(ibdm_port_attr_t *portinfo, ibdm_hca_list_t *hca)
1985 {
1986 uint_t ii, jj, nrecs;
1987 uint_t npaths = 0;
1988 size_t length;
1989 ib_gid_t sgid;
1990 ibdm_pkey_tbl_t *pkey_tbl;
1991 sa_path_record_t *result;
1992 sa_path_record_t *precp;
1993 ibdm_dp_gidinfo_t *gid_info;
1994
1995 ASSERT(MUTEX_HELD(&ibdm.ibdm_hl_mutex));
1996 IBTF_DPRINTF_L4("ibdm", "\tget_reachable_ports: portinfo %p", portinfo);
1997
1998 sgid.gid_prefix = portinfo->pa_sn_prefix;
1999 sgid.gid_guid = portinfo->pa_port_guid;
2000
2001 /* get reversible paths */
2002 if (portinfo->pa_sa_hdl && ibmf_saa_paths_from_gid(portinfo->pa_sa_hdl,
2003 sgid, IBMF_SAA_PKEY_WC, B_TRUE, 0, &nrecs, &length, &result)
2004 != IBMF_SUCCESS) {
2005 IBTF_DPRINTF_L2("ibdm",
2006 "\tget_reachable_ports: Getting path records failed");
2007 return (0);
2008 }
2009
2010 for (ii = 0; ii < nrecs; ii++) {
2011 sa_node_record_t *nrec;
2012 size_t length;
2013
2014 precp = &result[ii];
2015 if ((gid_info = ibdm_check_dgid(precp->DGID.gid_guid,
2016 precp->DGID.gid_prefix)) != NULL) {
2017 IBTF_DPRINTF_L5("ibdm", "\tget_reachable_ports: "
2018 "Already exists nrecs %d, ii %d", nrecs, ii);
2019 ibdm_addto_glhcalist(gid_info, hca);
2020 continue;
2021 }
2022 /*
2023 * This is a new GID. Allocate a GID structure and
2024 * initialize the structure
2025 * gl_state is initialized to IBDM_GID_PROBE_NOT_DONE (0)
2026 * by kmem_zalloc call
2027 */
2028 gid_info = kmem_zalloc(sizeof (ibdm_dp_gidinfo_t), KM_SLEEP);
2029 mutex_init(&gid_info->gl_mutex, NULL, MUTEX_DEFAULT, NULL);
2030 cv_init(&gid_info->gl_probe_cv, NULL, CV_DRIVER, NULL);
2031 gid_info->gl_dgid_hi = precp->DGID.gid_prefix;
2032 gid_info->gl_dgid_lo = precp->DGID.gid_guid;
2033 gid_info->gl_sgid_hi = precp->SGID.gid_prefix;
2034 gid_info->gl_sgid_lo = precp->SGID.gid_guid;
2035 gid_info->gl_p_key = precp->P_Key;
2036 gid_info->gl_sa_hdl = portinfo->pa_sa_hdl;
2037 gid_info->gl_ibmf_hdl = portinfo->pa_ibmf_hdl;
2038 gid_info->gl_slid = precp->SLID;
2039 gid_info->gl_dlid = precp->DLID;
2040 gid_info->gl_transactionID = (++ibdm.ibdm_transactionID)
2041 << IBDM_GID_TRANSACTIONID_SHIFT;
2042 gid_info->gl_min_transactionID = gid_info->gl_transactionID;
2043 gid_info->gl_max_transactionID = (ibdm.ibdm_transactionID +1)
2044 << IBDM_GID_TRANSACTIONID_SHIFT;
2045 gid_info->gl_SL = precp->SL;
2046
2047 /*
2048 * get the node record with this guid if the destination
2049 * device is a Cisco one.
2050 */
2051 if (ibdm_is_cisco(precp->DGID.gid_guid) &&
2052 (gid_info->gl_nodeguid == 0 || gid_info->gl_devid == 0) &&
2053 ibdm_get_node_record_by_port(portinfo->pa_sa_hdl,
2054 precp->DGID.gid_guid, &nrec, &length) == IBDM_SUCCESS) {
2055 gid_info->gl_nodeguid = nrec->NodeInfo.NodeGUID;
2056 gid_info->gl_devid = nrec->NodeInfo.DeviceID;
2057 kmem_free(nrec, length);
2058 }
2059
2060 ibdm_addto_glhcalist(gid_info, hca);
2061
2062 ibdm_dump_path_info(precp);
2063
2064 gid_info->gl_qp_hdl = NULL;
2065 ASSERT(portinfo->pa_pkey_tbl != NULL &&
2066 portinfo->pa_npkeys != 0);
2067
2068 for (jj = 0; jj < portinfo->pa_npkeys; jj++) {
2069 pkey_tbl = &portinfo->pa_pkey_tbl[jj];
2070 if ((gid_info->gl_p_key == pkey_tbl->pt_pkey) &&
2071 (pkey_tbl->pt_qp_hdl != NULL)) {
2072 gid_info->gl_qp_hdl = pkey_tbl->pt_qp_hdl;
2073 break;
2074 }
2075 }
2076
2077 /*
2078 * QP handle for GID not initialized. No matching Pkey
2079 * was found!! ibdm should *not* hit this case. Flag an
2080 * error and drop the GID if ibdm does encounter this.
2081 */
2082 if (gid_info->gl_qp_hdl == NULL) {
2083 IBTF_DPRINTF_L2(ibdm_string,
2084 "\tget_reachable_ports: No matching Pkey");
2085 ibdm_delete_gidinfo(gid_info);
2086 continue;
2087 }
2088 if (ibdm.ibdm_dp_gidlist_head == NULL) {
2089 ibdm.ibdm_dp_gidlist_head = gid_info;
2090 ibdm.ibdm_dp_gidlist_tail = gid_info;
2091 } else {
2092 ibdm.ibdm_dp_gidlist_tail->gl_next = gid_info;
2093 gid_info->gl_prev = ibdm.ibdm_dp_gidlist_tail;
2094 ibdm.ibdm_dp_gidlist_tail = gid_info;
2095 }
2096 npaths++;
2097 }
2098 kmem_free(result, length);
2099 IBTF_DPRINTF_L4("ibdm", "\tget_reachable_ports: npaths = %d", npaths);
2100 return (npaths);
2101 }
2102
2103
2104 /*
2105 * ibdm_check_dgid()
2106 * Look in the global list to check whether we know this DGID already
2107 * Return IBDM_GID_PRESENT/IBDM_GID_NOT_PRESENT
2108 */
2109 static ibdm_dp_gidinfo_t *
ibdm_check_dgid(ib_guid_t guid,ib_sn_prefix_t prefix)2110 ibdm_check_dgid(ib_guid_t guid, ib_sn_prefix_t prefix)
2111 {
2112 ibdm_dp_gidinfo_t *gid_list;
2113
2114 for (gid_list = ibdm.ibdm_dp_gidlist_head; gid_list;
2115 gid_list = gid_list->gl_next) {
2116 if ((guid == gid_list->gl_dgid_lo) &&
2117 (prefix == gid_list->gl_dgid_hi)) {
2118 break;
2119 }
2120 }
2121 return (gid_list);
2122 }
2123
2124
2125 /*
2126 * ibdm_find_gid()
2127 * Look in the global list to find a GID entry with matching
2128 * port & node GUID.
2129 * Return pointer to gidinfo if found, else return NULL
2130 */
2131 static ibdm_dp_gidinfo_t *
ibdm_find_gid(ib_guid_t nodeguid,ib_guid_t portguid)2132 ibdm_find_gid(ib_guid_t nodeguid, ib_guid_t portguid)
2133 {
2134 ibdm_dp_gidinfo_t *gid_list;
2135
2136 IBTF_DPRINTF_L4("ibdm", "ibdm_find_gid(%llx, %llx)\n",
2137 nodeguid, portguid);
2138
2139 for (gid_list = ibdm.ibdm_dp_gidlist_head; gid_list;
2140 gid_list = gid_list->gl_next) {
2141 if ((portguid == gid_list->gl_portguid) &&
2142 (nodeguid == gid_list->gl_nodeguid)) {
2143 break;
2144 }
2145 }
2146
2147 IBTF_DPRINTF_L4("ibdm", "ibdm_find_gid : returned %p\n",
2148 gid_list);
2149 return (gid_list);
2150 }
2151
2152
2153 /*
2154 * ibdm_set_classportinfo()
2155 * ibdm_set_classportinfo() is a function to activate a Cisco FC GW
2156 * by sending the setClassPortInfo request with the trapLID, trapGID
2157 * and etc. to the gateway since the gateway doesn't provide the IO
2158 * Unit Information othewise. This behavior is the Cisco specific one,
2159 * and this function is called to a Cisco FC GW only.
2160 * Returns IBDM_SUCCESS/IBDM_FAILURE
2161 */
2162 static int
ibdm_set_classportinfo(ibdm_dp_gidinfo_t * gid_info)2163 ibdm_set_classportinfo(ibdm_dp_gidinfo_t *gid_info)
2164 {
2165 ibmf_msg_t *msg;
2166 ib_mad_hdr_t *hdr;
2167 ibdm_timeout_cb_args_t *cb_args;
2168 void *data;
2169 ib_mad_classportinfo_t *cpi;
2170
2171 IBTF_DPRINTF_L4("ibdm",
2172 "\tset_classportinfo: gid info 0x%p", gid_info);
2173
2174 /*
2175 * Send command to set classportinfo attribute. Allocate a IBMF
2176 * packet and initialize the packet.
2177 */
2178 if (ibmf_alloc_msg(gid_info->gl_ibmf_hdl, IBMF_ALLOC_SLEEP,
2179 &msg) != IBMF_SUCCESS) {
2180 IBTF_DPRINTF_L4("ibdm", "\tset_classportinfo: pkt alloc fail");
2181 return (IBDM_FAILURE);
2182 }
2183
2184 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*msg))
2185 ibdm_alloc_send_buffers(msg);
2186 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*msg))
2187
2188 msg->im_local_addr.ia_local_lid = gid_info->gl_slid;
2189 msg->im_local_addr.ia_remote_lid = gid_info->gl_dlid;
2190 msg->im_local_addr.ia_remote_qno = 1;
2191 msg->im_local_addr.ia_p_key = gid_info->gl_p_key;
2192 msg->im_local_addr.ia_q_key = IB_GSI_QKEY;
2193 msg->im_local_addr.ia_service_level = gid_info->gl_SL;
2194
2195 hdr = IBDM_OUT_IBMFMSG_MADHDR(msg);
2196 hdr->BaseVersion = MAD_CLASS_BASE_VERS_1;
2197 hdr->MgmtClass = MAD_MGMT_CLASS_DEV_MGT;
2198 hdr->ClassVersion = IB_DM_CLASS_VERSION_1;
2199 hdr->R_Method = IB_DM_DEVMGT_METHOD_SET;
2200 hdr->Status = 0;
2201 hdr->TransactionID = h2b64(gid_info->gl_transactionID);
2202 hdr->AttributeID = h2b16(IB_DM_ATTR_CLASSPORTINFO);
2203 hdr->AttributeModifier = 0;
2204
2205 data = msg->im_msgbufs_send.im_bufs_cl_data;
2206 cpi = (ib_mad_classportinfo_t *)data;
2207
2208 /*
2209 * Set the classportinfo values to activate this Cisco FC GW.
2210 */
2211 cpi->TrapGID_hi = h2b64(gid_info->gl_sgid_hi);
2212 cpi->TrapGID_lo = h2b64(gid_info->gl_sgid_lo);
2213 cpi->TrapLID = h2b16(gid_info->gl_slid);
2214 cpi->TrapSL = gid_info->gl_SL;
2215 cpi->TrapP_Key = h2b16(gid_info->gl_p_key);
2216 cpi->TrapQP = h2b32((((ibmf_alt_qp_t *)gid_info->gl_qp_hdl)->isq_qpn));
2217 cpi->TrapQ_Key = h2b32((((ibmf_alt_qp_t *)
2218 gid_info->gl_qp_hdl)->isq_qkey));
2219
2220 cb_args = &gid_info->gl_cpi_cb_args;
2221 cb_args->cb_gid_info = gid_info;
2222 cb_args->cb_retry_count = ibdm_dft_retry_cnt;
2223 cb_args->cb_req_type = IBDM_REQ_TYPE_CLASSPORTINFO;
2224
2225 mutex_enter(&gid_info->gl_mutex);
2226 gid_info->gl_timeout_id = timeout(ibdm_pkt_timeout_hdlr,
2227 cb_args, IBDM_TIMEOUT_VALUE(ibdm_dft_timeout));
2228 mutex_exit(&gid_info->gl_mutex);
2229
2230 IBTF_DPRINTF_L5("ibdm", "\tset_classportinfo: "
2231 "timeout id %x", gid_info->gl_timeout_id);
2232
2233 if (ibmf_msg_transport(gid_info->gl_ibmf_hdl, gid_info->gl_qp_hdl,
2234 msg, NULL, ibdm_ibmf_send_cb, cb_args, 0) != IBMF_SUCCESS) {
2235 IBTF_DPRINTF_L2("ibdm",
2236 "\tset_classportinfo: ibmf send failed");
2237 ibdm_ibmf_send_cb(gid_info->gl_ibmf_hdl, msg, cb_args);
2238 }
2239
2240 return (IBDM_SUCCESS);
2241 }
2242
2243
2244 /*
2245 * ibdm_send_classportinfo()
2246 * Send classportinfo request. When the request is completed
2247 * IBMF calls ibdm_classportinfo_cb routine to inform about
2248 * the completion.
2249 * Returns IBDM_SUCCESS/IBDM_FAILURE
2250 */
2251 static int
ibdm_send_classportinfo(ibdm_dp_gidinfo_t * gid_info)2252 ibdm_send_classportinfo(ibdm_dp_gidinfo_t *gid_info)
2253 {
2254 ibmf_msg_t *msg;
2255 ib_mad_hdr_t *hdr;
2256 ibdm_timeout_cb_args_t *cb_args;
2257
2258 IBTF_DPRINTF_L4("ibdm",
2259 "\tsend_classportinfo: gid info 0x%p", gid_info);
2260
2261 /*
2262 * Send command to get classportinfo attribute. Allocate a IBMF
2263 * packet and initialize the packet.
2264 */
2265 if (ibmf_alloc_msg(gid_info->gl_ibmf_hdl, IBMF_ALLOC_SLEEP,
2266 &msg) != IBMF_SUCCESS) {
2267 IBTF_DPRINTF_L4("ibdm", "\tsend_classportinfo: pkt alloc fail");
2268 return (IBDM_FAILURE);
2269 }
2270
2271 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*msg))
2272 ibdm_alloc_send_buffers(msg);
2273 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*msg))
2274
2275 msg->im_local_addr.ia_local_lid = gid_info->gl_slid;
2276 msg->im_local_addr.ia_remote_lid = gid_info->gl_dlid;
2277 msg->im_local_addr.ia_remote_qno = 1;
2278 msg->im_local_addr.ia_p_key = gid_info->gl_p_key;
2279 msg->im_local_addr.ia_q_key = IB_GSI_QKEY;
2280 msg->im_local_addr.ia_service_level = gid_info->gl_SL;
2281
2282 hdr = IBDM_OUT_IBMFMSG_MADHDR(msg);
2283 hdr->BaseVersion = MAD_CLASS_BASE_VERS_1;
2284 hdr->MgmtClass = MAD_MGMT_CLASS_DEV_MGT;
2285 hdr->ClassVersion = IB_DM_CLASS_VERSION_1;
2286 hdr->R_Method = IB_DM_DEVMGT_METHOD_GET;
2287 hdr->Status = 0;
2288 hdr->TransactionID = h2b64(gid_info->gl_transactionID);
2289 hdr->AttributeID = h2b16(IB_DM_ATTR_CLASSPORTINFO);
2290 hdr->AttributeModifier = 0;
2291
2292 cb_args = &gid_info->gl_cpi_cb_args;
2293 cb_args->cb_gid_info = gid_info;
2294 cb_args->cb_retry_count = ibdm_dft_retry_cnt;
2295 cb_args->cb_req_type = IBDM_REQ_TYPE_CLASSPORTINFO;
2296
2297 mutex_enter(&gid_info->gl_mutex);
2298 gid_info->gl_timeout_id = timeout(ibdm_pkt_timeout_hdlr,
2299 cb_args, IBDM_TIMEOUT_VALUE(ibdm_dft_timeout));
2300 mutex_exit(&gid_info->gl_mutex);
2301
2302 IBTF_DPRINTF_L5("ibdm", "\tsend_classportinfo: "
2303 "timeout id %x", gid_info->gl_timeout_id);
2304
2305 if (ibmf_msg_transport(gid_info->gl_ibmf_hdl, gid_info->gl_qp_hdl,
2306 msg, NULL, ibdm_ibmf_send_cb, cb_args, 0) != IBMF_SUCCESS) {
2307 IBTF_DPRINTF_L2("ibdm",
2308 "\tsend_classportinfo: ibmf send failed");
2309 ibdm_ibmf_send_cb(gid_info->gl_ibmf_hdl, msg, cb_args);
2310 }
2311
2312 return (IBDM_SUCCESS);
2313 }
2314
2315
2316 /*
2317 * ibdm_handle_setclassportinfo()
2318 * Invoked by the IBMF when setClassPortInfo request is completed.
2319 */
2320 static void
ibdm_handle_setclassportinfo(ibmf_handle_t ibmf_hdl,ibmf_msg_t * msg,ibdm_dp_gidinfo_t * gid_info,int * flag)2321 ibdm_handle_setclassportinfo(ibmf_handle_t ibmf_hdl,
2322 ibmf_msg_t *msg, ibdm_dp_gidinfo_t *gid_info, int *flag)
2323 {
2324 void *data;
2325 timeout_id_t timeout_id;
2326 ib_mad_classportinfo_t *cpi;
2327
2328 IBTF_DPRINTF_L4("ibdm", "\thandle_setclassportinfo:ibmf hdl "
2329 "%p msg %p gid info %p", ibmf_hdl, msg, gid_info);
2330
2331 if (IBDM_IN_IBMFMSG_ATTR(msg) != IB_DM_ATTR_CLASSPORTINFO) {
2332 IBTF_DPRINTF_L4("ibdm", "\thandle_setclassportinfo: "
2333 "Not a ClassPortInfo resp");
2334 *flag |= IBDM_IBMF_PKT_UNEXP_RESP;
2335 return;
2336 }
2337
2338 /*
2339 * Verify whether timeout handler is created/active.
2340 * If created/ active, cancel the timeout handler
2341 */
2342 mutex_enter(&gid_info->gl_mutex);
2343 if (gid_info->gl_state != IBDM_SET_CLASSPORTINFO) {
2344 IBTF_DPRINTF_L2("ibdm", "\thandle_setclassportinfo:DUP resp");
2345 *flag |= IBDM_IBMF_PKT_DUP_RESP;
2346 mutex_exit(&gid_info->gl_mutex);
2347 return;
2348 }
2349 ibdm_bump_transactionID(gid_info);
2350
2351 gid_info->gl_iou_cb_args.cb_req_type = 0;
2352 if (gid_info->gl_timeout_id) {
2353 timeout_id = gid_info->gl_timeout_id;
2354 mutex_exit(&gid_info->gl_mutex);
2355 IBTF_DPRINTF_L5("ibdm", "handle_setlassportinfo: "
2356 "gl_timeout_id = 0x%x", timeout_id);
2357 if (untimeout(timeout_id) == -1) {
2358 IBTF_DPRINTF_L2("ibdm", "handle_setclassportinfo: "
2359 "untimeout gl_timeout_id failed");
2360 }
2361 mutex_enter(&gid_info->gl_mutex);
2362 gid_info->gl_timeout_id = 0;
2363 }
2364 mutex_exit(&gid_info->gl_mutex);
2365
2366 data = msg->im_msgbufs_recv.im_bufs_cl_data;
2367 cpi = (ib_mad_classportinfo_t *)data;
2368
2369 ibdm_dump_classportinfo(cpi);
2370 }
2371
2372
2373 /*
2374 * ibdm_handle_classportinfo()
2375 * Invoked by the IBMF when the classportinfo request is completed.
2376 */
2377 static void
ibdm_handle_classportinfo(ibmf_handle_t ibmf_hdl,ibmf_msg_t * msg,ibdm_dp_gidinfo_t * gid_info,int * flag)2378 ibdm_handle_classportinfo(ibmf_handle_t ibmf_hdl,
2379 ibmf_msg_t *msg, ibdm_dp_gidinfo_t *gid_info, int *flag)
2380 {
2381 void *data;
2382 timeout_id_t timeout_id;
2383 ib_mad_hdr_t *hdr;
2384 ib_mad_classportinfo_t *cpi;
2385
2386 IBTF_DPRINTF_L4("ibdm", "\thandle_classportinfo:ibmf hdl "
2387 "%p msg %p gid info %p", ibmf_hdl, msg, gid_info);
2388
2389 if (IBDM_IN_IBMFMSG_ATTR(msg) != IB_DM_ATTR_CLASSPORTINFO) {
2390 IBTF_DPRINTF_L4("ibdm", "\thandle_classportinfo: "
2391 "Not a ClassPortInfo resp");
2392 *flag |= IBDM_IBMF_PKT_UNEXP_RESP;
2393 return;
2394 }
2395
2396 /*
2397 * Verify whether timeout handler is created/active.
2398 * If created/ active, cancel the timeout handler
2399 */
2400 mutex_enter(&gid_info->gl_mutex);
2401 ibdm_bump_transactionID(gid_info);
2402 if (gid_info->gl_state != IBDM_GET_CLASSPORTINFO) {
2403 IBTF_DPRINTF_L2("ibdm", "\thandle_classportinfo:DUP resp");
2404 *flag |= IBDM_IBMF_PKT_DUP_RESP;
2405 mutex_exit(&gid_info->gl_mutex);
2406 return;
2407 }
2408 gid_info->gl_iou_cb_args.cb_req_type = 0;
2409 if (gid_info->gl_timeout_id) {
2410 timeout_id = gid_info->gl_timeout_id;
2411 mutex_exit(&gid_info->gl_mutex);
2412 IBTF_DPRINTF_L5("ibdm", "handle_ioclassportinfo: "
2413 "gl_timeout_id = 0x%x", timeout_id);
2414 if (untimeout(timeout_id) == -1) {
2415 IBTF_DPRINTF_L2("ibdm", "handle_classportinfo: "
2416 "untimeout gl_timeout_id failed");
2417 }
2418 mutex_enter(&gid_info->gl_mutex);
2419 gid_info->gl_timeout_id = 0;
2420 }
2421 gid_info->gl_state = IBDM_GET_IOUNITINFO;
2422 gid_info->gl_pending_cmds++;
2423 mutex_exit(&gid_info->gl_mutex);
2424
2425 data = msg->im_msgbufs_recv.im_bufs_cl_data;
2426 cpi = (ib_mad_classportinfo_t *)data;
2427
2428 /*
2429 * Cache the "RespTimeValue" and redirection information in the
2430 * global gid list data structure. This cached information will
2431 * be used to send any further requests to the GID.
2432 */
2433 gid_info->gl_resp_timeout =
2434 (b2h32(cpi->RespTimeValue) & 0x1F);
2435
2436 gid_info->gl_redirected = ((IBDM_IN_IBMFMSG_STATUS(msg) &
2437 MAD_STATUS_REDIRECT_REQUIRED) ? B_TRUE: B_FALSE);
2438 gid_info->gl_redirect_dlid = b2h16(cpi->RedirectLID);
2439 gid_info->gl_redirect_QP = (b2h32(cpi->RedirectQP) & 0xffffff);
2440 gid_info->gl_redirect_pkey = b2h16(cpi->RedirectP_Key);
2441 gid_info->gl_redirect_qkey = b2h32(cpi->RedirectQ_Key);
2442 gid_info->gl_redirectGID_hi = b2h64(cpi->RedirectGID_hi);
2443 gid_info->gl_redirectGID_lo = b2h64(cpi->RedirectGID_lo);
2444 gid_info->gl_redirectSL = cpi->RedirectSL;
2445
2446 ibdm_dump_classportinfo(cpi);
2447
2448 /*
2449 * Send IOUnitInfo request
2450 * Reuse previously allocated IBMF packet for sending ClassPortInfo
2451 * Check whether DM agent on the remote node requested redirection
2452 * If so, send the request to the redirect DGID/DLID/PKEY/QP.
2453 */
2454 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*msg))
2455 ibdm_alloc_send_buffers(msg);
2456 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*msg))
2457 msg->im_local_addr.ia_local_lid = gid_info->gl_slid;
2458 msg->im_local_addr.ia_remote_lid = gid_info->gl_dlid;
2459
2460 if (gid_info->gl_redirected == B_TRUE) {
2461 if (gid_info->gl_redirect_dlid != 0) {
2462 msg->im_local_addr.ia_remote_lid =
2463 gid_info->gl_redirect_dlid;
2464 }
2465 msg->im_local_addr.ia_remote_qno = gid_info->gl_redirect_QP;
2466 msg->im_local_addr.ia_p_key = gid_info->gl_redirect_pkey;
2467 msg->im_local_addr.ia_q_key = gid_info->gl_redirect_qkey;
2468 msg->im_local_addr.ia_service_level = gid_info->gl_redirectSL;
2469 } else {
2470 msg->im_local_addr.ia_remote_qno = 1;
2471 msg->im_local_addr.ia_p_key = gid_info->gl_p_key;
2472 msg->im_local_addr.ia_q_key = IB_GSI_QKEY;
2473 msg->im_local_addr.ia_service_level = gid_info->gl_SL;
2474 }
2475
2476 hdr = IBDM_OUT_IBMFMSG_MADHDR(msg);
2477 hdr->BaseVersion = MAD_CLASS_BASE_VERS_1;
2478 hdr->MgmtClass = MAD_MGMT_CLASS_DEV_MGT;
2479 hdr->ClassVersion = IB_DM_CLASS_VERSION_1;
2480 hdr->R_Method = IB_DM_DEVMGT_METHOD_GET;
2481 hdr->Status = 0;
2482 hdr->TransactionID = h2b64(gid_info->gl_transactionID);
2483 hdr->AttributeID = h2b16(IB_DM_ATTR_IO_UNITINFO);
2484 hdr->AttributeModifier = 0;
2485
2486 gid_info->gl_iou_cb_args.cb_req_type = IBDM_REQ_TYPE_IOUINFO;
2487 gid_info->gl_iou_cb_args.cb_gid_info = gid_info;
2488 gid_info->gl_iou_cb_args.cb_retry_count = ibdm_dft_retry_cnt;
2489
2490 mutex_enter(&gid_info->gl_mutex);
2491 gid_info->gl_timeout_id = timeout(ibdm_pkt_timeout_hdlr,
2492 &gid_info->gl_iou_cb_args, IBDM_TIMEOUT_VALUE(ibdm_dft_timeout));
2493 mutex_exit(&gid_info->gl_mutex);
2494
2495 IBTF_DPRINTF_L5("ibdm", "handle_classportinfo:"
2496 "timeout %x", gid_info->gl_timeout_id);
2497
2498 if (ibmf_msg_transport(ibmf_hdl, gid_info->gl_qp_hdl, msg, NULL,
2499 ibdm_ibmf_send_cb, &gid_info->gl_iou_cb_args, 0) != IBMF_SUCCESS) {
2500 IBTF_DPRINTF_L2("ibdm",
2501 "\thandle_classportinfo: msg transport failed");
2502 ibdm_ibmf_send_cb(ibmf_hdl, msg, &gid_info->gl_iou_cb_args);
2503 }
2504 (*flag) |= IBDM_IBMF_PKT_REUSED;
2505 }
2506
2507
2508 /*
2509 * ibdm_send_iounitinfo:
2510 * Sends a DM request to get IOU unitinfo.
2511 */
2512 static int
ibdm_send_iounitinfo(ibdm_dp_gidinfo_t * gid_info)2513 ibdm_send_iounitinfo(ibdm_dp_gidinfo_t *gid_info)
2514 {
2515 ibmf_msg_t *msg;
2516 ib_mad_hdr_t *hdr;
2517
2518 IBTF_DPRINTF_L4("ibdm", "\tsend_iounitinfo: gid info 0x%p", gid_info);
2519
2520 /*
2521 * Send command to get iounitinfo attribute. Allocate a IBMF
2522 * packet and initialize the packet.
2523 */
2524 if (ibmf_alloc_msg(gid_info->gl_ibmf_hdl, IBMF_ALLOC_SLEEP, &msg) !=
2525 IBMF_SUCCESS) {
2526 IBTF_DPRINTF_L4("ibdm", "\tsend_iounitinfo: pkt alloc fail");
2527 return (IBDM_FAILURE);
2528 }
2529
2530 mutex_enter(&gid_info->gl_mutex);
2531 ibdm_bump_transactionID(gid_info);
2532 mutex_exit(&gid_info->gl_mutex);
2533
2534
2535 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*msg))
2536 ibdm_alloc_send_buffers(msg);
2537 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*msg))
2538 msg->im_local_addr.ia_local_lid = gid_info->gl_slid;
2539 msg->im_local_addr.ia_remote_lid = gid_info->gl_dlid;
2540 msg->im_local_addr.ia_remote_qno = 1;
2541 msg->im_local_addr.ia_p_key = gid_info->gl_p_key;
2542 msg->im_local_addr.ia_q_key = IB_GSI_QKEY;
2543 msg->im_local_addr.ia_service_level = gid_info->gl_SL;
2544
2545 hdr = IBDM_OUT_IBMFMSG_MADHDR(msg);
2546 hdr->BaseVersion = MAD_CLASS_BASE_VERS_1;
2547 hdr->MgmtClass = MAD_MGMT_CLASS_DEV_MGT;
2548 hdr->ClassVersion = IB_DM_CLASS_VERSION_1;
2549 hdr->R_Method = IB_DM_DEVMGT_METHOD_GET;
2550 hdr->Status = 0;
2551 hdr->TransactionID = h2b64(gid_info->gl_transactionID);
2552 hdr->AttributeID = h2b16(IB_DM_ATTR_IO_UNITINFO);
2553 hdr->AttributeModifier = 0;
2554
2555 gid_info->gl_iou_cb_args.cb_gid_info = gid_info;
2556 gid_info->gl_iou_cb_args.cb_retry_count = ibdm_dft_retry_cnt;
2557 gid_info->gl_iou_cb_args.cb_req_type = IBDM_REQ_TYPE_IOUINFO;
2558
2559 mutex_enter(&gid_info->gl_mutex);
2560 gid_info->gl_timeout_id = timeout(ibdm_pkt_timeout_hdlr,
2561 &gid_info->gl_iou_cb_args, IBDM_TIMEOUT_VALUE(ibdm_dft_timeout));
2562 mutex_exit(&gid_info->gl_mutex);
2563
2564 IBTF_DPRINTF_L5("ibdm", "send_iouunitinfo:"
2565 "timeout %x", gid_info->gl_timeout_id);
2566
2567 if (ibmf_msg_transport(gid_info->gl_ibmf_hdl, gid_info->gl_qp_hdl, msg,
2568 NULL, ibdm_ibmf_send_cb, &gid_info->gl_iou_cb_args, 0) !=
2569 IBMF_SUCCESS) {
2570 IBTF_DPRINTF_L2("ibdm", "\tsend_iounitinfo: ibmf send failed");
2571 ibdm_ibmf_send_cb(gid_info->gl_ibmf_hdl,
2572 msg, &gid_info->gl_iou_cb_args);
2573 }
2574 return (IBDM_SUCCESS);
2575 }
2576
2577 /*
2578 * ibdm_handle_iounitinfo()
2579 * Invoked by the IBMF when IO Unitinfo request is completed.
2580 */
2581 static void
ibdm_handle_iounitinfo(ibmf_handle_t ibmf_hdl,ibmf_msg_t * msg,ibdm_dp_gidinfo_t * gid_info,int * flag)2582 ibdm_handle_iounitinfo(ibmf_handle_t ibmf_hdl,
2583 ibmf_msg_t *msg, ibdm_dp_gidinfo_t *gid_info, int *flag)
2584 {
2585 int ii, first = B_TRUE;
2586 int num_iocs;
2587 size_t size;
2588 uchar_t slot_info;
2589 timeout_id_t timeout_id;
2590 ib_mad_hdr_t *hdr;
2591 ibdm_ioc_info_t *ioc_info;
2592 ib_dm_io_unitinfo_t *iou_info;
2593 ib_dm_io_unitinfo_t *giou_info;
2594 ibdm_timeout_cb_args_t *cb_args;
2595
2596 IBTF_DPRINTF_L4("ibdm", "\thandle_iouintinfo:"
2597 " ibmf hdl %p pkt %p gid info %p", ibmf_hdl, msg, gid_info);
2598
2599 if (IBDM_IN_IBMFMSG_ATTR(msg) != IB_DM_ATTR_IO_UNITINFO) {
2600 IBTF_DPRINTF_L4("ibdm", "\thandle_iounitinfo: "
2601 "Unexpected response");
2602 (*flag) |= IBDM_IBMF_PKT_UNEXP_RESP;
2603 return;
2604 }
2605
2606 mutex_enter(&gid_info->gl_mutex);
2607 if (gid_info->gl_state != IBDM_GET_IOUNITINFO) {
2608 IBTF_DPRINTF_L4("ibdm",
2609 "\thandle_iounitinfo: DUP resp");
2610 mutex_exit(&gid_info->gl_mutex);
2611 (*flag) = IBDM_IBMF_PKT_DUP_RESP;
2612 return;
2613 }
2614 gid_info->gl_iou_cb_args.cb_req_type = 0;
2615 if (gid_info->gl_timeout_id) {
2616 timeout_id = gid_info->gl_timeout_id;
2617 mutex_exit(&gid_info->gl_mutex);
2618 IBTF_DPRINTF_L5("ibdm", "handle_iounitinfo: "
2619 "gl_timeout_id = 0x%x", timeout_id);
2620 if (untimeout(timeout_id) == -1) {
2621 IBTF_DPRINTF_L2("ibdm", "handle_iounitinfo: "
2622 "untimeout gl_timeout_id failed");
2623 }
2624 mutex_enter(&gid_info->gl_mutex);
2625 gid_info->gl_timeout_id = 0;
2626 }
2627 gid_info->gl_state = IBDM_GET_IOC_DETAILS;
2628
2629 iou_info = IBDM_IN_IBMFMSG2IOU(msg);
2630 ibdm_dump_iounitinfo(iou_info);
2631 num_iocs = iou_info->iou_num_ctrl_slots;
2632 /*
2633 * check if number of IOCs reported is zero? if yes, return.
2634 * when num_iocs are reported zero internal IOC database needs
2635 * to be updated. To ensure that save the number of IOCs in
2636 * the new field "gl_num_iocs". Use a new field instead of
2637 * "giou_info->iou_num_ctrl_slots" as that would prevent
2638 * an unnecessary kmem_alloc/kmem_free when num_iocs is 0.
2639 */
2640 if (num_iocs == 0 && gid_info->gl_num_iocs == 0) {
2641 IBTF_DPRINTF_L4("ibdm", "\thandle_iounitinfo: no IOC's");
2642 mutex_exit(&gid_info->gl_mutex);
2643 return;
2644 }
2645 IBTF_DPRINTF_L4("ibdm", "\thandle_iounitinfo: num_iocs = %d", num_iocs);
2646
2647 /*
2648 * if there is an existing gl_iou (IOU has been probed before)
2649 * check if the "iou_changeid" is same as saved entry in
2650 * "giou_info->iou_changeid".
2651 * (note: this logic can prevent IOC enumeration if a given
2652 * vendor doesn't support setting iou_changeid field for its IOU)
2653 *
2654 * if there is an existing gl_iou and iou_changeid has changed :
2655 * free up existing gl_iou info and its related structures.
2656 * reallocate gl_iou info all over again.
2657 * if we donot free this up; then this leads to memory leaks
2658 */
2659 if (gid_info->gl_iou) {
2660 giou_info = &gid_info->gl_iou->iou_info;
2661 if (b2h16(iou_info->iou_changeid) ==
2662 giou_info->iou_changeid) {
2663 IBTF_DPRINTF_L3("ibdm",
2664 "\thandle_iounitinfo: no IOCs changed");
2665 gid_info->gl_state = IBDM_GID_PROBING_COMPLETE;
2666 mutex_exit(&gid_info->gl_mutex);
2667 return;
2668 }
2669
2670 /*
2671 * Store the iou info as prev_iou to be used after
2672 * sweep is done.
2673 */
2674 ASSERT(gid_info->gl_prev_iou == NULL);
2675 IBTF_DPRINTF_L4(ibdm_string,
2676 "\thandle_iounitinfo: setting gl_prev_iou %p",
2677 gid_info->gl_prev_iou);
2678 gid_info->gl_prev_iou = gid_info->gl_iou;
2679 ibdm.ibdm_prev_iou = 1;
2680 gid_info->gl_iou = NULL;
2681 }
2682
2683 size = sizeof (ibdm_iou_info_t) + num_iocs * sizeof (ibdm_ioc_info_t);
2684 gid_info->gl_iou = (ibdm_iou_info_t *)kmem_zalloc(size, KM_SLEEP);
2685 giou_info = &gid_info->gl_iou->iou_info;
2686 gid_info->gl_iou->iou_ioc_info = (ibdm_ioc_info_t *)
2687 ((char *)gid_info->gl_iou + sizeof (ibdm_iou_info_t));
2688
2689 giou_info->iou_num_ctrl_slots = gid_info->gl_num_iocs = num_iocs;
2690 giou_info->iou_flag = iou_info->iou_flag;
2691 bcopy(iou_info->iou_ctrl_list, giou_info->iou_ctrl_list, 128);
2692 giou_info->iou_changeid = b2h16(iou_info->iou_changeid);
2693 gid_info->gl_pending_cmds++; /* for diag code */
2694 mutex_exit(&gid_info->gl_mutex);
2695
2696 if (ibdm_get_diagcode(gid_info, 0) != IBDM_SUCCESS) {
2697 mutex_enter(&gid_info->gl_mutex);
2698 gid_info->gl_pending_cmds--;
2699 mutex_exit(&gid_info->gl_mutex);
2700 }
2701 /*
2702 * Parallelize getting IOC controller profiles from here.
2703 * Allocate IBMF packets and send commands to get IOC profile for
2704 * each IOC present on the IOU.
2705 */
2706 for (ii = 0; ii < num_iocs; ii++) {
2707 /*
2708 * Check whether IOC is present in the slot
2709 * Series of nibbles (in the field iou_ctrl_list) represents
2710 * a slot in the IOU.
2711 * Byte format: 76543210
2712 * Bits 0-3 of first byte represent Slot 2
2713 * bits 4-7 of first byte represent slot 1,
2714 * bits 0-3 of second byte represent slot 4 and so on
2715 * Each 4-bit nibble has the following meaning
2716 * 0x0 : IOC not installed
2717 * 0x1 : IOC is present
2718 * 0xf : Slot does not exist
2719 * and all other values are reserved.
2720 */
2721 ioc_info = IBDM_GIDINFO2IOCINFO(gid_info, ii);
2722 slot_info = giou_info->iou_ctrl_list[(ii/2)];
2723 if ((ii % 2) == 0)
2724 slot_info = (slot_info >> 4);
2725
2726 if ((slot_info & 0xf) != 1) {
2727 IBTF_DPRINTF_L4("ibdm", "\thandle_iouintinfo: "
2728 "No IOC is present in the slot = %d", ii);
2729 ioc_info->ioc_state = IBDM_IOC_STATE_PROBE_FAILED;
2730 continue;
2731 }
2732
2733 mutex_enter(&gid_info->gl_mutex);
2734 ibdm_bump_transactionID(gid_info);
2735 mutex_exit(&gid_info->gl_mutex);
2736
2737 /*
2738 * Re use the already allocated packet (for IOUnitinfo) to
2739 * send the first IOC controller attribute. Allocate new
2740 * IBMF packets for the rest of the IOC's
2741 */
2742 if (first != B_TRUE) {
2743 msg = NULL;
2744 if (ibmf_alloc_msg(ibmf_hdl, IBMF_ALLOC_SLEEP,
2745 &msg) != IBMF_SUCCESS) {
2746 IBTF_DPRINTF_L4("ibdm", "\thandle_iouintinfo: "
2747 "IBMF packet allocation failed");
2748 continue;
2749 }
2750
2751 }
2752
2753 /* allocate send buffers for all messages */
2754 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*msg))
2755 ibdm_alloc_send_buffers(msg);
2756 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*msg))
2757
2758 msg->im_local_addr.ia_local_lid = gid_info->gl_slid;
2759 msg->im_local_addr.ia_remote_lid = gid_info->gl_dlid;
2760 if (gid_info->gl_redirected == B_TRUE) {
2761 if (gid_info->gl_redirect_dlid != 0) {
2762 msg->im_local_addr.ia_remote_lid =
2763 gid_info->gl_redirect_dlid;
2764 }
2765 msg->im_local_addr.ia_remote_qno =
2766 gid_info->gl_redirect_QP;
2767 msg->im_local_addr.ia_p_key =
2768 gid_info->gl_redirect_pkey;
2769 msg->im_local_addr.ia_q_key =
2770 gid_info->gl_redirect_qkey;
2771 msg->im_local_addr.ia_service_level =
2772 gid_info->gl_redirectSL;
2773 } else {
2774 msg->im_local_addr.ia_remote_qno = 1;
2775 msg->im_local_addr.ia_p_key = gid_info->gl_p_key;
2776 msg->im_local_addr.ia_q_key = IB_GSI_QKEY;
2777 msg->im_local_addr.ia_service_level = gid_info->gl_SL;
2778 }
2779
2780 hdr = IBDM_OUT_IBMFMSG_MADHDR(msg);
2781 hdr->BaseVersion = MAD_CLASS_BASE_VERS_1;
2782 hdr->MgmtClass = MAD_MGMT_CLASS_DEV_MGT;
2783 hdr->ClassVersion = IB_DM_CLASS_VERSION_1;
2784 hdr->R_Method = IB_DM_DEVMGT_METHOD_GET;
2785 hdr->Status = 0;
2786 hdr->TransactionID = h2b64(gid_info->gl_transactionID);
2787 hdr->AttributeID = h2b16(IB_DM_ATTR_IOC_CTRL_PROFILE);
2788 hdr->AttributeModifier = h2b32(ii + 1);
2789
2790 ioc_info->ioc_state = IBDM_IOC_STATE_PROBE_INVALID;
2791 cb_args = &ioc_info->ioc_cb_args;
2792 cb_args->cb_gid_info = gid_info;
2793 cb_args->cb_retry_count = ibdm_dft_retry_cnt;
2794 cb_args->cb_req_type = IBDM_REQ_TYPE_IOCINFO;
2795 cb_args->cb_ioc_num = ii;
2796
2797 mutex_enter(&gid_info->gl_mutex);
2798 gid_info->gl_pending_cmds++; /* for diag code */
2799
2800 ioc_info->ioc_timeout_id = timeout(ibdm_pkt_timeout_hdlr,
2801 cb_args, IBDM_TIMEOUT_VALUE(ibdm_dft_timeout));
2802 mutex_exit(&gid_info->gl_mutex);
2803
2804 IBTF_DPRINTF_L5("ibdm", "\thandle_iounitinfo:"
2805 "timeout 0x%x, ioc_num %d", ioc_info->ioc_timeout_id, ii);
2806
2807 if (ibmf_msg_transport(ibmf_hdl, gid_info->gl_qp_hdl, msg,
2808 NULL, ibdm_ibmf_send_cb, cb_args, 0) != IBMF_SUCCESS) {
2809 IBTF_DPRINTF_L2("ibdm",
2810 "\thandle_iounitinfo: msg transport failed");
2811 ibdm_ibmf_send_cb(ibmf_hdl, msg, cb_args);
2812 }
2813 (*flag) |= IBDM_IBMF_PKT_REUSED;
2814 first = B_FALSE;
2815 gid_info->gl_iou->iou_niocs_probe_in_progress++;
2816 }
2817 }
2818
2819
2820 /*
2821 * ibdm_handle_ioc_profile()
2822 * Invoked by the IBMF when the IOCControllerProfile request
2823 * gets completed
2824 */
2825 static void
ibdm_handle_ioc_profile(ibmf_handle_t ibmf_hdl,ibmf_msg_t * msg,ibdm_dp_gidinfo_t * gid_info,int * flag)2826 ibdm_handle_ioc_profile(ibmf_handle_t ibmf_hdl,
2827 ibmf_msg_t *msg, ibdm_dp_gidinfo_t *gid_info, int *flag)
2828 {
2829 int first = B_TRUE, reprobe = 0;
2830 uint_t ii, ioc_no, srv_start;
2831 uint_t nserv_entries;
2832 timeout_id_t timeout_id;
2833 ib_mad_hdr_t *hdr;
2834 ibdm_ioc_info_t *ioc_info;
2835 ibdm_timeout_cb_args_t *cb_args;
2836 ib_dm_ioc_ctrl_profile_t *ioc, *gioc;
2837
2838 IBTF_DPRINTF_L4("ibdm", "\thandle_ioc_profile:"
2839 " ibmf hdl %p msg %p gid info %p", ibmf_hdl, msg, gid_info);
2840
2841 ioc = IBDM_IN_IBMFMSG2IOC(msg);
2842 /*
2843 * Check whether we know this IOC already
2844 * This will return NULL if reprobe is in progress
2845 * IBDM_IOC_STATE_REPROBE_PROGRESS will be set.
2846 * Do not hold mutexes here.
2847 */
2848 if (ibdm_is_ioc_present(ioc->ioc_guid, gid_info, flag) != NULL) {
2849 IBTF_DPRINTF_L4("ibdm", "\thandle_ioc_profile:"
2850 "IOC guid %llx is present", ioc->ioc_guid);
2851 return;
2852 }
2853 ioc_no = IBDM_IN_IBMFMSG_ATTRMOD(msg);
2854 IBTF_DPRINTF_L4("ibdm", "\thandle_ioc_profile: ioc_no = %d", ioc_no-1);
2855
2856 /* Make sure that IOC index is with the valid range */
2857 if (IBDM_IS_IOC_NUM_INVALID(ioc_no, gid_info)) {
2858 IBTF_DPRINTF_L2("ibdm", "\thandle_ioc_profile: "
2859 "IOC index Out of range, index %d", ioc);
2860 (*flag) |= IBDM_IBMF_PKT_UNEXP_RESP;
2861 return;
2862 }
2863 ioc_info = &gid_info->gl_iou->iou_ioc_info[ioc_no - 1];
2864 ioc_info->ioc_iou_info = gid_info->gl_iou;
2865
2866 mutex_enter(&gid_info->gl_mutex);
2867 if (ioc_info->ioc_state == IBDM_IOC_STATE_REPROBE_PROGRESS) {
2868 reprobe = 1;
2869 ioc_info->ioc_prev_serv = ioc_info->ioc_serv;
2870 ioc_info->ioc_serv = NULL;
2871 ioc_info->ioc_prev_serv_cnt =
2872 ioc_info->ioc_profile.ioc_service_entries;
2873 } else if (ioc_info->ioc_state != IBDM_IOC_STATE_PROBE_INVALID) {
2874 IBTF_DPRINTF_L2("ibdm", "\thandle_ioc_profile: DUP response"
2875 "ioc %d, ioc_state %x", ioc_no - 1, ioc_info->ioc_state);
2876 mutex_exit(&gid_info->gl_mutex);
2877 (*flag) |= IBDM_IBMF_PKT_DUP_RESP;
2878 return;
2879 }
2880 ioc_info->ioc_cb_args.cb_req_type = 0;
2881 if (ioc_info->ioc_timeout_id) {
2882 timeout_id = ioc_info->ioc_timeout_id;
2883 ioc_info->ioc_timeout_id = 0;
2884 mutex_exit(&gid_info->gl_mutex);
2885 IBTF_DPRINTF_L5("ibdm", "handle_ioc_profile: "
2886 "ioc_timeout_id = 0x%x", timeout_id);
2887 if (untimeout(timeout_id) == -1) {
2888 IBTF_DPRINTF_L2("ibdm", "handle_ioc_profile: "
2889 "untimeout ioc_timeout_id failed");
2890 }
2891 mutex_enter(&gid_info->gl_mutex);
2892 }
2893
2894 ioc_info->ioc_state = IBDM_IOC_STATE_PROBE_SUCCESS;
2895 if (reprobe == 0) {
2896 ioc_info->ioc_iou_guid = gid_info->gl_nodeguid;
2897 ioc_info->ioc_nodeguid = gid_info->gl_nodeguid;
2898 }
2899
2900 /*
2901 * Save all the IOC information in the global structures.
2902 * Note the wire format is Big Endian and the Sparc process also
2903 * big endian. So, there is no need to convert the data fields
2904 * The conversion routines used below are ineffective on Sparc
2905 * machines where as they will be effective on little endian
2906 * machines such as Intel processors.
2907 */
2908 gioc = (ib_dm_ioc_ctrl_profile_t *)&ioc_info->ioc_profile;
2909
2910 /*
2911 * Restrict updates to onlyport GIDs and service entries during reprobe
2912 */
2913 if (reprobe == 0) {
2914 gioc->ioc_guid = b2h64(ioc->ioc_guid);
2915 gioc->ioc_vendorid =
2916 ((b2h32(ioc->ioc_vendorid) & IB_DM_VENDORID_MASK)
2917 >> IB_DM_VENDORID_SHIFT);
2918 gioc->ioc_deviceid = b2h32(ioc->ioc_deviceid);
2919 gioc->ioc_device_ver = b2h16(ioc->ioc_device_ver);
2920 gioc->ioc_subsys_vendorid =
2921 ((b2h32(ioc->ioc_subsys_vendorid) & IB_DM_VENDORID_MASK)
2922 >> IB_DM_VENDORID_SHIFT);
2923 gioc->ioc_subsys_id = b2h32(ioc->ioc_subsys_id);
2924 gioc->ioc_io_class = b2h16(ioc->ioc_io_class);
2925 gioc->ioc_io_subclass = b2h16(ioc->ioc_io_subclass);
2926 gioc->ioc_protocol = b2h16(ioc->ioc_protocol);
2927 gioc->ioc_protocol_ver = b2h16(ioc->ioc_protocol_ver);
2928 gioc->ioc_send_msg_qdepth =
2929 b2h16(ioc->ioc_send_msg_qdepth);
2930 gioc->ioc_rdma_read_qdepth =
2931 b2h16(ioc->ioc_rdma_read_qdepth);
2932 gioc->ioc_send_msg_sz = b2h32(ioc->ioc_send_msg_sz);
2933 gioc->ioc_rdma_xfer_sz = b2h32(ioc->ioc_rdma_xfer_sz);
2934 gioc->ioc_ctrl_opcap_mask = ioc->ioc_ctrl_opcap_mask;
2935 bcopy(ioc->ioc_id_string, gioc->ioc_id_string,
2936 IB_DM_IOC_ID_STRING_LEN);
2937
2938 ioc_info->ioc_iou_diagcode = gid_info->gl_iou->iou_diagcode;
2939 ioc_info->ioc_iou_dc_valid = gid_info->gl_iou->iou_dc_valid;
2940 ioc_info->ioc_diagdeviceid = (IB_DM_IOU_DEVICEID_MASK &
2941 gid_info->gl_iou->iou_info.iou_flag) ? B_TRUE : B_FALSE;
2942
2943 if (ioc_info->ioc_diagdeviceid == B_TRUE) {
2944 gid_info->gl_pending_cmds++;
2945 IBTF_DPRINTF_L3(ibdm_string,
2946 "\tibdm_handle_ioc_profile: "
2947 "%d: gid_info %p gl_state %d pending_cmds %d",
2948 __LINE__, gid_info, gid_info->gl_state,
2949 gid_info->gl_pending_cmds);
2950 }
2951 }
2952 gioc->ioc_service_entries = ioc->ioc_service_entries;
2953 mutex_exit(&gid_info->gl_mutex);
2954
2955 ibdm_dump_ioc_profile(gioc);
2956
2957 if ((ioc_info->ioc_diagdeviceid == B_TRUE) && (reprobe == 0)) {
2958 if (ibdm_get_diagcode(gid_info, ioc_no) != IBDM_SUCCESS) {
2959 mutex_enter(&gid_info->gl_mutex);
2960 gid_info->gl_pending_cmds--;
2961 mutex_exit(&gid_info->gl_mutex);
2962 }
2963 }
2964 ioc_info->ioc_serv = (ibdm_srvents_info_t *)kmem_zalloc(
2965 (gioc->ioc_service_entries * sizeof (ibdm_srvents_info_t)),
2966 KM_SLEEP);
2967
2968 /*
2969 * In one single request, maximum number of requests that can be
2970 * obtained is 4. If number of service entries are more than four,
2971 * calculate number requests needed and send them parallelly.
2972 */
2973 nserv_entries = ioc->ioc_service_entries;
2974 ii = 0;
2975 while (nserv_entries) {
2976 mutex_enter(&gid_info->gl_mutex);
2977 gid_info->gl_pending_cmds++;
2978 ibdm_bump_transactionID(gid_info);
2979 mutex_exit(&gid_info->gl_mutex);
2980
2981 if (first != B_TRUE) {
2982 if (ibmf_alloc_msg(ibmf_hdl, IBMF_ALLOC_SLEEP,
2983 &msg) != IBMF_SUCCESS) {
2984 continue;
2985 }
2986
2987 }
2988 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*msg))
2989 ibdm_alloc_send_buffers(msg);
2990 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*msg))
2991 msg->im_local_addr.ia_local_lid = gid_info->gl_slid;
2992 msg->im_local_addr.ia_remote_lid = gid_info->gl_dlid;
2993 if (gid_info->gl_redirected == B_TRUE) {
2994 if (gid_info->gl_redirect_dlid != 0) {
2995 msg->im_local_addr.ia_remote_lid =
2996 gid_info->gl_redirect_dlid;
2997 }
2998 msg->im_local_addr.ia_remote_qno =
2999 gid_info->gl_redirect_QP;
3000 msg->im_local_addr.ia_p_key =
3001 gid_info->gl_redirect_pkey;
3002 msg->im_local_addr.ia_q_key =
3003 gid_info->gl_redirect_qkey;
3004 msg->im_local_addr.ia_service_level =
3005 gid_info->gl_redirectSL;
3006 } else {
3007 msg->im_local_addr.ia_remote_qno = 1;
3008 msg->im_local_addr.ia_p_key = gid_info->gl_p_key;
3009 msg->im_local_addr.ia_q_key = IB_GSI_QKEY;
3010 msg->im_local_addr.ia_service_level = gid_info->gl_SL;
3011 }
3012
3013 hdr = IBDM_OUT_IBMFMSG_MADHDR(msg);
3014 hdr->BaseVersion = MAD_CLASS_BASE_VERS_1;
3015 hdr->MgmtClass = MAD_MGMT_CLASS_DEV_MGT;
3016 hdr->ClassVersion = IB_DM_CLASS_VERSION_1;
3017 hdr->R_Method = IB_DM_DEVMGT_METHOD_GET;
3018 hdr->Status = 0;
3019 hdr->TransactionID = h2b64(gid_info->gl_transactionID);
3020 hdr->AttributeID = h2b16(IB_DM_ATTR_SERVICE_ENTRIES);
3021
3022 srv_start = ii * 4;
3023 cb_args = &ioc_info->ioc_serv[srv_start].se_cb_args;
3024 cb_args->cb_gid_info = gid_info;
3025 cb_args->cb_retry_count = ibdm_dft_retry_cnt;
3026 cb_args->cb_req_type = IBDM_REQ_TYPE_SRVENTS;
3027 cb_args->cb_srvents_start = srv_start;
3028 cb_args->cb_ioc_num = ioc_no - 1;
3029
3030 if (nserv_entries >= IBDM_MAX_SERV_ENTRIES_PER_REQ) {
3031 nserv_entries -= IBDM_MAX_SERV_ENTRIES_PER_REQ;
3032 cb_args->cb_srvents_end = (cb_args->cb_srvents_start +
3033 IBDM_MAX_SERV_ENTRIES_PER_REQ - 1);
3034 } else {
3035 cb_args->cb_srvents_end =
3036 (cb_args->cb_srvents_start + nserv_entries - 1);
3037 nserv_entries = 0;
3038 }
3039 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*hdr))
3040 ibdm_fill_srv_attr_mod(hdr, cb_args);
3041 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*hdr))
3042
3043 mutex_enter(&gid_info->gl_mutex);
3044 ioc_info->ioc_serv[srv_start].se_timeout_id = timeout(
3045 ibdm_pkt_timeout_hdlr, cb_args,
3046 IBDM_TIMEOUT_VALUE(ibdm_dft_timeout));
3047 mutex_exit(&gid_info->gl_mutex);
3048
3049 IBTF_DPRINTF_L5("ibdm", "\thandle_ioc_profile:"
3050 "timeout %x, ioc %d srv %d",
3051 ioc_info->ioc_serv[srv_start].se_timeout_id,
3052 ioc_no - 1, srv_start);
3053
3054 if (ibmf_msg_transport(ibmf_hdl, gid_info->gl_qp_hdl, msg,
3055 NULL, ibdm_ibmf_send_cb, cb_args, 0) != IBMF_SUCCESS) {
3056 IBTF_DPRINTF_L2("ibdm",
3057 "\thandle_ioc_profile: msg send failed");
3058 ibdm_ibmf_send_cb(ibmf_hdl, msg, cb_args);
3059 }
3060 (*flag) |= IBDM_IBMF_PKT_REUSED;
3061 first = B_FALSE;
3062 ii++;
3063 }
3064 }
3065
3066
3067 /*
3068 * ibdm_handle_srventry_mad()
3069 */
3070 static void
ibdm_handle_srventry_mad(ibmf_msg_t * msg,ibdm_dp_gidinfo_t * gid_info,int * flag)3071 ibdm_handle_srventry_mad(ibmf_msg_t *msg,
3072 ibdm_dp_gidinfo_t *gid_info, int *flag)
3073 {
3074 uint_t ii, ioc_no, attrmod;
3075 uint_t nentries, start, end;
3076 timeout_id_t timeout_id;
3077 ib_dm_srv_t *srv_ents;
3078 ibdm_ioc_info_t *ioc_info;
3079 ibdm_srvents_info_t *gsrv_ents;
3080
3081 IBTF_DPRINTF_L4("ibdm", "\thandle_srventry_mad:"
3082 " IBMF msg %p gid info %p", msg, gid_info);
3083
3084 srv_ents = IBDM_IN_IBMFMSG2SRVENT(msg);
3085 /*
3086 * Get the start and end index of the service entries
3087 * Upper 16 bits identify the IOC
3088 * Lower 16 bits specify the range of service entries
3089 * LSB specifies (Big endian) end of the range
3090 * MSB specifies (Big endian) start of the range
3091 */
3092 attrmod = IBDM_IN_IBMFMSG_ATTRMOD(msg);
3093 ioc_no = ((attrmod >> 16) & IBDM_16_BIT_MASK);
3094 end = ((attrmod >> 8) & IBDM_8_BIT_MASK);
3095 start = (attrmod & IBDM_8_BIT_MASK);
3096
3097 /* Make sure that IOC index is with the valid range */
3098 if ((ioc_no < 1) |
3099 (ioc_no > gid_info->gl_iou->iou_info.iou_num_ctrl_slots)) {
3100 IBTF_DPRINTF_L2("ibdm", "\thandle_srventry_mad: "
3101 "IOC index Out of range, index %d", ioc_no);
3102 (*flag) |= IBDM_IBMF_PKT_UNEXP_RESP;
3103 return;
3104 }
3105 ioc_info = IBDM_GIDINFO2IOCINFO(gid_info, (ioc_no -1));
3106
3107 /*
3108 * Make sure that the "start" and "end" service indexes are
3109 * with in the valid range
3110 */
3111 nentries = ioc_info->ioc_profile.ioc_service_entries;
3112 if ((start > end) | (start >= nentries) | (end >= nentries)) {
3113 IBTF_DPRINTF_L2("ibdm", "\thandle_srventry_mad: "
3114 "Attr modifier 0x%x, #Serv entries %d", attrmod, nentries);
3115 (*flag) |= IBDM_IBMF_PKT_UNEXP_RESP;
3116 return;
3117 }
3118 gsrv_ents = &ioc_info->ioc_serv[start];
3119 mutex_enter(&gid_info->gl_mutex);
3120 if (gsrv_ents->se_state != IBDM_SE_INVALID) {
3121 IBTF_DPRINTF_L2("ibdm", "\thandle_srventry_mad: "
3122 "already known, ioc %d, srv %d, se_state %x",
3123 ioc_no - 1, start, gsrv_ents->se_state);
3124 mutex_exit(&gid_info->gl_mutex);
3125 (*flag) |= IBDM_IBMF_PKT_DUP_RESP;
3126 return;
3127 }
3128 ioc_info->ioc_serv[start].se_cb_args.cb_req_type = 0;
3129 if (ioc_info->ioc_serv[start].se_timeout_id) {
3130 IBTF_DPRINTF_L2("ibdm",
3131 "\thandle_srventry_mad: ioc %d start %d", ioc_no, start);
3132 timeout_id = ioc_info->ioc_serv[start].se_timeout_id;
3133 ioc_info->ioc_serv[start].se_timeout_id = 0;
3134 mutex_exit(&gid_info->gl_mutex);
3135 IBTF_DPRINTF_L5("ibdm", "handle_srverntry_mad: "
3136 "se_timeout_id = 0x%x", timeout_id);
3137 if (untimeout(timeout_id) == -1) {
3138 IBTF_DPRINTF_L2("ibdm", "handle_srventry_mad: "
3139 "untimeout se_timeout_id failed");
3140 }
3141 mutex_enter(&gid_info->gl_mutex);
3142 }
3143
3144 gsrv_ents->se_state = IBDM_SE_VALID;
3145 mutex_exit(&gid_info->gl_mutex);
3146 for (ii = start; ii <= end; ii++, srv_ents++, gsrv_ents++) {
3147 gsrv_ents->se_attr.srv_id = b2h64(srv_ents->srv_id);
3148 bcopy(srv_ents->srv_name,
3149 gsrv_ents->se_attr.srv_name, IB_DM_MAX_SVC_NAME_LEN);
3150 ibdm_dump_service_entries(&gsrv_ents->se_attr);
3151 }
3152 }
3153
3154
3155 /*
3156 * ibdm_get_diagcode:
3157 * Send request to get IOU/IOC diag code
3158 * Returns IBDM_SUCCESS/IBDM_FAILURE
3159 */
3160 static int
ibdm_get_diagcode(ibdm_dp_gidinfo_t * gid_info,int attr)3161 ibdm_get_diagcode(ibdm_dp_gidinfo_t *gid_info, int attr)
3162 {
3163 ibmf_msg_t *msg;
3164 ib_mad_hdr_t *hdr;
3165 ibdm_ioc_info_t *ioc;
3166 ibdm_timeout_cb_args_t *cb_args;
3167 timeout_id_t *timeout_id;
3168
3169 IBTF_DPRINTF_L4("ibdm", "\tget_diagcode: gid info %p, attr = %d",
3170 gid_info, attr);
3171
3172 if (ibmf_alloc_msg(gid_info->gl_ibmf_hdl, IBMF_ALLOC_SLEEP,
3173 &msg) != IBMF_SUCCESS) {
3174 IBTF_DPRINTF_L4("ibdm", "\tget_diagcode: pkt alloc fail");
3175 return (IBDM_FAILURE);
3176 }
3177
3178 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*msg))
3179 ibdm_alloc_send_buffers(msg);
3180 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*msg))
3181
3182 mutex_enter(&gid_info->gl_mutex);
3183 ibdm_bump_transactionID(gid_info);
3184 mutex_exit(&gid_info->gl_mutex);
3185
3186 msg->im_local_addr.ia_local_lid = gid_info->gl_slid;
3187 msg->im_local_addr.ia_remote_lid = gid_info->gl_dlid;
3188 if (gid_info->gl_redirected == B_TRUE) {
3189 if (gid_info->gl_redirect_dlid != 0) {
3190 msg->im_local_addr.ia_remote_lid =
3191 gid_info->gl_redirect_dlid;
3192 }
3193
3194 msg->im_local_addr.ia_remote_qno = gid_info->gl_redirect_QP;
3195 msg->im_local_addr.ia_p_key = gid_info->gl_redirect_pkey;
3196 msg->im_local_addr.ia_q_key = gid_info->gl_redirect_qkey;
3197 msg->im_local_addr.ia_service_level = gid_info->gl_redirectSL;
3198 } else {
3199 msg->im_local_addr.ia_remote_qno = 1;
3200 msg->im_local_addr.ia_p_key = gid_info->gl_p_key;
3201 msg->im_local_addr.ia_q_key = IB_GSI_QKEY;
3202 msg->im_local_addr.ia_service_level = gid_info->gl_SL;
3203 }
3204
3205 hdr = IBDM_OUT_IBMFMSG_MADHDR(msg);
3206 hdr->BaseVersion = MAD_CLASS_BASE_VERS_1;
3207 hdr->MgmtClass = MAD_MGMT_CLASS_DEV_MGT;
3208 hdr->ClassVersion = IB_DM_CLASS_VERSION_1;
3209 hdr->R_Method = IB_DM_DEVMGT_METHOD_GET;
3210 hdr->Status = 0;
3211 hdr->TransactionID = h2b64(gid_info->gl_transactionID);
3212
3213 hdr->AttributeID = h2b16(IB_DM_ATTR_DIAG_CODE);
3214 hdr->AttributeModifier = h2b32(attr);
3215
3216 if (attr == 0) {
3217 cb_args = &gid_info->gl_iou_cb_args;
3218 gid_info->gl_iou->iou_dc_valid = B_FALSE;
3219 cb_args->cb_ioc_num = 0;
3220 cb_args->cb_req_type = IBDM_REQ_TYPE_IOU_DIAGCODE;
3221 timeout_id = &gid_info->gl_timeout_id;
3222 } else {
3223 ioc = IBDM_GIDINFO2IOCINFO(gid_info, (attr - 1));
3224 ioc->ioc_dc_valid = B_FALSE;
3225 cb_args = &ioc->ioc_dc_cb_args;
3226 cb_args->cb_ioc_num = attr - 1;
3227 cb_args->cb_req_type = IBDM_REQ_TYPE_IOC_DIAGCODE;
3228 timeout_id = &ioc->ioc_dc_timeout_id;
3229 }
3230 cb_args->cb_gid_info = gid_info;
3231 cb_args->cb_retry_count = ibdm_dft_retry_cnt;
3232 cb_args->cb_srvents_start = 0;
3233
3234 mutex_enter(&gid_info->gl_mutex);
3235 *timeout_id = timeout(ibdm_pkt_timeout_hdlr,
3236 cb_args, IBDM_TIMEOUT_VALUE(ibdm_dft_timeout));
3237 mutex_exit(&gid_info->gl_mutex);
3238
3239 IBTF_DPRINTF_L5("ibdm", "\tget_diagcode:"
3240 "timeout %x, ioc %d", *timeout_id, cb_args->cb_ioc_num);
3241
3242 if (ibmf_msg_transport(gid_info->gl_ibmf_hdl, gid_info->gl_qp_hdl,
3243 msg, NULL, ibdm_ibmf_send_cb, cb_args, 0) != IBMF_SUCCESS) {
3244 IBTF_DPRINTF_L2("ibdm", "\tget_diagcode: ibmf send failed");
3245 ibdm_ibmf_send_cb(gid_info->gl_ibmf_hdl, msg, cb_args);
3246 }
3247 return (IBDM_SUCCESS);
3248 }
3249
3250 /*
3251 * ibdm_handle_diagcode:
3252 * Process the DiagCode MAD response and update local DM
3253 * data structure.
3254 */
3255 static void
ibdm_handle_diagcode(ibmf_msg_t * ibmf_msg,ibdm_dp_gidinfo_t * gid_info,int * flag)3256 ibdm_handle_diagcode(ibmf_msg_t *ibmf_msg,
3257 ibdm_dp_gidinfo_t *gid_info, int *flag)
3258 {
3259 uint16_t attrmod, *diagcode;
3260 ibdm_iou_info_t *iou;
3261 ibdm_ioc_info_t *ioc;
3262 timeout_id_t timeout_id;
3263 ibdm_timeout_cb_args_t *cb_args;
3264
3265 diagcode = (uint16_t *)ibmf_msg->im_msgbufs_recv.im_bufs_cl_data;
3266
3267 mutex_enter(&gid_info->gl_mutex);
3268 attrmod = IBDM_IN_IBMFMSG_ATTRMOD(ibmf_msg);
3269 iou = gid_info->gl_iou;
3270 if (attrmod == 0) {
3271 if (iou->iou_dc_valid != B_FALSE) {
3272 (*flag) |= IBDM_IBMF_PKT_DUP_RESP;
3273 IBTF_DPRINTF_L4("ibdm",
3274 "\thandle_diagcode: Duplicate IOU DiagCode");
3275 mutex_exit(&gid_info->gl_mutex);
3276 return;
3277 }
3278 cb_args = &gid_info->gl_iou_cb_args;
3279 cb_args->cb_req_type = 0;
3280 iou->iou_diagcode = b2h16(*diagcode);
3281 iou->iou_dc_valid = B_TRUE;
3282 if (gid_info->gl_timeout_id) {
3283 timeout_id = gid_info->gl_timeout_id;
3284 mutex_exit(&gid_info->gl_mutex);
3285 IBTF_DPRINTF_L5("ibdm", "\thandle_diagcode: "
3286 "gl_timeout_id = 0x%x", timeout_id);
3287 if (untimeout(timeout_id) == -1) {
3288 IBTF_DPRINTF_L2("ibdm", "handle_diagcode: "
3289 "untimeout gl_timeout_id failed");
3290 }
3291 mutex_enter(&gid_info->gl_mutex);
3292 gid_info->gl_timeout_id = 0;
3293 }
3294 } else {
3295 ioc = IBDM_GIDINFO2IOCINFO(gid_info, (attrmod - 1));
3296 if (ioc->ioc_dc_valid != B_FALSE) {
3297 (*flag) |= IBDM_IBMF_PKT_DUP_RESP;
3298 IBTF_DPRINTF_L4("ibdm",
3299 "\thandle_diagcode: Duplicate IOC DiagCode");
3300 mutex_exit(&gid_info->gl_mutex);
3301 return;
3302 }
3303 cb_args = &ioc->ioc_dc_cb_args;
3304 cb_args->cb_req_type = 0;
3305 ioc->ioc_diagcode = b2h16(*diagcode);
3306 ioc->ioc_dc_valid = B_TRUE;
3307 timeout_id = iou->iou_ioc_info[attrmod - 1].ioc_dc_timeout_id;
3308 if (timeout_id) {
3309 iou->iou_ioc_info[attrmod - 1].ioc_dc_timeout_id = 0;
3310 mutex_exit(&gid_info->gl_mutex);
3311 IBTF_DPRINTF_L5("ibdm", "handle_diagcode: "
3312 "timeout_id = 0x%x", timeout_id);
3313 if (untimeout(timeout_id) == -1) {
3314 IBTF_DPRINTF_L2("ibdm", "\thandle_diagcode: "
3315 "untimeout ioc_dc_timeout_id failed");
3316 }
3317 mutex_enter(&gid_info->gl_mutex);
3318 }
3319 }
3320 mutex_exit(&gid_info->gl_mutex);
3321
3322 IBTF_DPRINTF_L4("ibdm", "\thandle_diagcode: DiagCode : 0x%x"
3323 "attrmod : 0x%x", b2h16(*diagcode), attrmod);
3324 }
3325
3326
3327 /*
3328 * ibdm_is_ioc_present()
3329 * Return ibdm_ioc_info_t if IOC guid is found in the global gid list
3330 */
3331 static ibdm_ioc_info_t *
ibdm_is_ioc_present(ib_guid_t ioc_guid,ibdm_dp_gidinfo_t * gid_info,int * flag)3332 ibdm_is_ioc_present(ib_guid_t ioc_guid,
3333 ibdm_dp_gidinfo_t *gid_info, int *flag)
3334 {
3335 int ii;
3336 ibdm_ioc_info_t *ioc;
3337 ibdm_dp_gidinfo_t *head;
3338 ib_dm_io_unitinfo_t *iou;
3339
3340 mutex_enter(&ibdm.ibdm_mutex);
3341 head = ibdm.ibdm_dp_gidlist_head;
3342 while (head) {
3343 mutex_enter(&head->gl_mutex);
3344 if (head->gl_iou == NULL) {
3345 mutex_exit(&head->gl_mutex);
3346 head = head->gl_next;
3347 continue;
3348 }
3349 iou = &head->gl_iou->iou_info;
3350 for (ii = 0; ii < iou->iou_num_ctrl_slots; ii++) {
3351 ioc = IBDM_GIDINFO2IOCINFO(head, ii);
3352 if ((ioc->ioc_state == IBDM_IOC_STATE_PROBE_SUCCESS) &&
3353 (ioc->ioc_profile.ioc_guid == ioc_guid)) {
3354 if (gid_info == head) {
3355 *flag |= IBDM_IBMF_PKT_DUP_RESP;
3356 } else if (ibdm_check_dgid(head->gl_dgid_lo,
3357 head->gl_dgid_hi) != NULL) {
3358 IBTF_DPRINTF_L4("ibdm", "\tis_ioc_"
3359 "present: gid not present");
3360 ibdm_add_to_gl_gid(gid_info, head);
3361 }
3362 mutex_exit(&head->gl_mutex);
3363 mutex_exit(&ibdm.ibdm_mutex);
3364 return (ioc);
3365 }
3366 }
3367 mutex_exit(&head->gl_mutex);
3368 head = head->gl_next;
3369 }
3370 mutex_exit(&ibdm.ibdm_mutex);
3371 return (NULL);
3372 }
3373
3374
3375 /*
3376 * ibdm_ibmf_send_cb()
3377 * IBMF invokes this callback routine after posting the DM MAD to
3378 * the HCA.
3379 */
3380 /*ARGSUSED*/
3381 static void
ibdm_ibmf_send_cb(ibmf_handle_t ibmf_hdl,ibmf_msg_t * ibmf_msg,void * arg)3382 ibdm_ibmf_send_cb(ibmf_handle_t ibmf_hdl, ibmf_msg_t *ibmf_msg, void *arg)
3383 {
3384 ibdm_dump_ibmf_msg(ibmf_msg, 1);
3385 ibdm_free_send_buffers(ibmf_msg);
3386 if (ibmf_free_msg(ibmf_hdl, &ibmf_msg) != IBMF_SUCCESS) {
3387 IBTF_DPRINTF_L4("ibdm",
3388 "\tibmf_send_cb: IBMF free msg failed");
3389 }
3390 }
3391
3392
3393 /*
3394 * ibdm_ibmf_recv_cb()
3395 * Invoked by the IBMF when a response to the one of the DM requests
3396 * is received.
3397 */
3398 /*ARGSUSED*/
3399 static void
ibdm_ibmf_recv_cb(ibmf_handle_t ibmf_hdl,ibmf_msg_t * msg,void * arg)3400 ibdm_ibmf_recv_cb(ibmf_handle_t ibmf_hdl, ibmf_msg_t *msg, void *arg)
3401 {
3402 ibdm_taskq_args_t *taskq_args;
3403
3404 /*
3405 * If the taskq enable is set then dispatch a taskq to process
3406 * the MAD, otherwise just process it on this thread
3407 */
3408 if (ibdm_taskq_enable != IBDM_ENABLE_TASKQ_HANDLING) {
3409 ibdm_process_incoming_mad(ibmf_hdl, msg, arg);
3410 return;
3411 }
3412
3413 /*
3414 * create a taskq and dispatch it to process the incoming MAD
3415 */
3416 taskq_args = kmem_alloc(sizeof (ibdm_taskq_args_t), KM_NOSLEEP);
3417 if (taskq_args == NULL) {
3418 IBTF_DPRINTF_L2("ibdm", "ibmf_recv_cb: kmem_alloc failed for"
3419 "taskq_args");
3420 if (ibmf_free_msg(ibmf_hdl, &msg) != IBMF_SUCCESS) {
3421 IBTF_DPRINTF_L4("ibmf_recv_cb",
3422 "\tibmf_recv_cb: IBMF free msg failed");
3423 }
3424 return;
3425 }
3426 taskq_args->tq_ibmf_handle = ibmf_hdl;
3427 taskq_args->tq_ibmf_msg = msg;
3428 taskq_args->tq_args = arg;
3429
3430 if (taskq_dispatch(system_taskq, ibdm_recv_incoming_mad, taskq_args,
3431 TQ_NOSLEEP) == 0) {
3432 IBTF_DPRINTF_L2("ibdm", "ibmf_recv_cb: taskq_dispatch failed");
3433 if (ibmf_free_msg(ibmf_hdl, &msg) != IBMF_SUCCESS) {
3434 IBTF_DPRINTF_L4("ibmf_recv_cb",
3435 "\tibmf_recv_cb: IBMF free msg failed");
3436 }
3437 kmem_free(taskq_args, sizeof (ibdm_taskq_args_t));
3438 return;
3439 }
3440
3441 /* taskq_args are deleted in ibdm_recv_incoming_mad() */
3442 }
3443
3444
3445 void
ibdm_recv_incoming_mad(void * args)3446 ibdm_recv_incoming_mad(void *args)
3447 {
3448 ibdm_taskq_args_t *taskq_args;
3449
3450 taskq_args = (ibdm_taskq_args_t *)args;
3451
3452 IBTF_DPRINTF_L4("ibdm", "\tibdm_recv_incoming_mad: "
3453 "Processing incoming MAD via taskq");
3454
3455 ibdm_process_incoming_mad(taskq_args->tq_ibmf_handle,
3456 taskq_args->tq_ibmf_msg, taskq_args->tq_args);
3457
3458 kmem_free(taskq_args, sizeof (ibdm_taskq_args_t));
3459 }
3460
3461
3462 /*
3463 * Calls ibdm_process_incoming_mad with all function arguments extracted
3464 * from args
3465 */
3466 /*ARGSUSED*/
3467 static void
ibdm_process_incoming_mad(ibmf_handle_t ibmf_hdl,ibmf_msg_t * msg,void * arg)3468 ibdm_process_incoming_mad(ibmf_handle_t ibmf_hdl, ibmf_msg_t *msg, void *arg)
3469 {
3470 int flag = 0;
3471 int ret;
3472 uint64_t transaction_id;
3473 ib_mad_hdr_t *hdr;
3474 ibdm_dp_gidinfo_t *gid_info = NULL;
3475
3476 IBTF_DPRINTF_L4("ibdm",
3477 "\tprocess_incoming_mad: ibmf hdl %p pkt %p", ibmf_hdl, msg);
3478 ibdm_dump_ibmf_msg(msg, 0);
3479
3480 /*
3481 * IBMF calls this routine for every DM MAD that arrives at this port.
3482 * But we handle only the responses for requests we sent. We drop all
3483 * the DM packets that does not have response bit set in the MAD
3484 * header(this eliminates all the requests sent to this port).
3485 * We handle only DM class version 1 MAD's
3486 */
3487 hdr = IBDM_IN_IBMFMSG_MADHDR(msg);
3488 if (ibdm_verify_mad_status(hdr) != IBDM_SUCCESS) {
3489 if (ibmf_free_msg(ibmf_hdl, &msg) != IBMF_SUCCESS) {
3490 IBTF_DPRINTF_L2("ibdm", "\tprocess_incoming_mad: "
3491 "IBMF free msg failed DM request drop it");
3492 }
3493 return;
3494 }
3495
3496 transaction_id = b2h64(hdr->TransactionID);
3497
3498 mutex_enter(&ibdm.ibdm_mutex);
3499 gid_info = ibdm.ibdm_dp_gidlist_head;
3500 while (gid_info) {
3501 if ((gid_info->gl_transactionID &
3502 IBDM_GID_TRANSACTIONID_MASK) ==
3503 (transaction_id & IBDM_GID_TRANSACTIONID_MASK))
3504 break;
3505 gid_info = gid_info->gl_next;
3506 }
3507 mutex_exit(&ibdm.ibdm_mutex);
3508
3509 if (gid_info == NULL) {
3510 /* Drop the packet */
3511 IBTF_DPRINTF_L2("ibdm", "process_incoming_mad: transaction ID"
3512 " does not match: 0x%llx", transaction_id);
3513 if (ibmf_free_msg(ibmf_hdl, &msg) != IBMF_SUCCESS) {
3514 IBTF_DPRINTF_L2("ibdm", "process_incoming_mad: "
3515 "IBMF free msg failed DM request drop it");
3516 }
3517 return;
3518 }
3519
3520 /* Handle redirection for all the MAD's, except ClassPortInfo */
3521 if (((IBDM_IN_IBMFMSG_STATUS(msg) & MAD_STATUS_REDIRECT_REQUIRED)) &&
3522 (IBDM_IN_IBMFMSG_ATTR(msg) != IB_DM_ATTR_CLASSPORTINFO)) {
3523 ret = ibdm_handle_redirection(msg, gid_info, &flag);
3524 if (ret == IBDM_SUCCESS) {
3525 return;
3526 }
3527 } else {
3528 uint_t gl_state;
3529
3530 mutex_enter(&gid_info->gl_mutex);
3531 gl_state = gid_info->gl_state;
3532 mutex_exit(&gid_info->gl_mutex);
3533
3534 switch (gl_state) {
3535
3536 case IBDM_SET_CLASSPORTINFO:
3537 ibdm_handle_setclassportinfo(
3538 ibmf_hdl, msg, gid_info, &flag);
3539 break;
3540
3541 case IBDM_GET_CLASSPORTINFO:
3542 ibdm_handle_classportinfo(
3543 ibmf_hdl, msg, gid_info, &flag);
3544 break;
3545
3546 case IBDM_GET_IOUNITINFO:
3547 ibdm_handle_iounitinfo(ibmf_hdl, msg, gid_info, &flag);
3548 break;
3549
3550 case IBDM_GET_IOC_DETAILS:
3551 switch (IBDM_IN_IBMFMSG_ATTR(msg)) {
3552
3553 case IB_DM_ATTR_SERVICE_ENTRIES:
3554 ibdm_handle_srventry_mad(msg, gid_info, &flag);
3555 break;
3556
3557 case IB_DM_ATTR_IOC_CTRL_PROFILE:
3558 ibdm_handle_ioc_profile(
3559 ibmf_hdl, msg, gid_info, &flag);
3560 break;
3561
3562 case IB_DM_ATTR_DIAG_CODE:
3563 ibdm_handle_diagcode(msg, gid_info, &flag);
3564 break;
3565
3566 default:
3567 IBTF_DPRINTF_L2("ibdm", "process_incoming_mad: "
3568 "Error state, wrong attribute :-(");
3569 (void) ibmf_free_msg(ibmf_hdl, &msg);
3570 return;
3571 }
3572 break;
3573 default:
3574 IBTF_DPRINTF_L2("ibdm",
3575 "process_incoming_mad: Dropping the packet"
3576 " gl_state %x", gl_state);
3577 if (ibmf_free_msg(ibmf_hdl, &msg) != IBMF_SUCCESS) {
3578 IBTF_DPRINTF_L2("ibdm", "process_incoming_mad: "
3579 "IBMF free msg failed DM request drop it");
3580 }
3581 return;
3582 }
3583 }
3584
3585 if ((flag & IBDM_IBMF_PKT_DUP_RESP) ||
3586 (flag & IBDM_IBMF_PKT_UNEXP_RESP)) {
3587 IBTF_DPRINTF_L2("ibdm",
3588 "\tprocess_incoming_mad:Dup/unexp resp : 0x%x", flag);
3589 if (ibmf_free_msg(ibmf_hdl, &msg) != IBMF_SUCCESS) {
3590 IBTF_DPRINTF_L2("ibdm", "process_incoming_mad: "
3591 "IBMF free msg failed DM request drop it");
3592 }
3593 return;
3594 }
3595
3596 mutex_enter(&gid_info->gl_mutex);
3597 if (gid_info->gl_pending_cmds < 1) {
3598 IBTF_DPRINTF_L2("ibdm",
3599 "\tprocess_incoming_mad: pending commands negative");
3600 }
3601 if (--gid_info->gl_pending_cmds) {
3602 IBTF_DPRINTF_L4("ibdm", "\tprocess_incoming_mad: "
3603 "gid_info %p pending cmds %d",
3604 gid_info, gid_info->gl_pending_cmds);
3605 mutex_exit(&gid_info->gl_mutex);
3606 } else {
3607 uint_t prev_state;
3608 IBTF_DPRINTF_L4("ibdm", "\tprocess_incoming_mad: Probing DONE");
3609 prev_state = gid_info->gl_state;
3610 gid_info->gl_state = IBDM_GID_PROBING_COMPLETE;
3611 if (prev_state == IBDM_SET_CLASSPORTINFO) {
3612 IBTF_DPRINTF_L4("ibdm",
3613 "\tprocess_incoming_mad: "
3614 "Setclassportinfo for Cisco FC GW is done.");
3615 gid_info->gl_flag &= ~IBDM_CISCO_PROBE;
3616 gid_info->gl_flag |= IBDM_CISCO_PROBE_DONE;
3617 mutex_exit(&gid_info->gl_mutex);
3618 cv_broadcast(&gid_info->gl_probe_cv);
3619 } else {
3620 mutex_exit(&gid_info->gl_mutex);
3621 ibdm_notify_newgid_iocs(gid_info);
3622 mutex_enter(&ibdm.ibdm_mutex);
3623 if (--ibdm.ibdm_ngid_probes_in_progress == 0) {
3624 IBTF_DPRINTF_L4("ibdm",
3625 "\tprocess_incoming_mad: Wakeup");
3626 ibdm.ibdm_busy &= ~IBDM_PROBE_IN_PROGRESS;
3627 cv_broadcast(&ibdm.ibdm_probe_cv);
3628 }
3629 mutex_exit(&ibdm.ibdm_mutex);
3630 }
3631 }
3632
3633 /*
3634 * Do not deallocate the IBMF packet if atleast one request
3635 * is posted. IBMF packet is reused.
3636 */
3637 if (!(flag & IBDM_IBMF_PKT_REUSED)) {
3638 if (ibmf_free_msg(ibmf_hdl, &msg) != IBMF_SUCCESS) {
3639 IBTF_DPRINTF_L2("ibdm", "\tprocess_incoming_mad: "
3640 "IBMF free msg failed DM request drop it");
3641 }
3642 }
3643 }
3644
3645
3646 /*
3647 * ibdm_verify_mad_status()
3648 * Verifies the MAD status
3649 * Returns IBDM_SUCCESS if status is correct
3650 * Returns IBDM_FAILURE for bogus MAD status
3651 */
3652 static int
ibdm_verify_mad_status(ib_mad_hdr_t * hdr)3653 ibdm_verify_mad_status(ib_mad_hdr_t *hdr)
3654 {
3655 int ret = 0;
3656
3657 if ((hdr->R_Method != IB_DM_DEVMGT_METHOD_GET_RESP) ||
3658 (hdr->ClassVersion != IB_DM_CLASS_VERSION_1)) {
3659 return (IBDM_FAILURE);
3660 }
3661
3662 if (b2h16(hdr->Status) == 0)
3663 ret = IBDM_SUCCESS;
3664 else if ((b2h16(hdr->Status) & 0x1f) == MAD_STATUS_REDIRECT_REQUIRED)
3665 ret = IBDM_SUCCESS;
3666 else {
3667 IBTF_DPRINTF_L2("ibdm",
3668 "\tverify_mad_status: Status : 0x%x", b2h16(hdr->Status));
3669 ret = IBDM_FAILURE;
3670 }
3671 return (ret);
3672 }
3673
3674
3675
3676 /*
3677 * ibdm_handle_redirection()
3678 * Returns IBDM_SUCCESS/IBDM_FAILURE
3679 */
3680 static int
ibdm_handle_redirection(ibmf_msg_t * msg,ibdm_dp_gidinfo_t * gid_info,int * flag)3681 ibdm_handle_redirection(ibmf_msg_t *msg,
3682 ibdm_dp_gidinfo_t *gid_info, int *flag)
3683 {
3684 int attrmod, ioc_no, start;
3685 void *data;
3686 timeout_id_t *timeout_id;
3687 ib_mad_hdr_t *hdr;
3688 ibdm_ioc_info_t *ioc = NULL;
3689 ibdm_timeout_cb_args_t *cb_args;
3690 ib_mad_classportinfo_t *cpi;
3691
3692 IBTF_DPRINTF_L4("ibdm", "\thandle_redirection: Enter");
3693 mutex_enter(&gid_info->gl_mutex);
3694 switch (gid_info->gl_state) {
3695 case IBDM_GET_IOUNITINFO:
3696 cb_args = &gid_info->gl_iou_cb_args;
3697 timeout_id = &gid_info->gl_timeout_id;
3698 break;
3699
3700 case IBDM_GET_IOC_DETAILS:
3701 attrmod = IBDM_IN_IBMFMSG_ATTRMOD(msg);
3702 switch (IBDM_IN_IBMFMSG_ATTR(msg)) {
3703
3704 case IB_DM_ATTR_DIAG_CODE:
3705 if (attrmod == 0) {
3706 cb_args = &gid_info->gl_iou_cb_args;
3707 timeout_id = &gid_info->gl_timeout_id;
3708 break;
3709 }
3710 if (IBDM_IS_IOC_NUM_INVALID(attrmod, gid_info)) {
3711 IBTF_DPRINTF_L2("ibdm", "\thandle_redirction:"
3712 "IOC# Out of range %d", attrmod);
3713 (*flag) |= IBDM_IBMF_PKT_UNEXP_RESP;
3714 mutex_exit(&gid_info->gl_mutex);
3715 return (IBDM_FAILURE);
3716 }
3717 ioc = IBDM_GIDINFO2IOCINFO(gid_info, (attrmod -1));
3718 cb_args = &ioc->ioc_dc_cb_args;
3719 timeout_id = &ioc->ioc_dc_timeout_id;
3720 break;
3721
3722 case IB_DM_ATTR_IOC_CTRL_PROFILE:
3723 if (IBDM_IS_IOC_NUM_INVALID(attrmod, gid_info)) {
3724 IBTF_DPRINTF_L2("ibdm", "\thandle_redirction:"
3725 "IOC# Out of range %d", attrmod);
3726 (*flag) |= IBDM_IBMF_PKT_UNEXP_RESP;
3727 mutex_exit(&gid_info->gl_mutex);
3728 return (IBDM_FAILURE);
3729 }
3730 ioc = IBDM_GIDINFO2IOCINFO(gid_info, (attrmod -1));
3731 cb_args = &ioc->ioc_cb_args;
3732 timeout_id = &ioc->ioc_timeout_id;
3733 break;
3734
3735 case IB_DM_ATTR_SERVICE_ENTRIES:
3736 ioc_no = ((attrmod >> 16) & IBDM_16_BIT_MASK);
3737 if (IBDM_IS_IOC_NUM_INVALID(ioc_no, gid_info)) {
3738 IBTF_DPRINTF_L2("ibdm", "\thandle_redirction:"
3739 "IOC# Out of range %d", ioc_no);
3740 (*flag) |= IBDM_IBMF_PKT_UNEXP_RESP;
3741 mutex_exit(&gid_info->gl_mutex);
3742 return (IBDM_FAILURE);
3743 }
3744 start = (attrmod & IBDM_8_BIT_MASK);
3745 ioc = IBDM_GIDINFO2IOCINFO(gid_info, (ioc_no -1));
3746 if (start > ioc->ioc_profile.ioc_service_entries) {
3747 IBTF_DPRINTF_L2("ibdm", "\thandle_redirction:"
3748 " SE index Out of range %d", start);
3749 (*flag) |= IBDM_IBMF_PKT_UNEXP_RESP;
3750 mutex_exit(&gid_info->gl_mutex);
3751 return (IBDM_FAILURE);
3752 }
3753 cb_args = &ioc->ioc_serv[start].se_cb_args;
3754 timeout_id = &ioc->ioc_serv[start].se_timeout_id;
3755 break;
3756
3757 default:
3758 /* ERROR State */
3759 IBTF_DPRINTF_L2("ibdm",
3760 "\thandle_redirection: wrong attribute :-(");
3761 (*flag) |= IBDM_IBMF_PKT_UNEXP_RESP;
3762 mutex_exit(&gid_info->gl_mutex);
3763 return (IBDM_FAILURE);
3764 }
3765 break;
3766 default:
3767 /* ERROR State */
3768 IBTF_DPRINTF_L2("ibdm",
3769 "\thandle_redirection: Error state :-(");
3770 (*flag) |= IBDM_IBMF_PKT_UNEXP_RESP;
3771 mutex_exit(&gid_info->gl_mutex);
3772 return (IBDM_FAILURE);
3773 }
3774 if ((*timeout_id) != 0) {
3775 mutex_exit(&gid_info->gl_mutex);
3776 if (untimeout(*timeout_id) == -1) {
3777 IBTF_DPRINTF_L2("ibdm", "\thandle_redirection: "
3778 "untimeout failed %x", *timeout_id);
3779 } else {
3780 IBTF_DPRINTF_L5("ibdm",
3781 "\thandle_redirection: timeout %x", *timeout_id);
3782 }
3783 mutex_enter(&gid_info->gl_mutex);
3784 *timeout_id = 0;
3785 }
3786
3787 data = msg->im_msgbufs_recv.im_bufs_cl_data;
3788 cpi = (ib_mad_classportinfo_t *)data;
3789
3790 gid_info->gl_resp_timeout =
3791 (b2h32(cpi->RespTimeValue) & 0x1F);
3792
3793 gid_info->gl_redirected = B_TRUE;
3794 gid_info->gl_redirect_dlid = b2h16(cpi->RedirectLID);
3795 gid_info->gl_redirect_QP = (b2h32(cpi->RedirectQP) & 0xffffff);
3796 gid_info->gl_redirect_pkey = b2h16(cpi->RedirectP_Key);
3797 gid_info->gl_redirect_qkey = b2h32(cpi->RedirectQ_Key);
3798 gid_info->gl_redirectGID_hi = b2h64(cpi->RedirectGID_hi);
3799 gid_info->gl_redirectGID_lo = b2h64(cpi->RedirectGID_lo);
3800 gid_info->gl_redirectSL = cpi->RedirectSL;
3801
3802 if (gid_info->gl_redirect_dlid != 0) {
3803 msg->im_local_addr.ia_remote_lid =
3804 gid_info->gl_redirect_dlid;
3805 }
3806 ibdm_bump_transactionID(gid_info);
3807 mutex_exit(&gid_info->gl_mutex);
3808
3809 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*msg, *hdr))
3810 ibdm_alloc_send_buffers(msg);
3811
3812 hdr = IBDM_OUT_IBMFMSG_MADHDR(msg);
3813 hdr->BaseVersion = MAD_CLASS_BASE_VERS_1;
3814 hdr->MgmtClass = MAD_MGMT_CLASS_DEV_MGT;
3815 hdr->ClassVersion = IB_DM_CLASS_VERSION_1;
3816 hdr->R_Method = IB_DM_DEVMGT_METHOD_GET;
3817 hdr->Status = 0;
3818 hdr->TransactionID = h2b64(gid_info->gl_transactionID);
3819 hdr->AttributeID =
3820 msg->im_msgbufs_recv.im_bufs_mad_hdr->AttributeID;
3821 hdr->AttributeModifier =
3822 msg->im_msgbufs_recv.im_bufs_mad_hdr->AttributeModifier;
3823 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*msg, *hdr))
3824
3825 msg->im_local_addr.ia_remote_qno = gid_info->gl_redirect_QP;
3826 msg->im_local_addr.ia_p_key = gid_info->gl_redirect_pkey;
3827 msg->im_local_addr.ia_q_key = gid_info->gl_redirect_qkey;
3828 msg->im_local_addr.ia_service_level = gid_info->gl_redirectSL;
3829
3830 mutex_enter(&gid_info->gl_mutex);
3831 *timeout_id = timeout(ibdm_pkt_timeout_hdlr,
3832 cb_args, IBDM_TIMEOUT_VALUE(ibdm_dft_timeout));
3833 mutex_exit(&gid_info->gl_mutex);
3834
3835 IBTF_DPRINTF_L5("ibdm", "\thandle_redirect:"
3836 "timeout %x", *timeout_id);
3837
3838 if (ibmf_msg_transport(gid_info->gl_ibmf_hdl, gid_info->gl_qp_hdl,
3839 msg, NULL, ibdm_ibmf_send_cb, cb_args, 0) != IBMF_SUCCESS) {
3840 IBTF_DPRINTF_L4("ibdm", "\thandle_redirection:"
3841 "message transport failed");
3842 ibdm_ibmf_send_cb(gid_info->gl_ibmf_hdl, msg, cb_args);
3843 }
3844 (*flag) |= IBDM_IBMF_PKT_REUSED;
3845 IBTF_DPRINTF_L4("ibdm", "\thandle_redirection: Exit");
3846 return (IBDM_SUCCESS);
3847 }
3848
3849
3850 /*
3851 * ibdm_pkt_timeout_hdlr
3852 * This timeout handler is registed for every IBMF packet that is
3853 * sent through the IBMF. It gets called when no response is received
3854 * within the specified time for the packet. No retries for the failed
3855 * commands currently. Drops the failed IBMF packet and update the
3856 * pending list commands.
3857 */
3858 static void
ibdm_pkt_timeout_hdlr(void * arg)3859 ibdm_pkt_timeout_hdlr(void *arg)
3860 {
3861 ibdm_iou_info_t *iou;
3862 ibdm_ioc_info_t *ioc;
3863 ibdm_timeout_cb_args_t *cb_args = arg;
3864 ibdm_dp_gidinfo_t *gid_info;
3865 int srv_ent;
3866 uint_t new_gl_state;
3867
3868 IBTF_DPRINTF_L2("ibdm", "\tpkt_timeout_hdlr: gid_info: %p "
3869 "rtype 0x%x iocidx 0x%x srvidx %d", cb_args->cb_gid_info,
3870 cb_args->cb_req_type, cb_args->cb_ioc_num,
3871 cb_args->cb_srvents_start);
3872
3873 gid_info = cb_args->cb_gid_info;
3874 mutex_enter(&gid_info->gl_mutex);
3875
3876 if ((gid_info->gl_state == IBDM_GID_PROBING_COMPLETE) ||
3877 (cb_args->cb_req_type == 0)) {
3878
3879 IBTF_DPRINTF_L2("ibdm", "\tpkt_timeout_hdlr: req completed"
3880 "rtype 0x%x iocidx 0x%x srvidx %d", cb_args->cb_req_type,
3881 cb_args->cb_ioc_num, cb_args->cb_srvents_start);
3882
3883 if (gid_info->gl_timeout_id)
3884 gid_info->gl_timeout_id = 0;
3885 mutex_exit(&gid_info->gl_mutex);
3886 return;
3887 }
3888 if (cb_args->cb_retry_count) {
3889 cb_args->cb_retry_count--;
3890 /*
3891 * A new timeout_id is set inside ibdm_retry_command().
3892 * When the function returns an error, the timeout_id
3893 * is reset (to zero) in the switch statement below.
3894 */
3895 if (ibdm_retry_command(cb_args) == IBDM_SUCCESS) {
3896 mutex_exit(&gid_info->gl_mutex);
3897 return;
3898 }
3899 cb_args->cb_retry_count = 0;
3900 }
3901
3902 IBTF_DPRINTF_L2("ibdm", "\tpkt_timeout_hdlr: command failed: gid %p"
3903 " rtype 0x%x iocidx 0x%x srvidx %d", cb_args->cb_gid_info,
3904 cb_args->cb_req_type, cb_args->cb_ioc_num,
3905 cb_args->cb_srvents_start);
3906
3907 switch (cb_args->cb_req_type) {
3908
3909 case IBDM_REQ_TYPE_CLASSPORTINFO:
3910 case IBDM_REQ_TYPE_IOUINFO:
3911 new_gl_state = IBDM_GID_PROBING_FAILED;
3912 if (gid_info->gl_timeout_id)
3913 gid_info->gl_timeout_id = 0;
3914 break;
3915
3916 case IBDM_REQ_TYPE_IOCINFO:
3917 new_gl_state = IBDM_GID_PROBING_COMPLETE;
3918 iou = gid_info->gl_iou;
3919 ioc = &iou->iou_ioc_info[cb_args->cb_ioc_num];
3920 ioc->ioc_state = IBDM_IOC_STATE_PROBE_FAILED;
3921 if (ioc->ioc_timeout_id)
3922 ioc->ioc_timeout_id = 0;
3923 break;
3924
3925 case IBDM_REQ_TYPE_SRVENTS:
3926 new_gl_state = IBDM_GID_PROBING_COMPLETE;
3927 iou = gid_info->gl_iou;
3928 ioc = &iou->iou_ioc_info[cb_args->cb_ioc_num];
3929 ioc->ioc_state = IBDM_IOC_STATE_PROBE_FAILED;
3930 srv_ent = cb_args->cb_srvents_start;
3931 if (ioc->ioc_serv[srv_ent].se_timeout_id)
3932 ioc->ioc_serv[srv_ent].se_timeout_id = 0;
3933 break;
3934
3935 case IBDM_REQ_TYPE_IOU_DIAGCODE:
3936 new_gl_state = IBDM_GID_PROBING_COMPLETE;
3937 iou = gid_info->gl_iou;
3938 iou->iou_dc_valid = B_FALSE;
3939 if (gid_info->gl_timeout_id)
3940 gid_info->gl_timeout_id = 0;
3941 break;
3942
3943 case IBDM_REQ_TYPE_IOC_DIAGCODE:
3944 new_gl_state = IBDM_GID_PROBING_COMPLETE;
3945 iou = gid_info->gl_iou;
3946 ioc = &iou->iou_ioc_info[cb_args->cb_ioc_num];
3947 ioc->ioc_dc_valid = B_FALSE;
3948 if (ioc->ioc_dc_timeout_id)
3949 ioc->ioc_dc_timeout_id = 0;
3950 break;
3951
3952 default: /* ERROR State */
3953 new_gl_state = IBDM_GID_PROBING_FAILED;
3954 if (gid_info->gl_timeout_id)
3955 gid_info->gl_timeout_id = 0;
3956 IBTF_DPRINTF_L2("ibdm",
3957 "\tpkt_timeout_hdlr: wrong request type.");
3958 break;
3959 }
3960
3961 --gid_info->gl_pending_cmds; /* decrease the counter */
3962
3963 if (gid_info->gl_pending_cmds == 0) {
3964 gid_info->gl_state = new_gl_state;
3965 mutex_exit(&gid_info->gl_mutex);
3966 /*
3967 * Delete this gid_info if the gid probe fails.
3968 */
3969 if (new_gl_state == IBDM_GID_PROBING_FAILED) {
3970 ibdm_delete_glhca_list(gid_info);
3971 }
3972 ibdm_notify_newgid_iocs(gid_info);
3973 mutex_enter(&ibdm.ibdm_mutex);
3974 if (--ibdm.ibdm_ngid_probes_in_progress == 0) {
3975 IBTF_DPRINTF_L4("ibdm", "\tpkt_timeout_hdlr: Wakeup");
3976 ibdm.ibdm_busy &= ~IBDM_PROBE_IN_PROGRESS;
3977 cv_broadcast(&ibdm.ibdm_probe_cv);
3978 }
3979 mutex_exit(&ibdm.ibdm_mutex);
3980 } else {
3981 /*
3982 * Reset gl_pending_cmd if the extra timeout happens since
3983 * gl_pending_cmd becomes negative as a result.
3984 */
3985 if (gid_info->gl_pending_cmds < 0) {
3986 gid_info->gl_pending_cmds = 0;
3987 IBTF_DPRINTF_L2("ibdm",
3988 "\tpkt_timeout_hdlr: extra timeout request."
3989 " reset gl_pending_cmds");
3990 }
3991 mutex_exit(&gid_info->gl_mutex);
3992 /*
3993 * Delete this gid_info if the gid probe fails.
3994 */
3995 if (new_gl_state == IBDM_GID_PROBING_FAILED) {
3996 ibdm_delete_glhca_list(gid_info);
3997 }
3998 }
3999 }
4000
4001
4002 /*
4003 * ibdm_retry_command()
4004 * Retries the failed command.
4005 * Returns IBDM_FAILURE/IBDM_SUCCESS
4006 */
4007 static int
ibdm_retry_command(ibdm_timeout_cb_args_t * cb_args)4008 ibdm_retry_command(ibdm_timeout_cb_args_t *cb_args)
4009 {
4010 int ret;
4011 ibmf_msg_t *msg;
4012 ib_mad_hdr_t *hdr;
4013 ibdm_dp_gidinfo_t *gid_info = cb_args->cb_gid_info;
4014 timeout_id_t *timeout_id;
4015 ibdm_ioc_info_t *ioc;
4016 int ioc_no;
4017 ASSERT(MUTEX_HELD(&gid_info->gl_mutex));
4018
4019 IBTF_DPRINTF_L2("ibdm", "\tretry_command: gid_info: %p "
4020 "rtype 0x%x iocidx 0x%x srvidx %d", cb_args->cb_gid_info,
4021 cb_args->cb_req_type, cb_args->cb_ioc_num,
4022 cb_args->cb_srvents_start);
4023
4024 ret = ibmf_alloc_msg(gid_info->gl_ibmf_hdl, IBMF_ALLOC_NOSLEEP, &msg);
4025
4026
4027 /*
4028 * Reset the gid if alloc_msg failed with BAD_HANDLE
4029 * ibdm_reset_gidinfo reinits the gid_info
4030 */
4031 if (ret == IBMF_BAD_HANDLE) {
4032 IBTF_DPRINTF_L3(ibdm_string, "\tretry_command: gid %p hdl bad",
4033 gid_info);
4034
4035 mutex_exit(&gid_info->gl_mutex);
4036 ibdm_reset_gidinfo(gid_info);
4037 mutex_enter(&gid_info->gl_mutex);
4038
4039 /* Retry alloc */
4040 ret = ibmf_alloc_msg(gid_info->gl_ibmf_hdl, IBMF_ALLOC_NOSLEEP,
4041 &msg);
4042 }
4043
4044 if (ret != IBDM_SUCCESS) {
4045 IBTF_DPRINTF_L2("ibdm", "\tretry_command: alloc failed: %p "
4046 "rtype 0x%x iocidx 0x%x srvidx %d", cb_args->cb_gid_info,
4047 cb_args->cb_req_type, cb_args->cb_ioc_num,
4048 cb_args->cb_srvents_start);
4049 return (IBDM_FAILURE);
4050 }
4051
4052 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*msg))
4053 ibdm_alloc_send_buffers(msg);
4054 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*msg))
4055
4056 ibdm_bump_transactionID(gid_info);
4057
4058 msg->im_local_addr.ia_local_lid = gid_info->gl_slid;
4059 msg->im_local_addr.ia_remote_lid = gid_info->gl_dlid;
4060 if (gid_info->gl_redirected == B_TRUE) {
4061 if (gid_info->gl_redirect_dlid != 0) {
4062 msg->im_local_addr.ia_remote_lid =
4063 gid_info->gl_redirect_dlid;
4064 }
4065 msg->im_local_addr.ia_remote_qno = gid_info->gl_redirect_QP;
4066 msg->im_local_addr.ia_p_key = gid_info->gl_redirect_pkey;
4067 msg->im_local_addr.ia_q_key = gid_info->gl_redirect_qkey;
4068 msg->im_local_addr.ia_service_level = gid_info->gl_redirectSL;
4069 } else {
4070 msg->im_local_addr.ia_remote_qno = 1;
4071 msg->im_local_addr.ia_p_key = gid_info->gl_p_key;
4072 msg->im_local_addr.ia_q_key = IB_GSI_QKEY;
4073 msg->im_local_addr.ia_service_level = gid_info->gl_SL;
4074 }
4075 hdr = IBDM_OUT_IBMFMSG_MADHDR(msg);
4076 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*hdr))
4077 hdr->BaseVersion = MAD_CLASS_BASE_VERS_1;
4078 hdr->MgmtClass = MAD_MGMT_CLASS_DEV_MGT;
4079 hdr->ClassVersion = IB_DM_CLASS_VERSION_1;
4080 hdr->R_Method = IB_DM_DEVMGT_METHOD_GET;
4081 hdr->Status = 0;
4082 hdr->TransactionID = h2b64(gid_info->gl_transactionID);
4083
4084 switch (cb_args->cb_req_type) {
4085 case IBDM_REQ_TYPE_CLASSPORTINFO:
4086 hdr->AttributeID = h2b16(IB_DM_ATTR_CLASSPORTINFO);
4087 hdr->AttributeModifier = 0;
4088 timeout_id = &gid_info->gl_timeout_id;
4089 break;
4090 case IBDM_REQ_TYPE_IOUINFO:
4091 hdr->AttributeID = h2b16(IB_DM_ATTR_IO_UNITINFO);
4092 hdr->AttributeModifier = 0;
4093 timeout_id = &gid_info->gl_timeout_id;
4094 break;
4095 case IBDM_REQ_TYPE_IOCINFO:
4096 hdr->AttributeID = h2b16(IB_DM_ATTR_IOC_CTRL_PROFILE);
4097 hdr->AttributeModifier = h2b32(cb_args->cb_ioc_num + 1);
4098 ioc = IBDM_GIDINFO2IOCINFO(gid_info, cb_args->cb_ioc_num);
4099 timeout_id = &ioc->ioc_timeout_id;
4100 break;
4101 case IBDM_REQ_TYPE_SRVENTS:
4102 hdr->AttributeID = h2b16(IB_DM_ATTR_SERVICE_ENTRIES);
4103 ibdm_fill_srv_attr_mod(hdr, cb_args);
4104 ioc = IBDM_GIDINFO2IOCINFO(gid_info, cb_args->cb_ioc_num);
4105 timeout_id =
4106 &ioc->ioc_serv[cb_args->cb_srvents_start].se_timeout_id;
4107 break;
4108 case IBDM_REQ_TYPE_IOU_DIAGCODE:
4109 hdr->AttributeID = h2b16(IB_DM_ATTR_DIAG_CODE);
4110 hdr->AttributeModifier = 0;
4111 timeout_id = &gid_info->gl_timeout_id;
4112 break;
4113 case IBDM_REQ_TYPE_IOC_DIAGCODE:
4114 hdr->AttributeID = h2b16(IB_DM_ATTR_DIAG_CODE);
4115 hdr->AttributeModifier = h2b32(cb_args->cb_ioc_num + 1);
4116 ioc_no = cb_args->cb_ioc_num;
4117 ioc = &gid_info->gl_iou->iou_ioc_info[ioc_no];
4118 timeout_id = &ioc->ioc_dc_timeout_id;
4119 break;
4120 }
4121 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*hdr))
4122
4123 *timeout_id = timeout(ibdm_pkt_timeout_hdlr,
4124 cb_args, IBDM_TIMEOUT_VALUE(ibdm_dft_timeout));
4125
4126 mutex_exit(&gid_info->gl_mutex);
4127
4128 IBTF_DPRINTF_L5("ibdm", "\tretry_command: %p,%x,%d,%d:"
4129 "timeout %x", cb_args->cb_req_type, cb_args->cb_ioc_num,
4130 cb_args->cb_srvents_start, *timeout_id);
4131
4132 if (ibmf_msg_transport(gid_info->gl_ibmf_hdl,
4133 gid_info->gl_qp_hdl, msg, NULL, ibdm_ibmf_send_cb,
4134 cb_args, 0) != IBMF_SUCCESS) {
4135 IBTF_DPRINTF_L2("ibdm", "\tretry_command: send failed: %p "
4136 "rtype 0x%x iocidx 0x%x srvidx %d", cb_args->cb_gid_info,
4137 cb_args->cb_req_type, cb_args->cb_ioc_num,
4138 cb_args->cb_srvents_start);
4139 ibdm_ibmf_send_cb(gid_info->gl_ibmf_hdl, msg, cb_args);
4140 }
4141 mutex_enter(&gid_info->gl_mutex);
4142 return (IBDM_SUCCESS);
4143 }
4144
4145
4146 /*
4147 * ibdm_update_ioc_port_gidlist()
4148 */
4149 static void
ibdm_update_ioc_port_gidlist(ibdm_ioc_info_t * dest,ibdm_dp_gidinfo_t * gid_info)4150 ibdm_update_ioc_port_gidlist(ibdm_ioc_info_t *dest,
4151 ibdm_dp_gidinfo_t *gid_info)
4152 {
4153 int ii, ngid_ents;
4154 ibdm_gid_t *tmp;
4155 ibdm_hca_list_t *gid_hca_head, *temp;
4156 ibdm_hca_list_t *ioc_head = NULL;
4157 ASSERT(MUTEX_HELD(&gid_info->gl_mutex));
4158
4159 IBTF_DPRINTF_L5("ibdm", "\tupdate_ioc_port_gidlist: Enter");
4160
4161 ngid_ents = gid_info->gl_ngids;
4162 dest->ioc_nportgids = ngid_ents;
4163 dest->ioc_gid_list = kmem_zalloc(sizeof (ibdm_gid_t) *
4164 ngid_ents, KM_SLEEP);
4165 tmp = gid_info->gl_gid;
4166 for (ii = 0; (ii < ngid_ents) && (tmp); ii++) {
4167 dest->ioc_gid_list[ii].gid_dgid_hi = tmp->gid_dgid_hi;
4168 dest->ioc_gid_list[ii].gid_dgid_lo = tmp->gid_dgid_lo;
4169 tmp = tmp->gid_next;
4170 }
4171
4172 gid_hca_head = gid_info->gl_hca_list;
4173 while (gid_hca_head) {
4174 temp = ibdm_dup_hca_attr(gid_hca_head);
4175 temp->hl_next = ioc_head;
4176 ioc_head = temp;
4177 gid_hca_head = gid_hca_head->hl_next;
4178 }
4179 dest->ioc_hca_list = ioc_head;
4180 }
4181
4182
4183 /*
4184 * ibdm_alloc_send_buffers()
4185 * Allocates memory for the IBMF send buffer to send and/or receive
4186 * the Device Management MAD packet.
4187 */
4188 static void
ibdm_alloc_send_buffers(ibmf_msg_t * msgp)4189 ibdm_alloc_send_buffers(ibmf_msg_t *msgp)
4190 {
4191 msgp->im_msgbufs_send.im_bufs_mad_hdr =
4192 kmem_zalloc(IBDM_MAD_SIZE, KM_SLEEP);
4193
4194 msgp->im_msgbufs_send.im_bufs_cl_hdr = (uchar_t *)
4195 msgp->im_msgbufs_send.im_bufs_mad_hdr + sizeof (ib_mad_hdr_t);
4196 msgp->im_msgbufs_send.im_bufs_cl_hdr_len = IBDM_DM_MAD_HDR_SZ;
4197
4198 msgp->im_msgbufs_send.im_bufs_cl_data =
4199 ((char *)msgp->im_msgbufs_send.im_bufs_cl_hdr + IBDM_DM_MAD_HDR_SZ);
4200 msgp->im_msgbufs_send.im_bufs_cl_data_len =
4201 IBDM_MAD_SIZE - sizeof (ib_mad_hdr_t) - IBDM_DM_MAD_HDR_SZ;
4202 }
4203
4204
4205 /*
4206 * ibdm_alloc_send_buffers()
4207 * De-allocates memory for the IBMF send buffer
4208 */
4209 static void
ibdm_free_send_buffers(ibmf_msg_t * msgp)4210 ibdm_free_send_buffers(ibmf_msg_t *msgp)
4211 {
4212 if (msgp->im_msgbufs_send.im_bufs_mad_hdr != NULL)
4213 kmem_free(msgp->im_msgbufs_send.im_bufs_mad_hdr, IBDM_MAD_SIZE);
4214 }
4215
4216 /*
4217 * ibdm_probe_ioc()
4218 * 1. Gets the node records for the port GUID. This detects all the port
4219 * to the IOU.
4220 * 2. Selectively probes all the IOC, given it's node GUID
4221 * 3. In case of reprobe, only the IOC to be reprobed is send the IOC
4222 * Controller Profile asynchronously
4223 */
4224 /*ARGSUSED*/
4225 static void
ibdm_probe_ioc(ib_guid_t nodeguid,ib_guid_t ioc_guid,int reprobe_flag)4226 ibdm_probe_ioc(ib_guid_t nodeguid, ib_guid_t ioc_guid, int reprobe_flag)
4227 {
4228 int ii, nrecords;
4229 size_t nr_len = 0, pi_len = 0;
4230 ib_gid_t sgid, dgid;
4231 ibdm_hca_list_t *hca_list = NULL;
4232 sa_node_record_t *nr, *tmp;
4233 ibdm_port_attr_t *port = NULL;
4234 ibdm_dp_gidinfo_t *reprobe_gid, *new_gid, *node_gid;
4235 ibdm_dp_gidinfo_t *temp_gidinfo;
4236 ibdm_gid_t *temp_gid;
4237 sa_portinfo_record_t *pi;
4238
4239 IBTF_DPRINTF_L4("ibdm", "\tprobe_ioc(%llx, %llx, %x): Begin",
4240 nodeguid, ioc_guid, reprobe_flag);
4241
4242 /* Rescan the GID list for any removed GIDs for reprobe */
4243 if (reprobe_flag)
4244 ibdm_rescan_gidlist(&ioc_guid);
4245
4246 mutex_enter(&ibdm.ibdm_hl_mutex);
4247 for (ibdm_get_next_port(&hca_list, &port, 1); port;
4248 ibdm_get_next_port(&hca_list, &port, 1)) {
4249 reprobe_gid = new_gid = node_gid = NULL;
4250
4251 nr = ibdm_get_node_records(port->pa_sa_hdl, &nr_len, nodeguid);
4252 if (nr == NULL) {
4253 IBTF_DPRINTF_L4("ibdm", "\tprobe_ioc: no records");
4254 continue;
4255 }
4256 nrecords = (nr_len / sizeof (sa_node_record_t));
4257 for (tmp = nr, ii = 0; (ii < nrecords); ii++, tmp++) {
4258 if ((pi = ibdm_get_portinfo(
4259 port->pa_sa_hdl, &pi_len, tmp->LID)) == NULL) {
4260 IBTF_DPRINTF_L4("ibdm",
4261 "\tibdm_get_portinfo: no portinfo recs");
4262 continue;
4263 }
4264
4265 /*
4266 * If Device Management is not supported on
4267 * this port, skip the rest.
4268 */
4269 if (!(pi->PortInfo.CapabilityMask &
4270 SM_CAP_MASK_IS_DM_SUPPD)) {
4271 kmem_free(pi, pi_len);
4272 continue;
4273 }
4274
4275 /*
4276 * For reprobes: Check if GID, already in
4277 * the list. If so, set the state to SKIPPED
4278 */
4279 if (((temp_gidinfo = ibdm_find_gid(nodeguid,
4280 tmp->NodeInfo.PortGUID)) != NULL) &&
4281 temp_gidinfo->gl_state ==
4282 IBDM_GID_PROBING_COMPLETE) {
4283 ASSERT(reprobe_gid == NULL);
4284 ibdm_addto_glhcalist(temp_gidinfo,
4285 hca_list);
4286 reprobe_gid = temp_gidinfo;
4287 kmem_free(pi, pi_len);
4288 continue;
4289 } else if (temp_gidinfo != NULL) {
4290 kmem_free(pi, pi_len);
4291 ibdm_addto_glhcalist(temp_gidinfo,
4292 hca_list);
4293 continue;
4294 }
4295
4296 IBTF_DPRINTF_L4("ibdm", "\tprobe_ioc : "
4297 "create_gid : prefix %llx, guid %llx\n",
4298 pi->PortInfo.GidPrefix,
4299 tmp->NodeInfo.PortGUID);
4300
4301 sgid.gid_prefix = port->pa_sn_prefix;
4302 sgid.gid_guid = port->pa_port_guid;
4303 dgid.gid_prefix = pi->PortInfo.GidPrefix;
4304 dgid.gid_guid = tmp->NodeInfo.PortGUID;
4305 new_gid = ibdm_create_gid_info(port, sgid,
4306 dgid);
4307 if (new_gid == NULL) {
4308 IBTF_DPRINTF_L2("ibdm", "\tprobe_ioc: "
4309 "create_gid_info failed\n");
4310 kmem_free(pi, pi_len);
4311 continue;
4312 }
4313 if (node_gid == NULL) {
4314 node_gid = new_gid;
4315 ibdm_add_to_gl_gid(node_gid, node_gid);
4316 } else {
4317 IBTF_DPRINTF_L4("ibdm",
4318 "\tprobe_ioc: new gid");
4319 temp_gid = kmem_zalloc(
4320 sizeof (ibdm_gid_t), KM_SLEEP);
4321 temp_gid->gid_dgid_hi =
4322 new_gid->gl_dgid_hi;
4323 temp_gid->gid_dgid_lo =
4324 new_gid->gl_dgid_lo;
4325 temp_gid->gid_next = node_gid->gl_gid;
4326 node_gid->gl_gid = temp_gid;
4327 node_gid->gl_ngids++;
4328 }
4329 new_gid->gl_is_dm_capable = B_TRUE;
4330 new_gid->gl_nodeguid = nodeguid;
4331 new_gid->gl_portguid = dgid.gid_guid;
4332 ibdm_addto_glhcalist(new_gid, hca_list);
4333
4334 /*
4335 * Set the state to skipped as all these
4336 * gids point to the same node.
4337 * We (re)probe only one GID below and reset
4338 * state appropriately
4339 */
4340 new_gid->gl_state = IBDM_GID_PROBING_SKIPPED;
4341 new_gid->gl_devid = (*tmp).NodeInfo.DeviceID;
4342 kmem_free(pi, pi_len);
4343 }
4344 kmem_free(nr, nr_len);
4345
4346 IBTF_DPRINTF_L4("ibdm", "\tprobe_ioc : reprobe_flag %d "
4347 "reprobe_gid %p new_gid %p node_gid %p",
4348 reprobe_flag, reprobe_gid, new_gid, node_gid);
4349
4350 if (reprobe_flag != 0 && reprobe_gid != NULL) {
4351 int niocs, jj;
4352 ibdm_ioc_info_t *tmp_ioc;
4353 int ioc_matched = 0;
4354
4355 mutex_exit(&ibdm.ibdm_hl_mutex);
4356 mutex_enter(&reprobe_gid->gl_mutex);
4357 reprobe_gid->gl_state = IBDM_GET_IOC_DETAILS;
4358 niocs =
4359 reprobe_gid->gl_iou->iou_info.iou_num_ctrl_slots;
4360 reprobe_gid->gl_pending_cmds++;
4361 mutex_exit(&reprobe_gid->gl_mutex);
4362
4363 for (jj = 0; jj < niocs; jj++) {
4364 tmp_ioc =
4365 IBDM_GIDINFO2IOCINFO(reprobe_gid, jj);
4366 if (tmp_ioc->ioc_profile.ioc_guid != ioc_guid)
4367 continue;
4368
4369 ioc_matched = 1;
4370
4371 /*
4372 * Explicitly set gl_reprobe_flag to 0 so that
4373 * IBnex is not notified on completion
4374 */
4375 mutex_enter(&reprobe_gid->gl_mutex);
4376 reprobe_gid->gl_reprobe_flag = 0;
4377 mutex_exit(&reprobe_gid->gl_mutex);
4378
4379 mutex_enter(&ibdm.ibdm_mutex);
4380 ibdm.ibdm_ngid_probes_in_progress++;
4381 mutex_exit(&ibdm.ibdm_mutex);
4382 if (ibdm_send_ioc_profile(reprobe_gid, jj) !=
4383 IBDM_SUCCESS) {
4384 IBTF_DPRINTF_L4("ibdm",
4385 "\tprobe_ioc: "
4386 "send_ioc_profile failed "
4387 "for ioc %d", jj);
4388 ibdm_gid_decr_pending(reprobe_gid);
4389 break;
4390 }
4391 mutex_enter(&ibdm.ibdm_mutex);
4392 ibdm_wait_probe_completion();
4393 mutex_exit(&ibdm.ibdm_mutex);
4394 break;
4395 }
4396 if (ioc_matched == 0)
4397 ibdm_gid_decr_pending(reprobe_gid);
4398 else {
4399 mutex_enter(&ibdm.ibdm_hl_mutex);
4400 break;
4401 }
4402 } else if (new_gid != NULL) {
4403 mutex_exit(&ibdm.ibdm_hl_mutex);
4404 node_gid = node_gid ? node_gid : new_gid;
4405
4406 /*
4407 * New or reinserted GID : Enable notification
4408 * to IBnex
4409 */
4410 mutex_enter(&node_gid->gl_mutex);
4411 node_gid->gl_reprobe_flag = 1;
4412 mutex_exit(&node_gid->gl_mutex);
4413
4414 ibdm_probe_gid(node_gid);
4415
4416 mutex_enter(&ibdm.ibdm_hl_mutex);
4417 }
4418 }
4419 mutex_exit(&ibdm.ibdm_hl_mutex);
4420 IBTF_DPRINTF_L4("ibdm", "\tprobe_ioc : End\n");
4421 }
4422
4423
4424 /*
4425 * ibdm_probe_gid()
4426 * Selectively probes the GID
4427 */
4428 static void
ibdm_probe_gid(ibdm_dp_gidinfo_t * gid_info)4429 ibdm_probe_gid(ibdm_dp_gidinfo_t *gid_info)
4430 {
4431 IBTF_DPRINTF_L4("ibdm", "\tprobe_gid:");
4432
4433 /*
4434 * A Cisco FC GW needs the special handling to get IOUnitInfo.
4435 */
4436 mutex_enter(&gid_info->gl_mutex);
4437 if (ibdm_is_cisco_switch(gid_info)) {
4438 gid_info->gl_pending_cmds++;
4439 gid_info->gl_state = IBDM_SET_CLASSPORTINFO;
4440 mutex_exit(&gid_info->gl_mutex);
4441
4442 if (ibdm_set_classportinfo(gid_info) != IBDM_SUCCESS) {
4443
4444 mutex_enter(&gid_info->gl_mutex);
4445 gid_info->gl_state = IBDM_GID_PROBING_FAILED;
4446 --gid_info->gl_pending_cmds;
4447 mutex_exit(&gid_info->gl_mutex);
4448
4449 /* free the hca_list on this gid_info */
4450 ibdm_delete_glhca_list(gid_info);
4451 gid_info = gid_info->gl_next;
4452 return;
4453 }
4454
4455 mutex_enter(&gid_info->gl_mutex);
4456 ibdm_wait_cisco_probe_completion(gid_info);
4457
4458 IBTF_DPRINTF_L4("ibdm",
4459 "\tprobe_gid: CISCO Wakeup signal received");
4460 }
4461
4462 /* move on to the 'GET_CLASSPORTINFO' stage */
4463 gid_info->gl_pending_cmds++;
4464 gid_info->gl_state = IBDM_GET_CLASSPORTINFO;
4465 mutex_exit(&gid_info->gl_mutex);
4466
4467 if (ibdm_send_classportinfo(gid_info) != IBDM_SUCCESS) {
4468
4469 mutex_enter(&gid_info->gl_mutex);
4470 gid_info->gl_state = IBDM_GID_PROBING_FAILED;
4471 --gid_info->gl_pending_cmds;
4472 mutex_exit(&gid_info->gl_mutex);
4473
4474 /* free the hca_list on this gid_info */
4475 ibdm_delete_glhca_list(gid_info);
4476 gid_info = gid_info->gl_next;
4477 return;
4478 }
4479
4480 mutex_enter(&ibdm.ibdm_mutex);
4481 ibdm.ibdm_ngid_probes_in_progress++;
4482 gid_info = gid_info->gl_next;
4483 ibdm_wait_probe_completion();
4484 mutex_exit(&ibdm.ibdm_mutex);
4485
4486 IBTF_DPRINTF_L4("ibdm", "\tprobe_gid: Wakeup signal received");
4487 }
4488
4489
4490 /*
4491 * ibdm_create_gid_info()
4492 * Allocates a gid_info structure and initializes
4493 * Returns pointer to the structure on success
4494 * and NULL on failure
4495 */
4496 static ibdm_dp_gidinfo_t *
ibdm_create_gid_info(ibdm_port_attr_t * port,ib_gid_t sgid,ib_gid_t dgid)4497 ibdm_create_gid_info(ibdm_port_attr_t *port, ib_gid_t sgid, ib_gid_t dgid)
4498 {
4499 uint8_t ii, npaths;
4500 sa_path_record_t *path;
4501 size_t len;
4502 ibdm_pkey_tbl_t *pkey_tbl;
4503 ibdm_dp_gidinfo_t *gid_info = NULL;
4504 int ret;
4505
4506 IBTF_DPRINTF_L4("ibdm", "\tcreate_gid_info: Begin");
4507 npaths = 1;
4508
4509 /* query for reversible paths */
4510 if (port->pa_sa_hdl)
4511 ret = ibmf_saa_gid_to_pathrecords(port->pa_sa_hdl,
4512 sgid, dgid, IBMF_SAA_PKEY_WC, 0, B_TRUE, &npaths, 0,
4513 &len, &path);
4514 else
4515 return (NULL);
4516
4517 if (ret == IBMF_SUCCESS && path) {
4518 ibdm_dump_path_info(path);
4519
4520 gid_info = kmem_zalloc(
4521 sizeof (ibdm_dp_gidinfo_t), KM_SLEEP);
4522 mutex_init(&gid_info->gl_mutex, NULL, MUTEX_DEFAULT, NULL);
4523 cv_init(&gid_info->gl_probe_cv, NULL, CV_DRIVER, NULL);
4524 gid_info->gl_dgid_hi = path->DGID.gid_prefix;
4525 gid_info->gl_dgid_lo = path->DGID.gid_guid;
4526 gid_info->gl_sgid_hi = path->SGID.gid_prefix;
4527 gid_info->gl_sgid_lo = path->SGID.gid_guid;
4528 gid_info->gl_p_key = path->P_Key;
4529 gid_info->gl_sa_hdl = port->pa_sa_hdl;
4530 gid_info->gl_ibmf_hdl = port->pa_ibmf_hdl;
4531 gid_info->gl_slid = path->SLID;
4532 gid_info->gl_dlid = path->DLID;
4533 gid_info->gl_transactionID = (++ibdm.ibdm_transactionID)
4534 << IBDM_GID_TRANSACTIONID_SHIFT;
4535 gid_info->gl_min_transactionID = gid_info->gl_transactionID;
4536 gid_info->gl_max_transactionID = (ibdm.ibdm_transactionID +1)
4537 << IBDM_GID_TRANSACTIONID_SHIFT;
4538 gid_info->gl_SL = path->SL;
4539
4540 gid_info->gl_qp_hdl = IBMF_QP_HANDLE_DEFAULT;
4541 for (ii = 0; ii < port->pa_npkeys; ii++) {
4542 if (port->pa_pkey_tbl == NULL)
4543 break;
4544
4545 pkey_tbl = &port->pa_pkey_tbl[ii];
4546 if ((gid_info->gl_p_key == pkey_tbl->pt_pkey) &&
4547 (pkey_tbl->pt_qp_hdl != NULL)) {
4548 gid_info->gl_qp_hdl = pkey_tbl->pt_qp_hdl;
4549 break;
4550 }
4551 }
4552 kmem_free(path, len);
4553
4554 /*
4555 * QP handle for GID not initialized. No matching Pkey
4556 * was found!! ibdm should *not* hit this case. Flag an
4557 * error and drop the GID if ibdm does encounter this.
4558 */
4559 if (gid_info->gl_qp_hdl == NULL) {
4560 IBTF_DPRINTF_L2(ibdm_string,
4561 "\tcreate_gid_info: No matching Pkey");
4562 ibdm_delete_gidinfo(gid_info);
4563 return (NULL);
4564 }
4565
4566 ibdm.ibdm_ngids++;
4567 if (ibdm.ibdm_dp_gidlist_head == NULL) {
4568 ibdm.ibdm_dp_gidlist_head = gid_info;
4569 ibdm.ibdm_dp_gidlist_tail = gid_info;
4570 } else {
4571 ibdm.ibdm_dp_gidlist_tail->gl_next = gid_info;
4572 gid_info->gl_prev = ibdm.ibdm_dp_gidlist_tail;
4573 ibdm.ibdm_dp_gidlist_tail = gid_info;
4574 }
4575 }
4576
4577 return (gid_info);
4578 }
4579
4580
4581 /*
4582 * ibdm_get_node_records
4583 * Sends a SA query to get the NODE record
4584 * Returns pointer to the sa_node_record_t on success
4585 * and NULL on failure
4586 */
4587 static sa_node_record_t *
ibdm_get_node_records(ibmf_saa_handle_t sa_hdl,size_t * length,ib_guid_t guid)4588 ibdm_get_node_records(ibmf_saa_handle_t sa_hdl, size_t *length, ib_guid_t guid)
4589 {
4590 sa_node_record_t req, *resp = NULL;
4591 ibmf_saa_access_args_t args;
4592 int ret;
4593
4594 IBTF_DPRINTF_L4("ibdm", "\tget_node_records: Begin");
4595
4596 bzero(&req, sizeof (sa_node_record_t));
4597 req.NodeInfo.NodeGUID = guid;
4598
4599 args.sq_attr_id = SA_NODERECORD_ATTRID;
4600 args.sq_access_type = IBMF_SAA_RETRIEVE;
4601 args.sq_component_mask = SA_NODEINFO_COMPMASK_NODEGUID;
4602 args.sq_template = &req;
4603 args.sq_callback = NULL;
4604 args.sq_callback_arg = NULL;
4605
4606 ret = ibmf_sa_access(sa_hdl, &args, 0, length, (void **) &resp);
4607 if (ret != IBMF_SUCCESS) {
4608 IBTF_DPRINTF_L2("ibdm", "\tget_node_records:"
4609 " SA Retrieve Failed: %d", ret);
4610 return (NULL);
4611 }
4612 if ((resp == NULL) || (*length == 0)) {
4613 IBTF_DPRINTF_L2("ibdm", "\tget_node_records: No records");
4614 return (NULL);
4615 }
4616
4617 IBTF_DPRINTF_L4("ibdm", "\tget_node_records: NodeGuid %llx "
4618 "PortGUID %llx", resp->NodeInfo.NodeGUID, resp->NodeInfo.PortGUID);
4619
4620 return (resp);
4621 }
4622
4623
4624 /*
4625 * ibdm_get_portinfo()
4626 * Sends a SA query to get the PortInfo record
4627 * Returns pointer to the sa_portinfo_record_t on success
4628 * and NULL on failure
4629 */
4630 static sa_portinfo_record_t *
ibdm_get_portinfo(ibmf_saa_handle_t sa_hdl,size_t * length,ib_lid_t lid)4631 ibdm_get_portinfo(ibmf_saa_handle_t sa_hdl, size_t *length, ib_lid_t lid)
4632 {
4633 sa_portinfo_record_t req, *resp = NULL;
4634 ibmf_saa_access_args_t args;
4635 int ret;
4636
4637 IBTF_DPRINTF_L4("ibdm", "\tget_portinfo: Begin");
4638
4639 bzero(&req, sizeof (sa_portinfo_record_t));
4640 req.EndportLID = lid;
4641
4642 args.sq_attr_id = SA_PORTINFORECORD_ATTRID;
4643 args.sq_access_type = IBMF_SAA_RETRIEVE;
4644 args.sq_component_mask = SA_PORTINFO_COMPMASK_PORTLID;
4645 args.sq_template = &req;
4646 args.sq_callback = NULL;
4647 args.sq_callback_arg = NULL;
4648
4649 ret = ibmf_sa_access(sa_hdl, &args, 0, length, (void **) &resp);
4650 if (ret != IBMF_SUCCESS) {
4651 IBTF_DPRINTF_L2("ibdm", "\tget_portinfo:"
4652 " SA Retrieve Failed: 0x%X", ret);
4653 return (NULL);
4654 }
4655 if ((*length == 0) || (resp == NULL))
4656 return (NULL);
4657
4658 IBTF_DPRINTF_L4("ibdm", "\tget_portinfo: GidPrefix %llx Cap 0x%x",
4659 resp->PortInfo.GidPrefix, resp->PortInfo.CapabilityMask);
4660 return (resp);
4661 }
4662
4663
4664 /*
4665 * ibdm_ibnex_register_callback
4666 * IB nexus callback routine for HCA attach and detach notification
4667 */
4668 void
ibdm_ibnex_register_callback(ibdm_callback_t ibnex_dm_callback)4669 ibdm_ibnex_register_callback(ibdm_callback_t ibnex_dm_callback)
4670 {
4671 IBTF_DPRINTF_L4("ibdm", "\tibnex_register_callbacks");
4672 mutex_enter(&ibdm.ibdm_ibnex_mutex);
4673 ibdm.ibdm_ibnex_callback = ibnex_dm_callback;
4674 mutex_exit(&ibdm.ibdm_ibnex_mutex);
4675 }
4676
4677
4678 /*
4679 * ibdm_ibnex_unregister_callbacks
4680 */
4681 void
ibdm_ibnex_unregister_callback()4682 ibdm_ibnex_unregister_callback()
4683 {
4684 IBTF_DPRINTF_L4("ibdm", "\tibnex_unregister_callbacks");
4685 mutex_enter(&ibdm.ibdm_ibnex_mutex);
4686 ibdm.ibdm_ibnex_callback = NULL;
4687 mutex_exit(&ibdm.ibdm_ibnex_mutex);
4688 }
4689
4690 /*
4691 * ibdm_get_waittime()
4692 * Calculates the wait time based on the last HCA attach time
4693 */
4694 static time_t
ibdm_get_waittime(ib_guid_t hca_guid,int dft_wait)4695 ibdm_get_waittime(ib_guid_t hca_guid, int dft_wait)
4696 {
4697 int ii;
4698 time_t temp, wait_time = 0;
4699 ibdm_hca_list_t *hca;
4700
4701 IBTF_DPRINTF_L4("ibdm", "\tget_waittime hcaguid:%llx"
4702 "\tport settling time %d", hca_guid, dft_wait);
4703
4704 ASSERT(mutex_owned(&ibdm.ibdm_hl_mutex));
4705
4706 hca = ibdm.ibdm_hca_list_head;
4707
4708 if (hca_guid) {
4709 for (ii = 0; ii < ibdm.ibdm_hca_count; ii++) {
4710 if ((hca_guid == hca->hl_hca_guid) &&
4711 (hca->hl_nports != hca->hl_nports_active)) {
4712 wait_time =
4713 ddi_get_time() - hca->hl_attach_time;
4714 wait_time = ((wait_time >= dft_wait) ?
4715 0 : (dft_wait - wait_time));
4716 break;
4717 }
4718 hca = hca->hl_next;
4719 }
4720 IBTF_DPRINTF_L2("ibdm", "\tget_waittime: wait_time = %ld secs",
4721 (long)wait_time);
4722 return (wait_time);
4723 }
4724
4725 for (ii = 0; ii < ibdm.ibdm_hca_count; ii++) {
4726 if (hca->hl_nports != hca->hl_nports_active) {
4727 temp = ddi_get_time() - hca->hl_attach_time;
4728 temp = ((temp >= dft_wait) ? 0 : (dft_wait - temp));
4729 wait_time = (temp > wait_time) ? temp : wait_time;
4730 }
4731 hca = hca->hl_next;
4732 }
4733 IBTF_DPRINTF_L2("ibdm", "\tget_waittime: wait_time = %ld secs",
4734 (long)wait_time);
4735 return (wait_time);
4736 }
4737
4738 void
ibdm_ibnex_port_settle_wait(ib_guid_t hca_guid,int dft_wait)4739 ibdm_ibnex_port_settle_wait(ib_guid_t hca_guid, int dft_wait)
4740 {
4741 time_t wait_time;
4742 clock_t delta;
4743
4744 mutex_enter(&ibdm.ibdm_hl_mutex);
4745
4746 while ((wait_time = ibdm_get_waittime(hca_guid, dft_wait)) > 0) {
4747 if (wait_time > dft_wait) {
4748 IBTF_DPRINTF_L1("ibdm",
4749 "\tibnex_port_settle_wait: wait_time = %ld secs; "
4750 "Resetting to %d secs",
4751 (long)wait_time, dft_wait);
4752 wait_time = dft_wait;
4753 }
4754 delta = drv_usectohz(wait_time * 1000000);
4755 (void) cv_reltimedwait(&ibdm.ibdm_port_settle_cv,
4756 &ibdm.ibdm_hl_mutex, delta, TR_CLOCK_TICK);
4757 }
4758
4759 mutex_exit(&ibdm.ibdm_hl_mutex);
4760 }
4761
4762
4763 /*
4764 * ibdm_ibnex_probe_hcaport
4765 * Probes the presence of HCA port (with HCA dip and port number)
4766 * Returns port attributes structure on SUCCESS
4767 */
4768 ibdm_port_attr_t *
ibdm_ibnex_probe_hcaport(ib_guid_t hca_guid,uint8_t port_num)4769 ibdm_ibnex_probe_hcaport(ib_guid_t hca_guid, uint8_t port_num)
4770 {
4771 int ii, jj;
4772 ibdm_hca_list_t *hca_list;
4773 ibdm_port_attr_t *port_attr;
4774
4775 IBTF_DPRINTF_L4("ibdm", "\tibnex_probe_hcaport:");
4776
4777 mutex_enter(&ibdm.ibdm_hl_mutex);
4778 hca_list = ibdm.ibdm_hca_list_head;
4779 for (ii = 0; ii < ibdm.ibdm_hca_count; ii++) {
4780 if (hca_list->hl_hca_guid == hca_guid) {
4781 for (jj = 0; jj < hca_list->hl_nports; jj++) {
4782 if (hca_list->hl_port_attr[jj].pa_port_num ==
4783 port_num) {
4784 break;
4785 }
4786 }
4787 if (jj != hca_list->hl_nports)
4788 break;
4789 }
4790 hca_list = hca_list->hl_next;
4791 }
4792 if (ii == ibdm.ibdm_hca_count) {
4793 IBTF_DPRINTF_L2("ibdm", "\tibnex_probe_hcaport: not found");
4794 mutex_exit(&ibdm.ibdm_hl_mutex);
4795 return (NULL);
4796 }
4797 port_attr = (ibdm_port_attr_t *)kmem_zalloc(
4798 sizeof (ibdm_port_attr_t), KM_SLEEP);
4799 bcopy((char *)&hca_list->hl_port_attr[jj],
4800 port_attr, sizeof (ibdm_port_attr_t));
4801 ibdm_update_port_attr(port_attr);
4802
4803 mutex_exit(&ibdm.ibdm_hl_mutex);
4804 return (port_attr);
4805 }
4806
4807
4808 /*
4809 * ibdm_ibnex_get_port_attrs
4810 * Scan all HCAs for a matching port_guid.
4811 * Returns "port attributes" structure on success.
4812 */
4813 ibdm_port_attr_t *
ibdm_ibnex_get_port_attrs(ib_guid_t port_guid)4814 ibdm_ibnex_get_port_attrs(ib_guid_t port_guid)
4815 {
4816 int ii, jj;
4817 ibdm_hca_list_t *hca_list;
4818 ibdm_port_attr_t *port_attr;
4819
4820 IBTF_DPRINTF_L4("ibdm", "\tibnex_get_port_attrs:");
4821
4822 mutex_enter(&ibdm.ibdm_hl_mutex);
4823 hca_list = ibdm.ibdm_hca_list_head;
4824
4825 for (ii = 0; ii < ibdm.ibdm_hca_count; ii++) {
4826 for (jj = 0; jj < hca_list->hl_nports; jj++) {
4827 if (hca_list->hl_port_attr[jj].pa_port_guid ==
4828 port_guid) {
4829 break;
4830 }
4831 }
4832 if (jj != hca_list->hl_nports)
4833 break;
4834 hca_list = hca_list->hl_next;
4835 }
4836
4837 if (ii == ibdm.ibdm_hca_count) {
4838 IBTF_DPRINTF_L2("ibdm", "\tibnex_get_port_attrs: not found");
4839 mutex_exit(&ibdm.ibdm_hl_mutex);
4840 return (NULL);
4841 }
4842
4843 port_attr = (ibdm_port_attr_t *)kmem_alloc(sizeof (ibdm_port_attr_t),
4844 KM_SLEEP);
4845 bcopy((char *)&hca_list->hl_port_attr[jj], port_attr,
4846 sizeof (ibdm_port_attr_t));
4847 ibdm_update_port_attr(port_attr);
4848
4849 mutex_exit(&ibdm.ibdm_hl_mutex);
4850 return (port_attr);
4851 }
4852
4853
4854 /*
4855 * ibdm_ibnex_free_port_attr()
4856 */
4857 void
ibdm_ibnex_free_port_attr(ibdm_port_attr_t * port_attr)4858 ibdm_ibnex_free_port_attr(ibdm_port_attr_t *port_attr)
4859 {
4860 IBTF_DPRINTF_L4("ibdm", "\tibnex_free_port_attr:");
4861 if (port_attr) {
4862 if (port_attr->pa_pkey_tbl != NULL) {
4863 kmem_free(port_attr->pa_pkey_tbl,
4864 (port_attr->pa_npkeys * sizeof (ibdm_pkey_tbl_t)));
4865 }
4866 kmem_free(port_attr, sizeof (ibdm_port_attr_t));
4867 }
4868 }
4869
4870
4871 /*
4872 * ibdm_ibnex_get_hca_list()
4873 * Returns portinfo for all the port for all the HCA's
4874 */
4875 void
ibdm_ibnex_get_hca_list(ibdm_hca_list_t ** hca,int * count)4876 ibdm_ibnex_get_hca_list(ibdm_hca_list_t **hca, int *count)
4877 {
4878 ibdm_hca_list_t *head = NULL, *temp, *temp1;
4879 int ii;
4880
4881 IBTF_DPRINTF_L4("ibdm", "\tibnex_get_hca_list:");
4882
4883 mutex_enter(&ibdm.ibdm_hl_mutex);
4884 temp = ibdm.ibdm_hca_list_head;
4885 for (ii = 0; ii < ibdm.ibdm_hca_count; ii++) {
4886 temp1 = ibdm_dup_hca_attr(temp);
4887 temp1->hl_next = head;
4888 head = temp1;
4889 temp = temp->hl_next;
4890 }
4891 *count = ibdm.ibdm_hca_count;
4892 *hca = head;
4893 mutex_exit(&ibdm.ibdm_hl_mutex);
4894 }
4895
4896
4897 /*
4898 * ibdm_ibnex_get_hca_info_by_guid()
4899 */
4900 ibdm_hca_list_t *
ibdm_ibnex_get_hca_info_by_guid(ib_guid_t hca_guid)4901 ibdm_ibnex_get_hca_info_by_guid(ib_guid_t hca_guid)
4902 {
4903 ibdm_hca_list_t *head = NULL, *hca = NULL;
4904
4905 IBTF_DPRINTF_L4("ibdm", "\tibnex_get_hca_info_by_dip");
4906
4907 mutex_enter(&ibdm.ibdm_hl_mutex);
4908 head = ibdm.ibdm_hca_list_head;
4909 while (head) {
4910 if (head->hl_hca_guid == hca_guid) {
4911 hca = ibdm_dup_hca_attr(head);
4912 hca->hl_next = NULL;
4913 break;
4914 }
4915 head = head->hl_next;
4916 }
4917 mutex_exit(&ibdm.ibdm_hl_mutex);
4918 IBTF_DPRINTF_L4("ibdm", "\tibnex_get_hca_info_by_dip %p", hca);
4919 return (hca);
4920 }
4921
4922
4923 /*
4924 * ibdm_dup_hca_attr()
4925 * Allocate a new HCA attribute strucuture and initialize
4926 * hca attribute structure with the incoming HCA attributes
4927 * returned the allocated hca attributes.
4928 */
4929 static ibdm_hca_list_t *
ibdm_dup_hca_attr(ibdm_hca_list_t * in_hca)4930 ibdm_dup_hca_attr(ibdm_hca_list_t *in_hca)
4931 {
4932 int len;
4933 ibdm_hca_list_t *out_hca;
4934
4935 len = sizeof (ibdm_hca_list_t) +
4936 (in_hca->hl_nports * sizeof (ibdm_port_attr_t));
4937 IBTF_DPRINTF_L4("ibdm", "\tdup_hca_attr len %d", len);
4938 out_hca = (ibdm_hca_list_t *)kmem_alloc(len, KM_SLEEP);
4939 bcopy((char *)in_hca,
4940 (char *)out_hca, sizeof (ibdm_hca_list_t));
4941 if (in_hca->hl_nports) {
4942 out_hca->hl_port_attr = (ibdm_port_attr_t *)
4943 ((char *)out_hca + sizeof (ibdm_hca_list_t));
4944 bcopy((char *)in_hca->hl_port_attr,
4945 (char *)out_hca->hl_port_attr,
4946 (in_hca->hl_nports * sizeof (ibdm_port_attr_t)));
4947 for (len = 0; len < out_hca->hl_nports; len++)
4948 ibdm_update_port_attr(&out_hca->hl_port_attr[len]);
4949 }
4950 return (out_hca);
4951 }
4952
4953
4954 /*
4955 * ibdm_ibnex_free_hca_list()
4956 * Free one/more HCA lists
4957 */
4958 void
ibdm_ibnex_free_hca_list(ibdm_hca_list_t * hca_list)4959 ibdm_ibnex_free_hca_list(ibdm_hca_list_t *hca_list)
4960 {
4961 int ii;
4962 size_t len;
4963 ibdm_hca_list_t *temp;
4964 ibdm_port_attr_t *port;
4965
4966 IBTF_DPRINTF_L4("ibdm", "\tibnex_free_hca_list:");
4967 ASSERT(hca_list);
4968 while (hca_list) {
4969 temp = hca_list;
4970 hca_list = hca_list->hl_next;
4971 for (ii = 0; ii < temp->hl_nports; ii++) {
4972 port = &temp->hl_port_attr[ii];
4973 len = (port->pa_npkeys * sizeof (ibdm_pkey_tbl_t));
4974 if (len != 0)
4975 kmem_free(port->pa_pkey_tbl, len);
4976 }
4977 len = sizeof (ibdm_hca_list_t) + (temp->hl_nports *
4978 sizeof (ibdm_port_attr_t));
4979 kmem_free(temp, len);
4980 }
4981 }
4982
4983
4984 /*
4985 * ibdm_ibnex_probe_iocguid()
4986 * Probes the IOC on the fabric and returns the IOC information
4987 * if present. Otherwise, NULL is returned
4988 */
4989 /* ARGSUSED */
4990 ibdm_ioc_info_t *
ibdm_ibnex_probe_ioc(ib_guid_t iou,ib_guid_t ioc_guid,int reprobe_flag)4991 ibdm_ibnex_probe_ioc(ib_guid_t iou, ib_guid_t ioc_guid, int reprobe_flag)
4992 {
4993 int k;
4994 ibdm_ioc_info_t *ioc_info;
4995 ibdm_dp_gidinfo_t *gid_info; /* used as index and arg */
4996 timeout_id_t *timeout_id;
4997
4998 IBTF_DPRINTF_L4("ibdm", "\tibnex_probe_ioc: (%llX, %llX, %d) Begin",
4999 iou, ioc_guid, reprobe_flag);
5000
5001 if (ibdm_enumerate_iocs == 0)
5002 return (NULL);
5003
5004 /* Check whether we know this already */
5005 ioc_info = ibdm_get_ioc_info_with_gid(ioc_guid, &gid_info);
5006 if (ioc_info == NULL) {
5007 mutex_enter(&ibdm.ibdm_mutex);
5008 while (ibdm.ibdm_busy & IBDM_BUSY)
5009 cv_wait(&ibdm.ibdm_busy_cv, &ibdm.ibdm_mutex);
5010 ibdm.ibdm_busy |= IBDM_BUSY;
5011 mutex_exit(&ibdm.ibdm_mutex);
5012 ibdm_probe_ioc(iou, ioc_guid, 0);
5013 mutex_enter(&ibdm.ibdm_mutex);
5014 ibdm.ibdm_busy &= ~IBDM_BUSY;
5015 cv_broadcast(&ibdm.ibdm_busy_cv);
5016 mutex_exit(&ibdm.ibdm_mutex);
5017 ioc_info = ibdm_get_ioc_info_with_gid(ioc_guid, &gid_info);
5018 } else if (reprobe_flag) { /* Handle Reprobe for the IOC */
5019 ASSERT(gid_info != NULL);
5020 /* Free the ioc_list before reprobe; and cancel any timers */
5021 mutex_enter(&ibdm.ibdm_mutex);
5022 mutex_enter(&gid_info->gl_mutex);
5023 if (ioc_info->ioc_timeout_id) {
5024 timeout_id = ioc_info->ioc_timeout_id;
5025 ioc_info->ioc_timeout_id = 0;
5026 mutex_exit(&gid_info->gl_mutex);
5027 IBTF_DPRINTF_L5("ibdm", "\tprobe_ioc: "
5028 "ioc_timeout_id = 0x%x", timeout_id);
5029 if (untimeout(timeout_id) == -1) {
5030 IBTF_DPRINTF_L2("ibdm", "\tprobe_ioc: "
5031 "untimeout ioc_timeout_id failed");
5032 }
5033 mutex_enter(&gid_info->gl_mutex);
5034 }
5035 if (ioc_info->ioc_dc_timeout_id) {
5036 timeout_id = ioc_info->ioc_dc_timeout_id;
5037 ioc_info->ioc_dc_timeout_id = 0;
5038 mutex_exit(&gid_info->gl_mutex);
5039 IBTF_DPRINTF_L5("ibdm", "\tprobe_ioc: "
5040 "ioc_dc_timeout_id = 0x%x", timeout_id);
5041 if (untimeout(timeout_id) == -1) {
5042 IBTF_DPRINTF_L2("ibdm", "\tprobe_ioc: "
5043 "untimeout ioc_dc_timeout_id failed");
5044 }
5045 mutex_enter(&gid_info->gl_mutex);
5046 }
5047 for (k = 0; k < ioc_info->ioc_profile.ioc_service_entries; k++)
5048 if (ioc_info->ioc_serv[k].se_timeout_id) {
5049 timeout_id = ioc_info->ioc_serv[k].
5050 se_timeout_id;
5051 ioc_info->ioc_serv[k].se_timeout_id = 0;
5052 mutex_exit(&gid_info->gl_mutex);
5053 IBTF_DPRINTF_L5("ibdm", "\tprobe_ioc: "
5054 "ioc_info->ioc_serv[k].se_timeout_id = %x",
5055 k, timeout_id);
5056 if (untimeout(timeout_id) == -1) {
5057 IBTF_DPRINTF_L2("ibdm", "\tprobe_ioc: "
5058 "untimeout se_timeout_id %d "
5059 "failed", k);
5060 }
5061 mutex_enter(&gid_info->gl_mutex);
5062 }
5063 mutex_exit(&gid_info->gl_mutex);
5064 mutex_exit(&ibdm.ibdm_mutex);
5065 ibdm_ibnex_free_ioc_list(ioc_info);
5066
5067 mutex_enter(&ibdm.ibdm_mutex);
5068 while (ibdm.ibdm_busy & IBDM_BUSY)
5069 cv_wait(&ibdm.ibdm_busy_cv, &ibdm.ibdm_mutex);
5070 ibdm.ibdm_busy |= IBDM_BUSY;
5071 mutex_exit(&ibdm.ibdm_mutex);
5072
5073 ibdm_probe_ioc(iou, ioc_guid, 1);
5074
5075 /*
5076 * Skip if gl_reprobe_flag is set, this will be
5077 * a re-inserted / new GID, for which notifications
5078 * have already been send.
5079 */
5080 for (gid_info = ibdm.ibdm_dp_gidlist_head; gid_info;
5081 gid_info = gid_info->gl_next) {
5082 uint8_t ii, niocs;
5083 ibdm_ioc_info_t *ioc;
5084
5085 if (gid_info->gl_iou == NULL)
5086 continue;
5087
5088 if (gid_info->gl_reprobe_flag) {
5089 gid_info->gl_reprobe_flag = 0;
5090 continue;
5091 }
5092
5093 niocs = gid_info->gl_iou->iou_info.iou_num_ctrl_slots;
5094 for (ii = 0; ii < niocs; ii++) {
5095 ioc = IBDM_GIDINFO2IOCINFO(gid_info, ii);
5096 if (ioc->ioc_profile.ioc_guid == ioc_guid) {
5097 mutex_enter(&ibdm.ibdm_mutex);
5098 ibdm_reprobe_update_port_srv(ioc,
5099 gid_info);
5100 mutex_exit(&ibdm.ibdm_mutex);
5101 }
5102 }
5103 }
5104 mutex_enter(&ibdm.ibdm_mutex);
5105 ibdm.ibdm_busy &= ~IBDM_BUSY;
5106 cv_broadcast(&ibdm.ibdm_busy_cv);
5107 mutex_exit(&ibdm.ibdm_mutex);
5108
5109 ioc_info = ibdm_get_ioc_info_with_gid(ioc_guid, &gid_info);
5110 }
5111 return (ioc_info);
5112 }
5113
5114
5115 /*
5116 * ibdm_get_ioc_info_with_gid()
5117 * Returns pointer to ibdm_ioc_info_t if it finds
5118 * matching record for the ioc_guid. Otherwise NULL is returned.
5119 * The pointer to gid_info is set to the second argument in case that
5120 * the non-NULL value returns (and the second argument is not NULL).
5121 *
5122 * Note. use the same strings as "ibnex_get_ioc_info" in
5123 * IBTF_DPRINTF() to keep compatibility.
5124 */
5125 static ibdm_ioc_info_t *
ibdm_get_ioc_info_with_gid(ib_guid_t ioc_guid,ibdm_dp_gidinfo_t ** gid_info)5126 ibdm_get_ioc_info_with_gid(ib_guid_t ioc_guid,
5127 ibdm_dp_gidinfo_t **gid_info)
5128 {
5129 int ii;
5130 ibdm_ioc_info_t *ioc = NULL, *tmp = NULL;
5131 ibdm_dp_gidinfo_t *gid_list;
5132 ib_dm_io_unitinfo_t *iou;
5133
5134 IBTF_DPRINTF_L4("ibdm", "\tibnex_get_ioc_info: GUID %llx", ioc_guid);
5135
5136 mutex_enter(&ibdm.ibdm_mutex);
5137 while (ibdm.ibdm_busy & IBDM_BUSY)
5138 cv_wait(&ibdm.ibdm_busy_cv, &ibdm.ibdm_mutex);
5139 ibdm.ibdm_busy |= IBDM_BUSY;
5140
5141 if (gid_info)
5142 *gid_info = NULL; /* clear the value of gid_info */
5143
5144 gid_list = ibdm.ibdm_dp_gidlist_head;
5145 while (gid_list) {
5146 mutex_enter(&gid_list->gl_mutex);
5147 if (gid_list->gl_state != IBDM_GID_PROBING_COMPLETE) {
5148 mutex_exit(&gid_list->gl_mutex);
5149 gid_list = gid_list->gl_next;
5150 continue;
5151 }
5152 if (gid_list->gl_iou == NULL) {
5153 IBTF_DPRINTF_L2("ibdm",
5154 "\tget_ioc_info: No IOU info");
5155 mutex_exit(&gid_list->gl_mutex);
5156 gid_list = gid_list->gl_next;
5157 continue;
5158 }
5159 iou = &gid_list->gl_iou->iou_info;
5160 for (ii = 0; ii < iou->iou_num_ctrl_slots; ii++) {
5161 tmp = IBDM_GIDINFO2IOCINFO(gid_list, ii);
5162 if ((tmp->ioc_profile.ioc_guid == ioc_guid) &&
5163 (tmp->ioc_state == IBDM_IOC_STATE_PROBE_SUCCESS)) {
5164 ioc = ibdm_dup_ioc_info(tmp, gid_list);
5165 if (gid_info)
5166 *gid_info = gid_list; /* set this ptr */
5167 mutex_exit(&gid_list->gl_mutex);
5168 ibdm.ibdm_busy &= ~IBDM_BUSY;
5169 cv_broadcast(&ibdm.ibdm_busy_cv);
5170 mutex_exit(&ibdm.ibdm_mutex);
5171 IBTF_DPRINTF_L4("ibdm", "\tget_ioc_info: End");
5172 return (ioc);
5173 }
5174 }
5175 if (ii == iou->iou_num_ctrl_slots)
5176 ioc = NULL;
5177
5178 mutex_exit(&gid_list->gl_mutex);
5179 gid_list = gid_list->gl_next;
5180 }
5181
5182 ibdm.ibdm_busy &= ~IBDM_BUSY;
5183 cv_broadcast(&ibdm.ibdm_busy_cv);
5184 mutex_exit(&ibdm.ibdm_mutex);
5185 IBTF_DPRINTF_L4("ibdm", "\tget_ioc_info: failure End");
5186 return (ioc);
5187 }
5188
5189 /*
5190 * ibdm_ibnex_get_ioc_info()
5191 * Returns pointer to ibdm_ioc_info_t if it finds
5192 * matching record for the ioc_guid, otherwise NULL
5193 * is returned
5194 *
5195 * Note. this is a wrapper function to ibdm_get_ioc_info_with_gid() now.
5196 */
5197 ibdm_ioc_info_t *
ibdm_ibnex_get_ioc_info(ib_guid_t ioc_guid)5198 ibdm_ibnex_get_ioc_info(ib_guid_t ioc_guid)
5199 {
5200 if (ibdm_enumerate_iocs == 0)
5201 return (NULL);
5202
5203 /* will not use the gid_info pointer, so the second arg is NULL */
5204 return (ibdm_get_ioc_info_with_gid(ioc_guid, NULL));
5205 }
5206
5207 /*
5208 * ibdm_ibnex_get_ioc_count()
5209 * Returns number of ibdm_ioc_info_t it finds
5210 */
5211 int
ibdm_ibnex_get_ioc_count(void)5212 ibdm_ibnex_get_ioc_count(void)
5213 {
5214 int count = 0, k;
5215 ibdm_ioc_info_t *ioc;
5216 ibdm_dp_gidinfo_t *gid_list;
5217
5218 if (ibdm_enumerate_iocs == 0)
5219 return (0);
5220
5221 mutex_enter(&ibdm.ibdm_mutex);
5222 ibdm_sweep_fabric(0);
5223
5224 while (ibdm.ibdm_busy & IBDM_BUSY)
5225 cv_wait(&ibdm.ibdm_busy_cv, &ibdm.ibdm_mutex);
5226 ibdm.ibdm_busy |= IBDM_BUSY;
5227
5228 for (gid_list = ibdm.ibdm_dp_gidlist_head; gid_list;
5229 gid_list = gid_list->gl_next) {
5230 mutex_enter(&gid_list->gl_mutex);
5231 if ((gid_list->gl_state != IBDM_GID_PROBING_COMPLETE) ||
5232 (gid_list->gl_iou == NULL)) {
5233 mutex_exit(&gid_list->gl_mutex);
5234 continue;
5235 }
5236 for (k = 0; k < gid_list->gl_iou->iou_info.iou_num_ctrl_slots;
5237 k++) {
5238 ioc = IBDM_GIDINFO2IOCINFO(gid_list, k);
5239 if (ioc->ioc_state == IBDM_IOC_STATE_PROBE_SUCCESS)
5240 ++count;
5241 }
5242 mutex_exit(&gid_list->gl_mutex);
5243 }
5244 ibdm.ibdm_busy &= ~IBDM_BUSY;
5245 cv_broadcast(&ibdm.ibdm_busy_cv);
5246 mutex_exit(&ibdm.ibdm_mutex);
5247
5248 IBTF_DPRINTF_L4("ibdm", "\tget_ioc_count: count = %d", count);
5249 return (count);
5250 }
5251
5252
5253 /*
5254 * ibdm_ibnex_get_ioc_list()
5255 * Returns information about all the IOCs present on the fabric.
5256 * Reprobes the IOCs and the GID list if list_flag is set to REPROBE_ALL.
5257 * Does not sweep fabric if DONOT_PROBE is set
5258 */
5259 ibdm_ioc_info_t *
ibdm_ibnex_get_ioc_list(ibdm_ibnex_get_ioclist_mtd_t list_flag)5260 ibdm_ibnex_get_ioc_list(ibdm_ibnex_get_ioclist_mtd_t list_flag)
5261 {
5262 int ii;
5263 ibdm_ioc_info_t *ioc_list = NULL, *tmp, *ioc;
5264 ibdm_dp_gidinfo_t *gid_list;
5265 ib_dm_io_unitinfo_t *iou;
5266
5267 IBTF_DPRINTF_L4("ibdm", "\tget_ioc_list: Enter");
5268
5269 if (ibdm_enumerate_iocs == 0)
5270 return (NULL);
5271
5272 mutex_enter(&ibdm.ibdm_mutex);
5273 if (list_flag != IBDM_IBNEX_DONOT_PROBE)
5274 ibdm_sweep_fabric(list_flag == IBDM_IBNEX_REPROBE_ALL);
5275
5276 while (ibdm.ibdm_busy & IBDM_BUSY)
5277 cv_wait(&ibdm.ibdm_busy_cv, &ibdm.ibdm_mutex);
5278 ibdm.ibdm_busy |= IBDM_BUSY;
5279
5280 gid_list = ibdm.ibdm_dp_gidlist_head;
5281 while (gid_list) {
5282 mutex_enter(&gid_list->gl_mutex);
5283 if (gid_list->gl_state != IBDM_GID_PROBING_COMPLETE) {
5284 mutex_exit(&gid_list->gl_mutex);
5285 gid_list = gid_list->gl_next;
5286 continue;
5287 }
5288 if (gid_list->gl_iou == NULL) {
5289 IBTF_DPRINTF_L2("ibdm",
5290 "\tget_ioc_list: No IOU info");
5291 mutex_exit(&gid_list->gl_mutex);
5292 gid_list = gid_list->gl_next;
5293 continue;
5294 }
5295 iou = &gid_list->gl_iou->iou_info;
5296 for (ii = 0; ii < iou->iou_num_ctrl_slots; ii++) {
5297 ioc = IBDM_GIDINFO2IOCINFO(gid_list, ii);
5298 if (ioc->ioc_state == IBDM_IOC_STATE_PROBE_SUCCESS) {
5299 tmp = ibdm_dup_ioc_info(ioc, gid_list);
5300 tmp->ioc_next = ioc_list;
5301 ioc_list = tmp;
5302 }
5303 }
5304 mutex_exit(&gid_list->gl_mutex);
5305 gid_list = gid_list->gl_next;
5306 }
5307 ibdm.ibdm_busy &= ~IBDM_BUSY;
5308 cv_broadcast(&ibdm.ibdm_busy_cv);
5309 mutex_exit(&ibdm.ibdm_mutex);
5310
5311 IBTF_DPRINTF_L4("ibdm", "\tget_ioc_list: End");
5312 return (ioc_list);
5313 }
5314
5315 /*
5316 * ibdm_dup_ioc_info()
5317 * Duplicate the IOC information and return the IOC
5318 * information.
5319 */
5320 static ibdm_ioc_info_t *
ibdm_dup_ioc_info(ibdm_ioc_info_t * in_ioc,ibdm_dp_gidinfo_t * gid_list)5321 ibdm_dup_ioc_info(ibdm_ioc_info_t *in_ioc, ibdm_dp_gidinfo_t *gid_list)
5322 {
5323 ibdm_ioc_info_t *out_ioc;
5324 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*out_ioc));
5325 ASSERT(MUTEX_HELD(&gid_list->gl_mutex));
5326
5327 out_ioc = kmem_alloc(sizeof (ibdm_ioc_info_t), KM_SLEEP);
5328 bcopy(in_ioc, out_ioc, sizeof (ibdm_ioc_info_t));
5329 ibdm_update_ioc_port_gidlist(out_ioc, gid_list);
5330 out_ioc->ioc_iou_dc_valid = gid_list->gl_iou->iou_dc_valid;
5331 out_ioc->ioc_iou_diagcode = gid_list->gl_iou->iou_diagcode;
5332
5333 return (out_ioc);
5334 }
5335
5336
5337 /*
5338 * ibdm_free_ioc_list()
5339 * Deallocate memory for IOC list structure
5340 */
5341 void
ibdm_ibnex_free_ioc_list(ibdm_ioc_info_t * ioc)5342 ibdm_ibnex_free_ioc_list(ibdm_ioc_info_t *ioc)
5343 {
5344 ibdm_ioc_info_t *temp;
5345
5346 IBTF_DPRINTF_L4("ibdm", "\tibnex_free_ioc_list:");
5347 while (ioc) {
5348 temp = ioc;
5349 ioc = ioc->ioc_next;
5350 kmem_free(temp->ioc_gid_list,
5351 (sizeof (ibdm_gid_t) * temp->ioc_nportgids));
5352 if (temp->ioc_hca_list)
5353 ibdm_ibnex_free_hca_list(temp->ioc_hca_list);
5354 kmem_free(temp, sizeof (ibdm_ioc_info_t));
5355 }
5356 }
5357
5358
5359 /*
5360 * ibdm_ibnex_update_pkey_tbls
5361 * Updates the DM P_Key database.
5362 * NOTE: Two cases are handled here: P_Key being added or removed.
5363 *
5364 * Arguments : NONE
5365 * Return Values : NONE
5366 */
5367 void
ibdm_ibnex_update_pkey_tbls(void)5368 ibdm_ibnex_update_pkey_tbls(void)
5369 {
5370 int h, pp, pidx;
5371 uint_t nports;
5372 uint_t size;
5373 ib_pkey_t new_pkey;
5374 ib_pkey_t *orig_pkey;
5375 ibdm_hca_list_t *hca_list;
5376 ibdm_port_attr_t *port;
5377 ibt_hca_portinfo_t *pinfop;
5378
5379 IBTF_DPRINTF_L4("ibdm", "\tibnex_update_pkey_tbls:");
5380
5381 mutex_enter(&ibdm.ibdm_hl_mutex);
5382 hca_list = ibdm.ibdm_hca_list_head;
5383
5384 for (h = 0; h < ibdm.ibdm_hca_count; h++) {
5385
5386 /* This updates P_Key Tables for all ports of this HCA */
5387 (void) ibt_query_hca_ports(hca_list->hl_hca_hdl, 0, &pinfop,
5388 &nports, &size);
5389
5390 /* number of ports shouldn't have changed */
5391 ASSERT(nports == hca_list->hl_nports);
5392
5393 for (pp = 0; pp < hca_list->hl_nports; pp++) {
5394 port = &hca_list->hl_port_attr[pp];
5395
5396 /*
5397 * First figure out the P_Keys from IBTL.
5398 * Three things could have happened:
5399 * New P_Keys added
5400 * Existing P_Keys removed
5401 * Both of the above two
5402 *
5403 * Loop through the P_Key Indices and check if a
5404 * give P_Key_Ix matches that of the one seen by
5405 * IBDM. If they match no action is needed.
5406 *
5407 * If they don't match:
5408 * 1. if orig_pkey is invalid and new_pkey is valid
5409 * ---> add new_pkey to DM database
5410 * 2. if orig_pkey is valid and new_pkey is invalid
5411 * ---> remove orig_pkey from DM database
5412 * 3. if orig_pkey and new_pkey are both valid:
5413 * ---> remov orig_pkey from DM database
5414 * ---> add new_pkey to DM database
5415 * 4. if orig_pkey and new_pkey are both invalid:
5416 * ---> do nothing. Updated DM database.
5417 */
5418
5419 for (pidx = 0; pidx < port->pa_npkeys; pidx++) {
5420 new_pkey = pinfop[pp].p_pkey_tbl[pidx];
5421 orig_pkey = &port->pa_pkey_tbl[pidx].pt_pkey;
5422
5423 /* keys match - do nothing */
5424 if (*orig_pkey == new_pkey)
5425 continue;
5426
5427 if (IBDM_INVALID_PKEY(*orig_pkey) &&
5428 !IBDM_INVALID_PKEY(new_pkey)) {
5429 /* P_Key was added */
5430 IBTF_DPRINTF_L5("ibdm",
5431 "\tibnex_update_pkey_tbls: new "
5432 "P_Key added = 0x%x", new_pkey);
5433 *orig_pkey = new_pkey;
5434 ibdm_port_attr_ibmf_init(port,
5435 new_pkey, pp);
5436 } else if (!IBDM_INVALID_PKEY(*orig_pkey) &&
5437 IBDM_INVALID_PKEY(new_pkey)) {
5438 /* P_Key was removed */
5439 IBTF_DPRINTF_L5("ibdm",
5440 "\tibnex_update_pkey_tbls: P_Key "
5441 "removed = 0x%x", *orig_pkey);
5442 *orig_pkey = new_pkey;
5443 (void) ibdm_port_attr_ibmf_fini(port,
5444 pidx);
5445 } else if (!IBDM_INVALID_PKEY(*orig_pkey) &&
5446 !IBDM_INVALID_PKEY(new_pkey)) {
5447 /* P_Key were replaced */
5448 IBTF_DPRINTF_L5("ibdm",
5449 "\tibnex_update_pkey_tbls: P_Key "
5450 "replaced 0x%x with 0x%x",
5451 *orig_pkey, new_pkey);
5452 (void) ibdm_port_attr_ibmf_fini(port,
5453 pidx);
5454 *orig_pkey = new_pkey;
5455 ibdm_port_attr_ibmf_init(port,
5456 new_pkey, pp);
5457 } else {
5458 /*
5459 * P_Keys are invalid
5460 * set anyway to reflect if
5461 * INVALID_FULL was changed to
5462 * INVALID_LIMITED or vice-versa.
5463 */
5464 *orig_pkey = new_pkey;
5465 } /* end of else */
5466
5467 } /* loop of p_key index */
5468
5469 } /* loop of #ports of HCA */
5470
5471 ibt_free_portinfo(pinfop, size);
5472 hca_list = hca_list->hl_next;
5473
5474 } /* loop for all HCAs in the system */
5475
5476 mutex_exit(&ibdm.ibdm_hl_mutex);
5477 }
5478
5479
5480 /*
5481 * ibdm_send_ioc_profile()
5482 * Send IOC Controller Profile request. When the request is completed
5483 * IBMF calls ibdm_process_incoming_mad routine to inform about
5484 * the completion.
5485 */
5486 static int
ibdm_send_ioc_profile(ibdm_dp_gidinfo_t * gid_info,uint8_t ioc_no)5487 ibdm_send_ioc_profile(ibdm_dp_gidinfo_t *gid_info, uint8_t ioc_no)
5488 {
5489 ibmf_msg_t *msg;
5490 ib_mad_hdr_t *hdr;
5491 ibdm_ioc_info_t *ioc_info = &(gid_info->gl_iou->iou_ioc_info[ioc_no]);
5492 ibdm_timeout_cb_args_t *cb_args;
5493
5494 IBTF_DPRINTF_L4("ibdm", "\tsend_ioc_profile: "
5495 "gid info 0x%p, ioc_no = %d", gid_info, ioc_no);
5496
5497 /*
5498 * Send command to get IOC profile.
5499 * Allocate a IBMF packet and initialize the packet.
5500 */
5501 if (ibmf_alloc_msg(gid_info->gl_ibmf_hdl, IBMF_ALLOC_SLEEP,
5502 &msg) != IBMF_SUCCESS) {
5503 IBTF_DPRINTF_L2("ibdm", "\tsend_ioc_profile: pkt alloc fail");
5504 return (IBDM_FAILURE);
5505 }
5506
5507 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*msg))
5508 ibdm_alloc_send_buffers(msg);
5509 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*msg))
5510
5511 mutex_enter(&gid_info->gl_mutex);
5512 ibdm_bump_transactionID(gid_info);
5513 mutex_exit(&gid_info->gl_mutex);
5514
5515 msg->im_local_addr.ia_local_lid = gid_info->gl_slid;
5516 msg->im_local_addr.ia_remote_lid = gid_info->gl_dlid;
5517 if (gid_info->gl_redirected == B_TRUE) {
5518 if (gid_info->gl_redirect_dlid != 0) {
5519 msg->im_local_addr.ia_remote_lid =
5520 gid_info->gl_redirect_dlid;
5521 }
5522 msg->im_local_addr.ia_remote_qno = gid_info->gl_redirect_QP;
5523 msg->im_local_addr.ia_p_key = gid_info->gl_redirect_pkey;
5524 msg->im_local_addr.ia_q_key = gid_info->gl_redirect_qkey;
5525 msg->im_local_addr.ia_service_level = gid_info->gl_redirectSL;
5526 } else {
5527 msg->im_local_addr.ia_remote_qno = 1;
5528 msg->im_local_addr.ia_p_key = gid_info->gl_p_key;
5529 msg->im_local_addr.ia_q_key = IB_GSI_QKEY;
5530 msg->im_local_addr.ia_service_level = gid_info->gl_SL;
5531 }
5532
5533 hdr = IBDM_OUT_IBMFMSG_MADHDR(msg);
5534 hdr->BaseVersion = MAD_CLASS_BASE_VERS_1;
5535 hdr->MgmtClass = MAD_MGMT_CLASS_DEV_MGT;
5536 hdr->ClassVersion = IB_DM_CLASS_VERSION_1;
5537 hdr->R_Method = IB_DM_DEVMGT_METHOD_GET;
5538 hdr->Status = 0;
5539 hdr->TransactionID = h2b64(gid_info->gl_transactionID);
5540 hdr->AttributeID = h2b16(IB_DM_ATTR_IOC_CTRL_PROFILE);
5541 hdr->AttributeModifier = h2b32(ioc_no + 1);
5542
5543 ioc_info->ioc_state = IBDM_IOC_STATE_REPROBE_PROGRESS;
5544 cb_args = &ioc_info->ioc_cb_args;
5545 cb_args->cb_gid_info = gid_info;
5546 cb_args->cb_retry_count = ibdm_dft_retry_cnt;
5547 cb_args->cb_req_type = IBDM_REQ_TYPE_IOCINFO;
5548 cb_args->cb_ioc_num = ioc_no;
5549
5550 mutex_enter(&gid_info->gl_mutex);
5551 ioc_info->ioc_timeout_id = timeout(ibdm_pkt_timeout_hdlr,
5552 cb_args, IBDM_TIMEOUT_VALUE(ibdm_dft_timeout));
5553 mutex_exit(&gid_info->gl_mutex);
5554
5555 IBTF_DPRINTF_L5("ibdm", "\tsend_ioc_profile:"
5556 "timeout %x", ioc_info->ioc_timeout_id);
5557
5558 if (ibmf_msg_transport(gid_info->gl_ibmf_hdl, gid_info->gl_qp_hdl, msg,
5559 NULL, ibdm_ibmf_send_cb, cb_args, 0) != IBMF_SUCCESS) {
5560 IBTF_DPRINTF_L2("ibdm",
5561 "\tsend_ioc_profile: msg transport failed");
5562 ibdm_ibmf_send_cb(gid_info->gl_ibmf_hdl, msg, cb_args);
5563 }
5564 ioc_info->ioc_state = IBDM_IOC_STATE_REPROBE_PROGRESS;
5565 return (IBDM_SUCCESS);
5566 }
5567
5568
5569 /*
5570 * ibdm_port_reachable
5571 * Returns B_TRUE if the port GID is reachable by sending
5572 * a SA query to get the NODE record for this port GUID.
5573 */
5574 static boolean_t
ibdm_port_reachable(ibmf_saa_handle_t sa_hdl,ib_guid_t guid)5575 ibdm_port_reachable(ibmf_saa_handle_t sa_hdl, ib_guid_t guid)
5576 {
5577 sa_node_record_t *resp;
5578 size_t length;
5579
5580 /*
5581 * Verify if it's reachable by getting the node record.
5582 */
5583 if (ibdm_get_node_record_by_port(sa_hdl, guid, &resp, &length) ==
5584 IBDM_SUCCESS) {
5585 kmem_free(resp, length);
5586 return (B_TRUE);
5587 }
5588 return (B_FALSE);
5589 }
5590
5591 /*
5592 * ibdm_get_node_record_by_port
5593 * Sends a SA query to get the NODE record for port GUID
5594 * Returns IBDM_SUCCESS if the port GID is reachable.
5595 *
5596 * Note: the caller must be responsible for freeing the resource
5597 * by calling kmem_free(resp, length) later.
5598 */
5599 static int
ibdm_get_node_record_by_port(ibmf_saa_handle_t sa_hdl,ib_guid_t guid,sa_node_record_t ** resp,size_t * length)5600 ibdm_get_node_record_by_port(ibmf_saa_handle_t sa_hdl, ib_guid_t guid,
5601 sa_node_record_t **resp, size_t *length)
5602 {
5603 sa_node_record_t req;
5604 ibmf_saa_access_args_t args;
5605 int ret;
5606 ASSERT(resp != NULL && length != NULL);
5607
5608 IBTF_DPRINTF_L4("ibdm", "\tport_reachable: port_guid %llx",
5609 guid);
5610
5611 bzero(&req, sizeof (sa_node_record_t));
5612 req.NodeInfo.PortGUID = guid;
5613
5614 args.sq_attr_id = SA_NODERECORD_ATTRID;
5615 args.sq_access_type = IBMF_SAA_RETRIEVE;
5616 args.sq_component_mask = SA_NODEINFO_COMPMASK_PORTGUID;
5617 args.sq_template = &req;
5618 args.sq_callback = NULL;
5619 args.sq_callback_arg = NULL;
5620
5621 ret = ibmf_sa_access(sa_hdl, &args, 0, length, (void **) resp);
5622 if (ret != IBMF_SUCCESS) {
5623 IBTF_DPRINTF_L2("ibdm", "\tport_reachable:"
5624 " SA Retrieve Failed: %d", ret);
5625 return (IBDM_FAILURE);
5626 }
5627 if (*resp == NULL || *length == 0) {
5628 IBTF_DPRINTF_L2("ibdm", "\tport_reachable: No records");
5629 return (IBDM_FAILURE);
5630 }
5631 /*
5632 * There is one NodeRecord on each endport on a subnet.
5633 */
5634 ASSERT(*length == sizeof (sa_node_record_t));
5635
5636 return (IBDM_SUCCESS);
5637 }
5638
5639
5640 /*
5641 * Update the gidlist for all affected IOCs when GID becomes
5642 * available/unavailable.
5643 *
5644 * Parameters :
5645 * gidinfo - Incoming / Outgoing GID.
5646 * add_flag - 1 for GID added, 0 for GID removed.
5647 * - (-1) : IOC gid list updated, ioc_list required.
5648 *
5649 * This function gets the GID for the node GUID corresponding to the
5650 * port GID. Gets the IOU info
5651 */
5652 static ibdm_ioc_info_t *
ibdm_update_ioc_gidlist(ibdm_dp_gidinfo_t * gid_info,int avail_flag)5653 ibdm_update_ioc_gidlist(ibdm_dp_gidinfo_t *gid_info, int avail_flag)
5654 {
5655 ibdm_dp_gidinfo_t *node_gid = NULL;
5656 uint8_t niocs, ii;
5657 ibdm_ioc_info_t *ioc, *ioc_list = NULL, *tmp;
5658
5659 IBTF_DPRINTF_L4("ibdm", "\tupdate_ioc_gidlist");
5660
5661 switch (avail_flag) {
5662 case 1 :
5663 node_gid = ibdm_check_dest_nodeguid(gid_info);
5664 break;
5665 case 0 :
5666 node_gid = ibdm_handle_gid_rm(gid_info);
5667 break;
5668 case -1 :
5669 node_gid = gid_info;
5670 break;
5671 default :
5672 break;
5673 }
5674
5675 if (node_gid == NULL) {
5676 IBTF_DPRINTF_L4("ibdm", "\tupdate_ioc_gidlist: "
5677 "No node GID found, port gid 0x%p, avail_flag %d",
5678 gid_info, avail_flag);
5679 return (NULL);
5680 }
5681
5682 mutex_enter(&node_gid->gl_mutex);
5683 if ((node_gid->gl_state != IBDM_GID_PROBING_COMPLETE &&
5684 node_gid->gl_state != IBDM_GID_PROBING_SKIPPED) ||
5685 node_gid->gl_iou == NULL) {
5686 IBTF_DPRINTF_L4("ibdm", "\tupdate_ioc_gidlist "
5687 "gl_state %x, gl_iou %p", node_gid->gl_state,
5688 node_gid->gl_iou);
5689 mutex_exit(&node_gid->gl_mutex);
5690 return (NULL);
5691 }
5692
5693 niocs = node_gid->gl_iou->iou_info.iou_num_ctrl_slots;
5694 IBTF_DPRINTF_L4("ibdm", "\tupdate_ioc_gidlist : niocs %x",
5695 niocs);
5696 for (ii = 0; ii < niocs; ii++) {
5697 ioc = IBDM_GIDINFO2IOCINFO(node_gid, ii);
5698 /*
5699 * Skip IOCs for which probe is not complete or
5700 * reprobe is progress
5701 */
5702 if (ioc->ioc_state == IBDM_IOC_STATE_PROBE_SUCCESS) {
5703 tmp = ibdm_dup_ioc_info(ioc, node_gid);
5704 tmp->ioc_info_updated.ib_gid_prop_updated = 1;
5705 tmp->ioc_next = ioc_list;
5706 ioc_list = tmp;
5707 }
5708 }
5709 mutex_exit(&node_gid->gl_mutex);
5710
5711 IBTF_DPRINTF_L4("ibdm", "\tupdate_ioc_gidlist : return %p",
5712 ioc_list);
5713 return (ioc_list);
5714 }
5715
5716 /*
5717 * ibdm_saa_event_cb :
5718 * Event handling which does *not* require ibdm_hl_mutex to be
5719 * held are executed in the same thread. This is to prevent
5720 * deadlocks with HCA port down notifications which hold the
5721 * ibdm_hl_mutex.
5722 *
5723 * GID_AVAILABLE event is handled here. A taskq is spawned to
5724 * handle GID_UNAVAILABLE.
5725 *
5726 * A new mutex ibdm_ibnex_mutex has been introduced to protect
5727 * ibnex_callback. This has been done to prevent any possible
5728 * deadlock (described above) while handling GID_AVAILABLE.
5729 *
5730 * IBMF calls the event callback for a HCA port. The SA handle
5731 * for this port would be valid, till the callback returns.
5732 * IBDM calling IBDM using the above SA handle should be valid.
5733 *
5734 * IBDM will additionally check (SA handle != NULL), before
5735 * calling IBMF.
5736 */
5737 /*ARGSUSED*/
5738 static void
ibdm_saa_event_cb(ibmf_saa_handle_t ibmf_saa_handle,ibmf_saa_subnet_event_t ibmf_saa_event,ibmf_saa_event_details_t * event_details,void * callback_arg)5739 ibdm_saa_event_cb(ibmf_saa_handle_t ibmf_saa_handle,
5740 ibmf_saa_subnet_event_t ibmf_saa_event,
5741 ibmf_saa_event_details_t *event_details, void *callback_arg)
5742 {
5743 ibdm_saa_event_arg_t *event_arg;
5744 ib_gid_t sgid, dgid;
5745 ibdm_port_attr_t *hca_port;
5746 ibdm_dp_gidinfo_t *gid_info, *node_gid_info = NULL;
5747 sa_node_record_t *nrec;
5748 size_t length;
5749
5750 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*event_arg));
5751
5752 hca_port = (ibdm_port_attr_t *)callback_arg;
5753
5754 IBTF_DPRINTF_L4("ibdm", "\tsaa_event_cb(%x, %x, %x, %x)\n",
5755 ibmf_saa_handle, ibmf_saa_event, event_details,
5756 callback_arg);
5757
5758 #ifdef DEBUG
5759 if (ibdm_ignore_saa_event)
5760 return;
5761 #endif
5762
5763 if (ibmf_saa_event == IBMF_SAA_EVENT_GID_AVAILABLE) {
5764 /*
5765 * Ensure no other probe / sweep fabric is in
5766 * progress.
5767 */
5768 mutex_enter(&ibdm.ibdm_mutex);
5769 while (ibdm.ibdm_busy & IBDM_BUSY)
5770 cv_wait(&ibdm.ibdm_busy_cv, &ibdm.ibdm_mutex);
5771 ibdm.ibdm_busy |= IBDM_BUSY;
5772 mutex_exit(&ibdm.ibdm_mutex);
5773
5774 /*
5775 * If we already know about this GID, return.
5776 * GID_AVAILABLE may be reported for multiple HCA
5777 * ports.
5778 */
5779 if ((ibdm_check_dgid(event_details->ie_gid.gid_guid,
5780 event_details->ie_gid.gid_prefix)) != NULL) {
5781 mutex_enter(&ibdm.ibdm_mutex);
5782 ibdm.ibdm_busy &= ~IBDM_BUSY;
5783 cv_broadcast(&ibdm.ibdm_busy_cv);
5784 mutex_exit(&ibdm.ibdm_mutex);
5785 return;
5786 }
5787
5788 IBTF_DPRINTF_L4("ibdm", "\tGID (prefix %x, guid %llx) "
5789 "Insertion notified",
5790 event_details->ie_gid.gid_prefix,
5791 event_details->ie_gid.gid_guid);
5792
5793 /* This is a new gid, insert it to GID list */
5794 sgid.gid_prefix = hca_port->pa_sn_prefix;
5795 sgid.gid_guid = hca_port->pa_port_guid;
5796 dgid.gid_prefix = event_details->ie_gid.gid_prefix;
5797 dgid.gid_guid = event_details->ie_gid.gid_guid;
5798 gid_info = ibdm_create_gid_info(hca_port, sgid, dgid);
5799 if (gid_info == NULL) {
5800 IBTF_DPRINTF_L4("ibdm", "\tGID_AVAILABLE: "
5801 "create_gid_info returned NULL");
5802 mutex_enter(&ibdm.ibdm_mutex);
5803 ibdm.ibdm_busy &= ~IBDM_BUSY;
5804 cv_broadcast(&ibdm.ibdm_busy_cv);
5805 mutex_exit(&ibdm.ibdm_mutex);
5806 return;
5807 }
5808 mutex_enter(&gid_info->gl_mutex);
5809 gid_info->gl_state = IBDM_GID_PROBING_SKIPPED;
5810 mutex_exit(&gid_info->gl_mutex);
5811
5812 /* Get the node GUID */
5813 if (ibdm_get_node_record_by_port(ibmf_saa_handle, dgid.gid_guid,
5814 &nrec, &length) != IBDM_SUCCESS) {
5815 /*
5816 * Set the state to PROBE_NOT_DONE for the
5817 * next sweep to probe it
5818 */
5819 IBTF_DPRINTF_L2("ibdm", "\tsaa_event_taskq: "
5820 "Skipping GID : port GUID not found");
5821 mutex_enter(&gid_info->gl_mutex);
5822 gid_info->gl_state = IBDM_GID_PROBE_NOT_DONE;
5823 mutex_exit(&gid_info->gl_mutex);
5824 mutex_enter(&ibdm.ibdm_mutex);
5825 ibdm.ibdm_busy &= ~IBDM_BUSY;
5826 cv_broadcast(&ibdm.ibdm_busy_cv);
5827 mutex_exit(&ibdm.ibdm_mutex);
5828 return;
5829 }
5830 gid_info->gl_nodeguid = nrec->NodeInfo.NodeGUID;
5831 gid_info->gl_devid = nrec->NodeInfo.DeviceID;
5832 kmem_free(nrec, length);
5833 gid_info->gl_portguid = dgid.gid_guid;
5834
5835 /*
5836 * Get the gid info with the same node GUID.
5837 */
5838 mutex_enter(&ibdm.ibdm_mutex);
5839 node_gid_info = ibdm.ibdm_dp_gidlist_head;
5840 while (node_gid_info) {
5841 if (node_gid_info->gl_nodeguid ==
5842 gid_info->gl_nodeguid &&
5843 node_gid_info->gl_iou != NULL) {
5844 break;
5845 }
5846 node_gid_info = node_gid_info->gl_next;
5847 }
5848 mutex_exit(&ibdm.ibdm_mutex);
5849
5850 /*
5851 * Handling a new GID requires filling of gl_hca_list.
5852 * This require ibdm hca_list to be parsed and hence
5853 * holding the ibdm_hl_mutex. Spawning a new thread to
5854 * handle this.
5855 */
5856 if (node_gid_info == NULL) {
5857 if (taskq_dispatch(system_taskq,
5858 ibdm_saa_handle_new_gid, (void *)gid_info,
5859 TQ_NOSLEEP) == NULL) {
5860 IBTF_DPRINTF_L2("ibdm", "\tsaa_event_cb: "
5861 "new_gid taskq_dispatch failed");
5862 return;
5863 }
5864 }
5865
5866 mutex_enter(&ibdm.ibdm_mutex);
5867 ibdm.ibdm_busy &= ~IBDM_BUSY;
5868 cv_broadcast(&ibdm.ibdm_busy_cv);
5869 mutex_exit(&ibdm.ibdm_mutex);
5870 return;
5871 }
5872
5873 if (ibmf_saa_event != IBMF_SAA_EVENT_GID_UNAVAILABLE)
5874 return;
5875
5876 /*
5877 * GID UNAVAIL EVENT: Try to locate the GID in the GID list.
5878 * If we don't find it we just return.
5879 */
5880 mutex_enter(&ibdm.ibdm_mutex);
5881 gid_info = ibdm.ibdm_dp_gidlist_head;
5882 while (gid_info) {
5883 if (gid_info->gl_portguid ==
5884 event_details->ie_gid.gid_guid) {
5885 break;
5886 }
5887 gid_info = gid_info->gl_next;
5888 }
5889 mutex_exit(&ibdm.ibdm_mutex);
5890 if (gid_info == NULL) {
5891 IBTF_DPRINTF_L2("ibdm", "\tsaa_event_cb: "
5892 "GID for GUID %llX not found during GID UNAVAIL event",
5893 event_details->ie_gid.gid_guid);
5894 return;
5895 }
5896
5897 /*
5898 * If this GID is DM capable, we'll have to check whether this DGID
5899 * is reachable via another port.
5900 */
5901 if (gid_info->gl_is_dm_capable == B_TRUE) {
5902 event_arg = (ibdm_saa_event_arg_t *)kmem_alloc(
5903 sizeof (ibdm_saa_event_arg_t), KM_SLEEP);
5904 event_arg->ibmf_saa_handle = ibmf_saa_handle;
5905 event_arg->ibmf_saa_event = ibmf_saa_event;
5906 bcopy(event_details, &event_arg->event_details,
5907 sizeof (ibmf_saa_event_details_t));
5908 event_arg->callback_arg = callback_arg;
5909
5910 if (taskq_dispatch(system_taskq, ibdm_saa_event_taskq,
5911 (void *)event_arg, TQ_NOSLEEP) == NULL) {
5912 IBTF_DPRINTF_L2("ibdm", "\tsaa_event_cb: "
5913 "taskq_dispatch failed");
5914 ibdm_free_saa_event_arg(event_arg);
5915 return;
5916 }
5917 }
5918 }
5919
5920 /*
5921 * Handle a new GID discovered by GID_AVAILABLE saa event.
5922 */
5923 void
ibdm_saa_handle_new_gid(void * arg)5924 ibdm_saa_handle_new_gid(void *arg)
5925 {
5926 ibdm_dp_gidinfo_t *gid_info;
5927 ibdm_hca_list_t *hca_list = NULL;
5928 ibdm_port_attr_t *port = NULL;
5929 ibdm_ioc_info_t *ioc_list = NULL;
5930
5931 IBTF_DPRINTF_L4(ibdm_string, "\tsaa_handle_new_gid(%p)", arg);
5932
5933 gid_info = (ibdm_dp_gidinfo_t *)arg;
5934
5935 /*
5936 * Ensure that no other sweep / probe has completed
5937 * probing this gid.
5938 */
5939 mutex_enter(&gid_info->gl_mutex);
5940 if (gid_info->gl_state != IBDM_GID_PROBE_NOT_DONE) {
5941 mutex_exit(&gid_info->gl_mutex);
5942 return;
5943 }
5944 mutex_exit(&gid_info->gl_mutex);
5945
5946 /*
5947 * Parse HCAs to fill gl_hca_list
5948 */
5949 mutex_enter(&ibdm.ibdm_hl_mutex);
5950 for (ibdm_get_next_port(&hca_list, &port, 1); port;
5951 ibdm_get_next_port(&hca_list, &port, 1)) {
5952 if (ibdm_port_reachable(port->pa_sa_hdl,
5953 gid_info->gl_portguid) == B_TRUE) {
5954 ibdm_addto_glhcalist(gid_info, hca_list);
5955 }
5956 }
5957 mutex_exit(&ibdm.ibdm_hl_mutex);
5958
5959 /*
5960 * Ensure no other probe / sweep fabric is in
5961 * progress.
5962 */
5963 mutex_enter(&ibdm.ibdm_mutex);
5964 while (ibdm.ibdm_busy & IBDM_BUSY)
5965 cv_wait(&ibdm.ibdm_busy_cv, &ibdm.ibdm_mutex);
5966 ibdm.ibdm_busy |= IBDM_BUSY;
5967 mutex_exit(&ibdm.ibdm_mutex);
5968
5969 /*
5970 * New IOU probe it, to check if new IOCs
5971 */
5972 IBTF_DPRINTF_L4(ibdm_string, "\tsaa_handle_new_gid: "
5973 "new GID : probing");
5974 mutex_enter(&ibdm.ibdm_mutex);
5975 ibdm.ibdm_ngid_probes_in_progress++;
5976 mutex_exit(&ibdm.ibdm_mutex);
5977 mutex_enter(&gid_info->gl_mutex);
5978 gid_info->gl_reprobe_flag = 0;
5979 gid_info->gl_state = IBDM_GID_PROBE_NOT_DONE;
5980 mutex_exit(&gid_info->gl_mutex);
5981 ibdm_probe_gid_thread((void *)gid_info);
5982
5983 mutex_enter(&ibdm.ibdm_mutex);
5984 ibdm_wait_probe_completion();
5985 mutex_exit(&ibdm.ibdm_mutex);
5986
5987 if (gid_info->gl_iou == NULL) {
5988 mutex_enter(&ibdm.ibdm_mutex);
5989 ibdm.ibdm_busy &= ~IBDM_BUSY;
5990 cv_broadcast(&ibdm.ibdm_busy_cv);
5991 mutex_exit(&ibdm.ibdm_mutex);
5992 return;
5993 }
5994
5995 /*
5996 * Update GID list in all IOCs affected by this
5997 */
5998 ioc_list = ibdm_update_ioc_gidlist(gid_info, 1);
5999
6000 /*
6001 * Pass on the IOCs with updated GIDs to IBnexus
6002 */
6003 if (ioc_list) {
6004 mutex_enter(&ibdm.ibdm_ibnex_mutex);
6005 if (ibdm.ibdm_ibnex_callback != NULL) {
6006 (*ibdm.ibdm_ibnex_callback)((void *)ioc_list,
6007 IBDM_EVENT_IOC_PROP_UPDATE);
6008 }
6009 mutex_exit(&ibdm.ibdm_ibnex_mutex);
6010 }
6011
6012 mutex_enter(&ibdm.ibdm_mutex);
6013 ibdm.ibdm_busy &= ~IBDM_BUSY;
6014 cv_broadcast(&ibdm.ibdm_busy_cv);
6015 mutex_exit(&ibdm.ibdm_mutex);
6016 }
6017
6018 /*
6019 * ibdm_saa_event_taskq :
6020 * GID_UNAVAILABLE Event handling requires ibdm_hl_mutex to be
6021 * held. The GID_UNAVAILABLE handling is done in a taskq to
6022 * prevent deadlocks with HCA port down notifications which hold
6023 * ibdm_hl_mutex.
6024 */
6025 void
ibdm_saa_event_taskq(void * arg)6026 ibdm_saa_event_taskq(void *arg)
6027 {
6028 ibdm_saa_event_arg_t *event_arg;
6029 ibmf_saa_handle_t ibmf_saa_handle;
6030 ibmf_saa_subnet_event_t ibmf_saa_event;
6031 ibmf_saa_event_details_t *event_details;
6032 void *callback_arg;
6033
6034 ibdm_dp_gidinfo_t *gid_info;
6035 ibdm_port_attr_t *hca_port, *port = NULL;
6036 ibdm_hca_list_t *hca_list = NULL;
6037 int sa_handle_valid = 0;
6038 ibdm_ioc_info_t *ioc_list = NULL;
6039
6040 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*event_arg));
6041
6042 event_arg = (ibdm_saa_event_arg_t *)arg;
6043 ibmf_saa_handle = event_arg->ibmf_saa_handle;
6044 ibmf_saa_event = event_arg->ibmf_saa_event;
6045 event_details = &event_arg->event_details;
6046 callback_arg = event_arg->callback_arg;
6047
6048 ASSERT(callback_arg != NULL);
6049 ASSERT(ibmf_saa_event == IBMF_SAA_EVENT_GID_UNAVAILABLE);
6050 IBTF_DPRINTF_L4("ibdm", "\tsaa_event_taskq(%x, %x, %x, %x)",
6051 ibmf_saa_handle, ibmf_saa_event, event_details,
6052 callback_arg);
6053
6054 hca_port = (ibdm_port_attr_t *)callback_arg;
6055
6056 /* Check if the port_attr is still valid */
6057 mutex_enter(&ibdm.ibdm_hl_mutex);
6058 for (ibdm_get_next_port(&hca_list, &port, 0); port;
6059 ibdm_get_next_port(&hca_list, &port, 0)) {
6060 if (port == hca_port && port->pa_port_guid ==
6061 hca_port->pa_port_guid) {
6062 if (ibmf_saa_handle == hca_port->pa_sa_hdl)
6063 sa_handle_valid = 1;
6064 break;
6065 }
6066 }
6067 mutex_exit(&ibdm.ibdm_hl_mutex);
6068 if (sa_handle_valid == 0) {
6069 ibdm_free_saa_event_arg(event_arg);
6070 return;
6071 }
6072
6073 if (hca_port && (hca_port->pa_sa_hdl == NULL ||
6074 ibmf_saa_handle != hca_port->pa_sa_hdl)) {
6075 ibdm_free_saa_event_arg(event_arg);
6076 return;
6077 }
6078 hca_list = NULL;
6079 port = NULL;
6080
6081 /*
6082 * Check if the GID is visible to other HCA ports.
6083 * Return if so.
6084 */
6085 mutex_enter(&ibdm.ibdm_hl_mutex);
6086 for (ibdm_get_next_port(&hca_list, &port, 1); port;
6087 ibdm_get_next_port(&hca_list, &port, 1)) {
6088 if (ibdm_port_reachable(port->pa_sa_hdl,
6089 event_details->ie_gid.gid_guid) == B_TRUE) {
6090 mutex_exit(&ibdm.ibdm_hl_mutex);
6091 ibdm_free_saa_event_arg(event_arg);
6092 return;
6093 }
6094 }
6095 mutex_exit(&ibdm.ibdm_hl_mutex);
6096
6097 /*
6098 * Ensure no other probe / sweep fabric is in
6099 * progress.
6100 */
6101 mutex_enter(&ibdm.ibdm_mutex);
6102 while (ibdm.ibdm_busy & IBDM_BUSY)
6103 cv_wait(&ibdm.ibdm_busy_cv, &ibdm.ibdm_mutex);
6104 ibdm.ibdm_busy |= IBDM_BUSY;
6105 mutex_exit(&ibdm.ibdm_mutex);
6106
6107 /*
6108 * If this GID is no longer in GID list, return
6109 * GID_UNAVAILABLE may be reported for multiple HCA
6110 * ports.
6111 */
6112 mutex_enter(&ibdm.ibdm_mutex);
6113 gid_info = ibdm.ibdm_dp_gidlist_head;
6114 while (gid_info) {
6115 if (gid_info->gl_portguid ==
6116 event_details->ie_gid.gid_guid) {
6117 break;
6118 }
6119 gid_info = gid_info->gl_next;
6120 }
6121 mutex_exit(&ibdm.ibdm_mutex);
6122 if (gid_info == NULL) {
6123 mutex_enter(&ibdm.ibdm_mutex);
6124 ibdm.ibdm_busy &= ~IBDM_BUSY;
6125 cv_broadcast(&ibdm.ibdm_busy_cv);
6126 mutex_exit(&ibdm.ibdm_mutex);
6127 ibdm_free_saa_event_arg(event_arg);
6128 return;
6129 }
6130
6131 IBTF_DPRINTF_L4("ibdm", "\tGID (prefix %x, guid %llx) "
6132 "Unavailable notification",
6133 event_details->ie_gid.gid_prefix,
6134 event_details->ie_gid.gid_guid);
6135
6136 /*
6137 * Update GID list in all IOCs affected by this
6138 */
6139 if (gid_info->gl_state == IBDM_GID_PROBING_SKIPPED ||
6140 gid_info->gl_state == IBDM_GID_PROBING_COMPLETE)
6141 ioc_list = ibdm_update_ioc_gidlist(gid_info, 0);
6142
6143 /*
6144 * Remove GID from the global GID list
6145 * Handle the case where all port GIDs for an
6146 * IOU have been hot-removed. Check both gid_info
6147 * & ioc_info for checking ngids.
6148 */
6149 mutex_enter(&ibdm.ibdm_mutex);
6150 if (gid_info->gl_iou != NULL && gid_info->gl_ngids == 0) {
6151 mutex_enter(&gid_info->gl_mutex);
6152 (void) ibdm_free_iou_info(gid_info, &gid_info->gl_iou);
6153 mutex_exit(&gid_info->gl_mutex);
6154 }
6155 if (gid_info->gl_prev != NULL)
6156 gid_info->gl_prev->gl_next = gid_info->gl_next;
6157 if (gid_info->gl_next != NULL)
6158 gid_info->gl_next->gl_prev = gid_info->gl_prev;
6159
6160 if (gid_info == ibdm.ibdm_dp_gidlist_head)
6161 ibdm.ibdm_dp_gidlist_head = gid_info->gl_next;
6162 if (gid_info == ibdm.ibdm_dp_gidlist_tail)
6163 ibdm.ibdm_dp_gidlist_tail = gid_info->gl_prev;
6164 ibdm.ibdm_ngids--;
6165
6166 ibdm.ibdm_busy &= ~IBDM_BUSY;
6167 cv_broadcast(&ibdm.ibdm_busy_cv);
6168 mutex_exit(&ibdm.ibdm_mutex);
6169
6170 /* free the hca_list on this gid_info */
6171 ibdm_delete_glhca_list(gid_info);
6172
6173 mutex_destroy(&gid_info->gl_mutex);
6174 kmem_free(gid_info, sizeof (ibdm_dp_gidinfo_t));
6175
6176 /*
6177 * Pass on the IOCs with updated GIDs to IBnexus
6178 */
6179 if (ioc_list) {
6180 IBTF_DPRINTF_L4("ibdm", "\tGID_UNAVAILABLE "
6181 "IOC_PROP_UPDATE for %p\n", ioc_list);
6182 mutex_enter(&ibdm.ibdm_ibnex_mutex);
6183 if (ibdm.ibdm_ibnex_callback != NULL) {
6184 (*ibdm.ibdm_ibnex_callback)((void *)
6185 ioc_list, IBDM_EVENT_IOC_PROP_UPDATE);
6186 }
6187 mutex_exit(&ibdm.ibdm_ibnex_mutex);
6188 }
6189
6190 ibdm_free_saa_event_arg(event_arg);
6191 }
6192
6193
6194 static int
ibdm_cmp_gid_list(ibdm_gid_t * new,ibdm_gid_t * prev)6195 ibdm_cmp_gid_list(ibdm_gid_t *new, ibdm_gid_t *prev)
6196 {
6197 ibdm_gid_t *scan_new, *scan_prev;
6198 int cmp_failed = 0;
6199
6200 ASSERT(new != NULL);
6201 ASSERT(prev != NULL);
6202
6203 /*
6204 * Search for each new gid anywhere in the prev GID list.
6205 * Note that the gid list could have been re-ordered.
6206 */
6207 for (scan_new = new; scan_new; scan_new = scan_new->gid_next) {
6208 for (scan_prev = prev, cmp_failed = 1; scan_prev;
6209 scan_prev = scan_prev->gid_next) {
6210 if (scan_prev->gid_dgid_hi == scan_new->gid_dgid_hi &&
6211 scan_prev->gid_dgid_lo == scan_new->gid_dgid_lo) {
6212 cmp_failed = 0;
6213 break;
6214 }
6215 }
6216
6217 if (cmp_failed)
6218 return (1);
6219 }
6220 return (0);
6221 }
6222
6223 /*
6224 * This is always called in a single thread
6225 * This function updates the gid_list and serv_list of IOC
6226 * The current gid_list is in ioc_info_t(contains only port
6227 * guids for which probe is done) & gidinfo_t(other port gids)
6228 * The gids in both locations are used for comparision.
6229 */
6230 static void
ibdm_reprobe_update_port_srv(ibdm_ioc_info_t * ioc,ibdm_dp_gidinfo_t * gidinfo)6231 ibdm_reprobe_update_port_srv(ibdm_ioc_info_t *ioc, ibdm_dp_gidinfo_t *gidinfo)
6232 {
6233 ibdm_gid_t *cur_gid_list;
6234 uint_t cur_nportgids;
6235
6236 ASSERT(MUTEX_HELD(&ibdm.ibdm_mutex));
6237
6238 ioc->ioc_info_updated.ib_prop_updated = 0;
6239
6240
6241 /* Current GID list in gid_info only */
6242 cur_gid_list = gidinfo->gl_gid;
6243 cur_nportgids = gidinfo->gl_ngids;
6244
6245 if (ioc->ioc_prev_serv_cnt !=
6246 ioc->ioc_profile.ioc_service_entries ||
6247 ibdm_serv_cmp(&ioc->ioc_serv[0], &ioc->ioc_prev_serv[0],
6248 ioc->ioc_prev_serv_cnt))
6249 ioc->ioc_info_updated.ib_srv_prop_updated = 1;
6250
6251 if (ioc->ioc_prev_nportgids != cur_nportgids ||
6252 ioc->ioc_prev_gid_list == NULL || cur_gid_list == NULL) {
6253 ioc->ioc_info_updated.ib_gid_prop_updated = 1;
6254 } else if (ibdm_cmp_gid_list(ioc->ioc_prev_gid_list, cur_gid_list)) {
6255 ioc->ioc_info_updated.ib_gid_prop_updated = 1;
6256 }
6257
6258 /* Zero out previous entries */
6259 ibdm_free_gid_list(ioc->ioc_prev_gid_list);
6260 if (ioc->ioc_prev_serv)
6261 kmem_free(ioc->ioc_prev_serv, ioc->ioc_prev_serv_cnt *
6262 sizeof (ibdm_srvents_info_t));
6263 ioc->ioc_prev_serv_cnt = 0;
6264 ioc->ioc_prev_nportgids = 0;
6265 ioc->ioc_prev_serv = NULL;
6266 ioc->ioc_prev_gid_list = NULL;
6267 }
6268
6269 /*
6270 * Handle GID removal. This returns gid_info of an GID for the same
6271 * node GUID, if found. For an GID with IOU information, the same
6272 * gid_info is returned if no gid_info with same node_guid is found.
6273 */
6274 static ibdm_dp_gidinfo_t *
ibdm_handle_gid_rm(ibdm_dp_gidinfo_t * rm_gid)6275 ibdm_handle_gid_rm(ibdm_dp_gidinfo_t *rm_gid)
6276 {
6277 ibdm_dp_gidinfo_t *gid_list;
6278
6279 IBTF_DPRINTF_L4("ibdm", "\thandle_gid_rm(0x%p)", rm_gid);
6280
6281 if (rm_gid->gl_iou == NULL) {
6282 IBTF_DPRINTF_L4("ibdm", "\thandle_gid_rm NO iou");
6283 /*
6284 * Search for a GID with same node_guid and
6285 * gl_iou != NULL
6286 */
6287 for (gid_list = ibdm.ibdm_dp_gidlist_head; gid_list;
6288 gid_list = gid_list->gl_next) {
6289 if (gid_list->gl_iou != NULL && (gid_list->gl_nodeguid
6290 == rm_gid->gl_nodeguid))
6291 break;
6292 }
6293
6294 if (gid_list)
6295 ibdm_rmfrom_glgid_list(gid_list, rm_gid);
6296
6297 IBTF_DPRINTF_L4("ibdm", "\thandle_gid_rm ret %p", gid_list);
6298 return (gid_list);
6299 } else {
6300 /*
6301 * Search for a GID with same node_guid and
6302 * gl_iou == NULL
6303 */
6304 IBTF_DPRINTF_L4("ibdm", "\thandle_gid_rm with iou");
6305 for (gid_list = ibdm.ibdm_dp_gidlist_head; gid_list;
6306 gid_list = gid_list->gl_next) {
6307 if (gid_list->gl_iou == NULL && (gid_list->gl_nodeguid
6308 == rm_gid->gl_nodeguid))
6309 break;
6310 }
6311
6312 if (gid_list) {
6313 /*
6314 * Copy the following fields from rm_gid :
6315 * 1. gl_state
6316 * 2. gl_iou
6317 * 3. gl_gid & gl_ngids
6318 *
6319 * Note : Function is synchronized by
6320 * ibdm_busy flag.
6321 *
6322 * Note : Redirect info is initialized if
6323 * any MADs for the GID fail
6324 */
6325 IBTF_DPRINTF_L4("ibdm", "\thandle_gid_rm "
6326 "copying info to GID with gl_iou != NULl");
6327 gid_list->gl_state = rm_gid->gl_state;
6328 gid_list->gl_iou = rm_gid->gl_iou;
6329 gid_list->gl_gid = rm_gid->gl_gid;
6330 gid_list->gl_ngids = rm_gid->gl_ngids;
6331
6332 /* Remove the GID from gl_gid list */
6333 ibdm_rmfrom_glgid_list(gid_list, rm_gid);
6334 } else {
6335 /*
6336 * Handle a case where all GIDs to the IOU have
6337 * been removed.
6338 */
6339 IBTF_DPRINTF_L4("ibdm", "\thandle_gid_rm 0 GID "
6340 "to IOU");
6341
6342 ibdm_rmfrom_glgid_list(rm_gid, rm_gid);
6343 return (rm_gid);
6344 }
6345 IBTF_DPRINTF_L4("ibdm", "\thandle_gid_rm ret %p", gid_list);
6346 return (gid_list);
6347 }
6348 }
6349
6350 static void
ibdm_rmfrom_glgid_list(ibdm_dp_gidinfo_t * gid_info,ibdm_dp_gidinfo_t * rm_gid)6351 ibdm_rmfrom_glgid_list(ibdm_dp_gidinfo_t *gid_info,
6352 ibdm_dp_gidinfo_t *rm_gid)
6353 {
6354 ibdm_gid_t *tmp, *prev;
6355
6356 IBTF_DPRINTF_L4("ibdm", "\trmfrom_glgid (%p, %p)",
6357 gid_info, rm_gid);
6358
6359 for (tmp = gid_info->gl_gid, prev = NULL; tmp; ) {
6360 if (tmp->gid_dgid_hi == rm_gid->gl_dgid_hi &&
6361 tmp->gid_dgid_lo == rm_gid->gl_dgid_lo) {
6362 if (prev == NULL)
6363 gid_info->gl_gid = tmp->gid_next;
6364 else
6365 prev->gid_next = tmp->gid_next;
6366
6367 kmem_free(tmp, sizeof (ibdm_gid_t));
6368 gid_info->gl_ngids--;
6369 break;
6370 } else {
6371 prev = tmp;
6372 tmp = tmp->gid_next;
6373 }
6374 }
6375 }
6376
6377 static void
ibdm_addto_gidlist(ibdm_gid_t ** src_ptr,ibdm_gid_t * dest)6378 ibdm_addto_gidlist(ibdm_gid_t **src_ptr, ibdm_gid_t *dest)
6379 {
6380 ibdm_gid_t *head = NULL, *new, *tail;
6381
6382 /* First copy the destination */
6383 for (; dest; dest = dest->gid_next) {
6384 new = kmem_zalloc(sizeof (ibdm_gid_t), KM_SLEEP);
6385 new->gid_dgid_hi = dest->gid_dgid_hi;
6386 new->gid_dgid_lo = dest->gid_dgid_lo;
6387 new->gid_next = head;
6388 head = new;
6389 }
6390
6391 /* Insert this to the source */
6392 if (*src_ptr == NULL)
6393 *src_ptr = head;
6394 else {
6395 for (tail = *src_ptr; tail->gid_next != NULL;
6396 tail = tail->gid_next)
6397 ;
6398
6399 tail->gid_next = head;
6400 }
6401 }
6402
6403 static void
ibdm_free_gid_list(ibdm_gid_t * head)6404 ibdm_free_gid_list(ibdm_gid_t *head)
6405 {
6406 ibdm_gid_t *delete;
6407
6408 for (delete = head; delete; ) {
6409 head = delete->gid_next;
6410 kmem_free(delete, sizeof (ibdm_gid_t));
6411 delete = head;
6412 }
6413 }
6414
6415 /*
6416 * This function rescans the DM capable GIDs (gl_state is
6417 * GID_PROBE_COMPLETE or IBDM_GID_PROBING_SKIPPED.This
6418 * basically checks if the DM capable GID is reachable. If
6419 * not this is handled the same way as GID_UNAVAILABLE,
6420 * except that notifications are not send to IBnexus.
6421 *
6422 * This function also initializes the ioc_prev_list for
6423 * a particular IOC (when called from probe_ioc, with
6424 * ioc_guidp != NULL) or all IOCs for the gid (called from
6425 * sweep_fabric, ioc_guidp == NULL).
6426 */
6427 static void
ibdm_rescan_gidlist(ib_guid_t * ioc_guidp)6428 ibdm_rescan_gidlist(ib_guid_t *ioc_guidp)
6429 {
6430 ibdm_dp_gidinfo_t *gid_info, *tmp;
6431 int ii, niocs, found;
6432 ibdm_hca_list_t *hca_list = NULL;
6433 ibdm_port_attr_t *port = NULL;
6434 ibdm_ioc_info_t *ioc_list;
6435
6436 for (gid_info = ibdm.ibdm_dp_gidlist_head; gid_info; ) {
6437 found = 0;
6438 if (gid_info->gl_state != IBDM_GID_PROBING_SKIPPED &&
6439 gid_info->gl_state != IBDM_GID_PROBING_COMPLETE) {
6440 gid_info = gid_info->gl_next;
6441 continue;
6442 }
6443
6444 /*
6445 * Check if the GID is visible to any HCA ports.
6446 * Return if so.
6447 */
6448 mutex_enter(&ibdm.ibdm_hl_mutex);
6449 for (ibdm_get_next_port(&hca_list, &port, 1); port;
6450 ibdm_get_next_port(&hca_list, &port, 1)) {
6451 if (ibdm_port_reachable(port->pa_sa_hdl,
6452 gid_info->gl_dgid_lo) == B_TRUE) {
6453 found = 1;
6454 break;
6455 }
6456 }
6457 mutex_exit(&ibdm.ibdm_hl_mutex);
6458
6459 if (found) {
6460 if (gid_info->gl_iou == NULL) {
6461 gid_info = gid_info->gl_next;
6462 continue;
6463 }
6464
6465 /* Intialize the ioc_prev_gid_list */
6466 niocs =
6467 gid_info->gl_iou->iou_info.iou_num_ctrl_slots;
6468 for (ii = 0; ii < niocs; ii++) {
6469 ioc_list = IBDM_GIDINFO2IOCINFO(gid_info, ii);
6470
6471 if (ioc_guidp == NULL || (*ioc_guidp ==
6472 ioc_list->ioc_profile.ioc_guid)) {
6473 /* Add info of GIDs in gid_info also */
6474 ibdm_addto_gidlist(
6475 &ioc_list->ioc_prev_gid_list,
6476 gid_info->gl_gid);
6477 ioc_list->ioc_prev_nportgids =
6478 gid_info->gl_ngids;
6479 }
6480 }
6481 gid_info = gid_info->gl_next;
6482 continue;
6483 }
6484
6485 IBTF_DPRINTF_L4("ibdm", "\trescan_gidlist "
6486 "deleted port GUID %llx",
6487 gid_info->gl_dgid_lo);
6488
6489 /*
6490 * Update GID list in all IOCs affected by this
6491 */
6492 ioc_list = ibdm_update_ioc_gidlist(gid_info, 0);
6493
6494 /*
6495 * Remove GID from the global GID list
6496 * Handle the case where all port GIDs for an
6497 * IOU have been hot-removed.
6498 */
6499 mutex_enter(&ibdm.ibdm_mutex);
6500 if (gid_info->gl_iou != NULL && gid_info->gl_ngids == 0) {
6501 mutex_enter(&gid_info->gl_mutex);
6502 (void) ibdm_free_iou_info(gid_info, &gid_info->gl_iou);
6503 mutex_exit(&gid_info->gl_mutex);
6504 }
6505
6506 tmp = gid_info->gl_next;
6507 if (gid_info->gl_prev != NULL)
6508 gid_info->gl_prev->gl_next = gid_info->gl_next;
6509 if (gid_info->gl_next != NULL)
6510 gid_info->gl_next->gl_prev = gid_info->gl_prev;
6511
6512 if (gid_info == ibdm.ibdm_dp_gidlist_head)
6513 ibdm.ibdm_dp_gidlist_head = gid_info->gl_next;
6514 if (gid_info == ibdm.ibdm_dp_gidlist_tail)
6515 ibdm.ibdm_dp_gidlist_tail = gid_info->gl_prev;
6516 ibdm.ibdm_ngids--;
6517 mutex_exit(&ibdm.ibdm_mutex);
6518
6519 /* free the hca_list on this gid_info */
6520 ibdm_delete_glhca_list(gid_info);
6521
6522 mutex_destroy(&gid_info->gl_mutex);
6523 kmem_free(gid_info, sizeof (ibdm_dp_gidinfo_t));
6524
6525 gid_info = tmp;
6526
6527 /*
6528 * Pass on the IOCs with updated GIDs to IBnexus
6529 */
6530 if (ioc_list) {
6531 IBTF_DPRINTF_L4("ibdm", "\trescan_gidlist "
6532 "IOC_PROP_UPDATE for %p\n", ioc_list);
6533 mutex_enter(&ibdm.ibdm_ibnex_mutex);
6534 if (ibdm.ibdm_ibnex_callback != NULL) {
6535 (*ibdm.ibdm_ibnex_callback)((void *)
6536 ioc_list, IBDM_EVENT_IOC_PROP_UPDATE);
6537 }
6538 mutex_exit(&ibdm.ibdm_ibnex_mutex);
6539 }
6540 }
6541 }
6542
6543 /*
6544 * This function notifies IBnex of IOCs on this GID.
6545 * Notification is for GIDs with gl_reprobe_flag set.
6546 * The flag is set when IOC probe / fabric sweep
6547 * probes a GID starting from CLASS port info.
6548 *
6549 * IBnexus will have information of a reconnected IOC
6550 * if it had probed it before. If this is a new IOC,
6551 * IBnexus ignores the notification.
6552 *
6553 * This function should be called with no locks held.
6554 */
6555 static void
ibdm_notify_newgid_iocs(ibdm_dp_gidinfo_t * gid_info)6556 ibdm_notify_newgid_iocs(ibdm_dp_gidinfo_t *gid_info)
6557 {
6558 ibdm_ioc_info_t *ioc_list;
6559
6560 if (gid_info->gl_reprobe_flag == 0 ||
6561 gid_info->gl_iou == NULL)
6562 return;
6563
6564 ioc_list = ibdm_update_ioc_gidlist(gid_info, -1);
6565
6566 /*
6567 * Pass on the IOCs with updated GIDs to IBnexus
6568 */
6569 if (ioc_list) {
6570 mutex_enter(&ibdm.ibdm_ibnex_mutex);
6571 if (ibdm.ibdm_ibnex_callback != NULL) {
6572 (*ibdm.ibdm_ibnex_callback)((void *)ioc_list,
6573 IBDM_EVENT_IOC_PROP_UPDATE);
6574 }
6575 mutex_exit(&ibdm.ibdm_ibnex_mutex);
6576 }
6577 }
6578
6579
6580 static void
ibdm_free_saa_event_arg(ibdm_saa_event_arg_t * arg)6581 ibdm_free_saa_event_arg(ibdm_saa_event_arg_t *arg)
6582 {
6583 if (arg != NULL)
6584 kmem_free(arg, sizeof (ibdm_saa_event_arg_t));
6585 }
6586
6587 /*
6588 * This function parses the list of HCAs and HCA ports
6589 * to return the port_attr of the next HCA port. A port
6590 * connected to IB fabric (port_state active) is returned,
6591 * if connected_flag is set.
6592 */
6593 static void
ibdm_get_next_port(ibdm_hca_list_t ** inp_hcap,ibdm_port_attr_t ** inp_portp,int connect_flag)6594 ibdm_get_next_port(ibdm_hca_list_t **inp_hcap,
6595 ibdm_port_attr_t **inp_portp, int connect_flag)
6596 {
6597 int ii;
6598 ibdm_port_attr_t *port, *next_port = NULL;
6599 ibdm_port_attr_t *inp_port;
6600 ibdm_hca_list_t *hca_list;
6601 int found = 0;
6602
6603 ASSERT(MUTEX_HELD(&ibdm.ibdm_hl_mutex));
6604 IBTF_DPRINTF_L4(ibdm_string, "\tget_next_port(%p, %p, %x)",
6605 inp_hcap, inp_portp, connect_flag);
6606
6607 hca_list = *inp_hcap;
6608 inp_port = *inp_portp;
6609
6610 if (hca_list == NULL)
6611 hca_list = ibdm.ibdm_hca_list_head;
6612
6613 for (; hca_list; hca_list = hca_list->hl_next) {
6614 for (ii = 0; ii < hca_list->hl_nports; ii++) {
6615 port = &hca_list->hl_port_attr[ii];
6616
6617 /*
6618 * inp_port != NULL;
6619 * Skip till we find the matching port
6620 */
6621 if (inp_port && !found) {
6622 if (inp_port == port)
6623 found = 1;
6624 continue;
6625 }
6626
6627 if (!connect_flag) {
6628 next_port = port;
6629 break;
6630 }
6631
6632 if (port->pa_sa_hdl == NULL)
6633 ibdm_initialize_port(port);
6634 if (port->pa_sa_hdl == NULL)
6635 (void) ibdm_fini_port(port);
6636 else if (next_port == NULL &&
6637 port->pa_sa_hdl != NULL &&
6638 port->pa_state == IBT_PORT_ACTIVE) {
6639 next_port = port;
6640 break;
6641 }
6642 }
6643
6644 if (next_port)
6645 break;
6646 }
6647
6648 IBTF_DPRINTF_L4(ibdm_string, "\tget_next_port : "
6649 "returns hca_list %p port %p", hca_list, next_port);
6650 *inp_hcap = hca_list;
6651 *inp_portp = next_port;
6652 }
6653
6654 static void
ibdm_add_to_gl_gid(ibdm_dp_gidinfo_t * nodegid,ibdm_dp_gidinfo_t * addgid)6655 ibdm_add_to_gl_gid(ibdm_dp_gidinfo_t *nodegid, ibdm_dp_gidinfo_t *addgid)
6656 {
6657 ibdm_gid_t *tmp;
6658
6659 tmp = kmem_zalloc(sizeof (ibdm_gid_t), KM_SLEEP);
6660 tmp->gid_dgid_hi = addgid->gl_dgid_hi;
6661 tmp->gid_dgid_lo = addgid->gl_dgid_lo;
6662
6663 mutex_enter(&nodegid->gl_mutex);
6664 tmp->gid_next = nodegid->gl_gid;
6665 nodegid->gl_gid = tmp;
6666 nodegid->gl_ngids++;
6667 mutex_exit(&nodegid->gl_mutex);
6668 }
6669
6670 static void
ibdm_addto_glhcalist(ibdm_dp_gidinfo_t * gid_info,ibdm_hca_list_t * hca)6671 ibdm_addto_glhcalist(ibdm_dp_gidinfo_t *gid_info,
6672 ibdm_hca_list_t *hca)
6673 {
6674 ibdm_hca_list_t *head, *prev = NULL, *temp;
6675
6676 IBTF_DPRINTF_L4(ibdm_string, "\taddto_glhcalist(%p, %p) "
6677 ": gl_hca_list %p", gid_info, hca, gid_info->gl_hca_list);
6678 ASSERT(!MUTEX_HELD(&gid_info->gl_mutex));
6679
6680 mutex_enter(&gid_info->gl_mutex);
6681 head = gid_info->gl_hca_list;
6682 if (head == NULL) {
6683 head = ibdm_dup_hca_attr(hca);
6684 head->hl_next = NULL;
6685 gid_info->gl_hca_list = head;
6686 mutex_exit(&gid_info->gl_mutex);
6687 IBTF_DPRINTF_L4(ibdm_string, "\tadd_to_glhcalist: "
6688 "gid %p, gl_hca_list %p", gid_info,
6689 gid_info->gl_hca_list);
6690 return;
6691 }
6692
6693 /* Check if already in the list */
6694 while (head) {
6695 if (head->hl_hca_guid == hca->hl_hca_guid) {
6696 mutex_exit(&gid_info->gl_mutex);
6697 IBTF_DPRINTF_L4(ibdm_string,
6698 "\taddto_glhcalist : gid %p hca %p dup",
6699 gid_info, hca);
6700 return;
6701 }
6702 prev = head;
6703 head = head->hl_next;
6704 }
6705
6706 /* Add this HCA to gl_hca_list */
6707 temp = ibdm_dup_hca_attr(hca);
6708 temp->hl_next = NULL;
6709 prev->hl_next = temp;
6710 mutex_exit(&gid_info->gl_mutex);
6711
6712 IBTF_DPRINTF_L4(ibdm_string, "\tadd_to_glhcalist: "
6713 "gid %p, gl_hca_list %p", gid_info, gid_info->gl_hca_list);
6714 }
6715
6716 static void
ibdm_delete_glhca_list(ibdm_dp_gidinfo_t * gid_info)6717 ibdm_delete_glhca_list(ibdm_dp_gidinfo_t *gid_info)
6718 {
6719 ASSERT(!MUTEX_HELD(&gid_info->gl_mutex));
6720 ASSERT(!MUTEX_HELD(&ibdm.ibdm_mutex));
6721
6722 mutex_enter(&gid_info->gl_mutex);
6723 if (gid_info->gl_hca_list)
6724 ibdm_ibnex_free_hca_list(gid_info->gl_hca_list);
6725 gid_info->gl_hca_list = NULL;
6726 mutex_exit(&gid_info->gl_mutex);
6727 }
6728
6729
6730 static void
ibdm_reset_all_dgids(ibmf_saa_handle_t port_sa_hdl)6731 ibdm_reset_all_dgids(ibmf_saa_handle_t port_sa_hdl)
6732 {
6733 IBTF_DPRINTF_L4(ibdm_string, "\treset_all_dgids(%X)",
6734 port_sa_hdl);
6735
6736 if (ibdm_enumerate_iocs == 0)
6737 return;
6738
6739 ASSERT(!MUTEX_HELD(&ibdm.ibdm_mutex));
6740 ASSERT(!MUTEX_HELD(&ibdm.ibdm_hl_mutex));
6741
6742 /* Check : Not busy in another probe / sweep */
6743 mutex_enter(&ibdm.ibdm_mutex);
6744 if ((ibdm.ibdm_busy & IBDM_BUSY) == 0) {
6745 ibdm_dp_gidinfo_t *gid_info;
6746
6747 ibdm.ibdm_busy |= IBDM_BUSY;
6748 mutex_exit(&ibdm.ibdm_mutex);
6749
6750 /*
6751 * Check if any GID is using the SA & IBMF handle
6752 * of HCA port going down. Reset ibdm_dp_gidinfo_t
6753 * using another HCA port which can reach the GID.
6754 * This is for DM capable GIDs only, no need to do
6755 * this for others
6756 *
6757 * Delete the GID if no alternate HCA port to reach
6758 * it is found.
6759 */
6760 for (gid_info = ibdm.ibdm_dp_gidlist_head; gid_info; ) {
6761 ibdm_dp_gidinfo_t *tmp;
6762
6763 IBTF_DPRINTF_L4(ibdm_string, "\tevent_hdlr "
6764 "checking gidinfo %p", gid_info);
6765
6766 if (gid_info->gl_sa_hdl == port_sa_hdl) {
6767 IBTF_DPRINTF_L3(ibdm_string,
6768 "\tevent_hdlr: down HCA port hdl "
6769 "matches gid %p", gid_info);
6770
6771 /*
6772 * The non-DM GIDs can come back
6773 * with a new subnet prefix, when
6774 * the HCA port commes up again. To
6775 * avoid issues, delete non-DM
6776 * capable GIDs, if the gid was
6777 * discovered using the HCA port
6778 * going down. This is ensured by
6779 * setting gl_disconnected to 1.
6780 */
6781 if (gid_info->gl_is_dm_capable == B_FALSE)
6782 gid_info->gl_disconnected = 1;
6783 else
6784 ibdm_reset_gidinfo(gid_info);
6785
6786 if (gid_info->gl_disconnected) {
6787 IBTF_DPRINTF_L3(ibdm_string,
6788 "\tevent_hdlr: deleting"
6789 " gid %p", gid_info);
6790 tmp = gid_info;
6791 gid_info = gid_info->gl_next;
6792 ibdm_delete_gidinfo(tmp);
6793 } else
6794 gid_info = gid_info->gl_next;
6795 } else
6796 gid_info = gid_info->gl_next;
6797 }
6798
6799 mutex_enter(&ibdm.ibdm_mutex);
6800 ibdm.ibdm_busy &= ~IBDM_BUSY;
6801 cv_signal(&ibdm.ibdm_busy_cv);
6802 }
6803 mutex_exit(&ibdm.ibdm_mutex);
6804 }
6805
6806 static void
ibdm_reset_gidinfo(ibdm_dp_gidinfo_t * gidinfo)6807 ibdm_reset_gidinfo(ibdm_dp_gidinfo_t *gidinfo)
6808 {
6809 ibdm_hca_list_t *hca_list = NULL;
6810 ibdm_port_attr_t *port = NULL;
6811 int gid_reinited = 0;
6812 sa_node_record_t *nr, *tmp;
6813 sa_portinfo_record_t *pi;
6814 size_t nr_len = 0, pi_len = 0;
6815 size_t path_len;
6816 ib_gid_t sgid, dgid;
6817 int ret, ii, nrecords;
6818 sa_path_record_t *path;
6819 uint8_t npaths = 1;
6820 ibdm_pkey_tbl_t *pkey_tbl;
6821
6822 IBTF_DPRINTF_L4(ibdm_string, "\treset_gidinfo(%p)", gidinfo);
6823
6824 /*
6825 * Get list of all the ports reachable from the local known HCA
6826 * ports which are active
6827 */
6828 mutex_enter(&ibdm.ibdm_hl_mutex);
6829 for (ibdm_get_next_port(&hca_list, &port, 1); port;
6830 ibdm_get_next_port(&hca_list, &port, 1)) {
6831
6832
6833 /*
6834 * Get the path and re-populate the gidinfo.
6835 * Getting the path is the same probe_ioc
6836 * Init the gid info as in ibdm_create_gidinfo()
6837 */
6838 nr = ibdm_get_node_records(port->pa_sa_hdl, &nr_len,
6839 gidinfo->gl_nodeguid);
6840 if (nr == NULL) {
6841 IBTF_DPRINTF_L4(ibdm_string,
6842 "\treset_gidinfo : no records");
6843 continue;
6844 }
6845
6846 nrecords = (nr_len / sizeof (sa_node_record_t));
6847 for (tmp = nr, ii = 0; (ii < nrecords); ii++, tmp++) {
6848 if (tmp->NodeInfo.PortGUID == gidinfo->gl_portguid)
6849 break;
6850 }
6851
6852 if (ii == nrecords) {
6853 IBTF_DPRINTF_L4(ibdm_string,
6854 "\treset_gidinfo : no record for portguid");
6855 kmem_free(nr, nr_len);
6856 continue;
6857 }
6858
6859 pi = ibdm_get_portinfo(port->pa_sa_hdl, &pi_len, tmp->LID);
6860 if (pi == NULL) {
6861 IBTF_DPRINTF_L4(ibdm_string,
6862 "\treset_gidinfo : no portinfo");
6863 kmem_free(nr, nr_len);
6864 continue;
6865 }
6866
6867 sgid.gid_prefix = port->pa_sn_prefix;
6868 sgid.gid_guid = port->pa_port_guid;
6869 dgid.gid_prefix = pi->PortInfo.GidPrefix;
6870 dgid.gid_guid = tmp->NodeInfo.PortGUID;
6871
6872 ret = ibmf_saa_gid_to_pathrecords(port->pa_sa_hdl, sgid, dgid,
6873 IBMF_SAA_PKEY_WC, 0, B_TRUE, &npaths, 0, &path_len, &path);
6874
6875 if ((ret != IBMF_SUCCESS) || path == NULL) {
6876 IBTF_DPRINTF_L4(ibdm_string,
6877 "\treset_gidinfo : no paths");
6878 kmem_free(pi, pi_len);
6879 kmem_free(nr, nr_len);
6880 continue;
6881 }
6882
6883 gidinfo->gl_dgid_hi = path->DGID.gid_prefix;
6884 gidinfo->gl_dgid_lo = path->DGID.gid_guid;
6885 gidinfo->gl_sgid_hi = path->SGID.gid_prefix;
6886 gidinfo->gl_sgid_lo = path->SGID.gid_guid;
6887 gidinfo->gl_p_key = path->P_Key;
6888 gidinfo->gl_sa_hdl = port->pa_sa_hdl;
6889 gidinfo->gl_ibmf_hdl = port->pa_ibmf_hdl;
6890 gidinfo->gl_slid = path->SLID;
6891 gidinfo->gl_dlid = path->DLID;
6892 /* Reset redirect info, next MAD will set if redirected */
6893 gidinfo->gl_redirected = 0;
6894 gidinfo->gl_devid = (*tmp).NodeInfo.DeviceID;
6895 gidinfo->gl_SL = path->SL;
6896
6897 gidinfo->gl_qp_hdl = IBMF_QP_HANDLE_DEFAULT;
6898 for (ii = 0; ii < port->pa_npkeys; ii++) {
6899 if (port->pa_pkey_tbl == NULL)
6900 break;
6901
6902 pkey_tbl = &port->pa_pkey_tbl[ii];
6903 if ((gidinfo->gl_p_key == pkey_tbl->pt_pkey) &&
6904 (pkey_tbl->pt_qp_hdl != NULL)) {
6905 gidinfo->gl_qp_hdl = pkey_tbl->pt_qp_hdl;
6906 break;
6907 }
6908 }
6909
6910 if (gidinfo->gl_qp_hdl == NULL)
6911 IBTF_DPRINTF_L2(ibdm_string,
6912 "\treset_gid_info: No matching Pkey");
6913 else
6914 gid_reinited = 1;
6915
6916 kmem_free(path, path_len);
6917 kmem_free(pi, pi_len);
6918 kmem_free(nr, nr_len);
6919 break;
6920 }
6921 mutex_exit(&ibdm.ibdm_hl_mutex);
6922
6923 if (!gid_reinited)
6924 gidinfo->gl_disconnected = 1;
6925 }
6926
6927 static void
ibdm_delete_gidinfo(ibdm_dp_gidinfo_t * gidinfo)6928 ibdm_delete_gidinfo(ibdm_dp_gidinfo_t *gidinfo)
6929 {
6930 ibdm_ioc_info_t *ioc_list;
6931 int in_gidlist = 0;
6932
6933 /*
6934 * Check if gidinfo has been inserted into the
6935 * ibdm_dp_gidlist_head list. gl_next or gl_prev
6936 * != NULL, if gidinfo is the list.
6937 */
6938 if (gidinfo->gl_prev != NULL ||
6939 gidinfo->gl_next != NULL ||
6940 ibdm.ibdm_dp_gidlist_head == gidinfo)
6941 in_gidlist = 1;
6942
6943 ioc_list = ibdm_update_ioc_gidlist(gidinfo, 0);
6944
6945 /*
6946 * Remove GID from the global GID list
6947 * Handle the case where all port GIDs for an
6948 * IOU have been hot-removed.
6949 */
6950 mutex_enter(&ibdm.ibdm_mutex);
6951 if (gidinfo->gl_iou != NULL && gidinfo->gl_ngids == 0) {
6952 mutex_enter(&gidinfo->gl_mutex);
6953 (void) ibdm_free_iou_info(gidinfo, &gidinfo->gl_iou);
6954 mutex_exit(&gidinfo->gl_mutex);
6955 }
6956
6957 /* Delete gl_hca_list */
6958 mutex_exit(&ibdm.ibdm_mutex);
6959 ibdm_delete_glhca_list(gidinfo);
6960 mutex_enter(&ibdm.ibdm_mutex);
6961
6962 if (in_gidlist) {
6963 if (gidinfo->gl_prev != NULL)
6964 gidinfo->gl_prev->gl_next = gidinfo->gl_next;
6965 if (gidinfo->gl_next != NULL)
6966 gidinfo->gl_next->gl_prev = gidinfo->gl_prev;
6967
6968 if (gidinfo == ibdm.ibdm_dp_gidlist_head)
6969 ibdm.ibdm_dp_gidlist_head = gidinfo->gl_next;
6970 if (gidinfo == ibdm.ibdm_dp_gidlist_tail)
6971 ibdm.ibdm_dp_gidlist_tail = gidinfo->gl_prev;
6972 ibdm.ibdm_ngids--;
6973 }
6974 mutex_exit(&ibdm.ibdm_mutex);
6975
6976 mutex_destroy(&gidinfo->gl_mutex);
6977 cv_destroy(&gidinfo->gl_probe_cv);
6978 kmem_free(gidinfo, sizeof (ibdm_dp_gidinfo_t));
6979
6980 /*
6981 * Pass on the IOCs with updated GIDs to IBnexus
6982 */
6983 if (ioc_list) {
6984 IBTF_DPRINTF_L4("ibdm", "\tdelete_gidinfo "
6985 "IOC_PROP_UPDATE for %p\n", ioc_list);
6986 mutex_enter(&ibdm.ibdm_ibnex_mutex);
6987 if (ibdm.ibdm_ibnex_callback != NULL) {
6988 (*ibdm.ibdm_ibnex_callback)((void *)
6989 ioc_list, IBDM_EVENT_IOC_PROP_UPDATE);
6990 }
6991 mutex_exit(&ibdm.ibdm_ibnex_mutex);
6992 }
6993 }
6994
6995
6996 static void
ibdm_fill_srv_attr_mod(ib_mad_hdr_t * hdr,ibdm_timeout_cb_args_t * cb_args)6997 ibdm_fill_srv_attr_mod(ib_mad_hdr_t *hdr, ibdm_timeout_cb_args_t *cb_args)
6998 {
6999 uint32_t attr_mod;
7000
7001 attr_mod = (cb_args->cb_ioc_num + 1) << 16;
7002 attr_mod |= cb_args->cb_srvents_start;
7003 attr_mod |= (cb_args->cb_srvents_end) << 8;
7004 hdr->AttributeModifier = h2b32(attr_mod);
7005 }
7006
7007 static void
ibdm_bump_transactionID(ibdm_dp_gidinfo_t * gid_info)7008 ibdm_bump_transactionID(ibdm_dp_gidinfo_t *gid_info)
7009 {
7010 ASSERT(MUTEX_HELD(&gid_info->gl_mutex));
7011 gid_info->gl_transactionID++;
7012 if (gid_info->gl_transactionID == gid_info->gl_max_transactionID) {
7013 IBTF_DPRINTF_L4(ibdm_string,
7014 "\tbump_transactionID(%p), wrapup", gid_info);
7015 gid_info->gl_transactionID = gid_info->gl_min_transactionID;
7016 }
7017 }
7018
7019 /*
7020 * gl_prev_iou is set for *non-reprobe* sweeep requests, which
7021 * detected that ChangeID in IOU info has changed. The service
7022 * entry also may have changed. Check if service entry in IOC
7023 * has changed wrt the prev iou, if so notify to IB Nexus.
7024 */
7025 static ibdm_ioc_info_t *
ibdm_handle_prev_iou()7026 ibdm_handle_prev_iou()
7027 {
7028 ibdm_dp_gidinfo_t *gid_info;
7029 ibdm_ioc_info_t *ioc_list_head = NULL, *ioc_list;
7030 ibdm_ioc_info_t *prev_ioc, *ioc;
7031 int ii, jj, niocs, prev_niocs;
7032
7033 ASSERT(MUTEX_HELD(&ibdm.ibdm_mutex));
7034
7035 IBTF_DPRINTF_L4(ibdm_string, "\thandle_prev_iou enter");
7036 for (gid_info = ibdm.ibdm_dp_gidlist_head; gid_info;
7037 gid_info = gid_info->gl_next) {
7038 if (gid_info->gl_prev_iou == NULL)
7039 continue;
7040
7041 IBTF_DPRINTF_L4(ibdm_string, "\thandle_prev_iou gid %p",
7042 gid_info);
7043 niocs = gid_info->gl_iou->iou_info.iou_num_ctrl_slots;
7044 prev_niocs =
7045 gid_info->gl_prev_iou->iou_info.iou_num_ctrl_slots;
7046 for (ii = 0; ii < niocs; ii++) {
7047 ioc = IBDM_GIDINFO2IOCINFO(gid_info, ii);
7048
7049 /* Find matching IOC */
7050 for (jj = 0; jj < prev_niocs; jj++) {
7051 prev_ioc = (ibdm_ioc_info_t *)
7052 &gid_info->gl_prev_iou->iou_ioc_info[jj];
7053 if (prev_ioc->ioc_profile.ioc_guid ==
7054 ioc->ioc_profile.ioc_guid)
7055 break;
7056 }
7057 if (jj == prev_niocs)
7058 prev_ioc = NULL;
7059 if (ioc == NULL || prev_ioc == NULL)
7060 continue;
7061 if ((ioc->ioc_profile.ioc_service_entries !=
7062 prev_ioc->ioc_profile.ioc_service_entries) ||
7063 ibdm_serv_cmp(&ioc->ioc_serv[0],
7064 &prev_ioc->ioc_serv[0],
7065 ioc->ioc_profile.ioc_service_entries) != 0) {
7066 IBTF_DPRINTF_L4(ibdm_string,
7067 "/thandle_prev_iou modified IOC: "
7068 "current ioc %p, old ioc %p",
7069 ioc, prev_ioc);
7070 mutex_enter(&gid_info->gl_mutex);
7071 ioc_list = ibdm_dup_ioc_info(ioc, gid_info);
7072 mutex_exit(&gid_info->gl_mutex);
7073 ioc_list->ioc_info_updated.ib_prop_updated
7074 = 0;
7075 ioc_list->ioc_info_updated.ib_srv_prop_updated
7076 = 1;
7077
7078 if (ioc_list_head == NULL)
7079 ioc_list_head = ioc_list;
7080 else {
7081 ioc_list_head->ioc_next = ioc_list;
7082 ioc_list_head = ioc_list;
7083 }
7084 }
7085 }
7086
7087 mutex_enter(&gid_info->gl_mutex);
7088 (void) ibdm_free_iou_info(gid_info, &gid_info->gl_prev_iou);
7089 mutex_exit(&gid_info->gl_mutex);
7090 }
7091 IBTF_DPRINTF_L4(ibdm_string, "\thandle_prev_iouret %p",
7092 ioc_list_head);
7093 return (ioc_list_head);
7094 }
7095
7096 /*
7097 * Compares two service entries lists, returns 0 if same, returns 1
7098 * if no match.
7099 */
7100 static int
ibdm_serv_cmp(ibdm_srvents_info_t * serv1,ibdm_srvents_info_t * serv2,int nserv)7101 ibdm_serv_cmp(ibdm_srvents_info_t *serv1, ibdm_srvents_info_t *serv2,
7102 int nserv)
7103 {
7104 int ii;
7105
7106 IBTF_DPRINTF_L4(ibdm_string, "\tserv_cmp: enter");
7107 for (ii = 0; ii < nserv; ii++, serv1++, serv2++) {
7108 if (serv1->se_attr.srv_id != serv2->se_attr.srv_id ||
7109 bcmp(serv1->se_attr.srv_name,
7110 serv2->se_attr.srv_name,
7111 IB_DM_MAX_SVC_NAME_LEN) != 0) {
7112 IBTF_DPRINTF_L4(ibdm_string, "\tserv_cmp: ret 1");
7113 return (1);
7114 }
7115 }
7116 IBTF_DPRINTF_L4(ibdm_string, "\tserv_cmp: ret 0");
7117 return (0);
7118 }
7119
7120 /* For debugging purpose only */
7121 #ifdef DEBUG
7122 void
ibdm_dump_mad_hdr(ib_mad_hdr_t * mad_hdr)7123 ibdm_dump_mad_hdr(ib_mad_hdr_t *mad_hdr)
7124 {
7125 IBTF_DPRINTF_L4("ibdm", "\t\t MAD Header info");
7126 IBTF_DPRINTF_L4("ibdm", "\t\t ---------------");
7127
7128 IBTF_DPRINTF_L4("ibdm", "\tBase version : 0x%x"
7129 "\tMgmt Class : 0x%x", mad_hdr->BaseVersion, mad_hdr->MgmtClass);
7130 IBTF_DPRINTF_L4("ibdm", "\tClass version : 0x%x"
7131 "\tR Method : 0x%x",
7132 mad_hdr->ClassVersion, mad_hdr->R_Method);
7133 IBTF_DPRINTF_L4("ibdm", "\tMAD Status : 0x%x"
7134 "\tTransaction ID : 0x%llx",
7135 b2h16(mad_hdr->Status), b2h64(mad_hdr->TransactionID));
7136 IBTF_DPRINTF_L4("ibdm", "\t Attribute ID : 0x%x"
7137 "\tAttribute Modified : 0x%lx",
7138 b2h16(mad_hdr->AttributeID), b2h32(mad_hdr->AttributeModifier));
7139 }
7140
7141
7142 void
ibdm_dump_ibmf_msg(ibmf_msg_t * ibmf_msg,int flag)7143 ibdm_dump_ibmf_msg(ibmf_msg_t *ibmf_msg, int flag)
7144 {
7145 ib_mad_hdr_t *mad_hdr;
7146
7147 IBTF_DPRINTF_L4("ibdm", "\t\t(IBMF_PKT): Local address info");
7148 IBTF_DPRINTF_L4("ibdm", "\t\t ------------------");
7149
7150 IBTF_DPRINTF_L4("ibdm", "\tLocal Lid : 0x%x\tRemote Lid : 0x%x"
7151 " Remote Qp : 0x%x", ibmf_msg->im_local_addr.ia_local_lid,
7152 ibmf_msg->im_local_addr.ia_remote_lid,
7153 ibmf_msg->im_local_addr.ia_remote_qno);
7154 IBTF_DPRINTF_L4("ibdm", "\tP_key : 0x%x\tQ_key : 0x%x"
7155 " SL : 0x%x", ibmf_msg->im_local_addr.ia_p_key,
7156 ibmf_msg->im_local_addr.ia_q_key,
7157 ibmf_msg->im_local_addr.ia_service_level);
7158
7159 if (flag)
7160 mad_hdr = (ib_mad_hdr_t *)IBDM_OUT_IBMFMSG_MADHDR(ibmf_msg);
7161 else
7162 mad_hdr = IBDM_IN_IBMFMSG_MADHDR(ibmf_msg);
7163
7164 ibdm_dump_mad_hdr(mad_hdr);
7165 }
7166
7167
7168 void
ibdm_dump_path_info(sa_path_record_t * path)7169 ibdm_dump_path_info(sa_path_record_t *path)
7170 {
7171 IBTF_DPRINTF_L4("ibdm", "\t\t Path information");
7172 IBTF_DPRINTF_L4("ibdm", "\t\t ----------------");
7173
7174 IBTF_DPRINTF_L4("ibdm", "\t DGID hi : %llx\tDGID lo : %llx",
7175 path->DGID.gid_prefix, path->DGID.gid_guid);
7176 IBTF_DPRINTF_L4("ibdm", "\t SGID hi : %llx\tSGID lo : %llx",
7177 path->SGID.gid_prefix, path->SGID.gid_guid);
7178 IBTF_DPRINTF_L4("ibdm", "\t SLID : %x\t\tDlID : %x",
7179 path->SLID, path->DLID);
7180 IBTF_DPRINTF_L4("ibdm", "\t P Key : %x\t\tSL : %x",
7181 path->P_Key, path->SL);
7182 }
7183
7184
7185 void
ibdm_dump_classportinfo(ib_mad_classportinfo_t * classportinfo)7186 ibdm_dump_classportinfo(ib_mad_classportinfo_t *classportinfo)
7187 {
7188 IBTF_DPRINTF_L4("ibdm", "\t\t CLASSPORT INFO");
7189 IBTF_DPRINTF_L4("ibdm", "\t\t --------------");
7190
7191 IBTF_DPRINTF_L4("ibdm", "\t Response Time Value : 0x%x",
7192 ((b2h32(classportinfo->RespTimeValue)) & 0x1F));
7193
7194 IBTF_DPRINTF_L4("ibdm", "\t Redirected GID hi : 0x%llx",
7195 b2h64(classportinfo->RedirectGID_hi));
7196 IBTF_DPRINTF_L4("ibdm", "\t Redirected GID lo : 0x%llx",
7197 b2h64(classportinfo->RedirectGID_lo));
7198 IBTF_DPRINTF_L4("ibdm", "\t Redirected TC : 0x%x",
7199 classportinfo->RedirectTC);
7200 IBTF_DPRINTF_L4("ibdm", "\t Redirected SL : 0x%x",
7201 classportinfo->RedirectSL);
7202 IBTF_DPRINTF_L4("ibdm", "\t Redirected FL : 0x%x",
7203 classportinfo->RedirectFL);
7204 IBTF_DPRINTF_L4("ibdm", "\t Redirected LID : 0x%x",
7205 b2h16(classportinfo->RedirectLID));
7206 IBTF_DPRINTF_L4("ibdm", "\t Redirected P KEY : 0x%x",
7207 b2h16(classportinfo->RedirectP_Key));
7208 IBTF_DPRINTF_L4("ibdm", "\t Redirected QP : 0x%x",
7209 classportinfo->RedirectQP);
7210 IBTF_DPRINTF_L4("ibdm", "\t Redirected Q KEY : 0x%x",
7211 b2h32(classportinfo->RedirectQ_Key));
7212 IBTF_DPRINTF_L4("ibdm", "\t Trap GID hi : 0x%llx",
7213 b2h64(classportinfo->TrapGID_hi));
7214 IBTF_DPRINTF_L4("ibdm", "\t Trap GID lo : 0x%llx",
7215 b2h64(classportinfo->TrapGID_lo));
7216 IBTF_DPRINTF_L4("ibdm", "\t Trap TC : 0x%x",
7217 classportinfo->TrapTC);
7218 IBTF_DPRINTF_L4("ibdm", "\t Trap SL : 0x%x",
7219 classportinfo->TrapSL);
7220 IBTF_DPRINTF_L4("ibdm", "\t Trap FL : 0x%x",
7221 classportinfo->TrapFL);
7222 IBTF_DPRINTF_L4("ibdm", "\t Trap LID : 0x%x",
7223 b2h16(classportinfo->TrapLID));
7224 IBTF_DPRINTF_L4("ibdm", "\t Trap P_Key : 0x%x",
7225 b2h16(classportinfo->TrapP_Key));
7226 IBTF_DPRINTF_L4("ibdm", "\t Trap HL : 0x%x",
7227 classportinfo->TrapHL);
7228 IBTF_DPRINTF_L4("ibdm", "\t Trap QP : 0x%x",
7229 classportinfo->TrapQP);
7230 IBTF_DPRINTF_L4("ibdm", "\t Trap Q_Key : 0x%x",
7231 b2h32(classportinfo->TrapQ_Key));
7232 }
7233
7234
7235 void
ibdm_dump_iounitinfo(ib_dm_io_unitinfo_t * iou_info)7236 ibdm_dump_iounitinfo(ib_dm_io_unitinfo_t *iou_info)
7237 {
7238 IBTF_DPRINTF_L4("ibdm", "\t\t I/O UnitInfo");
7239 IBTF_DPRINTF_L4("ibdm", "\t\t ------------");
7240
7241 IBTF_DPRINTF_L4("ibdm", "\tChange ID : 0x%x",
7242 b2h16(iou_info->iou_changeid));
7243 IBTF_DPRINTF_L4("ibdm", "\t#of ctrl slots : %d",
7244 iou_info->iou_num_ctrl_slots);
7245 IBTF_DPRINTF_L4("ibdm", "\tIOU flag : 0x%x",
7246 iou_info->iou_flag);
7247 IBTF_DPRINTF_L4("ibdm", "\tContrl list byte 0 : 0x%x",
7248 iou_info->iou_ctrl_list[0]);
7249 IBTF_DPRINTF_L4("ibdm", "\tContrl list byte 1 : 0x%x",
7250 iou_info->iou_ctrl_list[1]);
7251 IBTF_DPRINTF_L4("ibdm", "\tContrl list byte 2 : 0x%x",
7252 iou_info->iou_ctrl_list[2]);
7253 }
7254
7255
7256 void
ibdm_dump_ioc_profile(ib_dm_ioc_ctrl_profile_t * ioc)7257 ibdm_dump_ioc_profile(ib_dm_ioc_ctrl_profile_t *ioc)
7258 {
7259 IBTF_DPRINTF_L4("ibdm", "\t\t IOC Controller Profile");
7260 IBTF_DPRINTF_L4("ibdm", "\t\t ----------------------");
7261
7262 IBTF_DPRINTF_L4("ibdm", "\tIOC Guid : %llx", ioc->ioc_guid);
7263 IBTF_DPRINTF_L4("ibdm", "\tVendorID : 0x%x", ioc->ioc_vendorid);
7264 IBTF_DPRINTF_L4("ibdm", "\tDevice Id : 0x%x", ioc->ioc_deviceid);
7265 IBTF_DPRINTF_L4("ibdm", "\tDevice Ver : 0x%x", ioc->ioc_device_ver);
7266 IBTF_DPRINTF_L4("ibdm", "\tSubsys ID : 0x%x", ioc->ioc_subsys_id);
7267 IBTF_DPRINTF_L4("ibdm", "\tIO class : 0x%x", ioc->ioc_io_class);
7268 IBTF_DPRINTF_L4("ibdm", "\tIO subclass : 0x%x", ioc->ioc_io_subclass);
7269 IBTF_DPRINTF_L4("ibdm", "\tProtocol : 0x%x", ioc->ioc_protocol);
7270 IBTF_DPRINTF_L4("ibdm", "\tProtocolV : 0x%x", ioc->ioc_protocol_ver);
7271 IBTF_DPRINTF_L4("ibdm", "\tmsg qdepth : %d", ioc->ioc_send_msg_qdepth);
7272 IBTF_DPRINTF_L4("ibdm", "\trdma qdepth : %d",
7273 ioc->ioc_rdma_read_qdepth);
7274 IBTF_DPRINTF_L4("ibdm", "\tsndmsg sz : %d", ioc->ioc_send_msg_sz);
7275 IBTF_DPRINTF_L4("ibdm", "\trdma xfersz : %d", ioc->ioc_rdma_xfer_sz);
7276 IBTF_DPRINTF_L4("ibdm", "\topcal mask : 0x%x",
7277 ioc->ioc_ctrl_opcap_mask);
7278 IBTF_DPRINTF_L4("ibdm", "\tsrventries : %x", ioc->ioc_service_entries);
7279 }
7280
7281
7282 void
ibdm_dump_service_entries(ib_dm_srv_t * srv_ents)7283 ibdm_dump_service_entries(ib_dm_srv_t *srv_ents)
7284 {
7285 IBTF_DPRINTF_L4("ibdm",
7286 "\thandle_srventry_mad: service id : %llx", srv_ents->srv_id);
7287
7288 IBTF_DPRINTF_L4("ibdm", "\thandle_srventry_mad: "
7289 "Service Name : %s", srv_ents->srv_name);
7290 }
7291
7292 int ibdm_allow_sweep_fabric_timestamp = 1;
7293
7294 void
ibdm_dump_sweep_fabric_timestamp(int flag)7295 ibdm_dump_sweep_fabric_timestamp(int flag)
7296 {
7297 static hrtime_t x;
7298 if (flag) {
7299 if (ibdm_allow_sweep_fabric_timestamp) {
7300 IBTF_DPRINTF_L4("ibdm", "\tTime taken to complete "
7301 "sweep %lld ms", ((gethrtime() - x)/ 1000000));
7302 }
7303 x = 0;
7304 } else
7305 x = gethrtime();
7306 }
7307 #endif
7308