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) 2010, Oracle and/or its affiliates. All rights reserved.
27 #include <sys/modctl.h>
28 #include <sys/taskq.h>
29 #include <sys/mdi_impldefs.h>
30 #include <sys/sunmdi.h>
31 #include <sys/sunpm.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/ibti.h>
36 #include <sys/ib/ibtl/impl/ibtl_ibnex.h>
38 #include <sys/hwconf.h>
39 #include <sys/fs/dv_node.h>
41 void ibnex_handle_hca_attach(void *);
42 static int ibnex_hca_bus_config_one(dev_info_t
*, void *,
43 ddi_bus_config_op_t
, uint_t
*, dev_info_t
**);
45 static ibnex_node_data_t
*ibnex_get_cdip_info(dev_info_t
*, char *,
46 dev_info_t
**, ibnex_node_type_t
*);
47 static int ibnex_prom_devname_to_pkey_n_portnum(
48 char *, ib_pkey_t
*, uint8_t *);
49 static dev_info_t
*ibnex_config_obp_args(dev_info_t
*, char *);
51 extern int ibnex_busctl(dev_info_t
*,
52 dev_info_t
*, ddi_ctl_enum_t
, void *, void *);
53 extern int ibnex_map_fault(dev_info_t
*,
54 dev_info_t
*, struct hat
*, struct seg
*,
55 caddr_t
, struct devpage
*, pfn_t
, uint_t
, uint_t
);
56 static int ibnex_hca_bus_config(dev_info_t
*, uint_t
,
57 ddi_bus_config_op_t
, void *, dev_info_t
**);
58 static int ibnex_hca_bus_unconfig(dev_info_t
*,
59 uint_t
, ddi_bus_config_op_t
, void *);
60 extern dev_info_t
*ibnex_config_port_node(dev_info_t
*, char *);
61 extern dev_info_t
*ibnex_config_obp_args(dev_info_t
*, char *);
62 extern int ibnex_ioc_bus_config_one(dev_info_t
**, uint_t
,
63 ddi_bus_config_op_t
, void *, dev_info_t
**, int *);
64 extern int ibnex_pseudo_config_one(
65 ibnex_node_data_t
*, char *, dev_info_t
*);
66 extern void ibnex_config_all_children(dev_info_t
*);
67 extern void ibnex_pseudo_initnodes(void);
69 extern int ibnex_pseudo_mdi_config_one(int, void *, dev_info_t
**,
71 extern int ibnex_get_dip_from_guid(ib_guid_t
, int,
72 ib_pkey_t
, dev_info_t
**);
73 extern dev_info_t
*ibnex_commsvc_initnode(dev_info_t
*,
74 ibdm_port_attr_t
*, int, int, ib_pkey_t
, int *,
76 extern uint64_t ibnex_str2hex(char *, int, int *);
77 extern int ibnex_str2int(char *, int, int *);
78 extern void ibnex_create_hcasvc_nodes(
79 dev_info_t
*, ibdm_port_attr_t
*);
80 extern void ibnex_create_port_nodes(
81 dev_info_t
*, ibdm_port_attr_t
*);
82 extern void ibnex_create_vppa_nodes(
83 dev_info_t
*, ibdm_port_attr_t
*);
84 extern int ibnex_get_pkey_commsvc_index_portnum(
85 char *, int *, ib_pkey_t
*, uint8_t *);
88 extern int ibnex_port_settling_time
;
91 * The bus_ops structure defines the capabilities of HCA nexus driver.
93 struct bus_ops ibnex_ci_busops
= {
95 nullbusmap
, /* bus_map */
96 NULL
, /* bus_get_intrspec */
97 NULL
, /* bus_add_intrspec */
98 NULL
, /* bus_remove_intrspec */
99 ibnex_map_fault
, /* Map Fault */
100 ddi_no_dma_map
, /* DMA related entry points */
108 ibnex_busctl
, /* bus_ctl */
109 ddi_bus_prop_op
, /* bus_prop_op */
110 NULL
, /* bus_get_eventcookie */
111 NULL
, /* bus_add_eventcall */
112 NULL
, /* bus_remove_eventcall */
113 NULL
, /* bus_post_event */
115 ibnex_hca_bus_config
, /* bus config */
116 ibnex_hca_bus_unconfig
/* bus unconfig */
120 * ibnex_hca_bus_config()
123 * Enumerate the exact instance of the driver. Use the device node name
124 * to locate the exact instance.
125 * Query IBDM to find whether the hardware exits for the instance of the
126 * driver. If exists, create a device node and return NDI_SUCCESS.
129 * Enumerate all the instances of all the possible children (seen before
130 * and never seen before).
133 * Enumerate all the instances of a particular driver.
136 ibnex_hca_bus_config(dev_info_t
*parent
, uint_t flag
,
137 ddi_bus_config_op_t op
, void *devname
, dev_info_t
**child
)
139 int ret
= IBNEX_SUCCESS
, circ
;
140 char *srvname
, nameaddr
[MAXNAMELEN
];
142 ibnex_node_data_t
*node_data
;
143 ibnex_port_node_t
*port_node
;
146 * In a normal case HCA is setup as a phci.
147 * If an HCA is in maintenance mode, its phci is not set up
148 * but the driver is attached to update the firmware. In this
149 * case, do not configure the MPxIO clients.
151 if (mdi_component_is_phci(parent
, NULL
) == MDI_FAILURE
) {
152 if (op
== BUS_CONFIG_ALL
|| op
== BUS_CONFIG_DRIVER
)
153 return (NDI_SUCCESS
);
155 return (NDI_FAILURE
);
160 IBTF_DPRINTF_L4("ibnex", "\thca_bus_config: CONFIG_ONE, "
161 "parent %p", parent
);
162 ret
= ibnex_hca_bus_config_one(
163 parent
, devname
, op
, &flag
, child
);
166 case BUS_CONFIG_OBP_ARGS
:
167 mdi_devi_enter(parent
, &circ
);
168 cdip
= ibnex_config_obp_args(parent
, devname
);
172 * Special handling because the "devname"
173 * format for the enumerated device is
176 node_data
= ddi_get_parent_data(cdip
);
177 port_node
= &node_data
->node_data
.port_node
;
178 if (node_data
->node_type
==
179 IBNEX_VPPA_COMMSVC_NODE
) {
181 ibnex
.ibnex_vppa_comm_svc_names
[
182 port_node
->port_commsvc_idx
];
183 (void) snprintf(nameaddr
, MAXNAMELEN
,
186 port_node
->port_pkey
, srvname
);
188 devname
= (void *)nameaddr
;
190 IBTF_DPRINTF_L2("ibnex", "\thca_bus_config: "
191 "CONFIG_OBP_ARGS : invalid state!!");
195 mdi_devi_exit(parent
, circ
);
199 IBTF_DPRINTF_L4("ibnex",
200 "\thca_bus_config: CONFIG_ALL parent %p", parent
);
201 ibnex_config_all_children(parent
);
204 case BUS_CONFIG_DRIVER
:
205 IBTF_DPRINTF_L4("ibnex", "\thca_bus_config: "
206 "CONFIG_DRIVER parent %p", parent
);
207 ibnex_config_all_children(parent
);
211 IBTF_DPRINTF_L4("ibnex", "\thca_bus_config: error");
217 if (ret
== IBNEX_SUCCESS
) {
218 if (op
== BUS_CONFIG_OBP_ARGS
)
221 ret
= ndi_busop_bus_config(
222 parent
, flag
, op
, devname
, child
, 0);
223 IBTF_DPRINTF_L4("ibnex", "\thca_bus_config:"
224 "ndi_busop_bus_config : retval %d", ret
);
228 return (NDI_FAILURE
);
232 * ibnex_hca_bus_unconfig()
234 * Unconfigure a particular device node or all instance of a device
235 * driver device or all children of IBnex
238 ibnex_hca_bus_unconfig(dev_info_t
*parent
,
239 uint_t flag
, ddi_bus_config_op_t op
, void *device_name
)
242 if (ndi_busop_bus_unconfig(parent
, flag
, op
, device_name
) !=
244 return (DDI_FAILURE
);
246 if ((op
== BUS_UNCONFIG_ALL
|| op
== BUS_UNCONFIG_DRIVER
) &&
247 (flag
& NDI_UNCONFIG
)) {
248 ibnex_node_data_t
*ndp
;
249 dev_info_t
*dip
= NULL
;
250 major_t major
= (major_t
)(uintptr_t)device_name
;
252 mutex_enter(&ibnex
.ibnex_mutex
);
256 * HCA dip. When major number is -1 HCA is
257 * going away cleanup all the port nodes.
259 for (ndp
= ibnex
.ibnex_port_node_head
;
260 ndp
; ndp
= ndp
->node_next
) {
261 ibnex_port_node_t
*port_node
;
263 port_node
= &ndp
->node_data
.port_node
;
264 if (port_node
->port_pdip
== parent
) {
265 port_node
->port_pdip
= NULL
;
266 ndp
->node_dip
= NULL
;
268 IBNEX_CFGADM_UNCONFIGURED
;
273 * HCA dip. Cleanup only the port nodes that
274 * match the major number.
276 for (ndp
= ibnex
.ibnex_port_node_head
;
277 ndp
; ndp
= ndp
->node_next
) {
278 ibnex_port_node_t
*port_node
;
280 port_node
= &ndp
->node_data
.port_node
;
282 if (dip
&& (ddi_driver_major(dip
) ==
283 major
) && port_node
->port_pdip
==
285 port_node
->port_pdip
= NULL
;
286 ndp
->node_dip
= NULL
;
288 IBNEX_CFGADM_UNCONFIGURED
;
292 mutex_exit(&ibnex
.ibnex_mutex
);
294 return (DDI_SUCCESS
);
298 * ibnex_config_obp_args()
299 * Configures a particular port node for a IP over IB communication
301 * The format of the input string "devname" is
302 * port=x,pkey=y,protocol=ip
303 * Thr format of the node name created here is
304 * ibport@<Port#>,<pkey>,<service name>
305 * where pkey = 0 for port communication service nodes
306 * Returns "dev_info_t" of the "child" node just created
307 * NULL when failed to enumerate the child node
311 ibnex_config_obp_args(dev_info_t
*parent
, char *devname
)
317 ib_guid_t hca_guid
, port_guid
;
320 boolean_t displayed
= B_FALSE
;
321 ibdm_port_attr_t
*port_attr
;
323 IBTF_DPRINTF_L4("ibnex", "\tconfig_obp_args: %s", devname
);
325 /* Is this OBP node for IPoIB ? */
328 temp
= strstr(temp
, ",protocol=ip");
332 if (strlen(devname
) > (int)((temp
- devname
) + 12)) {
343 if (ibnex_prom_devname_to_pkey_n_portnum(
344 devname
, &pkey
, &port_num
) != IBNEX_SUCCESS
) {
347 for (index
= 0; index
< ibnex
.ibnex_nvppa_comm_svcs
; index
++) {
348 if (strcmp(ibnex
.ibnex_vppa_comm_svc_names
[index
],
354 hca_guid
= ibtl_ibnex_hcadip2guid(parent
);
355 if ((port_attr
= ibdm_ibnex_probe_hcaport(
356 hca_guid
, port_num
)) == NULL
) {
357 IBTF_DPRINTF_L2("ibnex",
358 "\tconfig_port_node: Port does not exist");
362 /* Wait until "port is up" */
363 while (port_attr
->pa_state
!= IBT_PORT_ACTIVE
) {
364 ibdm_ibnex_free_port_attr(port_attr
);
365 delay(drv_usectohz(10000));
366 if ((port_attr
= ibdm_ibnex_probe_hcaport(
367 hca_guid
, port_num
)) == NULL
) {
371 if (displayed
== B_FALSE
) {
372 cmn_err(CE_NOTE
, "\tWaiting for Port %d "
373 "initialization", port_attr
->pa_port_num
);
378 IBTF_DPRINTF_L4("ibnex", "\tPort is initialized");
380 mutex_enter(&ibnex
.ibnex_mutex
);
381 port_guid
= port_attr
->pa_port_guid
;
382 rval
= ibnex_get_dip_from_guid(port_guid
, index
, pkey
, &cdip
);
383 if (rval
== IBNEX_SUCCESS
&& cdip
!= NULL
) {
384 IBTF_DPRINTF_L4("ibnex", "\tconfig_port_node: Node exists");
385 mutex_exit(&ibnex
.ibnex_mutex
);
386 ibdm_ibnex_free_port_attr(port_attr
);
389 for (ii
= 0; ii
< port_attr
->pa_npkeys
; ii
++) {
390 if (pkey
== port_attr
->pa_pkey_tbl
[ii
].pt_pkey
) {
391 cdip
= ibnex_commsvc_initnode(parent
, port_attr
,
392 index
, IBNEX_VPPA_COMMSVC_NODE
, pkey
, &rval
,
393 IBNEX_CFGADM_ENUMERATE
);
394 IBTF_DPRINTF_L5("ibnex",
395 "\t ibnex_commsvc_initnode rval %x", rval
);
399 mutex_exit(&ibnex
.ibnex_mutex
);
401 ibdm_ibnex_free_port_attr(port_attr
);
407 * ibnex_prom_devname_to_pkey_n_portnum()
408 * Parses the device node name and extracts "PKEY" and "port#"
409 * Returns IBNEX_SUCCESS/IBNEX_FAILURE
412 ibnex_prom_devname_to_pkey_n_portnum(
413 char *devname
, ib_pkey_t
*pkey
, uint8_t *port
)
415 int ret
= IBNEX_SUCCESS
;
418 if ((tmp
= strstr(devname
, "port=")) != NULL
) {
419 if ((tmp
= strchr(++tmp
, '=')) != NULL
)
420 if ((tmp1
= strchr(++tmp
, ',')) != NULL
)
421 *port
= ibnex_str2int(tmp
, (tmp1
- tmp
), &ret
);
425 if ((ret
== IBNEX_SUCCESS
) &&
426 (tmp
= strstr(devname
, "pkey=")) != NULL
) {
427 if ((tmp
= strchr(++tmp
, '=')) != NULL
)
428 if ((tmp1
= strchr(++tmp
, ',')) != NULL
)
429 *pkey
= ibnex_str2hex(tmp
, (tmp1
- tmp
), &ret
);
436 static ibnex_node_data_t
*
437 ibnex_get_cdip_info(dev_info_t
*parent
,
438 char *devname
, dev_info_t
**cdip
, ibnex_node_type_t
*type
)
440 char *device_name
, *cname
= NULL
, *caddr
= NULL
;
442 ibnex_node_data_t
*node_data
= NULL
;
444 len
= strlen((char *)devname
) + 1;
445 device_name
= i_ddi_strdup(devname
, KM_SLEEP
);
446 i_ddi_parse_name(device_name
, &cname
, &caddr
, NULL
);
448 IBTF_DPRINTF_L4("ibnex",
449 "\tfind_child_dip: cname %s addr %s", cname
, caddr
);
451 if (strncmp(cname
, IBNEX_IOC_CNAME
, 3) == 0)
452 *type
= IBNEX_IOC_NODE
;
453 else if (strncmp(cname
, IBNEX_IBPORT_CNAME
, 3) == 0)
454 *type
= IBNEX_HCA_CHILD_NODE
;
456 *type
= IBNEX_PSEUDO_NODE
;
458 *cdip
= ndi_devi_findchild(parent
, devname
);
460 IBTF_DPRINTF_L4("ibnex",
461 "\tfind_child_dip: cdip %p type %x", *cdip
, *type
);
464 node_data
= ddi_get_parent_data(*cdip
);
465 kmem_free(device_name
, len
);
471 ibnex_hca_bus_config_one(dev_info_t
*parent
, void *devname
,
472 ddi_bus_config_op_t op
, uint_t
*flag
, dev_info_t
**child
)
474 int ret
= IBNEX_SUCCESS
, len
, circ
, need_bus_config
;
475 char *device_name
, *caddr
, *cname
;
477 ibnex_node_data_t
*node_data
;
478 ibnex_node_type_t node_type
;
483 len
= strlen((char *)devname
) + 1;
484 device_name
= i_ddi_strdup(devname
, KM_SLEEP
);
485 i_ddi_parse_name(device_name
, &cname
, &caddr
, NULL
);
487 if (caddr
== NULL
|| (strlen(caddr
) == 0)) {
488 IBTF_DPRINTF_L2("ibnex",
489 "\thca_bus_config: Invalid device node address");
490 kmem_free(device_name
, len
);
491 return (IBNEX_FAILURE
);
494 ndi_devi_enter(parent
, &circ
);
495 node_data
= ibnex_get_cdip_info(
496 parent
, devname
, &cdip
, &node_type
);
497 ndi_devi_exit(parent
, circ
);
500 if ((node_data
) && (node_data
->node_type
==
501 IBNEX_PORT_COMMSVC_NODE
)) {
502 if (node_data
->node_dip
== NULL
) {
503 node_data
->node_dip
= cdip
;
504 node_data
->node_data
.port_node
.port_pdip
=
511 * If child dip is present, just return
514 if (cdip
!= NULL
|| (node_data
!= NULL
&&
515 node_data
->node_dip
!= NULL
)) {
522 ret
= ibnex_ioc_bus_config_one(&parent
, *flag
,
523 op
, devname
, child
, &need_bus_config
);
524 if (!need_bus_config
) {
525 kmem_free(device_name
, len
);
530 case IBNEX_PSEUDO_NODE
:
532 mdi_devi_enter(parent
, &circ
);
533 ibnex_pseudo_initnodes();
534 mutex_enter(&ibnex
.ibnex_mutex
);
535 ret
= ibnex_pseudo_config_one(NULL
,
537 mutex_exit(&ibnex
.ibnex_mutex
);
538 mdi_devi_exit(parent
, circ
);
542 if (ibnex_get_pkey_commsvc_index_portnum(devname
,
543 &index
, &pkey
, &port_num
) != IBNEX_SUCCESS
) {
544 IBTF_DPRINTF_L2("ibnex",
545 "\tconfig_port_node: Invalid Service Name");
546 kmem_free(device_name
, len
);
547 return (IBNEX_FAILURE
);
550 if ((pkey
!= 0) && (port_num
!= 0)) {
552 ibnex
.ibnex_vppa_comm_svc_names
[index
]) == 0) {
553 IBTF_DPRINTF_L2("ibnex",
554 "Skipping IBD devices... ");
559 ndi_devi_enter(parent
, &circ
);
560 cdip
= ibnex_config_port_node(parent
, devname
);
565 ndi_devi_exit(parent
, circ
);
569 if (node_type
== IBNEX_HCA_CHILD_NODE
) {
570 /* Allows enumeration under PHCI */
571 *flag
|= NDI_MDI_FALLBACK
;
573 kmem_free(device_name
, len
);
578 ibnex_handle_hca_attach(void *cb_arg
)
580 ib_guid_t hca_guid
= *((ib_guid_t
*)cb_arg
);
583 ibdm_hca_list_t
*hca_list
;
585 IBTF_DPRINTF_L4("ibnex", "handle_hca_attach(%llx)", hca_guid
);
587 phci
= ibtl_ibnex_hcaguid2dip(hca_guid
);
590 * Enumerate children of this HCA, port nodes,
591 * VPPA & HCA_SVC nodes. Use ndi_devi_enter() for
592 * locking. IB Nexus is enumerating the children
593 * of HCA, not MPXIO clients.
595 ndi_devi_enter(phci
, &circ
);
596 ibdm_ibnex_port_settle_wait(hca_guid
, ibnex_port_settling_time
);
597 hca_list
= ibdm_ibnex_get_hca_info_by_guid(hca_guid
);
598 if (hca_list
== NULL
) {
599 ndi_devi_exit(phci
, circ
);
600 kmem_free(cb_arg
, sizeof (ib_guid_t
));
603 ibnex_create_hcasvc_nodes(phci
, hca_list
->hl_hca_port_attr
);
604 for (ii
= 0; ii
< hca_list
->hl_nports
; ii
++) {
605 ibnex_create_port_nodes(phci
, &hca_list
->hl_port_attr
[ii
]);
606 ibnex_create_vppa_nodes(phci
, &hca_list
->hl_port_attr
[ii
]);
608 ibdm_ibnex_free_hca_list(hca_list
);
609 ndi_devi_exit(phci
, circ
);
610 kmem_free(cb_arg
, sizeof (ib_guid_t
));