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.
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.
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]
22 * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
26 * This file contains support required for IB cfgadm plugin.
31 #include <sys/modctl.h>
32 #include <sys/ib/mgt/ibdm/ibdm_impl.h>
33 #include <sys/ib/ibnex/ibnex.h>
34 #include <sys/ib/ibnex/ibnex_devctl.h>
35 #include <sys/ib/ibtl/impl/ibtl_ibnex.h>
36 #include <sys/ib/ibtl/impl/ibtl.h>
38 #include <sys/sunndi.h>
39 #include <sys/fs/dv_node.h>
40 #include <sys/mdi_impldefs.h>
41 #include <sys/sunmdi.h>
43 /* return the minimum value of (x) and (y) */
44 #define MIN(x, y) ((x) < (y) ? (x) : (y))
49 int ibnex_open(dev_t
*, int, int, cred_t
*);
50 int ibnex_close(dev_t
, int, int, cred_t
*);
51 int ibnex_ioctl(dev_t
, int, intptr_t, int, cred_t
*, int *);
52 int ibnex_offline_childdip(dev_info_t
*);
53 static int ibnex_get_num_devices(void);
54 static int ibnex_get_snapshot(char **, size_t *, int);
55 static int ibnex_get_commsvcnode_snapshot(nvlist_t
**, ib_guid_t
,
56 ib_guid_t
, int, ib_pkey_t
, ibnex_node_type_t
);
57 static int ibnex_fill_ioc_tmp(nvlist_t
**, ibdm_ioc_info_t
*);
58 static int ibnex_fill_nodeinfo(nvlist_t
**, ibnex_node_data_t
*,
60 static void ibnex_figure_ap_devstate(ibnex_node_data_t
*,
62 static void ibnex_figure_ib_apid_devstate(devctl_ap_state_t
*);
63 static char *ibnex_get_apid(struct devctl_iocdata
*);
64 static int ibnex_get_dip_from_apid(char *, dev_info_t
**,
65 ibnex_node_data_t
**);
66 extern int ibnex_get_node_and_dip_from_guid(ib_guid_t
, int,
67 ib_pkey_t
, ibnex_node_data_t
**, dev_info_t
**);
68 static ibnex_rval_t
ibnex_handle_pseudo_configure(char *);
69 static ibnex_rval_t
ibnex_handle_ioc_configure(char *);
70 static ibnex_rval_t
ibnex_handle_commsvcnode_configure(char *);
71 static void ibnex_return_apid(dev_info_t
*, char **);
72 static void ibnex_port_conf_entry_add(char *);
73 static void ibnex_vppa_conf_entry_add(char *);
74 static void ibnex_hcasvc_conf_entry_add(char *);
75 static int ibnex_port_conf_entry_delete(char *, char *);
76 static int ibnex_vppa_conf_entry_delete(char *, char *);
77 static int ibnex_hcasvc_conf_entry_delete(char *, char *);
79 static ibnex_rval_t
ibnex_ioc_fininode(dev_info_t
*, ibnex_ioc_node_t
*);
80 static ibnex_rval_t
ibnex_commsvc_fininode(dev_info_t
*);
81 static ibnex_rval_t
ibnex_pseudo_fininode(dev_info_t
*);
83 static int ibnex_devctl(dev_t
, int, intptr_t, int,
85 static int ibnex_ctl_get_api_ver(dev_t
, int, intptr_t, int,
87 static int ibnex_ctl_get_hca_list(dev_t
, int, intptr_t, int,
89 static int ibnex_ctl_query_hca(dev_t
, int, intptr_t, int,
91 static int ibnex_ctl_query_hca_port(dev_t
, int, intptr_t, int,
94 extern uint64_t ibnex_str2hex(char *, int, int *);
95 extern int ibnex_ioc_initnode_all_pi(ibdm_ioc_info_t
*);
96 extern dev_info_t
*ibnex_commsvc_initnode(dev_info_t
*,
97 ibdm_port_attr_t
*, int, int, ib_pkey_t
, int *,
99 extern int ibnex_get_dip_from_guid(ib_guid_t
, int,
100 ib_pkey_t
, dev_info_t
**);
101 extern void ibnex_reprobe_ioc_dev(void *arg
);
102 extern void ibnex_reprobe_ioc_all();
103 extern int ibnex_pseudo_create_all_pi(ibnex_node_data_t
*);
104 extern void ibnex_pseudo_initnodes(void);
106 extern ibnex_t ibnex
;
113 ibnex_open(dev_t
*dev
, int flag
, int otyp
, cred_t
*credp
)
115 IBTF_DPRINTF_L4("ibnex", "\topen");
125 ibnex_close(dev_t dev
, int flag
, int otyp
, cred_t
*credp
)
127 IBTF_DPRINTF_L4("ibnex", "\tclose");
132 ibnex_ioctl(dev_t dev
, int cmd
, intptr_t arg
, int mode
, cred_t
*credp
,
136 * For all generic devctl ioctls (such as DEVCTL_AP_CONFIGURE),
137 * call ibnex_devctl().
140 return (ibnex_devctl(dev
, cmd
, arg
, mode
, credp
, rvalp
));
143 * The rest are ibnex specific ioctls.
147 case IBNEX_CTL_GET_API_VER
:
148 return (ibnex_ctl_get_api_ver(dev
, cmd
, arg
, mode
,
151 case IBNEX_CTL_GET_HCA_LIST
:
152 return (ibnex_ctl_get_hca_list(dev
, cmd
, arg
, mode
,
155 case IBNEX_CTL_QUERY_HCA
:
156 return (ibnex_ctl_query_hca(dev
, cmd
, arg
, mode
,
159 case IBNEX_CTL_QUERY_HCA_PORT
:
160 return (ibnex_ctl_query_hca_port(dev
, cmd
, arg
, mode
,
170 * Ioctl routine for cfgadm controls
171 * DEVCTL_AP_GETSTATE: returns attachment point state
172 * DEVCTL_AP_CONTROL: Does "ibnex" specific ioctls listed below
173 * IBNEX_NUM_DEVICE_NODES Gives how many device nodes exist?
174 * IBNEX_NUM_HCA_NODES Gives how many HCAs exist in the fabric
175 * IBNEX_UPDATE_PKEY_TBLS "-x update_pkey_tbls"
176 * IBNEX_GET_SNAPSHOT Gets the "snapshot" back to user-land
177 * IBNEX_SNAPSHOT_SIZE What is "snapshot" size
178 * IBNEX_DEVICE_PATH_SZ What is device-path size
179 * IBNEX_GET_DEVICE_PATH Gets the device path for Dynamic ap
180 * IBNEX_HCA_LIST_SZ "-x list" option size for the HCA ap_id
181 * IBNEX_HCA_LIST_INFO "-x list" option info for the HCA ap_id
182 * IBNEX_UNCFG_CLNTS_SZ "-x unconfig_client option size"
183 * IBNEX_UNCFG_CLNTS_INFO "-x unconfig_client data"
184 * IBNEX_CONF_ENTRY_ADD: "-x add_service"
185 * IBNEX_CONF_ENTRY_DEL: "-x delete_service"
186 * IBNEX_HCA_VERBOSE_SZ: "-alv hca_apid data size"
187 * IBNEX_HCA_VERBOSE_INFO: "-alv hca_apid actual data"
188 * IBNEX_UPDATE_IOC_CONF "-x update_ioc_conf"
189 * DEVCTL_AP_CONFIGURE: "configure" the attachment point
190 * DEVCTL_AP_UNCONFIGURE: "unconfigure" the attachment point
194 ibnex_devctl(dev_t dev
, int cmd
, intptr_t arg
, int mode
, cred_t
*credp
,
197 int ret
, rv
= 0, ioc_reprobe_pending
= 0;
199 char *snapshot
= NULL
;
201 char *service
= NULL
;
206 size_t snapshot_sz
= 0;
210 boolean_t apid_alloced
= B_FALSE
;
211 dev_info_t
*apid_dip
= NULL
;
213 ibnex_rval_t ret_val
;
214 ib_service_type_t svc_type
= IB_NONE
;
215 devctl_ap_state_t ap_state
;
216 ibnex_node_data_t
*nodep
= NULL
;
217 ibnex_node_data_t
*scanp
;
218 struct devctl_iocdata
*dcp
= NULL
;
220 IBTF_DPRINTF_L4("ibnex", "\tdevctl: cmd=%x, arg=%p, mode=%x, cred=%p, "
221 "\t\trval=%p dev=0x%x", cmd
, arg
, mode
, credp
, rvalp
, dev
);
223 /* read devctl ioctl data */
224 if ((cmd
!= DEVCTL_AP_CONTROL
) &&
225 (ndi_dc_allochdl((void *)arg
, &dcp
) != NDI_SUCCESS
)) {
226 IBTF_DPRINTF_L4("ibnex",
227 "\tdevctl: ndi_dc_allochdl failed\n");
231 mutex_enter(&ibnex
.ibnex_mutex
);
233 case DEVCTL_AP_GETSTATE
:
234 msg
= "\tdevctl: DEVCTL_AP_GETSTATE";
235 IBTF_DPRINTF_L4("ibnex", "%s:", msg
);
237 apid_n
= ibnex_get_apid(dcp
);
238 if (*apid_n
== '\0') {
239 IBTF_DPRINTF_L2("ibnex",
240 "%s: ibnex_get_apid failed", msg
);
245 if (strncmp(apid_n
, IBNEX_FABRIC
, strlen(IBNEX_FABRIC
)) == 0) {
246 ibnex_figure_ib_apid_devstate(&ap_state
);
247 apid_dip
= ibnex
.ibnex_dip
;
249 /* if this apid is already seen by IBNEX, get the dip */
250 rv
= ibnex_get_dip_from_apid(apid_n
, &apid_dip
, &nodep
);
251 if (rv
!= IBNEX_DYN_APID
) {
252 IBTF_DPRINTF_L2("ibnex",
253 "%s: ibnex_get_dip_from_apid failed", msg
);
258 ndi_rele_devi(apid_dip
);
259 /* rv could be something undesirable, so reset it */
262 ibnex_figure_ap_devstate(nodep
, &ap_state
);
265 /* copy the return-AP-state information to the user space */
266 if (ndi_dc_return_ap_state(&ap_state
, dcp
) != NDI_SUCCESS
) {
267 IBTF_DPRINTF_L2("ibnex",
268 "%s: ndi_dc_return_ap_state failed", msg
);
273 case DEVCTL_AP_CONTROL
:
276 ibnex_ioctl_data_t ioc
; /* for 64-bit copies only */
278 msg
= "\tdevctl: DEVCTL_AP_CONTROL";
279 #ifdef _MULTI_DATAMODEL
280 if (ddi_model_convert_from(mode
& FMODELS
) == DDI_MODEL_ILP32
) {
281 ibnex_ioctl_data_32_t ioc32
;
283 if (ddi_copyin((void *)arg
, &ioc32
,
284 sizeof (ioc32
), mode
) != 0) {
285 IBTF_DPRINTF_L2("ibnex",
286 "%s: ddi_copyin err 1", msg
);
290 ioc
.cmd
= (uint_t
)ioc32
.cmd
;
291 ioc
.buf
= (caddr_t
)(uintptr_t)ioc32
.buf
;
292 ioc
.bufsiz
= (uint_t
)ioc32
.bufsiz
;
293 ioc
.ap_id
= (caddr_t
)(uintptr_t)ioc32
.ap_id
;
294 ioc
.ap_id_len
= (uint_t
)ioc32
.ap_id_len
;
295 ioc
.misc_arg
= (uint_t
)ioc32
.misc_arg
;
298 if (ddi_copyin((void *)arg
, &ioc
, sizeof (ioc
),
300 IBTF_DPRINTF_L2("ibnex",
301 "%s: ddi_copyin 2 failed", msg
);
305 #endif /* _MULTI_DATAMODEL */
307 IBTF_DPRINTF_L4("ibnex", "%s: \n\tioc: cmd=%x buf=%p, "
308 "bufsiz=%d", msg
, ioc
.cmd
, ioc
.buf
, ioc
.bufsiz
);
311 * figure out ap_id name as passed from user-land
312 * NOTE: We don't need to figure out ap_id for these
314 * IBNEX_NUM_DEVICE_NODES, IBNEX_NUM_HCA_NODES
316 * Hence, In user-land, these two ioctls force "ap_id_len" to 0.
318 if (ioc
.ap_id_len
> 0) {
319 apid_alloced
= B_TRUE
;
320 apid_len
= ioc
.ap_id_len
+ 1;
321 apid_n
= kmem_zalloc(apid_len
, KM_SLEEP
);
322 if (ddi_copyin((void *)ioc
.ap_id
, apid_n
,
323 ioc
.ap_id_len
, mode
) != 0) {
324 IBTF_DPRINTF_L2("ibnex",
325 "%s: ddi_copyin err 3", msg
);
330 IBTF_DPRINTF_L3("ibnex", "%s: apid_n= %s", msg
, apid_n
);
334 /* process sub-commands */
336 case IBNEX_NUM_DEVICE_NODES
:
337 msg
= "\tdevctl: DEVCTL_AP_CONTROL: NUM_DEVICE_NODES";
340 * figure out how many IOC, VPPA,
341 * Pseudo and Port nodes are present
343 num_nodes
= ibnex_get_num_devices();
344 IBTF_DPRINTF_L4("ibnex", "%s: num_nodes = %d",
347 if (ddi_copyout(&num_nodes
, ioc
.buf
,
348 ioc
.bufsiz
, mode
) != 0) {
349 IBTF_DPRINTF_L2("ibnex", "%s: copyout", msg
);
352 mutex_exit(&ibnex
.ibnex_mutex
);
355 case IBNEX_NUM_HCA_NODES
:
356 msg
= "\tdevctl: DEVCTL_AP_CONTROL: NUM_HCA_NODES";
358 /* figure out how many HCAs are present in the host */
359 mutex_exit(&ibnex
.ibnex_mutex
);
360 num_hcas
= ibt_get_hca_list(NULL
);
361 IBTF_DPRINTF_L4("ibnex", "%s: num %d", msg
, num_hcas
);
363 if (ddi_copyout(&num_hcas
, ioc
.buf
,
364 ioc
.bufsiz
, mode
) != 0) {
365 IBTF_DPRINTF_L2("ibnex", "%s: copyout", msg
);
370 case IBNEX_UPDATE_PKEY_TBLS
:
371 msg
= "\tdevctl: DEVCTL_AP_CONTROL: UPDATE_PKEY_TBLS";
372 IBTF_DPRINTF_L4("ibnex", "%s", msg
);
375 * update P_Key tables:
376 * ibdm_ibnex_update_pkey_tbls() calls
377 * ibt_query_hca_ports_byguids() for all the
378 * HCAs that the IBDM has "seen" in the system.
379 * This ends up updating the IBTL P_Key database.
380 * NOTE: Changes in this area will break this
381 * assumption. Initially the plan was to call
382 * ibt_query_hca_ports_byguids() in IBTL but
383 * IBDM needs to call it as well. So, eliminating
384 * the first invocation.
386 * It next updates the DM P_Key database.
387 * Note that the DM P_Key database updating
388 * will always be driven through cfgadm.
390 mutex_exit(&ibnex
.ibnex_mutex
);
391 ibdm_ibnex_update_pkey_tbls();
392 mutex_enter(&ibnex
.ibnex_mutex
);
395 case IBNEX_GET_SNAPSHOT
:
396 case IBNEX_SNAPSHOT_SIZE
:
397 msg
= (ioc
.cmd
== IBNEX_SNAPSHOT_SIZE
) ?
398 "\tdevctl: DEVCTL_AP_CONTROL: IBNEX_SNAPSHOT_SIZE" :
399 "\tdevctl: DEVCTL_AP_CONTROL: IBNEX_GET_SNAPSHOT";
401 IBTF_DPRINTF_L4("ibnex", "%s:", msg
);
403 if (ibnex_get_snapshot(&snapshot
, &snapshot_sz
,
404 ioc
.misc_arg
) != 0) {
405 IBTF_DPRINTF_L2("ibnex",
406 "%s:\n\tibnex_get_snapshot failed", msg
);
411 /* ssiz needs to be reinitialized again */
413 IBTF_DPRINTF_L4("ibnex",
414 "%s:\n\tsize =%x", msg
, snapshot_sz
);
416 if (ioc
.cmd
== IBNEX_SNAPSHOT_SIZE
) {
417 if (ddi_copyout(&ssiz
, ioc
.buf
,
418 ioc
.bufsiz
, mode
) != 0) {
419 IBTF_DPRINTF_L2("ibnex",
420 "%s:\n\tddi_copyout 2 failed", msg
);
425 if (ioc
.bufsiz
!= snapshot_sz
) {
426 IBTF_DPRINTF_L2("ibnex",
427 "%s:\n\tinvalid buffer size (%x %x)"
428 " ", msg
, ioc
.bufsiz
, snapshot_sz
);
431 } else if (ddi_copyout(snapshot
, ioc
.buf
,
432 ioc
.bufsiz
, mode
) != 0) {
433 IBTF_DPRINTF_L2("ibnex",
434 "%s:\n\tddi_copyout 3 failed", msg
);
439 kmem_free(snapshot
, snapshot_sz
);
442 case IBNEX_DEVICE_PATH_SZ
:
443 case IBNEX_GET_DEVICE_PATH
:
445 char path
[MAXPATHLEN
];
447 msg
= (ioc
.cmd
== IBNEX_DEVICE_PATH_SZ
) ?
448 "\tdevctl:DEVCTL_AP_CONTROL: IBNEX_DEVICE_PATH_SZ" :
449 "\tdevctl:DEVCTL_AP_CONTROL: IBNEX_GET_DEVICE_PATH";
451 IBTF_DPRINTF_L4("ibnex", "%s: apid = %s", msg
, apid_n
);
453 /* if this apid is already seen by IBNEX, get the dip */
454 rv
= ibnex_get_dip_from_apid(apid_n
, &apid_dip
, &nodep
);
455 if (rv
!= IBNEX_DYN_APID
|| apid_dip
== NULL
) {
456 IBTF_DPRINTF_L2("ibnex",
457 "%s:\n\tget_dip_from_apid failed", msg
);
461 ndi_rele_devi(apid_dip
);
463 /* ddi_pathname doesn't supply /devices, so we do. */
464 (void) strcpy(path
, "/devices");
465 (void) ddi_pathname(apid_dip
, path
+ strlen(path
));
466 ssiz
= (uint32_t)strlen(path
) + 1;
467 IBTF_DPRINTF_L4("ibnex",
468 "%s: len = %x\n\tpath = %s", msg
, ssiz
, path
);
470 /* rv could be something undesirable, so reset it */
473 if (ioc
.cmd
== IBNEX_DEVICE_PATH_SZ
) {
474 if (ddi_copyout(&ssiz
, ioc
.buf
,
475 ioc
.bufsiz
, mode
) != 0) {
476 IBTF_DPRINTF_L2("ibnex",
477 "%s: ddi_copyout 4 failed", msg
);
482 if (ioc
.bufsiz
!= ssiz
) {
483 IBTF_DPRINTF_L2("ibnex",
484 "%s: invalid size (%x, %x)",
485 msg
, ioc
.bufsiz
, ssiz
);
487 } else if (ddi_copyout(&path
, ioc
.buf
,
488 ioc
.bufsiz
, mode
) != 0) {
489 IBTF_DPRINTF_L2("ibnex", "%s "
490 "ddi_copyout 5 failed", msg
);
497 case IBNEX_HCA_LIST_SZ
:
498 case IBNEX_HCA_LIST_INFO
:
499 msg
= (ioc
.cmd
== IBNEX_HCA_LIST_SZ
) ?
500 "DEVCTL_AP_CONTROL: IBNEX_HCA_LIST_SZ" :
501 "DEVCTL_AP_CONTROL: IBNEX_HCA_LIST_INFO";
503 guid_str
= strrchr(apid_n
, ':') + 1;
504 IBTF_DPRINTF_L4("ibnex", "%s, input apid = %s, "
505 "guid = %s", msg
, apid_n
, guid_str
);
507 if (guid_str
== NULL
) {
508 IBTF_DPRINTF_L2("ibnex", "%s: invalid input "
509 "GUID passed %s", msg
, guid_str
);
514 /* Get the GUID(hex value) from apid_n */
515 hca_guid
= ibnex_str2hex(guid_str
, strlen(guid_str
),
517 if (ret
!= IBNEX_SUCCESS
) {
518 IBTF_DPRINTF_L2("ibnex", "%s: Invalid HCA "
523 IBTF_DPRINTF_L4("ibnex", "%s HCA GUID = %llX",
525 if (ibtl_ibnex_get_hca_info(hca_guid
,
526 IBTL_IBNEX_LIST_CLNTS_FLAG
, &snapshot
, &snapshot_sz
,
527 ibnex_return_apid
) != IBT_SUCCESS
) {
528 IBTF_DPRINTF_L2("ibnex",
529 "%s: get HCA consumers failed", msg
);
535 IBTF_DPRINTF_L4("ibnex", "%s: size =%x", msg
, ssiz
);
537 if (ioc
.cmd
== IBNEX_HCA_LIST_SZ
) {
538 if (ddi_copyout(&ssiz
, ioc
.buf
,
539 ioc
.bufsiz
, mode
) != 0) {
540 IBTF_DPRINTF_L2("ibnex",
541 "%s: ddi_copyout 6 failed", msg
);
545 if (ioc
.bufsiz
!= ssiz
) {
546 IBTF_DPRINTF_L2("ibnex", "%s: invalid "
547 "size (%x, %x)", msg
, ioc
.bufsiz
,
550 } else if (ddi_copyout(snapshot
, ioc
.buf
,
551 ioc
.bufsiz
, mode
) != 0) {
552 IBTF_DPRINTF_L2("ibnex", "%s "
553 "ddi_copyout 7 failed", msg
);
558 kmem_free(snapshot
, snapshot_sz
);
561 case IBNEX_UNCFG_CLNTS_SZ
:
562 case IBNEX_UNCFG_CLNTS_INFO
:
563 msg
= (ioc
.cmd
== IBNEX_UNCFG_CLNTS_SZ
) ?
564 "\tdevctl:DEVCTL_AP_CONTROL: IBNEX_UNCFG_CLNTS_SZ" :
565 "\tdevctl:DEVCTL_AP_CONTROL: "
566 "IBNEX_UNCFG_CLNTS_INFO";
568 guid_str
= strrchr(apid_n
, ':') + 1;
569 IBTF_DPRINTF_L4("ibnex", "%s, apid = %s, guid = %s",
570 msg
, apid_n
, guid_str
);
572 if (guid_str
== NULL
) {
573 IBTF_DPRINTF_L2("ibnex", "%s: invalid input "
574 "GUID %s", msg
, guid_str
);
579 /* Get the GUID(hex value) from apid_n */
580 hca_guid
= ibnex_str2hex(guid_str
, strlen(guid_str
),
582 if (ret
!= IBNEX_SUCCESS
) {
583 IBTF_DPRINTF_L2("ibnex", "%s: Invalid HCA "
584 "GUID string passed", msg
);
588 IBTF_DPRINTF_L4("ibnex", "%s G = %llX", msg
, hca_guid
);
589 if (ibtl_ibnex_get_hca_info(hca_guid
,
590 IBTL_IBNEX_UNCFG_CLNTS_FLAG
, &snapshot
,
591 &snapshot_sz
, ibnex_return_apid
) != IBT_SUCCESS
) {
592 IBTF_DPRINTF_L2("ibnex",
593 "%s: get HCA consumers failed", msg
);
597 /* ssiz needs to be reinitialized again */
600 IBTF_DPRINTF_L4("ibnex", "%s: size =%x", msg
, ssiz
);
602 if (ioc
.cmd
== IBNEX_UNCFG_CLNTS_SZ
) {
603 if (ddi_copyout(&ssiz
, ioc
.buf
,
604 ioc
.bufsiz
, mode
) != 0) {
605 IBTF_DPRINTF_L2("ibnex",
606 "%s: ddi_copyout 9 failed", msg
);
611 if (ioc
.bufsiz
!= ssiz
) {
612 IBTF_DPRINTF_L2("ibnex",
613 "%s: invalid size (%x, %x)",
614 msg
, ioc
.bufsiz
, ssiz
);
616 } else if (ddi_copyout(snapshot
, ioc
.buf
,
617 ioc
.bufsiz
, mode
) != 0) {
618 IBTF_DPRINTF_L2("ibnex", "%s "
619 "ddi_copyout 10 failed", msg
);
624 kmem_free(snapshot
, snapshot_sz
);
627 case IBNEX_CONF_ENTRY_ADD
:
628 msg
= "\tdevctl: IBNEX_CONF_ENTRY_ADD: ";
629 service
= kmem_zalloc(ioc
.bufsiz
+ 1, KM_SLEEP
);
630 /* read in the "service" name */
631 if (ddi_copyin(ioc
.buf
, service
,
632 ioc
.bufsiz
, mode
) != 0) {
633 IBTF_DPRINTF_L2("ibnex", "%s: ddi_copyin err 6",
639 /* read in the "service type" */
640 svc_type
= ioc
.misc_arg
;
641 IBTF_DPRINTF_L4("ibnex", "%s: service = %s, type = %d",
642 msg
, service
, svc_type
);
644 if (svc_type
== IB_PORT_SERVICE
) {
645 ibnex_port_conf_entry_add(service
);
646 } else if (svc_type
== IB_VPPA_SERVICE
) {
647 ibnex_vppa_conf_entry_add(service
);
648 } else if (svc_type
== IB_HCASVC_SERVICE
) {
649 ibnex_hcasvc_conf_entry_add(service
);
651 kmem_free(service
, ioc
.bufsiz
+ 1);
654 case IBNEX_CONF_ENTRY_DEL
:
655 msg
= "\tdevctl:IBNEX_CONF_ENTRY_DEL: ";
656 service
= kmem_zalloc(ioc
.bufsiz
+ 1, KM_SLEEP
);
657 /* read in the "service" name */
658 if (ddi_copyin(ioc
.buf
, service
,
659 ioc
.bufsiz
, mode
) != 0) {
660 IBTF_DPRINTF_L2("ibnex", "%s: ddi_copyin err 7",
666 /* read in the "service type" */
667 svc_type
= ioc
.misc_arg
;
668 IBTF_DPRINTF_L4("ibnex", "%s: service = %s, type = %d",
669 msg
, service
, svc_type
);
671 if (svc_type
== IB_PORT_SERVICE
) {
672 rv
= ibnex_port_conf_entry_delete(msg
, service
);
673 } else if (svc_type
== IB_VPPA_SERVICE
) {
674 rv
= ibnex_vppa_conf_entry_delete(msg
, service
);
675 } else if (svc_type
== IB_HCASVC_SERVICE
) {
676 rv
= ibnex_hcasvc_conf_entry_delete(msg
,
679 kmem_free(service
, ioc
.bufsiz
+ 1);
682 case IBNEX_HCA_VERBOSE_SZ
:
683 case IBNEX_HCA_VERBOSE_INFO
:
684 msg
= (ioc
.cmd
== IBNEX_HCA_VERBOSE_SZ
) ?
685 "DEVCTL_AP_CONTROL: IBNEX_HCA_VERBOSE_SZ" :
686 "DEVCTL_AP_CONTROL: IBNEX_HCA_VERBOSE_INFO";
688 guid_str
= strrchr(apid_n
, ':') + 1;
689 IBTF_DPRINTF_L4("ibnex", "%s, apid = %s, guid = %s",
690 msg
, apid_n
, guid_str
);
692 if (guid_str
== NULL
) {
693 IBTF_DPRINTF_L2("ibnex", "%s: invalid GUID %s",
699 /* Get the GUID(hex value) from apid_n */
700 hca_guid
= ibnex_str2hex(guid_str
, strlen(guid_str
),
702 if (ret
!= IBNEX_SUCCESS
) {
703 IBTF_DPRINTF_L2("ibnex", "%s: Invalid HCA GUID "
708 IBTF_DPRINTF_L4("ibnex", "%s HCA GUID = 0x%llX",
711 if (ibtl_ibnex_get_hca_verbose_data(hca_guid
, &snapshot
,
712 &snapshot_sz
) != IBT_SUCCESS
) {
713 IBTF_DPRINTF_L2("ibnex", "%s: get HCA verbose "
720 IBTF_DPRINTF_L4("ibnex", "%s: size =%x", msg
, ssiz
);
722 if (ioc
.cmd
== IBNEX_HCA_VERBOSE_SZ
) {
723 if (ddi_copyout(&ssiz
, ioc
.buf
,
724 ioc
.bufsiz
, mode
) != 0) {
725 IBTF_DPRINTF_L2("ibnex",
726 "%s: ddi_copyout 11 failed", msg
);
730 if (ioc
.bufsiz
!= ssiz
) {
731 IBTF_DPRINTF_L2("ibnex",
732 "%s: invalid size (%x, %x)",
733 msg
, ioc
.bufsiz
, ssiz
);
735 } else if (ddi_copyout(snapshot
,
736 ioc
.buf
, ioc
.bufsiz
, mode
) != 0) {
737 IBTF_DPRINTF_L2("ibnex", "%s "
738 "ddi_copyout 12 failed", msg
);
743 kmem_free(snapshot
, snapshot_sz
);
746 case IBNEX_UPDATE_IOC_CONF
:
747 msg
= "\tdevctl:IBNEX_UPDATE_IOC_CONF: ";
750 * If IB fabric APID, call ibnex_update_all
751 * If IOC APID, get the apid dip and call
754 if (ioc
.misc_arg
== IBNEX_BASE_APID
) {
756 * If reprobe is in progress or another reprobe
757 * is already waiting, wait.
759 if (ibnex
.ibnex_reprobe_state
!= 0) {
760 if (ibnex
.ibnex_reprobe_state
==
761 IBNEX_REPROBE_ALL_PROGRESS
)
762 ibnex
.ibnex_reprobe_state
=
763 IBNEX_REPROBE_ALL_WAIT
;
764 while (ibnex
.ibnex_reprobe_state
) {
765 cv_wait(&ibnex
.ibnex_reprobe_cv
,
770 * Pending reprobe all completed, return
775 /* Check if reprobe for any IOC is pending */
778 ioc_reprobe_pending
= 0;
779 for (scanp
= ibnex
.ibnex_ioc_node_head
;
781 scanp
= scanp
->node_next
) {
782 if (scanp
->node_reprobe_state
784 ioc_reprobe_pending
=
789 if (ioc_reprobe_pending
== 0) {
790 ibnex
.ibnex_reprobe_state
&=
791 ~IBNEX_REPROBE_IOC_WAIT
;
795 ibnex
.ibnex_reprobe_state
=
796 IBNEX_REPROBE_IOC_WAIT
;
797 cv_wait(&ibnex
.ibnex_reprobe_cv
,
802 * Set the REPROBE_ALL_PROGRESS state &
805 ibnex
.ibnex_reprobe_state
=
806 IBNEX_REPROBE_ALL_PROGRESS
;
807 mutex_exit(&ibnex
.ibnex_mutex
);
808 ibnex_reprobe_ioc_all();
809 mutex_enter(&ibnex
.ibnex_mutex
);
810 } else if (ioc
.misc_arg
== IBNEX_DYN_APID
) {
811 rv
= ibnex_get_dip_from_apid(apid_n
, &apid_dip
,
813 ASSERT(rv
== IBNEX_DYN_APID
);
815 /* Device unconfigured: return */
816 if (apid_dip
== NULL
)
819 ndi_rele_devi(apid_dip
);
820 /* Reset return value back to 0 */
822 if (ibnex
.ibnex_reprobe_state
!= 0 ||
823 nodep
->node_reprobe_state
!= 0) {
824 while (ibnex
.ibnex_reprobe_state
!= 0 &&
825 nodep
->node_reprobe_state
!= 0) {
826 cv_wait(&ibnex
.ibnex_reprobe_cv
,
829 /* Pending reprobe completed, return */
833 /* Set node_reprobe_state and start reprobe */
834 nodep
->node_reprobe_state
=
835 IBNEX_NODE_REPROBE_NOTIFY_ON_UPDATE
;
836 mutex_exit(&ibnex
.ibnex_mutex
);
837 ibnex_reprobe_ioc_dev((void *)apid_dip
);
838 mutex_enter(&ibnex
.ibnex_mutex
);
846 IBTF_DPRINTF_L2("ibnex",
847 "DEVCTL_AP_CONTROL: ioc:unknown cmd = %x", ioc
.cmd
);
853 case DEVCTL_AP_UNCONFIGURE
:
854 msg
= "DEVCTL_AP_UNCONFIGURE";
855 IBTF_DPRINTF_L4("ibnex", "%s", msg
);
857 /* Check for write permissions */
858 if (!(mode
& FWRITE
)) {
859 IBTF_DPRINTF_L2("ibnex", "%s: invalid mode %x",
865 if ((apid_n
= ibnex_get_apid(dcp
)) == NULL
) {
866 IBTF_DPRINTF_L2("ibnex",
867 "%s: ibnex_get_apid failed", msg
);
873 * If this apid is already seen by IBNEX, get the dip
874 * NOTE: ibnex_get_dip_from_apid() finds a valid dip
875 * and also does a ndi_devi_hold() on the child.
877 rv
= ibnex_get_dip_from_apid(apid_n
, &apid_dip
, &nodep
);
878 if ((rv
!= IBNEX_DYN_APID
) || (apid_dip
== NULL
)) {
879 IBTF_DPRINTF_L2("ibnex", "%s: get_dip_from_apid "
880 "failed with 0x%x", msg
, rv
);
884 IBTF_DPRINTF_L4("ibnex", "%s: DIP = %p", msg
, apid_dip
);
886 /* Check if it is a valid node type? */
887 if (!IBNEX_VALID_NODE_TYPE(nodep
)) {
888 IBTF_DPRINTF_L2("ibnex", "%s: invalid IB node", msg
);
890 ndi_rele_devi(apid_dip
);
895 * continue unconfigure operation, only if device node
896 * is already configured. Return EBUSY if another
897 * configure/unconfigure operation is in progress.
899 if (nodep
->node_state
== IBNEX_CFGADM_CONFIGURING
||
900 nodep
->node_state
== IBNEX_CFGADM_UNCONFIGURING
) {
902 ndi_rele_devi(apid_dip
);
906 /* do this before to avoid races */
907 nodep
->node_dip
= NULL
;
908 nodep
->node_state
= IBNEX_CFGADM_UNCONFIGURING
;
911 * Call devfs_clean first
912 * NOTE: The code so far is protected by holding ibnex_mutex
913 * and by doing a ndi_devi_hold() on the child.
915 pdip
= ddi_get_parent(apid_dip
);
916 if (i_ddi_node_state(apid_dip
) >= DS_INITIALIZED
) {
917 devnm
= kmem_alloc(MAXNAMELEN
+ 1, KM_SLEEP
);
918 (void) ddi_deviname(apid_dip
, devnm
);
919 mutex_exit(&ibnex
.ibnex_mutex
);
920 (void) devfs_clean(pdip
, devnm
+ 1, DV_CLEAN_FORCE
);
921 mutex_enter(&ibnex
.ibnex_mutex
);
922 kmem_free(devnm
, MAXNAMELEN
+ 1);
925 mutex_exit(&ibnex
.ibnex_mutex
);
926 ndi_devi_enter(pdip
, &circ
);
927 ndi_rele_devi(apid_dip
);
928 mutex_enter(&ibnex
.ibnex_mutex
);
930 /* unconfigure the Port/VPPA/HCA_SVC node */
931 if (IBNEX_COMMSVC_NODE_TYPE(nodep
)) {
932 ret_val
= ibnex_commsvc_fininode(apid_dip
);
933 } else if (nodep
->node_type
== IBNEX_IOC_NODE
) {
934 /* unconfigure the IOC node */
935 ret_val
= ibnex_ioc_fininode(apid_dip
,
936 &nodep
->node_data
.ioc_node
);
937 } else if (nodep
->node_type
== IBNEX_PSEUDO_NODE
) {
938 /* unconfigure the pseudo node */
939 ret_val
= ibnex_pseudo_fininode(apid_dip
);
942 /* reset upon failure */
943 if (ret_val
!= IBNEX_SUCCESS
) {
944 nodep
->node_dip
= apid_dip
;
945 nodep
->node_state
= IBNEX_CFGADM_CONFIGURED
;
947 nodep
->node_state
= IBNEX_CFGADM_UNCONFIGURED
;
948 nodep
->node_ap_state
= IBNEX_NODE_AP_UNCONFIGURED
;
951 rv
= (ret_val
!= IBNEX_SUCCESS
) ? EIO
: 0;
952 ndi_devi_exit(pdip
, circ
);
953 IBTF_DPRINTF_L2("ibnex", "%s: DONE !! It %s", msg
,
954 rv
? "failed" : "succeeded");
957 case DEVCTL_AP_CONFIGURE
:
958 msg
= "DEVCTL_AP_CONFIGURE";
959 IBTF_DPRINTF_L4("ibnex", "%s", msg
);
960 mutex_exit(&ibnex
.ibnex_mutex
);
961 ndi_devi_enter(ibnex
.ibnex_dip
, &circ
);
962 mutex_enter(&ibnex
.ibnex_mutex
);
964 /* Check for write permissions */
965 if (!(mode
& FWRITE
)) {
966 IBTF_DPRINTF_L2("ibnex", "%s: invalid mode %x",
969 ndi_devi_exit(ibnex
.ibnex_dip
, circ
);
973 if ((apid_n
= ibnex_get_apid(dcp
)) == NULL
) {
974 IBTF_DPRINTF_L2("ibnex",
975 "%s: ibnex_get_apid failed", msg
);
977 ndi_devi_exit(ibnex
.ibnex_dip
, circ
);
982 * Let's get the node if it already exists.
983 * NOTE: ibnex_get_dip_from_apid() finds a valid dip
984 * and also does a ndi_devi_hold() on the child.
987 ret_val
= ibnex_get_dip_from_apid(apid_n
, &apid_dip
, &nodep
);
989 * We need the node_data but not the dip. If we get a dip for
990 * this apid, it means it's already configured. We need to
993 if (apid_dip
!= NULL
) {
994 ndi_rele_devi(apid_dip
);
995 ndi_devi_exit(ibnex
.ibnex_dip
, circ
);
1001 * A node exits for this apid but not a dip. So we must have
1002 * unconfigured it earlier. Set the node_ap_state to configuring
1003 * to allow configure operation.
1005 if (nodep
!= NULL
) {
1006 nodep
->node_ap_state
= IBNEX_NODE_AP_CONFIGURING
;
1011 * Five types of APIDs are supported:
1012 * o HCA_GUID,0,service-name (HCA-SVC device)
1013 * o IOC_GUID (IOC device)
1014 * o PORT_GUID,0,service-name (Port device)
1015 * o pseudo_name,unit-address, (Pseudo device)
1016 * o PORT_GUID,P_Key,service-name (VPPA device)
1017 * If the apid doesn't have "," then treat it as an IOC
1018 * If the apid has one "," then it is Pseudo device
1019 * If the apid has 2 ","s then it is one of the
1020 * Port,VPPA,HCA_SVC devices
1022 if (strrchr(apid_n
, ',') == NULL
) {
1023 ret_val
= ibnex_handle_ioc_configure(apid_n
);
1025 char *first
= strchr(apid_n
, ',');
1028 second
= first
? strchr(first
+ 1, ',') : NULL
;
1029 if (first
!= NULL
&& second
== NULL
) {
1030 ret_val
= ibnex_handle_pseudo_configure(apid_n
);
1031 } else if (first
!= NULL
&& second
!= NULL
) {
1032 ret_val
= ibnex_handle_commsvcnode_configure(
1037 if (ret_val
!= IBNEX_SUCCESS
) {
1038 rv
= (ret_val
== IBNEX_BUSY
) ? EBUSY
: EIO
;
1041 * Get the newly created node and set the state to
1042 * IBNEX_NODE_AP_CONFIGURED.
1043 * NOTE: ibnex_get_dip_from_apid() finds a valid dip
1044 * and also does a ndi_devi_hold() on the child.
1047 ret_val
= ibnex_get_dip_from_apid(apid_n
,
1049 if (nodep
!= NULL
) {
1050 nodep
->node_ap_state
= IBNEX_NODE_AP_CONFIGURED
;
1052 if (apid_dip
!= NULL
) {
1053 ndi_rele_devi(apid_dip
);
1056 IBTF_DPRINTF_L2("ibnex", "%s: DONE !! It %s", msg
,
1057 rv
? "failed" : "succeeded");
1058 ndi_devi_exit(ibnex
.ibnex_dip
, circ
);
1065 mutex_exit(&ibnex
.ibnex_mutex
);
1067 if ((apid_alloced
== B_TRUE
) && (apid_n
!= NULL
)) {
1068 kmem_free(apid_n
, apid_len
);
1072 ndi_dc_freehdl(dcp
);
1079 * ibnex_get_num_devices()
1080 * Figure out how many IOC, VPPA, Pseudo, HCA_SVC and Port devices exist
1083 ibnex_get_num_devices(void)
1085 int j
, k
, l
, hca_count
;
1087 ibdm_hca_list_t
*hca_list
, *hcap
;
1088 ibdm_port_attr_t
*pattr
;
1089 ibnex_node_data_t
*nodep
;
1091 ASSERT(mutex_owned(&ibnex
.ibnex_mutex
));
1093 /* Get a count of HCAs, first. */
1094 mutex_exit(&ibnex
.ibnex_mutex
);
1095 ibdm_ibnex_get_hca_list(&hca_list
, &hca_count
);
1096 mutex_enter(&ibnex
.ibnex_mutex
);
1097 for (hcap
= hca_list
; hca_list
!= NULL
; hca_list
= hca_list
->hl_next
) {
1098 for (j
= 0; j
< ibnex
.ibnex_nhcasvc_comm_svcs
; j
++)
1100 for (j
= 0; j
< hca_list
->hl_nports
; j
++) {
1101 for (k
= 0; k
< ibnex
.ibnex_num_comm_svcs
; k
++)
1104 pattr
= &hca_list
->hl_port_attr
[j
];
1105 for (k
= 0; k
< pattr
->pa_npkeys
; k
++) {
1106 if (IBNEX_INVALID_PKEY(pattr
->pa_pkey_tbl
[k
].
1110 for (l
= 0; l
< ibnex
.ibnex_nvppa_comm_svcs
;
1113 } /* end of pa_npkeys */
1114 } /* end of hl_nports */
1115 } /* end of hca_list != NULL */
1117 ibdm_ibnex_free_hca_list(hcap
);
1120 * Now figure out how many IOC nodes are present.
1121 * Add count of configured "diconnected" IOCs
1123 mutex_exit(&ibnex
.ibnex_mutex
);
1124 num_nodes
+= ibdm_ibnex_get_ioc_count();
1125 mutex_enter(&ibnex
.ibnex_mutex
);
1126 num_nodes
+= ibnex
.ibnex_num_disconnect_iocs
;
1128 /* Last: figure out how many Pseudo nodes are present. */
1129 for (nodep
= ibnex
.ibnex_pseudo_node_head
; nodep
;
1130 nodep
= nodep
->node_next
) {
1131 if (nodep
->node_data
.pseudo_node
.pseudo_merge_node
== 1)
1141 * ibnex_get_snapshot()
1142 * Get a snapshot of all Port/IOC/VPPA/HCA_SVC/Pseudo nodes
1143 * Snapshot includes IBNEX_NODE_INFO_NVL, IBNEX_NODE_TYPE_NVL,
1144 * IBNEX_NODE_RSTATE_NVL, IBNEX_NODE_OSTATE_NVL and
1145 * IBNEX_NODE_COND_NVL
1148 ibnex_get_snapshot(char **buf
, size_t *sz
, int allow_probe
)
1150 int i
, j
, k
, l
, hca_count
;
1154 ibdm_ioc_info_t
*ioc_listp
;
1155 ibdm_ioc_info_t
*iocp
;
1156 ibdm_hca_list_t
*hca_list
, *hcap
;
1157 ibdm_port_attr_t
*port_attr
;
1158 ibnex_node_data_t
*nodep
;
1160 ASSERT(mutex_owned(&ibnex
.ibnex_mutex
));
1165 if (!ibnex
.ibnex_pseudo_inited
) {
1166 mutex_exit(&ibnex
.ibnex_mutex
);
1167 ibnex_pseudo_initnodes();
1168 mutex_enter(&ibnex
.ibnex_mutex
);
1169 ibnex
.ibnex_pseudo_inited
= 1;
1172 /* First, Port/VPPA/HCA_SVC nodes */
1173 mutex_exit(&ibnex
.ibnex_mutex
);
1174 ibdm_ibnex_get_hca_list(&hca_list
, &hca_count
);
1175 mutex_enter(&ibnex
.ibnex_mutex
);
1177 (void) nvlist_alloc(&nvl
, 0, KM_SLEEP
);
1179 /* Go thru all the ports of all the HCAs and all the port-svc indices */
1180 for (hcap
= hca_list
, i
= 0; i
< hca_count
;
1181 hca_list
= hca_list
->hl_next
, i
++) {
1183 IBTF_DPRINTF_L4("ibnex", "ibnex_get_snapshot: "
1184 "fill in COMM service HCA_SVC nodes");
1185 port_attr
= hca_list
->hl_hca_port_attr
;
1186 for (j
= 0; j
< ibnex
.ibnex_nhcasvc_comm_svcs
; j
++) {
1187 if (ibnex_get_commsvcnode_snapshot(&nvl
,
1188 port_attr
->pa_hca_guid
,
1189 port_attr
->pa_hca_guid
, j
, (ib_pkey_t
)0,
1190 IBNEX_HCASVC_COMMSVC_NODE
) != 0) {
1191 IBTF_DPRINTF_L2("ibnex",
1192 "ibnex_get_snapshot: failed to fill"
1193 " HCA_SVC device (%x %x)", i
, j
);
1194 ibdm_ibnex_free_hca_list(hcap
);
1201 for (j
= 0; j
< hca_list
->hl_nports
; j
++) {
1202 port_attr
= &hca_list
->hl_port_attr
[j
];
1204 IBTF_DPRINTF_L4("ibnex", "ibnex_get_snapshot: "
1205 "fill in COMM service Port nodes");
1206 for (k
= 0; k
< ibnex
.ibnex_num_comm_svcs
; k
++) {
1208 if (ibnex_get_commsvcnode_snapshot(&nvl
,
1209 port_attr
->pa_hca_guid
,
1210 port_attr
->pa_port_guid
, k
, (ib_pkey_t
)0,
1211 IBNEX_PORT_COMMSVC_NODE
) != 0) {
1212 IBTF_DPRINTF_L2("ibnex",
1213 "ibnex_get_snapshot: failed to fill"
1214 " Port device (%x %x %x)", i
, j
, k
);
1215 ibdm_ibnex_free_hca_list(hcap
);
1220 } /* end of num_comm_svcs for loop */
1222 IBTF_DPRINTF_L4("ibnex", "ibnex_get_snapshot: "
1223 "fill in VPPA service port nodes");
1224 for (l
= 0; l
< port_attr
->pa_npkeys
; l
++) {
1225 pkey
= port_attr
->pa_pkey_tbl
[l
].pt_pkey
;
1226 if (IBNEX_INVALID_PKEY(pkey
))
1229 for (k
= 0; k
< ibnex
.ibnex_nvppa_comm_svcs
;
1232 if (ibnex_get_commsvcnode_snapshot(&nvl
,
1233 port_attr
->pa_hca_guid
,
1234 port_attr
->pa_port_guid
, k
, pkey
,
1235 IBNEX_VPPA_COMMSVC_NODE
) != 0) {
1236 IBTF_DPRINTF_L2("ibnex",
1237 "ibnex_get_snapshot: "
1238 "failed to fill VPPA "
1239 "device (%x %x %x % x)",
1241 ibdm_ibnex_free_hca_list(hcap
);
1245 } /* end of ibnex_nvppa_comm_svcs loop */
1247 } /* end of pa_npkeys for loop */
1249 } /* end of hl_nports for loop */
1251 } /* end of hca_count for loop */
1254 ibdm_ibnex_free_hca_list(hcap
);
1256 /* save it to free up the entire list */
1257 mutex_exit(&ibnex
.ibnex_mutex
);
1258 iocp
= ioc_listp
= ibdm_ibnex_get_ioc_list(allow_probe
);
1259 mutex_enter(&ibnex
.ibnex_mutex
);
1260 for (; ioc_listp
!= NULL
; ioc_listp
= ioc_listp
->ioc_next
) {
1263 * Say we have N IOCs and all were deleted from ibnex
1266 if (ibnex
.ibnex_ioc_node_head
== NULL
) {
1267 if (ibnex_fill_ioc_tmp(&nvl
, ioc_listp
) != 0) {
1268 IBTF_DPRINTF_L2("ibnex", "ibnex_get_snapshot: "
1269 "filling NVL data failed");
1270 ibdm_ibnex_free_ioc_list(iocp
);
1279 /* Check first, if we have already seen this IOC? */
1280 for (nodep
= ibnex
.ibnex_ioc_node_head
; nodep
!= NULL
;
1281 nodep
= nodep
->node_next
) {
1282 if (ioc_listp
->ioc_profile
.ioc_guid
==
1283 nodep
->node_data
.ioc_node
.ioc_guid
) {
1290 /* have we seen this IOC before? */
1291 if (found
== B_TRUE
) {
1292 if (ibnex_fill_nodeinfo(&nvl
, nodep
,
1293 &ioc_listp
->ioc_profile
) != 0) {
1294 IBTF_DPRINTF_L2("ibnex",
1295 "ibnex_get_snapshot: filling NVL "
1296 "for IOC node %p failed", nodep
);
1297 ibdm_ibnex_free_ioc_list(iocp
);
1304 if (ibnex_fill_ioc_tmp(&nvl
, ioc_listp
) != 0) {
1305 IBTF_DPRINTF_L2("ibnex",
1306 "ibnex_get_snapshot: filling NVL "
1307 "tmp for IOC node %p failed",
1309 ibdm_ibnex_free_ioc_list(iocp
);
1315 } /* end of else ibnex_ioc_node_head == NULL */
1316 } /* end of external for */
1318 ibdm_ibnex_free_ioc_list(iocp
);
1321 * Add list of "disconnected" IOCs, not unconfigured.
1323 for (nodep
= ibnex
.ibnex_ioc_node_head
; nodep
!= NULL
;
1324 nodep
= nodep
->node_next
) {
1325 if (nodep
->node_data
.ioc_node
.ioc_ngids
== 0 &&
1326 nodep
->node_data
.ioc_node
.ioc_profile
!= NULL
&&
1327 nodep
->node_state
!= IBNEX_CFGADM_UNCONFIGURED
) {
1328 if (ibnex_fill_nodeinfo(&nvl
, nodep
,
1329 nodep
->node_data
.ioc_node
.ioc_profile
) != 0) {
1330 IBTF_DPRINTF_L2("ibnex",
1331 "ibnex_get_snapshot: filling NVL "
1332 "for disconnected IOC node %p "
1340 /* lastly; pseudo nodes */
1341 for (nodep
= ibnex
.ibnex_pseudo_node_head
; nodep
;
1342 nodep
= nodep
->node_next
) {
1343 if (nodep
->node_data
.pseudo_node
.pseudo_merge_node
== 1)
1345 if (ibnex_fill_nodeinfo(&nvl
, nodep
, NULL
) != 0) {
1346 IBTF_DPRINTF_L2("ibnex", "ibnex_get_snapshot: "
1347 "filling NVL data for Pseudo %p failed", nodep
);
1353 /* pack the data into the buffer */
1354 if (nvlist_pack(nvl
, buf
, sz
, NV_ENCODE_NATIVE
, KM_SLEEP
)) {
1355 IBTF_DPRINTF_L2("ibnex",
1356 "ibnex_get_snapshot: nvlist_pack failed");
1361 IBTF_DPRINTF_L4("ibnex", "ibnex_get_snapshot: size = 0x%x", *sz
);
1368 * ibnex_get_commsvcnode_snapshot()
1369 * A utility function to fill in a "dummy" Port/VPPA/HCA_SVC
1370 * information. Cfgadm plugin will display all Port/VPPA/
1371 * HCA_SVCs seen even if they are not all configured by IBNEX.
1373 * This function uses information from IBDM to fill up Port/VPPA/
1374 * HCA_SVC snapshot. If none exists then it makes up a "temporary"
1375 * node which will be displayed as "connected/unconfigured/unknown".
1377 * For HCA_SVC node port_guid will be same as hca_guid.
1380 ibnex_get_commsvcnode_snapshot(nvlist_t
**nvlpp
, ib_guid_t hca_guid
,
1381 ib_guid_t port_guid
, int svc_index
, ib_pkey_t p_key
,
1382 ibnex_node_type_t node_type
)
1385 dev_info_t
*dip
= NULL
;
1386 ibnex_node_data_t
*nodep
;
1387 ibnex_node_data_t dummy
;
1388 ibnex_node_data_t
*tmp
= &dummy
;
1390 IBTF_DPRINTF_L4("ibnex", "ibnex_get_commsvcnode_snapshot: "
1391 "HCA GUID: %llX Port GUID: %llX svc_index = %x pkey = %x "
1392 "node_type = %x", hca_guid
, port_guid
, svc_index
, p_key
, node_type
);
1394 /* check if this node was seen before? */
1395 rval
= ibnex_get_node_and_dip_from_guid(port_guid
, svc_index
, p_key
,
1397 if (rval
== IBNEX_SUCCESS
&& nodep
!= NULL
) {
1399 if (ibnex_fill_nodeinfo(nvlpp
, nodep
, NULL
) != 0) {
1400 IBTF_DPRINTF_L2("ibnex",
1401 "ibnex_get_commsvcnode_snapshot: failed to fill "
1402 "Port/VPPA device node %p NVL data", nodep
);
1407 /* Fake up a Port/VPPA/HCA_SVC node */
1408 IBTF_DPRINTF_L4("ibnex", "ibnex_get_commsvcnode_snapshot: "
1409 "VPPA/Port/HCA_SVC not seen by ibnex");
1410 bzero(tmp
, sizeof (ibnex_node_data_t
));
1411 tmp
->node_type
= node_type
;
1412 tmp
->node_data
.port_node
.port_guid
= port_guid
;
1413 tmp
->node_data
.port_node
.port_hcaguid
= hca_guid
;
1414 tmp
->node_data
.port_node
.port_commsvc_idx
= svc_index
;
1415 /* Fill P_Key only for VPPA nodes */
1416 if (node_type
== IBNEX_VPPA_COMMSVC_NODE
) {
1417 tmp
->node_data
.port_node
.port_pkey
= p_key
;
1420 if (ibnex_fill_nodeinfo(nvlpp
, tmp
, NULL
) != 0) {
1421 IBTF_DPRINTF_L2("ibnex",
1422 "ibnex_get_commsvcnode_snapshot: failed to fill "
1423 "tmp Port/VPPA device node %p NVL data", tmp
);
1433 * ibnex_fill_ioc_tmp()
1434 * A utility function to fill in a "dummy" IOC information.
1435 * Cfgadm plugin will display all IOCs seen by IBDM even if they
1436 * are configured or not by IBNEX.
1438 * This function uses information from IBDM to fill up a
1439 * dummy IOC information. It will be displayed as
1440 * "connected/unconfigured/unknown".
1443 ibnex_fill_ioc_tmp(nvlist_t
**nvlpp
, ibdm_ioc_info_t
*ioc_listp
)
1445 ibnex_node_data_t dummy
;
1446 ibnex_node_data_t
*nodep
= &dummy
;
1448 IBTF_DPRINTF_L4("ibnex", "\tibnex_fill_ioc_tmp:");
1450 bzero(nodep
, sizeof (ibnex_node_data_t
));
1451 nodep
->node_type
= IBNEX_IOC_NODE
;
1452 nodep
->node_data
.ioc_node
.ioc_guid
= ioc_listp
->ioc_profile
.ioc_guid
;
1453 nodep
->node_data
.ioc_node
.iou_guid
= ioc_listp
->ioc_iou_guid
;
1454 (void) strncpy(nodep
->node_data
.ioc_node
.ioc_id_string
,
1455 (char *)ioc_listp
->ioc_profile
.ioc_id_string
,
1456 IB_DM_IOC_ID_STRING_LEN
);
1457 IBTF_DPRINTF_L4("ibnex", "\tibnex_fill_ioc_tmp: %s",
1458 nodep
->node_data
.ioc_node
.ioc_id_string
);
1460 if (ibnex_fill_nodeinfo(nvlpp
, nodep
, &ioc_listp
->ioc_profile
) != 0) {
1461 IBTF_DPRINTF_L2("ibnex", "\tibnex_fill_ioc_tmp: filling NVL "
1462 "data for IOC node %p failed", nodep
);
1471 * ibnex_fill_nodeinfo()
1472 * A utility function to fill in to the NVLIST information about
1473 * a Port/IOC/VPPA/HCA_SVC/Pseudo driver that is then passed over
1474 * to cfgadm utility for display. This information is used only
1475 * for cfgadm -ll displays.
1477 * Information that is filled in here is:-
1481 * AP_ID_OCCUPANT_STATE
1482 * AP_ID_RECEPTACLE_STATE
1486 ibnex_fill_nodeinfo(nvlist_t
**nvlpp
, ibnex_node_data_t
*node_datap
, void *tmp
)
1490 char apid
[IBTL_IBNEX_APID_LEN
];
1491 char info_data
[MAXNAMELEN
];
1492 ib_dm_ioc_ctrl_profile_t
*profilep
;
1493 devctl_ap_state_t state
;
1495 IBTF_DPRINTF_L5("ibnex", "ibnex_fill_nodeinfo: 0x%x addr is %p",
1496 node_datap
->node_type
, node_datap
);
1498 if (node_datap
->node_type
== IBNEX_PORT_COMMSVC_NODE
) {
1499 svcname
= ibnex
.ibnex_comm_svc_names
[node_datap
->node_data
.
1500 port_node
.port_commsvc_idx
];
1501 (void) snprintf(apid
, IBTL_IBNEX_APID_LEN
, "%llX,0,%s",
1502 (longlong_t
)node_datap
->node_data
.port_node
.port_guid
,
1506 if (nvlist_add_string(*nvlpp
, IBNEX_NODE_APID_NVL
, apid
)) {
1507 IBTF_DPRINTF_L2("ibnex", "ibnex_fill_nodeinfo: "
1508 "failed to fill %s", IBNEX_NODE_APID_NVL
);
1513 if (nvlist_add_string(*nvlpp
, IBNEX_NODE_INFO_NVL
, svcname
)) {
1514 IBTF_DPRINTF_L2("ibnex", "ibnex_fill_nodeinfo: "
1515 "failed to fill Port %s", IBNEX_NODE_INFO_NVL
);
1519 IBTF_DPRINTF_L5("ibnex", "ibnex_fill_nodeinfo: "
1520 "Port %s = %s, %s = %s",
1521 IBNEX_NODE_INFO_NVL
, apid
, IBNEX_NODE_APID_NVL
, svcname
);
1523 } else if (node_datap
->node_type
== IBNEX_VPPA_COMMSVC_NODE
) {
1524 svcname
= ibnex
.ibnex_vppa_comm_svc_names
[node_datap
->node_data
.
1525 port_node
.port_commsvc_idx
];
1526 (void) snprintf(apid
, IBTL_IBNEX_APID_LEN
, "%llX,%x,%s",
1527 (longlong_t
)node_datap
->node_data
.port_node
.port_guid
,
1528 node_datap
->node_data
.port_node
.port_pkey
, svcname
);
1531 if (nvlist_add_string(*nvlpp
, IBNEX_NODE_APID_NVL
, apid
)) {
1532 IBTF_DPRINTF_L2("ibnex", "ibnex_fill_nodeinfo: "
1533 "failed to fill %s", IBNEX_NODE_APID_NVL
);
1538 if (nvlist_add_string(*nvlpp
, IBNEX_NODE_INFO_NVL
, svcname
)) {
1539 IBTF_DPRINTF_L2("ibnex", "ibnex_fill_nodeinfo: "
1540 "failed to fill VPPA %s", IBNEX_NODE_INFO_NVL
);
1544 IBTF_DPRINTF_L5("ibnex", "ibnex_fill_nodeinfo: "
1545 "VPPA %s = %s, %s = %s",
1546 IBNEX_NODE_APID_NVL
, apid
, IBNEX_NODE_INFO_NVL
, svcname
);
1548 } else if (node_datap
->node_type
== IBNEX_HCASVC_COMMSVC_NODE
) {
1549 svcname
= ibnex
.ibnex_hcasvc_comm_svc_names
[node_datap
->
1550 node_data
.port_node
.port_commsvc_idx
];
1551 (void) snprintf(apid
, IBTL_IBNEX_APID_LEN
, "%llX,0,%s",
1552 (longlong_t
)node_datap
->node_data
.port_node
.port_guid
,
1556 if (nvlist_add_string(*nvlpp
, IBNEX_NODE_APID_NVL
, apid
)) {
1557 IBTF_DPRINTF_L2("ibnex", "ibnex_fill_nodeinfo: "
1558 "failed to fill %s", IBNEX_NODE_APID_NVL
);
1563 if (nvlist_add_string(*nvlpp
, IBNEX_NODE_INFO_NVL
, svcname
)) {
1564 IBTF_DPRINTF_L2("ibnex", "ibnex_fill_nodeinfo: "
1565 "failed to fill Port %s", IBNEX_NODE_INFO_NVL
);
1569 IBTF_DPRINTF_L5("ibnex", "ibnex_fill_nodeinfo: "
1570 "Port %s = %s, %s = %s",
1571 IBNEX_NODE_INFO_NVL
, apid
, IBNEX_NODE_APID_NVL
, svcname
);
1573 } else if (node_datap
->node_type
== IBNEX_IOC_NODE
) {
1576 * get the IOC profile pointer from the args
1578 profilep
= (ib_dm_ioc_ctrl_profile_t
*)tmp
;
1579 IBNEX_FORM_GUID(apid
, IBTL_IBNEX_APID_LEN
, profilep
->ioc_guid
);
1582 if (nvlist_add_string(*nvlpp
, IBNEX_NODE_APID_NVL
, apid
)) {
1583 IBTF_DPRINTF_L2("ibnex", "ibnex_fill_nodeinfo: "
1584 "failed to fill in %s", IBNEX_NODE_APID_NVL
);
1587 IBTF_DPRINTF_L5("ibnex", "ibnex_fill_nodeinfo: %s %s",
1588 IBNEX_NODE_APID_NVL
, apid
);
1591 * IOC "info" filed will display the following fields
1592 * VendorID, IOCDeviceID, DeviceVersion, SubsystemVendorID,
1593 * SubsystemID, Class, Subclass, Protocol, ProtocolVersion
1595 (void) snprintf(info_data
, MAXNAMELEN
,
1596 "VID: 0x%x DEVID: 0x%x VER: 0x%x SUBSYS_VID: 0x%x "
1597 "SUBSYS_ID: 0x%x CLASS: 0x%x SUBCLASS: 0x%x PROTO: 0x%x "
1598 "PROTOVER: 0x%x ID_STRING: %s", profilep
->ioc_vendorid
,
1599 profilep
->ioc_deviceid
, profilep
->ioc_device_ver
,
1600 profilep
->ioc_subsys_vendorid
, profilep
->ioc_subsys_id
,
1601 profilep
->ioc_io_class
, profilep
->ioc_io_subclass
,
1602 profilep
->ioc_protocol
, profilep
->ioc_protocol_ver
,
1603 (char *)profilep
->ioc_id_string
);
1604 IBTF_DPRINTF_L5("ibnex", "ibnex_fill_nodeinfo: %s", info_data
);
1607 if (nvlist_add_string(*nvlpp
, IBNEX_NODE_INFO_NVL
, info_data
)) {
1608 IBTF_DPRINTF_L2("ibnex", "ibnex_fill_nodeinfo: "
1609 "failed to fill IOC %s", IBNEX_NODE_INFO_NVL
);
1613 } else if (node_datap
->node_type
== IBNEX_PSEUDO_NODE
) {
1614 (void) snprintf(apid
, IBTL_IBNEX_APID_LEN
, "%s",
1615 node_datap
->node_data
.pseudo_node
.pseudo_node_addr
);
1618 if (nvlist_add_string(*nvlpp
, IBNEX_NODE_APID_NVL
, apid
)) {
1619 IBTF_DPRINTF_L2("ibnex", "ibnex_fill_nodeinfo: "
1620 "failed to fill in %s", IBNEX_NODE_APID_NVL
);
1625 node_name
= node_datap
->node_data
.pseudo_node
.pseudo_devi_name
;
1626 (void) snprintf(info_data
, MAXNAMELEN
,
1627 "Pseudo Driver = \"%s\", Unit-address = \"%s\"",
1628 node_name
, apid
+ strlen(node_name
) + 1);
1629 if (nvlist_add_string(*nvlpp
, IBNEX_NODE_INFO_NVL
, info_data
)) {
1630 IBTF_DPRINTF_L2("ibnex", "ibnex_fill_nodeinfo: "
1631 "failed to fill Pseudo %s", IBNEX_NODE_INFO_NVL
);
1635 IBTF_DPRINTF_L5("ibnex", "ibnex_fill_nodeinfo: Pseudo %s = %s,"
1636 "%s = %s", IBNEX_NODE_APID_NVL
, apid
, IBNEX_NODE_INFO_NVL
,
1641 if (nvlist_add_int32(*nvlpp
, IBNEX_NODE_TYPE_NVL
,
1642 node_datap
->node_type
)) {
1643 IBTF_DPRINTF_L2("ibnex", "ibnex_fill_nodeinfo: "
1644 "failed to fill in %s", IBNEX_NODE_TYPE_NVL
);
1647 IBTF_DPRINTF_L5("ibnex", "ibnex_fill_nodeinfo: %s %d",
1648 IBNEX_NODE_TYPE_NVL
, node_datap
->node_type
);
1650 /* figure out "ostate", "rstate" and "condition" */
1651 ibnex_figure_ap_devstate(node_datap
, &state
);
1653 if (nvlist_add_int32(*nvlpp
, IBNEX_NODE_RSTATE_NVL
, state
.ap_rstate
)) {
1654 IBTF_DPRINTF_L2("ibnex", "ibnex_fill_nodeinfo: "
1655 "failed to fill in %s", IBNEX_NODE_RSTATE_NVL
);
1658 IBTF_DPRINTF_L5("ibnex", "ibnex_fill_nodeinfo: %s %d",
1659 IBNEX_NODE_RSTATE_NVL
, state
.ap_rstate
);
1661 if (nvlist_add_int32(*nvlpp
, IBNEX_NODE_OSTATE_NVL
, state
.ap_ostate
)) {
1662 IBTF_DPRINTF_L2("ibnex", "ibnex_fill_nodeinfo: "
1663 "failed to fill in %s", IBNEX_NODE_OSTATE_NVL
);
1666 IBTF_DPRINTF_L5("ibnex", "ibnex_fill_nodeinfo: %s %d",
1667 IBNEX_NODE_OSTATE_NVL
, state
.ap_ostate
);
1669 if (nvlist_add_int32(*nvlpp
, IBNEX_NODE_COND_NVL
, state
.ap_condition
)) {
1670 IBTF_DPRINTF_L2("ibnex", "ibnex_fill_nodeinfo: "
1671 "failed to fill in %s", IBNEX_NODE_COND_NVL
);
1674 IBTF_DPRINTF_L5("ibnex", "ibnex_fill_nodeinfo: %s %d",
1675 IBNEX_NODE_COND_NVL
, state
.ap_condition
);
1682 * ibnex_figure_ap_devstate()
1683 * Fills the "devctl_ap_state_t" for a given ap_id
1685 * currently it assumes that we don't support "error_code" and
1686 * "last_change" value.
1689 ibnex_figure_ap_devstate(ibnex_node_data_t
*nodep
, devctl_ap_state_t
*ap_state
)
1691 IBTF_DPRINTF_L5("ibnex", "ibnex_figure_ap_devstate: nodep = %p", nodep
);
1693 ap_state
->ap_rstate
= AP_RSTATE_CONNECTED
;
1694 if (nodep
== NULL
) { /* for nodes not seen by IBNEX yet */
1695 ap_state
->ap_ostate
= AP_OSTATE_UNCONFIGURED
;
1696 ap_state
->ap_condition
= AP_COND_UNKNOWN
;
1699 * IBNEX_NODE_AP_UNCONFIGURED & IBNEX_NODE_AP_CONFIGURING.
1701 if (nodep
->node_ap_state
>= IBNEX_NODE_AP_UNCONFIGURED
) {
1702 ap_state
->ap_ostate
= AP_OSTATE_UNCONFIGURED
;
1703 ap_state
->ap_condition
= AP_COND_UNKNOWN
;
1705 ap_state
->ap_ostate
= AP_OSTATE_CONFIGURED
;
1706 ap_state
->ap_condition
= AP_COND_OK
;
1709 ap_state
->ap_last_change
= (time_t)-1;
1710 ap_state
->ap_error_code
= 0;
1711 ap_state
->ap_in_transition
= 0;
1716 * ibnex_figure_ib_apid_devstate()
1717 * Fills the "devctl_ap_state_t" for a IB static ap_id
1720 ibnex_figure_ib_apid_devstate(devctl_ap_state_t
*ap_state
)
1722 ap_state
->ap_rstate
= AP_RSTATE_CONNECTED
;
1723 ap_state
->ap_condition
= AP_COND_OK
;
1724 ap_state
->ap_ostate
= (ibt_get_hca_list(NULL
) == 0) ?
1725 AP_OSTATE_UNCONFIGURED
: AP_OSTATE_CONFIGURED
;
1726 ap_state
->ap_last_change
= (time_t)-1;
1727 ap_state
->ap_error_code
= 0;
1728 ap_state
->ap_in_transition
= 0;
1734 * Reads in the ap_id passed as an nvlist_string from user-land
1737 ibnex_get_apid(struct devctl_iocdata
*dcp
)
1741 ASSERT(mutex_owned(&ibnex
.ibnex_mutex
));
1743 /* Get which ap_id to operate on. */
1744 if (nvlist_lookup_string(ndi_dc_get_ap_data(dcp
), "apid",
1746 IBTF_DPRINTF_L4("ibnex", "ibnex_get_apid: ap_id lookup failed");
1750 IBTF_DPRINTF_L4("ibnex", "ibnex_get_apid: ap_id=%s", ap_id
);
1756 * ibnex_get_dip_from_apid()
1757 * Figures out the dip/node_data from an ap_id given that this ap_id
1758 * exists as a "name" in the "ibnex" list
1760 * NOTE: ap_id was on stack earlier and gets manipulated here. Since this
1761 * function may be called twice; it is better to make a local copy of
1762 * ap_id; if the ap_id were to be reused.
1765 ibnex_get_dip_from_apid(char *apid
, dev_info_t
**ret_dip
,
1766 ibnex_node_data_t
**ret_node_datap
)
1770 int len
= strlen((char *)apid
) + 1;
1774 char *second
= NULL
;
1777 ibnex_node_data_t
*nodep
= NULL
;
1779 ap_id
= i_ddi_strdup(apid
, KM_SLEEP
);
1780 IBTF_DPRINTF_L4("ibnex", "\tibnex_get_dip_from_apid: %s", ap_id
);
1781 ASSERT(mutex_owned(&ibnex
.ibnex_mutex
));
1783 if ((dyn
= GET_DYN(ap_id
)) != NULL
) {
1784 rv
= IBNEX_DYN_APID
;
1785 } else { /* either static, hca or unknown */
1787 if (strstr(ap_id
, "hca") != 0) {
1788 rv
= IBNEX_HCA_APID
;
1789 } else if (strstr(ap_id
, IBNEX_FABRIC
) != 0) {
1790 rv
= IBNEX_BASE_APID
;
1792 rv
= IBNEX_UNKNOWN_APID
;
1794 kmem_free(ap_id
, len
);
1798 dyn
+= strlen(DYN_SEP
);
1801 kmem_free(ap_id
, len
);
1802 return (IBNEX_UNKNOWN_APID
);
1806 first
= strchr(dyn
, ',');
1808 second
= strchr(first
+1, ',');
1810 /* Implies Port or VPPA or HCA_SVC Driver ap_id */
1811 if (first
!= NULL
&& second
!= NULL
) {
1814 char *pkey_str
= strchr(ap_id
, ',');
1815 char *svc_str
= strrchr(pkey_str
, ',');
1817 /* dyn contains ,GUID,p_key,svc_name. Change it to GUID */
1818 str_len
= strlen(dyn
) - strlen(pkey_str
);
1819 dyn
[str_len
] = '\0';
1820 IBTF_DPRINTF_L4("ibnex", "\tibnex_get_dip_from_apid: "
1821 "Port / Node Guid %s", dyn
);
1823 /* figure out comm or vppa. figure out pkey */
1824 ++pkey_str
; /* pkey_str used to point to ",p_key,svc_name" */
1826 /* pkey_str contains p_key,svc_name. Change it to p_key */
1827 str_len
= strlen(pkey_str
) - strlen(svc_str
);
1828 pkey_str
[str_len
] = '\0';
1830 /* convert the string P_KEY to hex value */
1831 pkey_val
= ibnex_str2hex(pkey_str
, strlen(pkey_str
), &ret
);
1832 if (ret
!= IBNEX_SUCCESS
) {
1834 kmem_free(ap_id
, len
);
1835 return (IBNEX_UNKNOWN_APID
);
1838 ++svc_str
; /* svc_str used to point to ",svc_name" */
1839 IBTF_DPRINTF_L5("ibnex", "\tibnex_get_dip_from_apid: pkey %s"
1840 ":%x service name = %s", pkey_str
, pkey_val
, svc_str
);
1842 for (nodep
= ibnex
.ibnex_port_node_head
;
1843 nodep
!= NULL
; nodep
= nodep
->node_next
) {
1844 index
= nodep
->node_data
.port_node
.port_commsvc_idx
;
1845 IBNEX_FORM_GUID(name
, IBTL_IBNEX_APID_LEN
,
1846 nodep
->node_data
.port_node
.port_guid
);
1849 * Match P_Key, name string & service string:
1850 * For COMM / HCA_SVC services these should be true:
1851 * P_Key matches to 0, svc_str in comm_svc_names[]
1852 * and name matches the dynamic part of the ap_id
1853 * For VPPA services this should be true:
1854 * P_Key != 0 & matches, svc_str in
1855 * vppa_comm_svc_names[] and the name matches the
1856 * dynamic part of the ap_id.
1858 if ((pkey_val
== nodep
->node_data
.port_node
.
1859 port_pkey
) && (strstr(dyn
, name
) != NULL
)) {
1861 /* pkey != 0, COMM / HCA_SVC service */
1862 if (((pkey_val
== 0) && (
1864 ((ibnex
.ibnex_comm_svc_names
!= NULL
) &&
1865 (index
< ibnex
.ibnex_num_comm_svcs
) &&
1866 (strstr(svc_str
, ibnex
.
1867 ibnex_comm_svc_names
[index
]) != NULL
)) ||
1868 /* HCA_SVC service */
1869 ((ibnex
.ibnex_hcasvc_comm_svc_names
!=
1871 ibnex
.ibnex_nhcasvc_comm_svcs
) &&
1872 (strstr(svc_str
, ibnex
.
1873 ibnex_hcasvc_comm_svc_names
[index
])
1875 /* next the VPPA strings */
1876 ((pkey_val
!= 0) && (strstr(svc_str
, ibnex
.
1877 ibnex_vppa_comm_svc_names
[index
]) !=
1879 if (nodep
->node_dip
)
1880 ndi_hold_devi(nodep
->node_dip
);
1881 *ret_node_datap
= nodep
;
1882 *ret_dip
= nodep
->node_dip
;
1883 kmem_free(ap_id
, len
);
1890 } else if (first
!= NULL
&& second
== NULL
) {
1892 for (nodep
= ibnex
.ibnex_pseudo_node_head
; nodep
;
1893 nodep
= nodep
->node_next
) {
1894 if (nodep
->node_data
.pseudo_node
.pseudo_merge_node
1897 node_addr
= nodep
->node_data
.pseudo_node
.
1899 if (strncmp(dyn
, node_addr
, strlen(node_addr
)) == 0) {
1900 if (nodep
->node_dip
)
1901 ndi_hold_devi(nodep
->node_dip
);
1902 *ret_node_datap
= nodep
;
1903 *ret_dip
= nodep
->node_dip
;
1904 kmem_free(ap_id
, len
);
1909 } else if (first
== NULL
&& second
== NULL
) {
1910 /* This is an IOC ap_id */
1911 for (nodep
= ibnex
.ibnex_ioc_node_head
; nodep
!= NULL
;
1912 nodep
= nodep
->node_next
) {
1913 IBNEX_FORM_GUID(name
, IBTL_IBNEX_APID_LEN
,
1914 nodep
->node_data
.ioc_node
.ioc_guid
);
1915 if (strstr(dyn
, name
) != NULL
) {
1916 if (nodep
->node_dip
)
1917 ndi_hold_devi(nodep
->node_dip
);
1918 *ret_node_datap
= nodep
;
1919 *ret_dip
= nodep
->node_dip
;
1920 kmem_free(ap_id
, len
);
1926 /* Could not find a matching IB device */
1927 *ret_dip
= (nodep
) ? nodep
->node_dip
: NULL
;
1928 kmem_free(ap_id
, len
);
1934 * ibnex_handle_pseudo_configure()
1935 * Do DEVCTL_AP_CONNECT processing for Pseudo devices only.
1936 * The code also checks if the given ap_id is valid or not.
1939 ibnex_handle_pseudo_configure(char *apid
)
1942 char *last
= strrchr(apid
, ':') + 1;
1943 ibnex_rval_t retval
= IBNEX_FAILURE
;
1944 ibnex_node_data_t
*nodep
;
1946 IBTF_DPRINTF_L4("ibnex", "\tibnex_handle_pseudo_configure: "
1947 "last = %s\n\t\tapid = %s", last
, apid
);
1948 ASSERT(MUTEX_HELD(&ibnex
.ibnex_mutex
));
1950 /* Check if the APID is valid first */
1951 if (apid
== NULL
|| last
== NULL
) {
1952 IBTF_DPRINTF_L4("ibnex", "\tibnex_handle_pseudo_configure: "
1953 "invalid apid %s", apid
);
1957 /* find the matching entry and configure it */
1958 for (nodep
= ibnex
.ibnex_pseudo_node_head
; nodep
!= NULL
;
1959 nodep
= nodep
->node_next
) {
1960 if (nodep
->node_data
.pseudo_node
.pseudo_merge_node
== 1)
1962 node_addr
= nodep
->node_data
.pseudo_node
.pseudo_node_addr
;
1963 if (strncmp(node_addr
, last
, strlen(last
)))
1966 if (nodep
->node_dip
!= NULL
) {
1968 * Return BUSY if another configure
1969 * operation is in progress
1971 if (nodep
->node_state
==
1972 IBNEX_CFGADM_CONFIGURING
)
1973 return (IBNEX_BUSY
);
1975 return (IBNEX_SUCCESS
);
1979 * Return BUSY if another unconfigure operation is
1982 if (nodep
->node_state
== IBNEX_CFGADM_UNCONFIGURING
)
1983 return (IBNEX_BUSY
);
1985 ASSERT(nodep
->node_state
!= IBNEX_CFGADM_CONFIGURED
);
1986 nodep
->node_state
= IBNEX_CFGADM_CONFIGURING
;
1988 mutex_exit(&ibnex
.ibnex_mutex
);
1989 retval
= ibnex_pseudo_create_all_pi(nodep
);
1990 mutex_enter(&ibnex
.ibnex_mutex
);
1991 if (retval
== NDI_SUCCESS
) {
1992 nodep
->node_state
= IBNEX_CFGADM_CONFIGURED
;
1993 return (IBNEX_SUCCESS
);
1995 nodep
->node_state
= IBNEX_CFGADM_UNCONFIGURED
;
1996 return (IBNEX_FAILURE
);
2000 IBTF_DPRINTF_L4("ibnex", "\thandle_pseudo_configure: retval=%d",
2007 * ibnex_handle_ioc_configure()
2008 * Do DEVCTL_AP_CONNECT processing for IOCs only.
2009 * The code also checks if the given ap_id is valid or not.
2012 ibnex_handle_ioc_configure(char *apid
)
2015 char *guid_str
= strrchr(apid
, ':') + 1;
2017 ibnex_rval_t retval
= IBNEX_FAILURE
;
2018 ibdm_ioc_info_t
*ioc_info
;
2020 ASSERT(MUTEX_HELD(&ibnex
.ibnex_mutex
));
2021 IBTF_DPRINTF_L4("ibnex", "\tibnex_handle_ioc_configure: %s", apid
);
2023 /* Check if the APID is valid first */
2024 if (guid_str
== NULL
) {
2025 IBTF_DPRINTF_L4("ibnex",
2026 "\tibnex_handle_ioc_configure: invalid apid %s", apid
);
2031 * Call into IBDM to get IOC information
2033 ioc_guid
= ibnex_str2hex(guid_str
, strlen(guid_str
), &ret
);
2034 if (ret
!= IBNEX_SUCCESS
)
2037 IBTF_DPRINTF_L4("ibnex",
2038 "\tibnex_handle_ioc_configure: IOC GUID = %llX", ioc_guid
);
2039 mutex_exit(&ibnex
.ibnex_mutex
);
2040 ioc_info
= ibdm_ibnex_get_ioc_info(ioc_guid
);
2041 mutex_enter(&ibnex
.ibnex_mutex
);
2042 if (ioc_info
== NULL
) {
2043 IBTF_DPRINTF_L2("ibnex",
2044 "\tibnex_handle_ioc_configure: probe_iocguid failed");
2048 retval
= ibnex_ioc_initnode_all_pi(ioc_info
);
2049 ibdm_ibnex_free_ioc_list(ioc_info
);
2051 IBTF_DPRINTF_L4("ibnex", "\tibnex_handle_ioc_configure: "
2052 "done retval = %d", retval
);
2058 * ibnex_handle_commsvcnode_configure()
2059 * Do DEVCTL_AP_CONNECT processing
2060 * This is done for Port/VPPA/HCA_SVC drivers Only.
2061 * The code also checks if the given ap_id is valid or not.
2064 ibnex_handle_commsvcnode_configure(char *apid
)
2066 int ret
, str_len
, circ
;
2069 char *pkey_str
= strchr(apid
, ',');
2070 char *guid_str
= strrchr(apid
, ':') + 1;
2071 char *svc_str
= strrchr(pkey_str
, ',');
2072 boolean_t found
= B_FALSE
;
2073 boolean_t is_hcasvc_node
= B_FALSE
;
2074 ib_guid_t guid
; /* Port / Node GUID */
2076 ibnex_rval_t retval
= IBNEX_FAILURE
;
2077 ibdm_port_attr_t
*port_attr
;
2079 ibdm_hca_list_t
*hca_list
;
2081 ASSERT(MUTEX_HELD(&ibnex
.ibnex_mutex
));
2082 IBTF_DPRINTF_L4("ibnex", "\tibnex_handle_commsvcnode_configure: %s",
2085 /* Check if the APID is valid first */
2086 if (guid_str
== NULL
|| ((guid_str
!= NULL
) &&
2087 (pkey_str
== NULL
|| svc_str
== NULL
))) {
2088 IBTF_DPRINTF_L4("ibnex",
2089 "\tibnex_handle_commsvcnode_configure: "
2090 "invalid apid %s", apid
);
2094 /* guid_str contains GUID,p_key,svc_name. Change it to GUID */
2095 str_len
= strlen(guid_str
) - strlen(pkey_str
);
2096 guid_str
[str_len
] = '\0';
2098 /* convert the string GUID to hex value */
2099 guid
= ibnex_str2hex(guid_str
, strlen(guid_str
), &ret
);
2100 if (ret
== IBNEX_FAILURE
)
2102 IBTF_DPRINTF_L4("ibnex", "\tibnex_handle_commsvcnode_configure: "
2103 "Port / Node Guid %llX", guid
);
2105 /* figure out Port/HCA_SVC or VPPA. Also figure out the P_Key. */
2106 ++pkey_str
; /* pkey_str used to point to ",p_key,svc_name" */
2108 /* pkey_str contains p_key,svc_name. Change it to P_Key */
2109 str_len
= strlen(pkey_str
) - strlen(svc_str
);
2110 pkey_str
[str_len
] = '\0';
2111 IBTF_DPRINTF_L5("ibnex", "\tibnex_handle_commsvcnode_configure: "
2112 "p_key %s", pkey_str
);
2114 /* convert the string P_Key to a hexadecimal value */
2115 port_pkey
= ibnex_str2hex(pkey_str
, strlen(pkey_str
), &ret
);
2116 IBTF_DPRINTF_L5("ibnex", "\tibnex_handle_commsvcnode_configure: "
2117 "PKEY num %x", port_pkey
);
2118 if (ret
== IBNEX_FAILURE
)
2121 ++svc_str
; /* svc_str used to point to ",svc_name" */
2123 /* find the service index */
2124 if (port_pkey
== 0) {
2126 for (sndx
= 0; sndx
< ibnex
.ibnex_num_comm_svcs
; sndx
++) {
2127 if (strncmp(ibnex
.ibnex_comm_svc_names
[sndx
],
2128 svc_str
, strlen(svc_str
)) == 0) {
2134 /* HCA_SVC Devices */
2135 if (found
== B_FALSE
) {
2136 for (sndx
= 0; sndx
< ibnex
.ibnex_nhcasvc_comm_svcs
;
2138 if (strncmp(ibnex
.ibnex_hcasvc_comm_svc_names
2139 [sndx
], svc_str
, strlen(svc_str
)) == 0) {
2141 is_hcasvc_node
= B_TRUE
;
2148 for (sndx
= 0; sndx
< ibnex
.ibnex_nvppa_comm_svcs
; sndx
++) {
2149 if (strncmp(ibnex
.ibnex_vppa_comm_svc_names
[sndx
],
2150 svc_str
, strlen(svc_str
)) == 0) {
2157 if (found
== B_FALSE
) {
2158 IBTF_DPRINTF_L2("ibnex",
2159 "\tibnex_handle_commsvcnode_configure: "
2160 "invalid service %s", svc_str
);
2164 /* get Port attributes structure */
2165 mutex_exit(&ibnex
.ibnex_mutex
);
2166 if (is_hcasvc_node
== B_FALSE
) {
2167 port_attr
= ibdm_ibnex_get_port_attrs(guid
);
2168 if (port_attr
== NULL
) {
2169 IBTF_DPRINTF_L2("ibnex",
2170 "\tibnex_handle_commsvcnode_configure: "
2171 "ibdm_ibnex_get_port_attrs failed");
2172 mutex_enter(&ibnex
.ibnex_mutex
);
2176 hca_list
= ibdm_ibnex_get_hca_info_by_guid(guid
);
2177 if (hca_list
== NULL
) {
2178 IBTF_DPRINTF_L2("ibnex",
2179 "\tibnex_handle_commsvcnode_configure: "
2180 "ibdm_ibnex_get_hca_info_by_guid failed");
2181 mutex_enter(&ibnex
.ibnex_mutex
);
2184 port_attr
= hca_list
->hl_hca_port_attr
;
2188 parent
= ibtl_ibnex_hcaguid2dip(port_attr
->pa_hca_guid
);
2190 if (parent
== NULL
) {
2191 IBTF_DPRINTF_L2("ibnex",
2192 "\tibnex_handle_commsvcnode_configure: "
2194 mutex_enter(&ibnex
.ibnex_mutex
);
2195 if (is_hcasvc_node
== B_FALSE
)
2196 ibdm_ibnex_free_port_attr(port_attr
);
2198 ibdm_ibnex_free_hca_list(hca_list
);
2203 node_type
= (is_hcasvc_node
== B_FALSE
) ?
2204 IBNEX_PORT_COMMSVC_NODE
: IBNEX_HCASVC_COMMSVC_NODE
;
2206 node_type
= IBNEX_VPPA_COMMSVC_NODE
;
2208 mutex_enter(&ibnex
.ibnex_mutex
);
2209 ndi_devi_enter(parent
, &circ
);
2210 if (ibnex_commsvc_initnode(parent
, port_attr
, sndx
, node_type
,
2211 port_pkey
, &ret
, IBNEX_CFGADM_ENUMERATE
) != NULL
) {
2212 retval
= IBNEX_SUCCESS
;
2214 retval
= (ret
== IBNEX_BUSY
) ? IBNEX_BUSY
: IBNEX_FAILURE
;
2216 ndi_devi_exit(parent
, circ
);
2218 if (is_hcasvc_node
== B_FALSE
)
2219 ibdm_ibnex_free_port_attr(port_attr
);
2221 ibdm_ibnex_free_hca_list(hca_list
);
2223 IBTF_DPRINTF_L4("ibnex", "\tibnex_handle_commsvcnode_configure: "
2224 "done retval = %d", retval
);
2231 * ibnex_return_apid()
2232 * Construct the ap_id of a given IBTF client in kernel
2235 ibnex_return_apid(dev_info_t
*childp
, char **ret_apid
)
2237 ibnex_node_data_t
*nodep
;
2239 IBTF_DPRINTF_L4("ibnex", "ibnex_return_apid:");
2241 ASSERT(childp
!= NULL
);
2242 nodep
= ddi_get_parent_data(childp
);
2244 if (nodep
->node_type
== IBNEX_PORT_COMMSVC_NODE
) {
2245 (void) snprintf(*ret_apid
, IBTL_IBNEX_APID_LEN
,
2246 "ib%s%llX,0,%s", DYN_SEP
,
2247 (longlong_t
)nodep
->node_data
.port_node
.port_guid
,
2248 ibnex
.ibnex_comm_svc_names
[nodep
->node_data
.port_node
.
2251 } else if (nodep
->node_type
== IBNEX_HCASVC_COMMSVC_NODE
) {
2252 (void) snprintf(*ret_apid
, IBTL_IBNEX_APID_LEN
,
2253 "ib%s%llX,0,%s", DYN_SEP
,
2254 (longlong_t
)nodep
->node_data
.port_node
.port_guid
, ibnex
.
2255 ibnex_hcasvc_comm_svc_names
[nodep
->node_data
.port_node
.
2258 } else if (nodep
->node_type
== IBNEX_VPPA_COMMSVC_NODE
) {
2259 (void) snprintf(*ret_apid
, IBTL_IBNEX_APID_LEN
,
2260 "ib%s%llX,%x,%s", DYN_SEP
,
2261 (longlong_t
)nodep
->node_data
.port_node
.port_guid
,
2262 nodep
->node_data
.port_node
.port_pkey
,
2263 ibnex
.ibnex_vppa_comm_svc_names
[nodep
->node_data
.port_node
.
2266 } else if (nodep
->node_type
== IBNEX_IOC_NODE
) {
2267 (void) snprintf(*ret_apid
, IBTL_IBNEX_APID_LEN
,
2268 "ib%s%llX", DYN_SEP
,
2269 (longlong_t
)nodep
->node_data
.ioc_node
.ioc_guid
);
2271 } else if (nodep
->node_type
== IBNEX_PSEUDO_NODE
) {
2272 (void) snprintf(*ret_apid
, IBTL_IBNEX_APID_LEN
, "ib%s%s",
2273 DYN_SEP
, nodep
->node_data
.pseudo_node
.pseudo_node_addr
);
2276 (void) snprintf(*ret_apid
, IBTL_IBNEX_APID_LEN
, "%s", "-");
2279 IBTF_DPRINTF_L4("ibnex", "ibnex_return_apid: %x %s",
2280 nodep
->node_type
, ret_apid
);
2285 * ibnex_vppa_conf_entry_add()
2286 * Add a new service to the ibnex data base of VPPA communication
2290 ibnex_vppa_conf_entry_add(char *service
)
2293 char **service_name
;
2295 ASSERT(MUTEX_HELD(&ibnex
.ibnex_mutex
));
2296 nsvcs
= ibnex
.ibnex_nvppa_comm_svcs
;
2298 /* Allocate space for new "ibnex.ibnex_nvppa_comm_svcs + 1" */
2299 service_name
= kmem_alloc((nsvcs
+ 1) * sizeof (char *), KM_SLEEP
);
2301 * Copy over the existing "ibnex.ibnex_vppa_comm_svc_names"
2302 * array. Add the new service at the end.
2304 for (i
= 0; i
< nsvcs
; i
++)
2305 service_name
[i
] = ibnex
.ibnex_vppa_comm_svc_names
[i
];
2306 service_name
[i
] = kmem_alloc(strlen(service
) + 1, KM_SLEEP
);
2307 (void) snprintf(service_name
[i
], 5, "%s", service
);
2309 /* Replace existing pointer to VPPA services w/ newly allocated one */
2310 if (ibnex
.ibnex_vppa_comm_svc_names
) {
2311 kmem_free(ibnex
.ibnex_vppa_comm_svc_names
, nsvcs
*
2314 ibnex
.ibnex_nvppa_comm_svcs
++;
2315 ibnex
.ibnex_vppa_comm_svc_names
= service_name
;
2319 * ibnex_port_conf_entry_add()
2320 * Add a new service to the ibnex data base of Port communication
2324 ibnex_port_conf_entry_add(char *service
)
2327 char **service_name
;
2329 ASSERT(MUTEX_HELD(&ibnex
.ibnex_mutex
));
2330 nsvcs
= ibnex
.ibnex_num_comm_svcs
;
2332 /* Allocate space for new "ibnex.ibnex_num_comm_svcs + 1" */
2333 service_name
= kmem_alloc((nsvcs
+ 1) * sizeof (char *), KM_SLEEP
);
2335 * Copy over the existing "ibnex.ibnex_comm_svc_names" array.
2336 * Add the new service to the end.
2338 for (i
= 0; i
< nsvcs
; i
++)
2339 service_name
[i
] = ibnex
.ibnex_comm_svc_names
[i
];
2340 service_name
[i
] = kmem_alloc(strlen(service
) + 1, KM_SLEEP
);
2341 (void) snprintf(service_name
[i
], 5, "%s", service
);
2343 /* Replace existing pointer to Port services w/ newly allocated one */
2344 if (ibnex
.ibnex_comm_svc_names
) {
2345 kmem_free(ibnex
.ibnex_comm_svc_names
, nsvcs
* sizeof (char *));
2347 ibnex
.ibnex_num_comm_svcs
++;
2348 ibnex
.ibnex_comm_svc_names
= service_name
;
2352 * ibnex_hcasvc_conf_entry_add()
2353 * Add a new service to the ibnex data base of HCA_SVC communication
2357 ibnex_hcasvc_conf_entry_add(char *service
)
2360 char **service_name
;
2362 ASSERT(MUTEX_HELD(&ibnex
.ibnex_mutex
));
2363 nsvcs
= ibnex
.ibnex_nhcasvc_comm_svcs
;
2365 /* Allocate space for new "ibnex.ibnex_nvppa_comm_svcs + 1" */
2366 service_name
= kmem_alloc((nsvcs
+ 1) * sizeof (char *), KM_SLEEP
);
2368 * Copy over the existing "ibnex.ibnex_hcasvc_comm_svc_names"
2369 * array. Add the new service at the end.
2371 for (i
= 0; i
< nsvcs
; i
++)
2372 service_name
[i
] = ibnex
.ibnex_hcasvc_comm_svc_names
[i
];
2373 service_name
[i
] = kmem_alloc(strlen(service
) + 1, KM_SLEEP
);
2374 (void) snprintf(service_name
[i
], 5, "%s", service
);
2377 * Replace existing pointer to HCA_SVC services w/ newly
2380 if (ibnex
.ibnex_hcasvc_comm_svc_names
) {
2381 kmem_free(ibnex
.ibnex_hcasvc_comm_svc_names
, nsvcs
*
2384 ibnex
.ibnex_nhcasvc_comm_svcs
++;
2385 ibnex
.ibnex_hcasvc_comm_svc_names
= service_name
;
2390 * ibnex_vppa_conf_entry_delete()
2391 * Delete an existing service entry from ibnex data base of
2392 * VPPA communication services.
2395 ibnex_vppa_conf_entry_delete(char *msg
, char *service
)
2400 char **service_name
;
2401 boolean_t found
= B_FALSE
;
2402 ibnex_node_data_t
*node_datap
= ibnex
.ibnex_port_node_head
;
2404 IBTF_DPRINTF_L4("ibnex", "\tvppa_conf_entry_delete: %s", service
);
2406 ASSERT(MUTEX_HELD(&ibnex
.ibnex_mutex
));
2407 nsvcs
= ibnex
.ibnex_nvppa_comm_svcs
;
2409 /* find matching index */
2410 for (i
= 0; i
< nsvcs
; i
++) {
2411 if (strcmp(ibnex
.ibnex_vppa_comm_svc_names
[i
], service
))
2418 /* check for valid "nsvcs" */
2419 if (found
== B_FALSE
|| nsvcs
== 0) {
2420 IBTF_DPRINTF_L2("ibnex", "%s: invalid vppa services %x",
2425 /* Check if service is in use; return failure if so */
2426 for (; node_datap
; node_datap
= node_datap
->node_next
) {
2427 if ((node_datap
->node_data
.port_node
.port_commsvc_idx
== i
) &&
2428 node_datap
->node_type
== IBNEX_VPPA_COMMSVC_NODE
&&
2429 node_datap
->node_dip
) {
2430 IBTF_DPRINTF_L2("ibnex", "%s: service %s is in use",
2436 /* if nsvcs == 1, bailout early */
2438 /* free up that single entry */
2439 len
= strlen(ibnex
.ibnex_vppa_comm_svc_names
[0]) + 1;
2440 kmem_free(ibnex
.ibnex_vppa_comm_svc_names
[0], len
);
2441 kmem_free(ibnex
.ibnex_vppa_comm_svc_names
, sizeof (char *));
2442 ibnex
.ibnex_vppa_comm_svc_names
= NULL
;
2443 ibnex
.ibnex_nvppa_comm_svcs
= 0;
2447 /* Allocate space for new "ibnex.ibnex_nvppa_comm_svcs - 1" */
2448 service_name
= kmem_alloc((nsvcs
- 1) * sizeof (char *), KM_SLEEP
);
2450 * Copy over the existing "ibnex.ibnex_vppa_comm_svc_names"
2451 * array. Do not copy over the matching service.
2453 for (i
= 0, j
= 0; i
< nsvcs
; i
++) {
2454 if (i
== match_ndx
) {
2455 /* free up that entry */
2456 len
= strlen(ibnex
.ibnex_vppa_comm_svc_names
[i
]) + 1;
2457 kmem_free(ibnex
.ibnex_vppa_comm_svc_names
[i
], len
);
2460 service_name
[j
++] = ibnex
.ibnex_vppa_comm_svc_names
[i
];
2463 /* Replace existing pointer to VPPA services w/ newly adjusted one */
2464 if (ibnex
.ibnex_vppa_comm_svc_names
) {
2465 kmem_free(ibnex
.ibnex_vppa_comm_svc_names
, nsvcs
*
2467 ibnex
.ibnex_nvppa_comm_svcs
--;
2468 ibnex
.ibnex_vppa_comm_svc_names
= service_name
;
2475 * ibnex_port_conf_entry_delete()
2476 * Delete an existing service entry from ibnex data base of
2477 * Port communication services.
2480 ibnex_port_conf_entry_delete(char *msg
, char *service
)
2485 char **service_name
;
2486 boolean_t found
= B_FALSE
;
2487 ibnex_node_data_t
*node_datap
= ibnex
.ibnex_port_node_head
;
2489 IBTF_DPRINTF_L4("ibnex", "\tport_conf_entry_delete: %s", service
);
2491 ASSERT(MUTEX_HELD(&ibnex
.ibnex_mutex
));
2492 nsvcs
= ibnex
.ibnex_num_comm_svcs
;
2494 /* find matching index */
2495 for (i
= 0; i
< nsvcs
; i
++) {
2496 if (strcmp(ibnex
.ibnex_comm_svc_names
[i
], service
))
2503 /* check for valid "nsvcs" */
2504 if (found
== B_FALSE
|| nsvcs
== 0) {
2505 IBTF_DPRINTF_L2("ibnex", "%s: invalid services %x", msg
, nsvcs
);
2509 /* Check if service is in use; return failure if so */
2510 for (; node_datap
; node_datap
= node_datap
->node_next
) {
2511 if ((node_datap
->node_data
.port_node
.port_commsvc_idx
== i
) &&
2512 node_datap
->node_type
== IBNEX_PORT_COMMSVC_NODE
&&
2513 node_datap
->node_dip
)
2517 /* if nsvcs == 1, bailout early */
2519 /* free up that single entry */
2520 len
= strlen(ibnex
.ibnex_comm_svc_names
[0]) + 1;
2521 kmem_free(ibnex
.ibnex_comm_svc_names
[0], len
);
2522 kmem_free(ibnex
.ibnex_comm_svc_names
, sizeof (char *));
2523 ibnex
.ibnex_comm_svc_names
= NULL
;
2524 ibnex
.ibnex_num_comm_svcs
= 0;
2528 /* Allocate space for new "ibnex.ibnex_num_comm_svcs - 1" */
2529 service_name
= kmem_alloc((nsvcs
- 1) * sizeof (char *), KM_SLEEP
);
2531 * Copy over the existing "ibnex.ibnex_comm_svc_names" array.
2532 * Skip the matching service.
2534 for (i
= 0, j
= 0; i
< nsvcs
; i
++) {
2535 if (i
== match_ndx
) {
2536 /* free up that entry */
2537 len
= strlen(ibnex
.ibnex_comm_svc_names
[i
]) + 1;
2538 kmem_free(ibnex
.ibnex_comm_svc_names
[i
], len
);
2541 service_name
[j
++] = ibnex
.ibnex_comm_svc_names
[i
];
2544 /* Replace existing pointer to Port services w/ newly adjusted one */
2545 if (ibnex
.ibnex_comm_svc_names
) {
2546 kmem_free(ibnex
.ibnex_comm_svc_names
, nsvcs
* sizeof (char *));
2547 ibnex
.ibnex_num_comm_svcs
--;
2548 ibnex
.ibnex_comm_svc_names
= service_name
;
2554 * ibnex_hcasvc_conf_entry_delete()
2555 * Delete an existing service entry from ibnex data base of
2556 * HCA_SVC communication services.
2559 ibnex_hcasvc_conf_entry_delete(char *msg
, char *service
)
2564 char **service_name
;
2565 boolean_t found
= B_FALSE
;
2566 ibnex_node_data_t
*node_datap
= ibnex
.ibnex_port_node_head
;
2568 IBTF_DPRINTF_L4("ibnex", "\thcasvc_conf_entry_delete: %s", service
);
2570 ASSERT(MUTEX_HELD(&ibnex
.ibnex_mutex
));
2571 nsvcs
= ibnex
.ibnex_nhcasvc_comm_svcs
;
2573 /* find matching index */
2574 for (i
= 0; i
< nsvcs
; i
++) {
2575 if (strcmp(ibnex
.ibnex_hcasvc_comm_svc_names
[i
], service
))
2582 /* check for valid "nsvcs" */
2583 if (found
== B_FALSE
|| nsvcs
== 0) {
2584 IBTF_DPRINTF_L2("ibnex", "%s: invalid hca_svc services %x",
2589 /* Check if service is in use; return failure if so */
2590 for (; node_datap
; node_datap
= node_datap
->node_next
) {
2591 if ((node_datap
->node_data
.port_node
.port_commsvc_idx
== i
) &&
2592 node_datap
->node_type
== IBNEX_HCASVC_COMMSVC_NODE
&&
2593 node_datap
->node_dip
) {
2594 IBTF_DPRINTF_L2("ibnex", "%s: service %s is in use",
2600 /* if nsvcs == 1, bailout early */
2602 /* free up that single entry */
2603 len
= strlen(ibnex
.ibnex_hcasvc_comm_svc_names
[0]) + 1;
2604 kmem_free(ibnex
.ibnex_hcasvc_comm_svc_names
[0], len
);
2605 kmem_free(ibnex
.ibnex_hcasvc_comm_svc_names
, sizeof (char *));
2606 ibnex
.ibnex_hcasvc_comm_svc_names
= NULL
;
2607 ibnex
.ibnex_nhcasvc_comm_svcs
= 0;
2611 /* Allocate space for new "ibnex.ibnex_nhcasvc_comm_svcs - 1" */
2612 service_name
= kmem_alloc((nsvcs
- 1) * sizeof (char *), KM_SLEEP
);
2614 * Copy over the existing "ibnex.ibnex_hcasvc_comm_svc_names"
2615 * array. Do not copy over the matching service.
2617 for (i
= 0, j
= 0; i
< nsvcs
; i
++) {
2618 if (i
== match_ndx
) {
2619 /* free up that entry */
2620 len
= strlen(ibnex
.ibnex_hcasvc_comm_svc_names
[i
]) + 1;
2621 kmem_free(ibnex
.ibnex_hcasvc_comm_svc_names
[i
], len
);
2624 service_name
[j
++] = ibnex
.ibnex_hcasvc_comm_svc_names
[i
];
2627 /* Replace existing pointer to VPPA services w/ newly adjusted one */
2628 if (ibnex
.ibnex_hcasvc_comm_svc_names
) {
2629 kmem_free(ibnex
.ibnex_hcasvc_comm_svc_names
, nsvcs
*
2631 ibnex
.ibnex_nhcasvc_comm_svcs
--;
2632 ibnex
.ibnex_hcasvc_comm_svc_names
= service_name
;
2639 * ibnex_ioc_fininode()
2640 * Un-initialize a child device node for IOC device node
2641 * Returns IBNEX_SUCCESS/IBNEX_FAILURE
2644 ibnex_ioc_fininode(dev_info_t
*dip
, ibnex_ioc_node_t
*ioc_nodep
)
2646 int rval
= MDI_SUCCESS
;
2648 ASSERT(MUTEX_HELD(&ibnex
.ibnex_mutex
));
2649 IBTF_DPRINTF_L4("ibnex", "\tioc_fininode");
2652 * For a dis-connected IOC,
2653 * Free the ioc_profile &&
2654 * decrement ibnex_num_disconnect_iocs
2656 if (ioc_nodep
->ioc_ngids
== 0 && ioc_nodep
->ioc_profile
) {
2657 IBTF_DPRINTF_L4("ibnex", "\tioc_fininode: unconfigure "
2658 "disconnected IOC: GUID %lX", ioc_nodep
->ioc_guid
);
2659 ibnex
.ibnex_num_disconnect_iocs
--;
2660 kmem_free(ioc_nodep
->ioc_profile
,
2661 sizeof (ib_dm_ioc_ctrl_profile_t
));
2662 ioc_nodep
->ioc_profile
= NULL
;
2665 mutex_exit(&ibnex
.ibnex_mutex
);
2666 ASSERT(i_ddi_node_state(dip
) >= DS_BOUND
);
2668 IBTF_DPRINTF_L4("ibnex", "\tioc_fininode: offlining the IOC");
2669 rval
= ibnex_offline_childdip(dip
);
2671 if (rval
!= MDI_SUCCESS
) {
2673 IBTF_DPRINTF_L2("ibnex", "\toffline failed for IOC "
2674 "dip %p with 0x%x", dip
, rval
);
2677 mutex_enter(&ibnex
.ibnex_mutex
);
2678 return (rval
== MDI_SUCCESS
? IBNEX_SUCCESS
: IBNEX_OFFLINE_FAILED
);
2683 ibnex_offline_childdip(dev_info_t
*dip
)
2685 int rval
= MDI_SUCCESS
, rval2
;
2686 mdi_pathinfo_t
*path
= NULL
, *temp
;
2688 IBTF_DPRINTF_L4("ibnex", "\toffline_childdip; begin");
2690 IBTF_DPRINTF_L2("ibnex", "\toffline_childdip; NULL dip");
2691 return (MDI_FAILURE
);
2694 for (path
= mdi_get_next_phci_path(dip
, path
); path
; ) {
2695 IBTF_DPRINTF_L4("ibnex", "\toffline_childdip: "
2696 "offling path %p", path
);
2697 rval2
= MDI_SUCCESS
;
2698 if (MDI_PI_IS_ONLINE(path
)) {
2699 rval2
= mdi_pi_offline(path
, NDI_UNCONFIG
);
2700 /* If it cannot be offlined, log this path and error */
2701 if (rval2
!= MDI_SUCCESS
) {
2704 "!ibnex\toffline_childdip (0x%p): "
2705 "mdi_pi_offline path (0x%p) failed with %d",
2706 (void *)dip
, (void *)path
, rval2
);
2709 /* prepare the next path */
2711 path
= mdi_get_next_phci_path(dip
, path
);
2712 /* free the offline path */
2713 if (rval2
== MDI_SUCCESS
) {
2714 (void) mdi_pi_free(temp
, 0);
2722 * ibnex_commsvc_fininode()
2724 * Un-initialize a child device node for HCA port / node GUID
2725 * for a communication service.
2726 * Returns IBNEX_SUCCESS/IBNEX_FAILURE
2729 ibnex_commsvc_fininode(dev_info_t
*dip
)
2731 int rval
= NDI_SUCCESS
;
2733 ASSERT(MUTEX_HELD(&ibnex
.ibnex_mutex
));
2734 IBTF_DPRINTF_L4("ibnex", "\tcommsvc_fininode");
2736 mutex_exit(&ibnex
.ibnex_mutex
);
2737 if (i_ddi_node_state(dip
) < DS_BOUND
) {
2739 * if the child hasn't been bound yet, we can
2740 * just free the dip. This path is currently
2743 (void) ddi_remove_child(dip
, 0);
2744 IBTF_DPRINTF_L4("ibnex",
2745 "\tcommsvc_fininode: ddi_remove_child");
2747 IBTF_DPRINTF_L4("ibnex", "\tcommsvc_fininode: offlining the "
2750 rval
= ndi_devi_offline(dip
, NDI_DEVI_REMOVE
| NDI_UNCONFIG
);
2751 if (rval
!= NDI_SUCCESS
)
2752 IBTF_DPRINTF_L2("ibnex", "\toffline failed for Commsvc "
2753 "dip %p with 0x%x", dip
, rval
);
2755 mutex_enter(&ibnex
.ibnex_mutex
);
2756 return (rval
== NDI_SUCCESS
? IBNEX_SUCCESS
: IBNEX_OFFLINE_FAILED
);
2761 * ibnex_pseudo_fininode()
2762 * Un-initialize a child pseudo device node
2763 * Returns IBNEX_SUCCESS/IBNEX_FAILURE
2766 ibnex_pseudo_fininode(dev_info_t
*dip
)
2768 int rval
= MDI_SUCCESS
;
2770 ASSERT(MUTEX_HELD(&ibnex
.ibnex_mutex
));
2771 IBTF_DPRINTF_L4("ibnex", "\tpseudo_fininode: dip = %p", dip
);
2773 mutex_exit(&ibnex
.ibnex_mutex
);
2774 ASSERT(i_ddi_node_state(dip
) >= DS_BOUND
);
2776 IBTF_DPRINTF_L4("ibnex", "\tpseudo_fininode: offlining the "
2778 rval
= ibnex_offline_childdip(dip
);
2779 if (rval
!= MDI_SUCCESS
) {
2781 IBTF_DPRINTF_L2("ibnex", "\tpseudo offline failed for "
2782 "dip %p with 0x%x", dip
, rval
);
2785 mutex_enter(&ibnex
.ibnex_mutex
);
2786 return (rval
== MDI_SUCCESS
? IBNEX_SUCCESS
: IBNEX_OFFLINE_FAILED
);
2790 * IOCTL implementation to get api version number.
2793 ibnex_ctl_get_api_ver(dev_t dev
, int cmd
, intptr_t arg
, int mode
,
2794 cred_t
*credp
, int *rvalp
)
2796 ibnex_ctl_api_ver_t api_ver
;
2798 IBTF_DPRINTF_L4("ibnex", "\tctl_get_api_ver: cmd=%x, arg=%p, "
2799 "mode=%x, cred=%p, rval=%p, dev=0x%x", cmd
, arg
, mode
, credp
,
2802 api_ver
.api_ver_num
= IBNEX_CTL_API_VERSION
;
2804 if (ddi_copyout(&api_ver
, (void *)arg
, sizeof (ibnex_ctl_api_ver_t
),
2806 IBTF_DPRINTF_L2("ibnex",
2807 "\tctl_get_api_ver: ddi_copyout err");
2815 * IOCTL implementation to get the list of HCAs
2818 ibnex_ctl_get_hca_list(dev_t dev
, int cmd
, intptr_t arg
, int mode
,
2819 cred_t
*credp
, int *rvalp
)
2821 ibnex_ctl_get_hca_list_t hca_list
;
2825 ib_guid_t
*hca_guids
;
2827 IBTF_DPRINTF_L4("ibnex", "\tctl_get_hca_list: cmd=%x, arg=%p, "
2828 "mode=%x, cred=%p, rval=%p, dev=0x%x", cmd
, arg
, mode
, credp
,
2831 #ifdef _MULTI_DATAMODEL
2832 if (ddi_model_convert_from(mode
& FMODELS
) == DDI_MODEL_ILP32
) {
2833 ibnex_ctl_get_hca_list_32_t hca_list_32
;
2835 if (ddi_copyin((void *)arg
, &hca_list_32
,
2836 sizeof (ibnex_ctl_get_hca_list_32_t
), mode
) != 0) {
2837 IBTF_DPRINTF_L2("ibnex",
2838 "\tctl_get_hca_list: ddi_copyin err 1");
2842 hca_list
.hca_guids_alloc_sz
= hca_list_32
.hca_guids_alloc_sz
;
2843 hca_list
.hca_guids
=
2844 (ib_guid_t
*)(uintptr_t)hca_list_32
.hca_guids
;
2845 in_nhcasp
= &((ibnex_ctl_get_hca_list_32_t
*)arg
)->nhcas
;
2849 if (ddi_copyin((void *)arg
, &hca_list
,
2850 sizeof (ibnex_ctl_get_hca_list_t
), mode
) != 0) {
2851 IBTF_DPRINTF_L2("ibnex",
2852 "\tctl_get_hca_list: ddi_copyin err 2");
2856 in_nhcasp
= &((ibnex_ctl_get_hca_list_t
*)arg
)->nhcas
;
2859 nhcas
= ibt_get_hca_list(&hca_guids
);
2861 /* copy number of hcas to user space */
2862 if (ddi_copyout(&nhcas
, in_nhcasp
, sizeof (uint_t
), mode
) != 0) {
2863 IBTF_DPRINTF_L2("ibnex",
2864 "\tctl_get_hca_list: ddi_copyout err 1");
2869 n
= MIN(nhcas
, hca_list
.hca_guids_alloc_sz
);
2873 /* copy HCA guids to user space */
2874 if (ddi_copyout(hca_guids
, hca_list
.hca_guids
,
2875 n
* sizeof (ib_guid_t
), mode
) != 0) {
2876 IBTF_DPRINTF_L2("ibnex",
2877 "\tctl_get_hca_list: ddi_copyout err 2");
2883 ibt_free_hca_list(hca_guids
, nhcas
);
2888 #define IBNEX_CTL_CP_HCA_INFO(x, y, driver_name, instance, device_path, \
2889 device_path_alloc_sz, device_path_len) \
2891 (x)->hca_node_guid = (y)->hca_node_guid; \
2892 (x)->hca_si_guid = (y)->hca_si_guid; \
2893 (x)->hca_nports = (y)->hca_nports; \
2894 (x)->hca_flags = (y)->hca_flags; \
2895 (x)->hca_flags2 = (y)->hca_flags2; \
2896 (x)->hca_vendor_id = (y)->hca_vendor_id; \
2897 (x)->hca_device_id = (y)->hca_device_id; \
2898 (x)->hca_version_id = (y)->hca_version_id; \
2899 (x)->hca_max_chans = (y)->hca_max_chans; \
2900 (x)->hca_max_chan_sz = (y)->hca_max_chan_sz; \
2901 (x)->hca_max_sgl = (y)->hca_max_sgl; \
2902 (x)->hca_max_cq = (y)->hca_max_cq; \
2903 (x)->hca_max_cq_sz = (y)->hca_max_cq_sz; \
2904 (x)->hca_page_sz = (y)->hca_page_sz; \
2905 (x)->hca_max_memr = (y)->hca_max_memr; \
2906 (x)->hca_max_memr_len = (y)->hca_max_memr_len; \
2907 (x)->hca_max_mem_win = (y)->hca_max_mem_win; \
2908 (x)->hca_max_rsc = (y)->hca_max_rsc; \
2909 (x)->hca_max_rdma_in_chan = (y)->hca_max_rdma_in_chan; \
2910 (x)->hca_max_rdma_out_chan = (y)->hca_max_rdma_out_chan; \
2911 (x)->hca_max_ipv6_chan = (y)->hca_max_ipv6_chan; \
2912 (x)->hca_max_ether_chan = (y)->hca_max_ether_chan; \
2913 (x)->hca_max_mcg_chans = (y)->hca_max_mcg_chans; \
2914 (x)->hca_max_mcg = (y)->hca_max_mcg; \
2915 (x)->hca_max_chan_per_mcg = (y)->hca_max_chan_per_mcg; \
2916 (x)->hca_max_partitions = (y)->hca_max_partitions; \
2917 (x)->hca_local_ack_delay = (y)->hca_local_ack_delay; \
2918 (x)->hca_max_port_sgid_tbl_sz = (y)->hca_max_port_sgid_tbl_sz; \
2919 (x)->hca_max_port_pkey_tbl_sz = (y)->hca_max_port_pkey_tbl_sz; \
2920 (x)->hca_max_pd = (y)->hca_max_pd; \
2921 (x)->hca_max_ud_dest = (y)->hca_max_ud_dest; \
2922 (x)->hca_max_srqs = (y)->hca_max_srqs; \
2923 (x)->hca_max_srqs_sz = (y)->hca_max_srqs_sz; \
2924 (x)->hca_max_srq_sgl = (y)->hca_max_srq_sgl; \
2925 (x)->hca_max_cq_handlers = (y)->hca_max_cq_handlers; \
2926 (x)->hca_reserved_lkey = (y)->hca_reserved_lkey; \
2927 (x)->hca_max_fmrs = (y)->hca_max_fmrs; \
2928 (x)->hca_max_lso_size = (y)->hca_max_lso_size; \
2929 (x)->hca_max_lso_hdr_size = (y)->hca_max_lso_hdr_size; \
2930 (x)->hca_max_inline_size = (y)->hca_max_inline_size; \
2931 (x)->hca_max_cq_mod_count = (y)->hca_max_cq_mod_count; \
2932 (x)->hca_max_cq_mod_usec = (y)->hca_max_cq_mod_usec; \
2933 (x)->hca_fw_major_version = (y)->hca_fw_major_version; \
2934 (x)->hca_fw_minor_version = (y)->hca_fw_minor_version; \
2935 (x)->hca_fw_micro_version = (y)->hca_fw_micro_version; \
2936 (x)->hca_ud_send_inline_sz = (y)->hca_ud_send_inline_sz; \
2937 (x)->hca_conn_send_inline_sz = (y)->hca_conn_send_inline_sz; \
2938 (x)->hca_conn_rdmaw_inline_overhead = \
2939 (y)->hca_conn_rdmaw_inline_overhead; \
2940 (x)->hca_recv_sgl_sz = (y)->hca_recv_sgl_sz; \
2941 (x)->hca_ud_send_sgl_sz = (y)->hca_ud_send_sgl_sz; \
2942 (x)->hca_conn_send_sgl_sz = (y)->hca_conn_send_sgl_sz; \
2943 (x)->hca_conn_rdma_sgl_overhead = (y)->hca_conn_rdma_sgl_overhead; \
2945 (void) strlcpy((x)->hca_driver_name, (driver_name), \
2946 MAX_HCA_DRVNAME_LEN); \
2947 (x)->hca_driver_instance = (instance); \
2949 (x)->hca_device_path = ((device_path_alloc_sz) >= (device_path_len)) \
2950 ? (device_path) : 0; \
2951 (x)->hca_device_path_len = (device_path_len); \
2955 * IOCTL implementation to query HCA attributes
2958 ibnex_ctl_query_hca(dev_t dev
, int cmd
, intptr_t arg
, int mode
,
2959 cred_t
*credp
, int *rvalp
)
2962 ibnex_ctl_query_hca_t
*query_hca
= NULL
;
2963 ibnex_ctl_query_hca_32_t
*query_hca_32
= NULL
;
2964 ibt_hca_attr_t
*hca_attr
= NULL
;
2965 char driver_name
[MAX_HCA_DRVNAME_LEN
];
2969 uint_t device_path_alloc_sz
, hca_device_path_len
;
2970 char *hca_device_path
= NULL
;
2972 IBTF_DPRINTF_L4("ibnex", "\tctl_query_hca: cmd=%x, arg=%p, "
2973 "mode=%x, cred=%p, rval=%p, dev=0x%x", cmd
, arg
, mode
, credp
,
2976 #ifdef _MULTI_DATAMODEL
2977 if (ddi_model_convert_from(mode
& FMODELS
) == DDI_MODEL_ILP32
) {
2978 query_hca_32
= kmem_zalloc(
2979 sizeof (ibnex_ctl_query_hca_32_t
), KM_SLEEP
);
2981 if (ddi_copyin((void *)arg
, query_hca_32
,
2982 sizeof (ibnex_ctl_query_hca_32_t
), mode
) != 0) {
2983 IBTF_DPRINTF_L2("ibnex",
2984 "\tctl_query_hca: ddi_copyin err 1");
2989 hca_guid
= query_hca_32
->hca_guid
;
2990 device_path
= (char *)(uintptr_t)query_hca_32
->hca_device_path
;
2991 device_path_alloc_sz
= query_hca_32
->hca_device_path_alloc_sz
;
2995 query_hca
= kmem_zalloc(sizeof (ibnex_ctl_query_hca_t
),
2998 if (ddi_copyin((void *)arg
, query_hca
,
2999 sizeof (ibnex_ctl_query_hca_t
), mode
) != 0) {
3000 IBTF_DPRINTF_L2("ibnex",
3001 "\tctl_query_hca: ddi_copyin err 2");
3006 hca_guid
= query_hca
->hca_guid
;
3007 device_path
= query_hca
->hca_device_path
;
3008 device_path_alloc_sz
= query_hca
->hca_device_path_alloc_sz
;
3011 hca_attr
= kmem_zalloc(sizeof (ibt_hca_attr_t
), KM_SLEEP
);
3012 hca_device_path
= kmem_zalloc(MAXPATHLEN
, KM_SLEEP
);
3014 if (ibtl_ibnex_query_hca_byguid(hca_guid
, hca_attr
,
3015 driver_name
, sizeof (driver_name
), &instance
, hca_device_path
)
3021 hca_device_path_len
= strlen(hca_device_path
) + 1;
3023 #ifdef _MULTI_DATAMODEL
3024 if (ddi_model_convert_from(mode
& FMODELS
) == DDI_MODEL_ILP32
) {
3026 IBNEX_CTL_CP_HCA_INFO(&query_hca_32
->hca_info
, hca_attr
,
3027 driver_name
, instance
, query_hca_32
->hca_device_path
,
3028 device_path_alloc_sz
, hca_device_path_len
);
3030 /* copy hca information to the user space */
3031 if (ddi_copyout(&query_hca_32
->hca_info
,
3032 &((ibnex_ctl_query_hca_32_t
*)arg
)->hca_info
,
3033 sizeof (ibnex_ctl_hca_info_32_t
), mode
) != 0) {
3034 IBTF_DPRINTF_L2("ibnex",
3035 "\tctl_query_hca: ddi_copyout err 1");
3042 IBNEX_CTL_CP_HCA_INFO(&query_hca
->hca_info
, hca_attr
,
3043 driver_name
, instance
, device_path
,
3044 device_path_alloc_sz
, hca_device_path_len
);
3046 /* copy hca information to the user space */
3047 if (ddi_copyout(&query_hca
->hca_info
,
3048 &((ibnex_ctl_query_hca_t
*)arg
)->hca_info
,
3049 sizeof (ibnex_ctl_hca_info_t
), mode
) != 0) {
3050 IBTF_DPRINTF_L2("ibnex",
3051 "\tctl_query_hca: ddi_copyout err 2");
3057 if (device_path_alloc_sz
>= hca_device_path_len
) {
3058 if (ddi_copyout(hca_device_path
,
3060 hca_device_path_len
, mode
) != 0) {
3061 IBTF_DPRINTF_L2("ibnex", "\tctl_query_hca: "
3062 "ddi_copyout err copying device path");
3069 kmem_free(query_hca
, sizeof (ibnex_ctl_query_hca_t
));
3071 kmem_free(query_hca_32
, sizeof (ibnex_ctl_query_hca_32_t
));
3073 kmem_free(hca_attr
, sizeof (ibt_hca_attr_t
));
3074 if (hca_device_path
)
3075 kmem_free(hca_device_path
, MAXPATHLEN
);
3080 #define IBNEX_CTL_CP_PORT_INFO(x, y, sgid_tbl, pkey_tbl) \
3082 (x)->p_lid = (y)->p_opaque1; \
3083 (x)->p_qkey_violations = (y)->p_qkey_violations; \
3084 (x)->p_pkey_violations = (y)->p_pkey_violations; \
3085 (x)->p_sm_sl = (y)->p_sm_sl; \
3086 (x)->p_phys_state = (y)->p_phys_state; \
3087 (x)->p_sm_lid = (y)->p_sm_lid; \
3088 (x)->p_linkstate = (y)->p_linkstate; \
3089 (x)->p_port_num = (y)->p_port_num; \
3090 (x)->p_width_supported = (y)->p_width_supported; \
3091 (x)->p_width_enabled = (y)->p_width_enabled; \
3092 (x)->p_width_active = (y)->p_width_active; \
3093 (x)->p_mtu = (y)->p_mtu; \
3094 (x)->p_lmc = (y)->p_lmc; \
3095 (x)->p_speed_supported = (y)->p_speed_supported; \
3096 (x)->p_speed_enabled = (y)->p_speed_enabled; \
3097 (x)->p_speed_active = (y)->p_speed_active; \
3098 (x)->p_sgid_tbl = (sgid_tbl); \
3099 (x)->p_sgid_tbl_sz = (y)->p_sgid_tbl_sz; \
3100 (x)->p_pkey_tbl = (pkey_tbl); \
3101 (x)->p_pkey_tbl_sz = (y)->p_pkey_tbl_sz; \
3102 (x)->p_def_pkey_ix = (y)->p_def_pkey_ix; \
3103 (x)->p_max_vl = (y)->p_max_vl; \
3104 (x)->p_init_type_reply = (y)->p_init_type_reply; \
3105 (x)->p_subnet_timeout = (y)->p_subnet_timeout; \
3106 (x)->p_capabilities = (y)->p_capabilities; \
3107 (x)->p_msg_sz = (y)->p_msg_sz; \
3111 * IOCTL implementation to query HCA port attributes
3114 ibnex_ctl_query_hca_port(dev_t dev
, int cmd
, intptr_t arg
, int mode
,
3115 cred_t
*credp
, int *rvalp
)
3117 ibt_hca_portinfo_t
*ibt_pi
;
3121 ibnex_ctl_query_hca_port_t
*query_hca_port
= NULL
;
3122 ibnex_ctl_query_hca_port_32_t
*query_hca_port_32
= NULL
;
3124 uint16_t pkey_tbl_sz
;
3125 ibt_hca_attr_t hca_attr
;
3127 IBTF_DPRINTF_L4("ibnex", "\tctl_query_hca_port: cmd=%x, arg=%p, "
3128 "mode=%x, cred=%p, rval=%p, dev=0x%x", cmd
, arg
, mode
, credp
,
3131 query_hca_port
= kmem_zalloc(sizeof (ibnex_ctl_query_hca_port_t
),
3134 #ifdef _MULTI_DATAMODEL
3135 if (ddi_model_convert_from(mode
& FMODELS
) == DDI_MODEL_ILP32
) {
3136 query_hca_port_32
= kmem_zalloc(
3137 sizeof (ibnex_ctl_query_hca_port_32_t
), KM_SLEEP
);
3139 if (ddi_copyin((void *)arg
, query_hca_port_32
,
3140 sizeof (ibnex_ctl_query_hca_port_32_t
), mode
) != 0) {
3141 IBTF_DPRINTF_L2("ibnex",
3142 "\tctl_query_hca_port: ddi_copyin err 1");
3147 query_hca_port
->hca_guid
= query_hca_port_32
->hca_guid
;
3148 query_hca_port
->port_num
= query_hca_port_32
->port_num
;
3150 query_hca_port
->sgid_tbl
=
3151 (ib_gid_t
*)(uintptr_t)query_hca_port_32
->sgid_tbl
;
3152 query_hca_port
->sgid_tbl_alloc_sz
=
3153 query_hca_port_32
->sgid_tbl_alloc_sz
;
3155 query_hca_port
->pkey_tbl
=
3156 (ib_pkey_t
*)(uintptr_t)query_hca_port_32
->pkey_tbl
;
3157 query_hca_port
->pkey_tbl_alloc_sz
=
3158 query_hca_port_32
->pkey_tbl_alloc_sz
;
3163 if (ddi_copyin((void *)arg
, query_hca_port
,
3164 sizeof (ibnex_ctl_query_hca_port_t
), mode
) != 0) {
3165 IBTF_DPRINTF_L2("ibnex",
3166 "\tctl_query_hca_port: ddi_copyin err 2");
3172 if (ibt_query_hca_byguid(query_hca_port
->hca_guid
, &hca_attr
) !=
3178 if (query_hca_port
->port_num
== 0 ||
3179 query_hca_port
->port_num
> hca_attr
.hca_nports
) {
3185 * Query hca port attributes and copy them to the user space.
3188 if (ibt_query_hca_ports_byguid(query_hca_port
->hca_guid
,
3189 query_hca_port
->port_num
, &ibt_pi
, &nports
, &size
) != IBT_SUCCESS
) {
3194 sgid_tbl_sz
= MIN(query_hca_port
->sgid_tbl_alloc_sz
,
3195 ibt_pi
->p_sgid_tbl_sz
);
3197 pkey_tbl_sz
= MIN(query_hca_port
->pkey_tbl_alloc_sz
,
3198 ibt_pi
->p_pkey_tbl_sz
);
3200 #ifdef _MULTI_DATAMODEL
3201 if (ddi_model_convert_from(mode
& FMODELS
) == DDI_MODEL_ILP32
) {
3202 IBNEX_CTL_CP_PORT_INFO(
3203 &query_hca_port_32
->port_info
, ibt_pi
,
3204 query_hca_port_32
->sgid_tbl
, query_hca_port_32
->pkey_tbl
);
3206 if (ddi_copyout(&query_hca_port_32
->port_info
,
3207 &((ibnex_ctl_query_hca_port_32_t
*)arg
)->port_info
,
3208 sizeof (ibnex_ctl_hca_port_info_32_t
), mode
) != 0 ||
3210 ddi_copyout(ibt_pi
->p_sgid_tbl
,
3211 query_hca_port
->sgid_tbl
,
3212 sgid_tbl_sz
* sizeof (ib_gid_t
), mode
) != 0 ||
3214 ddi_copyout(ibt_pi
->p_pkey_tbl
,
3215 query_hca_port
->pkey_tbl
,
3216 pkey_tbl_sz
* sizeof (ib_pkey_t
), mode
) != 0) {
3218 IBTF_DPRINTF_L2("ibnex",
3219 "\tctl_query_hca_port: ddi_copyout err 2");
3226 IBNEX_CTL_CP_PORT_INFO(
3227 &query_hca_port
->port_info
, ibt_pi
,
3228 query_hca_port
->sgid_tbl
, query_hca_port
->pkey_tbl
);
3230 if (ddi_copyout(&query_hca_port
->port_info
,
3231 &((ibnex_ctl_query_hca_port_t
*)arg
)->port_info
,
3232 sizeof (ibnex_ctl_hca_port_info_t
), mode
) != 0 ||
3234 ddi_copyout(ibt_pi
->p_sgid_tbl
,
3235 query_hca_port
->sgid_tbl
,
3236 sgid_tbl_sz
* sizeof (ib_gid_t
), mode
) != 0 ||
3238 ddi_copyout(ibt_pi
->p_pkey_tbl
,
3239 query_hca_port
->pkey_tbl
,
3240 pkey_tbl_sz
* sizeof (ib_pkey_t
), mode
) != 0) {
3242 IBTF_DPRINTF_L2("ibnex",
3243 "\tctl_query_hca_port: ddi_copyout err 2");
3251 ibt_free_portinfo(ibt_pi
, size
);
3254 kmem_free(query_hca_port
, sizeof (ibnex_ctl_query_hca_port_t
));
3256 if (query_hca_port_32
)
3257 kmem_free(query_hca_port_32
,
3258 sizeof (ibnex_ctl_query_hca_port_32_t
));