1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
23 */
24
25 /*
26 * Copyright 2023 Oxide Computer Company
27 */
28
29 /*
30 * This file contains support required for IB cfgadm plugin.
31 */
32
33 #include <sys/conf.h>
34 #include <sys/stat.h>
35 #include <sys/modctl.h>
36 #include <sys/ib/mgt/ibdm/ibdm_impl.h>
37 #include <sys/ib/ibnex/ibnex.h>
38 #include <sys/ib/ibnex/ibnex_devctl.h>
39 #include <sys/ib/ibtl/impl/ibtl_ibnex.h>
40 #include <sys/ib/ibtl/impl/ibtl.h>
41 #include <sys/file.h>
42 #include <sys/sunndi.h>
43 #include <sys/fs/dv_node.h>
44 #include <sys/mdi_impldefs.h>
45 #include <sys/sunmdi.h>
46
47 /* return the minimum value of (x) and (y) */
48 #define MIN(x, y) ((x) < (y) ? (x) : (y))
49
50 /*
51 * function prototypes
52 */
53 int ibnex_open(dev_t *, int, int, cred_t *);
54 int ibnex_close(dev_t, int, int, cred_t *);
55 int ibnex_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
56 int ibnex_offline_childdip(dev_info_t *);
57 static int ibnex_get_num_devices(void);
58 static int ibnex_get_snapshot(char **, size_t *, int);
59 static int ibnex_get_commsvcnode_snapshot(nvlist_t **, ib_guid_t,
60 ib_guid_t, int, ib_pkey_t, ibnex_node_type_t);
61 static int ibnex_fill_ioc_tmp(nvlist_t **, ibdm_ioc_info_t *);
62 static int ibnex_fill_nodeinfo(nvlist_t **, ibnex_node_data_t *,
63 void *);
64 static void ibnex_figure_ap_devstate(ibnex_node_data_t *,
65 devctl_ap_state_t *);
66 static void ibnex_figure_ib_apid_devstate(devctl_ap_state_t *);
67 static char *ibnex_get_apid(struct devctl_iocdata *);
68 static int ibnex_get_dip_from_apid(char *, dev_info_t **,
69 ibnex_node_data_t **);
70 extern int ibnex_get_node_and_dip_from_guid(ib_guid_t, int,
71 ib_pkey_t, ibnex_node_data_t **, dev_info_t **);
72 static ibnex_rval_t ibnex_handle_pseudo_configure(char *);
73 static ibnex_rval_t ibnex_handle_ioc_configure(char *);
74 static ibnex_rval_t ibnex_handle_commsvcnode_configure(char *);
75 static void ibnex_return_apid(dev_info_t *, char **);
76 static void ibnex_port_conf_entry_add(char *);
77 static void ibnex_vppa_conf_entry_add(char *);
78 static void ibnex_hcasvc_conf_entry_add(char *);
79 static int ibnex_port_conf_entry_delete(char *, char *);
80 static int ibnex_vppa_conf_entry_delete(char *, char *);
81 static int ibnex_hcasvc_conf_entry_delete(char *, char *);
82
83 static ibnex_rval_t ibnex_ioc_fininode(dev_info_t *, ibnex_ioc_node_t *);
84 static ibnex_rval_t ibnex_commsvc_fininode(dev_info_t *);
85 static ibnex_rval_t ibnex_pseudo_fininode(dev_info_t *);
86
87 static int ibnex_devctl(dev_t, int, intptr_t, int,
88 cred_t *, int *);
89 static int ibnex_ctl_get_api_ver(dev_t, int, intptr_t, int,
90 cred_t *, int *);
91 static int ibnex_ctl_get_hca_list(dev_t, int, intptr_t, int,
92 cred_t *, int *);
93 static int ibnex_ctl_query_hca(dev_t, int, intptr_t, int,
94 cred_t *, int *);
95 static int ibnex_ctl_query_hca_port(dev_t, int, intptr_t, int,
96 cred_t *, int *);
97
98 extern uint64_t ibnex_str2hex(char *, int, int *);
99 extern int ibnex_ioc_initnode_all_pi(ibdm_ioc_info_t *);
100 extern dev_info_t *ibnex_commsvc_initnode(dev_info_t *,
101 ibdm_port_attr_t *, int, int, ib_pkey_t, int *,
102 int);
103 extern int ibnex_get_dip_from_guid(ib_guid_t, int,
104 ib_pkey_t, dev_info_t **);
105 extern void ibnex_reprobe_ioc_dev(void *arg);
106 extern void ibnex_reprobe_ioc_all();
107 extern int ibnex_pseudo_create_all_pi(ibnex_node_data_t *);
108 extern void ibnex_pseudo_initnodes(void);
109
110 extern ibnex_t ibnex;
111
112 /*
113 * ibnex_open()
114 */
115 /* ARGSUSED */
116 int
ibnex_open(dev_t * dev,int flag,int otyp,cred_t * credp)117 ibnex_open(dev_t *dev, int flag, int otyp, cred_t *credp)
118 {
119 IBTF_DPRINTF_L4("ibnex", "\topen");
120 return (0);
121 }
122
123
124 /*
125 * ibnex_close()
126 */
127 /* ARGSUSED */
128 int
ibnex_close(dev_t dev,int flag,int otyp,cred_t * credp)129 ibnex_close(dev_t dev, int flag, int otyp, cred_t *credp)
130 {
131 IBTF_DPRINTF_L4("ibnex", "\tclose");
132 return (0);
133 }
134
135 int
ibnex_ioctl(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * credp,int * rvalp)136 ibnex_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
137 int *rvalp)
138 {
139 /*
140 * For all generic devctl ioctls (such as DEVCTL_AP_CONFIGURE),
141 * call ibnex_devctl().
142 */
143 if (IS_DEVCTL(cmd))
144 return (ibnex_devctl(dev, cmd, arg, mode, credp, rvalp));
145
146 /*
147 * The rest are ibnex specific ioctls.
148 */
149
150 switch (cmd) {
151 case IBNEX_CTL_GET_API_VER:
152 return (ibnex_ctl_get_api_ver(dev, cmd, arg, mode,
153 credp, rvalp));
154
155 case IBNEX_CTL_GET_HCA_LIST:
156 return (ibnex_ctl_get_hca_list(dev, cmd, arg, mode,
157 credp, rvalp));
158
159 case IBNEX_CTL_QUERY_HCA:
160 return (ibnex_ctl_query_hca(dev, cmd, arg, mode,
161 credp, rvalp));
162
163 case IBNEX_CTL_QUERY_HCA_PORT:
164 return (ibnex_ctl_query_hca_port(dev, cmd, arg, mode,
165 credp, rvalp));
166
167 default:
168 return (EINVAL);
169 }
170 }
171
172 /*
173 * ibnex_ioctl()
174 * Ioctl routine for cfgadm controls
175 * DEVCTL_AP_GETSTATE: returns attachment point state
176 * DEVCTL_AP_CONTROL: Does "ibnex" specific ioctls listed below
177 * IBNEX_NUM_DEVICE_NODES Gives how many device nodes exist?
178 * IBNEX_NUM_HCA_NODES Gives how many HCAs exist in the fabric
179 * IBNEX_UPDATE_PKEY_TBLS "-x update_pkey_tbls"
180 * IBNEX_GET_SNAPSHOT Gets the "snapshot" back to user-land
181 * IBNEX_SNAPSHOT_SIZE What is "snapshot" size
182 * IBNEX_DEVICE_PATH_SZ What is device-path size
183 * IBNEX_GET_DEVICE_PATH Gets the device path for Dynamic ap
184 * IBNEX_HCA_LIST_SZ "-x list" option size for the HCA ap_id
185 * IBNEX_HCA_LIST_INFO "-x list" option info for the HCA ap_id
186 * IBNEX_UNCFG_CLNTS_SZ "-x unconfig_client option size"
187 * IBNEX_UNCFG_CLNTS_INFO "-x unconfig_client data"
188 * IBNEX_CONF_ENTRY_ADD: "-x add_service"
189 * IBNEX_CONF_ENTRY_DEL: "-x delete_service"
190 * IBNEX_HCA_VERBOSE_SZ: "-alv hca_apid data size"
191 * IBNEX_HCA_VERBOSE_INFO: "-alv hca_apid actual data"
192 * IBNEX_UPDATE_IOC_CONF "-x update_ioc_conf"
193 * DEVCTL_AP_CONFIGURE: "configure" the attachment point
194 * DEVCTL_AP_UNCONFIGURE: "unconfigure" the attachment point
195 */
196 /* ARGSUSED */
197 static int
ibnex_devctl(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * credp,int * rvalp)198 ibnex_devctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
199 int *rvalp)
200 {
201 int ret, rv = 0, ioc_reprobe_pending = 0;
202 char *snapshot = NULL;
203 char *apid_n = NULL;
204 char *service = NULL;
205 char *devnm = NULL;
206 char *msg;
207 char *guid_str;
208 uint_t num_hcas = 0;
209 size_t snapshot_sz = 0;
210 uint32_t ssiz;
211 uint32_t apid_len;
212 ib_guid_t hca_guid;
213 boolean_t apid_alloced = B_FALSE;
214 dev_info_t *apid_dip = NULL;
215 dev_info_t *pdip;
216 ibnex_rval_t ret_val;
217 ib_service_type_t svc_type = IB_NONE;
218 devctl_ap_state_t ap_state;
219 ibnex_node_data_t *nodep = NULL;
220 ibnex_node_data_t *scanp;
221 struct devctl_iocdata *dcp = NULL;
222
223 IBTF_DPRINTF_L4("ibnex", "\tdevctl: cmd=%x, arg=%p, mode=%x, cred=%p, "
224 "\t\trval=%p dev=0x%x", cmd, arg, mode, credp, rvalp, dev);
225
226 /* read devctl ioctl data */
227 if ((cmd != DEVCTL_AP_CONTROL) &&
228 (ndi_dc_allochdl((void *)arg, &dcp) != NDI_SUCCESS)) {
229 IBTF_DPRINTF_L4("ibnex",
230 "\tdevctl: ndi_dc_allochdl failed\n");
231 return (EFAULT);
232 }
233
234 mutex_enter(&ibnex.ibnex_mutex);
235 switch (cmd) {
236 case DEVCTL_AP_GETSTATE:
237 msg = "\tdevctl: DEVCTL_AP_GETSTATE";
238 IBTF_DPRINTF_L4("ibnex", "%s:", msg);
239
240 apid_n = ibnex_get_apid(dcp);
241 if (*apid_n == '\0') {
242 IBTF_DPRINTF_L2("ibnex",
243 "%s: ibnex_get_apid failed", msg);
244 rv = EIO;
245 break;
246 }
247
248 if (strncmp(apid_n, IBNEX_FABRIC, strlen(IBNEX_FABRIC)) == 0) {
249 ibnex_figure_ib_apid_devstate(&ap_state);
250 apid_dip = ibnex.ibnex_dip;
251 } else {
252 /* if this apid is already seen by IBNEX, get the dip */
253 rv = ibnex_get_dip_from_apid(apid_n, &apid_dip, &nodep);
254 if (rv != IBNEX_DYN_APID) {
255 IBTF_DPRINTF_L2("ibnex",
256 "%s: ibnex_get_dip_from_apid failed", msg);
257 rv = EIO;
258 break;
259 }
260 if (apid_dip)
261 ndi_rele_devi(apid_dip);
262 /* rv could be something undesirable, so reset it */
263 rv = 0;
264
265 ibnex_figure_ap_devstate(nodep, &ap_state);
266 }
267
268 /* copy the return-AP-state information to the user space */
269 if (ndi_dc_return_ap_state(&ap_state, dcp) != NDI_SUCCESS) {
270 IBTF_DPRINTF_L2("ibnex",
271 "%s: ndi_dc_return_ap_state failed", msg);
272 rv = EFAULT;
273 }
274 break;
275
276 case DEVCTL_AP_CONTROL:
277 {
278 int num_nodes = 0;
279 ibnex_ioctl_data_t ioc; /* for 64-bit copies only */
280
281 msg = "\tdevctl: DEVCTL_AP_CONTROL";
282 #ifdef _MULTI_DATAMODEL
283 if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
284 ibnex_ioctl_data_32_t ioc32;
285
286 if (ddi_copyin((void *)arg, &ioc32,
287 sizeof (ioc32), mode) != 0) {
288 IBTF_DPRINTF_L2("ibnex",
289 "%s: ddi_copyin err 1", msg);
290 rv = EFAULT;
291 break;
292 }
293 ioc.cmd = (uint_t)ioc32.cmd;
294 ioc.buf = (caddr_t)(uintptr_t)ioc32.buf;
295 ioc.bufsiz = (uint_t)ioc32.bufsiz;
296 ioc.ap_id = (caddr_t)(uintptr_t)ioc32.ap_id;
297 ioc.ap_id_len = (uint_t)ioc32.ap_id_len;
298 ioc.misc_arg = (uint_t)ioc32.misc_arg;
299 }
300 #else
301 if (ddi_copyin((void *)arg, &ioc, sizeof (ioc),
302 mode) != 0) {
303 IBTF_DPRINTF_L2("ibnex",
304 "%s: ddi_copyin 2 failed", msg);
305 rv = EFAULT;
306 break;
307 }
308 #endif /* _MULTI_DATAMODEL */
309
310 IBTF_DPRINTF_L4("ibnex", "%s: \n\tioc: cmd=%x buf=%p, "
311 "bufsiz=%d", msg, ioc.cmd, ioc.buf, ioc.bufsiz);
312
313 /*
314 * figure out ap_id name as passed from user-land
315 * NOTE: We don't need to figure out ap_id for these
316 * two sub-commands:-
317 * IBNEX_NUM_DEVICE_NODES, IBNEX_NUM_HCA_NODES
318 *
319 * Hence, In user-land, these two ioctls force "ap_id_len" to 0.
320 */
321 if (ioc.ap_id_len > 0) {
322 apid_alloced = B_TRUE;
323 apid_len = ioc.ap_id_len + 1;
324 apid_n = kmem_zalloc(apid_len, KM_SLEEP);
325 if (ddi_copyin((void *)ioc.ap_id, apid_n,
326 ioc.ap_id_len, mode) != 0) {
327 IBTF_DPRINTF_L2("ibnex",
328 "%s: ddi_copyin err 3", msg);
329 rv = EFAULT;
330 break;
331 }
332
333 IBTF_DPRINTF_L3("ibnex", "%s: apid_n= %s", msg, apid_n);
334 }
335
336
337 /* process sub-commands */
338 switch (ioc.cmd) {
339 case IBNEX_NUM_DEVICE_NODES:
340 msg = "\tdevctl: DEVCTL_AP_CONTROL: NUM_DEVICE_NODES";
341
342 /*
343 * figure out how many IOC, VPPA,
344 * Pseudo and Port nodes are present
345 */
346 num_nodes = ibnex_get_num_devices();
347 IBTF_DPRINTF_L4("ibnex", "%s: num_nodes = %d",
348 msg, num_nodes);
349
350 if (ddi_copyout(&num_nodes, ioc.buf,
351 ioc.bufsiz, mode) != 0) {
352 IBTF_DPRINTF_L2("ibnex", "%s: copyout", msg);
353 rv = EIO;
354 }
355 mutex_exit(&ibnex.ibnex_mutex);
356 return (rv);
357
358 case IBNEX_NUM_HCA_NODES:
359 msg = "\tdevctl: DEVCTL_AP_CONTROL: NUM_HCA_NODES";
360
361 /* figure out how many HCAs are present in the host */
362 mutex_exit(&ibnex.ibnex_mutex);
363 num_hcas = ibt_get_hca_list(NULL);
364 IBTF_DPRINTF_L4("ibnex", "%s: num %d", msg, num_hcas);
365
366 if (ddi_copyout(&num_hcas, ioc.buf,
367 ioc.bufsiz, mode) != 0) {
368 IBTF_DPRINTF_L2("ibnex", "%s: copyout", msg);
369 rv = EIO;
370 }
371 return (rv);
372
373 case IBNEX_UPDATE_PKEY_TBLS:
374 msg = "\tdevctl: DEVCTL_AP_CONTROL: UPDATE_PKEY_TBLS";
375 IBTF_DPRINTF_L4("ibnex", "%s", msg);
376
377 /*
378 * update P_Key tables:
379 * ibdm_ibnex_update_pkey_tbls() calls
380 * ibt_query_hca_ports_byguids() for all the
381 * HCAs that the IBDM has "seen" in the system.
382 * This ends up updating the IBTL P_Key database.
383 * NOTE: Changes in this area will break this
384 * assumption. Initially the plan was to call
385 * ibt_query_hca_ports_byguids() in IBTL but
386 * IBDM needs to call it as well. So, eliminating
387 * the first invocation.
388 *
389 * It next updates the DM P_Key database.
390 * Note that the DM P_Key database updating
391 * will always be driven through cfgadm.
392 */
393 mutex_exit(&ibnex.ibnex_mutex);
394 ibdm_ibnex_update_pkey_tbls();
395 mutex_enter(&ibnex.ibnex_mutex);
396 break;
397
398 case IBNEX_GET_SNAPSHOT:
399 case IBNEX_SNAPSHOT_SIZE:
400 msg = (ioc.cmd == IBNEX_SNAPSHOT_SIZE) ?
401 "\tdevctl: DEVCTL_AP_CONTROL: IBNEX_SNAPSHOT_SIZE" :
402 "\tdevctl: DEVCTL_AP_CONTROL: IBNEX_GET_SNAPSHOT";
403
404 IBTF_DPRINTF_L4("ibnex", "%s:", msg);
405
406 if (ibnex_get_snapshot(&snapshot, &snapshot_sz,
407 ioc.misc_arg) != 0) {
408 IBTF_DPRINTF_L2("ibnex",
409 "%s:\n\tibnex_get_snapshot failed", msg);
410 rv = EIO;
411 break;
412 }
413
414 /* ssiz needs to be reinitialized again */
415 ssiz = snapshot_sz;
416 IBTF_DPRINTF_L4("ibnex",
417 "%s:\n\tsize =%x", msg, snapshot_sz);
418
419 if (ioc.cmd == IBNEX_SNAPSHOT_SIZE) {
420 if (ddi_copyout(&ssiz, ioc.buf,
421 ioc.bufsiz, mode) != 0) {
422 IBTF_DPRINTF_L2("ibnex",
423 "%s:\n\tddi_copyout 2 failed", msg);
424 rv = EFAULT;
425 }
426
427 } else {
428 if (ioc.bufsiz != snapshot_sz) {
429 IBTF_DPRINTF_L2("ibnex",
430 "%s:\n\tinvalid buffer size (%x %x)"
431 " ", msg, ioc.bufsiz, snapshot_sz);
432 rv = EINVAL;
433
434 } else if (ddi_copyout(snapshot, ioc.buf,
435 ioc.bufsiz, mode) != 0) {
436 IBTF_DPRINTF_L2("ibnex",
437 "%s:\n\tddi_copyout 3 failed", msg);
438 rv = EFAULT;
439 }
440 }
441
442 kmem_free(snapshot, snapshot_sz);
443 break;
444
445 case IBNEX_DEVICE_PATH_SZ:
446 case IBNEX_GET_DEVICE_PATH:
447 {
448 char path[MAXPATHLEN];
449
450 msg = (ioc.cmd == IBNEX_DEVICE_PATH_SZ) ?
451 "\tdevctl:DEVCTL_AP_CONTROL: IBNEX_DEVICE_PATH_SZ" :
452 "\tdevctl:DEVCTL_AP_CONTROL: IBNEX_GET_DEVICE_PATH";
453
454 IBTF_DPRINTF_L4("ibnex", "%s: apid = %s", msg, apid_n);
455
456 /* if this apid is already seen by IBNEX, get the dip */
457 rv = ibnex_get_dip_from_apid(apid_n, &apid_dip, &nodep);
458 if (rv != IBNEX_DYN_APID || apid_dip == NULL) {
459 IBTF_DPRINTF_L2("ibnex",
460 "%s:\n\tget_dip_from_apid failed", msg);
461 rv = EIO;
462 break;
463 }
464 ndi_rele_devi(apid_dip);
465
466 /* ddi_pathname doesn't supply /devices, so we do. */
467 (void) strcpy(path, "/devices");
468 (void) ddi_pathname(apid_dip, path + strlen(path));
469 ssiz = (uint32_t)strlen(path) + 1;
470 IBTF_DPRINTF_L4("ibnex",
471 "%s: len = %x\n\tpath = %s", msg, ssiz, path);
472
473 /* rv could be something undesirable, so reset it */
474 rv = 0;
475
476 if (ioc.cmd == IBNEX_DEVICE_PATH_SZ) {
477 if (ddi_copyout(&ssiz, ioc.buf,
478 ioc.bufsiz, mode) != 0) {
479 IBTF_DPRINTF_L2("ibnex",
480 "%s: ddi_copyout 4 failed", msg);
481 rv = EFAULT;
482 }
483
484 } else {
485 if (ioc.bufsiz != ssiz) {
486 IBTF_DPRINTF_L2("ibnex",
487 "%s: invalid size (%x, %x)",
488 msg, ioc.bufsiz, ssiz);
489 rv = EINVAL;
490 } else if (ddi_copyout(&path, ioc.buf,
491 ioc.bufsiz, mode) != 0) {
492 IBTF_DPRINTF_L2("ibnex", "%s "
493 "ddi_copyout 5 failed", msg);
494 rv = EFAULT;
495 }
496 }
497 break;
498 }
499
500 case IBNEX_HCA_LIST_SZ:
501 case IBNEX_HCA_LIST_INFO:
502 msg = (ioc.cmd == IBNEX_HCA_LIST_SZ) ?
503 "DEVCTL_AP_CONTROL: IBNEX_HCA_LIST_SZ" :
504 "DEVCTL_AP_CONTROL: IBNEX_HCA_LIST_INFO";
505
506 guid_str = strrchr(apid_n, ':') + 1;
507 IBTF_DPRINTF_L4("ibnex", "%s, input apid = %s, "
508 "guid = %s", msg, apid_n, guid_str);
509
510 if (guid_str == NULL) {
511 IBTF_DPRINTF_L2("ibnex", "%s: invalid input "
512 "GUID passed %s", msg, guid_str);
513 rv = EFAULT;
514 break;
515 }
516
517 /* Get the GUID(hex value) from apid_n */
518 hca_guid = ibnex_str2hex(guid_str, strlen(guid_str),
519 &ret);
520 if (ret != IBNEX_SUCCESS) {
521 IBTF_DPRINTF_L2("ibnex", "%s: Invalid HCA "
522 "GUID string", msg);
523 rv = EIO;
524 break;
525 }
526 IBTF_DPRINTF_L4("ibnex", "%s HCA GUID = %llX",
527 msg, hca_guid);
528 if (ibtl_ibnex_get_hca_info(hca_guid,
529 IBTL_IBNEX_LIST_CLNTS_FLAG, &snapshot, &snapshot_sz,
530 ibnex_return_apid) != IBT_SUCCESS) {
531 IBTF_DPRINTF_L2("ibnex",
532 "%s: get HCA consumers failed", msg);
533 rv = EIO;
534 break;
535 }
536
537 ssiz = snapshot_sz;
538 IBTF_DPRINTF_L4("ibnex", "%s: size =%x", msg, ssiz);
539
540 if (ioc.cmd == IBNEX_HCA_LIST_SZ) {
541 if (ddi_copyout(&ssiz, ioc.buf,
542 ioc.bufsiz, mode) != 0) {
543 IBTF_DPRINTF_L2("ibnex",
544 "%s: ddi_copyout 6 failed", msg);
545 rv = EFAULT;
546 }
547 } else {
548 if (ioc.bufsiz != ssiz) {
549 IBTF_DPRINTF_L2("ibnex", "%s: invalid "
550 "size (%x, %x)", msg, ioc.bufsiz,
551 ssiz);
552 rv = EINVAL;
553 } else if (ddi_copyout(snapshot, ioc.buf,
554 ioc.bufsiz, mode) != 0) {
555 IBTF_DPRINTF_L2("ibnex", "%s "
556 "ddi_copyout 7 failed", msg);
557 rv = EFAULT;
558 }
559 }
560
561 kmem_free(snapshot, snapshot_sz);
562 break;
563
564 case IBNEX_UNCFG_CLNTS_SZ:
565 case IBNEX_UNCFG_CLNTS_INFO:
566 msg = (ioc.cmd == IBNEX_UNCFG_CLNTS_SZ) ?
567 "\tdevctl:DEVCTL_AP_CONTROL: IBNEX_UNCFG_CLNTS_SZ" :
568 "\tdevctl:DEVCTL_AP_CONTROL: "
569 "IBNEX_UNCFG_CLNTS_INFO";
570
571 guid_str = strrchr(apid_n, ':') + 1;
572 IBTF_DPRINTF_L4("ibnex", "%s, apid = %s, guid = %s",
573 msg, apid_n, guid_str);
574
575 if (guid_str == NULL) {
576 IBTF_DPRINTF_L2("ibnex", "%s: invalid input "
577 "GUID %s", msg, guid_str);
578 rv = EFAULT;
579 break;
580 }
581
582 /* Get the GUID(hex value) from apid_n */
583 hca_guid = ibnex_str2hex(guid_str, strlen(guid_str),
584 &ret);
585 if (ret != IBNEX_SUCCESS) {
586 IBTF_DPRINTF_L2("ibnex", "%s: Invalid HCA "
587 "GUID string passed", msg);
588 rv = EIO;
589 break;
590 }
591 IBTF_DPRINTF_L4("ibnex", "%s G = %llX", msg, hca_guid);
592 if (ibtl_ibnex_get_hca_info(hca_guid,
593 IBTL_IBNEX_UNCFG_CLNTS_FLAG, &snapshot,
594 &snapshot_sz, ibnex_return_apid) != IBT_SUCCESS) {
595 IBTF_DPRINTF_L2("ibnex",
596 "%s: get HCA consumers failed", msg);
597 rv = EIO;
598 break;
599 }
600 /* ssiz needs to be reinitialized again */
601 ssiz = snapshot_sz;
602
603 IBTF_DPRINTF_L4("ibnex", "%s: size =%x", msg, ssiz);
604
605 if (ioc.cmd == IBNEX_UNCFG_CLNTS_SZ) {
606 if (ddi_copyout(&ssiz, ioc.buf,
607 ioc.bufsiz, mode) != 0) {
608 IBTF_DPRINTF_L2("ibnex",
609 "%s: ddi_copyout 9 failed", msg);
610 rv = EFAULT;
611 }
612
613 } else {
614 if (ioc.bufsiz != ssiz) {
615 IBTF_DPRINTF_L2("ibnex",
616 "%s: invalid size (%x, %x)",
617 msg, ioc.bufsiz, ssiz);
618 rv = EINVAL;
619 } else if (ddi_copyout(snapshot, ioc.buf,
620 ioc.bufsiz, mode) != 0) {
621 IBTF_DPRINTF_L2("ibnex", "%s "
622 "ddi_copyout 10 failed", msg);
623 rv = EFAULT;
624 }
625 }
626
627 kmem_free(snapshot, snapshot_sz);
628 break;
629
630 case IBNEX_CONF_ENTRY_ADD:
631 msg = "\tdevctl: IBNEX_CONF_ENTRY_ADD: ";
632 service = kmem_zalloc(ioc.bufsiz + 1, KM_SLEEP);
633 /* read in the "service" name */
634 if (ddi_copyin(ioc.buf, service,
635 ioc.bufsiz, mode) != 0) {
636 IBTF_DPRINTF_L2("ibnex", "%s: ddi_copyin err 6",
637 msg);
638 rv = EFAULT;
639 break;
640 }
641
642 /* read in the "service type" */
643 svc_type = ioc.misc_arg;
644 IBTF_DPRINTF_L4("ibnex", "%s: service = %s, type = %d",
645 msg, service, svc_type);
646
647 if (svc_type == IB_PORT_SERVICE) {
648 ibnex_port_conf_entry_add(service);
649 } else if (svc_type == IB_VPPA_SERVICE) {
650 ibnex_vppa_conf_entry_add(service);
651 } else if (svc_type == IB_HCASVC_SERVICE) {
652 ibnex_hcasvc_conf_entry_add(service);
653 }
654 kmem_free(service, ioc.bufsiz + 1);
655 break;
656
657 case IBNEX_CONF_ENTRY_DEL:
658 msg = "\tdevctl:IBNEX_CONF_ENTRY_DEL: ";
659 service = kmem_zalloc(ioc.bufsiz + 1, KM_SLEEP);
660 /* read in the "service" name */
661 if (ddi_copyin(ioc.buf, service,
662 ioc.bufsiz, mode) != 0) {
663 IBTF_DPRINTF_L2("ibnex", "%s: ddi_copyin err 7",
664 msg);
665 rv = EFAULT;
666 break;
667 }
668
669 /* read in the "service type" */
670 svc_type = ioc.misc_arg;
671 IBTF_DPRINTF_L4("ibnex", "%s: service = %s, type = %d",
672 msg, service, svc_type);
673
674 if (svc_type == IB_PORT_SERVICE) {
675 rv = ibnex_port_conf_entry_delete(msg, service);
676 } else if (svc_type == IB_VPPA_SERVICE) {
677 rv = ibnex_vppa_conf_entry_delete(msg, service);
678 } else if (svc_type == IB_HCASVC_SERVICE) {
679 rv = ibnex_hcasvc_conf_entry_delete(msg,
680 service);
681 }
682 kmem_free(service, ioc.bufsiz + 1);
683 break;
684
685 case IBNEX_HCA_VERBOSE_SZ:
686 case IBNEX_HCA_VERBOSE_INFO:
687 msg = (ioc.cmd == IBNEX_HCA_VERBOSE_SZ) ?
688 "DEVCTL_AP_CONTROL: IBNEX_HCA_VERBOSE_SZ" :
689 "DEVCTL_AP_CONTROL: IBNEX_HCA_VERBOSE_INFO";
690
691 guid_str = strrchr(apid_n, ':') + 1;
692 IBTF_DPRINTF_L4("ibnex", "%s, apid = %s, guid = %s",
693 msg, apid_n, guid_str);
694
695 if (guid_str == NULL) {
696 IBTF_DPRINTF_L2("ibnex", "%s: invalid GUID %s",
697 msg, guid_str);
698 rv = EFAULT;
699 break;
700 }
701
702 /* Get the GUID(hex value) from apid_n */
703 hca_guid = ibnex_str2hex(guid_str, strlen(guid_str),
704 &ret);
705 if (ret != IBNEX_SUCCESS) {
706 IBTF_DPRINTF_L2("ibnex", "%s: Invalid HCA GUID "
707 "string", msg);
708 rv = EIO;
709 break;
710 }
711 IBTF_DPRINTF_L4("ibnex", "%s HCA GUID = 0x%llX",
712 msg, hca_guid);
713
714 if (ibtl_ibnex_get_hca_verbose_data(hca_guid, &snapshot,
715 &snapshot_sz) != IBT_SUCCESS) {
716 IBTF_DPRINTF_L2("ibnex", "%s: get HCA verbose "
717 "data failed", msg);
718 rv = EIO;
719 break;
720 }
721
722 ssiz = snapshot_sz;
723 IBTF_DPRINTF_L4("ibnex", "%s: size =%x", msg, ssiz);
724
725 if (ioc.cmd == IBNEX_HCA_VERBOSE_SZ) {
726 if (ddi_copyout(&ssiz, ioc.buf,
727 ioc.bufsiz, mode) != 0) {
728 IBTF_DPRINTF_L2("ibnex",
729 "%s: ddi_copyout 11 failed", msg);
730 rv = EFAULT;
731 }
732 } else {
733 if (ioc.bufsiz != ssiz) {
734 IBTF_DPRINTF_L2("ibnex",
735 "%s: invalid size (%x, %x)",
736 msg, ioc.bufsiz, ssiz);
737 rv = EINVAL;
738 } else if (ddi_copyout(snapshot,
739 ioc.buf, ioc.bufsiz, mode) != 0) {
740 IBTF_DPRINTF_L2("ibnex", "%s "
741 "ddi_copyout 12 failed", msg);
742 rv = EFAULT;
743 }
744 }
745
746 kmem_free(snapshot, snapshot_sz);
747 break;
748
749 case IBNEX_UPDATE_IOC_CONF :
750 msg = "\tdevctl:IBNEX_UPDATE_IOC_CONF: ";
751
752 /*
753 * If IB fabric APID, call ibnex_update_all
754 * If IOC APID, get the apid dip and call
755 * ibnex_update_ioc
756 */
757 if (ioc.misc_arg == IBNEX_BASE_APID) {
758 /*
759 * If reprobe is in progress or another reprobe
760 * is already waiting, wait.
761 */
762 if (ibnex.ibnex_reprobe_state != 0) {
763 if (ibnex.ibnex_reprobe_state ==
764 IBNEX_REPROBE_ALL_PROGRESS)
765 ibnex.ibnex_reprobe_state =
766 IBNEX_REPROBE_ALL_WAIT;
767 while (ibnex.ibnex_reprobe_state) {
768 cv_wait(&ibnex.ibnex_reprobe_cv,
769 &ibnex.ibnex_mutex);
770 }
771
772 /*
773 * Pending reprobe all completed, return
774 */
775 break;
776 }
777
778 /* Check if reprobe for any IOC is pending */
779 /* CONSTCOND */
780 while (1) {
781 ioc_reprobe_pending = 0;
782 for (scanp = ibnex.ibnex_ioc_node_head;
783 scanp;
784 scanp = scanp->node_next) {
785 if (scanp->node_reprobe_state
786 != 0) {
787 ioc_reprobe_pending =
788 1;
789 break;
790 }
791 }
792 if (ioc_reprobe_pending == 0) {
793 ibnex.ibnex_reprobe_state &=
794 ~IBNEX_REPROBE_IOC_WAIT;
795 break;
796 }
797
798 ibnex.ibnex_reprobe_state =
799 IBNEX_REPROBE_IOC_WAIT;
800 cv_wait(&ibnex.ibnex_reprobe_cv,
801 &ibnex.ibnex_mutex);
802 }
803
804 /*
805 * Set the REPROBE_ALL_PROGRESS state &
806 * start reprobe
807 */
808 ibnex.ibnex_reprobe_state =
809 IBNEX_REPROBE_ALL_PROGRESS;
810 mutex_exit(&ibnex.ibnex_mutex);
811 ibnex_reprobe_ioc_all();
812 mutex_enter(&ibnex.ibnex_mutex);
813 } else if (ioc.misc_arg == IBNEX_DYN_APID) {
814 rv = ibnex_get_dip_from_apid(apid_n, &apid_dip,
815 &nodep);
816 ASSERT(rv == IBNEX_DYN_APID);
817
818 /* Device unconfigured: return */
819 if (apid_dip == NULL)
820 break;
821
822 ndi_rele_devi(apid_dip);
823 /* Reset return value back to 0 */
824 rv = 0;
825 if (ibnex.ibnex_reprobe_state != 0 ||
826 nodep->node_reprobe_state != 0) {
827 while (ibnex.ibnex_reprobe_state != 0 &&
828 nodep->node_reprobe_state != 0) {
829 cv_wait(&ibnex.ibnex_reprobe_cv,
830 &ibnex.ibnex_mutex);
831 }
832 /* Pending reprobe completed, return */
833 break;
834 }
835
836 /* Set node_reprobe_state and start reprobe */
837 nodep->node_reprobe_state =
838 IBNEX_NODE_REPROBE_NOTIFY_ON_UPDATE;
839 mutex_exit(&ibnex.ibnex_mutex);
840 ibnex_reprobe_ioc_dev((void *)apid_dip);
841 mutex_enter(&ibnex.ibnex_mutex);
842 } else {
843 rv = EINVAL;
844 }
845
846 break;
847
848 default:
849 IBTF_DPRINTF_L2("ibnex",
850 "DEVCTL_AP_CONTROL: ioc:unknown cmd = %x", ioc.cmd);
851 break;
852 }
853 }
854 break;
855
856 case DEVCTL_AP_UNCONFIGURE:
857 msg = "DEVCTL_AP_UNCONFIGURE";
858 IBTF_DPRINTF_L4("ibnex", "%s", msg);
859
860 /* Check for write permissions */
861 if (!(mode & FWRITE)) {
862 IBTF_DPRINTF_L2("ibnex", "%s: invalid mode %x",
863 msg, mode);
864 rv = EPERM;
865 break;
866 }
867
868 if ((apid_n = ibnex_get_apid(dcp)) == NULL) {
869 IBTF_DPRINTF_L2("ibnex",
870 "%s: ibnex_get_apid failed", msg);
871 rv = EIO;
872 break;
873 }
874
875 /*
876 * If this apid is already seen by IBNEX, get the dip
877 * NOTE: ibnex_get_dip_from_apid() finds a valid dip
878 * and also does a ndi_devi_hold() on the child.
879 */
880 rv = ibnex_get_dip_from_apid(apid_n, &apid_dip, &nodep);
881 if ((rv != IBNEX_DYN_APID) || (apid_dip == NULL)) {
882 IBTF_DPRINTF_L2("ibnex", "%s: get_dip_from_apid "
883 "failed with 0x%x", msg, rv);
884 rv = EIO;
885 break;
886 }
887 IBTF_DPRINTF_L4("ibnex", "%s: DIP = %p", msg, apid_dip);
888
889 /* Check if it is a valid node type? */
890 if (!IBNEX_VALID_NODE_TYPE(nodep)) {
891 IBTF_DPRINTF_L2("ibnex", "%s: invalid IB node", msg);
892 rv = ENODEV;
893 ndi_rele_devi(apid_dip);
894 break;
895 }
896
897 /*
898 * continue unconfigure operation, only if device node
899 * is already configured. Return EBUSY if another
900 * configure/unconfigure operation is in progress.
901 */
902 if (nodep->node_state == IBNEX_CFGADM_CONFIGURING ||
903 nodep->node_state == IBNEX_CFGADM_UNCONFIGURING) {
904 rv = EBUSY;
905 ndi_rele_devi(apid_dip);
906 break;
907 }
908
909 /* do this before to avoid races */
910 nodep->node_dip = NULL;
911 nodep->node_state = IBNEX_CFGADM_UNCONFIGURING;
912
913 /*
914 * Call devfs_clean first
915 * NOTE: The code so far is protected by holding ibnex_mutex
916 * and by doing a ndi_devi_hold() on the child.
917 */
918 pdip = ddi_get_parent(apid_dip);
919 if (i_ddi_node_state(apid_dip) >= DS_INITIALIZED) {
920 devnm = kmem_alloc(MAXNAMELEN + 1, KM_SLEEP);
921 (void) ddi_deviname(apid_dip, devnm);
922 mutex_exit(&ibnex.ibnex_mutex);
923 (void) devfs_clean(pdip, devnm + 1, DV_CLEAN_FORCE);
924 mutex_enter(&ibnex.ibnex_mutex);
925 kmem_free(devnm, MAXNAMELEN + 1);
926 }
927
928 mutex_exit(&ibnex.ibnex_mutex);
929 ndi_devi_enter(pdip);
930 ndi_rele_devi(apid_dip);
931 mutex_enter(&ibnex.ibnex_mutex);
932
933 /* unconfigure the Port/VPPA/HCA_SVC node */
934 if (IBNEX_COMMSVC_NODE_TYPE(nodep)) {
935 ret_val = ibnex_commsvc_fininode(apid_dip);
936 } else if (nodep->node_type == IBNEX_IOC_NODE) {
937 /* unconfigure the IOC node */
938 ret_val = ibnex_ioc_fininode(apid_dip,
939 &nodep->node_data.ioc_node);
940 } else if (nodep->node_type == IBNEX_PSEUDO_NODE) {
941 /* unconfigure the pseudo node */
942 ret_val = ibnex_pseudo_fininode(apid_dip);
943 }
944
945 /* reset upon failure */
946 if (ret_val != IBNEX_SUCCESS) {
947 nodep->node_dip = apid_dip;
948 nodep->node_state = IBNEX_CFGADM_CONFIGURED;
949 } else {
950 nodep->node_state = IBNEX_CFGADM_UNCONFIGURED;
951 nodep->node_ap_state = IBNEX_NODE_AP_UNCONFIGURED;
952 }
953
954 rv = (ret_val != IBNEX_SUCCESS) ? EIO : 0;
955 ndi_devi_exit(pdip);
956 IBTF_DPRINTF_L2("ibnex", "%s: DONE !! It %s", msg,
957 rv ? "failed" : "succeeded");
958 break;
959
960 case DEVCTL_AP_CONFIGURE:
961 msg = "DEVCTL_AP_CONFIGURE";
962 IBTF_DPRINTF_L4("ibnex", "%s", msg);
963 mutex_exit(&ibnex.ibnex_mutex);
964 ndi_devi_enter(ibnex.ibnex_dip);
965 mutex_enter(&ibnex.ibnex_mutex);
966
967 /* Check for write permissions */
968 if (!(mode & FWRITE)) {
969 IBTF_DPRINTF_L2("ibnex", "%s: invalid mode %x",
970 msg, mode);
971 rv = EPERM;
972 ndi_devi_exit(ibnex.ibnex_dip);
973 break;
974 }
975
976 if ((apid_n = ibnex_get_apid(dcp)) == NULL) {
977 IBTF_DPRINTF_L2("ibnex",
978 "%s: ibnex_get_apid failed", msg);
979 rv = EIO;
980 ndi_devi_exit(ibnex.ibnex_dip);
981 break;
982 }
983
984 /*
985 * Let's get the node if it already exists.
986 * NOTE: ibnex_get_dip_from_apid() finds a valid dip
987 * and also does a ndi_devi_hold() on the child.
988 */
989 nodep = NULL;
990 ret_val = ibnex_get_dip_from_apid(apid_n, &apid_dip, &nodep);
991 /*
992 * We need the node_data but not the dip. If we get a dip for
993 * this apid, it means it's already configured. We need to
994 * return.
995 */
996 if (apid_dip != NULL) {
997 ndi_rele_devi(apid_dip);
998 ndi_devi_exit(ibnex.ibnex_dip);
999 rv = 0;
1000 break;
1001 }
1002
1003 /*
1004 * A node exits for this apid but not a dip. So we must have
1005 * unconfigured it earlier. Set the node_ap_state to configuring
1006 * to allow configure operation.
1007 */
1008 if (nodep != NULL) {
1009 nodep->node_ap_state = IBNEX_NODE_AP_CONFIGURING;
1010 }
1011
1012
1013 /*
1014 * Five types of APIDs are supported:
1015 * o HCA_GUID,0,service-name (HCA-SVC device)
1016 * o IOC_GUID (IOC device)
1017 * o PORT_GUID,0,service-name (Port device)
1018 * o pseudo_name,unit-address, (Pseudo device)
1019 * o PORT_GUID,P_Key,service-name (VPPA device)
1020 * If the apid doesn't have "," then treat it as an IOC
1021 * If the apid has one "," then it is Pseudo device
1022 * If the apid has 2 ","s then it is one of the
1023 * Port,VPPA,HCA_SVC devices
1024 */
1025 if (strrchr(apid_n, ',') == NULL) {
1026 ret_val = ibnex_handle_ioc_configure(apid_n);
1027 } else {
1028 char *first = strchr(apid_n, ',');
1029 char *second;
1030
1031 second = first ? strchr(first + 1, ',') : NULL;
1032 if (first != NULL && second == NULL) {
1033 ret_val = ibnex_handle_pseudo_configure(apid_n);
1034 } else if (first != NULL && second != NULL) {
1035 ret_val = ibnex_handle_commsvcnode_configure(
1036 apid_n);
1037 }
1038 } /* end of else */
1039
1040 if (ret_val != IBNEX_SUCCESS) {
1041 rv = (ret_val == IBNEX_BUSY) ? EBUSY : EIO;
1042 } else {
1043 /*
1044 * Get the newly created node and set the state to
1045 * IBNEX_NODE_AP_CONFIGURED.
1046 * NOTE: ibnex_get_dip_from_apid() finds a valid dip
1047 * and also does a ndi_devi_hold() on the child.
1048 */
1049 if (!nodep)
1050 ret_val = ibnex_get_dip_from_apid(apid_n,
1051 &apid_dip, &nodep);
1052 if (nodep != NULL) {
1053 nodep->node_ap_state = IBNEX_NODE_AP_CONFIGURED;
1054 }
1055 if (apid_dip != NULL) {
1056 ndi_rele_devi(apid_dip);
1057 }
1058 }
1059 IBTF_DPRINTF_L2("ibnex", "%s: DONE !! It %s", msg,
1060 rv ? "failed" : "succeeded");
1061 ndi_devi_exit(ibnex.ibnex_dip);
1062 break;
1063
1064 default:
1065 rv = EIO;
1066 break;
1067 }
1068 mutex_exit(&ibnex.ibnex_mutex);
1069
1070 if ((apid_alloced == B_TRUE) && (apid_n != NULL)) {
1071 kmem_free(apid_n, apid_len);
1072 }
1073
1074 if (dcp) {
1075 ndi_dc_freehdl(dcp);
1076 }
1077 return (rv);
1078 }
1079
1080
1081 /*
1082 * ibnex_get_num_devices()
1083 * Figure out how many IOC, VPPA, Pseudo, HCA_SVC and Port devices exist
1084 */
1085 static int
ibnex_get_num_devices(void)1086 ibnex_get_num_devices(void)
1087 {
1088 int j, k, l, hca_count;
1089 int num_nodes = 0;
1090 ibdm_hca_list_t *hca_list, *hcap;
1091 ibdm_port_attr_t *pattr;
1092 ibnex_node_data_t *nodep;
1093
1094 ASSERT(mutex_owned(&ibnex.ibnex_mutex));
1095
1096 /* Get a count of HCAs, first. */
1097 mutex_exit(&ibnex.ibnex_mutex);
1098 ibdm_ibnex_get_hca_list(&hca_list, &hca_count);
1099 mutex_enter(&ibnex.ibnex_mutex);
1100 for (hcap = hca_list; hca_list != NULL; hca_list = hca_list->hl_next) {
1101 for (j = 0; j < ibnex.ibnex_nhcasvc_comm_svcs; j++)
1102 num_nodes++;
1103 for (j = 0; j < hca_list->hl_nports; j++) {
1104 for (k = 0; k < ibnex.ibnex_num_comm_svcs; k++)
1105 num_nodes++;
1106
1107 pattr = &hca_list->hl_port_attr[j];
1108 for (k = 0; k < pattr->pa_npkeys; k++) {
1109 if (IBNEX_INVALID_PKEY(pattr->pa_pkey_tbl[k].
1110 pt_pkey))
1111 continue;
1112
1113 for (l = 0; l < ibnex.ibnex_nvppa_comm_svcs;
1114 l++, ++num_nodes)
1115 ;
1116 } /* end of pa_npkeys */
1117 } /* end of hl_nports */
1118 } /* end of hca_list != NULL */
1119 if (hcap)
1120 ibdm_ibnex_free_hca_list(hcap);
1121
1122 /*
1123 * Now figure out how many IOC nodes are present.
1124 * Add count of configured "diconnected" IOCs
1125 */
1126 mutex_exit(&ibnex.ibnex_mutex);
1127 num_nodes += ibdm_ibnex_get_ioc_count();
1128 mutex_enter(&ibnex.ibnex_mutex);
1129 num_nodes += ibnex.ibnex_num_disconnect_iocs;
1130
1131 /* Last: figure out how many Pseudo nodes are present. */
1132 for (nodep = ibnex.ibnex_pseudo_node_head; nodep;
1133 nodep = nodep->node_next) {
1134 if (nodep->node_data.pseudo_node.pseudo_merge_node == 1)
1135 continue;
1136
1137 num_nodes++;
1138 }
1139 return (num_nodes);
1140 }
1141
1142
1143 /*
1144 * ibnex_get_snapshot()
1145 * Get a snapshot of all Port/IOC/VPPA/HCA_SVC/Pseudo nodes
1146 * Snapshot includes IBNEX_NODE_INFO_NVL, IBNEX_NODE_TYPE_NVL,
1147 * IBNEX_NODE_RSTATE_NVL, IBNEX_NODE_OSTATE_NVL and
1148 * IBNEX_NODE_COND_NVL
1149 */
1150 static int
ibnex_get_snapshot(char ** buf,size_t * sz,int allow_probe)1151 ibnex_get_snapshot(char **buf, size_t *sz, int allow_probe)
1152 {
1153 int i, j, k, l, hca_count;
1154 nvlist_t *nvl;
1155 ib_pkey_t pkey;
1156 boolean_t found;
1157 ibdm_ioc_info_t *ioc_listp;
1158 ibdm_ioc_info_t *iocp;
1159 ibdm_hca_list_t *hca_list, *hcap;
1160 ibdm_port_attr_t *port_attr;
1161 ibnex_node_data_t *nodep;
1162
1163 ASSERT(mutex_owned(&ibnex.ibnex_mutex));
1164
1165 *buf = NULL;
1166 *sz = 0;
1167
1168 if (!ibnex.ibnex_pseudo_inited) {
1169 mutex_exit(&ibnex.ibnex_mutex);
1170 ibnex_pseudo_initnodes();
1171 mutex_enter(&ibnex.ibnex_mutex);
1172 ibnex.ibnex_pseudo_inited = 1;
1173 }
1174
1175 /* First, Port/VPPA/HCA_SVC nodes */
1176 mutex_exit(&ibnex.ibnex_mutex);
1177 ibdm_ibnex_get_hca_list(&hca_list, &hca_count);
1178 mutex_enter(&ibnex.ibnex_mutex);
1179
1180 (void) nvlist_alloc(&nvl, 0, KM_SLEEP);
1181
1182 /* Go thru all the ports of all the HCAs and all the port-svc indices */
1183 for (hcap = hca_list, i = 0; i < hca_count;
1184 hca_list = hca_list->hl_next, i++) {
1185
1186 IBTF_DPRINTF_L4("ibnex", "ibnex_get_snapshot: "
1187 "fill in COMM service HCA_SVC nodes");
1188 port_attr = hca_list->hl_hca_port_attr;
1189 for (j = 0; j < ibnex.ibnex_nhcasvc_comm_svcs; j++) {
1190 if (ibnex_get_commsvcnode_snapshot(&nvl,
1191 port_attr->pa_hca_guid,
1192 port_attr->pa_hca_guid, j, (ib_pkey_t)0,
1193 IBNEX_HCASVC_COMMSVC_NODE) != 0) {
1194 IBTF_DPRINTF_L2("ibnex",
1195 "ibnex_get_snapshot: failed to fill"
1196 " HCA_SVC device (%x %x)", i, j);
1197 ibdm_ibnex_free_hca_list(hcap);
1198 nvlist_free(nvl);
1199 return (-1);
1200 }
1201
1202 }
1203
1204 for (j = 0; j < hca_list->hl_nports; j++) {
1205 port_attr = &hca_list->hl_port_attr[j];
1206
1207 IBTF_DPRINTF_L4("ibnex", "ibnex_get_snapshot: "
1208 "fill in COMM service Port nodes");
1209 for (k = 0; k < ibnex.ibnex_num_comm_svcs; k++) {
1210
1211 if (ibnex_get_commsvcnode_snapshot(&nvl,
1212 port_attr->pa_hca_guid,
1213 port_attr->pa_port_guid, k, (ib_pkey_t)0,
1214 IBNEX_PORT_COMMSVC_NODE) != 0) {
1215 IBTF_DPRINTF_L2("ibnex",
1216 "ibnex_get_snapshot: failed to fill"
1217 " Port device (%x %x %x)", i, j, k);
1218 ibdm_ibnex_free_hca_list(hcap);
1219 nvlist_free(nvl);
1220 return (-1);
1221 }
1222
1223 } /* end of num_comm_svcs for loop */
1224
1225 IBTF_DPRINTF_L4("ibnex", "ibnex_get_snapshot: "
1226 "fill in VPPA service port nodes");
1227 for (l = 0; l < port_attr->pa_npkeys; l++) {
1228 pkey = port_attr->pa_pkey_tbl[l].pt_pkey;
1229 if (IBNEX_INVALID_PKEY(pkey))
1230 continue;
1231
1232 for (k = 0; k < ibnex.ibnex_nvppa_comm_svcs;
1233 k++) {
1234
1235 if (ibnex_get_commsvcnode_snapshot(&nvl,
1236 port_attr->pa_hca_guid,
1237 port_attr->pa_port_guid, k, pkey,
1238 IBNEX_VPPA_COMMSVC_NODE) != 0) {
1239 IBTF_DPRINTF_L2("ibnex",
1240 "ibnex_get_snapshot: "
1241 "failed to fill VPPA "
1242 "device (%x %x %x % x)",
1243 i, j, k, l);
1244 ibdm_ibnex_free_hca_list(hcap);
1245 nvlist_free(nvl);
1246 return (-1);
1247 }
1248 } /* end of ibnex_nvppa_comm_svcs loop */
1249
1250 } /* end of pa_npkeys for loop */
1251
1252 } /* end of hl_nports for loop */
1253
1254 } /* end of hca_count for loop */
1255
1256 if (hcap)
1257 ibdm_ibnex_free_hca_list(hcap);
1258
1259 /* save it to free up the entire list */
1260 mutex_exit(&ibnex.ibnex_mutex);
1261 iocp = ioc_listp = ibdm_ibnex_get_ioc_list(allow_probe);
1262 mutex_enter(&ibnex.ibnex_mutex);
1263 for (; ioc_listp != NULL; ioc_listp = ioc_listp->ioc_next) {
1264
1265 /*
1266 * Say we have N IOCs and all were deleted from ibnex
1267 * but not from IBDM
1268 */
1269 if (ibnex.ibnex_ioc_node_head == NULL) {
1270 if (ibnex_fill_ioc_tmp(&nvl, ioc_listp) != 0) {
1271 IBTF_DPRINTF_L2("ibnex", "ibnex_get_snapshot: "
1272 "filling NVL data failed");
1273 ibdm_ibnex_free_ioc_list(iocp);
1274 nvlist_free(nvl);
1275 return (-1);
1276 }
1277 continue;
1278
1279 } else {
1280 found = B_FALSE;
1281
1282 /* Check first, if we have already seen this IOC? */
1283 for (nodep = ibnex.ibnex_ioc_node_head; nodep != NULL;
1284 nodep = nodep->node_next) {
1285 if (ioc_listp->ioc_profile.ioc_guid ==
1286 nodep->node_data.ioc_node.ioc_guid) {
1287 found = B_TRUE;
1288 break;
1289 }
1290 }
1291
1292
1293 /* have we seen this IOC before? */
1294 if (found == B_TRUE) {
1295 if (ibnex_fill_nodeinfo(&nvl, nodep,
1296 &ioc_listp->ioc_profile) != 0) {
1297 IBTF_DPRINTF_L2("ibnex",
1298 "ibnex_get_snapshot: filling NVL "
1299 "for IOC node %p failed", nodep);
1300 ibdm_ibnex_free_ioc_list(iocp);
1301 nvlist_free(nvl);
1302 return (-1);
1303 }
1304
1305 } else {
1306
1307 if (ibnex_fill_ioc_tmp(&nvl, ioc_listp) != 0) {
1308 IBTF_DPRINTF_L2("ibnex",
1309 "ibnex_get_snapshot: filling NVL "
1310 "tmp for IOC node %p failed",
1311 ioc_listp);
1312 ibdm_ibnex_free_ioc_list(iocp);
1313 nvlist_free(nvl);
1314 return (-1);
1315 }
1316 }
1317
1318 } /* end of else ibnex_ioc_node_head == NULL */
1319 } /* end of external for */
1320
1321 ibdm_ibnex_free_ioc_list(iocp);
1322
1323 /*
1324 * Add list of "disconnected" IOCs, not unconfigured.
1325 */
1326 for (nodep = ibnex.ibnex_ioc_node_head; nodep != NULL;
1327 nodep = nodep->node_next) {
1328 if (nodep->node_data.ioc_node.ioc_ngids == 0 &&
1329 nodep->node_data.ioc_node.ioc_profile != NULL &&
1330 nodep->node_state != IBNEX_CFGADM_UNCONFIGURED) {
1331 if (ibnex_fill_nodeinfo(&nvl, nodep,
1332 nodep->node_data.ioc_node.ioc_profile) != 0) {
1333 IBTF_DPRINTF_L2("ibnex",
1334 "ibnex_get_snapshot: filling NVL "
1335 "for disconnected IOC node %p "
1336 "failed", nodep);
1337 nvlist_free(nvl);
1338 return (-1);
1339 }
1340 }
1341 }
1342
1343 /* lastly; pseudo nodes */
1344 for (nodep = ibnex.ibnex_pseudo_node_head; nodep;
1345 nodep = nodep->node_next) {
1346 if (nodep->node_data.pseudo_node.pseudo_merge_node == 1)
1347 continue;
1348 if (ibnex_fill_nodeinfo(&nvl, nodep, NULL) != 0) {
1349 IBTF_DPRINTF_L2("ibnex", "ibnex_get_snapshot: "
1350 "filling NVL data for Pseudo %p failed", nodep);
1351 nvlist_free(nvl);
1352 return (-1);
1353 }
1354 }
1355
1356 /* pack the data into the buffer */
1357 if (nvlist_pack(nvl, buf, sz, NV_ENCODE_NATIVE, KM_SLEEP)) {
1358 IBTF_DPRINTF_L2("ibnex",
1359 "ibnex_get_snapshot: nvlist_pack failed");
1360 nvlist_free(nvl);
1361 return (-1);
1362 }
1363
1364 IBTF_DPRINTF_L4("ibnex", "ibnex_get_snapshot: size = 0x%x", *sz);
1365 nvlist_free(nvl);
1366 return (0);
1367 }
1368
1369
1370 /*
1371 * ibnex_get_commsvcnode_snapshot()
1372 * A utility function to fill in a "dummy" Port/VPPA/HCA_SVC
1373 * information. Cfgadm plugin will display all Port/VPPA/
1374 * HCA_SVCs seen even if they are not all configured by IBNEX.
1375 *
1376 * This function uses information from IBDM to fill up Port/VPPA/
1377 * HCA_SVC snapshot. If none exists then it makes up a "temporary"
1378 * node which will be displayed as "connected/unconfigured/unknown".
1379 *
1380 * For HCA_SVC node port_guid will be same as hca_guid.
1381 */
1382 static int
ibnex_get_commsvcnode_snapshot(nvlist_t ** nvlpp,ib_guid_t hca_guid,ib_guid_t port_guid,int svc_index,ib_pkey_t p_key,ibnex_node_type_t node_type)1383 ibnex_get_commsvcnode_snapshot(nvlist_t **nvlpp, ib_guid_t hca_guid,
1384 ib_guid_t port_guid, int svc_index, ib_pkey_t p_key,
1385 ibnex_node_type_t node_type)
1386 {
1387 int rval;
1388 dev_info_t *dip = NULL;
1389 ibnex_node_data_t *nodep;
1390 ibnex_node_data_t dummy;
1391 ibnex_node_data_t *tmp = &dummy;
1392
1393 IBTF_DPRINTF_L4("ibnex", "ibnex_get_commsvcnode_snapshot: "
1394 "HCA GUID: %llX Port GUID: %llX svc_index = %x pkey = %x "
1395 "node_type = %x", hca_guid, port_guid, svc_index, p_key, node_type);
1396
1397 /* check if this node was seen before? */
1398 rval = ibnex_get_node_and_dip_from_guid(port_guid, svc_index, p_key,
1399 &nodep, &dip);
1400 if (rval == IBNEX_SUCCESS && nodep != NULL) {
1401
1402 if (ibnex_fill_nodeinfo(nvlpp, nodep, NULL) != 0) {
1403 IBTF_DPRINTF_L2("ibnex",
1404 "ibnex_get_commsvcnode_snapshot: failed to fill "
1405 "Port/VPPA device node %p NVL data", nodep);
1406 return (-1);
1407 }
1408
1409 } else {
1410 /* Fake up a Port/VPPA/HCA_SVC node */
1411 IBTF_DPRINTF_L4("ibnex", "ibnex_get_commsvcnode_snapshot: "
1412 "VPPA/Port/HCA_SVC not seen by ibnex");
1413 bzero(tmp, sizeof (ibnex_node_data_t));
1414 tmp->node_type = node_type;
1415 tmp->node_data.port_node.port_guid = port_guid;
1416 tmp->node_data.port_node.port_hcaguid = hca_guid;
1417 tmp->node_data.port_node.port_commsvc_idx = svc_index;
1418 /* Fill P_Key only for VPPA nodes */
1419 if (node_type == IBNEX_VPPA_COMMSVC_NODE) {
1420 tmp->node_data.port_node.port_pkey = p_key;
1421 }
1422
1423 if (ibnex_fill_nodeinfo(nvlpp, tmp, NULL) != 0) {
1424 IBTF_DPRINTF_L2("ibnex",
1425 "ibnex_get_commsvcnode_snapshot: failed to fill "
1426 "tmp Port/VPPA device node %p NVL data", tmp);
1427 return (-1);
1428 }
1429 }
1430
1431 return (0);
1432 }
1433
1434
1435 /*
1436 * ibnex_fill_ioc_tmp()
1437 * A utility function to fill in a "dummy" IOC information.
1438 * Cfgadm plugin will display all IOCs seen by IBDM even if they
1439 * are configured or not by IBNEX.
1440 *
1441 * This function uses information from IBDM to fill up a
1442 * dummy IOC information. It will be displayed as
1443 * "connected/unconfigured/unknown".
1444 */
1445 static int
ibnex_fill_ioc_tmp(nvlist_t ** nvlpp,ibdm_ioc_info_t * ioc_listp)1446 ibnex_fill_ioc_tmp(nvlist_t **nvlpp, ibdm_ioc_info_t *ioc_listp)
1447 {
1448 ibnex_node_data_t dummy;
1449 ibnex_node_data_t *nodep = &dummy;
1450
1451 IBTF_DPRINTF_L4("ibnex", "\tibnex_fill_ioc_tmp:");
1452
1453 bzero(nodep, sizeof (ibnex_node_data_t));
1454 nodep->node_type = IBNEX_IOC_NODE;
1455 nodep->node_data.ioc_node.ioc_guid = ioc_listp->ioc_profile.ioc_guid;
1456 nodep->node_data.ioc_node.iou_guid = ioc_listp->ioc_iou_guid;
1457 (void) strncpy(nodep->node_data.ioc_node.ioc_id_string,
1458 (char *)ioc_listp->ioc_profile.ioc_id_string,
1459 IB_DM_IOC_ID_STRING_LEN);
1460 IBTF_DPRINTF_L4("ibnex", "\tibnex_fill_ioc_tmp: %s",
1461 nodep->node_data.ioc_node.ioc_id_string);
1462
1463 if (ibnex_fill_nodeinfo(nvlpp, nodep, &ioc_listp->ioc_profile) != 0) {
1464 IBTF_DPRINTF_L2("ibnex", "\tibnex_fill_ioc_tmp: filling NVL "
1465 "data for IOC node %p failed", nodep);
1466 return (-1);
1467 }
1468
1469 return (0);
1470 }
1471
1472
1473 /*
1474 * ibnex_fill_nodeinfo()
1475 * A utility function to fill in to the NVLIST information about
1476 * a Port/IOC/VPPA/HCA_SVC/Pseudo driver that is then passed over
1477 * to cfgadm utility for display. This information is used only
1478 * for cfgadm -ll displays.
1479 *
1480 * Information that is filled in here is:-
1481 * AP_ID_NAME
1482 * AP_ID_INFO
1483 * AP_ID_TYPE
1484 * AP_ID_OCCUPANT_STATE
1485 * AP_ID_RECEPTACLE_STATE
1486 * AP_ID_CONDITION
1487 */
1488 static int
ibnex_fill_nodeinfo(nvlist_t ** nvlpp,ibnex_node_data_t * node_datap,void * tmp)1489 ibnex_fill_nodeinfo(nvlist_t **nvlpp, ibnex_node_data_t *node_datap, void *tmp)
1490 {
1491 char *svcname;
1492 char *node_name;
1493 char apid[IBTL_IBNEX_APID_LEN];
1494 char info_data[MAXNAMELEN];
1495 ib_dm_ioc_ctrl_profile_t *profilep;
1496 devctl_ap_state_t state;
1497
1498 IBTF_DPRINTF_L5("ibnex", "ibnex_fill_nodeinfo: 0x%x addr is %p",
1499 node_datap->node_type, node_datap);
1500
1501 if (node_datap->node_type == IBNEX_PORT_COMMSVC_NODE) {
1502 svcname = ibnex.ibnex_comm_svc_names[node_datap->node_data.
1503 port_node.port_commsvc_idx];
1504 (void) snprintf(apid, IBTL_IBNEX_APID_LEN, "%llX,0,%s",
1505 (longlong_t)node_datap->node_data.port_node.port_guid,
1506 svcname);
1507
1508 /* Node APID */
1509 if (nvlist_add_string(*nvlpp, IBNEX_NODE_APID_NVL, apid)) {
1510 IBTF_DPRINTF_L2("ibnex", "ibnex_fill_nodeinfo: "
1511 "failed to fill %s", IBNEX_NODE_APID_NVL);
1512 return (-1);
1513 }
1514
1515 /* Node Info */
1516 if (nvlist_add_string(*nvlpp, IBNEX_NODE_INFO_NVL, svcname)) {
1517 IBTF_DPRINTF_L2("ibnex", "ibnex_fill_nodeinfo: "
1518 "failed to fill Port %s", IBNEX_NODE_INFO_NVL);
1519 return (-1);
1520 }
1521
1522 IBTF_DPRINTF_L5("ibnex", "ibnex_fill_nodeinfo: "
1523 "Port %s = %s, %s = %s",
1524 IBNEX_NODE_INFO_NVL, apid, IBNEX_NODE_APID_NVL, svcname);
1525
1526 } else if (node_datap->node_type == IBNEX_VPPA_COMMSVC_NODE) {
1527 svcname = ibnex.ibnex_vppa_comm_svc_names[node_datap->node_data.
1528 port_node.port_commsvc_idx];
1529 (void) snprintf(apid, IBTL_IBNEX_APID_LEN, "%llX,%x,%s",
1530 (longlong_t)node_datap->node_data.port_node.port_guid,
1531 node_datap->node_data.port_node.port_pkey, svcname);
1532
1533 /* Node APID */
1534 if (nvlist_add_string(*nvlpp, IBNEX_NODE_APID_NVL, apid)) {
1535 IBTF_DPRINTF_L2("ibnex", "ibnex_fill_nodeinfo: "
1536 "failed to fill %s", IBNEX_NODE_APID_NVL);
1537 return (-1);
1538 }
1539
1540 /* Node Info */
1541 if (nvlist_add_string(*nvlpp, IBNEX_NODE_INFO_NVL, svcname)) {
1542 IBTF_DPRINTF_L2("ibnex", "ibnex_fill_nodeinfo: "
1543 "failed to fill VPPA %s", IBNEX_NODE_INFO_NVL);
1544 return (-1);
1545 }
1546
1547 IBTF_DPRINTF_L5("ibnex", "ibnex_fill_nodeinfo: "
1548 "VPPA %s = %s, %s = %s",
1549 IBNEX_NODE_APID_NVL, apid, IBNEX_NODE_INFO_NVL, svcname);
1550
1551 } else if (node_datap->node_type == IBNEX_HCASVC_COMMSVC_NODE) {
1552 svcname = ibnex.ibnex_hcasvc_comm_svc_names[node_datap->
1553 node_data.port_node.port_commsvc_idx];
1554 (void) snprintf(apid, IBTL_IBNEX_APID_LEN, "%llX,0,%s",
1555 (longlong_t)node_datap->node_data.port_node.port_guid,
1556 svcname);
1557
1558 /* Node APID */
1559 if (nvlist_add_string(*nvlpp, IBNEX_NODE_APID_NVL, apid)) {
1560 IBTF_DPRINTF_L2("ibnex", "ibnex_fill_nodeinfo: "
1561 "failed to fill %s", IBNEX_NODE_APID_NVL);
1562 return (-1);
1563 }
1564
1565 /* Node Info */
1566 if (nvlist_add_string(*nvlpp, IBNEX_NODE_INFO_NVL, svcname)) {
1567 IBTF_DPRINTF_L2("ibnex", "ibnex_fill_nodeinfo: "
1568 "failed to fill Port %s", IBNEX_NODE_INFO_NVL);
1569 return (-1);
1570 }
1571
1572 IBTF_DPRINTF_L5("ibnex", "ibnex_fill_nodeinfo: "
1573 "Port %s = %s, %s = %s",
1574 IBNEX_NODE_INFO_NVL, apid, IBNEX_NODE_APID_NVL, svcname);
1575
1576 } else if (node_datap->node_type == IBNEX_IOC_NODE) {
1577
1578 /*
1579 * get the IOC profile pointer from the args
1580 */
1581 profilep = (ib_dm_ioc_ctrl_profile_t *)tmp;
1582 IBNEX_FORM_GUID(apid, IBTL_IBNEX_APID_LEN, profilep->ioc_guid);
1583
1584 /* Node APID */
1585 if (nvlist_add_string(*nvlpp, IBNEX_NODE_APID_NVL, apid)) {
1586 IBTF_DPRINTF_L2("ibnex", "ibnex_fill_nodeinfo: "
1587 "failed to fill in %s", IBNEX_NODE_APID_NVL);
1588 return (-1);
1589 }
1590 IBTF_DPRINTF_L5("ibnex", "ibnex_fill_nodeinfo: %s %s",
1591 IBNEX_NODE_APID_NVL, apid);
1592
1593 /*
1594 * IOC "info" filed will display the following fields
1595 * VendorID, IOCDeviceID, DeviceVersion, SubsystemVendorID,
1596 * SubsystemID, Class, Subclass, Protocol, ProtocolVersion
1597 */
1598 (void) snprintf(info_data, MAXNAMELEN,
1599 "VID: 0x%x DEVID: 0x%x VER: 0x%x SUBSYS_VID: 0x%x "
1600 "SUBSYS_ID: 0x%x CLASS: 0x%x SUBCLASS: 0x%x PROTO: 0x%x "
1601 "PROTOVER: 0x%x ID_STRING: %s", profilep->ioc_vendorid,
1602 profilep->ioc_deviceid, profilep->ioc_device_ver,
1603 profilep->ioc_subsys_vendorid, profilep->ioc_subsys_id,
1604 profilep->ioc_io_class, profilep->ioc_io_subclass,
1605 profilep->ioc_protocol, profilep->ioc_protocol_ver,
1606 (char *)profilep->ioc_id_string);
1607 IBTF_DPRINTF_L5("ibnex", "ibnex_fill_nodeinfo: %s", info_data);
1608
1609 /* Node Info */
1610 if (nvlist_add_string(*nvlpp, IBNEX_NODE_INFO_NVL, info_data)) {
1611 IBTF_DPRINTF_L2("ibnex", "ibnex_fill_nodeinfo: "
1612 "failed to fill IOC %s", IBNEX_NODE_INFO_NVL);
1613 return (-1);
1614 }
1615
1616 } else if (node_datap->node_type == IBNEX_PSEUDO_NODE) {
1617 (void) snprintf(apid, IBTL_IBNEX_APID_LEN, "%s",
1618 node_datap->node_data.pseudo_node.pseudo_node_addr);
1619
1620 /* Node APID */
1621 if (nvlist_add_string(*nvlpp, IBNEX_NODE_APID_NVL, apid)) {
1622 IBTF_DPRINTF_L2("ibnex", "ibnex_fill_nodeinfo: "
1623 "failed to fill in %s", IBNEX_NODE_APID_NVL);
1624 return (-1);
1625 }
1626
1627 /* Node Info */
1628 node_name = node_datap->node_data.pseudo_node.pseudo_devi_name;
1629 (void) snprintf(info_data, MAXNAMELEN,
1630 "Pseudo Driver = \"%s\", Unit-address = \"%s\"",
1631 node_name, apid + strlen(node_name) + 1);
1632 if (nvlist_add_string(*nvlpp, IBNEX_NODE_INFO_NVL, info_data)) {
1633 IBTF_DPRINTF_L2("ibnex", "ibnex_fill_nodeinfo: "
1634 "failed to fill Pseudo %s", IBNEX_NODE_INFO_NVL);
1635 return (-1);
1636 }
1637
1638 IBTF_DPRINTF_L5("ibnex", "ibnex_fill_nodeinfo: Pseudo %s = %s,"
1639 "%s = %s", IBNEX_NODE_APID_NVL, apid, IBNEX_NODE_INFO_NVL,
1640 info_data);
1641 }
1642
1643 /* Node type */
1644 if (nvlist_add_int32(*nvlpp, IBNEX_NODE_TYPE_NVL,
1645 node_datap->node_type)) {
1646 IBTF_DPRINTF_L2("ibnex", "ibnex_fill_nodeinfo: "
1647 "failed to fill in %s", IBNEX_NODE_TYPE_NVL);
1648 return (-1);
1649 }
1650 IBTF_DPRINTF_L5("ibnex", "ibnex_fill_nodeinfo: %s %d",
1651 IBNEX_NODE_TYPE_NVL, node_datap->node_type);
1652
1653 /* figure out "ostate", "rstate" and "condition" */
1654 ibnex_figure_ap_devstate(node_datap, &state);
1655
1656 if (nvlist_add_int32(*nvlpp, IBNEX_NODE_RSTATE_NVL, state.ap_rstate)) {
1657 IBTF_DPRINTF_L2("ibnex", "ibnex_fill_nodeinfo: "
1658 "failed to fill in %s", IBNEX_NODE_RSTATE_NVL);
1659 return (-1);
1660 }
1661 IBTF_DPRINTF_L5("ibnex", "ibnex_fill_nodeinfo: %s %d",
1662 IBNEX_NODE_RSTATE_NVL, state.ap_rstate);
1663
1664 if (nvlist_add_int32(*nvlpp, IBNEX_NODE_OSTATE_NVL, state.ap_ostate)) {
1665 IBTF_DPRINTF_L2("ibnex", "ibnex_fill_nodeinfo: "
1666 "failed to fill in %s", IBNEX_NODE_OSTATE_NVL);
1667 return (-1);
1668 }
1669 IBTF_DPRINTF_L5("ibnex", "ibnex_fill_nodeinfo: %s %d",
1670 IBNEX_NODE_OSTATE_NVL, state.ap_ostate);
1671
1672 if (nvlist_add_int32(*nvlpp, IBNEX_NODE_COND_NVL, state.ap_condition)) {
1673 IBTF_DPRINTF_L2("ibnex", "ibnex_fill_nodeinfo: "
1674 "failed to fill in %s", IBNEX_NODE_COND_NVL);
1675 return (-1);
1676 }
1677 IBTF_DPRINTF_L5("ibnex", "ibnex_fill_nodeinfo: %s %d",
1678 IBNEX_NODE_COND_NVL, state.ap_condition);
1679
1680 return (0);
1681 }
1682
1683
1684 /*
1685 * ibnex_figure_ap_devstate()
1686 * Fills the "devctl_ap_state_t" for a given ap_id
1687 *
1688 * currently it assumes that we don't support "error_code" and
1689 * "last_change" value.
1690 */
1691 static void
ibnex_figure_ap_devstate(ibnex_node_data_t * nodep,devctl_ap_state_t * ap_state)1692 ibnex_figure_ap_devstate(ibnex_node_data_t *nodep, devctl_ap_state_t *ap_state)
1693 {
1694 IBTF_DPRINTF_L5("ibnex", "ibnex_figure_ap_devstate: nodep = %p", nodep);
1695
1696 ap_state->ap_rstate = AP_RSTATE_CONNECTED;
1697 if (nodep == NULL) { /* for nodes not seen by IBNEX yet */
1698 ap_state->ap_ostate = AP_OSTATE_UNCONFIGURED;
1699 ap_state->ap_condition = AP_COND_UNKNOWN;
1700 } else {
1701 /*
1702 * IBNEX_NODE_AP_UNCONFIGURED & IBNEX_NODE_AP_CONFIGURING.
1703 */
1704 if (nodep->node_ap_state >= IBNEX_NODE_AP_UNCONFIGURED) {
1705 ap_state->ap_ostate = AP_OSTATE_UNCONFIGURED;
1706 ap_state->ap_condition = AP_COND_UNKNOWN;
1707 } else {
1708 ap_state->ap_ostate = AP_OSTATE_CONFIGURED;
1709 ap_state->ap_condition = AP_COND_OK;
1710 }
1711 }
1712 ap_state->ap_last_change = (time_t)-1;
1713 ap_state->ap_error_code = 0;
1714 ap_state->ap_in_transition = 0;
1715 }
1716
1717
1718 /*
1719 * ibnex_figure_ib_apid_devstate()
1720 * Fills the "devctl_ap_state_t" for a IB static ap_id
1721 */
1722 static void
ibnex_figure_ib_apid_devstate(devctl_ap_state_t * ap_state)1723 ibnex_figure_ib_apid_devstate(devctl_ap_state_t *ap_state)
1724 {
1725 ap_state->ap_rstate = AP_RSTATE_CONNECTED;
1726 ap_state->ap_condition = AP_COND_OK;
1727 ap_state->ap_ostate = (ibt_get_hca_list(NULL) == 0) ?
1728 AP_OSTATE_UNCONFIGURED : AP_OSTATE_CONFIGURED;
1729 ap_state->ap_last_change = (time_t)-1;
1730 ap_state->ap_error_code = 0;
1731 ap_state->ap_in_transition = 0;
1732 }
1733
1734
1735 /*
1736 * ibnex_get_apid()
1737 * Reads in the ap_id passed as an nvlist_string from user-land
1738 */
1739 static char *
ibnex_get_apid(struct devctl_iocdata * dcp)1740 ibnex_get_apid(struct devctl_iocdata *dcp)
1741 {
1742 char *ap_id;
1743
1744 ASSERT(mutex_owned(&ibnex.ibnex_mutex));
1745
1746 /* Get which ap_id to operate on. */
1747 if (nvlist_lookup_string(ndi_dc_get_ap_data(dcp), "apid",
1748 &ap_id) != 0) {
1749 IBTF_DPRINTF_L4("ibnex", "ibnex_get_apid: ap_id lookup failed");
1750 ap_id = NULL;
1751 }
1752
1753 IBTF_DPRINTF_L4("ibnex", "ibnex_get_apid: ap_id=%s", ap_id);
1754 return (ap_id);
1755 }
1756
1757
1758 /*
1759 * ibnex_get_dip_from_apid()
1760 * Figures out the dip/node_data from an ap_id given that this ap_id
1761 * exists as a "name" in the "ibnex" list
1762 *
1763 * NOTE: ap_id was on stack earlier and gets manipulated here. Since this
1764 * function may be called twice; it is better to make a local copy of
1765 * ap_id; if the ap_id were to be reused.
1766 */
1767 static int
ibnex_get_dip_from_apid(char * apid,dev_info_t ** ret_dip,ibnex_node_data_t ** ret_node_datap)1768 ibnex_get_dip_from_apid(char *apid, dev_info_t **ret_dip,
1769 ibnex_node_data_t **ret_node_datap)
1770 {
1771 int rv, ret;
1772 int index;
1773 int len = strlen((char *)apid) + 1;
1774 char *dyn;
1775 char *ap_id;
1776 char *first;
1777 char *second = NULL;
1778 char *node_addr;
1779 char name[100];
1780 ibnex_node_data_t *nodep = NULL;
1781
1782 ap_id = i_ddi_strdup(apid, KM_SLEEP);
1783 IBTF_DPRINTF_L4("ibnex", "\tibnex_get_dip_from_apid: %s", ap_id);
1784 ASSERT(mutex_owned(&ibnex.ibnex_mutex));
1785
1786 if ((dyn = GET_DYN(ap_id)) != NULL) {
1787 rv = IBNEX_DYN_APID;
1788 } else { /* either static, hca or unknown */
1789 *ret_dip = NULL;
1790 if (strstr(ap_id, "hca") != 0) {
1791 rv = IBNEX_HCA_APID;
1792 } else if (strstr(ap_id, IBNEX_FABRIC) != 0) {
1793 rv = IBNEX_BASE_APID;
1794 } else {
1795 rv = IBNEX_UNKNOWN_APID;
1796 }
1797 kmem_free(ap_id, len);
1798 return (rv);
1799 }
1800
1801 dyn += strlen(DYN_SEP);
1802 if (*dyn == '\0') {
1803 *ret_dip = NULL;
1804 kmem_free(ap_id, len);
1805 return (IBNEX_UNKNOWN_APID);
1806 }
1807
1808 /* APID */
1809 first = strchr(dyn, ',');
1810 if (first != NULL)
1811 second = strchr(first+1, ',');
1812
1813 /* Implies Port or VPPA or HCA_SVC Driver ap_id */
1814 if (first != NULL && second != NULL) {
1815 int str_len;
1816 int pkey_val = 0;
1817 char *pkey_str = strchr(ap_id, ',');
1818 char *svc_str = strrchr(pkey_str, ',');
1819
1820 /* dyn contains ,GUID,p_key,svc_name. Change it to GUID */
1821 str_len = strlen(dyn) - strlen(pkey_str);
1822 dyn[str_len] = '\0';
1823 IBTF_DPRINTF_L4("ibnex", "\tibnex_get_dip_from_apid: "
1824 "Port / Node Guid %s", dyn);
1825
1826 /* figure out comm or vppa. figure out pkey */
1827 ++pkey_str; /* pkey_str used to point to ",p_key,svc_name" */
1828
1829 /* pkey_str contains p_key,svc_name. Change it to p_key */
1830 str_len = strlen(pkey_str) - strlen(svc_str);
1831 pkey_str[str_len] = '\0';
1832
1833 /* convert the string P_KEY to hex value */
1834 pkey_val = ibnex_str2hex(pkey_str, strlen(pkey_str), &ret);
1835 if (ret != IBNEX_SUCCESS) {
1836 *ret_dip = NULL;
1837 kmem_free(ap_id, len);
1838 return (IBNEX_UNKNOWN_APID);
1839 }
1840
1841 ++svc_str; /* svc_str used to point to ",svc_name" */
1842 IBTF_DPRINTF_L5("ibnex", "\tibnex_get_dip_from_apid: pkey %s"
1843 ":%x service name = %s", pkey_str, pkey_val, svc_str);
1844
1845 for (nodep = ibnex.ibnex_port_node_head;
1846 nodep != NULL; nodep = nodep->node_next) {
1847 index = nodep->node_data.port_node.port_commsvc_idx;
1848 IBNEX_FORM_GUID(name, IBTL_IBNEX_APID_LEN,
1849 nodep->node_data.port_node.port_guid);
1850
1851 /*
1852 * Match P_Key, name string & service string:
1853 * For COMM / HCA_SVC services these should be true:
1854 * P_Key matches to 0, svc_str in comm_svc_names[]
1855 * and name matches the dynamic part of the ap_id
1856 * For VPPA services this should be true:
1857 * P_Key != 0 & matches, svc_str in
1858 * vppa_comm_svc_names[] and the name matches the
1859 * dynamic part of the ap_id.
1860 */
1861 if ((pkey_val == nodep->node_data.port_node.
1862 port_pkey) && (strstr(dyn, name) != NULL)) {
1863
1864 /* pkey != 0, COMM / HCA_SVC service */
1865 if (((pkey_val == 0) && (
1866 /* Port Service */
1867 ((ibnex.ibnex_comm_svc_names != NULL) &&
1868 (index < ibnex.ibnex_num_comm_svcs) &&
1869 (strstr(svc_str, ibnex.
1870 ibnex_comm_svc_names[index]) != NULL)) ||
1871 /* HCA_SVC service */
1872 ((ibnex.ibnex_hcasvc_comm_svc_names !=
1873 NULL) && (index <
1874 ibnex.ibnex_nhcasvc_comm_svcs) &&
1875 (strstr(svc_str, ibnex.
1876 ibnex_hcasvc_comm_svc_names[index])
1877 != NULL)))) ||
1878 /* next the VPPA strings */
1879 ((pkey_val != 0) && (strstr(svc_str, ibnex.
1880 ibnex_vppa_comm_svc_names[index]) !=
1881 NULL))) {
1882 if (nodep->node_dip)
1883 ndi_hold_devi(nodep->node_dip);
1884 *ret_node_datap = nodep;
1885 *ret_dip = nodep->node_dip;
1886 kmem_free(ap_id, len);
1887 return (rv);
1888 }
1889 }
1890
1891 } /* end of for */
1892
1893 } else if (first != NULL && second == NULL) {
1894 /* pseudo ap_id */
1895 for (nodep = ibnex.ibnex_pseudo_node_head; nodep;
1896 nodep = nodep->node_next) {
1897 if (nodep->node_data.pseudo_node.pseudo_merge_node
1898 == 1)
1899 continue;
1900 node_addr = nodep->node_data.pseudo_node.
1901 pseudo_node_addr;
1902 if (strncmp(dyn, node_addr, strlen(node_addr)) == 0) {
1903 if (nodep->node_dip)
1904 ndi_hold_devi(nodep->node_dip);
1905 *ret_node_datap = nodep;
1906 *ret_dip = nodep->node_dip;
1907 kmem_free(ap_id, len);
1908 return (rv);
1909 }
1910 }
1911
1912 } else if (first == NULL && second == NULL) {
1913 /* This is an IOC ap_id */
1914 for (nodep = ibnex.ibnex_ioc_node_head; nodep != NULL;
1915 nodep = nodep->node_next) {
1916 IBNEX_FORM_GUID(name, IBTL_IBNEX_APID_LEN,
1917 nodep->node_data.ioc_node.ioc_guid);
1918 if (strstr(dyn, name) != NULL) {
1919 if (nodep->node_dip)
1920 ndi_hold_devi(nodep->node_dip);
1921 *ret_node_datap = nodep;
1922 *ret_dip = nodep->node_dip;
1923 kmem_free(ap_id, len);
1924 return (rv);
1925 }
1926 }
1927 }
1928
1929 /* Could not find a matching IB device */
1930 *ret_dip = (nodep) ? nodep->node_dip : NULL;
1931 kmem_free(ap_id, len);
1932 return (rv);
1933 }
1934
1935
1936 /*
1937 * ibnex_handle_pseudo_configure()
1938 * Do DEVCTL_AP_CONNECT processing for Pseudo devices only.
1939 * The code also checks if the given ap_id is valid or not.
1940 */
1941 static ibnex_rval_t
ibnex_handle_pseudo_configure(char * apid)1942 ibnex_handle_pseudo_configure(char *apid)
1943 {
1944 char *node_addr;
1945 char *last = strrchr(apid, ':') + 1;
1946 ibnex_rval_t retval = IBNEX_FAILURE;
1947 ibnex_node_data_t *nodep;
1948
1949 IBTF_DPRINTF_L4("ibnex", "\tibnex_handle_pseudo_configure: "
1950 "last = %s\n\t\tapid = %s", last, apid);
1951 ASSERT(MUTEX_HELD(&ibnex.ibnex_mutex));
1952
1953 /* Check if the APID is valid first */
1954 if (apid == NULL || last == NULL) {
1955 IBTF_DPRINTF_L4("ibnex", "\tibnex_handle_pseudo_configure: "
1956 "invalid apid %s", apid);
1957 return (retval);
1958 }
1959
1960 /* find the matching entry and configure it */
1961 for (nodep = ibnex.ibnex_pseudo_node_head; nodep != NULL;
1962 nodep = nodep->node_next) {
1963 if (nodep->node_data.pseudo_node.pseudo_merge_node == 1)
1964 continue;
1965 node_addr = nodep->node_data.pseudo_node.pseudo_node_addr;
1966 if (strncmp(node_addr, last, strlen(last)))
1967 continue;
1968
1969 if (nodep->node_dip != NULL) {
1970 /*
1971 * Return BUSY if another configure
1972 * operation is in progress
1973 */
1974 if (nodep->node_state ==
1975 IBNEX_CFGADM_CONFIGURING)
1976 return (IBNEX_BUSY);
1977 else
1978 return (IBNEX_SUCCESS);
1979 }
1980
1981 /*
1982 * Return BUSY if another unconfigure operation is
1983 * in progress
1984 */
1985 if (nodep->node_state == IBNEX_CFGADM_UNCONFIGURING)
1986 return (IBNEX_BUSY);
1987
1988 ASSERT(nodep->node_state != IBNEX_CFGADM_CONFIGURED);
1989 nodep->node_state = IBNEX_CFGADM_CONFIGURING;
1990
1991 mutex_exit(&ibnex.ibnex_mutex);
1992 retval = ibnex_pseudo_create_all_pi(nodep);
1993 mutex_enter(&ibnex.ibnex_mutex);
1994 if (retval == NDI_SUCCESS) {
1995 nodep->node_state = IBNEX_CFGADM_CONFIGURED;
1996 return (IBNEX_SUCCESS);
1997 } else {
1998 nodep->node_state = IBNEX_CFGADM_UNCONFIGURED;
1999 return (IBNEX_FAILURE);
2000 }
2001 }
2002
2003 IBTF_DPRINTF_L4("ibnex", "\thandle_pseudo_configure: retval=%d",
2004 retval);
2005 return (retval);
2006 }
2007
2008
2009 /*
2010 * ibnex_handle_ioc_configure()
2011 * Do DEVCTL_AP_CONNECT processing for IOCs only.
2012 * The code also checks if the given ap_id is valid or not.
2013 */
2014 static ibnex_rval_t
ibnex_handle_ioc_configure(char * apid)2015 ibnex_handle_ioc_configure(char *apid)
2016 {
2017 int ret;
2018 char *guid_str = strrchr(apid, ':') + 1;
2019 ib_guid_t ioc_guid;
2020 ibnex_rval_t retval = IBNEX_FAILURE;
2021 ibdm_ioc_info_t *ioc_info;
2022
2023 ASSERT(MUTEX_HELD(&ibnex.ibnex_mutex));
2024 IBTF_DPRINTF_L4("ibnex", "\tibnex_handle_ioc_configure: %s", apid);
2025
2026 /* Check if the APID is valid first */
2027 if (guid_str == NULL) {
2028 IBTF_DPRINTF_L4("ibnex",
2029 "\tibnex_handle_ioc_configure: invalid apid %s", apid);
2030 return (retval);
2031 }
2032
2033 /*
2034 * Call into IBDM to get IOC information
2035 */
2036 ioc_guid = ibnex_str2hex(guid_str, strlen(guid_str), &ret);
2037 if (ret != IBNEX_SUCCESS)
2038 return (ret);
2039
2040 IBTF_DPRINTF_L4("ibnex",
2041 "\tibnex_handle_ioc_configure: IOC GUID = %llX", ioc_guid);
2042 mutex_exit(&ibnex.ibnex_mutex);
2043 ioc_info = ibdm_ibnex_get_ioc_info(ioc_guid);
2044 mutex_enter(&ibnex.ibnex_mutex);
2045 if (ioc_info == NULL) {
2046 IBTF_DPRINTF_L2("ibnex",
2047 "\tibnex_handle_ioc_configure: probe_iocguid failed");
2048 return (retval);
2049 }
2050
2051 retval = ibnex_ioc_initnode_all_pi(ioc_info);
2052 ibdm_ibnex_free_ioc_list(ioc_info);
2053
2054 IBTF_DPRINTF_L4("ibnex", "\tibnex_handle_ioc_configure: "
2055 "done retval = %d", retval);
2056 return (retval);
2057 }
2058
2059
2060 /*
2061 * ibnex_handle_commsvcnode_configure()
2062 * Do DEVCTL_AP_CONNECT processing
2063 * This is done for Port/VPPA/HCA_SVC drivers Only.
2064 * The code also checks if the given ap_id is valid or not.
2065 */
2066 static ibnex_rval_t
ibnex_handle_commsvcnode_configure(char * apid)2067 ibnex_handle_commsvcnode_configure(char *apid)
2068 {
2069 int ret, str_len;
2070 int sndx;
2071 int port_pkey = 0;
2072 char *pkey_str = strchr(apid, ',');
2073 char *guid_str = strrchr(apid, ':') + 1;
2074 char *svc_str = strrchr(pkey_str, ',');
2075 boolean_t found = B_FALSE;
2076 boolean_t is_hcasvc_node = B_FALSE;
2077 ib_guid_t guid; /* Port / Node GUID */
2078 dev_info_t *parent;
2079 ibnex_rval_t retval = IBNEX_FAILURE;
2080 ibdm_port_attr_t *port_attr;
2081 int node_type;
2082 ibdm_hca_list_t *hca_list;
2083
2084 ASSERT(MUTEX_HELD(&ibnex.ibnex_mutex));
2085 IBTF_DPRINTF_L4("ibnex", "\tibnex_handle_commsvcnode_configure: %s",
2086 apid);
2087
2088 /* Check if the APID is valid first */
2089 if (guid_str == NULL || ((guid_str != NULL) &&
2090 (pkey_str == NULL || svc_str == NULL))) {
2091 IBTF_DPRINTF_L4("ibnex",
2092 "\tibnex_handle_commsvcnode_configure: "
2093 "invalid apid %s", apid);
2094 return (retval);
2095 }
2096
2097 /* guid_str contains GUID,p_key,svc_name. Change it to GUID */
2098 str_len = strlen(guid_str) - strlen(pkey_str);
2099 guid_str[str_len] = '\0';
2100
2101 /* convert the string GUID to hex value */
2102 guid = ibnex_str2hex(guid_str, strlen(guid_str), &ret);
2103 if (ret == IBNEX_FAILURE)
2104 return (ret);
2105 IBTF_DPRINTF_L4("ibnex", "\tibnex_handle_commsvcnode_configure: "
2106 "Port / Node Guid %llX", guid);
2107
2108 /* figure out Port/HCA_SVC or VPPA. Also figure out the P_Key. */
2109 ++pkey_str; /* pkey_str used to point to ",p_key,svc_name" */
2110
2111 /* pkey_str contains p_key,svc_name. Change it to P_Key */
2112 str_len = strlen(pkey_str) - strlen(svc_str);
2113 pkey_str[str_len] = '\0';
2114 IBTF_DPRINTF_L5("ibnex", "\tibnex_handle_commsvcnode_configure: "
2115 "p_key %s", pkey_str);
2116
2117 /* convert the string P_Key to a hexadecimal value */
2118 port_pkey = ibnex_str2hex(pkey_str, strlen(pkey_str), &ret);
2119 IBTF_DPRINTF_L5("ibnex", "\tibnex_handle_commsvcnode_configure: "
2120 "PKEY num %x", port_pkey);
2121 if (ret == IBNEX_FAILURE)
2122 return (ret);
2123
2124 ++svc_str; /* svc_str used to point to ",svc_name" */
2125
2126 /* find the service index */
2127 if (port_pkey == 0) {
2128 /* PORT Devices */
2129 for (sndx = 0; sndx < ibnex.ibnex_num_comm_svcs; sndx++) {
2130 if (strncmp(ibnex.ibnex_comm_svc_names[sndx],
2131 svc_str, strlen(svc_str)) == 0) {
2132 found = B_TRUE;
2133 break;
2134 }
2135 }
2136
2137 /* HCA_SVC Devices */
2138 if (found == B_FALSE) {
2139 for (sndx = 0; sndx < ibnex.ibnex_nhcasvc_comm_svcs;
2140 sndx++) {
2141 if (strncmp(ibnex.ibnex_hcasvc_comm_svc_names
2142 [sndx], svc_str, strlen(svc_str)) == 0) {
2143 found = B_TRUE;
2144 is_hcasvc_node = B_TRUE;
2145 break;
2146 }
2147 }
2148 }
2149
2150 } else {
2151 for (sndx = 0; sndx < ibnex.ibnex_nvppa_comm_svcs; sndx++) {
2152 if (strncmp(ibnex.ibnex_vppa_comm_svc_names[sndx],
2153 svc_str, strlen(svc_str)) == 0) {
2154 found = B_TRUE;
2155 break;
2156 }
2157 }
2158 }
2159
2160 if (found == B_FALSE) {
2161 IBTF_DPRINTF_L2("ibnex",
2162 "\tibnex_handle_commsvcnode_configure: "
2163 "invalid service %s", svc_str);
2164 return (retval);
2165 }
2166
2167 /* get Port attributes structure */
2168 mutex_exit(&ibnex.ibnex_mutex);
2169 if (is_hcasvc_node == B_FALSE) {
2170 port_attr = ibdm_ibnex_get_port_attrs(guid);
2171 if (port_attr == NULL) {
2172 IBTF_DPRINTF_L2("ibnex",
2173 "\tibnex_handle_commsvcnode_configure: "
2174 "ibdm_ibnex_get_port_attrs failed");
2175 mutex_enter(&ibnex.ibnex_mutex);
2176 return (retval);
2177 }
2178 } else {
2179 hca_list = ibdm_ibnex_get_hca_info_by_guid(guid);
2180 if (hca_list == NULL) {
2181 IBTF_DPRINTF_L2("ibnex",
2182 "\tibnex_handle_commsvcnode_configure: "
2183 "ibdm_ibnex_get_hca_info_by_guid failed");
2184 mutex_enter(&ibnex.ibnex_mutex);
2185 return (retval);
2186 }
2187 port_attr = hca_list->hl_hca_port_attr;
2188 }
2189
2190 /* get HCA's dip */
2191 parent = ibtl_ibnex_hcaguid2dip(port_attr->pa_hca_guid);
2192
2193 if (parent == NULL) {
2194 IBTF_DPRINTF_L2("ibnex",
2195 "\tibnex_handle_commsvcnode_configure: "
2196 "no HCA present");
2197 mutex_enter(&ibnex.ibnex_mutex);
2198 if (is_hcasvc_node == B_FALSE)
2199 ibdm_ibnex_free_port_attr(port_attr);
2200 else
2201 ibdm_ibnex_free_hca_list(hca_list);
2202 return (retval);
2203 }
2204
2205 if (port_pkey == 0)
2206 node_type = (is_hcasvc_node == B_FALSE) ?
2207 IBNEX_PORT_COMMSVC_NODE : IBNEX_HCASVC_COMMSVC_NODE;
2208 else
2209 node_type = IBNEX_VPPA_COMMSVC_NODE;
2210
2211 mutex_enter(&ibnex.ibnex_mutex);
2212 ndi_devi_enter(parent);
2213 if (ibnex_commsvc_initnode(parent, port_attr, sndx, node_type,
2214 port_pkey, &ret, IBNEX_CFGADM_ENUMERATE) != NULL) {
2215 retval = IBNEX_SUCCESS;
2216 } else {
2217 retval = (ret == IBNEX_BUSY) ? IBNEX_BUSY : IBNEX_FAILURE;
2218 }
2219 ndi_devi_exit(parent);
2220
2221 if (is_hcasvc_node == B_FALSE)
2222 ibdm_ibnex_free_port_attr(port_attr);
2223 else
2224 ibdm_ibnex_free_hca_list(hca_list);
2225
2226 IBTF_DPRINTF_L4("ibnex", "\tibnex_handle_commsvcnode_configure: "
2227 "done retval = %d", retval);
2228
2229 return (retval);
2230 }
2231
2232
2233 /*
2234 * ibnex_return_apid()
2235 * Construct the ap_id of a given IBTF client in kernel
2236 */
2237 static void
ibnex_return_apid(dev_info_t * childp,char ** ret_apid)2238 ibnex_return_apid(dev_info_t *childp, char **ret_apid)
2239 {
2240 ibnex_node_data_t *nodep;
2241
2242 IBTF_DPRINTF_L4("ibnex", "ibnex_return_apid:");
2243
2244 ASSERT(childp != NULL);
2245 nodep = ddi_get_parent_data(childp);
2246
2247 if (nodep->node_type == IBNEX_PORT_COMMSVC_NODE) {
2248 (void) snprintf(*ret_apid, IBTL_IBNEX_APID_LEN,
2249 "ib%s%llX,0,%s", DYN_SEP,
2250 (longlong_t)nodep->node_data.port_node.port_guid,
2251 ibnex.ibnex_comm_svc_names[nodep->node_data.port_node.
2252 port_commsvc_idx]);
2253
2254 } else if (nodep->node_type == IBNEX_HCASVC_COMMSVC_NODE) {
2255 (void) snprintf(*ret_apid, IBTL_IBNEX_APID_LEN,
2256 "ib%s%llX,0,%s", DYN_SEP,
2257 (longlong_t)nodep->node_data.port_node.port_guid, ibnex.
2258 ibnex_hcasvc_comm_svc_names[nodep->node_data.port_node.
2259 port_commsvc_idx]);
2260
2261 } else if (nodep->node_type == IBNEX_VPPA_COMMSVC_NODE) {
2262 (void) snprintf(*ret_apid, IBTL_IBNEX_APID_LEN,
2263 "ib%s%llX,%x,%s", DYN_SEP,
2264 (longlong_t)nodep->node_data.port_node.port_guid,
2265 nodep->node_data.port_node.port_pkey,
2266 ibnex.ibnex_vppa_comm_svc_names[nodep->node_data.port_node.
2267 port_commsvc_idx]);
2268
2269 } else if (nodep->node_type == IBNEX_IOC_NODE) {
2270 (void) snprintf(*ret_apid, IBTL_IBNEX_APID_LEN,
2271 "ib%s%llX", DYN_SEP,
2272 (longlong_t)nodep->node_data.ioc_node.ioc_guid);
2273
2274 } else if (nodep->node_type == IBNEX_PSEUDO_NODE) {
2275 (void) snprintf(*ret_apid, IBTL_IBNEX_APID_LEN, "ib%s%s",
2276 DYN_SEP, nodep->node_data.pseudo_node.pseudo_node_addr);
2277
2278 } else {
2279 (void) snprintf(*ret_apid, IBTL_IBNEX_APID_LEN, "%s", "-");
2280 }
2281
2282 IBTF_DPRINTF_L4("ibnex", "ibnex_return_apid: %x %s",
2283 nodep->node_type, ret_apid);
2284 }
2285
2286
2287 /*
2288 * ibnex_vppa_conf_entry_add()
2289 * Add a new service to the ibnex data base of VPPA communication
2290 * services.
2291 */
2292 static void
ibnex_vppa_conf_entry_add(char * service)2293 ibnex_vppa_conf_entry_add(char *service)
2294 {
2295 int i, nsvcs;
2296 char **service_name;
2297
2298 ASSERT(MUTEX_HELD(&ibnex.ibnex_mutex));
2299 nsvcs = ibnex.ibnex_nvppa_comm_svcs;
2300
2301 /* Allocate space for new "ibnex.ibnex_nvppa_comm_svcs + 1" */
2302 service_name = kmem_alloc((nsvcs + 1) * sizeof (char *), KM_SLEEP);
2303 /*
2304 * Copy over the existing "ibnex.ibnex_vppa_comm_svc_names"
2305 * array. Add the new service at the end.
2306 */
2307 for (i = 0; i < nsvcs; i++)
2308 service_name[i] = ibnex.ibnex_vppa_comm_svc_names[i];
2309 service_name[i] = kmem_alloc(strlen(service) + 1, KM_SLEEP);
2310 (void) snprintf(service_name[i], 5, "%s", service);
2311
2312 /* Replace existing pointer to VPPA services w/ newly allocated one */
2313 if (ibnex.ibnex_vppa_comm_svc_names) {
2314 kmem_free(ibnex.ibnex_vppa_comm_svc_names, nsvcs *
2315 sizeof (char *));
2316 }
2317 ibnex.ibnex_nvppa_comm_svcs++;
2318 ibnex.ibnex_vppa_comm_svc_names = service_name;
2319 }
2320
2321 /*
2322 * ibnex_port_conf_entry_add()
2323 * Add a new service to the ibnex data base of Port communication
2324 * services.
2325 */
2326 static void
ibnex_port_conf_entry_add(char * service)2327 ibnex_port_conf_entry_add(char *service)
2328 {
2329 int i, nsvcs;
2330 char **service_name;
2331
2332 ASSERT(MUTEX_HELD(&ibnex.ibnex_mutex));
2333 nsvcs = ibnex.ibnex_num_comm_svcs;
2334
2335 /* Allocate space for new "ibnex.ibnex_num_comm_svcs + 1" */
2336 service_name = kmem_alloc((nsvcs + 1) * sizeof (char *), KM_SLEEP);
2337 /*
2338 * Copy over the existing "ibnex.ibnex_comm_svc_names" array.
2339 * Add the new service to the end.
2340 */
2341 for (i = 0; i < nsvcs; i++)
2342 service_name[i] = ibnex.ibnex_comm_svc_names[i];
2343 service_name[i] = kmem_alloc(strlen(service) + 1, KM_SLEEP);
2344 (void) snprintf(service_name[i], 5, "%s", service);
2345
2346 /* Replace existing pointer to Port services w/ newly allocated one */
2347 if (ibnex.ibnex_comm_svc_names) {
2348 kmem_free(ibnex.ibnex_comm_svc_names, nsvcs * sizeof (char *));
2349 }
2350 ibnex.ibnex_num_comm_svcs++;
2351 ibnex.ibnex_comm_svc_names = service_name;
2352 }
2353
2354 /*
2355 * ibnex_hcasvc_conf_entry_add()
2356 * Add a new service to the ibnex data base of HCA_SVC communication
2357 * services.
2358 */
2359 static void
ibnex_hcasvc_conf_entry_add(char * service)2360 ibnex_hcasvc_conf_entry_add(char *service)
2361 {
2362 int i, nsvcs;
2363 char **service_name;
2364
2365 ASSERT(MUTEX_HELD(&ibnex.ibnex_mutex));
2366 nsvcs = ibnex.ibnex_nhcasvc_comm_svcs;
2367
2368 /* Allocate space for new "ibnex.ibnex_nvppa_comm_svcs + 1" */
2369 service_name = kmem_alloc((nsvcs + 1) * sizeof (char *), KM_SLEEP);
2370 /*
2371 * Copy over the existing "ibnex.ibnex_hcasvc_comm_svc_names"
2372 * array. Add the new service at the end.
2373 */
2374 for (i = 0; i < nsvcs; i++)
2375 service_name[i] = ibnex.ibnex_hcasvc_comm_svc_names[i];
2376 service_name[i] = kmem_alloc(strlen(service) + 1, KM_SLEEP);
2377 (void) snprintf(service_name[i], 5, "%s", service);
2378
2379 /*
2380 * Replace existing pointer to HCA_SVC services w/ newly
2381 * allocated one
2382 */
2383 if (ibnex.ibnex_hcasvc_comm_svc_names) {
2384 kmem_free(ibnex.ibnex_hcasvc_comm_svc_names, nsvcs *
2385 sizeof (char *));
2386 }
2387 ibnex.ibnex_nhcasvc_comm_svcs++;
2388 ibnex.ibnex_hcasvc_comm_svc_names = service_name;
2389 }
2390
2391
2392 /*
2393 * ibnex_vppa_conf_entry_delete()
2394 * Delete an existing service entry from ibnex data base of
2395 * VPPA communication services.
2396 */
2397 static int
ibnex_vppa_conf_entry_delete(char * msg,char * service)2398 ibnex_vppa_conf_entry_delete(char *msg, char *service)
2399 {
2400 int i, j, nsvcs;
2401 int len;
2402 int match_ndx;
2403 char **service_name;
2404 boolean_t found = B_FALSE;
2405 ibnex_node_data_t *node_datap = ibnex.ibnex_port_node_head;
2406
2407 IBTF_DPRINTF_L4("ibnex", "\tvppa_conf_entry_delete: %s", service);
2408
2409 ASSERT(MUTEX_HELD(&ibnex.ibnex_mutex));
2410 nsvcs = ibnex.ibnex_nvppa_comm_svcs;
2411
2412 /* find matching index */
2413 for (i = 0; i < nsvcs; i++) {
2414 if (strcmp(ibnex.ibnex_vppa_comm_svc_names[i], service))
2415 continue;
2416 found = B_TRUE;
2417 match_ndx = i;
2418 break;
2419 }
2420
2421 /* check for valid "nsvcs" */
2422 if (found == B_FALSE || nsvcs == 0) {
2423 IBTF_DPRINTF_L2("ibnex", "%s: invalid vppa services %x",
2424 msg, nsvcs);
2425 return (EIO);
2426 }
2427
2428 /* Check if service is in use; return failure if so */
2429 for (; node_datap; node_datap = node_datap->node_next) {
2430 if ((node_datap->node_data.port_node.port_commsvc_idx == i) &&
2431 node_datap->node_type == IBNEX_VPPA_COMMSVC_NODE &&
2432 node_datap->node_dip) {
2433 IBTF_DPRINTF_L2("ibnex", "%s: service %s is in use",
2434 msg, service);
2435 return (EIO);
2436 }
2437 }
2438
2439 /* if nsvcs == 1, bailout early */
2440 if (nsvcs == 1) {
2441 /* free up that single entry */
2442 len = strlen(ibnex.ibnex_vppa_comm_svc_names[0]) + 1;
2443 kmem_free(ibnex.ibnex_vppa_comm_svc_names[0], len);
2444 kmem_free(ibnex.ibnex_vppa_comm_svc_names, sizeof (char *));
2445 ibnex.ibnex_vppa_comm_svc_names = NULL;
2446 ibnex.ibnex_nvppa_comm_svcs = 0;
2447 return (0);
2448 }
2449
2450 /* Allocate space for new "ibnex.ibnex_nvppa_comm_svcs - 1" */
2451 service_name = kmem_alloc((nsvcs - 1) * sizeof (char *), KM_SLEEP);
2452 /*
2453 * Copy over the existing "ibnex.ibnex_vppa_comm_svc_names"
2454 * array. Do not copy over the matching service.
2455 */
2456 for (i = 0, j = 0; i < nsvcs; i++) {
2457 if (i == match_ndx) {
2458 /* free up that entry */
2459 len = strlen(ibnex.ibnex_vppa_comm_svc_names[i]) + 1;
2460 kmem_free(ibnex.ibnex_vppa_comm_svc_names[i], len);
2461 continue;
2462 }
2463 service_name[j++] = ibnex.ibnex_vppa_comm_svc_names[i];
2464 }
2465
2466 /* Replace existing pointer to VPPA services w/ newly adjusted one */
2467 if (ibnex.ibnex_vppa_comm_svc_names) {
2468 kmem_free(ibnex.ibnex_vppa_comm_svc_names, nsvcs *
2469 sizeof (char *));
2470 ibnex.ibnex_nvppa_comm_svcs--;
2471 ibnex.ibnex_vppa_comm_svc_names = service_name;
2472 }
2473 return (0);
2474 }
2475
2476
2477 /*
2478 * ibnex_port_conf_entry_delete()
2479 * Delete an existing service entry from ibnex data base of
2480 * Port communication services.
2481 */
2482 static int
ibnex_port_conf_entry_delete(char * msg,char * service)2483 ibnex_port_conf_entry_delete(char *msg, char *service)
2484 {
2485 int i, j, nsvcs;
2486 int match_ndx;
2487 int len;
2488 char **service_name;
2489 boolean_t found = B_FALSE;
2490 ibnex_node_data_t *node_datap = ibnex.ibnex_port_node_head;
2491
2492 IBTF_DPRINTF_L4("ibnex", "\tport_conf_entry_delete: %s", service);
2493
2494 ASSERT(MUTEX_HELD(&ibnex.ibnex_mutex));
2495 nsvcs = ibnex.ibnex_num_comm_svcs;
2496
2497 /* find matching index */
2498 for (i = 0; i < nsvcs; i++) {
2499 if (strcmp(ibnex.ibnex_comm_svc_names[i], service))
2500 continue;
2501 found = B_TRUE;
2502 match_ndx = i;
2503 break;
2504 }
2505
2506 /* check for valid "nsvcs" */
2507 if (found == B_FALSE || nsvcs == 0) {
2508 IBTF_DPRINTF_L2("ibnex", "%s: invalid services %x", msg, nsvcs);
2509 return (EIO);
2510 }
2511
2512 /* Check if service is in use; return failure if so */
2513 for (; node_datap; node_datap = node_datap->node_next) {
2514 if ((node_datap->node_data.port_node.port_commsvc_idx == i) &&
2515 node_datap->node_type == IBNEX_PORT_COMMSVC_NODE &&
2516 node_datap->node_dip)
2517 return (EIO);
2518 }
2519
2520 /* if nsvcs == 1, bailout early */
2521 if (nsvcs == 1) {
2522 /* free up that single entry */
2523 len = strlen(ibnex.ibnex_comm_svc_names[0]) + 1;
2524 kmem_free(ibnex.ibnex_comm_svc_names[0], len);
2525 kmem_free(ibnex.ibnex_comm_svc_names, sizeof (char *));
2526 ibnex.ibnex_comm_svc_names = NULL;
2527 ibnex.ibnex_num_comm_svcs = 0;
2528 return (0);
2529 }
2530
2531 /* Allocate space for new "ibnex.ibnex_num_comm_svcs - 1" */
2532 service_name = kmem_alloc((nsvcs - 1) * sizeof (char *), KM_SLEEP);
2533 /*
2534 * Copy over the existing "ibnex.ibnex_comm_svc_names" array.
2535 * Skip the matching service.
2536 */
2537 for (i = 0, j = 0; i < nsvcs; i++) {
2538 if (i == match_ndx) {
2539 /* free up that entry */
2540 len = strlen(ibnex.ibnex_comm_svc_names[i]) + 1;
2541 kmem_free(ibnex.ibnex_comm_svc_names[i], len);
2542 continue;
2543 }
2544 service_name[j++] = ibnex.ibnex_comm_svc_names[i];
2545 }
2546
2547 /* Replace existing pointer to Port services w/ newly adjusted one */
2548 if (ibnex.ibnex_comm_svc_names) {
2549 kmem_free(ibnex.ibnex_comm_svc_names, nsvcs * sizeof (char *));
2550 ibnex.ibnex_num_comm_svcs--;
2551 ibnex.ibnex_comm_svc_names = service_name;
2552 }
2553 return (0);
2554 }
2555
2556 /*
2557 * ibnex_hcasvc_conf_entry_delete()
2558 * Delete an existing service entry from ibnex data base of
2559 * HCA_SVC communication services.
2560 */
2561 static int
ibnex_hcasvc_conf_entry_delete(char * msg,char * service)2562 ibnex_hcasvc_conf_entry_delete(char *msg, char *service)
2563 {
2564 int i, j, nsvcs;
2565 int len;
2566 int match_ndx;
2567 char **service_name;
2568 boolean_t found = B_FALSE;
2569 ibnex_node_data_t *node_datap = ibnex.ibnex_port_node_head;
2570
2571 IBTF_DPRINTF_L4("ibnex", "\thcasvc_conf_entry_delete: %s", service);
2572
2573 ASSERT(MUTEX_HELD(&ibnex.ibnex_mutex));
2574 nsvcs = ibnex.ibnex_nhcasvc_comm_svcs;
2575
2576 /* find matching index */
2577 for (i = 0; i < nsvcs; i++) {
2578 if (strcmp(ibnex.ibnex_hcasvc_comm_svc_names[i], service))
2579 continue;
2580 found = B_TRUE;
2581 match_ndx = i;
2582 break;
2583 }
2584
2585 /* check for valid "nsvcs" */
2586 if (found == B_FALSE || nsvcs == 0) {
2587 IBTF_DPRINTF_L2("ibnex", "%s: invalid hca_svc services %x",
2588 msg, nsvcs);
2589 return (EIO);
2590 }
2591
2592 /* Check if service is in use; return failure if so */
2593 for (; node_datap; node_datap = node_datap->node_next) {
2594 if ((node_datap->node_data.port_node.port_commsvc_idx == i) &&
2595 node_datap->node_type == IBNEX_HCASVC_COMMSVC_NODE &&
2596 node_datap->node_dip) {
2597 IBTF_DPRINTF_L2("ibnex", "%s: service %s is in use",
2598 msg, service);
2599 return (EIO);
2600 }
2601 }
2602
2603 /* if nsvcs == 1, bailout early */
2604 if (nsvcs == 1) {
2605 /* free up that single entry */
2606 len = strlen(ibnex.ibnex_hcasvc_comm_svc_names[0]) + 1;
2607 kmem_free(ibnex.ibnex_hcasvc_comm_svc_names[0], len);
2608 kmem_free(ibnex.ibnex_hcasvc_comm_svc_names, sizeof (char *));
2609 ibnex.ibnex_hcasvc_comm_svc_names = NULL;
2610 ibnex.ibnex_nhcasvc_comm_svcs = 0;
2611 return (0);
2612 }
2613
2614 /* Allocate space for new "ibnex.ibnex_nhcasvc_comm_svcs - 1" */
2615 service_name = kmem_alloc((nsvcs - 1) * sizeof (char *), KM_SLEEP);
2616 /*
2617 * Copy over the existing "ibnex.ibnex_hcasvc_comm_svc_names"
2618 * array. Do not copy over the matching service.
2619 */
2620 for (i = 0, j = 0; i < nsvcs; i++) {
2621 if (i == match_ndx) {
2622 /* free up that entry */
2623 len = strlen(ibnex.ibnex_hcasvc_comm_svc_names[i]) + 1;
2624 kmem_free(ibnex.ibnex_hcasvc_comm_svc_names[i], len);
2625 continue;
2626 }
2627 service_name[j++] = ibnex.ibnex_hcasvc_comm_svc_names[i];
2628 }
2629
2630 /* Replace existing pointer to VPPA services w/ newly adjusted one */
2631 if (ibnex.ibnex_hcasvc_comm_svc_names) {
2632 kmem_free(ibnex.ibnex_hcasvc_comm_svc_names, nsvcs *
2633 sizeof (char *));
2634 ibnex.ibnex_nhcasvc_comm_svcs--;
2635 ibnex.ibnex_hcasvc_comm_svc_names = service_name;
2636 }
2637 return (0);
2638 }
2639
2640
2641 /*
2642 * ibnex_ioc_fininode()
2643 * Un-initialize a child device node for IOC device node
2644 * Returns IBNEX_SUCCESS/IBNEX_FAILURE
2645 */
2646 static ibnex_rval_t
ibnex_ioc_fininode(dev_info_t * dip,ibnex_ioc_node_t * ioc_nodep)2647 ibnex_ioc_fininode(dev_info_t *dip, ibnex_ioc_node_t *ioc_nodep)
2648 {
2649 int rval = MDI_SUCCESS;
2650
2651 ASSERT(MUTEX_HELD(&ibnex.ibnex_mutex));
2652 IBTF_DPRINTF_L4("ibnex", "\tioc_fininode");
2653
2654 /*
2655 * For a dis-connected IOC,
2656 * Free the ioc_profile &&
2657 * decrement ibnex_num_disconnect_iocs
2658 */
2659 if (ioc_nodep->ioc_ngids == 0 && ioc_nodep->ioc_profile) {
2660 IBTF_DPRINTF_L4("ibnex", "\tioc_fininode: unconfigure "
2661 "disconnected IOC: GUID %lX", ioc_nodep->ioc_guid);
2662 ibnex.ibnex_num_disconnect_iocs--;
2663 kmem_free(ioc_nodep->ioc_profile,
2664 sizeof (ib_dm_ioc_ctrl_profile_t));
2665 ioc_nodep->ioc_profile = NULL;
2666 }
2667
2668 mutex_exit(&ibnex.ibnex_mutex);
2669 ASSERT(i_ddi_node_state(dip) >= DS_BOUND);
2670
2671 IBTF_DPRINTF_L4("ibnex", "\tioc_fininode: offlining the IOC");
2672 rval = ibnex_offline_childdip(dip);
2673
2674 if (rval != MDI_SUCCESS) {
2675 rval = NDI_FAILURE;
2676 IBTF_DPRINTF_L2("ibnex", "\toffline failed for IOC "
2677 "dip %p with 0x%x", dip, rval);
2678 }
2679
2680 mutex_enter(&ibnex.ibnex_mutex);
2681 return (rval == MDI_SUCCESS ? IBNEX_SUCCESS : IBNEX_OFFLINE_FAILED);
2682 }
2683
2684
2685 int
ibnex_offline_childdip(dev_info_t * dip)2686 ibnex_offline_childdip(dev_info_t *dip)
2687 {
2688 int rval = MDI_SUCCESS, rval2;
2689 mdi_pathinfo_t *path = NULL, *temp;
2690
2691 IBTF_DPRINTF_L4("ibnex", "\toffline_childdip; begin");
2692 if (dip == NULL) {
2693 IBTF_DPRINTF_L2("ibnex", "\toffline_childdip; NULL dip");
2694 return (MDI_FAILURE);
2695 }
2696
2697 for (path = mdi_get_next_phci_path(dip, path); path; ) {
2698 IBTF_DPRINTF_L4("ibnex", "\toffline_childdip: "
2699 "offling path %p", path);
2700 rval2 = MDI_SUCCESS;
2701 if (MDI_PI_IS_ONLINE(path)) {
2702 rval2 = mdi_pi_offline(path, NDI_UNCONFIG);
2703 /* If it cannot be offlined, log this path and error */
2704 if (rval2 != MDI_SUCCESS) {
2705 rval = rval2;
2706 cmn_err(CE_WARN,
2707 "!ibnex\toffline_childdip (0x%p): "
2708 "mdi_pi_offline path (0x%p) failed with %d",
2709 (void *)dip, (void *)path, rval2);
2710 }
2711 }
2712 /* prepare the next path */
2713 temp = path;
2714 path = mdi_get_next_phci_path(dip, path);
2715 /* free the offline path */
2716 if (rval2 == MDI_SUCCESS) {
2717 (void) mdi_pi_free(temp, 0);
2718 }
2719 }
2720 return (rval);
2721 }
2722
2723
2724 /*
2725 * ibnex_commsvc_fininode()
2726 *
2727 * Un-initialize a child device node for HCA port / node GUID
2728 * for a communication service.
2729 * Returns IBNEX_SUCCESS/IBNEX_FAILURE
2730 */
2731 static ibnex_rval_t
ibnex_commsvc_fininode(dev_info_t * dip)2732 ibnex_commsvc_fininode(dev_info_t *dip)
2733 {
2734 int rval = NDI_SUCCESS;
2735
2736 ASSERT(MUTEX_HELD(&ibnex.ibnex_mutex));
2737 IBTF_DPRINTF_L4("ibnex", "\tcommsvc_fininode");
2738
2739 mutex_exit(&ibnex.ibnex_mutex);
2740 if (i_ddi_node_state(dip) < DS_BOUND) {
2741 /*
2742 * if the child hasn't been bound yet, we can
2743 * just free the dip. This path is currently
2744 * untested.
2745 */
2746 (void) ddi_remove_child(dip, 0);
2747 IBTF_DPRINTF_L4("ibnex",
2748 "\tcommsvc_fininode: ddi_remove_child");
2749 } else {
2750 IBTF_DPRINTF_L4("ibnex", "\tcommsvc_fininode: offlining the "
2751 "Commsvc node");
2752
2753 rval = ndi_devi_offline(dip, NDI_DEVI_REMOVE | NDI_UNCONFIG);
2754 if (rval != NDI_SUCCESS)
2755 IBTF_DPRINTF_L2("ibnex", "\toffline failed for Commsvc "
2756 "dip %p with 0x%x", dip, rval);
2757 }
2758 mutex_enter(&ibnex.ibnex_mutex);
2759 return (rval == NDI_SUCCESS ? IBNEX_SUCCESS : IBNEX_OFFLINE_FAILED);
2760 }
2761
2762
2763 /*
2764 * ibnex_pseudo_fininode()
2765 * Un-initialize a child pseudo device node
2766 * Returns IBNEX_SUCCESS/IBNEX_FAILURE
2767 */
2768 static ibnex_rval_t
ibnex_pseudo_fininode(dev_info_t * dip)2769 ibnex_pseudo_fininode(dev_info_t *dip)
2770 {
2771 int rval = MDI_SUCCESS;
2772
2773 ASSERT(MUTEX_HELD(&ibnex.ibnex_mutex));
2774 IBTF_DPRINTF_L4("ibnex", "\tpseudo_fininode: dip = %p", dip);
2775
2776 mutex_exit(&ibnex.ibnex_mutex);
2777 ASSERT(i_ddi_node_state(dip) >= DS_BOUND);
2778
2779 IBTF_DPRINTF_L4("ibnex", "\tpseudo_fininode: offlining the "
2780 "pseudo device");
2781 rval = ibnex_offline_childdip(dip);
2782 if (rval != MDI_SUCCESS) {
2783 rval = NDI_FAILURE;
2784 IBTF_DPRINTF_L2("ibnex", "\tpseudo offline failed for "
2785 "dip %p with 0x%x", dip, rval);
2786 }
2787
2788 mutex_enter(&ibnex.ibnex_mutex);
2789 return (rval == MDI_SUCCESS ? IBNEX_SUCCESS : IBNEX_OFFLINE_FAILED);
2790 }
2791
2792 /*
2793 * IOCTL implementation to get api version number.
2794 */
2795 static int
ibnex_ctl_get_api_ver(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * credp,int * rvalp)2796 ibnex_ctl_get_api_ver(dev_t dev, int cmd, intptr_t arg, int mode,
2797 cred_t *credp, int *rvalp)
2798 {
2799 ibnex_ctl_api_ver_t api_ver;
2800
2801 IBTF_DPRINTF_L4("ibnex", "\tctl_get_api_ver: cmd=%x, arg=%p, "
2802 "mode=%x, cred=%p, rval=%p, dev=0x%x", cmd, arg, mode, credp,
2803 rvalp, dev);
2804
2805 api_ver.api_ver_num = IBNEX_CTL_API_VERSION;
2806
2807 if (ddi_copyout(&api_ver, (void *)arg, sizeof (ibnex_ctl_api_ver_t),
2808 mode) != 0) {
2809 IBTF_DPRINTF_L2("ibnex",
2810 "\tctl_get_api_ver: ddi_copyout err");
2811 return (EFAULT);
2812 }
2813
2814 return (0);
2815 }
2816
2817 /*
2818 * IOCTL implementation to get the list of HCAs
2819 */
2820 static int
ibnex_ctl_get_hca_list(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * credp,int * rvalp)2821 ibnex_ctl_get_hca_list(dev_t dev, int cmd, intptr_t arg, int mode,
2822 cred_t *credp, int *rvalp)
2823 {
2824 ibnex_ctl_get_hca_list_t hca_list;
2825 int rv = 0;
2826 uint_t *in_nhcasp;
2827 uint_t nhcas, n;
2828 ib_guid_t *hca_guids;
2829
2830 IBTF_DPRINTF_L4("ibnex", "\tctl_get_hca_list: cmd=%x, arg=%p, "
2831 "mode=%x, cred=%p, rval=%p, dev=0x%x", cmd, arg, mode, credp,
2832 rvalp, dev);
2833
2834 #ifdef _MULTI_DATAMODEL
2835 if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
2836 ibnex_ctl_get_hca_list_32_t hca_list_32;
2837
2838 if (ddi_copyin((void *)arg, &hca_list_32,
2839 sizeof (ibnex_ctl_get_hca_list_32_t), mode) != 0) {
2840 IBTF_DPRINTF_L2("ibnex",
2841 "\tctl_get_hca_list: ddi_copyin err 1");
2842 return (EFAULT);
2843 }
2844
2845 hca_list.hca_guids_alloc_sz = hca_list_32.hca_guids_alloc_sz;
2846 hca_list.hca_guids =
2847 (ib_guid_t *)(uintptr_t)hca_list_32.hca_guids;
2848 in_nhcasp = &((ibnex_ctl_get_hca_list_32_t *)arg)->nhcas;
2849 } else
2850 #endif
2851 {
2852 if (ddi_copyin((void *)arg, &hca_list,
2853 sizeof (ibnex_ctl_get_hca_list_t), mode) != 0) {
2854 IBTF_DPRINTF_L2("ibnex",
2855 "\tctl_get_hca_list: ddi_copyin err 2");
2856 return (EFAULT);
2857 }
2858
2859 in_nhcasp = &((ibnex_ctl_get_hca_list_t *)arg)->nhcas;
2860 }
2861
2862 nhcas = ibt_get_hca_list(&hca_guids);
2863
2864 /* copy number of hcas to user space */
2865 if (ddi_copyout(&nhcas, in_nhcasp, sizeof (uint_t), mode) != 0) {
2866 IBTF_DPRINTF_L2("ibnex",
2867 "\tctl_get_hca_list: ddi_copyout err 1");
2868 rv = EFAULT;
2869 goto out;
2870 }
2871
2872 n = MIN(nhcas, hca_list.hca_guids_alloc_sz);
2873 if (n == 0)
2874 goto out;
2875
2876 /* copy HCA guids to user space */
2877 if (ddi_copyout(hca_guids, hca_list.hca_guids,
2878 n * sizeof (ib_guid_t), mode) != 0) {
2879 IBTF_DPRINTF_L2("ibnex",
2880 "\tctl_get_hca_list: ddi_copyout err 2");
2881 rv = EFAULT;
2882 }
2883
2884 out:
2885 if (nhcas > 0)
2886 ibt_free_hca_list(hca_guids, nhcas);
2887
2888 return (rv);
2889 }
2890
2891 #define IBNEX_CTL_CP_HCA_INFO(x, y, driver_name, instance, device_path, \
2892 device_path_alloc_sz, device_path_len) \
2893 { \
2894 (x)->hca_node_guid = (y)->hca_node_guid; \
2895 (x)->hca_si_guid = (y)->hca_si_guid; \
2896 (x)->hca_nports = (y)->hca_nports; \
2897 (x)->hca_flags = (y)->hca_flags; \
2898 (x)->hca_flags2 = (y)->hca_flags2; \
2899 (x)->hca_vendor_id = (y)->hca_vendor_id; \
2900 (x)->hca_device_id = (y)->hca_device_id; \
2901 (x)->hca_version_id = (y)->hca_version_id; \
2902 (x)->hca_max_chans = (y)->hca_max_chans; \
2903 (x)->hca_max_chan_sz = (y)->hca_max_chan_sz; \
2904 (x)->hca_max_sgl = (y)->hca_max_sgl; \
2905 (x)->hca_max_cq = (y)->hca_max_cq; \
2906 (x)->hca_max_cq_sz = (y)->hca_max_cq_sz; \
2907 (x)->hca_page_sz = (y)->hca_page_sz; \
2908 (x)->hca_max_memr = (y)->hca_max_memr; \
2909 (x)->hca_max_memr_len = (y)->hca_max_memr_len; \
2910 (x)->hca_max_mem_win = (y)->hca_max_mem_win; \
2911 (x)->hca_max_rsc = (y)->hca_max_rsc; \
2912 (x)->hca_max_rdma_in_chan = (y)->hca_max_rdma_in_chan; \
2913 (x)->hca_max_rdma_out_chan = (y)->hca_max_rdma_out_chan; \
2914 (x)->hca_max_ipv6_chan = (y)->hca_max_ipv6_chan; \
2915 (x)->hca_max_ether_chan = (y)->hca_max_ether_chan; \
2916 (x)->hca_max_mcg_chans = (y)->hca_max_mcg_chans; \
2917 (x)->hca_max_mcg = (y)->hca_max_mcg; \
2918 (x)->hca_max_chan_per_mcg = (y)->hca_max_chan_per_mcg; \
2919 (x)->hca_max_partitions = (y)->hca_max_partitions; \
2920 (x)->hca_local_ack_delay = (y)->hca_local_ack_delay; \
2921 (x)->hca_max_port_sgid_tbl_sz = (y)->hca_max_port_sgid_tbl_sz; \
2922 (x)->hca_max_port_pkey_tbl_sz = (y)->hca_max_port_pkey_tbl_sz; \
2923 (x)->hca_max_pd = (y)->hca_max_pd; \
2924 (x)->hca_max_ud_dest = (y)->hca_max_ud_dest; \
2925 (x)->hca_max_srqs = (y)->hca_max_srqs; \
2926 (x)->hca_max_srqs_sz = (y)->hca_max_srqs_sz; \
2927 (x)->hca_max_srq_sgl = (y)->hca_max_srq_sgl; \
2928 (x)->hca_max_cq_handlers = (y)->hca_max_cq_handlers; \
2929 (x)->hca_reserved_lkey = (y)->hca_reserved_lkey; \
2930 (x)->hca_max_fmrs = (y)->hca_max_fmrs; \
2931 (x)->hca_max_lso_size = (y)->hca_max_lso_size; \
2932 (x)->hca_max_lso_hdr_size = (y)->hca_max_lso_hdr_size; \
2933 (x)->hca_max_inline_size = (y)->hca_max_inline_size; \
2934 (x)->hca_max_cq_mod_count = (y)->hca_max_cq_mod_count; \
2935 (x)->hca_max_cq_mod_usec = (y)->hca_max_cq_mod_usec; \
2936 (x)->hca_fw_major_version = (y)->hca_fw_major_version; \
2937 (x)->hca_fw_minor_version = (y)->hca_fw_minor_version; \
2938 (x)->hca_fw_micro_version = (y)->hca_fw_micro_version; \
2939 (x)->hca_ud_send_inline_sz = (y)->hca_ud_send_inline_sz; \
2940 (x)->hca_conn_send_inline_sz = (y)->hca_conn_send_inline_sz; \
2941 (x)->hca_conn_rdmaw_inline_overhead = \
2942 (y)->hca_conn_rdmaw_inline_overhead; \
2943 (x)->hca_recv_sgl_sz = (y)->hca_recv_sgl_sz; \
2944 (x)->hca_ud_send_sgl_sz = (y)->hca_ud_send_sgl_sz; \
2945 (x)->hca_conn_send_sgl_sz = (y)->hca_conn_send_sgl_sz; \
2946 (x)->hca_conn_rdma_sgl_overhead = (y)->hca_conn_rdma_sgl_overhead; \
2947 \
2948 (void) strlcpy((x)->hca_driver_name, (driver_name), \
2949 MAX_HCA_DRVNAME_LEN); \
2950 (x)->hca_driver_instance = (instance); \
2951 \
2952 (x)->hca_device_path = (device_path); \
2953 (x)->hca_device_path_len = (device_path_len); \
2954 }
2955
2956 /*
2957 * IOCTL implementation to query HCA attributes
2958 */
2959 static int
ibnex_ctl_query_hca(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * credp,int * rvalp)2960 ibnex_ctl_query_hca(dev_t dev, int cmd, intptr_t arg, int mode,
2961 cred_t *credp, int *rvalp)
2962 {
2963 int rv = 0;
2964 ibnex_ctl_query_hca_t *query_hca = NULL;
2965 #ifdef _MULTI_DATAMODEL
2966 ibnex_ctl_query_hca_32_t *query_hca_32 = NULL;
2967 #endif
2968 ibt_hca_attr_t *hca_attr = NULL;
2969 char driver_name[MAX_HCA_DRVNAME_LEN];
2970 int instance;
2971 ib_guid_t hca_guid;
2972 char *device_path;
2973 uint_t device_path_alloc_sz, hca_device_path_len;
2974 char *hca_device_path = NULL;
2975 uint_t model;
2976
2977 IBTF_DPRINTF_L4("ibnex", "\tctl_query_hca: cmd=%x, arg=%p, "
2978 "mode=%x, cred=%p, rval=%p, dev=0x%x", cmd, arg, mode, credp,
2979 rvalp, dev);
2980
2981 switch (model = ddi_model_convert_from(mode & FMODELS)) {
2982 #ifdef _MULTI_DATAMODEL
2983 case DDI_MODEL_ILP32:
2984 query_hca_32 = kmem_zalloc(
2985 sizeof (ibnex_ctl_query_hca_32_t), KM_SLEEP);
2986
2987 if (ddi_copyin((void *)arg, query_hca_32,
2988 sizeof (ibnex_ctl_query_hca_32_t), mode) != 0) {
2989 IBTF_DPRINTF_L2("ibnex",
2990 "\tctl_query_hca: ddi_copyin err 1");
2991 rv = EFAULT;
2992 goto out;
2993 }
2994
2995 hca_guid = query_hca_32->hca_guid;
2996 device_path = (char *)(uintptr_t)query_hca_32->hca_device_path;
2997 device_path_alloc_sz = query_hca_32->hca_device_path_alloc_sz;
2998 break;
2999 #endif
3000 default:
3001 query_hca = kmem_zalloc(sizeof (ibnex_ctl_query_hca_t),
3002 KM_SLEEP);
3003
3004 if (ddi_copyin((void *)arg, query_hca,
3005 sizeof (ibnex_ctl_query_hca_t), mode) != 0) {
3006 IBTF_DPRINTF_L2("ibnex",
3007 "\tctl_query_hca: ddi_copyin err 2");
3008 rv = EFAULT;
3009 goto out;
3010 }
3011
3012 hca_guid = query_hca->hca_guid;
3013 device_path = query_hca->hca_device_path;
3014 device_path_alloc_sz = query_hca->hca_device_path_alloc_sz;
3015 break;
3016 }
3017
3018 hca_attr = kmem_zalloc(sizeof (ibt_hca_attr_t), KM_SLEEP);
3019 hca_device_path = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
3020
3021 if (ibtl_ibnex_query_hca_byguid(hca_guid, hca_attr,
3022 driver_name, sizeof (driver_name), &instance, hca_device_path)
3023 != IBT_SUCCESS) {
3024 rv = ENXIO;
3025 goto out;
3026 }
3027
3028 hca_device_path_len = strlen(hca_device_path) + 1;
3029
3030 switch (model) {
3031 char *device_path64;
3032 #ifdef _MULTI_DATAMODEL
3033 caddr32_t device_path32;
3034 case DDI_MODEL_ILP32:
3035
3036 if (device_path_alloc_sz >= hca_device_path_len)
3037 device_path32 = (uintptr_t)device_path;
3038 else
3039 device_path32 = (uintptr_t)NULL;
3040
3041 IBNEX_CTL_CP_HCA_INFO(&query_hca_32->hca_info, hca_attr,
3042 driver_name, instance, device_path32,
3043 device_path_alloc_sz, hca_device_path_len);
3044
3045 /* copy hca information to the user space */
3046 if (ddi_copyout(&query_hca_32->hca_info,
3047 &((ibnex_ctl_query_hca_32_t *)arg)->hca_info,
3048 sizeof (ibnex_ctl_hca_info_32_t), mode) != 0) {
3049 IBTF_DPRINTF_L2("ibnex",
3050 "\tctl_query_hca: ddi_copyout err 1");
3051 rv = EFAULT;
3052 goto out;
3053 }
3054 break;
3055 #endif
3056 default:
3057 if (device_path_alloc_sz >= hca_device_path_len)
3058 device_path64 = device_path;
3059 else
3060 device_path64 = NULL;
3061
3062 IBNEX_CTL_CP_HCA_INFO(&query_hca->hca_info, hca_attr,
3063 driver_name, instance, device_path64,
3064 device_path_alloc_sz, hca_device_path_len);
3065
3066 /* copy hca information to the user space */
3067 if (ddi_copyout(&query_hca->hca_info,
3068 &((ibnex_ctl_query_hca_t *)arg)->hca_info,
3069 sizeof (ibnex_ctl_hca_info_t), mode) != 0) {
3070 IBTF_DPRINTF_L2("ibnex",
3071 "\tctl_query_hca: ddi_copyout err 2");
3072 rv = EFAULT;
3073 goto out;
3074 }
3075 break;
3076 }
3077
3078 if (device_path_alloc_sz >= hca_device_path_len) {
3079 if (ddi_copyout(hca_device_path,
3080 device_path,
3081 hca_device_path_len, mode) != 0) {
3082 IBTF_DPRINTF_L2("ibnex", "\tctl_query_hca: "
3083 "ddi_copyout err copying device path");
3084 rv = EFAULT;
3085 }
3086 }
3087
3088 out:
3089 if (query_hca)
3090 kmem_free(query_hca, sizeof (ibnex_ctl_query_hca_t));
3091 #ifdef _MULTI_DATAMODEL
3092 if (query_hca_32)
3093 kmem_free(query_hca_32, sizeof (ibnex_ctl_query_hca_32_t));
3094 #endif
3095 if (hca_attr)
3096 kmem_free(hca_attr, sizeof (ibt_hca_attr_t));
3097 if (hca_device_path)
3098 kmem_free(hca_device_path, MAXPATHLEN);
3099
3100 return (rv);
3101 }
3102
3103 #define IBNEX_CTL_CP_PORT_INFO(x, y, sgid_tbl, pkey_tbl) \
3104 { \
3105 (x)->p_lid = (y)->p_opaque1; \
3106 (x)->p_qkey_violations = (y)->p_qkey_violations; \
3107 (x)->p_pkey_violations = (y)->p_pkey_violations; \
3108 (x)->p_sm_sl = (y)->p_sm_sl; \
3109 (x)->p_phys_state = (y)->p_phys_state; \
3110 (x)->p_sm_lid = (y)->p_sm_lid; \
3111 (x)->p_linkstate = (y)->p_linkstate; \
3112 (x)->p_port_num = (y)->p_port_num; \
3113 (x)->p_width_supported = (y)->p_width_supported; \
3114 (x)->p_width_enabled = (y)->p_width_enabled; \
3115 (x)->p_width_active = (y)->p_width_active; \
3116 (x)->p_mtu = (y)->p_mtu; \
3117 (x)->p_lmc = (y)->p_lmc; \
3118 (x)->p_speed_supported = (y)->p_speed_supported; \
3119 (x)->p_speed_enabled = (y)->p_speed_enabled; \
3120 (x)->p_speed_active = (y)->p_speed_active; \
3121 (x)->p_sgid_tbl = (sgid_tbl); \
3122 (x)->p_sgid_tbl_sz = (y)->p_sgid_tbl_sz; \
3123 (x)->p_pkey_tbl = (pkey_tbl); \
3124 (x)->p_pkey_tbl_sz = (y)->p_pkey_tbl_sz; \
3125 (x)->p_def_pkey_ix = (y)->p_def_pkey_ix; \
3126 (x)->p_max_vl = (y)->p_max_vl; \
3127 (x)->p_init_type_reply = (y)->p_init_type_reply; \
3128 (x)->p_subnet_timeout = (y)->p_subnet_timeout; \
3129 (x)->p_capabilities = (y)->p_capabilities; \
3130 (x)->p_msg_sz = (y)->p_msg_sz; \
3131 }
3132
3133 /*
3134 * IOCTL implementation to query HCA port attributes
3135 */
3136 static int
ibnex_ctl_query_hca_port(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * credp,int * rvalp)3137 ibnex_ctl_query_hca_port(dev_t dev, int cmd, intptr_t arg, int mode,
3138 cred_t *credp, int *rvalp)
3139 {
3140 ibt_hca_portinfo_t *ibt_pi;
3141 uint_t nports;
3142 uint_t size = 0;
3143 int rv = 0;
3144 ibnex_ctl_query_hca_port_t *query_hca_port = NULL;
3145 ibnex_ctl_query_hca_port_32_t *query_hca_port_32 = NULL;
3146 uint_t sgid_tbl_sz;
3147 uint16_t pkey_tbl_sz;
3148 ibt_hca_attr_t hca_attr;
3149
3150 IBTF_DPRINTF_L4("ibnex", "\tctl_query_hca_port: cmd=%x, arg=%p, "
3151 "mode=%x, cred=%p, rval=%p, dev=0x%x", cmd, arg, mode, credp,
3152 rvalp, dev);
3153
3154 query_hca_port = kmem_zalloc(sizeof (ibnex_ctl_query_hca_port_t),
3155 KM_SLEEP);
3156
3157 #ifdef _MULTI_DATAMODEL
3158 if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
3159 query_hca_port_32 = kmem_zalloc(
3160 sizeof (ibnex_ctl_query_hca_port_32_t), KM_SLEEP);
3161
3162 if (ddi_copyin((void *)arg, query_hca_port_32,
3163 sizeof (ibnex_ctl_query_hca_port_32_t), mode) != 0) {
3164 IBTF_DPRINTF_L2("ibnex",
3165 "\tctl_query_hca_port: ddi_copyin err 1");
3166 rv = EFAULT;
3167 goto out;
3168 }
3169
3170 query_hca_port->hca_guid = query_hca_port_32->hca_guid;
3171 query_hca_port->port_num = query_hca_port_32->port_num;
3172
3173 query_hca_port->sgid_tbl =
3174 (ib_gid_t *)(uintptr_t)query_hca_port_32->sgid_tbl;
3175 query_hca_port->sgid_tbl_alloc_sz =
3176 query_hca_port_32->sgid_tbl_alloc_sz;
3177
3178 query_hca_port->pkey_tbl =
3179 (ib_pkey_t *)(uintptr_t)query_hca_port_32->pkey_tbl;
3180 query_hca_port->pkey_tbl_alloc_sz =
3181 query_hca_port_32->pkey_tbl_alloc_sz;
3182
3183 } else
3184 #endif
3185 {
3186 if (ddi_copyin((void *)arg, query_hca_port,
3187 sizeof (ibnex_ctl_query_hca_port_t), mode) != 0) {
3188 IBTF_DPRINTF_L2("ibnex",
3189 "\tctl_query_hca_port: ddi_copyin err 2");
3190 rv = EFAULT;
3191 goto out;
3192 }
3193 }
3194
3195 if (ibt_query_hca_byguid(query_hca_port->hca_guid, &hca_attr) !=
3196 IBT_SUCCESS) {
3197 rv = ENXIO;
3198 goto out;
3199 }
3200
3201 if (query_hca_port->port_num == 0 ||
3202 query_hca_port->port_num > hca_attr.hca_nports) {
3203 rv = ENOENT;
3204 goto out;
3205 }
3206
3207 /*
3208 * Query hca port attributes and copy them to the user space.
3209 */
3210
3211 if (ibt_query_hca_ports_byguid(query_hca_port->hca_guid,
3212 query_hca_port->port_num, &ibt_pi, &nports, &size) != IBT_SUCCESS) {
3213 rv = ENXIO;
3214 goto out;
3215 }
3216
3217 sgid_tbl_sz = MIN(query_hca_port->sgid_tbl_alloc_sz,
3218 ibt_pi->p_sgid_tbl_sz);
3219
3220 pkey_tbl_sz = MIN(query_hca_port->pkey_tbl_alloc_sz,
3221 ibt_pi->p_pkey_tbl_sz);
3222
3223 #ifdef _MULTI_DATAMODEL
3224 if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
3225 IBNEX_CTL_CP_PORT_INFO(
3226 &query_hca_port_32->port_info, ibt_pi,
3227 query_hca_port_32->sgid_tbl, query_hca_port_32->pkey_tbl);
3228
3229 if (ddi_copyout(&query_hca_port_32->port_info,
3230 &((ibnex_ctl_query_hca_port_32_t *)arg)->port_info,
3231 sizeof (ibnex_ctl_hca_port_info_32_t), mode) != 0 ||
3232
3233 ddi_copyout(ibt_pi->p_sgid_tbl,
3234 query_hca_port->sgid_tbl,
3235 sgid_tbl_sz * sizeof (ib_gid_t), mode) != 0 ||
3236
3237 ddi_copyout(ibt_pi->p_pkey_tbl,
3238 query_hca_port->pkey_tbl,
3239 pkey_tbl_sz * sizeof (ib_pkey_t), mode) != 0) {
3240
3241 IBTF_DPRINTF_L2("ibnex",
3242 "\tctl_query_hca_port: ddi_copyout err 2");
3243 rv = EFAULT;
3244 goto out;
3245 }
3246 } else
3247 #endif
3248 {
3249 IBNEX_CTL_CP_PORT_INFO(
3250 &query_hca_port->port_info, ibt_pi,
3251 query_hca_port->sgid_tbl, query_hca_port->pkey_tbl);
3252
3253 if (ddi_copyout(&query_hca_port->port_info,
3254 &((ibnex_ctl_query_hca_port_t *)arg)->port_info,
3255 sizeof (ibnex_ctl_hca_port_info_t), mode) != 0 ||
3256
3257 ddi_copyout(ibt_pi->p_sgid_tbl,
3258 query_hca_port->sgid_tbl,
3259 sgid_tbl_sz * sizeof (ib_gid_t), mode) != 0 ||
3260
3261 ddi_copyout(ibt_pi->p_pkey_tbl,
3262 query_hca_port->pkey_tbl,
3263 pkey_tbl_sz * sizeof (ib_pkey_t), mode) != 0) {
3264
3265 IBTF_DPRINTF_L2("ibnex",
3266 "\tctl_query_hca_port: ddi_copyout err 2");
3267 rv = EFAULT;
3268 goto out;
3269 }
3270 }
3271
3272 out:
3273 if (size > 0)
3274 ibt_free_portinfo(ibt_pi, size);
3275
3276 if (query_hca_port)
3277 kmem_free(query_hca_port, sizeof (ibnex_ctl_query_hca_port_t));
3278
3279 if (query_hca_port_32)
3280 kmem_free(query_hca_port_32,
3281 sizeof (ibnex_ctl_query_hca_port_32_t));
3282 return (rv);
3283 }
3284