xref: /illumos-gate/usr/src/lib/cfgadm_plugins/fp/common/cfga_cvt.c (revision 75eba5b6d79ed4d2ce3daf7b2806306b6b69a938)
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 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 
27 #include "cfga_fp.h"
28 
29 /* Function prototypes */
30 
31 static fpcfga_ret_t get_xport_devlink(const char *hba_phys,
32     char **hba_logpp, int *l_errnop);
33 static char ctoi(char c);
34 static fpcfga_ret_t is_apid_configured(const char *xport_phys,
35 	const char *dyncomp, struct luninfo_list **lunlistpp, int *l_errnop);
36 static fpcfga_ret_t insert_lun_to_lunlist(struct luninfo_list **lunlistpp,
37 	const char *dyncomp, di_node_t devnode, int *l_errnop);
38 static fpcfga_ret_t update_lunlist(struct luninfo_list **lunlistpp, int lun,
39 	uint_t	state, char *pathp, int	*l_errnop);
40 
41 
42 /* Globals */
43 
44 /* Various conversions routines */
45 
46 void
47 cvt_lawwn_to_dyncomp(const la_wwn_t *pwwn, char **dyncomp, int *l_errnop)
48 {
49 	*dyncomp = calloc(1, WWN_SIZE*2 + 1);
50 	if (*dyncomp == NULL) {
51 		*l_errnop = errno;
52 	}
53 
54 	(void) sprintf(*dyncomp, "%016llx",
55 	(wwnConversion((uchar_t *)pwwn->raw_wwn)));
56 }
57 
58 
59 int
60 cvt_dyncomp_to_lawwn(const char *dyncomp, la_wwn_t *port_wwn)
61 {
62 	int	i;
63 	char	c, c1;
64 	uchar_t	*wwnp;
65 
66 	wwnp = port_wwn->raw_wwn;
67 	for (i = 0; i < WWN_SIZE; i++, wwnp++) {
68 
69 		c = ctoi(*dyncomp++);
70 		c1 = ctoi(*dyncomp++);
71 		if (c == -1 || c1 == -1)
72 			return (-1);
73 		*wwnp = ((c << 4) + c1);
74 	}
75 
76 	return (0);
77 }
78 
79 
80 static char
81 ctoi(char c)
82 {
83 	if ((c >= '0') && (c <= '9'))
84 		c -= '0';
85 	else if ((c >= 'A') && (c <= 'F'))
86 		c = c - 'A' + 10;
87 	else if ((c >= 'a') && (c <= 'f'))
88 		c = c - 'a' + 10;
89 	else
90 		c = -1;
91 	return (c);
92 }
93 
94 
95 /*
96  * Generates the HBA logical ap_id from physical ap_id.
97  */
98 fpcfga_ret_t
99 make_xport_logid(const char *xport_phys, char **xport_logpp, int *l_errnop)
100 {
101 	if (*xport_logpp != NULL) {
102 		return (FPCFGA_ERR);
103 	}
104 
105 	/*
106 	 * A devlink for the XPORT should exist.  Without the /dev/cfg link
107 	 * driver name and instance number based based link needs to be
108 	 * constructed for the minor node type of DDI_NT_FC_ATTACHMENT_POINT.
109 	 * sunddi.h defines DDI_NT_FC_ATTACHMENT_POINT for
110 	 * ddi_ctl:attachment_point:fc
111 	 */
112 	if (get_xport_devlink(xport_phys, xport_logpp, l_errnop) == FPCFGA_OK) {
113 		assert(*xport_logpp != NULL);
114 		return (FPCFGA_OK);
115 	} else {
116 		return (FPCFGA_ERR);
117 	}
118 }
119 
120 static fpcfga_ret_t
121 get_xport_devlink(const char *xport_phys, char **xport_logpp, int *l_errnop)
122 {
123 	int match_minor;
124 	size_t len;
125 	fpcfga_ret_t ret;
126 
127 	match_minor = 1;
128 	ret = physpath_to_devlink(CFGA_DEV_DIR, (char *)xport_phys,
129 	    xport_logpp, l_errnop, match_minor);
130 	if (ret != FPCFGA_OK) {
131 		return (ret);
132 	}
133 
134 	assert(*xport_logpp != NULL);
135 
136 	/* Remove the "/dev/cfg/"  prefix */
137 	len = strlen(CFGA_DEV_DIR SLASH);
138 
139 	(void) memmove(*xport_logpp, *xport_logpp + len,
140 	    strlen(*xport_logpp + len) + 1);
141 
142 	return (FPCFGA_OK);
143 }
144 
145 
146 /*
147  * Given a xport path and dynamic ap_id, returns the physical
148  * path in pathpp.  If the dynamic ap is not configured pathpp set to NULL
149  * and returns FPCFGA_APID_NOCONFIGURE.
150  */
151 fpcfga_ret_t
152 dyn_apid_to_path(
153 	const char *xport_phys,
154 	const char *dyncomp,
155 	struct luninfo_list **lunlistpp,
156 	int *l_errnop)
157 {
158 	fpcfga_ret_t 	ret;
159 
160 	/* A device MUST have a dynamic component */
161 	if (dyncomp == NULL) {
162 		return (FPCFGA_LIB_ERR);
163 	}
164 
165 	ret = is_apid_configured(xport_phys, dyncomp, lunlistpp, l_errnop);
166 
167 	assert(ret != FPCFGA_OK);
168 
169 	return (ret);
170 }
171 
172 /*
173  * When both the transport and dynamic comp are given this function
174  * checks to see if the dynamic ap is configured on the dev tree.
175  * If it is configured the devfs path will be stored in pathpp.
176  * When the dynamic comp is null this function check to see if the transport
177  * node has any child.
178  *
179  * Retrun value: FPCFGA_OK if the apid is configured.
180  *		 FPCFGA_APID_NOCONFIGURE if the apid is not configured.
181  *		 FPCFGA_LIB_ERR for other errors.
182  */
183 static fpcfga_ret_t
184 is_apid_configured(
185 	const char *xport_phys,
186 	const char *dyncomp,
187 	struct luninfo_list **lunlistpp,
188 	int *l_errnop)
189 {
190 	char 		*devfs_phys, *devfs_fp_path, *client_path, *cp,
191 			*pathp = NULL;
192 	char 		path_name[MAXPATHLEN];
193 	di_node_t	tree_root, root, fpnode, dev_node, client_node;
194 	di_path_t 	path = DI_PATH_NIL;
195 	di_prop_t	prop = DI_PROP_NIL;
196 	uchar_t		*port_wwn_data = NULL;
197 	char		*lun_guid = NULL;
198 	char		port_wwn[WWN_SIZE*2+1];
199 	int		count, *lunnump, devlen,
200 			found_fp = 0;
201 	uint_t		state;
202 	uint_t		statep;
203 	fpcfga_ret_t 	ret;
204 
205 	if (*lunlistpp != NULL) {
206 		return (FPCFGA_LIB_ERR);
207 	}
208 
209 	ret = FPCFGA_APID_NOCONFIGURE;
210 
211 	if ((devfs_phys = strdup(xport_phys)) == NULL) {
212 		*l_errnop = errno;
213 		return (FPCFGA_LIB_ERR);
214 	}
215 
216 	if (strncmp(devfs_phys, DEVICES_DIR SLASH, strlen(DEVICES_DIR) +
217 			strlen(SLASH)) == 0) {
218 		cp = devfs_phys + strlen(DEVICES_DIR);
219 		(void) memmove(devfs_phys, cp, strlen(cp) + 1);
220 	}
221 
222 	if ((cp = strstr(devfs_phys, MINOR_SEP)) != NULL) {
223 		*cp = '\0';  /* Terminate string. */
224 	}
225 
226 	if ((tree_root = di_init("/", DINFOCPYALL | DINFOPATH))
227 			== DI_NODE_NIL) {
228 		*l_errnop = errno;
229 		S_FREE(devfs_phys);
230 		return (FPCFGA_LIB_ERR);
231 	}
232 
233 	fpnode = di_drv_first_node("fp", tree_root);
234 
235 	while (fpnode) {
236 		devfs_fp_path = di_devfs_path(fpnode);
237 		if ((devfs_fp_path) && !(strncmp(devfs_fp_path,
238 				devfs_phys, strlen(devfs_phys)))) {
239 			found_fp = 1;
240 			di_devfs_path_free(devfs_fp_path);
241 			break;
242 		}
243 		di_devfs_path_free(devfs_fp_path);
244 		fpnode = di_drv_next_node(fpnode);
245 	}
246 	if (!(found_fp)) {
247 		ret = FPCFGA_LIB_ERR;
248 		goto out;
249 	} else {
250 		root = fpnode;
251 	}
252 
253 	/*
254 	 * when there is no child and path info node the
255 	 * FPCFGA_APID_NOCONFIGURE is returned
256 	 * regardless of the dynamic comp.
257 	 */
258 	dev_node = di_child_node(root);
259 	path = di_path_next_client(root, path);
260 	if ((dev_node == DI_NODE_NIL) && (path == DI_PATH_NIL)) {
261 		*l_errnop = errno;
262 		ret = FPCFGA_APID_NOCONFIGURE;
263 		goto out;
264 	}
265 
266 	/*
267 	 * when dyn comp is null the function just checks if there is any
268 	 * child under fp transport attachment point.
269 	 */
270 	if (dyncomp == NULL) {
271 		ret = FPCFGA_OK;
272 		goto out;
273 	}
274 
275 	/*
276 	 * now checks the children node to find
277 	 * if dynamic ap is configured. if there are multiple luns
278 	 * store into lunlist.
279 	 */
280 	if (dev_node != DI_NODE_NIL) {
281 		do {
282 			while ((prop = di_prop_next(dev_node, prop)) !=
283 					DI_PROP_NIL) {
284 				/* is property name port-wwn */
285 				if ((!(strcmp(PORT_WWN_PROP,
286 					di_prop_name(prop)))) &&
287 					(di_prop_type(prop) ==
288 					DI_PROP_TYPE_BYTE)) {
289 					break;
290 				}
291 			}
292 
293 			if (prop != DI_PROP_NIL) {
294 				count = di_prop_bytes(prop, &port_wwn_data);
295 				if (count != WWN_SIZE) {
296 					ret = FPCFGA_LIB_ERR;
297 					goto out;
298 				} else {
299 					(void) sprintf(port_wwn,
300 				"%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x",
301 					port_wwn_data[0], port_wwn_data[1],
302 					port_wwn_data[2], port_wwn_data[3],
303 					port_wwn_data[4], port_wwn_data[5],
304 					port_wwn_data[6], port_wwn_data[7]);
305 					if (!(strncmp(port_wwn, dyncomp,
306 							WWN_SIZE*2))) {
307 						ret = insert_lun_to_lunlist(
308 							lunlistpp, dyncomp,
309 							dev_node, l_errnop);
310 						if (ret != FPCFGA_OK) {
311 							goto out;
312 						}
313 					}
314 				}
315 			}
316 			dev_node = di_sibling_node(dev_node);
317 			prop = DI_PROP_NIL;
318 		} while (dev_node != DI_NODE_NIL);
319 	}
320 
321 	/*
322 	 * now checks the path info node to find
323 	 * if dynamic ap is configured. if there are multiple luns
324 	 * store into lunlist.
325 	 */
326 	if (path != DI_PATH_NIL) {
327 		/*
328 		 * now parse the path info node.
329 		 */
330 		do {
331 			count = di_path_prop_lookup_bytes(path, PORT_WWN_PROP,
332 				&port_wwn_data);
333 			if (count != WWN_SIZE) {
334 				ret = FPCFGA_LIB_ERR;
335 				goto out;
336 			}
337 
338 			(void) sprintf(port_wwn,
339 				"%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x",
340 				port_wwn_data[0], port_wwn_data[1],
341 				port_wwn_data[2], port_wwn_data[3],
342 				port_wwn_data[4], port_wwn_data[5],
343 				port_wwn_data[6], port_wwn_data[7]);
344 
345 			/* if matches get the path of scsi_vhci child node. */
346 			if (!(strncmp(port_wwn, dyncomp, WWN_SIZE*2))) {
347 				client_node = di_path_client_node(path);
348 				if (client_node == DI_NODE_NIL) {
349 					ret = FPCFGA_LIB_ERR;
350 					*l_errnop = errno;
351 					goto out;
352 				}
353 				count = di_path_prop_lookup_ints(path,
354 						LUN_PROP, &lunnump);
355 				client_path = di_devfs_path(client_node);
356 				strcpy(path_name, client_path);
357 				di_devfs_path_free(client_path);
358 				state = di_state(client_node);
359 				statep = di_path_state(path);
360 
361 				/*
362 				 * If the node is
363 				 * state then check the devfs_path to
364 				 * see if it has a complete path.
365 				 * For non scsi_vhci node the path
366 				 * doesn't contain @w(portwwn) part
367 				 * consistently.  For scsi_vhci
368 				 * this behavior may not be there.
369 				 * To be safe @g(guid) is attempted
370 				 * to be added here.
371 				 */
372 				if ((state & DI_DRIVER_DETACHED) &&
373 					(strstr(path_name, "@g") == NULL)) {
374 					prop = DI_PROP_NIL;
375 					while ((prop = di_prop_next(client_node,
376 							prop)) != DI_PROP_NIL) {
377 						/* is property name lun-wwn */
378 						if ((!(strcmp(LUN_GUID_PROP,
379 							di_prop_name(prop)))) &&
380 							(di_prop_type(prop) ==
381 							DI_PROP_TYPE_STRING)) {
382 							break;
383 						}
384 					}
385 
386 					if (prop != DI_PROP_NIL) {
387 						count = di_prop_strings(
388 							prop, &lun_guid);
389 						sprintf(&path_name[
390 							strlen(path_name)],
391 							"@g%s", lun_guid);
392 					} else {
393 						ret = FPCFGA_LIB_ERR;
394 						goto out;
395 					}
396 				}
397 
398 				devlen = strlen(DEVICES_DIR) +
399 						strlen(path_name) + 1;
400 				if ((pathp = calloc(1, devlen))
401 						== NULL) {
402 					*l_errnop = errno;
403 					return (FPCFGA_LIB_ERR);
404 				} else {
405 					(void) snprintf(pathp, devlen,
406 					"%s%s", DEVICES_DIR, path_name);
407 				}
408 				if ((ret = (update_lunlist(lunlistpp, *lunnump,
409 						statep, pathp, l_errnop))) !=
410 						FPCFGA_OK) {
411 					S_FREE(pathp);
412 					goto out;
413 				}
414 			}
415 			path = di_path_next_client(root, path);
416 		} while (path != DI_PATH_NIL);
417 	}
418 
419 out:
420 	di_fini(tree_root);
421 	S_FREE(devfs_phys);
422 	return (ret);
423 }
424 
425 static fpcfga_ret_t
426 insert_lun_to_lunlist(
427 	struct luninfo_list **lunlistpp,
428 	const char *dyncomp,
429 	di_node_t dev_node,
430 	int *l_errnop)
431 {
432 	char		path_name[MAXPATHLEN];
433 	char 		*pathp, *dev_phys;
434 	di_prop_t	prop_lun = DI_PROP_NIL;
435 	uint_t 		state;
436 	int		count, devlen;
437 	int		*lunp;
438 
439 	while ((prop_lun = di_prop_next(dev_node, prop_lun)) != DI_PROP_NIL) {
440 		if (!(strcmp(LUN_PROP, di_prop_name(prop_lun))) &&
441 				(di_prop_type(prop_lun) == DI_PROP_TYPE_INT)) {
442 			count = di_prop_ints(prop_lun, &lunp);
443 			if (count <= 0) {
444 				return (FPCFGA_LIB_ERR);
445 			}
446 			break;
447 		}
448 	}
449 
450 	if (prop_lun == DI_PROP_NIL) {
451 		return (FPCFGA_LIB_ERR);
452 	}
453 
454 	/*
455 	 * stores state info in state.
456 	 * This information is used to get the
457 	 * validity of path.
458 	 * if driver_detached don't try to get
459 	 * the devfs_path since it is not
460 	 * complete. ex, /pci@1f,2000/pci@1/
461 	 * SUNW,qlc@5/fp@0,0/ssd
462 	 * which doesn't contain the port wwn
463 	 * part.  The attached node looks like
464 	 * /pci@1f,2000/pci@1/SUNW,qlc@5/fp@0,0/
465 	 * ssd@w2100002037006b14,0
466 	 */
467 	state = di_state(dev_node);
468 
469 	dev_phys = di_devfs_path(dev_node);
470 	if (dev_phys == NULL) {
471 		return (FPCFGA_LIB_ERR);
472 	}
473 
474 	strcpy(path_name, dev_phys);
475 
476 	di_devfs_path_free(dev_phys);
477 
478 	if ((state & DI_DRIVER_DETACHED) &&
479 		(strstr(path_name, "@w") == NULL)) {
480 		sprintf(&path_name[strlen(path_name)], "@w%s,%x", dyncomp,
481 									*lunp);
482 	}
483 
484 	devlen = strlen(DEVICES_DIR) + strlen(path_name) + 1;
485 
486 	if ((pathp = calloc(1, devlen))
487 			== NULL) {
488 		*l_errnop = errno;
489 		return (FPCFGA_LIB_ERR);
490 	} else {
491 		(void) snprintf(pathp, devlen, "%s%s", DEVICES_DIR, path_name);
492 	}
493 
494 	return (update_lunlist(lunlistpp, *lunp, state, pathp, l_errnop));
495 }
496 
497 static fpcfga_ret_t
498 update_lunlist(
499 	struct luninfo_list **lunlistpp,
500 	int	lun,
501 	uint_t	state,
502 	char 	*pathp,
503 	int 	*l_errnop)
504 {
505 	struct luninfo_list *newlun, *curlun, *prevlun;
506 
507 	newlun = curlun = prevlun = (struct luninfo_list *)NULL;
508 
509 	newlun = calloc(1, sizeof (struct luninfo_list));
510 	if (newlun == NULL) {
511 		*l_errnop = errno;
512 		return (FPCFGA_LIB_ERR);
513 	}
514 
515 	newlun->lunnum = lun;
516 	newlun->node_state = state;
517 	newlun->path = pathp;
518 	newlun->next = (struct luninfo_list *)NULL;
519 
520 	/* if lunlist is empty add the new lun info and return. */
521 	if (*lunlistpp == NULL) {
522 		*lunlistpp = newlun;
523 		return (FPCFGA_OK);
524 	}
525 
526 	/* if the first lun in the list is the same as the new lun return. */
527 	if ((*lunlistpp)->lunnum == lun) {
528 		S_FREE(newlun);
529 		return (FPCFGA_OK);
530 	}
531 
532 	/*
533 	 * if the first lun in the list is less than the new lun add the
534 	 * new lun as the first lun and return.
535 	 */
536 	if ((*lunlistpp)->lunnum < lun) {
537 		newlun->next = *lunlistpp;
538 		*lunlistpp = newlun;
539 		return (FPCFGA_OK);
540 	}
541 
542 	/*
543 	 * if the first lun in the list is greater than the new lun and
544 	 * there is a single lun add new lun after the first lun and return.
545 	 */
546 	if ((*lunlistpp)->next == NULL) {
547 		(*lunlistpp)->next = newlun;
548 		return (FPCFGA_OK);
549 	}
550 
551 	/*
552 	 * now there is more than two luns in the list and the first lun
553 	 * is greter than the input lun.
554 	 */
555 	curlun = (*lunlistpp)->next;
556 	prevlun = *lunlistpp;
557 
558 	while (curlun != NULL) {
559 		if (curlun->lunnum == lun) {
560 			S_FREE(newlun);
561 			return (FPCFGA_OK);
562 		} else if (curlun->lunnum < lun) {
563 			newlun->next = curlun;
564 			prevlun->next = newlun;
565 			return (FPCFGA_OK);
566 		} else {
567 			prevlun = curlun;
568 			curlun = curlun->next;
569 		}
570 	}
571 
572 	/* add the new lun at the end of list. */
573 	prevlun->next = newlun;
574 	return (FPCFGA_OK);
575 
576 }
577 
578 
579 fpcfga_ret_t
580 make_dyncomp_from_dinode(
581 	const di_node_t node,
582 	char **dyncompp,
583 	int *l_errnop)
584 {
585 	di_prop_t	prop = DI_PROP_NIL;
586 	uchar_t		*port_wwn_data;
587 	int		count;
588 
589 	*l_errnop = 0;
590 	*dyncompp = calloc(1, WWN_SIZE*2 + 1);
591 	if (*dyncompp == NULL) {
592 		*l_errnop = errno;
593 		return (FPCFGA_LIB_ERR);
594 	}
595 
596 	/* now get port-wwn for the input node. */
597 	while ((prop = di_prop_next(node, prop)) != DI_PROP_NIL) {
598 		if (!(strcmp(PORT_WWN_PROP, di_prop_name(prop))) &&
599 			(di_prop_type(prop) == DI_PROP_TYPE_BYTE)) {
600 			break;
601 		}
602 	}
603 
604 	if (prop != DI_PROP_NIL) {
605 		count = di_prop_bytes(prop, &port_wwn_data);
606 		if (count != WWN_SIZE) {
607 			S_FREE(*dyncompp);
608 			return (FPCFGA_LIB_ERR);
609 		}
610 
611 		(void) sprintf(*dyncompp, "%016llx",
612 			(wwnConversion(port_wwn_data)));
613 	} else {
614 		*l_errnop = errno;
615 		S_FREE(*dyncompp);
616 		return (FPCFGA_LIB_ERR);
617 	}
618 
619 	return (FPCFGA_OK);
620 }
621 
622 fpcfga_ret_t
623 make_portwwn_luncomp_from_dinode(
624 	const di_node_t node,
625 	char **dyncompp,
626 	int **luncompp,
627 	int *l_errnop)
628 {
629 	uchar_t		*port_wwn_data;
630 	int		pwwn_ret, lun_ret;
631 
632 	*l_errnop = 0;
633 
634 	if ((dyncompp != NULL) &&
635 			((pwwn_ret = di_prop_lookup_bytes(DDI_DEV_T_ANY,
636 			node, PORT_WWN_PROP, &port_wwn_data)) <= 0)) {
637 		*l_errnop = errno;
638 	}
639 	if ((luncompp != NULL) &&
640 			((lun_ret = di_prop_lookup_ints(DDI_DEV_T_ANY,
641 			node, LUN_PROP, luncompp)) <= 0)) {
642 		*l_errnop = errno;
643 	}
644 
645 	/*
646 	 * di_prop* returns the number of entries found or 0 if not found
647 	 * or -1 for othere failure.
648 	 */
649 	if ((pwwn_ret <= 0) || (lun_ret <= 0)) {
650 		return (FPCFGA_LIB_ERR);
651 	}
652 
653 	*dyncompp = calloc(1, WWN_SIZE*2+1);
654 	if (*dyncompp == NULL) {
655 		*l_errnop = errno;
656 		return (FPCFGA_LIB_ERR);
657 	}
658 
659 	(void) sprintf(*dyncompp, "%016llx", (wwnConversion(port_wwn_data)));
660 
661 	return (FPCFGA_OK);
662 }
663 
664 fpcfga_ret_t
665 make_portwwn_luncomp_from_pinode(
666 	const di_path_t pinode,
667 	char **dyncompp,
668 	int **luncompp,
669 	int *l_errnop)
670 {
671 	uchar_t		*port_wwn_data;
672 	int		pwwn_ret, lun_ret;
673 
674 	*l_errnop = 0;
675 
676 	if ((dyncompp != NULL) &&
677 			((pwwn_ret = di_path_prop_lookup_bytes(pinode,
678 			PORT_WWN_PROP, &port_wwn_data)) <= 0)) {
679 		*l_errnop = errno;
680 	}
681 	if ((luncompp != NULL) &&
682 			((lun_ret = di_path_prop_lookup_ints(pinode,
683 			LUN_PROP, luncompp)) <= 0)) {
684 		*l_errnop = errno;
685 	}
686 
687 	/*
688 	 * di_prop* returns the number of entries found or 0 if not found
689 	 * or -1 for othere failure.
690 	 */
691 	if ((pwwn_ret <= 0) || (lun_ret <= 0)) {
692 		return (FPCFGA_LIB_ERR);
693 	}
694 
695 	*dyncompp = calloc(1, WWN_SIZE*2+1);
696 	if (*dyncompp == NULL) {
697 		*l_errnop = errno;
698 		return (FPCFGA_LIB_ERR);
699 	}
700 
701 	(void) sprintf(*dyncompp, "%016llx", (wwnConversion(port_wwn_data)));
702 
703 	return (FPCFGA_OK);
704 }
705 
706 fpcfga_ret_t
707 construct_nodepath_from_dinode(
708 	const di_node_t node,
709 	char **node_pathp,
710 	int *l_errnop)
711 {
712 	char *devfs_path, path_name[MAXPATHLEN], *lun_guid, *port_wwn;
713 	uchar_t *port_wwn_data;
714 	int is_scsi_vhci_dev, di_ret, devlen;
715 	uint_t	state;
716 
717 	devfs_path = di_devfs_path(node);
718 	strcpy(path_name, devfs_path);
719 	di_devfs_path_free(devfs_path);
720 	state = di_state(node);
721 
722 	is_scsi_vhci_dev = (strstr(path_name, SCSI_VHCI_DRVR) != NULL) ? 1 : 0;
723 
724 	/*
725 	 * If the node is
726 	 * state then check the devfs_path to
727 	 * see if it has a complete path.
728 	 * For non scsi_vhci node the path
729 	 * doesn't contain @w(portwwn) part
730 	 * consistently.  For scsi_vhci
731 	 * this behavior may not be there.
732 	 * To be safe @g(guid) is attempted
733 	 * to be added here.
734 	 */
735 	if (state & DI_DRIVER_DETACHED) {
736 		if (is_scsi_vhci_dev &&
737 			(strstr(path_name, "@g") == NULL)) {
738 			di_ret = di_prop_lookup_strings(DDI_DEV_T_ANY, node,
739 				LUN_GUID_PROP, &lun_guid);
740 			if (di_ret == -1) {
741 				*l_errnop = errno;
742 				return (FPCFGA_LIB_ERR);
743 			} else {
744 				sprintf(&path_name[strlen(path_name)],
745 					"@g%s", lun_guid);
746 			}
747 		} else if (!is_scsi_vhci_dev &&
748 			(strstr(path_name, "@w") == NULL)) {
749 			di_ret = di_prop_lookup_bytes(DDI_DEV_T_ANY, node,
750 				PORT_WWN_PROP, &port_wwn_data);
751 			if (di_ret == -1) {
752 				*l_errnop = errno;
753 				return (FPCFGA_LIB_ERR);
754 			} else {
755 				if ((port_wwn = calloc(1, WWN_SIZE*2 + 1))
756 						== NULL) {
757 					*l_errnop = errno;
758 					return (FPCFGA_LIB_ERR);
759 				}
760 
761 				(void) sprintf(port_wwn, "%016llx",
762 					(wwnConversion(port_wwn_data)));
763 				(void) sprintf(&path_name[strlen(path_name)],
764 					"@w%s", port_wwn);
765 				S_FREE(port_wwn);
766 			}
767 		}
768 	}
769 
770 	devlen = strlen(DEVICES_DIR) + strlen(path_name) + 1;
771 	if ((*node_pathp = calloc(1, devlen)) == NULL) {
772 		*l_errnop = errno;
773 		return (FPCFGA_LIB_ERR);
774 	} else {
775 		(void) snprintf(*node_pathp, devlen,
776 		"%s%s", DEVICES_DIR, path_name);
777 	}
778 
779 	return (FPCFGA_OK);
780 }
781 
782 u_longlong_t
783 wwnConversion(uchar_t *wwn)
784 {
785 	u_longlong_t tmp;
786 	memcpy(&tmp, wwn, sizeof (u_longlong_t));
787 	return (ntohll(tmp));
788 }
789