xref: /illumos-gate/usr/src/lib/libdladm/common/libdlib.c (revision a4955f4fa65e38d70c07d38e657a9aff43fa155f)
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) 2010, Oracle and/or its affiliates. All rights reserved.
23  */
24 
25 #include <stdio.h>
26 #include <libdevinfo.h>
27 #include <sys/types.h>
28 #include <sys/stat.h>
29 #include <string.h>
30 #include <fcntl.h>
31 #include <unistd.h>
32 #include <stropts.h>
33 #include <stdlib.h>
34 #include <errno.h>
35 #include <strings.h>
36 #include <libintl.h>
37 #include <net/if_types.h>
38 #include <net/if_dl.h>
39 #include <sys/dld.h>
40 #include <sys/ib/ib_types.h>
41 #include <sys/ibpart.h>
42 #include <libdllink.h>
43 #include <libdladm.h>
44 #include <libdlib.h>
45 #include <libdladm_impl.h>
46 
47 /*
48  * IP over IB administration API; see PSARC/2010/085
49  */
50 
51 /*
52  * Function prototypes
53  */
54 dladm_status_t dladm_part_create(dladm_handle_t, datalink_id_t, ib_pkey_t,
55     uint32_t, char *, datalink_id_t *, dladm_arg_list_t *);
56 static dladm_status_t	i_dladm_part_create(dladm_handle_t,
57     dladm_part_attr_t *);
58 static dladm_status_t	dladm_part_persist_conf(dladm_handle_t, const char *,
59     dladm_part_attr_t *);
60 static dladm_status_t i_dladm_part_delete(dladm_handle_t, datalink_id_t);
61 dladm_status_t	dladm_part_delete(dladm_handle_t, datalink_id_t, int);
62 static int	i_dladm_part_up(dladm_handle_t, datalink_id_t, void *);
63 dladm_status_t	dladm_part_up(dladm_handle_t, datalink_id_t, uint32_t);
64 
65 /*
66  * Convert a error status returned by the IP over IB kernel driver to a
67  * valid dladm status.
68  */
69 static dladm_status_t
70 dladm_ib_ioctl_err2status(int err)
71 {
72 	switch (err) {
73 	case 0:
74 		return (DLADM_STATUS_OK);
75 	case IBD_INVALID_PORT_INST:
76 		return (DLADM_STATUS_INVALID_PORT_INSTANCE);
77 	case IBD_PORT_IS_DOWN:
78 		return (DLADM_STATUS_PORT_IS_DOWN);
79 	case IBD_PKEY_NOT_PRESENT:
80 		return (DLADM_STATUS_PKEY_NOT_PRESENT);
81 	case IBD_PARTITION_EXISTS:
82 		return (DLADM_STATUS_PARTITION_EXISTS);
83 	case IBD_INVALID_PKEY:
84 		return (DLADM_STATUS_INVALID_PKEY);
85 	case IBD_NO_HW_RESOURCE:
86 		return (DLADM_STATUS_NO_IB_HW_RESOURCE);
87 	case IBD_INVALID_PKEY_TBL_SIZE:
88 		return (DLADM_STATUS_INVALID_PKEY_TBL_SIZE);
89 	default:
90 		return (DLADM_STATUS_FAILED);
91 	}
92 }
93 
94 static dladm_status_t
95 i_dladm_ib_ioctl(dladm_handle_t handle, int ioccmd, ibd_ioctl_t *iocp)
96 {
97 	if (ioctl(dladm_dld_fd(handle), ioccmd, iocp) == 0)
98 		return (DLADM_STATUS_OK);
99 
100 	if (iocp->ioc_status == 0)
101 		return (dladm_errno2status(errno));
102 
103 	return (dladm_ib_ioctl_err2status(iocp->ioc_status));
104 }
105 
106 /*
107  * Get the active configuration information for the partition given by
108  * the 'linkid'.
109  */
110 static dladm_status_t
111 i_dladm_part_info_active(dladm_handle_t handle, datalink_id_t linkid,
112     dladm_part_attr_t *attrp)
113 {
114 	ibpart_ioctl_t ioc;
115 	dladm_status_t status = DLADM_STATUS_OK;
116 
117 	bzero(&ioc, sizeof (ioc));
118 	bzero(attrp, sizeof (*attrp));
119 	/*
120 	 * The ioc_linkid here will contain the data link id of the IB partition
121 	 * object.
122 	 */
123 	ioc.ibdioc.ioc_linkid = linkid;
124 	ioc.ibdioc.ioc_info_cmd = IBD_INFO_CMD_IBPART;
125 
126 	status = i_dladm_ib_ioctl(handle, IBD_INFO_IBPART, (ibd_ioctl_t *)&ioc);
127 	if (status != DLADM_STATUS_OK)
128 		goto bail;
129 
130 	/*
131 	 * On return from the ioctl ioc_linkid field contains the IB port's
132 	 * linkid.
133 	 */
134 	attrp->dia_physlinkid = ioc.ibdioc.ioc_linkid;
135 	attrp->dia_partlinkid = ioc.ioc_partid;
136 	attrp->dia_pkey = ioc.ioc_pkey;
137 	attrp->dia_portnum = ioc.ibdioc.ioc_portnum;
138 	attrp->dia_hca_guid = ioc.ibdioc.ioc_hcaguid;
139 	attrp->dia_port_guid = ioc.ibdioc.ioc_portguid;
140 	attrp->dia_instance = ioc.ibdioc.ioc_port_inst;
141 
142 	/*
143 	 * If the IP over IB driver reports that this partition was created
144 	 * forcibly, then set the force create flag.
145 	 */
146 	if (ioc.ioc_force_create)
147 		attrp->dia_flags |= DLADM_PART_FORCE_CREATE;
148 
149 bail:
150 	return (status);
151 }
152 
153 /*
154  * Get the configuration information about the IB partition 'linkid' from the
155  * persistent configuration.
156  */
157 static dladm_status_t
158 i_dladm_part_info_persist(dladm_handle_t handle, datalink_id_t linkid,
159     dladm_part_attr_t *attrp)
160 {
161 	dladm_conf_t conf;
162 	dladm_status_t status;
163 	char linkover[MAXLINKNAMELEN];
164 	datalink_class_t class;
165 	boolean_t force = B_FALSE;
166 
167 	conf.ds_readonly = B_FALSE;
168 	conf.ds_confid = DLADM_INVALID_CONF;
169 
170 	/* Get the IB partition's datalink ID */
171 	if ((status = dladm_datalink_id2info(handle, linkid, NULL, &class,
172 	    NULL, NULL, 0)) != DLADM_STATUS_OK)
173 		goto done;
174 
175 	bzero(attrp, sizeof (*attrp));
176 	attrp->dia_partlinkid = linkid;
177 	if ((status = dladm_getsnap_conf(handle, linkid, &conf)) !=
178 	    DLADM_STATUS_OK)
179 		return (status);
180 
181 	/*
182 	 * Get the name of the IB Phys link over which IB partition was
183 	 * created.
184 	 */
185 	status = dladm_get_conf_field(handle, conf, FLINKOVER, linkover,
186 	    sizeof (linkover));
187 	if (status != DLADM_STATUS_OK) {
188 		attrp->dia_physlinkid = DATALINK_INVALID_LINKID;
189 		goto done;
190 	} else {
191 		/* Get the IB Phys link's datalink ID */
192 		if ((status = dladm_name2info(handle, linkover,
193 		    &attrp->dia_physlinkid, NULL, NULL, NULL)) !=
194 		    DLADM_STATUS_OK)
195 			goto done;
196 	}
197 
198 	/* Get the IB partition's P_Key */
199 	status = dladm_get_conf_field(handle, conf, FPORTPKEY,
200 	    &attrp->dia_pkey, sizeof (uint64_t));
201 	if (status != DLADM_STATUS_OK)
202 		goto done;
203 
204 	if (class != DATALINK_CLASS_PART) {
205 		status = DLADM_STATUS_BADARG;
206 		goto done;
207 	}
208 
209 	/*
210 	 * If the FFORCE field is set in the persistent configuration database
211 	 * set the force create flag in the partition attributes.
212 	 */
213 	status = dladm_get_conf_field(handle, conf, FFORCE, &force,
214 	    sizeof (boolean_t));
215 	if (status != DLADM_STATUS_OK) {
216 		if (status != DLADM_STATUS_NOTFOUND)
217 			goto done;
218 	} else if (force == B_TRUE) {
219 		attrp->dia_flags |= DLADM_PART_FORCE_CREATE;
220 	}
221 
222 	status = DLADM_STATUS_OK;
223 done:
224 	dladm_destroy_conf(handle, conf);
225 	return (status);
226 }
227 
228 /*
229  * Get the configuration information for the IB partition given by the datalink
230  * ID 'linkid'. Based on the 'flags' field the information is either from the
231  * active system (DLADM_OPT_ACTIVE) or from the persistent configuration
232  * database.
233  */
234 dladm_status_t
235 dladm_part_info(dladm_handle_t handle, datalink_id_t linkid,
236     dladm_part_attr_t *attrp, uint32_t flags)
237 {
238 	if (flags == DLADM_OPT_ACTIVE)
239 		return (i_dladm_part_info_active(handle, linkid, attrp));
240 	else if (flags == DLADM_OPT_PERSIST)
241 		return (i_dladm_part_info_persist(handle, linkid, attrp));
242 	else
243 		return (DLADM_STATUS_BADARG);
244 }
245 
246 /*
247  * Get the configuration information for the IB Phys link given by the datalink
248  * ID 'linkid'.
249  */
250 /* ARGSUSED */
251 dladm_status_t
252 dladm_ib_info(dladm_handle_t handle, datalink_id_t linkid,
253     dladm_ib_attr_t *attrp, uint32_t flags)
254 {
255 	uint_t instance;
256 	ibport_ioctl_t ioc;
257 	dladm_phys_attr_t	dpa;
258 	dladm_status_t status = DLADM_STATUS_OK;
259 
260 	/*
261 	 * We need to get the device name of the IB Phys link to get the
262 	 * correct instance number of the IP over IB driver instance.
263 	 */
264 	if (dladm_phys_info(handle, linkid, &dpa, DLADM_OPT_ACTIVE)
265 	    != DLADM_STATUS_OK)
266 		return (DLADM_STATUS_BADARG);
267 
268 	/*
269 	 * Get the instance number of the IP over IB driver instance which
270 	 * represents this IB Phys link.
271 	 */
272 	if (dladm_parselink(dpa.dp_dev, NULL, &instance) != DLADM_STATUS_OK)
273 		return (DLADM_STATUS_FAILED);
274 
275 	bzero(&ioc, sizeof (ioc));
276 	/*
277 	 * The ioc_linkid here will contain IB port linkid here. We make the
278 	 * first ioctl call to get the P_Key table size for this HCA port.
279 	 */
280 	ioc.ibdioc.ioc_linkid = linkid;
281 	ioc.ibdioc.ioc_info_cmd = IBD_INFO_CMD_PKEYTBLSZ;
282 	ioc.ioc_pkey_tbl_sz = 0;
283 	ioc.ibdioc.ioc_port_inst = instance;
284 
285 	status = i_dladm_ib_ioctl(handle, IBD_INFO_IBPART, (ibd_ioctl_t *)&ioc);
286 	if (status != DLADM_STATUS_OK)
287 		return (status);
288 
289 	/*
290 	 * Now allocate the memory for the P_Key table based on the table size
291 	 * return by the ioctl.
292 	 */
293 	ioc.ioc_pkeys = calloc(sizeof (ib_pkey_t), ioc.ioc_pkey_tbl_sz);
294 	if (ioc.ioc_pkeys == NULL) {
295 		status = dladm_errno2status(errno);
296 		goto bail;
297 	}
298 
299 	/*
300 	 * Call the ioctl again to get the P_Key table and other IB Phys link
301 	 * attributes.
302 	 */
303 	ioc.ibdioc.ioc_linkid = linkid;
304 	ioc.ibdioc.ioc_port_inst = instance;
305 	ioc.ibdioc.ioc_info_cmd = IBD_INFO_CMD_IBPORT;
306 
307 	status = i_dladm_ib_ioctl(handle, IBD_INFO_IBPART, (ibd_ioctl_t *)&ioc);
308 	if (status != DLADM_STATUS_OK)
309 		goto bail;
310 
311 	attrp->dia_physlinkid = ioc.ibdioc.ioc_linkid;
312 	attrp->dia_portnum = ioc.ibdioc.ioc_portnum;
313 	attrp->dia_port_pkey_tbl_sz = ioc.ioc_pkey_tbl_sz;
314 	attrp->dia_port_pkeys = ioc.ioc_pkeys;
315 	attrp->dia_hca_guid = ioc.ibdioc.ioc_hcaguid;
316 	attrp->dia_port_guid = ioc.ibdioc.ioc_portguid;
317 	attrp->dia_instance = ioc.ibdioc.ioc_port_inst;
318 	return (status);
319 bail:
320 	free(ioc.ioc_pkeys);
321 	return (status);
322 }
323 
324 /*
325  * Free the memory allocated for the IB HCA port's P_Key table by
326  * dladm_ib_info library call.
327  */
328 void
329 dladm_free_ib_info(dladm_ib_attr_t *attr)
330 {
331 	if (attr && attr->dia_port_pkeys)
332 		free(attr->dia_port_pkeys);
333 }
334 
335 /*
336  * Call into the IP over IB driver to create a partition object.
337  */
338 static dladm_status_t
339 i_dladm_part_create(dladm_handle_t handle, dladm_part_attr_t *pattr)
340 {
341 	ibpart_ioctl_t	ioc;
342 
343 	bzero(&ioc, sizeof (ioc));
344 
345 	/* IB Physical datalink ID */
346 	ioc.ibdioc.ioc_linkid		= pattr->dia_physlinkid;
347 	/* IB Partition datalink ID */
348 	ioc.ioc_partid			= pattr->dia_partlinkid;
349 	ioc.ioc_pkey			= pattr->dia_pkey;
350 	ioc.ibdioc.ioc_port_inst	= pattr->dia_instance;
351 	ioc.ioc_force_create		= ((pattr->dia_flags & DLADM_OPT_FORCE)
352 	    != 0);
353 
354 	return (i_dladm_ib_ioctl(handle, IBD_CREATE_IBPART, &ioc.ibdioc));
355 }
356 
357 /*
358  * Create an entry in the dladm persistent configuration database for the
359  * partition specified by pattr.
360  */
361 dladm_status_t
362 dladm_part_persist_conf(dladm_handle_t handle, const char *pname,
363     dladm_part_attr_t *pattr)
364 {
365 
366 	dladm_conf_t	conf;
367 	dladm_status_t	status;
368 	char		linkover[MAXLINKNAMELEN];
369 	uint64_t	u64;
370 
371 	status = dladm_create_conf(handle, pname, pattr->dia_partlinkid,
372 	    DATALINK_CLASS_PART, DL_IB, &conf);
373 	if (status != DLADM_STATUS_OK)
374 		return (status);
375 
376 	/*
377 	 * Get the name of the IB Phys link over which this partition was
378 	 * created.
379 	 */
380 	status = dladm_datalink_id2info(handle, pattr->dia_physlinkid,
381 	    NULL, NULL, NULL, linkover, sizeof (linkover));
382 	if (status != DLADM_STATUS_OK)
383 		return (status);
384 
385 	/* Store IB Phys link name (linkover) */
386 	status = dladm_set_conf_field(handle, conf, FLINKOVER, DLADM_TYPE_STR,
387 	    linkover);
388 	if (status != DLADM_STATUS_OK)
389 		return (status);
390 
391 	u64 = pattr->dia_pkey;
392 
393 	/* Store the IB Partitions P_Key */
394 	status = dladm_set_conf_field(handle, conf, FPORTPKEY,
395 	    DLADM_TYPE_UINT64, &u64);
396 	if (status != DLADM_STATUS_OK)
397 		return (status);
398 
399 	if (pattr->dia_flags & DLADM_OPT_FORCE) {
400 		boolean_t force = B_TRUE;
401 		/* Store the force create flag. */
402 		status = dladm_set_conf_field(handle, conf, FFORCE,
403 		    DLADM_TYPE_BOOLEAN, &force);
404 		if (status != DLADM_STATUS_OK)
405 			goto done;
406 	}
407 
408 	status = dladm_write_conf(handle, conf);
409 	if (status != DLADM_STATUS_OK)
410 		return (status);
411 
412 	dladm_destroy_conf(handle, conf);
413 done:
414 	return (status);
415 }
416 
417 /*
418  * Create a new IB Partition datalink of name 'pname' over the IB Physical link
419  * given in 'physlinkid' with the P_key 'pkey' and return the datalink ID in
420  * 'partlinkid'. If the 'force' option is set in the 'flags' argument, the
421  * partition will be created even if the P_Key 'pkey' does not exist or if the
422  * HCA port represented by the IB Phys link is down. If the 'temporary' flag is
423  * set, then the configuration information is not added to the persistent
424  * database.
425  */
426 dladm_status_t
427 dladm_part_create(dladm_handle_t handle, datalink_id_t physlinkid,
428     ib_pkey_t pkey, uint32_t flags, char *pname, datalink_id_t *partlinkid,
429     dladm_arg_list_t *proplist)
430 {
431 	int			i;
432 	dladm_status_t		status;
433 	uint_t			media;
434 	boolean_t		part_created = B_FALSE;
435 	boolean_t		conf_set = B_FALSE;
436 	dladm_phys_attr_t	dpa;
437 	dladm_part_attr_t	pattr;
438 
439 	pattr.dia_pkey = pkey;
440 	pattr.dia_physlinkid = physlinkid; /* IB Phys link's datalink id */
441 	pattr.dia_flags = flags;
442 
443 	flags &= ~DLADM_OPT_FORCE;
444 
445 	/*
446 	 * Check whether the PKEY is valid. If not, return immediately
447 	 * Only full members are allowed as per the IPoIB specification
448 	 */
449 	if (pattr.dia_pkey <= IB_PKEY_INVALID_FULL)
450 		return (DLADM_STATUS_INVALID_PKEY);
451 
452 	/*
453 	 * Get the media type of the Phys link datalink ID provided and
454 	 * make sure that it is Infiniband media DL_IB)
455 	 */
456 	if ((status = dladm_datalink_id2info(handle, pattr.dia_physlinkid, NULL,
457 	    NULL, &media, NULL, 0)) != DLADM_STATUS_OK)
458 		return (status);
459 
460 	if (media != DL_IB)
461 		return (dladm_errno2status(ENOTSUP));
462 
463 	/*
464 	 * Get the instance number of the IP over IB driver instance which the
465 	 * IB Phys link 'physlinkid' over which we will be creating our IB
466 	 * partition.
467 	 */
468 	if ((status = dladm_phys_info(handle, pattr.dia_physlinkid, &dpa,
469 	    DLADM_OPT_ACTIVE)) != DLADM_STATUS_OK)
470 		return (status);
471 
472 	if (dladm_parselink(dpa.dp_dev, NULL, (uint_t *)&pattr.dia_instance) !=
473 	    DLADM_STATUS_OK)
474 		return (DLADM_STATUS_FAILED);
475 
476 
477 	if ((status = dladm_create_datalink_id(handle, pname,
478 	    DATALINK_CLASS_PART, DL_IB, flags, &pattr.dia_partlinkid)) !=
479 	    DLADM_STATUS_OK)
480 		return (status);
481 
482 	/*
483 	 * Create the IB partition object.
484 	 */
485 	status = i_dladm_part_create(handle, &pattr);
486 	if (status != DLADM_STATUS_OK)
487 		goto done;
488 
489 	part_created = B_TRUE;
490 
491 	/*
492 	 * If the persist flag is set then write this partition information
493 	 * to the persistent configuration.
494 	 */
495 	if (pattr.dia_flags & DLADM_OPT_PERSIST) {
496 		status = dladm_part_persist_conf(handle, pname, &pattr);
497 		if (status != DLADM_STATUS_OK)
498 			goto done;
499 		conf_set = B_TRUE;
500 	}
501 
502 	/*
503 	 * If the name-value pair list of properties were provided set those
504 	 * properties over the datalink.
505 	 */
506 	if (proplist != NULL) {
507 		for (i = 0; i < proplist->al_count; i++) {
508 			dladm_arg_info_t *aip = &proplist->al_info[i];
509 
510 			status = dladm_set_linkprop(handle,
511 			    pattr.dia_partlinkid, aip->ai_name, aip->ai_val,
512 			    aip->ai_count, pattr.dia_flags);
513 			if (status != DLADM_STATUS_OK)
514 				break;
515 		}
516 	}
517 done:
518 	if (status != DLADM_STATUS_OK) {
519 		if (conf_set)
520 			(void) dladm_remove_conf(handle, pattr.dia_partlinkid);
521 		if (part_created)
522 			(void) i_dladm_part_delete(handle,
523 			    pattr.dia_partlinkid);
524 		(void) dladm_destroy_datalink_id(handle, pattr.dia_partlinkid,
525 		    flags);
526 	}
527 
528 	if (partlinkid != NULL)
529 		*partlinkid = pattr.dia_partlinkid;
530 
531 	return (status);
532 }
533 
534 /*
535  * Call into the IP over IB driver to delete the IB partition and free up all
536  * the resources allocated for it.
537  */
538 static dladm_status_t
539 i_dladm_part_delete(dladm_handle_t handle, datalink_id_t partid)
540 {
541 	ibpart_ioctl_t ioc;
542 
543 	bzero(&ioc, sizeof (ioc));
544 	ioc.ioc_partid = partid;
545 	return (i_dladm_ib_ioctl(handle, IBD_DELETE_IBPART, &ioc.ibdioc));
546 }
547 
548 /*
549  * Delete an IB partition if 'flags' contains the active flag. Update the
550  * persistent configuration if 'flags' contains the persist flag.
551  */
552 dladm_status_t
553 dladm_part_delete(dladm_handle_t handle, datalink_id_t partid, int flags)
554 {
555 	dladm_status_t	status = DLADM_STATUS_OK;
556 	datalink_class_t class;
557 
558 	if (flags == 0)
559 		return (DLADM_STATUS_BADARG);
560 
561 	/*
562 	 * Make sure that the datalinkid provided is an IB partition class
563 	 * datalink ID.
564 	 */
565 	if ((dladm_datalink_id2info(handle, partid, NULL, &class, NULL, NULL, 0)
566 	    != DLADM_STATUS_OK))
567 		return (DLADM_STATUS_BADARG);
568 
569 	if (class != DATALINK_CLASS_PART)
570 		return (DLADM_STATUS_BADARG);
571 
572 	if ((flags & DLADM_OPT_ACTIVE) != 0) {
573 		status = i_dladm_part_delete(handle, partid);
574 		if (status == DLADM_STATUS_OK) {
575 			(void) dladm_set_linkprop(handle, partid, NULL, NULL, 0,
576 			    DLADM_OPT_ACTIVE);
577 			(void) dladm_destroy_datalink_id(handle, partid,
578 			    DLADM_OPT_ACTIVE);
579 		} else if (status != DLADM_STATUS_NOTFOUND ||
580 		    !(flags & DLADM_OPT_PERSIST)) {
581 			return (status);
582 		}
583 	}
584 
585 	if ((flags & DLADM_OPT_PERSIST) != 0) {
586 		dladm_status_t db_status;
587 		db_status = dladm_remove_conf(handle, partid);
588 
589 		/*
590 		 * A partition could have been temporarily deleted in which
591 		 * case the delete of the active partition above would have
592 		 * failed. In that case, we update the status to be returned
593 		 * to that of the status returned for deleting the persistent
594 		 * database entry.
595 		 */
596 		if (status == DLADM_STATUS_NOTFOUND)
597 			status = db_status;
598 
599 		(void) dladm_destroy_datalink_id(handle, partid,
600 		    DLADM_OPT_PERSIST);
601 	}
602 
603 	return (status);
604 }
605 
606 /*
607  * Call into the IP over IB driver to create the active instances of one or all
608  * IB partitions present in the persistent configuration.
609  */
610 /* ARGSUSED */
611 static int
612 i_dladm_part_up(dladm_handle_t handle, datalink_id_t plinkid, void *arg)
613 {
614 	dladm_conf_t	conf;
615 	datalink_id_t	linkid;
616 	ib_pkey_t	pkey;
617 	uint64_t	u64;
618 	char linkover[MAXLINKNAMELEN];
619 	dladm_status_t	status;
620 	dladm_phys_attr_t dpa;
621 	dladm_part_attr_t pattr;
622 
623 	/*
624 	 * plinkid is the IB partition datalink's ID. Get an handle to the
625 	 * persistent configuration entry for this datalink ID. If this datalink
626 	 * ID is not present in the persistent configuration return.
627 	 */
628 	if ((status = dladm_getsnap_conf(handle, plinkid, &conf)) !=
629 	    DLADM_STATUS_OK)
630 		return (status);
631 
632 	/*
633 	 * Get the name of the IB Phys link over which this partition was
634 	 * created.
635 	 */
636 	status = dladm_get_conf_field(handle, conf, FLINKOVER, linkover,
637 	    sizeof (linkover));
638 	if (status != DLADM_STATUS_OK)
639 		goto done;
640 
641 	if ((status = dladm_name2info(handle, linkover, &linkid, NULL, NULL,
642 	    NULL)) != DLADM_STATUS_OK)
643 		goto done;
644 
645 	/*
646 	 * Get the phys attribute of the IB Phys link to get the device name
647 	 * associated with the phys link. We need this to get the IP over IB
648 	 * driver instance number.
649 	 */
650 	if (dladm_phys_info(handle, linkid, &dpa, DLADM_OPT_ACTIVE)
651 	    != DLADM_STATUS_OK)
652 		goto done;
653 
654 	/* Get the IB partition's P_key */
655 	status = dladm_get_conf_field(handle, conf, FPORTPKEY, &u64,
656 	    sizeof (u64));
657 	if (status != DLADM_STATUS_OK)
658 		goto done;
659 
660 	pkey = (ib_pkey_t)u64;
661 
662 	/*
663 	 * We always set the force flag during dladm_part_up because we want
664 	 * the partition creation to succeed even if the IB HCA port over which
665 	 * the partition is being created is still down. Since dladm_part_up
666 	 * is usually invoked during early boot sequence, it is possible under
667 	 * some IB subnet configurations for dladm_up_part to be called before
668 	 * the IB link negotiation is completed and port state is set to active
669 	 * and P_Key table is updated.
670 	 */
671 	pattr.dia_flags = DLADM_OPT_FORCE | DLADM_OPT_ACTIVE |
672 	    DLADM_OPT_PERSIST;
673 	/* IB Phys link's datalink ID. */
674 	pattr.dia_physlinkid = linkid;
675 	/* IB Partition's datalink ID. */
676 	pattr.dia_partlinkid = plinkid;
677 	pattr.dia_pkey = pkey;
678 	if (dladm_parselink(dpa.dp_dev, NULL, (uint_t *)&pattr.dia_instance) !=
679 	    DLADM_STATUS_OK)
680 		return (DLADM_WALK_CONTINUE);
681 
682 	/* Create the active IB Partition object. */
683 	if (i_dladm_part_create(handle, &pattr) == DLADM_STATUS_OK &&
684 	    dladm_up_datalink_id(handle, plinkid) != DLADM_STATUS_OK)
685 		(void) i_dladm_part_delete(handle, linkid);
686 
687 done:
688 	dladm_destroy_conf(handle, conf);
689 	return (DLADM_WALK_CONTINUE);
690 }
691 
692 /*
693  * Bring up one or all IB partition(s) present in the persistent configuration
694  * database. If we need to bring up one IB Partition, its datalink ID is
695  * provided in 'linkid'.
696  */
697 /* ARGSUSED */
698 dladm_status_t
699 dladm_part_up(dladm_handle_t handle, datalink_id_t linkid, uint32_t flags)
700 {
701 	dladm_status_t status = DLADM_STATUS_OK;
702 
703 	if (linkid == DATALINK_ALL_LINKID) {
704 		(void) dladm_walk_datalink_id(i_dladm_part_up, handle,
705 		    &status, DATALINK_CLASS_PART, DATALINK_ANY_MEDIATYPE,
706 		    DLADM_OPT_PERSIST);
707 		return (DLADM_STATUS_OK);
708 	} else {
709 		(void) i_dladm_part_up(handle, linkid, &status);
710 		return (status);
711 	}
712 }
713