dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / lib / cfgadm_plugins / fp / common / cfga_cs.c
blob79afa6b97362eb2d1cdedde99d0db4c4e82da3ad
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
27 #include "cfga_fp.h"
29 /* define */
30 #define ALL_APID_LUNS_UNUSABLE 0x10
32 #define DEFAULT_LUN_COUNT 1024
33 #define LUN_SIZE 8
34 #define LUN_HEADER_SIZE 8
35 #define DEFAULT_LUN_LENGTH DEFAULT_LUN_COUNT * \
36 LUN_SIZE + \
37 LUN_HEADER_SIZE
39 /* Some forward declarations */
40 static fpcfga_ret_t do_devctl_dev_create(apid_t *, char *, int,
41 uchar_t, char **);
42 static fpcfga_ret_t dev_rcm_online(apid_t *, int, cfga_flags_t, char **);
43 static void dev_rcm_online_nonoperationalpath(apid_t *, cfga_flags_t, char **);
44 static fpcfga_ret_t dev_rcm_offline(apid_t *, cfga_flags_t, char **);
45 static fpcfga_ret_t dev_rcm_remove(apid_t *, cfga_flags_t, char **);
46 static fpcfga_ret_t lun_unconf(char *, int, char *, char *, char **);
47 static fpcfga_ret_t dev_unconf(apid_t *, char **, uchar_t *);
48 static fpcfga_ret_t is_xport_phys_in_pathlist(apid_t *, char **);
49 static void copy_pwwn_data_to_str(char *, const uchar_t *);
50 static fpcfga_ret_t unconf_vhci_nodes(di_path_t, di_node_t, char *,
51 char *, int, int *, int *, char **, cfga_flags_t);
52 static fpcfga_ret_t unconf_non_vhci_nodes(di_node_t, char *, char *,
53 int, int *, int *, char **, cfga_flags_t);
54 static fpcfga_ret_t unconf_any_devinfo_nodes(apid_t *, cfga_flags_t, char **,
55 int *, int *);
56 static fpcfga_ret_t handle_devs(cfga_cmd_t, apid_t *, cfga_flags_t,
57 char **, HBA_HANDLE, int, HBA_PORTATTRIBUTES);
61 * This function initiates the creation of the new device node for a given
62 * port WWN.
63 * So, apidt->dyncomp CANNOT be NULL
65 static fpcfga_ret_t
66 do_devctl_dev_create(apid_t *apidt, char *dev_path, int pathlen,
67 uchar_t dev_dtype, char **errstring)
69 devctl_ddef_t ddef_hdl;
70 devctl_hdl_t bus_hdl, dev_hdl;
71 char *drvr_name = "dummy";
72 la_wwn_t pwwn;
74 *dev_path = '\0';
75 if ((ddef_hdl = devctl_ddef_alloc(drvr_name, 0)) == NULL) {
76 cfga_err(errstring, errno, ERRARG_DC_DDEF_ALLOC, drvr_name, 0);
77 return (FPCFGA_LIB_ERR);
80 if (cvt_dyncomp_to_lawwn(apidt->dyncomp, &pwwn)) {
81 devctl_ddef_free(ddef_hdl);
82 cfga_err(errstring, 0, ERR_APID_INVAL, 0);
83 return (FPCFGA_LIB_ERR);
86 if (devctl_ddef_byte_array(ddef_hdl, PORT_WWN_PROP, FC_WWN_SIZE,
87 pwwn.raw_wwn) == -1) {
88 devctl_ddef_free(ddef_hdl);
89 cfga_err(errstring, errno, ERRARG_DC_BYTE_ARRAY,
90 PORT_WWN_PROP, 0);
91 return (FPCFGA_LIB_ERR);
94 if ((bus_hdl = devctl_bus_acquire(apidt->xport_phys, 0)) == NULL) {
95 devctl_ddef_free(ddef_hdl);
96 cfga_err(errstring, errno, ERRARG_DC_BUS_ACQUIRE,
97 apidt->xport_phys, 0);
98 return (FPCFGA_LIB_ERR);
101 /* Let driver handle creation of the new path */
102 if (devctl_bus_dev_create(bus_hdl, ddef_hdl, 0, &dev_hdl)) {
103 devctl_ddef_free(ddef_hdl);
104 devctl_release(bus_hdl);
105 if (dev_dtype == DTYPE_UNKNOWN) {
107 * Unknown DTYPES are devices such as another system's
108 * FC HBA port. We have tried to configure it but
109 * have failed. Since devices with no device type
110 * or an unknown dtype cannot be configured, we will
111 * return an appropriate error message.
113 cfga_err(errstring, errno,
114 ERRARG_BUS_DEV_CREATE_UNKNOWN, apidt->dyncomp, 0);
115 } else {
116 cfga_err(errstring, errno, ERRARG_BUS_DEV_CREATE,
117 apidt->dyncomp, 0);
119 return (FPCFGA_LIB_ERR);
121 devctl_release(bus_hdl);
122 devctl_ddef_free(ddef_hdl);
124 devctl_get_pathname(dev_hdl, dev_path, pathlen);
125 devctl_release(dev_hdl);
127 return (FPCFGA_OK);
131 * Online, in RCM, all the LUNs for a particular device.
132 * Caller can specify the # of luns in the lunlist that have to be onlined
133 * by passing a count that is not -ve.
135 * INPUT :
136 * apidt - this is expected to have the list of luns for the device and so
137 * is assumed to be filled in prior to this call
138 * count - # of LUNs in the list that have to be onlined.
139 * errstring - If non-NULL, it will hold any error messages
141 * RETURNS :
142 * 0 on success
143 * non-zero otherwise
145 static fpcfga_ret_t
146 dev_rcm_online(apid_t *apidt, int count, cfga_flags_t flags, char **errstring)
148 luninfo_list_t *lunlistp;
149 int i = 0, ret = 0;
150 fpcfga_ret_t retval = FPCFGA_OK;
152 /* This check may be redundant, but safer this way */
153 if ((apidt->flags & FLAG_DISABLE_RCM) != 0) {
154 /* User has requested not to notify RCM framework */
155 return (FPCFGA_OK);
158 lunlistp = apidt->lunlist;
160 for (lunlistp = apidt->lunlist; lunlistp != NULL;
161 i++, lunlistp = lunlistp->next) {
162 if ((count >= 0) && (i >= count))
163 break;
164 if (fp_rcm_online(lunlistp->path, errstring, flags) !=
165 FPCFGA_OK) {
166 ret++;
170 if (ret > 0)
171 retval = FPCFGA_LIB_ERR;
173 return (retval);
177 * Online in RCM for devices which only have paths
178 * not in ONLINE/STANDBY state
180 void
181 dev_rcm_online_nonoperationalpath(apid_t *apidt, cfga_flags_t flags,
182 char **errstring)
184 luninfo_list_t *lunlistp;
186 if ((apidt->flags & FLAG_DISABLE_RCM) != 0) {
187 return;
190 lunlistp = apidt->lunlist;
192 for (lunlistp = apidt->lunlist; lunlistp != NULL;
193 lunlistp = lunlistp->next) {
194 if ((lunlistp->lun_flag & FLAG_SKIP_ONLINEOTHERS) != 0) {
195 continue;
197 (void) fp_rcm_online(lunlistp->path, errstring, flags);
202 * Offline, in RCM, all the LUNs for a particular device.
203 * This function should not be called for the MPXIO case.
205 * INPUT :
206 * apidt - this is expected to have the list of luns for the device and so
207 * is assumed to be filled in prior to this call
208 * errstring - If non-NULL, it will hold any error messages
210 * RETURNS :
211 * FPCFGA_OK on success
212 * error code otherwise
214 static fpcfga_ret_t
215 dev_rcm_offline(apid_t *apidt, cfga_flags_t flags, char **errstring)
217 int count = 0;
218 luninfo_list_t *lunlistp;
220 if ((apidt->flags & FLAG_DISABLE_RCM) != 0) {
221 /* User has requested not to notify RCM framework */
222 return (FPCFGA_OK);
225 for (lunlistp = apidt->lunlist; lunlistp != NULL;
226 lunlistp = lunlistp->next) {
227 if ((lunlistp->lun_flag & FLAG_SKIP_RCMOFFLINE) != 0) {
228 continue;
230 if ((apidt->flags & FLAG_REMOVE_UNUSABLE_FCP_DEV) ==
231 FLAG_REMOVE_UNUSABLE_FCP_DEV) {
232 int ret = strncmp(lunlistp->path, SCSI_VHCI_ROOT,
233 strlen(SCSI_VHCI_ROOT));
235 if (((ret == 0) &&
236 (lunlistp->node_state == DI_PATH_STATE_OFFLINE)) ||
237 ((ret != 0) &&
238 ((lunlistp->node_state & DI_DEVICE_OFFLINE) ==
239 DI_DEVICE_OFFLINE))) {
240 /* Offline the device through RCM */
241 if (fp_rcm_offline(lunlistp->path, errstring,
242 flags) != 0) {
244 * Bring everything back online in
245 * rcm and return
247 (void) dev_rcm_online(apidt, count,
248 flags, NULL);
249 return (FPCFGA_LIB_ERR);
251 count++;
253 } else {
254 /* Offline the device through RCM */
255 if (fp_rcm_offline(lunlistp->path, errstring,
256 flags) != 0) {
258 * Bring everything back online in
259 * rcm and return
261 (void) dev_rcm_online(apidt, count, flags,
262 NULL);
263 return (FPCFGA_LIB_ERR);
265 count++;
268 return (FPCFGA_OK);
272 * Remove, in RCM, all the LUNs for a particular device.
273 * This function should not be called for the MPXIO case.
275 * INPUT :
276 * apidt - this is expected to have the list of luns for the device and so
277 * is assumed to be filled in prior to this call
278 * errstring - If non-NULL, it will hold any error messages
280 * RETURNS :
281 * FPCFGA_OK on success
282 * error code otherwise
284 static fpcfga_ret_t
285 dev_rcm_remove(apid_t *apidt, cfga_flags_t flags, char **errstring)
287 int count = 0;
288 luninfo_list_t *lunlistp;
290 if ((apidt->flags & FLAG_DISABLE_RCM) != 0) {
291 /* User has requested not to notify RCM framework */
292 return (FPCFGA_OK);
295 for (lunlistp = apidt->lunlist; lunlistp != NULL;
296 lunlistp = lunlistp->next) {
297 if ((lunlistp->lun_flag & FLAG_SKIP_RCMREMOVE) != 0)
298 continue;
299 if ((apidt->flags & FLAG_REMOVE_UNUSABLE_FCP_DEV) ==
300 FLAG_REMOVE_UNUSABLE_FCP_DEV) {
301 int ret = strncmp(lunlistp->path, SCSI_VHCI_ROOT,
302 strlen(SCSI_VHCI_ROOT));
304 if (((ret == 0) &&
305 (lunlistp->node_state == DI_PATH_STATE_OFFLINE)) ||
306 ((ret != 0) &&
307 ((lunlistp->node_state & DI_DEVICE_OFFLINE) ==
308 DI_DEVICE_OFFLINE))) {
309 /* remove the device through RCM */
310 if (fp_rcm_remove(lunlistp->path, errstring,
311 flags) != 0) {
313 * Bring everything back online in
314 * rcm and return
316 (void) dev_rcm_online(apidt, count,
317 flags, NULL);
318 return (FPCFGA_LIB_ERR);
320 count++;
322 } else {
323 /* remove the device through RCM */
324 if (fp_rcm_remove(lunlistp->path, errstring,
325 flags) != 0) {
327 * Bring everything back online in rcm and
328 * return
330 (void) dev_rcm_online(apidt, count, flags,
331 NULL);
332 return (FPCFGA_LIB_ERR);
334 count++;
337 return (FPCFGA_OK);
340 static fpcfga_ret_t
341 lun_unconf(char *path, int lunnum, char *xport_phys, char *dyncomp,
342 char **errstring)
344 devctl_hdl_t hdl;
345 char *ptr; /* To use as scratch/temp pointer */
346 char pathname[MAXPATHLEN];
348 if (path == NULL)
349 return (FPCFGA_OK);
351 if (strncmp(path, SCSI_VHCI_ROOT, strlen(SCSI_VHCI_ROOT)) == 0) {
353 * We have an MPXIO managed device here.
354 * So, we have to concoct a path for the device.
356 * xport_phys looks like :
357 * /devices/pci@b,2000/pci@1/SUNW,qlc@5/fp@0,0:fc
359 (void) strlcpy(pathname, xport_phys, MAXPATHLEN);
360 if ((ptr = strrchr(pathname, ':')) != NULL) {
361 *ptr = '\0';
365 * Get pointer to driver name from VHCI path
366 * So, if lunlistp->path is
367 * /devices/scsi_vhci/ssd@g220000203707a417,
368 * we need a pointer to the last '/'
370 * Assumption:
371 * With MPXIO there will be only one entry per lun
372 * So, there will only be one entry in the linked list
373 * apidt->lunlist
375 if ((ptr = strrchr(path, '/')) == NULL) {
376 /* This shouldn't happen, but anyways ... */
377 cfga_err(errstring, 0, ERRARG_INVALID_PATH, path, 0);
378 return (FPCFGA_LIB_ERR);
382 * Make pathname to look something like :
383 * /devices/pci@x,xxxx/pci@x/SUNW,qlc@x/fp@x,x/ssd@w...
385 strcat(pathname, ptr);
388 * apidt_create() will make sure that lunlist->path
389 * has a "@<something>" at the end even if the driver
390 * state is "detached"
392 if ((ptr = strrchr(pathname, '@')) == NULL) {
393 /* This shouldn't happen, but anyways ... */
394 cfga_err(errstring, 0, ERRARG_INVALID_PATH,
395 pathname, 0);
396 return (FPCFGA_LIB_ERR);
398 *ptr = '\0';
400 /* Now, concoct the path */
401 sprintf(&pathname[strlen(pathname)], "@w%s,%x",
402 dyncomp, lunnum);
403 ptr = pathname;
404 } else {
406 * non-MPXIO path, use the path that is passed in
408 ptr = path;
411 if ((hdl = devctl_device_acquire(ptr, 0)) == NULL) {
412 cfga_err(errstring, errno, ERRARG_DEV_ACQUIRE, ptr, 0);
413 return (FPCFGA_LIB_ERR);
416 if (devctl_device_remove(hdl) != 0) {
417 devctl_release(hdl);
418 cfga_err(errstring, errno, ERRARG_DEV_REMOVE, ptr, 0);
419 return (FPCFGA_LIB_ERR);
421 devctl_release(hdl);
423 return (FPCFGA_OK);
426 static fpcfga_ret_t
427 dev_unconf(apid_t *apidt, char **errstring, uchar_t *flag)
429 luninfo_list_t *lunlistp;
430 fpcfga_ret_t ret = FPCFGA_OK;
431 int lun_cnt = 0, unusable_lun_cnt = 0;
433 for (lunlistp = apidt->lunlist; lunlistp != NULL;
434 lunlistp = lunlistp->next) {
435 lun_cnt++;
437 * Unconfigure each LUN.
438 * Note that for MPXIO devices, lunlistp->path will be a
439 * vHCI path
441 if ((apidt->flags & FLAG_REMOVE_UNUSABLE_FCP_DEV) ==
442 FLAG_REMOVE_UNUSABLE_FCP_DEV) {
443 if (strncmp(lunlistp->path, SCSI_VHCI_ROOT,
444 strlen(SCSI_VHCI_ROOT)) == 0) {
445 if (lunlistp->node_state ==
446 DI_PATH_STATE_OFFLINE) {
447 unusable_lun_cnt++;
448 if ((ret = lun_unconf(lunlistp->path,
449 lunlistp->lunnum, apidt->xport_phys,
450 apidt->dyncomp, errstring)) !=
451 FPCFGA_OK) {
452 return (ret);
455 } else {
456 if ((lunlistp->node_state &
457 DI_DEVICE_OFFLINE) == DI_DEVICE_OFFLINE) {
458 unusable_lun_cnt++;
459 if ((ret = lun_unconf(lunlistp->path,
460 lunlistp->lunnum, apidt->xport_phys,
461 apidt->dyncomp, errstring)) !=
462 FPCFGA_OK) {
463 return (ret);
467 } else {
469 * Unconfigure each LUN.
470 * Note that for MPXIO devices, lunlistp->path will be a
471 * vHCI path
473 if ((ret = lun_unconf(lunlistp->path, lunlistp->lunnum,
474 apidt->xport_phys, apidt->dyncomp,
475 errstring)) != FPCFGA_OK) {
476 return (ret);
481 if ((apidt->flags & FLAG_REMOVE_UNUSABLE_FCP_DEV) ==
482 FLAG_REMOVE_UNUSABLE_FCP_DEV) {
484 * when all luns are unconfigured
485 * indicate to remove repository entry.
487 if (lun_cnt == unusable_lun_cnt) {
488 *flag = ALL_APID_LUNS_UNUSABLE;
492 return (ret);
496 * Check if the given physical path (the xport_phys) is part of the
497 * pHCI list and if the RCM should be done for a particular pHCI.
498 * Skip non-MPxIO dev node if any.
500 static fpcfga_ret_t
501 is_xport_phys_in_pathlist(apid_t *apidt, char **errstring)
503 di_node_t root, vhci, node, phci;
504 di_path_t path = DI_PATH_NIL;
505 int num_active_paths, found = 0;
506 char *vhci_path_ptr, *pathname_ptr, pathname[MAXPATHLEN];
507 char *phci_path, *node_path;
508 char phci_addr[MAXPATHLEN];
509 char *xport_phys, *vhci_path, *dyncomp;
510 luninfo_list_t *lunlistp, *temp;
511 int non_operational_path_count;
513 /* a safety check */
514 if ((apidt->dyncomp == NULL) || (*apidt->dyncomp == '\0')) {
515 return (FPCFGA_LIB_ERR);
518 xport_phys = apidt->xport_phys;
519 dyncomp = apidt->dyncomp;
521 lunlistp = apidt->lunlist;
522 for (lunlistp = apidt->lunlist; lunlistp != NULL;
523 lunlistp = lunlistp->next) {
525 if (strncmp(lunlistp->path, SCSI_VHCI_ROOT,
526 strlen(SCSI_VHCI_ROOT)) != 0) {
527 lunlistp->lun_flag |= FLAG_SKIP_ONLINEOTHERS;
528 continue;
531 vhci_path = lunlistp->path;
533 num_active_paths = 0; /* # of paths in ONLINE/STANDBY */
534 non_operational_path_count = 0;
536 if (xport_phys == NULL || vhci_path == NULL) {
537 cfga_err(errstring, 0, ERRARG_XPORT_NOT_IN_PHCI_LIST,
538 xport_phys, 0);
539 return (FPCFGA_LIB_ERR);
542 (void) strlcpy(pathname, xport_phys, MAXPATHLEN);
543 if ((pathname_ptr = strrchr(pathname, ':')) != NULL) {
544 *pathname_ptr = '\0';
546 /* strip off the /devices/from the path */
547 pathname_ptr = pathname + strlen(DEVICES_DIR);
549 root = di_init("/", DINFOCPYALL|DINFOPATH);
551 if (root == DI_NODE_NIL) {
552 return (FPCFGA_LIB_ERR);
555 vhci_path_ptr = vhci_path + strlen(DEVICES_DIR);
556 if ((vhci = di_drv_first_node(SCSI_VHCI_DRVR, root)) ==
557 DI_NODE_NIL) {
558 return (FPCFGA_LIB_ERR);
560 found = 0;
561 for (node = di_child_node(vhci); node != DI_NODE_NIL;
562 node = di_sibling_node(node)) {
563 if ((node_path = di_devfs_path(node)) != NULL) {
564 if (strncmp(vhci_path_ptr, node_path,
565 strlen(node_path)) != 0) {
566 di_devfs_path_free(node_path);
567 } else {
568 found = 1;
569 break;
573 if (found == 0) {
574 cfga_err(errstring, 0, ERRARG_XPORT_NOT_IN_PHCI_LIST,
575 xport_phys, 0);
576 di_fini(root);
577 return (FPCFGA_LIB_ERR);
579 /* found vhci_path we are looking for */
580 di_devfs_path_free(node_path);
581 found = 0;
582 for (path = di_path_next_phci(node, DI_PATH_NIL);
583 path != DI_PATH_NIL;
584 path = di_path_next_phci(node, path)) {
585 if ((phci = di_path_phci_node(path)) == DI_NODE_NIL) {
586 cfga_err(errstring, 0,
587 ERRARG_XPORT_NOT_IN_PHCI_LIST,
588 xport_phys, 0);
589 di_fini(root);
590 return (FPCFGA_LIB_ERR);
592 if ((phci_path = di_devfs_path(phci)) == NULL) {
593 cfga_err(errstring, 0,
594 ERRARG_XPORT_NOT_IN_PHCI_LIST,
595 xport_phys, 0);
596 di_fini(root);
597 return (FPCFGA_LIB_ERR);
599 (void) di_path_addr(path, (char *)phci_addr);
600 if ((phci_addr == NULL) || (*phci_addr == '\0')) {
601 cfga_err(errstring, 0,
602 ERRARG_XPORT_NOT_IN_PHCI_LIST,
603 xport_phys, 0);
604 di_devfs_path_free(phci_path);
605 di_fini(root);
606 return (FPCFGA_LIB_ERR);
609 * Check if the phci path has the same
610 * xport addr and the target addr with current lun
612 if ((strncmp(phci_path, pathname_ptr,
613 strlen(pathname_ptr)) == 0) &&
614 (strstr(phci_addr, dyncomp) != NULL)) {
615 /* SUCCESS Found xport_phys */
616 found = 1;
617 } else if ((di_path_state(path) ==
618 DI_PATH_STATE_ONLINE) ||
619 (di_path_state(path) == DI_PATH_STATE_STANDBY)) {
620 num_active_paths++;
621 } else {
623 * We have another path not in ONLINE/STANDBY
624 * state now, so should do a RCM online after
625 * the unconfiguration of current path.
627 non_operational_path_count++;
629 di_devfs_path_free(phci_path);
631 di_fini(root);
632 if (found == 1) {
633 if (num_active_paths != 0) {
635 * There are other ONLINE/STANDBY paths,
636 * so no need to do the RCM
638 lunlistp->lun_flag |= FLAG_SKIP_RCMREMOVE;
639 lunlistp->lun_flag |= FLAG_SKIP_RCMOFFLINE;
641 if (non_operational_path_count == 0) {
642 lunlistp->lun_flag |= FLAG_SKIP_ONLINEOTHERS;
644 } else {
646 * Fail all operations here
648 cfga_err(errstring, 0, ERRARG_XPORT_NOT_IN_PHCI_LIST,
649 xport_phys, 0);
650 return (FPCFGA_APID_NOEXIST);
654 /* Mark duplicated paths for same vhci in the list */
655 for (lunlistp = apidt->lunlist; lunlistp != NULL;
656 lunlistp = lunlistp->next) {
657 if (strncmp(lunlistp->path, SCSI_VHCI_ROOT,
658 strlen(SCSI_VHCI_ROOT)) != 0) {
659 continue;
661 for (temp = lunlistp->next; temp != NULL;
662 temp = temp->next) {
663 if (strcmp(lunlistp->path, temp->path) == 0) {
665 * don't do RCM for dup
667 lunlistp->lun_flag |= FLAG_SKIP_RCMREMOVE;
668 lunlistp->lun_flag |= FLAG_SKIP_RCMOFFLINE;
669 lunlistp->lun_flag |= FLAG_SKIP_ONLINEOTHERS;
673 return (FPCFGA_OK);
676 * apidt->dyncomp has to be non-NULL by the time this routine is called
678 fpcfga_ret_t
679 dev_change_state(cfga_cmd_t state_change_cmd, apid_t *apidt, la_wwn_t *pwwn,
680 cfga_flags_t flags, char **errstring, HBA_HANDLE handle,
681 HBA_PORTATTRIBUTES portAttrs)
683 char dev_path[MAXPATHLEN];
684 char *update_str, *t_apid;
685 int optflag = apidt->flags;
686 int no_config_attempt = 0;
687 fpcfga_ret_t ret;
688 apid_t my_apidt;
689 uchar_t unconf_flag = 0, peri_qual;
690 HBA_STATUS status;
691 HBA_PORTATTRIBUTES discPortAttrs;
692 uint64_t lun = 0;
693 struct scsi_inquiry inq;
694 struct scsi_extended_sense sense;
695 HBA_UINT8 scsiStatus;
696 uint32_t inquirySize = sizeof (inq),
697 senseSize = sizeof (sense);
698 report_lun_resp_t *resp_buf;
699 int i, l_errno, num_luns = 0;
700 uchar_t *lun_string;
702 if ((apidt->dyncomp == NULL) || (*apidt->dyncomp == '\0')) {
704 * No dynamic component specified. Just return success.
705 * Should not see this case. Just a safety check.
707 return (FPCFGA_OK);
710 /* Now construct the string we are going to put in the repository */
711 if ((update_str = calloc(1, (strlen(apidt->xport_phys) +
712 strlen(DYN_SEP) + strlen(apidt->dyncomp) + 1))) == NULL) {
713 cfga_err(errstring, errno, ERR_MEM_ALLOC, 0);
714 return (FPCFGA_LIB_ERR);
716 strcpy(update_str, apidt->xport_phys);
717 strcat(update_str, DYN_SEP);
718 strcat(update_str, apidt->dyncomp);
720 /* If force update of repository is sought, do it first */
721 if (optflag & FLAG_FORCE_UPDATE_REP) {
722 /* Ignore any failure in rep update */
723 (void) update_fabric_wwn_list(
724 ((state_change_cmd == CFGA_CMD_CONFIGURE) ?
725 ADD_ENTRY : REMOVE_ENTRY),
726 update_str, errstring);
729 memset(&sense, 0, sizeof (sense));
730 if ((ret = get_report_lun_data(apidt->xport_phys, apidt->dyncomp,
731 &num_luns, &resp_buf, &sense, &l_errno)) != FPCFGA_OK) {
733 * Checking the sense key data as well as the additional
734 * sense key. The SES Node is not required to repond
735 * to Report LUN. In the case of Minnow, the SES node
736 * returns with KEY_ILLEGAL_REQUEST and the additional
737 * sense key of 0x20. In this case we will blindly
738 * send the SCSI Inquiry call to lun 0
740 * if we get any other error we will set the inq_type
741 * appropriately
743 if ((sense.es_key == KEY_ILLEGAL_REQUEST) &&
744 (sense.es_add_code == 0x20)) {
745 lun = 0;
746 } else {
747 if (ret == FPCFGA_FCP_SEND_SCSI_DEV_NOT_TGT) {
748 inq.inq_dtype = DTYPE_UNKNOWN;
749 } else {
751 * Failed to get the LUN data for the device
752 * If we find that there is a lunlist for this
753 * device it could mean that there are dangling
754 * devinfo nodes. So, we will go ahead and try
755 * to unconfigure them.
757 if ((apidt->lunlist == NULL) ||
758 (state_change_cmd == CFGA_CMD_CONFIGURE)) {
759 S_FREE(update_str);
760 status = getPortAttrsByWWN(handle,
761 *((HBA_WWN *)(pwwn)),
762 &discPortAttrs);
763 if (status ==
764 HBA_STATUS_ERROR_ILLEGAL_WWN) {
765 return (FPCFGA_APID_NOEXIST);
766 } else {
767 cfga_err(errstring, 0,
768 ERRARG_FC_REP_LUNS,
769 apidt->dyncomp, 0);
770 return (FPCFGA_LIB_ERR);
772 } else {
773 /* unconfig with lunlist not empty */
774 no_config_attempt++;
779 for (i = 0; i < num_luns; i++) {
781 * issue the inquiry to the first valid lun found
782 * in the lun_string
784 lun_string = (uchar_t *)&(resp_buf->lun_string[i]);
785 memcpy(&lun, lun_string, sizeof (lun));
787 memset(&sense, 0, sizeof (sense));
788 status = HBA_ScsiInquiryV2(handle, portAttrs.PortWWN,
789 *(HBA_WWN *)(pwwn), lun, 0, 0, &inq, &inquirySize,
790 &scsiStatus, &sense, &senseSize);
792 * if Inquiry is returned correctly, check the
793 * peripheral qualifier for the lun. if it is non-zero
794 * then try the SCSI Inquiry on the next lun
796 if (status == HBA_STATUS_OK) {
797 peri_qual = inq.inq_dtype & FP_PERI_QUAL_MASK;
798 if (peri_qual == DPQ_POSSIBLE) {
799 break;
804 if (ret == FPCFGA_OK)
805 S_FREE(resp_buf);
808 * If there are no luns on this target, we will attempt to send
809 * the SCSI Inquiry to lun 0
811 if (num_luns == 0) {
812 lun = 0;
813 status = HBA_ScsiInquiryV2(handle, portAttrs.PortWWN,
814 *(HBA_WWN *)(pwwn), lun, 0, 0, &inq, &inquirySize,
815 &scsiStatus, &sense, &senseSize);
818 if (status != HBA_STATUS_OK) {
819 if (status == HBA_STATUS_ERROR_NOT_A_TARGET) {
820 inq.inq_dtype = DTYPE_UNKNOWN;
821 } else if (status == HBA_STATUS_ERROR_ILLEGAL_WWN) {
822 free(update_str);
823 return (FPCFGA_APID_NOEXIST);
824 } else {
826 * Failed to get the inq_dtype of device
827 * If we find that there is a lunlist for this
828 * device it could mean that there dangling
829 * devinfo nodes. So, we will go ahead and try
830 * to unconfigure them. We'll just set the
831 * inq_dtype to some invalid value (0xFF)
833 if ((apidt->lunlist == NULL) ||
834 (state_change_cmd == CFGA_CMD_CONFIGURE)) {
835 cfga_err(errstring, 0,
836 ERRARG_FC_INQUIRY,
837 apidt->dyncomp, 0);
838 free(update_str);
839 return (FPCFGA_LIB_ERR);
840 } else {
841 /* unconfig with lunlist not empty */
842 no_config_attempt++;
846 switch (state_change_cmd) {
847 case CFGA_CMD_CONFIGURE:
848 if (portAttrs.PortType != HBA_PORTTYPE_NLPORT &&
849 portAttrs.PortType != HBA_PORTTYPE_NPORT) {
850 free(update_str);
851 return (FPCFGA_OK);
854 if (((inq.inq_dtype & DTYPE_MASK) == DTYPE_UNKNOWN) &&
855 ((flags & CFGA_FLAG_FORCE) == 0)) {
857 * We assume all DTYPE_UNKNOWNs are HBAs and we wont
858 * waste time trying to config them. If they are not
859 * HBAs, then there is something wrong since they should
860 * have had a valid dtype.
862 * However, if the force flag is set (cfgadm -f), we
863 * go ahead and try to configure.
865 * In this path, however, the force flag is not set.
867 free(update_str);
868 return (FPCFGA_OK);
871 errno = 0;
873 * We'll issue the devctl_bus_dev_create() call even if the
874 * path exists in the devinfo tree. This is to take care of
875 * the situation where the device may be in a state other
876 * than the online and attached state.
878 if ((ret = do_devctl_dev_create(apidt, dev_path, MAXPATHLEN,
879 inq.inq_dtype, errstring)) != FPCFGA_OK) {
881 * Could not configure device. To provide a more
882 * meaningful error message, first see if the supplied port
883 * WWN is there on the fabric. Otherwise print the error
884 * message using the information received from the driver
886 status = getPortAttrsByWWN(handle, *((HBA_WWN *)(pwwn)),
887 &discPortAttrs);
888 S_FREE(update_str);
889 if (status == HBA_STATUS_ERROR_ILLEGAL_WWN) {
890 return (FPCFGA_APID_NOEXIST);
891 } else {
892 return (FPCFGA_LIB_ERR);
896 if (!(optflag & (FLAG_FORCE_UPDATE_REP|FLAG_NO_UPDATE_REP)) &&
897 update_fabric_wwn_list(ADD_ENTRY, update_str, errstring)) {
898 cfga_err(errstring, 0, ERR_CONF_OK_UPD_REP, 0);
901 S_FREE(update_str);
903 if ((apidt->flags & FLAG_DISABLE_RCM) == 0) {
905 * There may be multiple LUNs associated with the
906 * WWN we created nodes for. So, we'll call
907 * apidt_create() again and let it build a list of
908 * all the LUNs for this WWN using the devinfo tree.
909 * We will then online all those devices in RCM
911 if ((t_apid = calloc(1, strlen(apidt->xport_phys) +
912 strlen(DYN_SEP) +
913 strlen(apidt->dyncomp) + 1)) == NULL) {
914 cfga_err(errstring, errno, ERR_MEM_ALLOC, 0);
915 return (FPCFGA_LIB_ERR);
917 sprintf(t_apid, "%s%s%s", apidt->xport_phys, DYN_SEP,
918 apidt->dyncomp);
919 if ((ret = apidt_create(t_apid, &my_apidt,
920 errstring)) != FPCFGA_OK) {
921 free(t_apid);
922 return (ret);
925 my_apidt.flags = apidt->flags;
926 if ((ret = dev_rcm_online(&my_apidt, -1, flags,
927 NULL)) != FPCFGA_OK) {
928 cfga_err(errstring, 0, ERRARG_RCM_ONLINE,
929 apidt->lunlist->path, 0);
930 apidt_free(&my_apidt);
931 free(t_apid);
932 return (ret);
934 S_FREE(t_apid);
935 apidt_free(&my_apidt);
937 return (FPCFGA_OK);
939 case CFGA_CMD_UNCONFIGURE:
940 if (portAttrs.PortType != HBA_PORTTYPE_NLPORT &&
941 portAttrs.PortType != HBA_PORTTYPE_NPORT) {
942 free(update_str);
943 return (FPCFGA_OPNOTSUPP);
946 status = getPortAttrsByWWN(handle, *((HBA_WWN *)(pwwn)),
947 &discPortAttrs);
948 if (apidt->lunlist == NULL) {
950 * But first, remove entry from the repository if it is
951 * there ... provided the force update flag is not set
952 * (in which case the update is already done) or if
953 * the no-update flag is not set.
955 if ((optflag &
956 (FLAG_FORCE_UPDATE_REP|FLAG_NO_UPDATE_REP)) == 0) {
957 if (update_fabric_wwn_list(REMOVE_ENTRY,
958 update_str, errstring)) {
959 free(update_str);
960 cfga_err(errstring, 0,
961 ERR_UNCONF_OK_UPD_REP, 0);
962 return
963 (FPCFGA_UNCONF_OK_UPD_REP_FAILED);
966 S_FREE(update_str);
967 if (status == HBA_STATUS_ERROR_ILLEGAL_WWN) {
968 return (FPCFGA_APID_NOEXIST);
970 return (FPCFGA_OK);
973 * If there are multiple paths to the mpxio
974 * device, we will not check in RCM ONLY when there
975 * is atleast one other ONLINE/STANDBY path
977 if (is_xport_phys_in_pathlist(apidt, errstring) !=
978 FPCFGA_OK) {
979 free(update_str);
980 return (FPCFGA_XPORT_NOT_IN_PHCI_LIST);
984 * dev_rcm_offline() updates errstring
986 if ((ret = dev_rcm_offline(apidt, flags, errstring)) !=
987 FPCFGA_OK) {
988 free(update_str);
989 return (ret);
991 if ((ret = dev_unconf(apidt, errstring, &unconf_flag)) !=
992 FPCFGA_OK) {
993 /* when inq failed don't attempt to reconfigure */
994 if (!no_config_attempt) {
995 (void) do_devctl_dev_create(apidt, dev_path,
996 MAXPATHLEN, inq.inq_dtype, NULL);
997 (void) dev_rcm_online(apidt, -1, flags, NULL);
999 free(update_str);
1000 return (ret);
1002 if ((ret = dev_rcm_remove(apidt, flags, errstring)) !=
1003 FPCFGA_OK) {
1004 (void) do_devctl_dev_create(apidt, dev_path, MAXPATHLEN,
1005 inq.inq_dtype, NULL);
1006 (void) dev_rcm_online(apidt, -1, flags, NULL);
1007 free(update_str);
1008 return (ret);
1011 * If we offlined a lun in RCM when there are multiple paths but
1012 * none of them are ONLINE/STANDBY, we have to online it back
1013 * in RCM now. This is a try best, will not fail for it.
1015 dev_rcm_online_nonoperationalpath(apidt, flags, NULL);
1017 /* Update the repository if we havent already done it */
1018 if ((optflag &
1019 (FLAG_FORCE_UPDATE_REP|FLAG_NO_UPDATE_REP)) == 0) {
1020 if (((optflag & FLAG_REMOVE_UNUSABLE_FCP_DEV) !=
1021 FLAG_REMOVE_UNUSABLE_FCP_DEV) ||
1022 (((optflag & FLAG_REMOVE_UNUSABLE_FCP_DEV) ==
1023 FLAG_REMOVE_UNUSABLE_FCP_DEV) &&
1024 (unconf_flag == ALL_APID_LUNS_UNUSABLE))) {
1025 if (update_fabric_wwn_list(REMOVE_ENTRY,
1026 update_str, errstring)) {
1027 free(update_str);
1028 cfga_err(errstring, errno,
1029 ERR_UNCONF_OK_UPD_REP, 0);
1030 return
1031 (FPCFGA_UNCONF_OK_UPD_REP_FAILED);
1035 free(update_str);
1036 return (FPCFGA_OK);
1038 default:
1039 free(update_str);
1040 return (FPCFGA_OPNOTSUPP);
1045 * This function copies a port_wwn got by reading the property on a device
1046 * node (from_ptr in the function below) on to an array (to_ptr) so that it is
1047 * readable.
1049 * Caller responsible to allocate enough memory in "to_ptr"
1051 static void
1052 copy_pwwn_data_to_str(char *to_ptr, const uchar_t *from_ptr)
1054 if ((to_ptr == NULL) || (from_ptr == NULL))
1055 return;
1057 (void) sprintf(to_ptr, "%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x",
1058 from_ptr[0], from_ptr[1], from_ptr[2], from_ptr[3],
1059 from_ptr[4], from_ptr[5], from_ptr[6], from_ptr[7]);
1062 static fpcfga_ret_t
1063 unconf_vhci_nodes(di_path_t pnode, di_node_t fp_node, char *xport_phys,
1064 char *dyncomp, int unusable_flag,
1065 int *num_devs, int *failure_count, char **errstring,
1066 cfga_flags_t flags)
1068 int iret1, iret2, *lunnump;
1069 char *ptr; /* scratch pad */
1070 char *node_path, *vhci_path, *update_str;
1071 char port_wwn[WWN_SIZE*2+1], pathname[MAXPATHLEN];
1072 uchar_t *port_wwn_data = NULL;
1073 di_node_t client_node;
1075 while (pnode != DI_PATH_NIL) {
1077 (*num_devs)++;
1080 if ((node_path = di_devfs_path(fp_node)) == NULL) {
1081 cfga_err(errstring, 0, ERRARG_DEVINFO,
1082 xport_phys, 0);
1083 (*failure_count)++;
1084 pnode = di_path_next_client(fp_node, pnode);
1085 continue;
1088 iret1 = di_path_prop_lookup_bytes(pnode, PORT_WWN_PROP,
1089 &port_wwn_data);
1091 iret2 = di_path_prop_lookup_ints(pnode, LUN_PROP, &lunnump);
1093 if ((iret1 == -1) || (iret2 == -1)) {
1094 cfga_err(errstring, 0, ERRARG_DI_GET_PROP,
1095 node_path, 0);
1096 di_devfs_path_free(node_path);
1097 node_path = NULL;
1098 (*failure_count)++;
1099 pnode = di_path_next_client(fp_node, pnode);
1100 continue;
1103 copy_pwwn_data_to_str(port_wwn, port_wwn_data);
1105 if ((client_node = di_path_client_node(pnode)) == DI_NODE_NIL) {
1106 (*failure_count)++;
1107 di_devfs_path_free(node_path);
1108 node_path = NULL;
1109 pnode = di_path_next_client(fp_node, pnode);
1110 continue;
1113 if ((vhci_path = di_devfs_path(client_node)) == NULL) {
1114 (*failure_count)++;
1115 di_devfs_path_free(node_path);
1116 node_path = NULL;
1117 pnode = di_path_next_client(fp_node, pnode);
1118 continue;
1121 if ((ptr = strrchr(vhci_path, '@')) != NULL) {
1122 *ptr = '\0';
1125 if ((ptr = strrchr(vhci_path, '/')) == NULL) {
1126 (*failure_count)++;
1127 di_devfs_path_free(node_path);
1128 node_path = NULL;
1129 pnode = di_path_next_client(fp_node, pnode);
1130 continue;
1133 sprintf(pathname, "%s%s/%s@w%s,%x", DEVICES_DIR, node_path,
1134 ++ptr, port_wwn, *lunnump);
1136 di_devfs_path_free(node_path);
1137 di_devfs_path_free(vhci_path);
1138 node_path = vhci_path = NULL;
1141 * Try to offline in RCM first and if that is successful,
1142 * unconfigure the LUN. If offlining in RCM fails, then
1143 * update the failure_count which gets passed back to caller
1145 * Here we got to check if unusable_flag is set or not.
1146 * If set, then unconfigure only those luns which are in
1147 * node_state DI_PATH_STATE_OFFLINE. If not set, unconfigure
1148 * all luns.
1150 if ((unusable_flag & FLAG_REMOVE_UNUSABLE_FCP_DEV) ==
1151 FLAG_REMOVE_UNUSABLE_FCP_DEV) {
1152 if (pnode->path_state == DI_PATH_STATE_OFFLINE) {
1153 if (fp_rcm_offline(pathname, errstring,
1154 flags) != 0) {
1155 (*failure_count)++;
1156 pnode = di_path_next_client(fp_node,
1157 pnode);
1158 continue;
1159 } else if (lun_unconf(pathname, *lunnump,
1160 xport_phys, dyncomp, errstring)
1161 != FPCFGA_OK) {
1162 (void) fp_rcm_online(pathname,
1163 NULL, flags);
1164 (*failure_count)++;
1165 pnode = di_path_next_client(fp_node,
1166 pnode);
1167 continue;
1168 } else if (fp_rcm_remove(pathname, errstring,
1169 flags) != 0) {
1171 * Bring everything back online
1172 * in rcm and continue
1174 (void) fp_rcm_online(pathname,
1175 NULL, flags);
1176 (*failure_count)++;
1177 pnode = di_path_next_client(fp_node,
1178 pnode);
1179 continue;
1181 } else {
1182 pnode = di_path_next(fp_node, pnode);
1183 continue;
1185 } else {
1186 if (fp_rcm_offline(pathname, errstring, flags) != 0) {
1187 (*failure_count)++;
1188 pnode = di_path_next_client(fp_node, pnode);
1189 continue;
1190 } else if (lun_unconf(pathname, *lunnump, xport_phys,
1191 dyncomp, errstring) != FPCFGA_OK) {
1192 (void) fp_rcm_online(pathname, NULL, flags);
1193 (*failure_count)++;
1194 pnode = di_path_next_client(fp_node, pnode);
1195 continue;
1196 } else if (fp_rcm_remove(pathname, errstring,
1197 flags) != 0) {
1199 * Bring everything back online
1200 * in rcm and continue
1202 (void) fp_rcm_online(pathname, NULL, flags);
1203 (*failure_count)++;
1204 pnode = di_path_next_client(fp_node, pnode);
1205 continue;
1209 /* Update the repository only on a successful unconfigure */
1210 if ((update_str = calloc(1, strlen(xport_phys) +
1211 strlen(DYN_SEP) + strlen(port_wwn) + 1)) == NULL) {
1212 cfga_err(errstring, errno, ERR_UNCONF_OK_UPD_REP, 0);
1213 (*failure_count)++;
1214 pnode = di_path_next_client(fp_node, pnode);
1215 continue;
1218 /* Init the string to be removed from repository */
1219 sprintf(update_str, "%s%s%s", xport_phys, DYN_SEP, port_wwn);
1221 if (update_fabric_wwn_list(REMOVE_ENTRY, update_str,
1222 errstring)) {
1223 S_FREE(update_str);
1224 cfga_err(errstring, errno,
1225 ERR_UNCONF_OK_UPD_REP, 0);
1226 (*failure_count)++;
1227 /* Cleanup and continue from here just for clarity */
1228 pnode = di_path_next_client(fp_node, pnode);
1229 continue;
1232 S_FREE(update_str);
1233 pnode = di_path_next_client(fp_node, pnode);
1236 return (FPCFGA_OK);
1239 static fpcfga_ret_t
1240 unconf_non_vhci_nodes(di_node_t dnode, char *xport_phys, char *dyncomp,
1241 int unusable_flag, int *num_devs, int *failure_count,
1242 char **errstring, cfga_flags_t flags)
1244 int ret1, ret2, *lunnump;
1245 char pathname[MAXPATHLEN];
1246 char *node_path, *update_str;
1247 char port_wwn[WWN_SIZE*2+1];
1248 uchar_t *port_wwn_data = NULL;
1250 while (dnode != DI_NODE_NIL) {
1252 (*num_devs)++;
1254 /* Get the physical path for this node */
1255 if ((node_path = di_devfs_path(dnode)) == NULL) {
1257 * We don't try to offline in RCM here because we
1258 * don't know the path to offline. Just continue to
1259 * the next node.
1261 cfga_err(errstring, 0, ERRARG_DEVINFO, xport_phys, 0);
1262 (*failure_count)++;
1263 dnode = di_sibling_node(dnode);
1264 continue;
1267 /* Now get the LUN # of this device thru the property */
1268 ret1 = di_prop_lookup_ints(DDI_DEV_T_ANY, dnode,
1269 LUN_PROP, &lunnump);
1271 /* Next get the port WWN of the device */
1272 ret2 = di_prop_lookup_bytes(DDI_DEV_T_ANY, dnode,
1273 PORT_WWN_PROP, &port_wwn_data);
1275 /* A failure in any of the above is not good */
1276 if ((ret1 == -1) || (ret2 == -1)) {
1278 * We don't try to offline in RCM here because we
1279 * don't know the path to offline. Just continue to
1280 * the next node.
1282 cfga_err(errstring, 0,
1283 ERRARG_DI_GET_PROP, node_path, 0);
1284 di_devfs_path_free(node_path);
1285 node_path = NULL;
1286 (*failure_count)++;
1287 dnode = di_sibling_node(dnode);
1288 continue;
1291 /* Prepend the "/devices" prefix to the path and copy it */
1292 sprintf(pathname, "%s%s", DEVICES_DIR, node_path);
1293 di_devfs_path_free(node_path);
1294 node_path = NULL;
1296 copy_pwwn_data_to_str(port_wwn, port_wwn_data);
1298 if (strstr(pathname, "@w") == NULL) {
1300 * If the driver is detached, some part of the path
1301 * may be missing and so we'll manually construct it
1303 sprintf(&pathname[strlen(pathname)], "@w%s,%x",
1304 port_wwn, *lunnump);
1308 * Try to offline in RCM first and if that is successful,
1309 * unconfigure the LUN. If offlining in RCM fails, then
1310 * update the failure count
1312 * Here we got to check if unusable_flag is set or not.
1313 * If set, then unconfigure only those luns which are in
1314 * node_state DI_DEVICE_OFFLINE or DI_DEVICE_DOWN.
1315 * If not set, unconfigure all luns.
1317 if ((unusable_flag & FLAG_REMOVE_UNUSABLE_FCP_DEV) ==
1318 FLAG_REMOVE_UNUSABLE_FCP_DEV) {
1319 if ((dnode->node_state == DI_DEVICE_OFFLINE) ||
1320 (dnode->node_state == DI_DEVICE_DOWN)) {
1321 if (fp_rcm_offline(pathname, errstring,
1322 flags) != 0) {
1323 (*failure_count)++;
1324 dnode = di_sibling_node(dnode);
1325 continue;
1326 } else if (lun_unconf(pathname, *lunnump,
1327 xport_phys, dyncomp, errstring)
1328 != FPCFGA_OK) {
1329 (void) fp_rcm_online(pathname,
1330 NULL, flags);
1331 (*failure_count)++;
1332 dnode = di_sibling_node(dnode);
1333 continue;
1334 } else if (fp_rcm_remove(pathname, errstring,
1335 flags) != 0) {
1337 * Bring everything back online
1338 * in rcm and continue
1340 (void) fp_rcm_online(pathname,
1341 NULL, flags);
1342 (*failure_count)++;
1343 dnode = di_sibling_node(dnode);
1344 continue;
1346 } else {
1347 dnode = di_sibling_node(dnode);
1348 continue;
1350 } else {
1351 if (fp_rcm_offline(pathname, errstring, flags) != 0) {
1352 (*failure_count)++;
1353 dnode = di_sibling_node(dnode);
1354 continue;
1355 } else if (lun_unconf(pathname, *lunnump, xport_phys,
1356 dyncomp, errstring) != FPCFGA_OK) {
1357 (void) fp_rcm_online(pathname, NULL, flags);
1358 (*failure_count)++;
1359 dnode = di_sibling_node(dnode);
1360 continue;
1361 } else if (fp_rcm_remove(pathname, errstring,
1362 flags) != 0) {
1364 * Bring everything back online
1365 * in rcm and continue
1367 (void) fp_rcm_online(pathname, NULL, flags);
1368 (*failure_count)++;
1369 dnode = di_sibling_node(dnode);
1370 continue;
1374 /* Update the repository only on a successful unconfigure */
1375 if ((update_str = calloc(1, strlen(xport_phys) +
1376 strlen(DYN_SEP) +
1377 strlen(port_wwn) + 1)) == NULL) {
1378 cfga_err(errstring, errno, ERR_UNCONF_OK_UPD_REP, 0);
1379 (*failure_count)++;
1380 dnode = di_sibling_node(dnode);
1381 continue;
1384 /* Init the string to be removed from repository */
1385 sprintf(update_str, "%s%s%s", xport_phys, DYN_SEP, port_wwn);
1387 if (update_fabric_wwn_list(REMOVE_ENTRY, update_str,
1388 errstring)) {
1389 S_FREE(update_str);
1390 cfga_err(errstring, errno, ERR_UNCONF_OK_UPD_REP, 0);
1391 (*failure_count)++;
1392 dnode = di_sibling_node(dnode);
1393 continue;
1396 S_FREE(update_str);
1397 dnode = di_sibling_node(dnode);
1400 return (FPCFGA_OK);
1404 * INPUT:
1405 * apidt - Pointer to apid_t structure with data filled in
1406 * flags - Flags for special handling
1408 * OUTPUT:
1409 * errstring - Applicable only on a failure from plugin
1410 * num_devs - Incremented per lun
1411 * failure_count - Incremented on any failed operation on lun
1413 * RETURNS:
1414 * non-FPCFGA_OK on any validation check error. If this value is returned, no
1415 * devices were handled. Consequently num_devs and failure_count
1416 * will not be incremented.
1417 * FPCFGA_OK This return value doesn't mean that all devices were successfully
1418 * unconfigured, you have to check failure_count.
1420 static fpcfga_ret_t
1421 unconf_any_devinfo_nodes(apid_t *apidt, cfga_flags_t flags, char **errstring,
1422 int *num_devs, int *failure_count)
1424 char *node_path = NULL;
1425 char pathname[MAXPATHLEN], *ptr; /* scratch pad */
1426 di_node_t root_node, direct_node, fp_node;
1427 di_path_t path_node = DI_PATH_NIL;
1430 * apidt->xport_phys is something like :
1431 * /devices/pci@.../SUNW,qlc@../fp@0,0:fc
1432 * Make sure we copy both the devinfo and pathinfo nodes
1434 (void) strlcpy(pathname, apidt->xport_phys, MAXPATHLEN);
1436 /* Now get rid of the ':' at the end */
1437 if ((ptr = strstr(pathname, MINOR_SEP)) != NULL)
1438 *ptr = '\0';
1440 if (strncmp(pathname, DEVICES_DIR, strlen(DEVICES_DIR))) {
1441 cfga_err(errstring, 0, ERRARG_INVALID_PATH, pathname, 0);
1442 return (FPCFGA_INVALID_PATH);
1445 if ((root_node = di_init("/", DINFOCPYALL | DINFOPATH)) ==
1446 DI_NODE_NIL) {
1447 cfga_err(errstring, errno, ERRARG_DEVINFO,
1448 apidt->xport_phys, 0);
1449 return (FPCFGA_LIB_ERR);
1452 if ((fp_node = di_drv_first_node("fp", root_node)) == DI_NODE_NIL) {
1453 cfga_err(errstring, errno, ERRARG_DEVINFO,
1454 apidt->xport_phys, 0);
1455 di_fini(root_node);
1456 return (FPCFGA_LIB_ERR);
1460 * Search all the fp nodes to see if any match the one we are trying
1461 * to unconfigure
1464 /* Skip the "/devices" prefix */
1465 ptr = pathname + strlen(DEVICES_DIR);
1467 while (fp_node != DI_NODE_NIL) {
1468 node_path = di_devfs_path(fp_node);
1469 if (strcmp(node_path, ptr) == 0) {
1470 /* Found the fp node. 'pathname' has the full path */
1471 di_devfs_path_free(node_path);
1472 node_path = NULL;
1473 break;
1475 fp_node = di_drv_next_node(fp_node);
1476 di_devfs_path_free(node_path);
1479 if (fp_node == DI_NODE_NIL) {
1480 cfga_err(errstring, 0, ERRARG_NOT_IN_DEVINFO,
1481 apidt->xport_phys, 0);
1482 di_fini(root_node);
1483 return (FPCFGA_LIB_ERR);
1486 direct_node = di_child_node(fp_node);
1487 path_node = di_path_next_client(fp_node, path_node);
1489 if ((direct_node == DI_NODE_NIL) && (path_node == DI_PATH_NIL)) {
1490 /* No devinfo or pathinfo nodes. Great ! Just return success */
1491 di_fini(root_node);
1492 return (FPCFGA_OK);
1495 /* First unconfigure any non-MPXIO nodes */
1496 unconf_non_vhci_nodes(direct_node, apidt->xport_phys, apidt->dyncomp,
1497 apidt->flags, num_devs, failure_count, errstring, flags);
1500 * Now we will traverse any path info nodes that are there
1502 * Only MPXIO devices have pathinfo nodes
1504 unconf_vhci_nodes(path_node, fp_node, apidt->xport_phys, apidt->dyncomp,
1505 apidt->flags, num_devs, failure_count, errstring, flags);
1507 di_fini(root_node);
1510 * We don't want to check the return value of unconf_non_vhci_nodes()
1511 * and unconf_vhci_nodes(). But instead, we are interested only in
1512 * consistently incrementing num_devs and failure_count so that we can
1513 * compare them.
1515 return (FPCFGA_OK);
1519 * This function handles configuring/unconfiguring all the devices w.r.t
1520 * the FCA port specified by apidt.
1522 * In the unconfigure case, it first unconfigures all the devices that are
1523 * seen through the given port at that moment and then unconfigures all the
1524 * devices that still (somehow) have devinfo nodes on the system for that FCA
1525 * port.
1527 * INPUT:
1528 * cmd - CFGA_CMD_CONFIGURE or CFGA_CMD_UNCONFIGURE
1529 * apidt - Pointer to apid_t structure with data filled in
1530 * flags - Flags for special handling
1532 * OUTPUT:
1533 * errstring - Applicable only on a failure from plugin
1535 * RETURNS:
1536 * FPCFGA_OK on success
1537 * non-FPCFGA_OK otherwise
1539 static fpcfga_ret_t
1540 handle_devs(cfga_cmd_t cmd, apid_t *apidt, cfga_flags_t flags,
1541 char **errstring, HBA_HANDLE handle, int portIndex,
1542 HBA_PORTATTRIBUTES portAttrs)
1544 int num_devs = 0, dev_cs_failed = 0;
1545 char port_wwn[WWN_S_LEN];
1546 la_wwn_t pwwn;
1547 apid_t my_apidt = {NULL};
1548 char *my_apid;
1549 HBA_PORTATTRIBUTES discPortAttrs;
1550 int discIndex;
1551 fpcfga_ret_t rval = FPCFGA_OK;
1553 if ((my_apid = calloc(
1554 1, strlen(apidt->xport_phys) + strlen(DYN_SEP) +
1555 (2 * FC_WWN_SIZE) + 1)) == NULL) {
1556 cfga_err(errstring, errno, ERR_MEM_ALLOC, 0);
1557 return (FPCFGA_LIB_ERR);
1560 num_devs = portAttrs.NumberofDiscoveredPorts;
1561 for (discIndex = 0; discIndex < portAttrs.NumberofDiscoveredPorts;
1562 discIndex++) {
1563 if (getDiscPortAttrs(handle, portIndex,
1564 discIndex, &discPortAttrs)) {
1565 dev_cs_failed++;
1566 /* Move on to the next target */
1567 continue;
1569 (void) sprintf(port_wwn, "%016llx",
1570 wwnConversion(discPortAttrs.PortWWN.wwn));
1572 * Construct a fake apid string similar to the one the
1573 * plugin gets from the framework and have apidt_create()
1574 * fill in the apid_t structure.
1576 strcpy(my_apid, apidt->xport_phys);
1577 strcat(my_apid, DYN_SEP);
1578 strcat(my_apid, port_wwn);
1579 if (apidt_create(my_apid, &my_apidt, errstring) != FPCFGA_OK) {
1580 dev_cs_failed++;
1581 continue;
1583 my_apidt.flags = apidt->flags;
1585 memcpy(&pwwn, &(discPortAttrs.PortWWN), sizeof (la_wwn_t));
1586 if (dev_change_state(cmd, &my_apidt, &pwwn,
1587 flags, errstring, handle, portAttrs) != FPCFGA_OK) {
1588 dev_cs_failed++;
1590 apidt_free(&my_apidt);
1593 S_FREE(my_apid);
1596 * We have now handled all the devices that are currently visible
1597 * through the given FCA port. But, it is possible that there are
1598 * some devinfo nodes hanging around. For the unconfigure operation,
1599 * this has to be looked into too.
1601 if (cmd == CFGA_CMD_UNCONFIGURE) {
1602 /* dev_cs_failed will be updated to indicate any failures */
1603 rval = unconf_any_devinfo_nodes(apidt, flags, errstring,
1604 &num_devs, &dev_cs_failed);
1607 if (rval == FPCFGA_OK) {
1608 if (dev_cs_failed == 0)
1609 return (FPCFGA_OK);
1612 * For the discovered ports, num_devs is counted on target
1613 * basis, but for invisible targets, num_devs is counted on
1614 * lun basis.
1616 * But if dev_cs_failed and num_devs are incremented
1617 * consistently, comparation of these two counters is still
1618 * meaningful.
1620 if (dev_cs_failed == num_devs) {
1621 /* Failed on all devices seen through this FCA port */
1622 cfga_err(errstring, 0,
1623 ((cmd == CFGA_CMD_CONFIGURE) ?
1624 ERR_FCA_CONFIGURE : ERR_FCA_UNCONFIGURE), 0);
1625 return (FPCFGA_LIB_ERR);
1626 } else {
1627 /* Failed only on some of the devices */
1628 cfga_err(errstring, 0, ERR_PARTIAL_SUCCESS, 0);
1629 return (FPCFGA_LIB_ERR);
1631 } else {
1632 if (dev_cs_failed == num_devs) {
1633 /* Failed on all devices seen through this FCA port */
1634 cfga_err(errstring, 0,
1635 ((cmd == CFGA_CMD_CONFIGURE) ?
1636 ERR_FCA_CONFIGURE : ERR_FCA_UNCONFIGURE), 0);
1637 return (FPCFGA_LIB_ERR);
1638 } else {
1639 /* Failed only on some of the devices */
1640 cfga_err(errstring, 0, ERR_PARTIAL_SUCCESS, 0);
1641 return (FPCFGA_LIB_ERR);
1646 * Should never get here
1650 fpcfga_ret_t
1651 fca_change_state(cfga_cmd_t state_change_cmd, apid_t *apidt,
1652 cfga_flags_t flags, char **errstring)
1654 fpcfga_ret_t ret;
1655 HBA_HANDLE handle;
1656 HBA_PORTATTRIBUTES portAttrs;
1657 int portIndex;
1659 if ((ret = findMatchingAdapterPort(apidt->xport_phys, &handle,
1660 &portIndex, &portAttrs, errstring)) != FPCFGA_OK) {
1661 return (ret);
1665 * Bail out if not fabric/public loop
1667 switch (state_change_cmd) {
1668 case CFGA_CMD_CONFIGURE:
1669 if (portAttrs.PortType != HBA_PORTTYPE_NLPORT &&
1670 portAttrs.PortType != HBA_PORTTYPE_NPORT) {
1671 HBA_CloseAdapter(handle);
1672 HBA_FreeLibrary();
1673 return (FPCFGA_OK);
1675 break;
1677 case CFGA_CMD_UNCONFIGURE:
1678 if (portAttrs.PortType != HBA_PORTTYPE_NLPORT &&
1679 portAttrs.PortType != HBA_PORTTYPE_NPORT) {
1680 HBA_CloseAdapter(handle);
1681 HBA_FreeLibrary();
1682 return (FPCFGA_OPNOTSUPP);
1684 break;
1685 default:
1686 HBA_CloseAdapter(handle);
1687 HBA_FreeLibrary();
1688 return (FPCFGA_LIB_ERR);
1690 ret = (handle_devs(state_change_cmd, apidt, flags, errstring,
1691 handle, portIndex, portAttrs));
1692 HBA_CloseAdapter(handle);
1693 HBA_FreeLibrary();
1694 return (ret);