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