xref: /onnv-gate/usr/src/lib/cfgadm_plugins/fp/common/cfga_cs.c (revision 9240:9f612b5a857d)
17836SJohn.Forte@Sun.COM /*
27836SJohn.Forte@Sun.COM  * CDDL HEADER START
37836SJohn.Forte@Sun.COM  *
47836SJohn.Forte@Sun.COM  * The contents of this file are subject to the terms of the
57836SJohn.Forte@Sun.COM  * Common Development and Distribution License (the "License").
67836SJohn.Forte@Sun.COM  * You may not use this file except in compliance with the License.
77836SJohn.Forte@Sun.COM  *
87836SJohn.Forte@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97836SJohn.Forte@Sun.COM  * or http://www.opensolaris.org/os/licensing.
107836SJohn.Forte@Sun.COM  * See the License for the specific language governing permissions
117836SJohn.Forte@Sun.COM  * and limitations under the License.
127836SJohn.Forte@Sun.COM  *
137836SJohn.Forte@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
147836SJohn.Forte@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157836SJohn.Forte@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
167836SJohn.Forte@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
177836SJohn.Forte@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
187836SJohn.Forte@Sun.COM  *
197836SJohn.Forte@Sun.COM  * CDDL HEADER END
207836SJohn.Forte@Sun.COM  */
217836SJohn.Forte@Sun.COM /*
22*9240SRaghuram.Prahlada@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
237836SJohn.Forte@Sun.COM  * Use is subject to license terms.
247836SJohn.Forte@Sun.COM  */
257836SJohn.Forte@Sun.COM 
267836SJohn.Forte@Sun.COM 
277836SJohn.Forte@Sun.COM #include	"cfga_fp.h"
287836SJohn.Forte@Sun.COM 
297836SJohn.Forte@Sun.COM /* define */
307836SJohn.Forte@Sun.COM #define	ALL_APID_LUNS_UNUSABLE	0x10
317836SJohn.Forte@Sun.COM 
327836SJohn.Forte@Sun.COM #define	DEFAULT_LUN_COUNT	1024
337836SJohn.Forte@Sun.COM #define	LUN_SIZE		8
347836SJohn.Forte@Sun.COM #define	LUN_HEADER_SIZE		8
357836SJohn.Forte@Sun.COM #define	DEFAULT_LUN_LENGTH	DEFAULT_LUN_COUNT   *	\
367836SJohn.Forte@Sun.COM 				LUN_SIZE	    +	\
377836SJohn.Forte@Sun.COM 				LUN_HEADER_SIZE
387836SJohn.Forte@Sun.COM 
397836SJohn.Forte@Sun.COM /* Some forward declarations */
407836SJohn.Forte@Sun.COM static fpcfga_ret_t do_devctl_dev_create(apid_t *, char *, int,
417836SJohn.Forte@Sun.COM 							uchar_t, char **);
427836SJohn.Forte@Sun.COM static fpcfga_ret_t dev_rcm_online(apid_t *, int, cfga_flags_t, char **);
437836SJohn.Forte@Sun.COM static void dev_rcm_online_nonoperationalpath(apid_t *, cfga_flags_t, char **);
447836SJohn.Forte@Sun.COM static fpcfga_ret_t dev_rcm_offline(apid_t *, cfga_flags_t, char **);
457836SJohn.Forte@Sun.COM static fpcfga_ret_t dev_rcm_remove(apid_t *, cfga_flags_t, char **);
467836SJohn.Forte@Sun.COM static fpcfga_ret_t lun_unconf(char *, int, char *, char *, char **);
477836SJohn.Forte@Sun.COM static fpcfga_ret_t dev_unconf(apid_t *, char **, uchar_t *);
487836SJohn.Forte@Sun.COM static fpcfga_ret_t is_xport_phys_in_pathlist(apid_t *, char **);
497836SJohn.Forte@Sun.COM static void copy_pwwn_data_to_str(char *, const uchar_t *);
507836SJohn.Forte@Sun.COM static fpcfga_ret_t unconf_vhci_nodes(di_path_t, di_node_t, char *,
51*9240SRaghuram.Prahlada@Sun.COM 			char *, int, int *, int *, char **, cfga_flags_t);
527836SJohn.Forte@Sun.COM static fpcfga_ret_t unconf_non_vhci_nodes(di_node_t, char *, char *,
53*9240SRaghuram.Prahlada@Sun.COM 			int, int *, int *, char **, cfga_flags_t);
547836SJohn.Forte@Sun.COM static fpcfga_ret_t unconf_any_devinfo_nodes(apid_t *, cfga_flags_t, char **,
557836SJohn.Forte@Sun.COM 			int *, int *);
567836SJohn.Forte@Sun.COM static fpcfga_ret_t handle_devs(cfga_cmd_t, apid_t *, cfga_flags_t,
577836SJohn.Forte@Sun.COM 			char **, HBA_HANDLE, int, HBA_PORTATTRIBUTES);
587836SJohn.Forte@Sun.COM 
597836SJohn.Forte@Sun.COM 
607836SJohn.Forte@Sun.COM /*
617836SJohn.Forte@Sun.COM  * This function initiates the creation of the new device node for a given
627836SJohn.Forte@Sun.COM  * port WWN.
637836SJohn.Forte@Sun.COM  * So, apidt->dyncomp CANNOT be NULL
647836SJohn.Forte@Sun.COM  */
657836SJohn.Forte@Sun.COM static fpcfga_ret_t
do_devctl_dev_create(apid_t * apidt,char * dev_path,int pathlen,uchar_t dev_dtype,char ** errstring)667836SJohn.Forte@Sun.COM do_devctl_dev_create(apid_t *apidt, char *dev_path, int pathlen,
677836SJohn.Forte@Sun.COM 					uchar_t dev_dtype, char **errstring)
687836SJohn.Forte@Sun.COM {
697836SJohn.Forte@Sun.COM 	devctl_ddef_t	ddef_hdl;
707836SJohn.Forte@Sun.COM 	devctl_hdl_t	bus_hdl, dev_hdl;
717836SJohn.Forte@Sun.COM 	char		*drvr_name = "dummy";
727836SJohn.Forte@Sun.COM 	la_wwn_t	pwwn;
737836SJohn.Forte@Sun.COM 
747836SJohn.Forte@Sun.COM 	*dev_path = NULL;
757836SJohn.Forte@Sun.COM 	if ((ddef_hdl = devctl_ddef_alloc(drvr_name, 0)) == NULL) {
767836SJohn.Forte@Sun.COM 		cfga_err(errstring, errno, ERRARG_DC_DDEF_ALLOC, drvr_name, 0);
777836SJohn.Forte@Sun.COM 		return (FPCFGA_LIB_ERR);
787836SJohn.Forte@Sun.COM 	}
797836SJohn.Forte@Sun.COM 
807836SJohn.Forte@Sun.COM 	if (cvt_dyncomp_to_lawwn(apidt->dyncomp, &pwwn)) {
817836SJohn.Forte@Sun.COM 		devctl_ddef_free(ddef_hdl);
827836SJohn.Forte@Sun.COM 		cfga_err(errstring, 0, ERR_APID_INVAL, 0);
837836SJohn.Forte@Sun.COM 		return (FPCFGA_LIB_ERR);
847836SJohn.Forte@Sun.COM 	}
857836SJohn.Forte@Sun.COM 
867836SJohn.Forte@Sun.COM 	if (devctl_ddef_byte_array(ddef_hdl, PORT_WWN_PROP, FC_WWN_SIZE,
877836SJohn.Forte@Sun.COM 							pwwn.raw_wwn) == -1) {
887836SJohn.Forte@Sun.COM 		devctl_ddef_free(ddef_hdl);
897836SJohn.Forte@Sun.COM 		cfga_err(errstring, errno, ERRARG_DC_BYTE_ARRAY,
907836SJohn.Forte@Sun.COM 							PORT_WWN_PROP, 0);
917836SJohn.Forte@Sun.COM 		return (FPCFGA_LIB_ERR);
927836SJohn.Forte@Sun.COM 	}
937836SJohn.Forte@Sun.COM 
947836SJohn.Forte@Sun.COM 	if ((bus_hdl = devctl_bus_acquire(apidt->xport_phys, 0)) == NULL) {
957836SJohn.Forte@Sun.COM 		devctl_ddef_free(ddef_hdl);
967836SJohn.Forte@Sun.COM 		cfga_err(errstring, errno, ERRARG_DC_BUS_ACQUIRE,
977836SJohn.Forte@Sun.COM 							apidt->xport_phys, 0);
987836SJohn.Forte@Sun.COM 		return (FPCFGA_LIB_ERR);
997836SJohn.Forte@Sun.COM 	}
1007836SJohn.Forte@Sun.COM 
1017836SJohn.Forte@Sun.COM 	/* Let driver handle creation of the new path */
1027836SJohn.Forte@Sun.COM 	if (devctl_bus_dev_create(bus_hdl, ddef_hdl, 0, &dev_hdl)) {
1037836SJohn.Forte@Sun.COM 		devctl_ddef_free(ddef_hdl);
1047836SJohn.Forte@Sun.COM 		devctl_release(bus_hdl);
1057836SJohn.Forte@Sun.COM 		if (dev_dtype == DTYPE_UNKNOWN) {
1067836SJohn.Forte@Sun.COM 			/*
1077836SJohn.Forte@Sun.COM 			 * Unknown DTYPES are devices such as another system's
1087836SJohn.Forte@Sun.COM 			 * FC HBA port. We have tried to configure it but
1097836SJohn.Forte@Sun.COM 			 * have failed. Since devices with no device type
1107836SJohn.Forte@Sun.COM 			 * or an unknown dtype cannot be configured, we will
1117836SJohn.Forte@Sun.COM 			 * return an appropriate error message.
1127836SJohn.Forte@Sun.COM 			 */
1137836SJohn.Forte@Sun.COM 			cfga_err(errstring, errno,
1147836SJohn.Forte@Sun.COM 			    ERRARG_BUS_DEV_CREATE_UNKNOWN, apidt->dyncomp, 0);
1157836SJohn.Forte@Sun.COM 		} else {
1167836SJohn.Forte@Sun.COM 			cfga_err(errstring, errno, ERRARG_BUS_DEV_CREATE,
1177836SJohn.Forte@Sun.COM 			    apidt->dyncomp, 0);
1187836SJohn.Forte@Sun.COM 		}
1197836SJohn.Forte@Sun.COM 		return (FPCFGA_LIB_ERR);
1207836SJohn.Forte@Sun.COM 	}
1217836SJohn.Forte@Sun.COM 	devctl_release(bus_hdl);
1227836SJohn.Forte@Sun.COM 	devctl_ddef_free(ddef_hdl);
1237836SJohn.Forte@Sun.COM 
1247836SJohn.Forte@Sun.COM 	devctl_get_pathname(dev_hdl, dev_path, pathlen);
1257836SJohn.Forte@Sun.COM 	devctl_release(dev_hdl);
1267836SJohn.Forte@Sun.COM 
1277836SJohn.Forte@Sun.COM 	return (FPCFGA_OK);
1287836SJohn.Forte@Sun.COM }
1297836SJohn.Forte@Sun.COM 
1307836SJohn.Forte@Sun.COM /*
1317836SJohn.Forte@Sun.COM  * Online, in RCM, all the LUNs for a particular device.
1327836SJohn.Forte@Sun.COM  * Caller can specify the # of luns in the lunlist that have to be onlined
1337836SJohn.Forte@Sun.COM  * by passing a count that is not -ve.
1347836SJohn.Forte@Sun.COM  *
1357836SJohn.Forte@Sun.COM  * INPUT :
1367836SJohn.Forte@Sun.COM  * apidt - this is expected to have the list of luns for the device and so
1377836SJohn.Forte@Sun.COM  *         is assumed to be filled in prior to this call
1387836SJohn.Forte@Sun.COM  * count - # of LUNs in the list that have to be onlined.
1397836SJohn.Forte@Sun.COM  * errstring - If non-NULL, it will hold any error messages
1407836SJohn.Forte@Sun.COM  *
1417836SJohn.Forte@Sun.COM  * RETURNS :
1427836SJohn.Forte@Sun.COM  * 0 on success
1437836SJohn.Forte@Sun.COM  * non-zero otherwise
1447836SJohn.Forte@Sun.COM  */
1457836SJohn.Forte@Sun.COM static fpcfga_ret_t
dev_rcm_online(apid_t * apidt,int count,cfga_flags_t flags,char ** errstring)1467836SJohn.Forte@Sun.COM dev_rcm_online(apid_t *apidt, int count, cfga_flags_t flags, char **errstring)
1477836SJohn.Forte@Sun.COM {
1487836SJohn.Forte@Sun.COM 	luninfo_list_t	*lunlistp;
1497836SJohn.Forte@Sun.COM 	int		i = 0, ret = 0;
1507836SJohn.Forte@Sun.COM 	fpcfga_ret_t	retval = FPCFGA_OK;
1517836SJohn.Forte@Sun.COM 
1527836SJohn.Forte@Sun.COM 	/* This check may be redundant, but safer this way */
1537836SJohn.Forte@Sun.COM 	if ((apidt->flags & FLAG_DISABLE_RCM) != 0) {
1547836SJohn.Forte@Sun.COM 		/* User has requested not to notify RCM framework */
1557836SJohn.Forte@Sun.COM 		return (FPCFGA_OK);
1567836SJohn.Forte@Sun.COM 	}
1577836SJohn.Forte@Sun.COM 
1587836SJohn.Forte@Sun.COM 	lunlistp = apidt->lunlist;
1597836SJohn.Forte@Sun.COM 
1607836SJohn.Forte@Sun.COM 	for (lunlistp = apidt->lunlist; lunlistp != NULL;
1617836SJohn.Forte@Sun.COM 					i++, lunlistp = lunlistp->next) {
1627836SJohn.Forte@Sun.COM 		if ((count >= 0) && (i >= count))
1637836SJohn.Forte@Sun.COM 			break;
1647836SJohn.Forte@Sun.COM 		if (fp_rcm_online(lunlistp->path, errstring, flags) !=
1657836SJohn.Forte@Sun.COM 								FPCFGA_OK) {
1667836SJohn.Forte@Sun.COM 			ret++;
1677836SJohn.Forte@Sun.COM 		}
1687836SJohn.Forte@Sun.COM 	}
1697836SJohn.Forte@Sun.COM 
1707836SJohn.Forte@Sun.COM 	if (ret > 0)
1717836SJohn.Forte@Sun.COM 		retval = FPCFGA_LIB_ERR;
1727836SJohn.Forte@Sun.COM 
1737836SJohn.Forte@Sun.COM 	return (retval);
1747836SJohn.Forte@Sun.COM }
1757836SJohn.Forte@Sun.COM 
1767836SJohn.Forte@Sun.COM /*
1777836SJohn.Forte@Sun.COM  * Online in RCM for devices which only have paths
1787836SJohn.Forte@Sun.COM  * not in ONLINE/STANDBY state
1797836SJohn.Forte@Sun.COM  */
1807836SJohn.Forte@Sun.COM void
dev_rcm_online_nonoperationalpath(apid_t * apidt,cfga_flags_t flags,char ** errstring)1817836SJohn.Forte@Sun.COM dev_rcm_online_nonoperationalpath(apid_t *apidt, cfga_flags_t flags,
1827836SJohn.Forte@Sun.COM     char **errstring)
1837836SJohn.Forte@Sun.COM {
1847836SJohn.Forte@Sun.COM 	luninfo_list_t	*lunlistp;
1857836SJohn.Forte@Sun.COM 
1867836SJohn.Forte@Sun.COM 	if ((apidt->flags & FLAG_DISABLE_RCM) != 0) {
1877836SJohn.Forte@Sun.COM 		return;
1887836SJohn.Forte@Sun.COM 	}
1897836SJohn.Forte@Sun.COM 
1907836SJohn.Forte@Sun.COM 	lunlistp = apidt->lunlist;
1917836SJohn.Forte@Sun.COM 
1927836SJohn.Forte@Sun.COM 	for (lunlistp = apidt->lunlist; lunlistp != NULL;
1937836SJohn.Forte@Sun.COM 	    lunlistp = lunlistp->next) {
1947836SJohn.Forte@Sun.COM 		if ((lunlistp->lun_flag & FLAG_SKIP_ONLINEOTHERS) != 0) {
1957836SJohn.Forte@Sun.COM 			continue;
1967836SJohn.Forte@Sun.COM 		}
1977836SJohn.Forte@Sun.COM 		(void) fp_rcm_online(lunlistp->path, errstring, flags);
1987836SJohn.Forte@Sun.COM 	}
1997836SJohn.Forte@Sun.COM }
2007836SJohn.Forte@Sun.COM 
2017836SJohn.Forte@Sun.COM /*
2027836SJohn.Forte@Sun.COM  * Offline, in RCM, all the LUNs for a particular device.
2037836SJohn.Forte@Sun.COM  * This function should not be called for the MPXIO case.
2047836SJohn.Forte@Sun.COM  *
2057836SJohn.Forte@Sun.COM  * INPUT :
2067836SJohn.Forte@Sun.COM  * apidt - this is expected to have the list of luns for the device and so
2077836SJohn.Forte@Sun.COM  *         is assumed to be filled in prior to this call
2087836SJohn.Forte@Sun.COM  * errstring - If non-NULL, it will hold any error messages
2097836SJohn.Forte@Sun.COM  *
2107836SJohn.Forte@Sun.COM  * RETURNS :
2117836SJohn.Forte@Sun.COM  * FPCFGA_OK on success
2127836SJohn.Forte@Sun.COM  * error code otherwise
2137836SJohn.Forte@Sun.COM  */
2147836SJohn.Forte@Sun.COM static fpcfga_ret_t
dev_rcm_offline(apid_t * apidt,cfga_flags_t flags,char ** errstring)2157836SJohn.Forte@Sun.COM dev_rcm_offline(apid_t *apidt, cfga_flags_t flags, char **errstring)
2167836SJohn.Forte@Sun.COM {
2177836SJohn.Forte@Sun.COM 	int		count = 0;
2187836SJohn.Forte@Sun.COM 	luninfo_list_t	*lunlistp;
2197836SJohn.Forte@Sun.COM 
2207836SJohn.Forte@Sun.COM 	if ((apidt->flags & FLAG_DISABLE_RCM) != 0) {
2217836SJohn.Forte@Sun.COM 		/* User has requested not to notify RCM framework */
2227836SJohn.Forte@Sun.COM 		return (FPCFGA_OK);
2237836SJohn.Forte@Sun.COM 	}
2247836SJohn.Forte@Sun.COM 
2257836SJohn.Forte@Sun.COM 	for (lunlistp = apidt->lunlist; lunlistp != NULL;
2267836SJohn.Forte@Sun.COM 						lunlistp = lunlistp->next) {
2277836SJohn.Forte@Sun.COM 		if ((lunlistp->lun_flag & FLAG_SKIP_RCMOFFLINE) != 0) {
2287836SJohn.Forte@Sun.COM 			continue;
2297836SJohn.Forte@Sun.COM 		}
2307836SJohn.Forte@Sun.COM 		if ((apidt->flags & FLAG_REMOVE_UNUSABLE_FCP_DEV) ==
2317836SJohn.Forte@Sun.COM 		    FLAG_REMOVE_UNUSABLE_FCP_DEV) {
2327836SJohn.Forte@Sun.COM 			int ret = strncmp(lunlistp->path, SCSI_VHCI_ROOT,
2337836SJohn.Forte@Sun.COM 				strlen(SCSI_VHCI_ROOT));
2347836SJohn.Forte@Sun.COM 
2357836SJohn.Forte@Sun.COM 			if (((ret == 0) &&
2367836SJohn.Forte@Sun.COM 			    (lunlistp->node_state == DI_PATH_STATE_OFFLINE)) ||
2377836SJohn.Forte@Sun.COM 			    ((ret != 0) &&
2387836SJohn.Forte@Sun.COM 			    ((lunlistp->node_state & DI_DEVICE_OFFLINE) ==
2397836SJohn.Forte@Sun.COM 			    DI_DEVICE_OFFLINE))) {
2407836SJohn.Forte@Sun.COM 				/* Offline the device through RCM */
2417836SJohn.Forte@Sun.COM 				if (fp_rcm_offline(lunlistp->path, errstring,
2427836SJohn.Forte@Sun.COM 					    flags) != 0) {
2437836SJohn.Forte@Sun.COM 					/*
2447836SJohn.Forte@Sun.COM 					 * Bring everything back online in
2457836SJohn.Forte@Sun.COM 					 * rcm and return
2467836SJohn.Forte@Sun.COM 					 */
2477836SJohn.Forte@Sun.COM 					(void) dev_rcm_online(apidt, count,
2487836SJohn.Forte@Sun.COM 								flags, NULL);
2497836SJohn.Forte@Sun.COM 					return (FPCFGA_LIB_ERR);
2507836SJohn.Forte@Sun.COM 				}
2517836SJohn.Forte@Sun.COM 				count++;
2527836SJohn.Forte@Sun.COM 			}
2537836SJohn.Forte@Sun.COM 		} else {
2547836SJohn.Forte@Sun.COM 			/* Offline the device through RCM */
2557836SJohn.Forte@Sun.COM 			if (fp_rcm_offline(lunlistp->path, errstring,
2567836SJohn.Forte@Sun.COM 				    flags) != 0) {
2577836SJohn.Forte@Sun.COM 				/*
2587836SJohn.Forte@Sun.COM 				 * Bring everything back online in
2597836SJohn.Forte@Sun.COM 				 * rcm and return
2607836SJohn.Forte@Sun.COM 				 */
2617836SJohn.Forte@Sun.COM 				(void) dev_rcm_online(apidt, count, flags,
2627836SJohn.Forte@Sun.COM 									NULL);
2637836SJohn.Forte@Sun.COM 				return (FPCFGA_LIB_ERR);
2647836SJohn.Forte@Sun.COM 			}
2657836SJohn.Forte@Sun.COM 			count++;
2667836SJohn.Forte@Sun.COM 		}
2677836SJohn.Forte@Sun.COM 	}
2687836SJohn.Forte@Sun.COM 	return (FPCFGA_OK);
2697836SJohn.Forte@Sun.COM }
2707836SJohn.Forte@Sun.COM 
2717836SJohn.Forte@Sun.COM /*
2727836SJohn.Forte@Sun.COM  * Remove, in RCM, all the LUNs for a particular device.
2737836SJohn.Forte@Sun.COM  * This function should not be called for the MPXIO case.
2747836SJohn.Forte@Sun.COM  *
2757836SJohn.Forte@Sun.COM  * INPUT :
2767836SJohn.Forte@Sun.COM  * apidt - this is expected to have the list of luns for the device and so
2777836SJohn.Forte@Sun.COM  *         is assumed to be filled in prior to this call
2787836SJohn.Forte@Sun.COM  * errstring - If non-NULL, it will hold any error messages
2797836SJohn.Forte@Sun.COM  *
2807836SJohn.Forte@Sun.COM  * RETURNS :
2817836SJohn.Forte@Sun.COM  * FPCFGA_OK on success
2827836SJohn.Forte@Sun.COM  * error code otherwise
2837836SJohn.Forte@Sun.COM  */
2847836SJohn.Forte@Sun.COM static fpcfga_ret_t
dev_rcm_remove(apid_t * apidt,cfga_flags_t flags,char ** errstring)2857836SJohn.Forte@Sun.COM dev_rcm_remove(apid_t *apidt, cfga_flags_t flags, char **errstring)
2867836SJohn.Forte@Sun.COM {
2877836SJohn.Forte@Sun.COM 	int		count = 0;
2887836SJohn.Forte@Sun.COM 	luninfo_list_t	*lunlistp;
2897836SJohn.Forte@Sun.COM 
2907836SJohn.Forte@Sun.COM 	if ((apidt->flags & FLAG_DISABLE_RCM) != 0) {
2917836SJohn.Forte@Sun.COM 		/* User has requested not to notify RCM framework */
2927836SJohn.Forte@Sun.COM 		return (FPCFGA_OK);
2937836SJohn.Forte@Sun.COM 	}
2947836SJohn.Forte@Sun.COM 
2957836SJohn.Forte@Sun.COM 	for (lunlistp = apidt->lunlist; lunlistp != NULL;
2967836SJohn.Forte@Sun.COM 						lunlistp = lunlistp->next) {
2977836SJohn.Forte@Sun.COM 		if ((lunlistp->lun_flag & FLAG_SKIP_RCMREMOVE) != 0)
2987836SJohn.Forte@Sun.COM 			continue;
2997836SJohn.Forte@Sun.COM 		if ((apidt->flags & FLAG_REMOVE_UNUSABLE_FCP_DEV) ==
3007836SJohn.Forte@Sun.COM 		    FLAG_REMOVE_UNUSABLE_FCP_DEV) {
3017836SJohn.Forte@Sun.COM 			int ret = strncmp(lunlistp->path, SCSI_VHCI_ROOT,
3027836SJohn.Forte@Sun.COM 				strlen(SCSI_VHCI_ROOT));
3037836SJohn.Forte@Sun.COM 
3047836SJohn.Forte@Sun.COM 			if (((ret == 0) &&
3057836SJohn.Forte@Sun.COM 			    (lunlistp->node_state == DI_PATH_STATE_OFFLINE)) ||
3067836SJohn.Forte@Sun.COM 			    ((ret != 0) &&
3077836SJohn.Forte@Sun.COM 			    ((lunlistp->node_state & DI_DEVICE_OFFLINE) ==
3087836SJohn.Forte@Sun.COM 			    DI_DEVICE_OFFLINE))) {
3097836SJohn.Forte@Sun.COM 				/* remove the device through RCM */
3107836SJohn.Forte@Sun.COM 				if (fp_rcm_remove(lunlistp->path, errstring,
3117836SJohn.Forte@Sun.COM 					    flags) != 0) {
3127836SJohn.Forte@Sun.COM 					/*
3137836SJohn.Forte@Sun.COM 					 * Bring everything back online in
3147836SJohn.Forte@Sun.COM 					 * rcm and return
3157836SJohn.Forte@Sun.COM 					 */
3167836SJohn.Forte@Sun.COM 					(void) dev_rcm_online(apidt, count,
3177836SJohn.Forte@Sun.COM 								flags, NULL);
3187836SJohn.Forte@Sun.COM 					return (FPCFGA_LIB_ERR);
3197836SJohn.Forte@Sun.COM 				}
3207836SJohn.Forte@Sun.COM 				count++;
3217836SJohn.Forte@Sun.COM 			}
3227836SJohn.Forte@Sun.COM 		} else {
3237836SJohn.Forte@Sun.COM 			/* remove the device through RCM */
3247836SJohn.Forte@Sun.COM 			if (fp_rcm_remove(lunlistp->path, errstring,
3257836SJohn.Forte@Sun.COM 				flags) != 0) {
3267836SJohn.Forte@Sun.COM 				/*
3277836SJohn.Forte@Sun.COM 				 * Bring everything back online in rcm and
3287836SJohn.Forte@Sun.COM 				 * return
3297836SJohn.Forte@Sun.COM 				 */
3307836SJohn.Forte@Sun.COM 				(void) dev_rcm_online(apidt, count, flags,
3317836SJohn.Forte@Sun.COM 									NULL);
3327836SJohn.Forte@Sun.COM 				return (FPCFGA_LIB_ERR);
3337836SJohn.Forte@Sun.COM 			}
3347836SJohn.Forte@Sun.COM 			count++;
3357836SJohn.Forte@Sun.COM 		}
3367836SJohn.Forte@Sun.COM 	}
3377836SJohn.Forte@Sun.COM 	return (FPCFGA_OK);
3387836SJohn.Forte@Sun.COM }
3397836SJohn.Forte@Sun.COM 
3407836SJohn.Forte@Sun.COM static fpcfga_ret_t
lun_unconf(char * path,int lunnum,char * xport_phys,char * dyncomp,char ** errstring)3417836SJohn.Forte@Sun.COM lun_unconf(char *path, int lunnum, char *xport_phys, char *dyncomp,
3427836SJohn.Forte@Sun.COM 						char **errstring)
3437836SJohn.Forte@Sun.COM {
3447836SJohn.Forte@Sun.COM 	devctl_hdl_t	hdl;
3457836SJohn.Forte@Sun.COM 	char		*ptr;		/* To use as scratch/temp pointer */
3467836SJohn.Forte@Sun.COM 	char		pathname[MAXPATHLEN];
3477836SJohn.Forte@Sun.COM 
3487836SJohn.Forte@Sun.COM 	if (path == NULL)
3497836SJohn.Forte@Sun.COM 		return (FPCFGA_OK);
3507836SJohn.Forte@Sun.COM 
3517836SJohn.Forte@Sun.COM 	if (strncmp(path, SCSI_VHCI_ROOT, strlen(SCSI_VHCI_ROOT)) == 0) {
3527836SJohn.Forte@Sun.COM 		/*
3537836SJohn.Forte@Sun.COM 		 * We have an MPXIO managed device here.
3547836SJohn.Forte@Sun.COM 		 * So, we have to concoct a path for the device.
3557836SJohn.Forte@Sun.COM 		 *
3567836SJohn.Forte@Sun.COM 		 * xport_phys looks like :
3577836SJohn.Forte@Sun.COM 		 * /devices/pci@b,2000/pci@1/SUNW,qlc@5/fp@0,0:fc
3587836SJohn.Forte@Sun.COM 		 */
3597836SJohn.Forte@Sun.COM 		(void) strlcpy(pathname, xport_phys, MAXPATHLEN);
3607836SJohn.Forte@Sun.COM 		if ((ptr = strrchr(pathname, ':')) != NULL) {
3617836SJohn.Forte@Sun.COM 			*ptr = '\0';
3627836SJohn.Forte@Sun.COM 		}
3637836SJohn.Forte@Sun.COM 
3647836SJohn.Forte@Sun.COM 		/*
3657836SJohn.Forte@Sun.COM 		 * Get pointer to driver name from VHCI path
3667836SJohn.Forte@Sun.COM 		 * So, if lunlistp->path is
3677836SJohn.Forte@Sun.COM 		 * /devices/scsi_vhci/ssd@g220000203707a417,
3687836SJohn.Forte@Sun.COM 		 * we need a pointer to the last '/'
3697836SJohn.Forte@Sun.COM 		 *
3707836SJohn.Forte@Sun.COM 		 * Assumption:
3717836SJohn.Forte@Sun.COM 		 * With MPXIO there will be only one entry per lun
3727836SJohn.Forte@Sun.COM 		 * So, there will only be one entry in the linked list
3737836SJohn.Forte@Sun.COM 		 * apidt->lunlist
3747836SJohn.Forte@Sun.COM 		 */
3757836SJohn.Forte@Sun.COM 		if ((ptr = strrchr(path, '/')) == NULL) {
3767836SJohn.Forte@Sun.COM 			/* This shouldn't happen, but anyways ... */
3777836SJohn.Forte@Sun.COM 			cfga_err(errstring, 0, ERRARG_INVALID_PATH, path, 0);
3787836SJohn.Forte@Sun.COM 			return (FPCFGA_LIB_ERR);
3797836SJohn.Forte@Sun.COM 		}
3807836SJohn.Forte@Sun.COM 
3817836SJohn.Forte@Sun.COM 		/*
3827836SJohn.Forte@Sun.COM 		 * Make pathname to look something like :
3837836SJohn.Forte@Sun.COM 		 * /devices/pci@x,xxxx/pci@x/SUNW,qlc@x/fp@x,x/ssd@w...
3847836SJohn.Forte@Sun.COM 		 */
3857836SJohn.Forte@Sun.COM 		strcat(pathname, ptr);
3867836SJohn.Forte@Sun.COM 
3877836SJohn.Forte@Sun.COM 		/*
3887836SJohn.Forte@Sun.COM 		 * apidt_create() will make sure that lunlist->path
3897836SJohn.Forte@Sun.COM 		 * has a "@<something>" at the end even if the driver
3907836SJohn.Forte@Sun.COM 		 * state is "detached"
3917836SJohn.Forte@Sun.COM 		 */
3927836SJohn.Forte@Sun.COM 		if ((ptr = strrchr(pathname, '@')) == NULL) {
3937836SJohn.Forte@Sun.COM 			/* This shouldn't happen, but anyways ... */
3947836SJohn.Forte@Sun.COM 			cfga_err(errstring, 0, ERRARG_INVALID_PATH,
3957836SJohn.Forte@Sun.COM 						pathname, 0);
3967836SJohn.Forte@Sun.COM 			return (FPCFGA_LIB_ERR);
3977836SJohn.Forte@Sun.COM 		}
3987836SJohn.Forte@Sun.COM 		*ptr = '\0';
3997836SJohn.Forte@Sun.COM 
4007836SJohn.Forte@Sun.COM 		/* Now, concoct the path */
4017836SJohn.Forte@Sun.COM 		sprintf(&pathname[strlen(pathname)], "@w%s,%x",
4027836SJohn.Forte@Sun.COM 							dyncomp, lunnum);
4037836SJohn.Forte@Sun.COM 		ptr = pathname;
4047836SJohn.Forte@Sun.COM 	} else {
4057836SJohn.Forte@Sun.COM 		/*
4067836SJohn.Forte@Sun.COM 		 * non-MPXIO path, use the path that is passed in
4077836SJohn.Forte@Sun.COM 		 */
4087836SJohn.Forte@Sun.COM 		ptr = path;
4097836SJohn.Forte@Sun.COM 	}
4107836SJohn.Forte@Sun.COM 
4117836SJohn.Forte@Sun.COM 	if ((hdl = devctl_device_acquire(ptr,  0)) == NULL) {
4127836SJohn.Forte@Sun.COM 		cfga_err(errstring, errno, ERRARG_DEV_ACQUIRE, ptr, 0);
4137836SJohn.Forte@Sun.COM 		return (FPCFGA_LIB_ERR);
4147836SJohn.Forte@Sun.COM 	}
4157836SJohn.Forte@Sun.COM 
4167836SJohn.Forte@Sun.COM 	if (devctl_device_remove(hdl) != 0) {
4177836SJohn.Forte@Sun.COM 		devctl_release(hdl);
4187836SJohn.Forte@Sun.COM 		cfga_err(errstring, errno, ERRARG_DEV_REMOVE, ptr, 0);
4197836SJohn.Forte@Sun.COM 		return (FPCFGA_LIB_ERR);
4207836SJohn.Forte@Sun.COM 	}
4217836SJohn.Forte@Sun.COM 	devctl_release(hdl);
4227836SJohn.Forte@Sun.COM 
4237836SJohn.Forte@Sun.COM 	return (FPCFGA_OK);
4247836SJohn.Forte@Sun.COM }
4257836SJohn.Forte@Sun.COM 
4267836SJohn.Forte@Sun.COM static fpcfga_ret_t
dev_unconf(apid_t * apidt,char ** errstring,uchar_t * flag)4277836SJohn.Forte@Sun.COM dev_unconf(apid_t *apidt, char **errstring, uchar_t *flag)
4287836SJohn.Forte@Sun.COM {
4297836SJohn.Forte@Sun.COM 	luninfo_list_t	*lunlistp;
4307836SJohn.Forte@Sun.COM 	fpcfga_ret_t	ret = FPCFGA_OK;
4317836SJohn.Forte@Sun.COM 	int lun_cnt = 0, unusable_lun_cnt = 0;
4327836SJohn.Forte@Sun.COM 
4337836SJohn.Forte@Sun.COM 	for (lunlistp = apidt->lunlist; lunlistp != NULL;
4347836SJohn.Forte@Sun.COM 	    lunlistp = lunlistp->next) {
4357836SJohn.Forte@Sun.COM 		lun_cnt++;
4367836SJohn.Forte@Sun.COM 		/*
4377836SJohn.Forte@Sun.COM 		 * Unconfigure each LUN.
4387836SJohn.Forte@Sun.COM 		 * Note that for MPXIO devices, lunlistp->path will be a
4397836SJohn.Forte@Sun.COM 		 * vHCI path
4407836SJohn.Forte@Sun.COM 		 */
4417836SJohn.Forte@Sun.COM 		if ((apidt->flags & FLAG_REMOVE_UNUSABLE_FCP_DEV) ==
4427836SJohn.Forte@Sun.COM 			FLAG_REMOVE_UNUSABLE_FCP_DEV) {
4437836SJohn.Forte@Sun.COM 		    if (strncmp(lunlistp->path, SCSI_VHCI_ROOT,
4447836SJohn.Forte@Sun.COM 			strlen(SCSI_VHCI_ROOT)) == 0) {
4457836SJohn.Forte@Sun.COM 			if (lunlistp->node_state ==
4467836SJohn.Forte@Sun.COM 				DI_PATH_STATE_OFFLINE) {
4477836SJohn.Forte@Sun.COM 			    unusable_lun_cnt++;
4487836SJohn.Forte@Sun.COM 			    if ((ret = lun_unconf(lunlistp->path,
4497836SJohn.Forte@Sun.COM 				lunlistp->lunnum, apidt->xport_phys,
4507836SJohn.Forte@Sun.COM 				apidt->dyncomp, errstring)) != FPCFGA_OK) {
4517836SJohn.Forte@Sun.COM 				return (ret);
4527836SJohn.Forte@Sun.COM 			    }
4537836SJohn.Forte@Sun.COM 			}
4547836SJohn.Forte@Sun.COM 		    } else {
4557836SJohn.Forte@Sun.COM 			if ((lunlistp->node_state & DI_DEVICE_OFFLINE) ==
4567836SJohn.Forte@Sun.COM 				DI_DEVICE_OFFLINE) {
4577836SJohn.Forte@Sun.COM 			    unusable_lun_cnt++;
4587836SJohn.Forte@Sun.COM 			    if ((ret = lun_unconf(lunlistp->path,
4597836SJohn.Forte@Sun.COM 				lunlistp->lunnum, apidt->xport_phys,
4607836SJohn.Forte@Sun.COM 				apidt->dyncomp, errstring)) != FPCFGA_OK) {
4617836SJohn.Forte@Sun.COM 				return (ret);
4627836SJohn.Forte@Sun.COM 			    }
4637836SJohn.Forte@Sun.COM 			}
4647836SJohn.Forte@Sun.COM 		    }
4657836SJohn.Forte@Sun.COM 		} else {
4667836SJohn.Forte@Sun.COM 		/*
4677836SJohn.Forte@Sun.COM 		 * Unconfigure each LUN.
4687836SJohn.Forte@Sun.COM 		 * Note that for MPXIO devices, lunlistp->path will be a
4697836SJohn.Forte@Sun.COM 		 * vHCI path
4707836SJohn.Forte@Sun.COM 		 */
4717836SJohn.Forte@Sun.COM 		    if ((ret = lun_unconf(lunlistp->path, lunlistp->lunnum,
4727836SJohn.Forte@Sun.COM 				apidt->xport_phys, apidt->dyncomp,
4737836SJohn.Forte@Sun.COM 				errstring)) != FPCFGA_OK) {
4747836SJohn.Forte@Sun.COM 			return (ret);
4757836SJohn.Forte@Sun.COM 		    }
4767836SJohn.Forte@Sun.COM 		}
4777836SJohn.Forte@Sun.COM 	}
4787836SJohn.Forte@Sun.COM 
4797836SJohn.Forte@Sun.COM 	if ((apidt->flags & FLAG_REMOVE_UNUSABLE_FCP_DEV) ==
4807836SJohn.Forte@Sun.COM 			FLAG_REMOVE_UNUSABLE_FCP_DEV) {
4817836SJohn.Forte@Sun.COM 		/*
4827836SJohn.Forte@Sun.COM 		 * when all luns are unconfigured
4837836SJohn.Forte@Sun.COM 		 * indicate to remove repository entry.
4847836SJohn.Forte@Sun.COM 		 */
4857836SJohn.Forte@Sun.COM 		if (lun_cnt == unusable_lun_cnt) {
4867836SJohn.Forte@Sun.COM 			*flag = ALL_APID_LUNS_UNUSABLE;
4877836SJohn.Forte@Sun.COM 		}
4887836SJohn.Forte@Sun.COM 	}
4897836SJohn.Forte@Sun.COM 
4907836SJohn.Forte@Sun.COM 	return (ret);
4917836SJohn.Forte@Sun.COM }
4927836SJohn.Forte@Sun.COM 
4937836SJohn.Forte@Sun.COM /*
4947836SJohn.Forte@Sun.COM  * Check if the given physical path (the xport_phys) is part of the
4957836SJohn.Forte@Sun.COM  * pHCI list and if the RCM should be done for a particular pHCI.
4967836SJohn.Forte@Sun.COM  * Skip non-MPxIO dev node if any.
4977836SJohn.Forte@Sun.COM  */
4987836SJohn.Forte@Sun.COM static fpcfga_ret_t
is_xport_phys_in_pathlist(apid_t * apidt,char ** errstring)4997836SJohn.Forte@Sun.COM is_xport_phys_in_pathlist(apid_t *apidt, char **errstring)
5007836SJohn.Forte@Sun.COM {
5017836SJohn.Forte@Sun.COM 	di_node_t	root, vhci, node, phci;
5027836SJohn.Forte@Sun.COM 	di_path_t	path = DI_PATH_NIL;
5037836SJohn.Forte@Sun.COM 	int		num_active_paths, found = 0;
5047836SJohn.Forte@Sun.COM 	char		*vhci_path_ptr, *pathname_ptr, pathname[MAXPATHLEN];
5057836SJohn.Forte@Sun.COM 	char		*phci_path, *node_path;
5067836SJohn.Forte@Sun.COM 	char		phci_addr[MAXPATHLEN];
5077836SJohn.Forte@Sun.COM 	char		*xport_phys, *vhci_path, *dyncomp;
5087836SJohn.Forte@Sun.COM 	luninfo_list_t	*lunlistp, *temp;
5097836SJohn.Forte@Sun.COM 	int		non_operational_path_count;
5107836SJohn.Forte@Sun.COM 
5117836SJohn.Forte@Sun.COM 	/* a safety check */
5127836SJohn.Forte@Sun.COM 	if ((apidt->dyncomp == NULL) || (*apidt->dyncomp == '\0')) {
5137836SJohn.Forte@Sun.COM 		return (FPCFGA_LIB_ERR);
5147836SJohn.Forte@Sun.COM 	}
5157836SJohn.Forte@Sun.COM 
5167836SJohn.Forte@Sun.COM 	xport_phys = apidt->xport_phys;
5177836SJohn.Forte@Sun.COM 	dyncomp = apidt->dyncomp;
5187836SJohn.Forte@Sun.COM 
5197836SJohn.Forte@Sun.COM 	lunlistp = apidt->lunlist;
5207836SJohn.Forte@Sun.COM 	for (lunlistp = apidt->lunlist; lunlistp != NULL;
5217836SJohn.Forte@Sun.COM 	    lunlistp = lunlistp->next) {
5227836SJohn.Forte@Sun.COM 
5237836SJohn.Forte@Sun.COM 		if (strncmp(lunlistp->path, SCSI_VHCI_ROOT,
5247836SJohn.Forte@Sun.COM 		    strlen(SCSI_VHCI_ROOT)) != 0) {
5257836SJohn.Forte@Sun.COM 			lunlistp->lun_flag |= FLAG_SKIP_ONLINEOTHERS;
5267836SJohn.Forte@Sun.COM 			continue;
5277836SJohn.Forte@Sun.COM 		}
5287836SJohn.Forte@Sun.COM 
5297836SJohn.Forte@Sun.COM 		vhci_path = lunlistp->path;
5307836SJohn.Forte@Sun.COM 
5317836SJohn.Forte@Sun.COM 		num_active_paths = 0;	/* # of paths in ONLINE/STANDBY */
5327836SJohn.Forte@Sun.COM 		non_operational_path_count = 0;
5337836SJohn.Forte@Sun.COM 
5347836SJohn.Forte@Sun.COM 		if (xport_phys == NULL || vhci_path == NULL) {
5357836SJohn.Forte@Sun.COM 		    cfga_err(errstring, 0, ERRARG_XPORT_NOT_IN_PHCI_LIST,
5367836SJohn.Forte@Sun.COM 		    xport_phys, 0);
5377836SJohn.Forte@Sun.COM 			return (FPCFGA_LIB_ERR);
5387836SJohn.Forte@Sun.COM 		}
5397836SJohn.Forte@Sun.COM 
5407836SJohn.Forte@Sun.COM 		(void) strlcpy(pathname, xport_phys, MAXPATHLEN);
5417836SJohn.Forte@Sun.COM 		if ((pathname_ptr = strrchr(pathname, ':')) != NULL) {
5427836SJohn.Forte@Sun.COM 			*pathname_ptr = '\0';
5437836SJohn.Forte@Sun.COM 		}
5447836SJohn.Forte@Sun.COM 		/* strip off the /devices/from the path */
5457836SJohn.Forte@Sun.COM 		pathname_ptr = pathname + strlen(DEVICES_DIR);
5467836SJohn.Forte@Sun.COM 
5477836SJohn.Forte@Sun.COM 		root = di_init("/", DINFOCPYALL|DINFOPATH);
5487836SJohn.Forte@Sun.COM 
5497836SJohn.Forte@Sun.COM 		if (root == DI_NODE_NIL) {
5507836SJohn.Forte@Sun.COM 			return (FPCFGA_LIB_ERR);
5517836SJohn.Forte@Sun.COM 		}
5527836SJohn.Forte@Sun.COM 
5537836SJohn.Forte@Sun.COM 		vhci_path_ptr = vhci_path + strlen(DEVICES_DIR);
5547836SJohn.Forte@Sun.COM 		if ((vhci = di_drv_first_node(SCSI_VHCI_DRVR, root)) ==
5557836SJohn.Forte@Sun.COM 		    DI_NODE_NIL) {
5567836SJohn.Forte@Sun.COM 			return (FPCFGA_LIB_ERR);
5577836SJohn.Forte@Sun.COM 		}
5587836SJohn.Forte@Sun.COM 		found = 0;
5597836SJohn.Forte@Sun.COM 		for (node = di_child_node(vhci); node != DI_NODE_NIL;
5607836SJohn.Forte@Sun.COM 		    node = di_sibling_node(node)) {
5617836SJohn.Forte@Sun.COM 			if ((node_path = di_devfs_path(node)) != NULL) {
5627836SJohn.Forte@Sun.COM 				if (strncmp(vhci_path_ptr, node_path,
5637836SJohn.Forte@Sun.COM 				    strlen(node_path)) != 0) {
5647836SJohn.Forte@Sun.COM 					di_devfs_path_free(node_path);
5657836SJohn.Forte@Sun.COM 				} else {
5667836SJohn.Forte@Sun.COM 					found = 1;
5677836SJohn.Forte@Sun.COM 					break;
5687836SJohn.Forte@Sun.COM 				}
5697836SJohn.Forte@Sun.COM 			}
5707836SJohn.Forte@Sun.COM 		}
5717836SJohn.Forte@Sun.COM 		if (found == 0) {
5727836SJohn.Forte@Sun.COM 			cfga_err(errstring, 0, ERRARG_XPORT_NOT_IN_PHCI_LIST,
5737836SJohn.Forte@Sun.COM 			    xport_phys, 0);
5747836SJohn.Forte@Sun.COM 			di_fini(root);
5757836SJohn.Forte@Sun.COM 			return (FPCFGA_LIB_ERR);
5767836SJohn.Forte@Sun.COM 		}
5777836SJohn.Forte@Sun.COM 		/* found vhci_path we are looking for */
5787836SJohn.Forte@Sun.COM 		di_devfs_path_free(node_path);
5797836SJohn.Forte@Sun.COM 		found = 0;
5807836SJohn.Forte@Sun.COM 		for (path = di_path_next_phci(node, DI_PATH_NIL);
5817836SJohn.Forte@Sun.COM 		    path != DI_PATH_NIL;
5827836SJohn.Forte@Sun.COM 		    path = di_path_next_phci(node, path)) {
5837836SJohn.Forte@Sun.COM 			if ((phci = di_path_phci_node(path)) == DI_NODE_NIL) {
5847836SJohn.Forte@Sun.COM 				cfga_err(errstring, 0,
5857836SJohn.Forte@Sun.COM 				    ERRARG_XPORT_NOT_IN_PHCI_LIST,
5867836SJohn.Forte@Sun.COM 				    xport_phys, 0);
5877836SJohn.Forte@Sun.COM 				di_fini(root);
5887836SJohn.Forte@Sun.COM 				return (FPCFGA_LIB_ERR);
5897836SJohn.Forte@Sun.COM 			}
5907836SJohn.Forte@Sun.COM 			if ((phci_path = di_devfs_path(phci)) == NULL) {
5917836SJohn.Forte@Sun.COM 				cfga_err(errstring, 0,
5927836SJohn.Forte@Sun.COM 				    ERRARG_XPORT_NOT_IN_PHCI_LIST,
5937836SJohn.Forte@Sun.COM 				    xport_phys, 0);
5947836SJohn.Forte@Sun.COM 				di_fini(root);
5957836SJohn.Forte@Sun.COM 				return (FPCFGA_LIB_ERR);
5967836SJohn.Forte@Sun.COM 			}
5977836SJohn.Forte@Sun.COM 			(void) di_path_addr(path, (char *)phci_addr);
5987836SJohn.Forte@Sun.COM 			if ((phci_addr == NULL) || (*phci_addr == '\0')) {
5997836SJohn.Forte@Sun.COM 				cfga_err(errstring, 0,
6007836SJohn.Forte@Sun.COM 				    ERRARG_XPORT_NOT_IN_PHCI_LIST,
6017836SJohn.Forte@Sun.COM 				    xport_phys, 0);
6027836SJohn.Forte@Sun.COM 				di_devfs_path_free(phci_path);
6037836SJohn.Forte@Sun.COM 				di_fini(root);
6047836SJohn.Forte@Sun.COM 				return (FPCFGA_LIB_ERR);
6057836SJohn.Forte@Sun.COM 			}
6067836SJohn.Forte@Sun.COM 			/*
6077836SJohn.Forte@Sun.COM 			 * Check if the phci path has the same
6087836SJohn.Forte@Sun.COM 			 * xport addr and the target addr with current lun
6097836SJohn.Forte@Sun.COM 			 */
6107836SJohn.Forte@Sun.COM 			if ((strncmp(phci_path, pathname_ptr,
6117836SJohn.Forte@Sun.COM 			    strlen(pathname_ptr)) == 0) &&
6127836SJohn.Forte@Sun.COM 			    (strstr(phci_addr, dyncomp) != NULL)) {
6137836SJohn.Forte@Sun.COM 				/* SUCCESS Found xport_phys */
6147836SJohn.Forte@Sun.COM 				found = 1;
6157836SJohn.Forte@Sun.COM 			} else if ((di_path_state(path) ==
6167836SJohn.Forte@Sun.COM 			    DI_PATH_STATE_ONLINE) ||
6177836SJohn.Forte@Sun.COM 			    (di_path_state(path) == DI_PATH_STATE_STANDBY)) {
6187836SJohn.Forte@Sun.COM 				num_active_paths++;
6197836SJohn.Forte@Sun.COM 			} else {
6207836SJohn.Forte@Sun.COM 				/*
6217836SJohn.Forte@Sun.COM 				 * We have another path not in ONLINE/STANDBY
6227836SJohn.Forte@Sun.COM 				 * state now, so should do a RCM online after
6237836SJohn.Forte@Sun.COM 				 * the unconfiguration of current path.
6247836SJohn.Forte@Sun.COM 				 */
6257836SJohn.Forte@Sun.COM 				non_operational_path_count++;
6267836SJohn.Forte@Sun.COM 			}
6277836SJohn.Forte@Sun.COM 			di_devfs_path_free(phci_path);
6287836SJohn.Forte@Sun.COM 		}
6297836SJohn.Forte@Sun.COM 		di_fini(root);
6307836SJohn.Forte@Sun.COM 		if (found == 1) {
6317836SJohn.Forte@Sun.COM 			if (num_active_paths != 0) {
6327836SJohn.Forte@Sun.COM 				/*
6337836SJohn.Forte@Sun.COM 				 * There are other ONLINE/STANDBY paths,
6347836SJohn.Forte@Sun.COM 				 * so no need to do the RCM
6357836SJohn.Forte@Sun.COM 				 */
6367836SJohn.Forte@Sun.COM 				lunlistp->lun_flag |= FLAG_SKIP_RCMREMOVE;
6377836SJohn.Forte@Sun.COM 				lunlistp->lun_flag |= FLAG_SKIP_RCMOFFLINE;
6387836SJohn.Forte@Sun.COM 			}
6397836SJohn.Forte@Sun.COM 			if (non_operational_path_count == 0) {
6407836SJohn.Forte@Sun.COM 				lunlistp->lun_flag |= FLAG_SKIP_ONLINEOTHERS;
6417836SJohn.Forte@Sun.COM 			}
6427836SJohn.Forte@Sun.COM 		} else {
6437836SJohn.Forte@Sun.COM 			/*
6447836SJohn.Forte@Sun.COM 			 * Fail all operations here
6457836SJohn.Forte@Sun.COM 			 */
6467836SJohn.Forte@Sun.COM 			cfga_err(errstring, 0, ERRARG_XPORT_NOT_IN_PHCI_LIST,
6477836SJohn.Forte@Sun.COM 			    xport_phys, 0);
6487836SJohn.Forte@Sun.COM 			return (FPCFGA_APID_NOEXIST);
6497836SJohn.Forte@Sun.COM 		}
6507836SJohn.Forte@Sun.COM 	}
6517836SJohn.Forte@Sun.COM 
6527836SJohn.Forte@Sun.COM 	/* Mark duplicated paths for same vhci in the list */
6537836SJohn.Forte@Sun.COM 	for (lunlistp = apidt->lunlist; lunlistp != NULL;
6547836SJohn.Forte@Sun.COM 	    lunlistp = lunlistp->next) {
6557836SJohn.Forte@Sun.COM 		if (strncmp(lunlistp->path, SCSI_VHCI_ROOT,
6567836SJohn.Forte@Sun.COM 		    strlen(SCSI_VHCI_ROOT)) != 0) {
6577836SJohn.Forte@Sun.COM 			continue;
6587836SJohn.Forte@Sun.COM 		}
6597836SJohn.Forte@Sun.COM 		for (temp = lunlistp->next; temp != NULL;
6607836SJohn.Forte@Sun.COM 		    temp = temp->next) {
6617836SJohn.Forte@Sun.COM 			if (strcmp(lunlistp->path, temp->path) == 0) {
6627836SJohn.Forte@Sun.COM 				/*
6637836SJohn.Forte@Sun.COM 				 * don't do RCM for dup
6647836SJohn.Forte@Sun.COM 				 */
6657836SJohn.Forte@Sun.COM 				lunlistp->lun_flag |= FLAG_SKIP_RCMREMOVE;
6667836SJohn.Forte@Sun.COM 				lunlistp->lun_flag |= FLAG_SKIP_RCMOFFLINE;
6677836SJohn.Forte@Sun.COM 				lunlistp->lun_flag |= FLAG_SKIP_ONLINEOTHERS;
6687836SJohn.Forte@Sun.COM 			}
6697836SJohn.Forte@Sun.COM 		}
6707836SJohn.Forte@Sun.COM 	}
6717836SJohn.Forte@Sun.COM 	return (FPCFGA_OK);
6727836SJohn.Forte@Sun.COM }
6737836SJohn.Forte@Sun.COM /*
6747836SJohn.Forte@Sun.COM  * apidt->dyncomp has to be non-NULL by the time this routine is called
6757836SJohn.Forte@Sun.COM  */
6767836SJohn.Forte@Sun.COM fpcfga_ret_t
dev_change_state(cfga_cmd_t state_change_cmd,apid_t * apidt,la_wwn_t * pwwn,cfga_flags_t flags,char ** errstring,HBA_HANDLE handle,HBA_PORTATTRIBUTES portAttrs)6777836SJohn.Forte@Sun.COM dev_change_state(cfga_cmd_t state_change_cmd, apid_t *apidt, la_wwn_t *pwwn,
6787836SJohn.Forte@Sun.COM 		cfga_flags_t flags, char **errstring, HBA_HANDLE handle,
6797836SJohn.Forte@Sun.COM 		HBA_PORTATTRIBUTES portAttrs)
6807836SJohn.Forte@Sun.COM {
6817836SJohn.Forte@Sun.COM 	char			dev_path[MAXPATHLEN];
6827836SJohn.Forte@Sun.COM 	char			*update_str, *t_apid;
6837836SJohn.Forte@Sun.COM 	int			optflag = apidt->flags;
6847836SJohn.Forte@Sun.COM 	int			no_config_attempt = 0;
6857836SJohn.Forte@Sun.COM 	fpcfga_ret_t		ret;
6867836SJohn.Forte@Sun.COM 	apid_t			my_apidt;
6877836SJohn.Forte@Sun.COM 	uchar_t			unconf_flag = 0, peri_qual;
6887836SJohn.Forte@Sun.COM 	HBA_STATUS		status;
6897836SJohn.Forte@Sun.COM 	HBA_PORTATTRIBUTES	discPortAttrs;
6907836SJohn.Forte@Sun.COM 	uint64_t		lun = 0;
6917836SJohn.Forte@Sun.COM 	struct scsi_inquiry	inq;
6927836SJohn.Forte@Sun.COM 	struct scsi_extended_sense sense;
6937836SJohn.Forte@Sun.COM 	HBA_UINT8		scsiStatus;
6947836SJohn.Forte@Sun.COM 	uint32_t		inquirySize = sizeof (inq),
6957836SJohn.Forte@Sun.COM 				senseSize = sizeof (sense);
6967836SJohn.Forte@Sun.COM 	report_lun_resp_t	*resp_buf;
6977836SJohn.Forte@Sun.COM 	int			i, l_errno, num_luns = 0;
6987836SJohn.Forte@Sun.COM 	uchar_t			*lun_string;
6997836SJohn.Forte@Sun.COM 
7007836SJohn.Forte@Sun.COM 	if ((apidt->dyncomp == NULL) || (*apidt->dyncomp == '\0')) {
7017836SJohn.Forte@Sun.COM 		/*
7027836SJohn.Forte@Sun.COM 		 * No dynamic component specified. Just return success.
7037836SJohn.Forte@Sun.COM 		 * Should not see this case. Just a safety check.
7047836SJohn.Forte@Sun.COM 		 */
7057836SJohn.Forte@Sun.COM 		return (FPCFGA_OK);
7067836SJohn.Forte@Sun.COM 	}
7077836SJohn.Forte@Sun.COM 
7087836SJohn.Forte@Sun.COM 	/* Now construct the string we are going to put in the repository */
7097836SJohn.Forte@Sun.COM 	if ((update_str = calloc(1, (strlen(apidt->xport_phys) +
7107836SJohn.Forte@Sun.COM 		strlen(DYN_SEP) + strlen(apidt->dyncomp) + 1))) == NULL) {
7117836SJohn.Forte@Sun.COM 		cfga_err(errstring, errno, ERR_MEM_ALLOC, 0);
7127836SJohn.Forte@Sun.COM 		return (FPCFGA_LIB_ERR);
7137836SJohn.Forte@Sun.COM 	}
7147836SJohn.Forte@Sun.COM 	strcpy(update_str, apidt->xport_phys);
7157836SJohn.Forte@Sun.COM 	strcat(update_str, DYN_SEP);
7167836SJohn.Forte@Sun.COM 	strcat(update_str, apidt->dyncomp);
7177836SJohn.Forte@Sun.COM 
7187836SJohn.Forte@Sun.COM 	/* If force update of repository is sought, do it first */
7197836SJohn.Forte@Sun.COM 	if (optflag & FLAG_FORCE_UPDATE_REP) {
7207836SJohn.Forte@Sun.COM 		/* Ignore any failure in rep update */
7217836SJohn.Forte@Sun.COM 		(void) update_fabric_wwn_list(
7227836SJohn.Forte@Sun.COM 			((state_change_cmd == CFGA_CMD_CONFIGURE) ?
7237836SJohn.Forte@Sun.COM 			ADD_ENTRY : REMOVE_ENTRY),
7247836SJohn.Forte@Sun.COM 			update_str, errstring);
7257836SJohn.Forte@Sun.COM 	}
7267836SJohn.Forte@Sun.COM 
7277836SJohn.Forte@Sun.COM 	memset(&sense, 0, sizeof (sense));
7287836SJohn.Forte@Sun.COM 	if ((ret = get_report_lun_data(apidt->xport_phys, apidt->dyncomp,
7297836SJohn.Forte@Sun.COM 		&num_luns, &resp_buf, &sense, &l_errno)) != FPCFGA_OK) {
7307836SJohn.Forte@Sun.COM 		/*
7317836SJohn.Forte@Sun.COM 		 * Checking the sense key data as well as the additional
7327836SJohn.Forte@Sun.COM 		 * sense key.  The SES Node is not required to repond
7337836SJohn.Forte@Sun.COM 		 * to Report LUN.  In the case of Minnow, the SES node
7347836SJohn.Forte@Sun.COM 		 * returns with KEY_ILLEGAL_REQUEST and the additional
7357836SJohn.Forte@Sun.COM 		 * sense key of 0x20.  In this case we will blindly
7367836SJohn.Forte@Sun.COM 		 * send the SCSI Inquiry call to lun 0
7377836SJohn.Forte@Sun.COM 		 *
7387836SJohn.Forte@Sun.COM 		 * if we get any other error we will set the inq_type
7397836SJohn.Forte@Sun.COM 		 * appropriately
7407836SJohn.Forte@Sun.COM 		 */
7417836SJohn.Forte@Sun.COM 		if ((sense.es_key == KEY_ILLEGAL_REQUEST) &&
7427836SJohn.Forte@Sun.COM 		    (sense.es_add_code == 0x20)) {
7437836SJohn.Forte@Sun.COM 			lun = 0;
7447836SJohn.Forte@Sun.COM 		} else {
7457836SJohn.Forte@Sun.COM 			if (ret == FPCFGA_FCP_SEND_SCSI_DEV_NOT_TGT) {
7467836SJohn.Forte@Sun.COM 				inq.inq_dtype = DTYPE_UNKNOWN;
7477836SJohn.Forte@Sun.COM 			} else {
7487836SJohn.Forte@Sun.COM 				/*
7497836SJohn.Forte@Sun.COM 				 * Failed to get the LUN data for the device
7507836SJohn.Forte@Sun.COM 				 * If we find that there is a lunlist for this
7517836SJohn.Forte@Sun.COM 				 * device it could mean that there are dangling
7527836SJohn.Forte@Sun.COM 				 * devinfo nodes. So, we will go ahead and try
7537836SJohn.Forte@Sun.COM 				 * to unconfigure them.
7547836SJohn.Forte@Sun.COM 				 */
7557836SJohn.Forte@Sun.COM 				if ((apidt->lunlist == NULL) ||
7567836SJohn.Forte@Sun.COM 				    (state_change_cmd == CFGA_CMD_CONFIGURE)) {
7577836SJohn.Forte@Sun.COM 					S_FREE(update_str);
7587836SJohn.Forte@Sun.COM 					status = getPortAttrsByWWN(handle,
7597836SJohn.Forte@Sun.COM 					    *((HBA_WWN *)(pwwn)),
7607836SJohn.Forte@Sun.COM 					    &discPortAttrs);
7617836SJohn.Forte@Sun.COM 					if (status ==
7627836SJohn.Forte@Sun.COM 					    HBA_STATUS_ERROR_ILLEGAL_WWN) {
7637836SJohn.Forte@Sun.COM 						return (FPCFGA_APID_NOEXIST);
7647836SJohn.Forte@Sun.COM 					} else {
7657836SJohn.Forte@Sun.COM 						cfga_err(errstring, 0,
7667836SJohn.Forte@Sun.COM 						    ERRARG_FC_REP_LUNS,
7677836SJohn.Forte@Sun.COM 						    apidt->dyncomp, 0);
7687836SJohn.Forte@Sun.COM 						return (FPCFGA_LIB_ERR);
7697836SJohn.Forte@Sun.COM 					}
7707836SJohn.Forte@Sun.COM 				} else {
7717836SJohn.Forte@Sun.COM 					/* unconfig with lunlist not empty */
7727836SJohn.Forte@Sun.COM 					no_config_attempt++;
7737836SJohn.Forte@Sun.COM 				}
7747836SJohn.Forte@Sun.COM 			}
7757836SJohn.Forte@Sun.COM 		}
7767836SJohn.Forte@Sun.COM 	}
7777836SJohn.Forte@Sun.COM 	for (i = 0; i < num_luns; i++) {
7787836SJohn.Forte@Sun.COM 		/*
7797836SJohn.Forte@Sun.COM 		 * issue the inquiry to the first valid lun found
7807836SJohn.Forte@Sun.COM 		 * in the lun_string
7817836SJohn.Forte@Sun.COM 		 */
7827836SJohn.Forte@Sun.COM 		lun_string = (uchar_t *)&(resp_buf->lun_string[i]);
7837836SJohn.Forte@Sun.COM 		memcpy(&lun, lun_string, sizeof (lun));
7847836SJohn.Forte@Sun.COM 
7857836SJohn.Forte@Sun.COM 		memset(&sense, 0, sizeof (sense));
7867836SJohn.Forte@Sun.COM 		status = HBA_ScsiInquiryV2(handle, portAttrs.PortWWN,
7877836SJohn.Forte@Sun.COM 		    *(HBA_WWN *)(pwwn), lun, 0, 0, &inq, &inquirySize,
7887836SJohn.Forte@Sun.COM 		    &scsiStatus, &sense, &senseSize);
7897836SJohn.Forte@Sun.COM 		/*
7907836SJohn.Forte@Sun.COM 		 * if Inquiry is returned correctly, check the
7917836SJohn.Forte@Sun.COM 		 * peripheral qualifier for the lun.  if it is non-zero
7927836SJohn.Forte@Sun.COM 		 * then try the SCSI Inquiry on the next lun
7937836SJohn.Forte@Sun.COM 		 */
7947836SJohn.Forte@Sun.COM 		if (status == HBA_STATUS_OK) {
7957836SJohn.Forte@Sun.COM 			peri_qual = inq.inq_dtype & FP_PERI_QUAL_MASK;
7967836SJohn.Forte@Sun.COM 			if (peri_qual == DPQ_POSSIBLE) {
7977836SJohn.Forte@Sun.COM 				break;
7987836SJohn.Forte@Sun.COM 			}
7997836SJohn.Forte@Sun.COM 		}
8007836SJohn.Forte@Sun.COM 	}
8017836SJohn.Forte@Sun.COM 
8027836SJohn.Forte@Sun.COM 	if (ret == FPCFGA_OK)
8037836SJohn.Forte@Sun.COM 		S_FREE(resp_buf);
8047836SJohn.Forte@Sun.COM 
8057836SJohn.Forte@Sun.COM 	/*
8067836SJohn.Forte@Sun.COM 	 * If there are no luns on this target, we will attempt to send
8077836SJohn.Forte@Sun.COM 	 * the SCSI Inquiry to lun 0
8087836SJohn.Forte@Sun.COM 	 */
8097836SJohn.Forte@Sun.COM 	if (num_luns == 0) {
8107836SJohn.Forte@Sun.COM 		lun = 0;
8117836SJohn.Forte@Sun.COM 		status = HBA_ScsiInquiryV2(handle, portAttrs.PortWWN,
8127836SJohn.Forte@Sun.COM 		    *(HBA_WWN *)(pwwn), lun, 0, 0, &inq, &inquirySize,
8137836SJohn.Forte@Sun.COM 		    &scsiStatus, &sense, &senseSize);
8147836SJohn.Forte@Sun.COM 	}
8157836SJohn.Forte@Sun.COM 
8167836SJohn.Forte@Sun.COM 	if (status != HBA_STATUS_OK) {
8177836SJohn.Forte@Sun.COM 		if (status ==  HBA_STATUS_ERROR_NOT_A_TARGET) {
8187836SJohn.Forte@Sun.COM 			inq.inq_dtype = DTYPE_UNKNOWN;
8197836SJohn.Forte@Sun.COM 		} else if (status ==  HBA_STATUS_ERROR_ILLEGAL_WWN) {
8207836SJohn.Forte@Sun.COM 			free(update_str);
8217836SJohn.Forte@Sun.COM 			return (FPCFGA_APID_NOEXIST);
8227836SJohn.Forte@Sun.COM 		} else {
8237836SJohn.Forte@Sun.COM 			/*
8247836SJohn.Forte@Sun.COM 			 * Failed to get the inq_dtype of device
8257836SJohn.Forte@Sun.COM 			 * If we find that there is a lunlist for this
8267836SJohn.Forte@Sun.COM 			 * device it could mean that there dangling
8277836SJohn.Forte@Sun.COM 			 * devinfo nodes. So, we will go ahead and try
8287836SJohn.Forte@Sun.COM 			 * to unconfigure them.  We'll just set the
8297836SJohn.Forte@Sun.COM 			 * inq_dtype to some invalid value (0xFF)
8307836SJohn.Forte@Sun.COM 			 */
8317836SJohn.Forte@Sun.COM 			if ((apidt->lunlist == NULL) ||
8327836SJohn.Forte@Sun.COM 			    (state_change_cmd == CFGA_CMD_CONFIGURE)) {
8337836SJohn.Forte@Sun.COM 				cfga_err(errstring, 0,
8347836SJohn.Forte@Sun.COM 				    ERRARG_FC_INQUIRY,
8357836SJohn.Forte@Sun.COM 				    apidt->dyncomp, 0);
8367836SJohn.Forte@Sun.COM 				free(update_str);
8377836SJohn.Forte@Sun.COM 				return (FPCFGA_LIB_ERR);
8387836SJohn.Forte@Sun.COM 			} else {
8397836SJohn.Forte@Sun.COM 				/* unconfig with lunlist not empty */
8407836SJohn.Forte@Sun.COM 				no_config_attempt++;
8417836SJohn.Forte@Sun.COM 			}
8427836SJohn.Forte@Sun.COM 		}
8437836SJohn.Forte@Sun.COM 	}
8447836SJohn.Forte@Sun.COM 	switch (state_change_cmd) {
8457836SJohn.Forte@Sun.COM 	case CFGA_CMD_CONFIGURE:
8467836SJohn.Forte@Sun.COM 	    if (portAttrs.PortType != HBA_PORTTYPE_NLPORT &&
8477836SJohn.Forte@Sun.COM 		portAttrs.PortType != HBA_PORTTYPE_NPORT) {
8487836SJohn.Forte@Sun.COM 		free(update_str);
8497836SJohn.Forte@Sun.COM 		return (FPCFGA_OK);
8507836SJohn.Forte@Sun.COM 	    }
8517836SJohn.Forte@Sun.COM 
8527836SJohn.Forte@Sun.COM 	    if (((inq.inq_dtype & DTYPE_MASK) == DTYPE_UNKNOWN) &&
8537836SJohn.Forte@Sun.COM 		((flags & CFGA_FLAG_FORCE) == 0)) {
8547836SJohn.Forte@Sun.COM 		/*
8557836SJohn.Forte@Sun.COM 		 * We assume all DTYPE_UNKNOWNs are HBAs and we wont
8567836SJohn.Forte@Sun.COM 		 * waste time trying to config them. If they are not
8577836SJohn.Forte@Sun.COM 		 * HBAs, then there is something wrong since they should
8587836SJohn.Forte@Sun.COM 		 * have had a valid dtype.
8597836SJohn.Forte@Sun.COM 		 *
8607836SJohn.Forte@Sun.COM 		 * However, if the force flag is set (cfgadm -f), we
8617836SJohn.Forte@Sun.COM 		 * go ahead and try to configure.
8627836SJohn.Forte@Sun.COM 		 *
8637836SJohn.Forte@Sun.COM 		 * In this path, however, the force flag is not set.
8647836SJohn.Forte@Sun.COM 		 */
8657836SJohn.Forte@Sun.COM 		free(update_str);
8667836SJohn.Forte@Sun.COM 		return (FPCFGA_OK);
8677836SJohn.Forte@Sun.COM 	    }
8687836SJohn.Forte@Sun.COM 
8697836SJohn.Forte@Sun.COM 	    errno = 0;
8707836SJohn.Forte@Sun.COM 		/*
8717836SJohn.Forte@Sun.COM 		 * We'll issue the devctl_bus_dev_create() call even if the
8727836SJohn.Forte@Sun.COM 		 * path exists in the devinfo tree. This is to take care of
8737836SJohn.Forte@Sun.COM 		 * the situation where the device may be in a state other
8747836SJohn.Forte@Sun.COM 		 * than the online and attached state.
8757836SJohn.Forte@Sun.COM 		 */
8767836SJohn.Forte@Sun.COM 	    if ((ret = do_devctl_dev_create(apidt, dev_path, MAXPATHLEN,
8777836SJohn.Forte@Sun.COM 			inq.inq_dtype, errstring)) != FPCFGA_OK) {
8787836SJohn.Forte@Sun.COM 		/*
8797836SJohn.Forte@Sun.COM 		 * Could not configure device. To provide a more
8807836SJohn.Forte@Sun.COM 		 * meaningful error message, first see if the supplied port
8817836SJohn.Forte@Sun.COM 		 * WWN is there on the fabric. Otherwise print the error
8827836SJohn.Forte@Sun.COM 		 * message using the information received from the driver
8837836SJohn.Forte@Sun.COM 		 */
8847836SJohn.Forte@Sun.COM 		status = getPortAttrsByWWN(handle, *((HBA_WWN *)(pwwn)),
8857836SJohn.Forte@Sun.COM 		    &discPortAttrs);
8867836SJohn.Forte@Sun.COM 		S_FREE(update_str);
8877836SJohn.Forte@Sun.COM 		if (status == HBA_STATUS_ERROR_ILLEGAL_WWN) {
8887836SJohn.Forte@Sun.COM 			return (FPCFGA_APID_NOEXIST);
8897836SJohn.Forte@Sun.COM 		} else {
8907836SJohn.Forte@Sun.COM 			return (FPCFGA_LIB_ERR);
8917836SJohn.Forte@Sun.COM 		}
8927836SJohn.Forte@Sun.COM 	    }
8937836SJohn.Forte@Sun.COM 
8947836SJohn.Forte@Sun.COM 	    if (((optflag & (FLAG_FORCE_UPDATE_REP|FLAG_NO_UPDATE_REP)) == 0) &&
8957836SJohn.Forte@Sun.COM 		update_fabric_wwn_list(ADD_ENTRY, update_str, errstring)) {
8967836SJohn.Forte@Sun.COM 		    cfga_err(errstring, 0, ERR_CONF_OK_UPD_REP, 0);
8977836SJohn.Forte@Sun.COM 	    }
8987836SJohn.Forte@Sun.COM 
8997836SJohn.Forte@Sun.COM 	    S_FREE(update_str);
9007836SJohn.Forte@Sun.COM 
9017836SJohn.Forte@Sun.COM 	    if ((apidt->flags & FLAG_DISABLE_RCM) == 0) {
9027836SJohn.Forte@Sun.COM 		/*
9037836SJohn.Forte@Sun.COM 		 * There may be multiple LUNs associated with the
9047836SJohn.Forte@Sun.COM 		 * WWN we created nodes for. So, we'll call
9057836SJohn.Forte@Sun.COM 		 * apidt_create() again and let it build a list of
9067836SJohn.Forte@Sun.COM 		 * all the LUNs for this WWN using the devinfo tree.
9077836SJohn.Forte@Sun.COM 		 * We will then online all those devices in RCM
9087836SJohn.Forte@Sun.COM 		 */
9097836SJohn.Forte@Sun.COM 		    if ((t_apid = calloc(1, strlen(apidt->xport_phys) +
9107836SJohn.Forte@Sun.COM 					strlen(DYN_SEP) +
9117836SJohn.Forte@Sun.COM 					strlen(apidt->dyncomp) + 1)) == NULL) {
9127836SJohn.Forte@Sun.COM 			    cfga_err(errstring, errno, ERR_MEM_ALLOC, 0);
9137836SJohn.Forte@Sun.COM 			    return (FPCFGA_LIB_ERR);
9147836SJohn.Forte@Sun.COM 		    }
9157836SJohn.Forte@Sun.COM 		    sprintf(t_apid, "%s%s%s", apidt->xport_phys, DYN_SEP,
9167836SJohn.Forte@Sun.COM 			apidt->dyncomp);
9177836SJohn.Forte@Sun.COM 		    if ((ret = apidt_create(t_apid, &my_apidt,
9187836SJohn.Forte@Sun.COM 					errstring)) != FPCFGA_OK) {
9197836SJohn.Forte@Sun.COM 			    free(t_apid);
9207836SJohn.Forte@Sun.COM 			    return (ret);
9217836SJohn.Forte@Sun.COM 		    }
9227836SJohn.Forte@Sun.COM 
9237836SJohn.Forte@Sun.COM 		    my_apidt.flags = apidt->flags;
9247836SJohn.Forte@Sun.COM 		    if ((ret = dev_rcm_online(&my_apidt, -1, flags,
9257836SJohn.Forte@Sun.COM 					NULL)) != FPCFGA_OK) {
9267836SJohn.Forte@Sun.COM 			    cfga_err(errstring, 0, ERRARG_RCM_ONLINE,
9277836SJohn.Forte@Sun.COM 				apidt->lunlist->path, 0);
9287836SJohn.Forte@Sun.COM 			    apidt_free(&my_apidt);
9297836SJohn.Forte@Sun.COM 			    free(t_apid);
9307836SJohn.Forte@Sun.COM 			    return (ret);
9317836SJohn.Forte@Sun.COM 		    }
9327836SJohn.Forte@Sun.COM 		    S_FREE(t_apid);
9337836SJohn.Forte@Sun.COM 		    apidt_free(&my_apidt);
9347836SJohn.Forte@Sun.COM 	    }
9357836SJohn.Forte@Sun.COM 	    return (FPCFGA_OK);
9367836SJohn.Forte@Sun.COM 
9377836SJohn.Forte@Sun.COM 	case CFGA_CMD_UNCONFIGURE:
9387836SJohn.Forte@Sun.COM 		if (portAttrs.PortType != HBA_PORTTYPE_NLPORT &&
9397836SJohn.Forte@Sun.COM 		    portAttrs.PortType != HBA_PORTTYPE_NPORT) {
9407836SJohn.Forte@Sun.COM 			free(update_str);
9417836SJohn.Forte@Sun.COM 			return (FPCFGA_OPNOTSUPP);
9427836SJohn.Forte@Sun.COM 		}
9437836SJohn.Forte@Sun.COM 
9447836SJohn.Forte@Sun.COM 		status = getPortAttrsByWWN(handle, *((HBA_WWN *)(pwwn)),
9457836SJohn.Forte@Sun.COM 		    &discPortAttrs);
9467836SJohn.Forte@Sun.COM 		if (apidt->lunlist == NULL) {
9477836SJohn.Forte@Sun.COM 			/*
9487836SJohn.Forte@Sun.COM 			 * But first, remove entry from the repository if it is
9497836SJohn.Forte@Sun.COM 			 * there ... provided the force update flag is not set
9507836SJohn.Forte@Sun.COM 			 * (in which case the update is already done) or if
9517836SJohn.Forte@Sun.COM 			 * the no-update flag is not set.
9527836SJohn.Forte@Sun.COM 			 */
9537836SJohn.Forte@Sun.COM 			if ((optflag &
9547836SJohn.Forte@Sun.COM 			(FLAG_FORCE_UPDATE_REP|FLAG_NO_UPDATE_REP)) == 0) {
9557836SJohn.Forte@Sun.COM 				if (update_fabric_wwn_list(REMOVE_ENTRY,
9567836SJohn.Forte@Sun.COM 						update_str, errstring)) {
9577836SJohn.Forte@Sun.COM 					free(update_str);
9587836SJohn.Forte@Sun.COM 					cfga_err(errstring, 0,
9597836SJohn.Forte@Sun.COM 						ERR_UNCONF_OK_UPD_REP, 0);
9607836SJohn.Forte@Sun.COM 					return
9617836SJohn.Forte@Sun.COM 					(FPCFGA_UNCONF_OK_UPD_REP_FAILED);
9627836SJohn.Forte@Sun.COM 				}
9637836SJohn.Forte@Sun.COM 			}
9647836SJohn.Forte@Sun.COM 			S_FREE(update_str);
9657836SJohn.Forte@Sun.COM 			if (status == HBA_STATUS_ERROR_ILLEGAL_WWN) {
9667836SJohn.Forte@Sun.COM 				return (FPCFGA_APID_NOEXIST);
9677836SJohn.Forte@Sun.COM 			}
9687836SJohn.Forte@Sun.COM 			return (FPCFGA_OK);
9697836SJohn.Forte@Sun.COM 		}
9707836SJohn.Forte@Sun.COM 		/*
9717836SJohn.Forte@Sun.COM 		 * If there are multiple paths to the mpxio
9727836SJohn.Forte@Sun.COM 		 * device, we will not check in RCM ONLY when there
9737836SJohn.Forte@Sun.COM 		 * is atleast one other ONLINE/STANDBY path
9747836SJohn.Forte@Sun.COM 		 */
9757836SJohn.Forte@Sun.COM 		if (is_xport_phys_in_pathlist(apidt, errstring) !=
9767836SJohn.Forte@Sun.COM 		    FPCFGA_OK) {
9777836SJohn.Forte@Sun.COM 			free(update_str);
9787836SJohn.Forte@Sun.COM 			return (FPCFGA_XPORT_NOT_IN_PHCI_LIST);
9797836SJohn.Forte@Sun.COM 		}
9807836SJohn.Forte@Sun.COM 
9817836SJohn.Forte@Sun.COM 		/*
9827836SJohn.Forte@Sun.COM 		 * dev_rcm_offline() updates errstring
9837836SJohn.Forte@Sun.COM 		 */
9847836SJohn.Forte@Sun.COM 		if ((ret = dev_rcm_offline(apidt, flags, errstring)) !=
9857836SJohn.Forte@Sun.COM 		    FPCFGA_OK) {
9867836SJohn.Forte@Sun.COM 			free(update_str);
9877836SJohn.Forte@Sun.COM 			return (ret);
9887836SJohn.Forte@Sun.COM 		}
9897836SJohn.Forte@Sun.COM 		if ((ret = dev_unconf(apidt, errstring, &unconf_flag)) !=
9907836SJohn.Forte@Sun.COM 		    FPCFGA_OK) {
9917836SJohn.Forte@Sun.COM 			/* when inq failed don't attempt to reconfigure */
9927836SJohn.Forte@Sun.COM 		    if (!no_config_attempt) {
9937836SJohn.Forte@Sun.COM 			(void) do_devctl_dev_create(apidt, dev_path, MAXPATHLEN,
9947836SJohn.Forte@Sun.COM 				inq.inq_dtype, NULL);
9957836SJohn.Forte@Sun.COM 			(void) dev_rcm_online(apidt, -1, flags, NULL);
9967836SJohn.Forte@Sun.COM 		    }
9977836SJohn.Forte@Sun.COM 		    free(update_str);
9987836SJohn.Forte@Sun.COM 		    return (ret);
9997836SJohn.Forte@Sun.COM 		}
10007836SJohn.Forte@Sun.COM 		if ((ret = dev_rcm_remove(apidt, flags, errstring)) !=
10017836SJohn.Forte@Sun.COM 		    FPCFGA_OK) {
10027836SJohn.Forte@Sun.COM 			(void) do_devctl_dev_create(apidt, dev_path, MAXPATHLEN,
10037836SJohn.Forte@Sun.COM 				inq.inq_dtype, NULL);
10047836SJohn.Forte@Sun.COM 			(void) dev_rcm_online(apidt, -1, flags, NULL);
10057836SJohn.Forte@Sun.COM 			free(update_str);
10067836SJohn.Forte@Sun.COM 			return (ret);
10077836SJohn.Forte@Sun.COM 		}
10087836SJohn.Forte@Sun.COM 		/*
10097836SJohn.Forte@Sun.COM 		 * If we offlined a lun in RCM when there are multiple paths but
10107836SJohn.Forte@Sun.COM 		 * none of them are ONLINE/STANDBY, we have to online it back
10117836SJohn.Forte@Sun.COM 		 * in RCM now. This is a try best, will not fail for it.
10127836SJohn.Forte@Sun.COM 		 */
10137836SJohn.Forte@Sun.COM 		dev_rcm_online_nonoperationalpath(apidt, flags, NULL);
10147836SJohn.Forte@Sun.COM 
10157836SJohn.Forte@Sun.COM 		/* Update the repository if we havent already done it */
10167836SJohn.Forte@Sun.COM 		if ((optflag &
10177836SJohn.Forte@Sun.COM 			(FLAG_FORCE_UPDATE_REP|FLAG_NO_UPDATE_REP)) == 0) {
10187836SJohn.Forte@Sun.COM 			if (((optflag & FLAG_REMOVE_UNUSABLE_FCP_DEV) !=
10197836SJohn.Forte@Sun.COM 				    FLAG_REMOVE_UNUSABLE_FCP_DEV) ||
10207836SJohn.Forte@Sun.COM 			    (((optflag & FLAG_REMOVE_UNUSABLE_FCP_DEV) ==
10217836SJohn.Forte@Sun.COM 				FLAG_REMOVE_UNUSABLE_FCP_DEV) &&
10227836SJohn.Forte@Sun.COM 			    (unconf_flag == ALL_APID_LUNS_UNUSABLE))) {
10237836SJohn.Forte@Sun.COM 				if (update_fabric_wwn_list(REMOVE_ENTRY,
10247836SJohn.Forte@Sun.COM 					    update_str, errstring)) {
10257836SJohn.Forte@Sun.COM 				    free(update_str);
10267836SJohn.Forte@Sun.COM 				    cfga_err(errstring, errno,
10277836SJohn.Forte@Sun.COM 					ERR_UNCONF_OK_UPD_REP, 0);
10287836SJohn.Forte@Sun.COM 				    return (FPCFGA_UNCONF_OK_UPD_REP_FAILED);
10297836SJohn.Forte@Sun.COM 				}
10307836SJohn.Forte@Sun.COM 			}
10317836SJohn.Forte@Sun.COM 		}
10327836SJohn.Forte@Sun.COM 		free(update_str);
10337836SJohn.Forte@Sun.COM 		return (FPCFGA_OK);
10347836SJohn.Forte@Sun.COM 
10357836SJohn.Forte@Sun.COM 	default:
10367836SJohn.Forte@Sun.COM 		free(update_str);
10377836SJohn.Forte@Sun.COM 		return (FPCFGA_OPNOTSUPP);
10387836SJohn.Forte@Sun.COM 	}
10397836SJohn.Forte@Sun.COM }
10407836SJohn.Forte@Sun.COM 
10417836SJohn.Forte@Sun.COM /*
10427836SJohn.Forte@Sun.COM  * This function copies a port_wwn got by reading the property on a device
10437836SJohn.Forte@Sun.COM  * node (from_ptr in the function below) on to an array (to_ptr) so that it is
10447836SJohn.Forte@Sun.COM  * readable.
10457836SJohn.Forte@Sun.COM  *
10467836SJohn.Forte@Sun.COM  * Caller responsible to allocate enough memory in "to_ptr"
10477836SJohn.Forte@Sun.COM  */
10487836SJohn.Forte@Sun.COM static void
copy_pwwn_data_to_str(char * to_ptr,const uchar_t * from_ptr)10497836SJohn.Forte@Sun.COM copy_pwwn_data_to_str(char *to_ptr, const uchar_t *from_ptr)
10507836SJohn.Forte@Sun.COM {
10517836SJohn.Forte@Sun.COM 	if ((to_ptr == NULL) || (from_ptr == NULL))
10527836SJohn.Forte@Sun.COM 		return;
10537836SJohn.Forte@Sun.COM 
10547836SJohn.Forte@Sun.COM 	(void) sprintf(to_ptr, "%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x",
10557836SJohn.Forte@Sun.COM 	from_ptr[0], from_ptr[1], from_ptr[2], from_ptr[3],
10567836SJohn.Forte@Sun.COM 	from_ptr[4], from_ptr[5], from_ptr[6], from_ptr[7]);
10577836SJohn.Forte@Sun.COM }
10587836SJohn.Forte@Sun.COM 
10597836SJohn.Forte@Sun.COM static fpcfga_ret_t
unconf_vhci_nodes(di_path_t pnode,di_node_t fp_node,char * xport_phys,char * dyncomp,int unusable_flag,int * num_devs,int * failure_count,char ** errstring,cfga_flags_t flags)10607836SJohn.Forte@Sun.COM unconf_vhci_nodes(di_path_t pnode, di_node_t fp_node, char *xport_phys,
1061*9240SRaghuram.Prahlada@Sun.COM 	char *dyncomp, int unusable_flag,
1062*9240SRaghuram.Prahlada@Sun.COM 	int *num_devs, int *failure_count, char **errstring,
10637836SJohn.Forte@Sun.COM 	cfga_flags_t flags)
10647836SJohn.Forte@Sun.COM {
10657836SJohn.Forte@Sun.COM 	int		iret1, iret2, *lunnump;
10667836SJohn.Forte@Sun.COM 	char		*ptr;		/* scratch pad */
10677836SJohn.Forte@Sun.COM 	char		*node_path, *vhci_path, *update_str;
10687836SJohn.Forte@Sun.COM 	char		port_wwn[WWN_SIZE*2+1], pathname[MAXPATHLEN];
10697836SJohn.Forte@Sun.COM 	uchar_t		*port_wwn_data = NULL;
10707836SJohn.Forte@Sun.COM 	di_node_t	client_node;
10717836SJohn.Forte@Sun.COM 
10727836SJohn.Forte@Sun.COM 	while (pnode != DI_PATH_NIL) {
10737836SJohn.Forte@Sun.COM 
10747836SJohn.Forte@Sun.COM 		(*num_devs)++;
10757836SJohn.Forte@Sun.COM 
10767836SJohn.Forte@Sun.COM 
10777836SJohn.Forte@Sun.COM 		if ((node_path = di_devfs_path(fp_node)) == NULL) {
10787836SJohn.Forte@Sun.COM 			cfga_err(errstring, 0, ERRARG_DEVINFO,
10797836SJohn.Forte@Sun.COM 							xport_phys, 0);
10807836SJohn.Forte@Sun.COM 			(*failure_count)++;
10817836SJohn.Forte@Sun.COM 			pnode = di_path_next_client(fp_node, pnode);
10827836SJohn.Forte@Sun.COM 			continue;
10837836SJohn.Forte@Sun.COM 		}
10847836SJohn.Forte@Sun.COM 
10857836SJohn.Forte@Sun.COM 		iret1 = di_path_prop_lookup_bytes(pnode, PORT_WWN_PROP,
10867836SJohn.Forte@Sun.COM 			&port_wwn_data);
10877836SJohn.Forte@Sun.COM 
10887836SJohn.Forte@Sun.COM 		iret2 = di_path_prop_lookup_ints(pnode, LUN_PROP, &lunnump);
10897836SJohn.Forte@Sun.COM 
10907836SJohn.Forte@Sun.COM 		if ((iret1 == -1) || (iret2 == -1)) {
10917836SJohn.Forte@Sun.COM 			cfga_err(errstring, 0, ERRARG_DI_GET_PROP,
10927836SJohn.Forte@Sun.COM 								node_path, 0);
10937836SJohn.Forte@Sun.COM 			di_devfs_path_free(node_path);
10947836SJohn.Forte@Sun.COM 			node_path = NULL;
10957836SJohn.Forte@Sun.COM 			(*failure_count)++;
10967836SJohn.Forte@Sun.COM 			pnode = di_path_next_client(fp_node, pnode);
10977836SJohn.Forte@Sun.COM 			continue;
10987836SJohn.Forte@Sun.COM 		}
10997836SJohn.Forte@Sun.COM 
11007836SJohn.Forte@Sun.COM 		copy_pwwn_data_to_str(port_wwn, port_wwn_data);
11017836SJohn.Forte@Sun.COM 
11027836SJohn.Forte@Sun.COM 		if ((client_node = di_path_client_node(pnode)) ==
11037836SJohn.Forte@Sun.COM 								DI_NODE_NIL) {
11047836SJohn.Forte@Sun.COM 			(*failure_count)++;
11057836SJohn.Forte@Sun.COM 			di_devfs_path_free(node_path);
11067836SJohn.Forte@Sun.COM 			node_path = NULL;
11077836SJohn.Forte@Sun.COM 			pnode = di_path_next_client(fp_node, pnode);
11087836SJohn.Forte@Sun.COM 			continue;
11097836SJohn.Forte@Sun.COM 		}
11107836SJohn.Forte@Sun.COM 
11117836SJohn.Forte@Sun.COM 		if ((vhci_path = di_devfs_path(client_node)) == NULL) {
11127836SJohn.Forte@Sun.COM 			(*failure_count)++;
11137836SJohn.Forte@Sun.COM 			di_devfs_path_free(node_path);
11147836SJohn.Forte@Sun.COM 			node_path = NULL;
11157836SJohn.Forte@Sun.COM 			pnode = di_path_next_client(fp_node, pnode);
11167836SJohn.Forte@Sun.COM 			continue;
11177836SJohn.Forte@Sun.COM 		}
11187836SJohn.Forte@Sun.COM 
11197836SJohn.Forte@Sun.COM 		if ((ptr = strrchr(vhci_path, '@')) != NULL) {
11207836SJohn.Forte@Sun.COM 			*ptr = '\0';
11217836SJohn.Forte@Sun.COM 		}
11227836SJohn.Forte@Sun.COM 
11237836SJohn.Forte@Sun.COM 		if ((ptr = strrchr(vhci_path, '/')) == NULL) {
11247836SJohn.Forte@Sun.COM 			(*failure_count)++;
11257836SJohn.Forte@Sun.COM 			di_devfs_path_free(node_path);
11267836SJohn.Forte@Sun.COM 			node_path = NULL;
11277836SJohn.Forte@Sun.COM 			pnode = di_path_next_client(fp_node, pnode);
11287836SJohn.Forte@Sun.COM 			continue;
11297836SJohn.Forte@Sun.COM 		}
11307836SJohn.Forte@Sun.COM 
11317836SJohn.Forte@Sun.COM 		sprintf(pathname, "%s%s/%s@w%s,%x", DEVICES_DIR, node_path,
11327836SJohn.Forte@Sun.COM 					++ptr, port_wwn, *lunnump);
11337836SJohn.Forte@Sun.COM 
11347836SJohn.Forte@Sun.COM 		di_devfs_path_free(node_path);
11357836SJohn.Forte@Sun.COM 		di_devfs_path_free(vhci_path);
11367836SJohn.Forte@Sun.COM 		node_path = vhci_path = NULL;
11377836SJohn.Forte@Sun.COM 
11387836SJohn.Forte@Sun.COM 		/*
11397836SJohn.Forte@Sun.COM 		 * Try to offline in RCM first and if that is successful,
11407836SJohn.Forte@Sun.COM 		 * unconfigure the LUN. If offlining in RCM fails, then
11417836SJohn.Forte@Sun.COM 		 * update the failure_count which gets passed back to caller
1142*9240SRaghuram.Prahlada@Sun.COM 		 *
1143*9240SRaghuram.Prahlada@Sun.COM 		 * Here we got to check if unusable_flag is set or not.
1144*9240SRaghuram.Prahlada@Sun.COM 		 * If set, then unconfigure only those luns which are in
1145*9240SRaghuram.Prahlada@Sun.COM 		 * node_state DI_PATH_STATE_OFFLINE. If not set, unconfigure
1146*9240SRaghuram.Prahlada@Sun.COM 		 * all luns.
11477836SJohn.Forte@Sun.COM 		 */
1148*9240SRaghuram.Prahlada@Sun.COM 		if ((unusable_flag & FLAG_REMOVE_UNUSABLE_FCP_DEV) ==
1149*9240SRaghuram.Prahlada@Sun.COM 		    FLAG_REMOVE_UNUSABLE_FCP_DEV) {
1150*9240SRaghuram.Prahlada@Sun.COM 			if (pnode->path_state == DI_PATH_STATE_OFFLINE) {
1151*9240SRaghuram.Prahlada@Sun.COM 				if (fp_rcm_offline(pathname, errstring,
1152*9240SRaghuram.Prahlada@Sun.COM 				    flags) != 0) {
1153*9240SRaghuram.Prahlada@Sun.COM 					(*failure_count)++;
1154*9240SRaghuram.Prahlada@Sun.COM 					pnode = di_path_next_client(fp_node,
1155*9240SRaghuram.Prahlada@Sun.COM 					    pnode);
1156*9240SRaghuram.Prahlada@Sun.COM 					continue;
1157*9240SRaghuram.Prahlada@Sun.COM 				} else if (lun_unconf(pathname, *lunnump,
1158*9240SRaghuram.Prahlada@Sun.COM 				    xport_phys,dyncomp, errstring)
1159*9240SRaghuram.Prahlada@Sun.COM 				    != FPCFGA_OK) {
1160*9240SRaghuram.Prahlada@Sun.COM 					(void) fp_rcm_online(pathname,
1161*9240SRaghuram.Prahlada@Sun.COM 					    NULL, flags);
1162*9240SRaghuram.Prahlada@Sun.COM 					(*failure_count)++;
1163*9240SRaghuram.Prahlada@Sun.COM 					pnode = di_path_next_client(fp_node,
1164*9240SRaghuram.Prahlada@Sun.COM 					    pnode);
1165*9240SRaghuram.Prahlada@Sun.COM 					continue;
1166*9240SRaghuram.Prahlada@Sun.COM 				} else if (fp_rcm_remove(pathname, errstring,
1167*9240SRaghuram.Prahlada@Sun.COM 				    flags) != 0) {
1168*9240SRaghuram.Prahlada@Sun.COM 					/*
1169*9240SRaghuram.Prahlada@Sun.COM 					 * Bring everything back online
1170*9240SRaghuram.Prahlada@Sun.COM 					 * in rcm and continue
1171*9240SRaghuram.Prahlada@Sun.COM 					 */
1172*9240SRaghuram.Prahlada@Sun.COM 					(void) fp_rcm_online(pathname,
1173*9240SRaghuram.Prahlada@Sun.COM 					    NULL, flags);
1174*9240SRaghuram.Prahlada@Sun.COM 					(*failure_count)++;
1175*9240SRaghuram.Prahlada@Sun.COM 					pnode = di_path_next_client(fp_node,
1176*9240SRaghuram.Prahlada@Sun.COM 					    pnode);
1177*9240SRaghuram.Prahlada@Sun.COM 					continue;
1178*9240SRaghuram.Prahlada@Sun.COM 				}
1179*9240SRaghuram.Prahlada@Sun.COM 			} else {
1180*9240SRaghuram.Prahlada@Sun.COM 				pnode = di_path_next(fp_node, pnode);
1181*9240SRaghuram.Prahlada@Sun.COM 				continue;
1182*9240SRaghuram.Prahlada@Sun.COM 			}
1183*9240SRaghuram.Prahlada@Sun.COM 		} else {
1184*9240SRaghuram.Prahlada@Sun.COM 			if (fp_rcm_offline(pathname, errstring, flags) != 0) {
1185*9240SRaghuram.Prahlada@Sun.COM 				(*failure_count)++;
1186*9240SRaghuram.Prahlada@Sun.COM 				pnode = di_path_next_client(fp_node, pnode);
1187*9240SRaghuram.Prahlada@Sun.COM 				continue;
1188*9240SRaghuram.Prahlada@Sun.COM 			} else if (lun_unconf(pathname, *lunnump, xport_phys,
1189*9240SRaghuram.Prahlada@Sun.COM 			    dyncomp, errstring) != FPCFGA_OK) {
1190*9240SRaghuram.Prahlada@Sun.COM 				(void) fp_rcm_online(pathname, NULL, flags);
1191*9240SRaghuram.Prahlada@Sun.COM 				(*failure_count)++;
1192*9240SRaghuram.Prahlada@Sun.COM 				pnode = di_path_next_client(fp_node, pnode);
1193*9240SRaghuram.Prahlada@Sun.COM 				continue;
1194*9240SRaghuram.Prahlada@Sun.COM 			} else if (fp_rcm_remove(pathname, errstring,
1195*9240SRaghuram.Prahlada@Sun.COM 			    flags) != 0) {
1196*9240SRaghuram.Prahlada@Sun.COM 				/*
1197*9240SRaghuram.Prahlada@Sun.COM 				 * Bring everything back online
1198*9240SRaghuram.Prahlada@Sun.COM 				 * in rcm and continue
1199*9240SRaghuram.Prahlada@Sun.COM 				 */
1200*9240SRaghuram.Prahlada@Sun.COM 				(void) fp_rcm_online(pathname, NULL, flags);
1201*9240SRaghuram.Prahlada@Sun.COM 				(*failure_count)++;
1202*9240SRaghuram.Prahlada@Sun.COM 				pnode = di_path_next_client(fp_node, pnode);
1203*9240SRaghuram.Prahlada@Sun.COM 				continue;
1204*9240SRaghuram.Prahlada@Sun.COM 			}
12057836SJohn.Forte@Sun.COM 		}
12067836SJohn.Forte@Sun.COM 
12077836SJohn.Forte@Sun.COM 		/* Update the repository only on a successful unconfigure */
12087836SJohn.Forte@Sun.COM 		if ((update_str = calloc(1, strlen(xport_phys) +
12097836SJohn.Forte@Sun.COM 					strlen(DYN_SEP) +
12107836SJohn.Forte@Sun.COM 					strlen(port_wwn) + 1)) == NULL) {
12117836SJohn.Forte@Sun.COM 			cfga_err(errstring, errno, ERR_UNCONF_OK_UPD_REP, 0);
12127836SJohn.Forte@Sun.COM 			(*failure_count)++;
12137836SJohn.Forte@Sun.COM 			pnode = di_path_next_client(fp_node, pnode);
12147836SJohn.Forte@Sun.COM 			continue;
12157836SJohn.Forte@Sun.COM 		}
12167836SJohn.Forte@Sun.COM 
12177836SJohn.Forte@Sun.COM 		/* Init the string to be removed from repository */
12187836SJohn.Forte@Sun.COM 		sprintf(update_str, "%s%s%s", xport_phys, DYN_SEP, port_wwn);
12197836SJohn.Forte@Sun.COM 
12207836SJohn.Forte@Sun.COM 		if (update_fabric_wwn_list(REMOVE_ENTRY, update_str,
12217836SJohn.Forte@Sun.COM 								errstring)) {
12227836SJohn.Forte@Sun.COM 			S_FREE(update_str);
12237836SJohn.Forte@Sun.COM 			cfga_err(errstring, errno,
12247836SJohn.Forte@Sun.COM 					ERR_UNCONF_OK_UPD_REP, 0);
12257836SJohn.Forte@Sun.COM 			(*failure_count)++;
12267836SJohn.Forte@Sun.COM 			/* Cleanup and continue from here just for clarity */
12277836SJohn.Forte@Sun.COM 			pnode = di_path_next_client(fp_node, pnode);
12287836SJohn.Forte@Sun.COM 			continue;
12297836SJohn.Forte@Sun.COM 		}
12307836SJohn.Forte@Sun.COM 
12317836SJohn.Forte@Sun.COM 		S_FREE(update_str);
12327836SJohn.Forte@Sun.COM 		pnode = di_path_next_client(fp_node, pnode);
12337836SJohn.Forte@Sun.COM 	}
12347836SJohn.Forte@Sun.COM 
12357836SJohn.Forte@Sun.COM 	return (FPCFGA_OK);
12367836SJohn.Forte@Sun.COM }
12377836SJohn.Forte@Sun.COM 
12387836SJohn.Forte@Sun.COM static fpcfga_ret_t
unconf_non_vhci_nodes(di_node_t dnode,char * xport_phys,char * dyncomp,int unusable_flag,int * num_devs,int * failure_count,char ** errstring,cfga_flags_t flags)12397836SJohn.Forte@Sun.COM unconf_non_vhci_nodes(di_node_t dnode, char *xport_phys, char *dyncomp,
1240*9240SRaghuram.Prahlada@Sun.COM 	int unusable_flag, int *num_devs, int *failure_count,
1241*9240SRaghuram.Prahlada@Sun.COM 	char **errstring, cfga_flags_t flags)
12427836SJohn.Forte@Sun.COM {
12437836SJohn.Forte@Sun.COM 	int	ret1, ret2, *lunnump;
12447836SJohn.Forte@Sun.COM 	char	pathname[MAXPATHLEN];
12457836SJohn.Forte@Sun.COM 	char	*node_path, *update_str;
12467836SJohn.Forte@Sun.COM 	char	port_wwn[WWN_SIZE*2+1];
12477836SJohn.Forte@Sun.COM 	uchar_t	*port_wwn_data = NULL;
12487836SJohn.Forte@Sun.COM 
12497836SJohn.Forte@Sun.COM 	while (dnode != DI_NODE_NIL) {
12507836SJohn.Forte@Sun.COM 
12517836SJohn.Forte@Sun.COM 		(*num_devs)++;
12527836SJohn.Forte@Sun.COM 
12537836SJohn.Forte@Sun.COM 		/* Get the physical path for this node */
12547836SJohn.Forte@Sun.COM 		if ((node_path = di_devfs_path(dnode)) == NULL) {
12557836SJohn.Forte@Sun.COM 			/*
12567836SJohn.Forte@Sun.COM 			 * We don't try to offline in RCM here because we
12577836SJohn.Forte@Sun.COM 			 * don't know the path to offline. Just continue to
12587836SJohn.Forte@Sun.COM 			 * the next node.
12597836SJohn.Forte@Sun.COM 			 */
12607836SJohn.Forte@Sun.COM 			cfga_err(errstring, 0, ERRARG_DEVINFO, xport_phys, 0);
12617836SJohn.Forte@Sun.COM 			(*failure_count)++;
12627836SJohn.Forte@Sun.COM 			dnode = di_sibling_node(dnode);
12637836SJohn.Forte@Sun.COM 			continue;
12647836SJohn.Forte@Sun.COM 		}
12657836SJohn.Forte@Sun.COM 
12667836SJohn.Forte@Sun.COM 		/* Now get the LUN # of this device thru the property */
12677836SJohn.Forte@Sun.COM 		ret1 = di_prop_lookup_ints(DDI_DEV_T_ANY, dnode,
12687836SJohn.Forte@Sun.COM 							LUN_PROP, &lunnump);
12697836SJohn.Forte@Sun.COM 
12707836SJohn.Forte@Sun.COM 		/* Next get the port WWN of the device */
12717836SJohn.Forte@Sun.COM 		ret2 = di_prop_lookup_bytes(DDI_DEV_T_ANY, dnode,
12727836SJohn.Forte@Sun.COM 						PORT_WWN_PROP, &port_wwn_data);
12737836SJohn.Forte@Sun.COM 
12747836SJohn.Forte@Sun.COM 		/* A failure in any of the above is not good */
12757836SJohn.Forte@Sun.COM 		if ((ret1 == -1) || (ret2 == -1)) {
12767836SJohn.Forte@Sun.COM 			/*
12777836SJohn.Forte@Sun.COM 			 * We don't try to offline in RCM here because we
12787836SJohn.Forte@Sun.COM 			 * don't know the path to offline. Just continue to
12797836SJohn.Forte@Sun.COM 			 * the next node.
12807836SJohn.Forte@Sun.COM 			 */
12817836SJohn.Forte@Sun.COM 			cfga_err(errstring, 0,
12827836SJohn.Forte@Sun.COM 					ERRARG_DI_GET_PROP, node_path, 0);
12837836SJohn.Forte@Sun.COM 			di_devfs_path_free(node_path);
12847836SJohn.Forte@Sun.COM 			node_path = NULL;
12857836SJohn.Forte@Sun.COM 			(*failure_count)++;
12867836SJohn.Forte@Sun.COM 			dnode = di_sibling_node(dnode);
12877836SJohn.Forte@Sun.COM 			continue;
12887836SJohn.Forte@Sun.COM 		}
12897836SJohn.Forte@Sun.COM 
12907836SJohn.Forte@Sun.COM 		/* Prepend the "/devices" prefix to the path and copy it */
12917836SJohn.Forte@Sun.COM 		sprintf(pathname, "%s%s", DEVICES_DIR, node_path);
12927836SJohn.Forte@Sun.COM 		di_devfs_path_free(node_path);
12937836SJohn.Forte@Sun.COM 		node_path = NULL;
12947836SJohn.Forte@Sun.COM 
12957836SJohn.Forte@Sun.COM 		copy_pwwn_data_to_str(port_wwn, port_wwn_data);
12967836SJohn.Forte@Sun.COM 
12977836SJohn.Forte@Sun.COM 		if (strstr(pathname, "@w") == NULL) {
12987836SJohn.Forte@Sun.COM 			/*
12997836SJohn.Forte@Sun.COM 			 * If the driver is detached, some part of the path
13007836SJohn.Forte@Sun.COM 			 * may be missing and so we'll manually construct it
13017836SJohn.Forte@Sun.COM 			 */
13027836SJohn.Forte@Sun.COM 			sprintf(&pathname[strlen(pathname)], "@w%s,%x",
13037836SJohn.Forte@Sun.COM 							port_wwn, *lunnump);
13047836SJohn.Forte@Sun.COM 		}
13057836SJohn.Forte@Sun.COM 
13067836SJohn.Forte@Sun.COM 		/*
13077836SJohn.Forte@Sun.COM 		 * Try to offline in RCM first and if that is successful,
13087836SJohn.Forte@Sun.COM 		 * unconfigure the LUN. If offlining in RCM fails, then
13097836SJohn.Forte@Sun.COM 		 * update the failure count
1310*9240SRaghuram.Prahlada@Sun.COM 		 *
1311*9240SRaghuram.Prahlada@Sun.COM 		 * Here we got to check if unusable_flag is set or not.
1312*9240SRaghuram.Prahlada@Sun.COM 		 * If set, then unconfigure only those luns which are in
1313*9240SRaghuram.Prahlada@Sun.COM 		 * node_state DI_DEVICE_OFFLINE or DI_DEVICE_DOWN.
1314*9240SRaghuram.Prahlada@Sun.COM 		 * If not set, unconfigure all luns.
13157836SJohn.Forte@Sun.COM 		 */
1316*9240SRaghuram.Prahlada@Sun.COM 		if ((unusable_flag & FLAG_REMOVE_UNUSABLE_FCP_DEV) ==
1317*9240SRaghuram.Prahlada@Sun.COM 		    FLAG_REMOVE_UNUSABLE_FCP_DEV) {
1318*9240SRaghuram.Prahlada@Sun.COM 			if ((dnode->node_state == DI_DEVICE_OFFLINE) ||
1319*9240SRaghuram.Prahlada@Sun.COM 			    (dnode->node_state == DI_DEVICE_DOWN)) {
1320*9240SRaghuram.Prahlada@Sun.COM 				if (fp_rcm_offline(pathname, errstring,
1321*9240SRaghuram.Prahlada@Sun.COM 				    flags) != 0) {
1322*9240SRaghuram.Prahlada@Sun.COM 					(*failure_count)++;
1323*9240SRaghuram.Prahlada@Sun.COM 					dnode = di_sibling_node(dnode);
1324*9240SRaghuram.Prahlada@Sun.COM 					continue;
1325*9240SRaghuram.Prahlada@Sun.COM 				} else if (lun_unconf(pathname, *lunnump,
1326*9240SRaghuram.Prahlada@Sun.COM 				    xport_phys,dyncomp, errstring)
1327*9240SRaghuram.Prahlada@Sun.COM 				    != FPCFGA_OK) {
1328*9240SRaghuram.Prahlada@Sun.COM 					(void) fp_rcm_online(pathname,
1329*9240SRaghuram.Prahlada@Sun.COM 					    NULL, flags);
1330*9240SRaghuram.Prahlada@Sun.COM 					(*failure_count)++;
1331*9240SRaghuram.Prahlada@Sun.COM 					dnode = di_sibling_node(dnode);
1332*9240SRaghuram.Prahlada@Sun.COM 					continue;
1333*9240SRaghuram.Prahlada@Sun.COM 				} else if (fp_rcm_remove(pathname, errstring,
1334*9240SRaghuram.Prahlada@Sun.COM 				    flags) != 0) {
1335*9240SRaghuram.Prahlada@Sun.COM 					/*
1336*9240SRaghuram.Prahlada@Sun.COM 					 * Bring everything back online
1337*9240SRaghuram.Prahlada@Sun.COM 					 * in rcm and continue
1338*9240SRaghuram.Prahlada@Sun.COM 					 */
1339*9240SRaghuram.Prahlada@Sun.COM 					(void) fp_rcm_online(pathname,
1340*9240SRaghuram.Prahlada@Sun.COM 					    NULL, flags);
1341*9240SRaghuram.Prahlada@Sun.COM 					(*failure_count)++;
1342*9240SRaghuram.Prahlada@Sun.COM 					dnode = di_sibling_node(dnode);
1343*9240SRaghuram.Prahlada@Sun.COM 					continue;
1344*9240SRaghuram.Prahlada@Sun.COM 				}
1345*9240SRaghuram.Prahlada@Sun.COM 			} else {
1346*9240SRaghuram.Prahlada@Sun.COM 				dnode = di_sibling_node(dnode);
1347*9240SRaghuram.Prahlada@Sun.COM 				continue;
1348*9240SRaghuram.Prahlada@Sun.COM 			}
1349*9240SRaghuram.Prahlada@Sun.COM 		} else {
1350*9240SRaghuram.Prahlada@Sun.COM 			if (fp_rcm_offline(pathname, errstring, flags) != 0) {
1351*9240SRaghuram.Prahlada@Sun.COM 				(*failure_count)++;
1352*9240SRaghuram.Prahlada@Sun.COM 				dnode = di_sibling_node(dnode);
1353*9240SRaghuram.Prahlada@Sun.COM 				continue;
1354*9240SRaghuram.Prahlada@Sun.COM 			} else if (lun_unconf(pathname, *lunnump, xport_phys,
1355*9240SRaghuram.Prahlada@Sun.COM 			    dyncomp, errstring) != FPCFGA_OK) {
1356*9240SRaghuram.Prahlada@Sun.COM 				(void) fp_rcm_online(pathname, NULL, flags);
1357*9240SRaghuram.Prahlada@Sun.COM 				(*failure_count)++;
1358*9240SRaghuram.Prahlada@Sun.COM 				dnode = di_sibling_node(dnode);
1359*9240SRaghuram.Prahlada@Sun.COM 				continue;
1360*9240SRaghuram.Prahlada@Sun.COM 			} else if (fp_rcm_remove(pathname, errstring,
1361*9240SRaghuram.Prahlada@Sun.COM 			    flags) != 0) {
1362*9240SRaghuram.Prahlada@Sun.COM 				/*
1363*9240SRaghuram.Prahlada@Sun.COM 				 * Bring everything back online
1364*9240SRaghuram.Prahlada@Sun.COM 				 * in rcm and continue
1365*9240SRaghuram.Prahlada@Sun.COM 				 */
1366*9240SRaghuram.Prahlada@Sun.COM 				(void) fp_rcm_online(pathname, NULL, flags);
1367*9240SRaghuram.Prahlada@Sun.COM 				(*failure_count)++;
1368*9240SRaghuram.Prahlada@Sun.COM 				dnode = di_sibling_node(dnode);
1369*9240SRaghuram.Prahlada@Sun.COM 				continue;
1370*9240SRaghuram.Prahlada@Sun.COM 			}
13717836SJohn.Forte@Sun.COM 		}
13727836SJohn.Forte@Sun.COM 
13737836SJohn.Forte@Sun.COM 		/* Update the repository only on a successful unconfigure */
13747836SJohn.Forte@Sun.COM 		if ((update_str = calloc(1, strlen(xport_phys) +
13757836SJohn.Forte@Sun.COM 					strlen(DYN_SEP) +
13767836SJohn.Forte@Sun.COM 					strlen(port_wwn) + 1)) == NULL) {
13777836SJohn.Forte@Sun.COM 			cfga_err(errstring, errno, ERR_UNCONF_OK_UPD_REP, 0);
13787836SJohn.Forte@Sun.COM 			(*failure_count)++;
13797836SJohn.Forte@Sun.COM 			dnode = di_sibling_node(dnode);
13807836SJohn.Forte@Sun.COM 			continue;
13817836SJohn.Forte@Sun.COM 		}
13827836SJohn.Forte@Sun.COM 
13837836SJohn.Forte@Sun.COM 		/* Init the string to be removed from repository */
13847836SJohn.Forte@Sun.COM 		sprintf(update_str, "%s%s%s", xport_phys, DYN_SEP, port_wwn);
13857836SJohn.Forte@Sun.COM 
13867836SJohn.Forte@Sun.COM 		if (update_fabric_wwn_list(REMOVE_ENTRY, update_str,
13877836SJohn.Forte@Sun.COM 								errstring)) {
13887836SJohn.Forte@Sun.COM 			S_FREE(update_str);
13897836SJohn.Forte@Sun.COM 			cfga_err(errstring, errno, ERR_UNCONF_OK_UPD_REP, 0);
13907836SJohn.Forte@Sun.COM 			(*failure_count)++;
13917836SJohn.Forte@Sun.COM 			dnode = di_sibling_node(dnode);
13927836SJohn.Forte@Sun.COM 			continue;
13937836SJohn.Forte@Sun.COM 		}
13947836SJohn.Forte@Sun.COM 
13957836SJohn.Forte@Sun.COM 		S_FREE(update_str);
13967836SJohn.Forte@Sun.COM 		dnode = di_sibling_node(dnode);
13977836SJohn.Forte@Sun.COM 	}
13987836SJohn.Forte@Sun.COM 
13997836SJohn.Forte@Sun.COM 	return (FPCFGA_OK);
14007836SJohn.Forte@Sun.COM }
14017836SJohn.Forte@Sun.COM 
14027836SJohn.Forte@Sun.COM /*
14037836SJohn.Forte@Sun.COM  * INPUT:
14047836SJohn.Forte@Sun.COM  * apidt - Pointer to apid_t structure with data filled in
14057836SJohn.Forte@Sun.COM  * flags - Flags for special handling
14067836SJohn.Forte@Sun.COM  *
14077836SJohn.Forte@Sun.COM  * OUTPUT:
14087836SJohn.Forte@Sun.COM  * errstring - Applicable only on a failure from plugin
14097836SJohn.Forte@Sun.COM  * num_devs  - Incremented per lun
14107836SJohn.Forte@Sun.COM  * failure_count - Incremented on any failed operation on lun
14117836SJohn.Forte@Sun.COM  *
14127836SJohn.Forte@Sun.COM  * RETURNS:
14137836SJohn.Forte@Sun.COM  * non-FPCFGA_OK on any validation check error. If this value is returned, no
14147836SJohn.Forte@Sun.COM  *             devices were handled.  Consequently num_devs and failure_count
14157836SJohn.Forte@Sun.COM  *             will not be incremented.
14167836SJohn.Forte@Sun.COM  * FPCFGA_OK This return value doesn't mean that all devices were successfully
14177836SJohn.Forte@Sun.COM  *             unconfigured, you have to check failure_count.
14187836SJohn.Forte@Sun.COM  */
14197836SJohn.Forte@Sun.COM static fpcfga_ret_t
unconf_any_devinfo_nodes(apid_t * apidt,cfga_flags_t flags,char ** errstring,int * num_devs,int * failure_count)14207836SJohn.Forte@Sun.COM unconf_any_devinfo_nodes(apid_t *apidt, cfga_flags_t flags, char **errstring,
14217836SJohn.Forte@Sun.COM 				int *num_devs, int *failure_count)
14227836SJohn.Forte@Sun.COM {
14237836SJohn.Forte@Sun.COM 	char		*node_path = NULL;
14247836SJohn.Forte@Sun.COM 	char		pathname[MAXPATHLEN], *ptr;	/* scratch pad */
14257836SJohn.Forte@Sun.COM 	di_node_t	root_node, direct_node, fp_node;
14267836SJohn.Forte@Sun.COM 	di_path_t	path_node = DI_PATH_NIL;
14277836SJohn.Forte@Sun.COM 
14287836SJohn.Forte@Sun.COM 	/*
14297836SJohn.Forte@Sun.COM 	 * apidt->xport_phys is something like :
14307836SJohn.Forte@Sun.COM 	 * /devices/pci@.../SUNW,qlc@../fp@0,0:fc
14317836SJohn.Forte@Sun.COM 	 * Make sure we copy both the devinfo and pathinfo nodes
14327836SJohn.Forte@Sun.COM 	 */
14337836SJohn.Forte@Sun.COM 	(void) strlcpy(pathname, apidt->xport_phys, MAXPATHLEN);
14347836SJohn.Forte@Sun.COM 
14357836SJohn.Forte@Sun.COM 	/* Now get rid of the ':' at the end */
14367836SJohn.Forte@Sun.COM 	if ((ptr = strstr(pathname, MINOR_SEP)) != NULL)
14377836SJohn.Forte@Sun.COM 		*ptr = '\0';
14387836SJohn.Forte@Sun.COM 
14397836SJohn.Forte@Sun.COM 	if (strncmp(pathname, DEVICES_DIR, strlen(DEVICES_DIR))) {
14407836SJohn.Forte@Sun.COM 		cfga_err(errstring, 0, ERRARG_INVALID_PATH, pathname, 0);
14417836SJohn.Forte@Sun.COM 		return (FPCFGA_INVALID_PATH);
14427836SJohn.Forte@Sun.COM 	}
14437836SJohn.Forte@Sun.COM 
14447836SJohn.Forte@Sun.COM 	if ((root_node = di_init("/", DINFOCPYALL | DINFOPATH)) ==
14457836SJohn.Forte@Sun.COM 								DI_NODE_NIL) {
14467836SJohn.Forte@Sun.COM 		cfga_err(errstring, errno, ERRARG_DEVINFO,
14477836SJohn.Forte@Sun.COM 							apidt->xport_phys, 0);
14487836SJohn.Forte@Sun.COM 		return (FPCFGA_LIB_ERR);
14497836SJohn.Forte@Sun.COM 	}
14507836SJohn.Forte@Sun.COM 
14517836SJohn.Forte@Sun.COM 	if ((fp_node = di_drv_first_node("fp", root_node)) == DI_NODE_NIL) {
14527836SJohn.Forte@Sun.COM 		cfga_err(errstring, errno, ERRARG_DEVINFO,
14537836SJohn.Forte@Sun.COM 							apidt->xport_phys, 0);
14547836SJohn.Forte@Sun.COM 		di_fini(root_node);
14557836SJohn.Forte@Sun.COM 		return (FPCFGA_LIB_ERR);
14567836SJohn.Forte@Sun.COM 	}
14577836SJohn.Forte@Sun.COM 
14587836SJohn.Forte@Sun.COM 	/*
14597836SJohn.Forte@Sun.COM 	 * Search all the fp nodes to see if any match the one we are trying
14607836SJohn.Forte@Sun.COM 	 * to unconfigure
14617836SJohn.Forte@Sun.COM 	 */
14627836SJohn.Forte@Sun.COM 
14637836SJohn.Forte@Sun.COM 	/* Skip the "/devices" prefix */
14647836SJohn.Forte@Sun.COM 	ptr = pathname + strlen(DEVICES_DIR);
14657836SJohn.Forte@Sun.COM 
14667836SJohn.Forte@Sun.COM 	while (fp_node != DI_NODE_NIL) {
14677836SJohn.Forte@Sun.COM 		node_path = di_devfs_path(fp_node);
14687836SJohn.Forte@Sun.COM 		if (strcmp(node_path, ptr) == 0) {
14697836SJohn.Forte@Sun.COM 			/* Found the fp node. 'pathname' has the full path */
14707836SJohn.Forte@Sun.COM 			di_devfs_path_free(node_path);
14717836SJohn.Forte@Sun.COM 			node_path = NULL;
14727836SJohn.Forte@Sun.COM 			break;
14737836SJohn.Forte@Sun.COM 		}
14747836SJohn.Forte@Sun.COM 		fp_node = di_drv_next_node(fp_node);
14757836SJohn.Forte@Sun.COM 		di_devfs_path_free(node_path);
14767836SJohn.Forte@Sun.COM 	}
14777836SJohn.Forte@Sun.COM 
14787836SJohn.Forte@Sun.COM 	if (fp_node == DI_NODE_NIL) {
14797836SJohn.Forte@Sun.COM 		cfga_err(errstring, 0, ERRARG_NOT_IN_DEVINFO,
14807836SJohn.Forte@Sun.COM 							apidt->xport_phys, 0);
14817836SJohn.Forte@Sun.COM 		di_fini(root_node);
14827836SJohn.Forte@Sun.COM 		return (FPCFGA_LIB_ERR);
14837836SJohn.Forte@Sun.COM 	}
14847836SJohn.Forte@Sun.COM 
14857836SJohn.Forte@Sun.COM 	direct_node = di_child_node(fp_node);
14867836SJohn.Forte@Sun.COM 	path_node = di_path_next_client(fp_node, path_node);
14877836SJohn.Forte@Sun.COM 
14887836SJohn.Forte@Sun.COM 	if ((direct_node == DI_NODE_NIL) && (path_node == DI_PATH_NIL)) {
14897836SJohn.Forte@Sun.COM 		/* No devinfo or pathinfo nodes. Great ! Just return success */
14907836SJohn.Forte@Sun.COM 		di_fini(root_node);
14917836SJohn.Forte@Sun.COM 		return (FPCFGA_OK);
14927836SJohn.Forte@Sun.COM 	}
14937836SJohn.Forte@Sun.COM 
14947836SJohn.Forte@Sun.COM 	/* First unconfigure any non-MPXIO nodes */
14957836SJohn.Forte@Sun.COM 	unconf_non_vhci_nodes(direct_node, apidt->xport_phys, apidt->dyncomp,
1496*9240SRaghuram.Prahlada@Sun.COM 	    apidt->flags, num_devs, failure_count, errstring, flags);
14977836SJohn.Forte@Sun.COM 
14987836SJohn.Forte@Sun.COM 	/*
14997836SJohn.Forte@Sun.COM 	 * Now we will traverse any path info nodes that are there
15007836SJohn.Forte@Sun.COM 	 *
15017836SJohn.Forte@Sun.COM 	 * Only MPXIO devices have pathinfo nodes
15027836SJohn.Forte@Sun.COM 	 */
15037836SJohn.Forte@Sun.COM 	unconf_vhci_nodes(path_node, fp_node, apidt->xport_phys, apidt->dyncomp,
1504*9240SRaghuram.Prahlada@Sun.COM 	    apidt->flags, num_devs, failure_count, errstring, flags);
15057836SJohn.Forte@Sun.COM 
15067836SJohn.Forte@Sun.COM 	di_fini(root_node);
15077836SJohn.Forte@Sun.COM 
15087836SJohn.Forte@Sun.COM 	/*
15097836SJohn.Forte@Sun.COM 	 * We don't want to check the return value of unconf_non_vhci_nodes()
15107836SJohn.Forte@Sun.COM 	 * and unconf_vhci_nodes().  But instead, we are interested only in
15117836SJohn.Forte@Sun.COM 	 * consistently incrementing num_devs and failure_count so that we can
15127836SJohn.Forte@Sun.COM 	 * compare them.
15137836SJohn.Forte@Sun.COM 	 */
15147836SJohn.Forte@Sun.COM 	return (FPCFGA_OK);
15157836SJohn.Forte@Sun.COM }
15167836SJohn.Forte@Sun.COM 
15177836SJohn.Forte@Sun.COM /*
15187836SJohn.Forte@Sun.COM  * This function handles configuring/unconfiguring all the devices w.r.t
15197836SJohn.Forte@Sun.COM  * the FCA port specified by apidt.
15207836SJohn.Forte@Sun.COM  *
15217836SJohn.Forte@Sun.COM  * In the unconfigure case, it first unconfigures all the devices that are
15227836SJohn.Forte@Sun.COM  * seen through the given port at that moment and then unconfigures all the
15237836SJohn.Forte@Sun.COM  * devices that still (somehow) have devinfo nodes on the system for that FCA
15247836SJohn.Forte@Sun.COM  * port.
15257836SJohn.Forte@Sun.COM  *
15267836SJohn.Forte@Sun.COM  * INPUT:
15277836SJohn.Forte@Sun.COM  * cmd - CFGA_CMD_CONFIGURE or CFGA_CMD_UNCONFIGURE
15287836SJohn.Forte@Sun.COM  * apidt - Pointer to apid_t structure with data filled in
15297836SJohn.Forte@Sun.COM  * flags - Flags for special handling
15307836SJohn.Forte@Sun.COM  *
15317836SJohn.Forte@Sun.COM  * OUTPUT:
15327836SJohn.Forte@Sun.COM  * errstring - Applicable only on a failure from plugin
15337836SJohn.Forte@Sun.COM  *
15347836SJohn.Forte@Sun.COM  * RETURNS:
15357836SJohn.Forte@Sun.COM  * FPCFGA_OK on success
15367836SJohn.Forte@Sun.COM  * non-FPCFGA_OK otherwise
15377836SJohn.Forte@Sun.COM  */
15387836SJohn.Forte@Sun.COM static fpcfga_ret_t
handle_devs(cfga_cmd_t cmd,apid_t * apidt,cfga_flags_t flags,char ** errstring,HBA_HANDLE handle,int portIndex,HBA_PORTATTRIBUTES portAttrs)15397836SJohn.Forte@Sun.COM handle_devs(cfga_cmd_t cmd, apid_t *apidt, cfga_flags_t flags,
15407836SJohn.Forte@Sun.COM 	char **errstring, HBA_HANDLE handle, int portIndex,
15417836SJohn.Forte@Sun.COM 	HBA_PORTATTRIBUTES portAttrs)
15427836SJohn.Forte@Sun.COM {
15437836SJohn.Forte@Sun.COM 	int		num_devs = 0, dev_cs_failed = 0;
15447836SJohn.Forte@Sun.COM 	char		port_wwn[WWN_S_LEN];
15457836SJohn.Forte@Sun.COM 	la_wwn_t	pwwn;
15467836SJohn.Forte@Sun.COM 	apid_t		my_apidt = {NULL};
15477836SJohn.Forte@Sun.COM 	char		*my_apid;
15487836SJohn.Forte@Sun.COM 	HBA_PORTATTRIBUTES	discPortAttrs;
15497836SJohn.Forte@Sun.COM 	int			discIndex;
15507836SJohn.Forte@Sun.COM 	fpcfga_ret_t		rval = FPCFGA_OK;
15517836SJohn.Forte@Sun.COM 
15527836SJohn.Forte@Sun.COM 	if ((my_apid = calloc(
15537836SJohn.Forte@Sun.COM 		1, strlen(apidt->xport_phys) + strlen(DYN_SEP) +
15547836SJohn.Forte@Sun.COM 		(2 * FC_WWN_SIZE) + 1)) == NULL) {
15557836SJohn.Forte@Sun.COM 		cfga_err(errstring, errno, ERR_MEM_ALLOC, 0);
15567836SJohn.Forte@Sun.COM 		return (FPCFGA_LIB_ERR);
15577836SJohn.Forte@Sun.COM 	}
15587836SJohn.Forte@Sun.COM 
15597836SJohn.Forte@Sun.COM 	num_devs = portAttrs.NumberofDiscoveredPorts;
15607836SJohn.Forte@Sun.COM 	for (discIndex = 0; discIndex < portAttrs.NumberofDiscoveredPorts;
15617836SJohn.Forte@Sun.COM 		discIndex++) {
15627836SJohn.Forte@Sun.COM 	    if (getDiscPortAttrs(handle, portIndex,
15637836SJohn.Forte@Sun.COM 		discIndex, &discPortAttrs)) {
15647836SJohn.Forte@Sun.COM 		dev_cs_failed++;
15657836SJohn.Forte@Sun.COM 		/* Move on to the next target */
15667836SJohn.Forte@Sun.COM 		continue;
15677836SJohn.Forte@Sun.COM 	    }
15687836SJohn.Forte@Sun.COM 	    (void) sprintf(port_wwn, "%016llx",
15697836SJohn.Forte@Sun.COM 		wwnConversion(discPortAttrs.PortWWN.wwn));
15707836SJohn.Forte@Sun.COM 		/*
15717836SJohn.Forte@Sun.COM 		 * Construct a fake apid string similar to the one the
15727836SJohn.Forte@Sun.COM 		 * plugin gets from the framework and have apidt_create()
15737836SJohn.Forte@Sun.COM 		 * fill in the apid_t structure.
15747836SJohn.Forte@Sun.COM 		 */
15757836SJohn.Forte@Sun.COM 	    strcpy(my_apid, apidt->xport_phys);
15767836SJohn.Forte@Sun.COM 	    strcat(my_apid, DYN_SEP);
15777836SJohn.Forte@Sun.COM 	    strcat(my_apid, port_wwn);
15787836SJohn.Forte@Sun.COM 	    if (apidt_create(my_apid, &my_apidt, errstring) != FPCFGA_OK) {
15797836SJohn.Forte@Sun.COM 		dev_cs_failed++;
15807836SJohn.Forte@Sun.COM 		continue;
15817836SJohn.Forte@Sun.COM 	    }
15827836SJohn.Forte@Sun.COM 	    my_apidt.flags = apidt->flags;
15837836SJohn.Forte@Sun.COM 
15847836SJohn.Forte@Sun.COM 	    memcpy(&pwwn, &(discPortAttrs.PortWWN), sizeof (la_wwn_t));
15857836SJohn.Forte@Sun.COM 	    if (dev_change_state(cmd, &my_apidt, &pwwn,
15867836SJohn.Forte@Sun.COM 		flags, errstring, handle, portAttrs) != FPCFGA_OK) {
15877836SJohn.Forte@Sun.COM 		dev_cs_failed++;
15887836SJohn.Forte@Sun.COM 	    }
15897836SJohn.Forte@Sun.COM 	    apidt_free(&my_apidt);
15907836SJohn.Forte@Sun.COM 	}
15917836SJohn.Forte@Sun.COM 
15927836SJohn.Forte@Sun.COM 	S_FREE(my_apid);
15937836SJohn.Forte@Sun.COM 
15947836SJohn.Forte@Sun.COM 	/*
15957836SJohn.Forte@Sun.COM 	 * We have now handled all the devices that are currently visible
15967836SJohn.Forte@Sun.COM 	 * through the given FCA port. But, it is possible that there are
15977836SJohn.Forte@Sun.COM 	 * some devinfo nodes hanging around. For the unconfigure operation,
15987836SJohn.Forte@Sun.COM 	 * this has to be looked into too.
15997836SJohn.Forte@Sun.COM 	 */
16007836SJohn.Forte@Sun.COM 	if (cmd == CFGA_CMD_UNCONFIGURE) {
16017836SJohn.Forte@Sun.COM 		/* dev_cs_failed will be updated to indicate any failures */
16027836SJohn.Forte@Sun.COM 		rval = unconf_any_devinfo_nodes(apidt, flags, errstring,
16037836SJohn.Forte@Sun.COM 		    &num_devs, &dev_cs_failed);
16047836SJohn.Forte@Sun.COM 	}
16057836SJohn.Forte@Sun.COM 
16067836SJohn.Forte@Sun.COM 	if (rval == FPCFGA_OK) {
16077836SJohn.Forte@Sun.COM 		if (dev_cs_failed == 0)
16087836SJohn.Forte@Sun.COM 			return (FPCFGA_OK);
16097836SJohn.Forte@Sun.COM 
16107836SJohn.Forte@Sun.COM 		/*
16117836SJohn.Forte@Sun.COM 		 * For the discovered ports, num_devs is counted on target
16127836SJohn.Forte@Sun.COM 		 * basis, but for invisible targets, num_devs is counted on
16137836SJohn.Forte@Sun.COM 		 * lun basis.
16147836SJohn.Forte@Sun.COM 		 *
16157836SJohn.Forte@Sun.COM 		 * But if dev_cs_failed and num_devs are incremented
16167836SJohn.Forte@Sun.COM 		 * consistently, comparation of these two counters is still
16177836SJohn.Forte@Sun.COM 		 * meaningful.
16187836SJohn.Forte@Sun.COM 		 */
16197836SJohn.Forte@Sun.COM 		if (dev_cs_failed == num_devs) {
16207836SJohn.Forte@Sun.COM 			/* Failed on all devices seen through this FCA port */
16217836SJohn.Forte@Sun.COM 			cfga_err(errstring, 0,
16227836SJohn.Forte@Sun.COM 			((cmd == CFGA_CMD_CONFIGURE) ?
16237836SJohn.Forte@Sun.COM 				ERR_FCA_CONFIGURE : ERR_FCA_UNCONFIGURE), 0);
16247836SJohn.Forte@Sun.COM 			return (FPCFGA_LIB_ERR);
16257836SJohn.Forte@Sun.COM 		} else {
16267836SJohn.Forte@Sun.COM 			/* Failed only on some of the devices */
16277836SJohn.Forte@Sun.COM 			cfga_err(errstring, 0, ERR_PARTIAL_SUCCESS, 0);
16287836SJohn.Forte@Sun.COM 			return (FPCFGA_LIB_ERR);
16297836SJohn.Forte@Sun.COM 		}
16307836SJohn.Forte@Sun.COM 	} else {
16317836SJohn.Forte@Sun.COM 		if (dev_cs_failed == num_devs) {
16327836SJohn.Forte@Sun.COM 			/* Failed on all devices seen through this FCA port */
16337836SJohn.Forte@Sun.COM 			cfga_err(errstring, 0,
16347836SJohn.Forte@Sun.COM 			((cmd == CFGA_CMD_CONFIGURE) ?
16357836SJohn.Forte@Sun.COM 				ERR_FCA_CONFIGURE : ERR_FCA_UNCONFIGURE), 0);
16367836SJohn.Forte@Sun.COM 			return (FPCFGA_LIB_ERR);
16377836SJohn.Forte@Sun.COM 		} else {
16387836SJohn.Forte@Sun.COM 			/* Failed only on some of the devices */
16397836SJohn.Forte@Sun.COM 			cfga_err(errstring, 0, ERR_PARTIAL_SUCCESS, 0);
16407836SJohn.Forte@Sun.COM 			return (FPCFGA_LIB_ERR);
16417836SJohn.Forte@Sun.COM 		}
16427836SJohn.Forte@Sun.COM 	}
16437836SJohn.Forte@Sun.COM 
16447836SJohn.Forte@Sun.COM 	/*
16457836SJohn.Forte@Sun.COM 	 * Should never get here
16467836SJohn.Forte@Sun.COM 	 */
16477836SJohn.Forte@Sun.COM }
16487836SJohn.Forte@Sun.COM 
16497836SJohn.Forte@Sun.COM fpcfga_ret_t
fca_change_state(cfga_cmd_t state_change_cmd,apid_t * apidt,cfga_flags_t flags,char ** errstring)16507836SJohn.Forte@Sun.COM fca_change_state(cfga_cmd_t state_change_cmd, apid_t *apidt,
16517836SJohn.Forte@Sun.COM 		cfga_flags_t flags, char **errstring)
16527836SJohn.Forte@Sun.COM {
16537836SJohn.Forte@Sun.COM 	fpcfga_ret_t	ret;
16547836SJohn.Forte@Sun.COM 	HBA_HANDLE	handle;
16557836SJohn.Forte@Sun.COM 	HBA_PORTATTRIBUTES	portAttrs;
16567836SJohn.Forte@Sun.COM 	int			portIndex;
16577836SJohn.Forte@Sun.COM 
16587836SJohn.Forte@Sun.COM 	if ((ret = findMatchingAdapterPort(apidt->xport_phys, &handle,
16597836SJohn.Forte@Sun.COM 	    &portIndex, &portAttrs, errstring)) != FPCFGA_OK) {
16607836SJohn.Forte@Sun.COM 		return (ret);
16617836SJohn.Forte@Sun.COM 	}
16627836SJohn.Forte@Sun.COM 
16637836SJohn.Forte@Sun.COM 	/*
16647836SJohn.Forte@Sun.COM 	 * Bail out if not fabric/public loop
16657836SJohn.Forte@Sun.COM 	 */
16667836SJohn.Forte@Sun.COM 	switch (state_change_cmd) {
16677836SJohn.Forte@Sun.COM 	case CFGA_CMD_CONFIGURE:
16687836SJohn.Forte@Sun.COM 	    if (portAttrs.PortType != HBA_PORTTYPE_NLPORT &&
16697836SJohn.Forte@Sun.COM 		portAttrs.PortType != HBA_PORTTYPE_NPORT) {
16707836SJohn.Forte@Sun.COM 			HBA_CloseAdapter(handle);
16717836SJohn.Forte@Sun.COM 			HBA_FreeLibrary();
16727836SJohn.Forte@Sun.COM 			return (FPCFGA_OK);
16737836SJohn.Forte@Sun.COM 	    }
16747836SJohn.Forte@Sun.COM 	    break;
16757836SJohn.Forte@Sun.COM 
16767836SJohn.Forte@Sun.COM 	case CFGA_CMD_UNCONFIGURE:
16777836SJohn.Forte@Sun.COM 	    if (portAttrs.PortType != HBA_PORTTYPE_NLPORT &&
16787836SJohn.Forte@Sun.COM 		portAttrs.PortType != HBA_PORTTYPE_NPORT) {
16797836SJohn.Forte@Sun.COM 		HBA_CloseAdapter(handle);
16807836SJohn.Forte@Sun.COM 		HBA_FreeLibrary();
16817836SJohn.Forte@Sun.COM 		return (FPCFGA_OPNOTSUPP);
16827836SJohn.Forte@Sun.COM 	    }
16837836SJohn.Forte@Sun.COM 	    break;
16847836SJohn.Forte@Sun.COM 	default:
16857836SJohn.Forte@Sun.COM 		HBA_CloseAdapter(handle);
16867836SJohn.Forte@Sun.COM 		HBA_FreeLibrary();
16877836SJohn.Forte@Sun.COM 		return (FPCFGA_LIB_ERR);
16887836SJohn.Forte@Sun.COM 	}
16897836SJohn.Forte@Sun.COM 	ret = (handle_devs(state_change_cmd, apidt, flags, errstring,
16907836SJohn.Forte@Sun.COM 	    handle, portIndex, portAttrs));
16917836SJohn.Forte@Sun.COM 	HBA_CloseAdapter(handle);
16927836SJohn.Forte@Sun.COM 	HBA_FreeLibrary();
16937836SJohn.Forte@Sun.COM 	return (ret);
16947836SJohn.Forte@Sun.COM }
1695