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 /*
23 * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
24 */
25
26 /*
27 * Copyright 2023 Oxide Computer Company
28 */
29
30 #include <sys/systm.h>
31 #include <sys/sunndi.h>
32 #include <sys/sunmdi.h>
33 #include <sys/ib/ibtl/impl/ibtl.h>
34 #include <sys/ib/ibtl/impl/ibtl_ibnex.h>
35
36 /*
37 * ibtl_ibnex.c
38 * These routines tie the Device Manager into IBTL.
39 *
40 * ibt_reprobe_dev which can be called by IBTF clients.
41 * This results in calls to IBnexus callback.
42 */
43
44 /*
45 * Globals.
46 */
47 static char ibtl_ibnex[] = "ibtl_ibnex";
48 ibtl_ibnex_callback_t ibtl_ibnex_callback_routine = NULL;
49
50 /*
51 * Function:
52 * ibtl_ibnex_get_hca_info
53 * Input:
54 * hca_guid - The HCA's node GUID.
55 * flag - Tells what to do
56 * IBTL_IBNEX_LIST_CLNTS_FLAG - Build a NVLIST containing
57 * client's names, their AP_IDs and
58 * alternate_HCA information.
59 * (-x list_clients option)
60 * IBTL_IBNEX_UNCFG_CLNTS_FLAG - Build a NVLIST containing
61 * clients' devpaths and their
62 * AP_IDs. (-x unconfig_clients)
63 * callback - Callback function to get ap_id from ib(4D)
64 * Output:
65 * buffer - The information is returned in this buffer
66 * bufsiz - The size of the information buffer
67 * Returns:
68 * IBT_SUCCESS/IBT_HCA_INVALID/IBT_INVALID_PARAM
69 * Description:
70 * For a given HCA node GUID it figures out the registered clients
71 * (ie. ones who called ibt_open_hca(9f) on this GUID) and creates
72 * a NVL packed buffer (of client names/ap_ids or devpaths) and returns
73 * it. If flag is not specified, then an error is returned.
74 */
75 ibt_status_t
ibtl_ibnex_get_hca_info(ib_guid_t hca_guid,int flag,char ** buffer,size_t * bufsiz,void (* callback)(dev_info_t *,char **))76 ibtl_ibnex_get_hca_info(ib_guid_t hca_guid, int flag, char **buffer,
77 size_t *bufsiz, void (*callback)(dev_info_t *, char **))
78 {
79 char *node_name;
80 char *ret_apid;
81 nvlist_t *nvl;
82 ibtl_hca_t *ibt_hca;
83 ibtl_clnt_t *clntp;
84 dev_info_t *child;
85 dev_info_t *parent;
86 ibtl_hca_devinfo_t *hca_devp;
87
88 IBTF_DPRINTF_L3(ibtl_ibnex, "ibtl_ibnex_get_hca_info: "
89 "GUID 0x%llX, flag = 0x%x", hca_guid, flag);
90
91 *buffer = NULL;
92 *bufsiz = 0;
93
94 /* verify that valid "flag" is passed */
95 if (flag != IBTL_IBNEX_LIST_CLNTS_FLAG &&
96 flag != IBTL_IBNEX_UNCFG_CLNTS_FLAG) {
97 return (IBT_INVALID_PARAM);
98 }
99
100 mutex_enter(&ibtl_clnt_list_mutex);
101
102 if ((hca_devp = ibtl_get_hcadevinfo(hca_guid)) == NULL) {
103 mutex_exit(&ibtl_clnt_list_mutex);
104
105 /*
106 * If we are here, then the requested HCA device is not
107 * present. Return the status as Invalid HCA GUID.
108 */
109 IBTF_DPRINTF_L2(ibtl_ibnex, "ibtl_ibnex_get_hca_info: "
110 "HCA Not Found, Invalid HCA GUID 0x%llX", hca_guid);
111 return (IBT_HCA_INVALID);
112 }
113
114 /* Walk the client list */
115 ibt_hca = hca_devp->hd_clnt_list;
116 (void) nvlist_alloc(&nvl, 0, KM_SLEEP);
117
118 /* Allocate memory for ret_apid, instead of using stack */
119 ret_apid = kmem_alloc(IBTL_IBNEX_APID_LEN, KM_SLEEP);
120
121 while (ibt_hca != NULL) {
122 clntp = ibt_hca->ha_clnt_devp;
123 child = clntp->clnt_dip;
124 IBTF_DPRINTF_L4(ibtl_ibnex, "ibtl_ibnex_get_hca_info: "
125 "Client = %s", clntp->clnt_modinfop->mi_clnt_name);
126
127 if (flag == IBTL_IBNEX_LIST_CLNTS_FLAG) {
128 (void) nvlist_add_string(nvl, "Client",
129 clntp->clnt_modinfop->mi_clnt_name);
130
131 /*
132 * Always check, first, if this client exists
133 * under this HCA anymore? If not, continue.
134 */
135 if (clntp->clnt_hca_list == NULL) {
136 (void) nvlist_add_string(nvl, "Alt_HCA", "no");
137 (void) nvlist_add_string(nvl, "ApID", "-");
138 ibt_hca = ibt_hca->ha_clnt_link;
139 continue;
140 }
141
142 /* Check if this client has more than one HCAs */
143 if (clntp->clnt_hca_list->ha_hca_link == NULL)
144 (void) nvlist_add_string(nvl, "Alt_HCA", "no");
145 else
146 (void) nvlist_add_string(nvl, "Alt_HCA", "yes");
147
148 if (child == NULL) {
149 (void) nvlist_add_string(nvl, "ApID", "-");
150 ibt_hca = ibt_hca->ha_clnt_link;
151 continue;
152 }
153
154 /*
155 * All IB clients (IOC, VPPA, Port, Pseudo etc.)
156 * need to be looked at. The parent of IOC nodes
157 * is "ib" nexus and node-name is "ioc". "VPPA/Port"s
158 * should have HCA as parent and node-name is "ibport".
159 * HCA validity is checked by looking at parent's "dip"
160 * and the dip saved in the ibtl_hca_devinfo_t.
161 * NOTE: We only want to list this HCA's IB clients.
162 * All others clients are ignored.
163 */
164 parent = ddi_get_parent(child);
165 if (parent == NULL || /* No parent? */
166 ddi_get_parent_data(child) == NULL) {
167 (void) nvlist_add_string(nvl, "ApID", "-");
168 ibt_hca = ibt_hca->ha_clnt_link;
169 continue;
170 }
171
172 node_name = ddi_node_name(child);
173 if ((strcmp(ddi_node_name(parent), "ib") == 0) ||
174 ((hca_devp->hd_hca_dip == parent) &&
175 (strncmp(node_name, IBNEX_IBPORT_CNAME, 6) == 0))) {
176 ASSERT(callback != NULL);
177 /*
178 * Callback is invoked to figure out the
179 * ap_id string.
180 */
181 callback(child, &ret_apid);
182 (void) nvlist_add_string(nvl, "ApID", ret_apid);
183 } else {
184 (void) nvlist_add_string(nvl, "ApID", "-");
185 }
186
187 } else if (flag == IBTL_IBNEX_UNCFG_CLNTS_FLAG) {
188 char path[MAXPATHLEN];
189
190 if (child == NULL) {
191 IBTF_DPRINTF_L4(ibtl_ibnex,
192 "ibtl_ibnex_get_hca_info: No dip exists");
193 ibt_hca = ibt_hca->ha_clnt_link;
194 continue;
195 }
196
197 /*
198 * if the child has a alternate HCA then skip it
199 */
200 if (clntp->clnt_hca_list->ha_hca_link) {
201 IBTF_DPRINTF_L4(ibtl_ibnex,
202 "ibtl_ibnex_get_hca_info: Alt HCA exists");
203 ibt_hca = ibt_hca->ha_clnt_link;
204 continue;
205 }
206
207 /*
208 * See earlier comments on how to check if a client
209 * is IOC, VPPA, Port or a Pseudo node.
210 */
211 parent = ddi_get_parent(child);
212 if (parent == NULL || /* No parent? */
213 ddi_get_parent_data(child) == NULL) {
214 IBTF_DPRINTF_L4(ibtl_ibnex,
215 "ibtl_ibnex_get_hca_info: no parent");
216 ibt_hca = ibt_hca->ha_clnt_link;
217 continue;
218 }
219
220 node_name = ddi_node_name(child);
221 if ((strcmp(ddi_node_name(parent), "ib") == 0) ||
222 ((hca_devp->hd_hca_dip == parent) &&
223 (strncmp(node_name, IBNEX_IBPORT_CNAME, 6) == 0))) {
224 ASSERT(callback != NULL);
225 /*
226 * Callback is invoked to figure out the
227 * ap_id string.
228 */
229 callback(child, &ret_apid);
230 (void) nvlist_add_string(nvl, "ApID", ret_apid);
231
232 /*
233 * ddi_pathname() doesn't supply /devices,
234 * so we do
235 */
236 (void) strcpy(path, "/devices");
237 (void) ddi_pathname(child, path + strlen(path));
238 IBTF_DPRINTF_L4(ibtl_ibnex,
239 "ibtl_ibnex_get_hca_info: "
240 "device path = %s", path);
241
242 if (nvlist_add_string(nvl, "devpath", path)) {
243 IBTF_DPRINTF_L2(ibtl_ibnex,
244 "ibtl_ibnex_get_hca_info: "
245 "failed to fill in path %s", path);
246 mutex_exit(&ibtl_clnt_list_mutex);
247 nvlist_free(nvl);
248 kmem_free(ret_apid,
249 IBTL_IBNEX_APID_LEN);
250 return (ibt_get_module_failure(
251 IBT_FAILURE_IBTL, 0));
252 }
253 } /* end of if */
254 } /* end of while */
255
256 ibt_hca = ibt_hca->ha_clnt_link;
257 } /* End of while */
258 mutex_exit(&ibtl_clnt_list_mutex);
259
260 kmem_free(ret_apid, IBTL_IBNEX_APID_LEN);
261
262 /* Pack all data into "buffer" */
263 if (nvlist_pack(nvl, buffer, bufsiz, NV_ENCODE_NATIVE, KM_SLEEP)) {
264 IBTF_DPRINTF_L2(ibtl_ibnex, "ibtl_ibnex_get_hca_info: "
265 "nvlist_pack failed");
266 nvlist_free(nvl);
267 return (ibt_get_module_failure(IBT_FAILURE_IBTL, 0));
268 }
269
270 IBTF_DPRINTF_L4(ibtl_ibnex, "ibtl_ibnex_get_hca_info: size = %x",
271 *bufsiz);
272 nvlist_free(nvl);
273 return (IBT_SUCCESS);
274 }
275
276
277 /*
278 * Function:
279 * ibtl_ibnex_register_callback()
280 * Input:
281 * ibnex_cb - IB nexus driver callback routine
282 * Output:
283 * none
284 * Returns:
285 * none
286 * Description:
287 * Register a callback routine for IB nexus driver
288 */
289 void
ibtl_ibnex_register_callback(ibtl_ibnex_callback_t ibnex_cb)290 ibtl_ibnex_register_callback(ibtl_ibnex_callback_t ibnex_cb)
291 {
292 IBTF_DPRINTF_L5(ibtl_ibnex, "ibtl_ibnex_register_callback:");
293
294 mutex_enter(&ibtl_clnt_list_mutex);
295 ibtl_ibnex_callback_routine = ibnex_cb;
296 mutex_exit(&ibtl_clnt_list_mutex);
297 }
298
299 /*
300 * Function:
301 * ibtl_ibnex_unregister_callback()
302 * Input:
303 * none
304 * Output:
305 * none
306 * Returns:
307 * none
308 * Description:
309 * Un-register a callback routine for IB nexus driver
310 */
311 void
ibtl_ibnex_unregister_callback()312 ibtl_ibnex_unregister_callback()
313 {
314 IBTF_DPRINTF_L5(ibtl_ibnex, "ibtl_ibnex_unregister_callback: ibnex cb");
315
316 mutex_enter(&ibtl_clnt_list_mutex);
317 ibtl_ibnex_callback_routine = NULL;
318 mutex_exit(&ibtl_clnt_list_mutex);
319 }
320
321
322 /*
323 * Function:
324 * ibtl_ibnex_hcadip2guid
325 * Input:
326 * dev_info_t - The "dip" of this HCA
327 * Output:
328 * hca_guid - The HCA's node GUID.
329 * Returns:
330 * "HCA GUID" on SUCCESS, NULL on FAILURE
331 * Description:
332 * For a given HCA node GUID it figures out the HCA GUID
333 * and returns it. If not found, NULL is returned.
334 */
335 ib_guid_t
ibtl_ibnex_hcadip2guid(dev_info_t * hca_dip)336 ibtl_ibnex_hcadip2guid(dev_info_t *hca_dip)
337 {
338 ib_guid_t hca_guid = 0LL;
339 ibtl_hca_devinfo_t *hca_devp;
340
341 mutex_enter(&ibtl_clnt_list_mutex);
342 hca_devp = ibtl_hca_list;
343
344 while (hca_devp) {
345 if (hca_devp->hd_hca_dip == hca_dip) {
346 hca_guid = hca_devp->hd_hca_attr->hca_node_guid;
347 break;
348 }
349 hca_devp = hca_devp->hd_hca_dev_link;
350 }
351 mutex_exit(&ibtl_clnt_list_mutex);
352 IBTF_DPRINTF_L4(ibtl_ibnex, "ibtl_ibnex_hcadip_guid: hca_guid 0x%llX",
353 hca_guid);
354 return (hca_guid);
355 }
356
357
358 /*
359 * Function:
360 * ibtl_ibnex_hcaguid2dip
361 * Input:
362 * hca_guid - The HCA's node GUID.
363 * Output:
364 * dev_info_t - The "dip" of this HCA
365 * Returns:
366 * "dip" on SUCCESS, NULL on FAILURE
367 * Description:
368 * For a given HCA node GUID it figures out the "dip"
369 * and returns it. If not found, NULL is returned.
370 */
371 dev_info_t *
ibtl_ibnex_hcaguid2dip(ib_guid_t hca_guid)372 ibtl_ibnex_hcaguid2dip(ib_guid_t hca_guid)
373 {
374 dev_info_t *dip = NULL;
375 ibtl_hca_devinfo_t *hca_devp;
376
377 IBTF_DPRINTF_L4(ibtl_ibnex, "ibtl_ibnex_hcaguid2dip:");
378
379 mutex_enter(&ibtl_clnt_list_mutex);
380 hca_devp = ibtl_hca_list;
381
382 while (hca_devp) {
383 if (hca_devp->hd_hca_attr->hca_node_guid == hca_guid) {
384 dip = hca_devp->hd_hca_dip;
385 break;
386 }
387 hca_devp = hca_devp->hd_hca_dev_link;
388 }
389 mutex_exit(&ibtl_clnt_list_mutex);
390 return (dip);
391 }
392
393
394 /*
395 * Function:
396 * ibtl_ibnex_get_hca_verbose_data
397 * Input:
398 * hca_guid - The HCA's node GUID.
399 * Output:
400 * buffer - The information is returned in this buffer
401 * bufsiz - The size of the information buffer
402 * Returns:
403 * IBT_SUCCESS/IBT_HCA_INVALID
404 * Description:
405 * For a given HCA node GUID it figures out the verbose listing display.
406 */
407 ibt_status_t
ibtl_ibnex_get_hca_verbose_data(ib_guid_t hca_guid,char ** buffer,size_t * bufsiz)408 ibtl_ibnex_get_hca_verbose_data(ib_guid_t hca_guid, char **buffer,
409 size_t *bufsiz)
410 {
411 char path[IBTL_IBNEX_STR_LEN];
412 char tmp[MAXPATHLEN];
413 uint_t ii;
414 ibt_hca_portinfo_t *pinfop;
415 ibtl_hca_devinfo_t *hca_devp;
416
417 IBTF_DPRINTF_L3(ibtl_ibnex, "ibtl_ibnex_get_hca_verbose_data: "
418 "HCA GUID 0x%llX", hca_guid);
419
420 *buffer = NULL;
421 *bufsiz = 0;
422
423 mutex_enter(&ibtl_clnt_list_mutex);
424 if ((hca_devp = ibtl_get_hcadevinfo(hca_guid)) == NULL) {
425 mutex_exit(&ibtl_clnt_list_mutex);
426
427 /*
428 * If we are here, then the requested HCA device is not
429 * present. Return the status as Invalid HCA GUID.
430 */
431 IBTF_DPRINTF_L2(ibtl_ibnex, "ibtl_ibnex_get_hca_verbose_data: "
432 "HCA Not Found, Invalid HCA GUID");
433 return (IBT_HCA_INVALID);
434 }
435
436 (void) snprintf(tmp, MAXPATHLEN, "VID: 0x%x, PID: 0x%x, #ports: 0x%x",
437 hca_devp->hd_hca_attr->hca_vendor_id,
438 hca_devp->hd_hca_attr->hca_device_id,
439 hca_devp->hd_hca_attr->hca_nports);
440
441 pinfop = hca_devp->hd_portinfop;
442 for (ii = 0; ii < hca_devp->hd_hca_attr->hca_nports; ii++) {
443 (void) snprintf(path, IBTL_IBNEX_STR_LEN,
444 ", port%d GUID: 0x%llX", ii + 1,
445 (longlong_t)pinfop[ii].p_sgid_tbl->gid_guid);
446 (void) strcat(tmp, path);
447 }
448 mutex_exit(&ibtl_clnt_list_mutex);
449
450 *bufsiz = strlen(tmp);
451 *buffer = kmem_alloc(*bufsiz, KM_SLEEP);
452 (void) strncpy(*buffer, tmp, *bufsiz);
453
454 IBTF_DPRINTF_L4(ibtl_ibnex, "ibtl_ibnex_get_hca_verbose_data: "
455 "data = %s, size = 0x%x", *buffer, *bufsiz);
456 return (IBT_SUCCESS);
457 }
458
459 /*
460 * Function:
461 * ibt_reprobe_dev()
462 * Input:
463 * dev_info_t *dip
464 * Output:
465 * none
466 * Returns:
467 * Return value from IBnexus callback handler
468 * IBT_ILLEGAL_OP if IBnexus callback is not installed.
469 * Description:
470 * This function passes the IBTF client's "reprobe device
471 * properties" request to IBnexus. See ibt_reprobe_dev(9f)
472 * for details.
473 */
474 ibt_status_t
ibt_reprobe_dev(dev_info_t * dip)475 ibt_reprobe_dev(dev_info_t *dip)
476 {
477 ibt_status_t rv;
478 ibtl_ibnex_cb_args_t cb_args;
479
480 if (dip == NULL)
481 return (IBT_NOT_SUPPORTED);
482
483 /*
484 * Restricting the reprobe request to the children of
485 * ibnexus. Note the IB_CONF_UPDATE_EVENT DDI event can
486 * be subscribed by any device on the IBnexus device tree.
487 */
488 if (strcmp(ddi_node_name(ddi_get_parent(dip)), "ib") != 0)
489 return (IBT_NOT_SUPPORTED);
490
491 /* Reprobe for IOC nodes only */
492 if (strncmp(ddi_node_name(dip), IBNEX_IBPORT_CNAME, 6) == 0)
493 return (IBT_NOT_SUPPORTED);
494
495 cb_args.cb_flag = IBTL_IBNEX_REPROBE_DEV_REQ;
496 cb_args.cb_dip = dip;
497 mutex_enter(&ibtl_clnt_list_mutex);
498 if (ibtl_ibnex_callback_routine) {
499 rv = (*ibtl_ibnex_callback_routine)(&cb_args);
500 mutex_exit(&ibtl_clnt_list_mutex);
501 return (rv);
502 }
503 mutex_exit(&ibtl_clnt_list_mutex);
504
505 /* Should -not- come here */
506 IBTF_DPRINTF_L2("ibtl", "ibt_reprobe_dev: ibnex not registered!!");
507 return (IBT_ILLEGAL_OP);
508 }
509
510
511 /*
512 * Function:
513 * ibtl_ibnex_valid_hca_parent
514 * Input:
515 * pdip - The parent dip from client's child dev_info_t
516 * Output:
517 * NONE
518 * Returns:
519 * IBT_SUCCESS/IBT_NO_HCAS_AVAILABLE
520 * Description:
521 * For a given pdip, of Port/VPPA devices, match it against all the
522 * registered HCAs's dip. If match found return IBT_SUCCESS,
523 * else IBT_NO_HCAS_AVAILABLE.
524 *
525 * For IOC/Pseudo devices check if the given pdip is that of
526 * the ib(4D) nexus or that of the eoib(4D) nexus. If yes
527 * return IBT_SUCCESS, else IBT_NO_HCAS_AVAILABLE.
528 */
529 ibt_status_t
ibtl_ibnex_valid_hca_parent(dev_info_t * pdip)530 ibtl_ibnex_valid_hca_parent(dev_info_t *pdip)
531 {
532 ibtl_hca_devinfo_t *hca_devp;
533
534 IBTF_DPRINTF_L4(ibtl_ibnex, "ibtl_ibnex_valid_hca_parent: pdip %p",
535 pdip);
536
537 /* For Pseudo devices and IOCs */
538 if (strncmp(ddi_node_name(pdip), "ib", 2) == 0 ||
539 strncmp(ddi_node_name(pdip), "eibnx", 5) == 0) {
540 return (IBT_SUCCESS);
541 } else {
542 /* For Port devices and VPPAs */
543 mutex_enter(&ibtl_clnt_list_mutex);
544 hca_devp = ibtl_hca_list;
545 while (hca_devp) {
546 if (hca_devp->hd_hca_dip == pdip) {
547 mutex_exit(&ibtl_clnt_list_mutex);
548 return (IBT_SUCCESS);
549 }
550 hca_devp = hca_devp->hd_hca_dev_link;
551 }
552 mutex_exit(&ibtl_clnt_list_mutex);
553 return (IBT_NO_HCAS_AVAILABLE);
554 }
555 }
556
557 /*
558 * Function:
559 * ibtl_ibnex_phci_register
560 * Input:
561 * hca_dip - The HCA dip
562 * Output:
563 * NONE
564 * Returns:
565 * IBT_SUCCESS/IBT_FAILURE
566 * Description:
567 * Register the HCA dip as the MPxIO PCHI.
568 */
569 ibt_status_t
ibtl_ibnex_phci_register(dev_info_t * hca_dip)570 ibtl_ibnex_phci_register(dev_info_t *hca_dip)
571 {
572 /* Register the with MPxIO as PHCI */
573 if (mdi_phci_register(MDI_HCI_CLASS_IB, hca_dip, 0) !=
574 MDI_SUCCESS) {
575 return (IBT_FAILURE);
576 }
577 return (IBT_SUCCESS);
578 }
579
580 /*
581 * Function:
582 * ibtl_ibnex_phci_unregister
583 * Input:
584 * hca_dip - The HCA dip
585 * Output:
586 * NONE
587 * Returns:
588 * IBT_SUCCESS/IBT_FAILURE
589 * Description:
590 * Free up any pending MPxIO Pathinfos and unregister the HCA dip as the
591 * MPxIO PCHI.
592 */
593 ibt_status_t
ibtl_ibnex_phci_unregister(dev_info_t * hca_dip)594 ibtl_ibnex_phci_unregister(dev_info_t *hca_dip)
595 {
596 mdi_pathinfo_t *pip = NULL;
597 dev_info_t *vdip = 0;
598
599 /*
600 * Should free all the Pathinfos associated with the HCA pdip before
601 * unregistering the PHCI.
602 *
603 * mdi_pi_free will call ib_vhci_pi_uninit() callbackfor each PI where
604 * the ibnex internal datastructures (ibnex_node_data) will have to be
605 * cleaned up if needed.
606 */
607 vdip = mdi_devi_get_vdip(hca_dip);
608 ndi_devi_enter(vdip);
609 ndi_devi_enter(hca_dip);
610 while (pip = mdi_get_next_client_path(hca_dip, NULL)) {
611 if (mdi_pi_free(pip, 0) == MDI_SUCCESS) {
612 continue;
613 }
614 ndi_devi_exit(hca_dip);
615 ndi_devi_exit(vdip);
616 IBTF_DPRINTF_L1(ibtl_ibnex, "ibtl_ibnex_phci_unregister: "
617 "mdi_pi_free failed");
618 return (IBT_FAILURE);
619 }
620 ndi_devi_exit(hca_dip);
621 ndi_devi_exit(vdip);
622
623 if (mdi_phci_unregister(hca_dip, 0) != MDI_SUCCESS) {
624 IBTF_DPRINTF_L1(ibtl_ibnex, "ibtl_ibnex_phci_unregister: PHCI "
625 "unregister failed");
626 return (IBT_FAILURE);
627 }
628 return (IBT_SUCCESS);
629 }
630
631 /*
632 * Function:
633 * ibtl_ibnex_query_hca_byguid
634 * Input:
635 * hca_guid - The HCA's node GUID.
636 * driver_name_size- size of the caller allocated driver_name buffer
637 * Output:
638 * hca_attrs - caller allocated buffer which will contain
639 * HCA attributes upon success
640 * driver_name - caller allocated buffer which will contain
641 * HCA driver name upon success
642 * driver_instance - HCA driver instance
643 * hca_device_path - caller allocated buffer of size MAXPATHLEN which
644 * will contain hca device path upon success.
645 * Returns:
646 * IBT_SUCCESS/IBT_FAILURE
647 * Description:
648 * Get the HCA attributes, driver name and instance number of the
649 * specified HCA.
650 */
651 ibt_status_t
ibtl_ibnex_query_hca_byguid(ib_guid_t hca_guid,ibt_hca_attr_t * hca_attrs,char * driver_name,size_t driver_name_size,int * driver_instance,char * hca_device_path)652 ibtl_ibnex_query_hca_byguid(ib_guid_t hca_guid, ibt_hca_attr_t *hca_attrs,
653 char *driver_name, size_t driver_name_size, int *driver_instance,
654 char *hca_device_path)
655 {
656 ibtl_hca_devinfo_t *hca_devp;
657
658 IBTF_DPRINTF_L4(ibtl_ibnex, "ibtl_ibnex_query_hca_byguid("
659 "hca_guid = 0x%llx, hca_attrs = 0x%p, driver_name = 0x%p, "
660 "driver_name_size = 0x%d, driver_instancep = 0x%p)", hca_guid,
661 hca_attrs, driver_name, (int)driver_name_size, driver_instance);
662
663 mutex_enter(&ibtl_clnt_list_mutex);
664
665 hca_devp = ibtl_get_hcadevinfo(hca_guid);
666 if (hca_devp == NULL) {
667 mutex_exit(&ibtl_clnt_list_mutex);
668 return (IBT_HCA_INVALID);
669 }
670
671 if (strlcpy(driver_name,
672 ddi_driver_name(hca_devp->hd_hca_dip), driver_name_size) >=
673 driver_name_size) {
674 mutex_exit(&ibtl_clnt_list_mutex);
675 return (IBT_INSUFF_KERNEL_RESOURCE);
676 }
677
678 (void) ddi_pathname(hca_devp->hd_hca_dip, hca_device_path);
679 *driver_instance = ddi_get_instance(hca_devp->hd_hca_dip);
680 bcopy(hca_devp->hd_hca_attr, hca_attrs, sizeof (ibt_hca_attr_t));
681
682 mutex_exit(&ibtl_clnt_list_mutex);
683 return (IBT_SUCCESS);
684 }
685