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