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
cvt_lawwn_to_dyncomp(const la_wwn_t * pwwn,char ** dyncomp,int * l_errnop)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
cvt_dyncomp_to_lawwn(const char * dyncomp,la_wwn_t * port_wwn)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
ctoi(char c)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
make_xport_logid(const char * xport_phys,char ** xport_logpp,int * l_errnop)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
get_xport_devlink(const char * xport_phys,char ** xport_logpp,int * l_errnop)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
dyn_apid_to_path(const char * xport_phys,const char * dyncomp,struct luninfo_list ** lunlistpp,int * l_errnop)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
is_apid_configured(const char * xport_phys,const char * dyncomp,struct luninfo_list ** lunlistpp,int * l_errnop)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
insert_lun_to_lunlist(struct luninfo_list ** lunlistpp,const char * dyncomp,di_node_t dev_node,int * l_errnop)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
update_lunlist(struct luninfo_list ** lunlistpp,int lun,uint_t state,char * pathp,int * l_errnop)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
make_dyncomp_from_dinode(const di_node_t node,char ** dyncompp,int * l_errnop)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
make_portwwn_luncomp_from_dinode(const di_node_t node,char ** dyncompp,int ** luncompp,int * l_errnop)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
make_portwwn_luncomp_from_pinode(const di_path_t pinode,char ** dyncompp,int ** luncompp,int * l_errnop)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
construct_nodepath_from_dinode(const di_node_t node,char ** node_pathp,int * l_errnop)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
wwnConversion(uchar_t * wwn)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