11e1ddd6cScth /*
21e1ddd6cScth  * CDDL HEADER START
31e1ddd6cScth  *
41e1ddd6cScth  * The contents of this file are subject to the terms of the
51e1ddd6cScth  * Common Development and Distribution License (the "License").
61e1ddd6cScth  * You may not use this file except in compliance with the License.
71e1ddd6cScth  *
81e1ddd6cScth  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
91e1ddd6cScth  * or http://www.opensolaris.org/os/licensing.
101e1ddd6cScth  * See the License for the specific language governing permissions
111e1ddd6cScth  * and limitations under the License.
121e1ddd6cScth  *
131e1ddd6cScth  * When distributing Covered Code, include this CDDL HEADER in each
141e1ddd6cScth  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
151e1ddd6cScth  * If applicable, add the following below this CDDL HEADER, with the
161e1ddd6cScth  * fields enclosed by brackets "[]" replaced with your own identifying
171e1ddd6cScth  * information: Portions Copyright [yyyy] [name of copyright owner]
181e1ddd6cScth  *
191e1ddd6cScth  * CDDL HEADER END
201e1ddd6cScth  */
211e1ddd6cScth /*
2217d71211SJiri Svoboda  * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
2319d47a18SJason King  * Copyright 2021 Racktop Systems, Inc.
24*3fe80ca4SDan Cross  * Copyright 2023 Oxide Computer Company
251e1ddd6cScth  */
261e1ddd6cScth 
271e1ddd6cScth /*
281e1ddd6cScth  * SNIA Multipath Management API implementation
291e1ddd6cScth  */
301e1ddd6cScth 
311e1ddd6cScth #include <sys/conf.h>
321e1ddd6cScth #include <sys/file.h>
331e1ddd6cScth #include <sys/disp.h>
341e1ddd6cScth #include <sys/ddi.h>
351e1ddd6cScth #include <sys/sunddi.h>
361e1ddd6cScth #include <sys/sunmdi.h>
371e1ddd6cScth #include <sys/mdi_impldefs.h>
381e1ddd6cScth #include <sys/scsi/scsi.h>
391e1ddd6cScth #include <sys/scsi/impl/services.h>
401e1ddd6cScth #include <sys/scsi/impl/scsi_reset_notify.h>
411e1ddd6cScth #include <sys/scsi/adapters/scsi_vhci.h>
421e1ddd6cScth 
431e1ddd6cScth /* used to manually force a request sense */
441e1ddd6cScth int vhci_force_manual_sense = 0;
451e1ddd6cScth 
461e1ddd6cScth #define	STD_ACTIVE_OPTIMIZED	0x0
471e1ddd6cScth #define	STD_ACTIVE_NONOPTIMIZED	0x1
481e1ddd6cScth #define	STD_STANDBY		0x2
491e1ddd6cScth #define	STD_UNAVAILABLE		0x3
501e1ddd6cScth #define	STD_TRANSITIONING	0xf
511e1ddd6cScth 
521e1ddd6cScth /*
531e1ddd6cScth  * MP-API Prototypes
541e1ddd6cScth  */
551e1ddd6cScth int vhci_mpapi_init(struct scsi_vhci *);
561e1ddd6cScth void vhci_mpapi_add_dev_prod(struct scsi_vhci *, char *);
571e1ddd6cScth int vhci_mpapi_ctl(dev_t, int, intptr_t, int, cred_t *, int *);
581e1ddd6cScth void vhci_update_mpapi_data(struct scsi_vhci *,
591e1ddd6cScth     scsi_vhci_lun_t *, mdi_pathinfo_t *);
601e1ddd6cScth void* vhci_get_mpapi_item(struct scsi_vhci *, mpapi_list_header_t *,
611e1ddd6cScth     uint8_t, void*);
621e1ddd6cScth int vhci_mpapi_sync_init_port_list(dev_info_t *, void *);
631e1ddd6cScth int vhci_mpapi_get_vhci(dev_info_t *, void *);
641e1ddd6cScth void vhci_mpapi_set_path_state(dev_info_t *, mdi_pathinfo_t *, int);
651e1ddd6cScth void vhci_mpapi_synthesize_tpg_data(struct scsi_vhci *, scsi_vhci_lun_t *,
661e1ddd6cScth     mdi_pathinfo_t *);
67b1a03ab1SVictor Li void vhci_mpapi_update_tpg_data(struct scsi_address *, char *, int);
681e1ddd6cScth int vhci_mpapi_update_tpg_acc_state_for_lu(struct scsi_vhci *,
691e1ddd6cScth     scsi_vhci_lun_t *);
701e1ddd6cScth 
711e1ddd6cScth /* Static Functions */
721e1ddd6cScth static int vhci_get_driver_prop(struct scsi_vhci *, mp_iocdata_t *,
731e1ddd6cScth     void *, void *, int);
741e1ddd6cScth static int vhci_get_dev_prod_list(struct scsi_vhci *, mp_iocdata_t *,
751e1ddd6cScth     void *, void *, int);
761e1ddd6cScth static int vhci_get_dev_prod_prop(struct scsi_vhci *, mp_iocdata_t *,
771e1ddd6cScth     void *, void *, int);
781e1ddd6cScth static int vhci_get_lu_list(struct scsi_vhci *, mp_iocdata_t *,
791e1ddd6cScth     void *, void *, int);
801e1ddd6cScth static int vhci_get_lu_list_from_tpg(struct scsi_vhci *, mp_iocdata_t *,
811e1ddd6cScth     void *, void *, int);
821e1ddd6cScth static int vhci_get_tpg_list_for_lu(struct scsi_vhci *, mp_iocdata_t *,
831e1ddd6cScth     void *, void *, int);
841e1ddd6cScth static int vhci_get_lu_prop(struct scsi_vhci *, mp_iocdata_t *,
851e1ddd6cScth     void *, void *, int);
861e1ddd6cScth static int vhci_get_path_list_for_mp_lu(struct scsi_vhci *, mp_iocdata_t *,
871e1ddd6cScth     void *, void *, int);
881e1ddd6cScth static int vhci_get_path_list_for_init_port(struct scsi_vhci *, mp_iocdata_t *,
891e1ddd6cScth     void *, void *, int);
901e1ddd6cScth static int vhci_get_path_list_for_target_port(struct scsi_vhci *,
911e1ddd6cScth     mp_iocdata_t *, void *, void *, int);
921e1ddd6cScth static int vhci_get_path_prop(struct scsi_vhci *, mp_iocdata_t *,
931e1ddd6cScth     void *, void *, int);
941e1ddd6cScth static int vhci_get_init_port_list(struct scsi_vhci *, mp_iocdata_t *,
951e1ddd6cScth     void *, void *, int);
961e1ddd6cScth static int vhci_get_init_port_prop(struct scsi_vhci *, mp_iocdata_t *,
971e1ddd6cScth     void *, void *, int);
981e1ddd6cScth static int vhci_get_target_port_prop(struct scsi_vhci *, mp_iocdata_t *,
991e1ddd6cScth     void *, void *, int);
1001e1ddd6cScth static int vhci_get_tpg_prop(struct scsi_vhci *, mp_iocdata_t *,
1011e1ddd6cScth     void *, void *, int);
1021e1ddd6cScth static int vhci_get_target_port_list_for_tpg(struct scsi_vhci *, mp_iocdata_t *,
1031e1ddd6cScth     void *, void *, int);
1041e1ddd6cScth static int vhci_set_tpg_access_state(struct scsi_vhci *, mp_iocdata_t *,
1051e1ddd6cScth     void *, void *, int);
1061e1ddd6cScth static int vhci_get_prop_lb_list(struct scsi_vhci *, mp_iocdata_t *,
1071e1ddd6cScth     void *, void *, int);
1081e1ddd6cScth static int vhci_get_prop_lb_prop(struct scsi_vhci *, mp_iocdata_t *,
1091e1ddd6cScth     void *, void *, int);
1101e1ddd6cScth static int vhci_assign_lu_to_tpg(struct scsi_vhci *, mp_iocdata_t *,
1111e1ddd6cScth     void *, void *, int);
1121e1ddd6cScth static int vhci_enable_auto_failback(struct scsi_vhci *, mp_iocdata_t *,
1131e1ddd6cScth     void *, void *, int);
1141e1ddd6cScth static int vhci_disable_auto_failback(struct scsi_vhci *, mp_iocdata_t *,
1151e1ddd6cScth     void *, void *, int);
1161e1ddd6cScth static int vhci_enable_path(struct scsi_vhci *, mp_iocdata_t *,
1171e1ddd6cScth     void *, void *, int);
1181e1ddd6cScth static int vhci_disable_path(struct scsi_vhci *, mp_iocdata_t *,
1191e1ddd6cScth     void *, void *, int);
1201e1ddd6cScth static int vhci_send_uscsi_cmd(dev_t dev, struct scsi_vhci *, mp_iocdata_t *,
1211e1ddd6cScth     void *, void *, int);
1221e1ddd6cScth static int vhci_mpapi_validate(void *, mp_iocdata_t *, int, cred_t *);
1231e1ddd6cScth static uint64_t vhci_mpapi_create_oid(mpapi_priv_t *, uint8_t);
1241e1ddd6cScth static int vhci_mpapi_ioctl(dev_t dev, struct scsi_vhci *, void *,
1251e1ddd6cScth     mp_iocdata_t *, int, cred_t *);
1261e1ddd6cScth static int vhci_mpapi_add_to_list(mpapi_list_header_t *, mpapi_item_list_t *);
1271e1ddd6cScth static mpapi_item_list_t *vhci_mpapi_create_item(struct scsi_vhci *,
1281e1ddd6cScth     uint8_t, void *);
1299b4f248cSChris Liu static mpapi_item_list_t *vhci_mpapi_get_alua_item(struct scsi_vhci *,
1309b4f248cSChris Liu     void *, void *, void *);
1311e1ddd6cScth static mpapi_item_list_t *vhci_mpapi_get_tpg_item(struct scsi_vhci *,
1321e1ddd6cScth     uint32_t, void *, char *, void *);
1331e1ddd6cScth static mpapi_list_header_t *vhci_mpapi_create_list_head();
1341e1ddd6cScth static int vhci_get_mpiocdata(const void *, mp_iocdata_t *, int);
1351e1ddd6cScth static int vhci_is_model_type32(int);
1361e1ddd6cScth static int vhci_mpapi_copyout_iocdata(void *, void *, int);
1371e1ddd6cScth static int vhci_mpapi_chk_last_path(mdi_pathinfo_t *);
1381e1ddd6cScth static int vhci_mpapi_sync_lu_oid_list(struct scsi_vhci *);
13917d71211SJiri Svoboda static void vhci_mpapi_set_lu_valid(struct scsi_vhci *, mpapi_item_t *, int);
14017d71211SJiri Svoboda static void vhci_mpapi_set_tpg_as_prop(struct scsi_vhci *, mpapi_item_t *,
14117d71211SJiri Svoboda     uint32_t);
1421e1ddd6cScth static mpapi_item_list_t *vhci_mpapi_get_tpg_for_lun(struct scsi_vhci *,
1431e1ddd6cScth     char *, void *, void *);
1441e1ddd6cScth static int vhci_mpapi_check_tp_in_tpg(mpapi_tpg_data_t *tpgdata, void *tp);
1451e1ddd6cScth static void vhci_mpapi_log_sysevent(dev_info_t *, uint64_t *, char *);
1461e1ddd6cScth static mpapi_item_list_t *vhci_mpapi_match_pip(struct scsi_vhci *,
1471e1ddd6cScth     mpapi_item_list_t *, void *);
1481e1ddd6cScth static mpapi_item_list_t *vhci_mpapi_match_lu(struct scsi_vhci *,
1491e1ddd6cScth     mpapi_item_list_t *, void *);
1501e1ddd6cScth static void *vhci_mpapi_get_rel_tport_pair(struct scsi_vhci *vhci,
1511e1ddd6cScth     mpapi_list_header_t *list, void *tgt_port, uint32_t rel_tid);
1521e1ddd6cScth 
1531e1ddd6cScth /*
1541e1ddd6cScth  * Extern variables, structures and functions
1551e1ddd6cScth  */
1561e1ddd6cScth extern void	*vhci_softstate;
1571e1ddd6cScth extern char	vhci_version_name[];
1580205780bSrralphs extern int vhci_tpgs_set_target_groups(struct scsi_address *, int, int);
1590205780bSrralphs 
1601e1ddd6cScth 
1611e1ddd6cScth extern void mdi_vhci_walk_phcis(dev_info_t *,
1621e1ddd6cScth     int (*)(dev_info_t *, void *), void *);
1631e1ddd6cScth extern void vhci_update_pathstates(void *);
1641e1ddd6cScth extern int vhci_uscsi_iostart(struct buf *bp);
1651e1ddd6cScth 
1661e1ddd6cScth /*
1671e1ddd6cScth  * Routine for SCSI VHCI MPAPI IOCTL implementation.
1681e1ddd6cScth  */
1691e1ddd6cScth /* ARGSUSED */
1701e1ddd6cScth int
vhci_mpapi_ctl(dev_t dev,int cm,intptr_t data,int mode,cred_t * credp,int * rval)1711e1ddd6cScth vhci_mpapi_ctl(dev_t dev, int cm, intptr_t data, int mode,
1721e1ddd6cScth     cred_t *credp, int *rval)
1731e1ddd6cScth {
1741e1ddd6cScth 	struct scsi_vhci		*vhci;
1751e1ddd6cScth 	dev_info_t			*vdip;
1761e1ddd6cScth 	int				retval = 0;
1771e1ddd6cScth 	mp_iocdata_t			mpio_blk;
1781e1ddd6cScth 	mp_iocdata_t			*mpioc = &mpio_blk;
1791e1ddd6cScth 
1801e1ddd6cScth 	/* Check for validity of vhci structure */
1811e1ddd6cScth 	vhci = ddi_get_soft_state(vhci_softstate, MINOR2INST(getminor(dev)));
1821e1ddd6cScth 	if (vhci == NULL) {
1831e1ddd6cScth 		return (ENXIO);
1841e1ddd6cScth 	}
1851e1ddd6cScth 
1861e1ddd6cScth 	mutex_enter(&vhci->vhci_mutex);
1871e1ddd6cScth 	if ((vhci->vhci_state & VHCI_STATE_OPEN) == 0) {
1881e1ddd6cScth 		mutex_exit(&vhci->vhci_mutex);
1891e1ddd6cScth 		return (ENXIO);
1901e1ddd6cScth 	}
1911e1ddd6cScth 	mutex_exit(&vhci->vhci_mutex);
1921e1ddd6cScth 
1931e1ddd6cScth 	/* Get the vhci dip */
1941e1ddd6cScth 	vdip = vhci->vhci_dip;
1951e1ddd6cScth 	ASSERT(vdip != NULL);
1961e1ddd6cScth 
1971e1ddd6cScth 	/*
1981e1ddd6cScth 	 * Get IOCTL parameters from userland
1991e1ddd6cScth 	 */
2001e1ddd6cScth 	if (vhci_get_mpiocdata((const void *)data, mpioc, mode) != 0) {
2011e1ddd6cScth 		VHCI_DEBUG(1, (CE_WARN, NULL, "!vhci_mpapi_ctl: "
2021e1ddd6cScth 		    "vhci_get_mpiocdata() failed"));
2031e1ddd6cScth 	}
2041e1ddd6cScth 	if (mpioc->mp_cmd < MP_API_SUBCMD_MIN ||
2051e1ddd6cScth 	    mpioc->mp_cmd > MP_API_SUBCMD_MAX) {
2061e1ddd6cScth 		return (ENXIO);
2071e1ddd6cScth 	}
2081e1ddd6cScth 
2091e1ddd6cScth 	retval = vhci_mpapi_ioctl(dev, vhci, (void *)data, mpioc, mode, credp);
2101e1ddd6cScth 
2111e1ddd6cScth 	return (retval);
2121e1ddd6cScth }
2131e1ddd6cScth 
2141e1ddd6cScth /* ARGSUSED */
2151e1ddd6cScth static int
vhci_mpapi_validate(void * udata,mp_iocdata_t * mpioc,int mode,cred_t * credp)2161e1ddd6cScth vhci_mpapi_validate(void *udata, mp_iocdata_t *mpioc, int mode, cred_t *credp)
2171e1ddd6cScth {
2181e1ddd6cScth 	int		rval = 0, olen = 0;
2191e1ddd6cScth 	int		mode32 = 0;
2201e1ddd6cScth 
2211e1ddd6cScth 	if (vhci_is_model_type32(mode) == 1) {
2221e1ddd6cScth 		mode32 = 1;
2231e1ddd6cScth 	}
2241e1ddd6cScth 
2251e1ddd6cScth 	switch (mpioc->mp_cmd) {
2261e1ddd6cScth 
2271e1ddd6cScth 	case MP_GET_DEV_PROD_LIST:
2281e1ddd6cScth 	case MP_GET_LU_LIST: /* XXX: This wont come; Plugin already has it */
2291e1ddd6cScth 	case MP_GET_INIT_PORT_LIST: /* XXX: This call wont come either */
2301e1ddd6cScth 	case MP_GET_TPG_LIST:
2311e1ddd6cScth 	case MP_GET_PROPRIETARY_LOADBALANCE_LIST:
2321e1ddd6cScth 	{
2331e1ddd6cScth 		if ((mpioc->mp_olen == 0) ||
2341e1ddd6cScth 		    (mpioc->mp_obuf == NULL) ||
2351e1ddd6cScth 		    (mpioc->mp_xfer != MP_XFER_READ)) {
2361e1ddd6cScth 			rval = EINVAL;
2371e1ddd6cScth 		}
2381e1ddd6cScth 		if (mpioc->mp_olen == 0) {
2391e1ddd6cScth 			/* We don't know alen yet, No point trying to set it */
2401e1ddd6cScth 			mpioc->mp_errno = MP_MORE_DATA;
2411e1ddd6cScth 			rval = MP_MORE_DATA;
2421e1ddd6cScth 		}
2431e1ddd6cScth 	}
2441e1ddd6cScth 	break;
2451e1ddd6cScth 
2461e1ddd6cScth 	case MP_GET_DRIVER_PROP:
2471e1ddd6cScth 	{
2481e1ddd6cScth 		olen = sizeof (mp_driver_prop_t);
2491e1ddd6cScth 
2501e1ddd6cScth 		if ((mpioc->mp_obuf == NULL) ||
2511e1ddd6cScth 		    (mpioc->mp_olen < olen) ||
2521e1ddd6cScth 		    (mpioc->mp_xfer != MP_XFER_READ)) {
2531e1ddd6cScth 			rval = EINVAL;
2541e1ddd6cScth 		}
2551e1ddd6cScth 		if (mpioc->mp_olen < olen) {
2561e1ddd6cScth 			mpioc->mp_alen = olen;
2571e1ddd6cScth 			mpioc->mp_errno = MP_MORE_DATA;
2581e1ddd6cScth 		}
2591e1ddd6cScth 	}
2601e1ddd6cScth 	break;
2611e1ddd6cScth 
2621e1ddd6cScth 	case MP_GET_DEV_PROD_PROP:
2631e1ddd6cScth 	{
2641e1ddd6cScth 		olen = sizeof (mp_dev_prod_prop_t);
2651e1ddd6cScth 
2661e1ddd6cScth 		if ((mpioc->mp_olen < olen) ||
2671e1ddd6cScth 		    (mpioc->mp_ilen < sizeof (uint64_t)) ||
2681e1ddd6cScth 		    (mpioc->mp_obuf == NULL) ||
2691e1ddd6cScth 		    (mpioc->mp_ibuf == NULL) ||
2701e1ddd6cScth 		    (mpioc->mp_xfer != MP_XFER_READ)) {
2711e1ddd6cScth 			rval = EINVAL;
2721e1ddd6cScth 		}
2731e1ddd6cScth 		if (mpioc->mp_olen < olen) {
2741e1ddd6cScth 			mpioc->mp_alen = olen;
2751e1ddd6cScth 			mpioc->mp_errno = MP_MORE_DATA;
2761e1ddd6cScth 		}
2771e1ddd6cScth 	}
2781e1ddd6cScth 	break;
2791e1ddd6cScth 
2801e1ddd6cScth 	case MP_GET_LU_PROP:
2811e1ddd6cScth 	{
2821e1ddd6cScth 		olen = sizeof (mp_logical_unit_prop_t);
2831e1ddd6cScth 
2841e1ddd6cScth 		if ((mpioc->mp_ilen != sizeof (uint64_t)) ||
2851e1ddd6cScth 		    (mpioc->mp_ibuf == NULL) ||
2861e1ddd6cScth 		    (mpioc->mp_olen < olen) ||
2871e1ddd6cScth 		    (mpioc->mp_obuf == NULL) ||
2881e1ddd6cScth 		    (mpioc->mp_xfer != MP_XFER_READ)) {
2891e1ddd6cScth 			rval = EINVAL;
2901e1ddd6cScth 		}
2911e1ddd6cScth 		if (mpioc->mp_olen < olen) {
2921e1ddd6cScth 			mpioc->mp_alen = olen;
2931e1ddd6cScth 			mpioc->mp_errno = MP_MORE_DATA;
2941e1ddd6cScth 		}
2951e1ddd6cScth 	}
2961e1ddd6cScth 	break;
2971e1ddd6cScth 
2981e1ddd6cScth 	case MP_GET_PATH_PROP:
2991e1ddd6cScth 	{
3001e1ddd6cScth 		olen = sizeof (mp_path_prop_t);
3011e1ddd6cScth 
3021e1ddd6cScth 		if ((mpioc->mp_ilen != sizeof (uint64_t)) ||
3031e1ddd6cScth 		    (mpioc->mp_ibuf == NULL) ||
3041e1ddd6cScth 		    (mpioc->mp_olen < olen) ||
3051e1ddd6cScth 		    (mpioc->mp_obuf == NULL) ||
3061e1ddd6cScth 		    (mpioc->mp_xfer != MP_XFER_READ)) {
3071e1ddd6cScth 			rval = EINVAL;
3081e1ddd6cScth 		}
3091e1ddd6cScth 		if (mpioc->mp_olen < olen) {
3101e1ddd6cScth 			mpioc->mp_alen = olen;
3111e1ddd6cScth 			mpioc->mp_errno = MP_MORE_DATA;
3121e1ddd6cScth 		}
3131e1ddd6cScth 	}
3141e1ddd6cScth 	break;
3151e1ddd6cScth 
3161e1ddd6cScth 	case MP_GET_INIT_PORT_PROP:
3171e1ddd6cScth 	{
3181e1ddd6cScth 		olen = sizeof (mp_init_port_prop_t);
3191e1ddd6cScth 
3201e1ddd6cScth 		if ((mpioc->mp_ilen != sizeof (uint64_t)) ||
3211e1ddd6cScth 		    (mpioc->mp_ibuf == NULL) ||
3221e1ddd6cScth 		    (mpioc->mp_olen < olen) ||
3231e1ddd6cScth 		    (mpioc->mp_obuf == NULL) ||
3241e1ddd6cScth 		    (mpioc->mp_xfer != MP_XFER_READ)) {
3251e1ddd6cScth 			rval = EINVAL;
3261e1ddd6cScth 		}
3271e1ddd6cScth 		if (mpioc->mp_olen < olen) {
3281e1ddd6cScth 			mpioc->mp_alen = olen;
3291e1ddd6cScth 			mpioc->mp_errno = MP_MORE_DATA;
3301e1ddd6cScth 		}
3311e1ddd6cScth 	}
3321e1ddd6cScth 	break;
3331e1ddd6cScth 
3341e1ddd6cScth 	case MP_GET_TARGET_PORT_PROP:
3351e1ddd6cScth 	{
3361e1ddd6cScth 		olen = sizeof (mp_target_port_prop_t);
3371e1ddd6cScth 
3381e1ddd6cScth 		if ((mpioc->mp_ilen != sizeof (uint64_t)) ||
3391e1ddd6cScth 		    (mpioc->mp_ibuf == NULL) ||
3401e1ddd6cScth 		    (mpioc->mp_olen < olen) ||
3411e1ddd6cScth 		    (mpioc->mp_obuf == NULL) ||
3421e1ddd6cScth 		    (mpioc->mp_xfer != MP_XFER_READ)) {
3431e1ddd6cScth 			rval = EINVAL;
3441e1ddd6cScth 		}
3451e1ddd6cScth 		if (mpioc->mp_olen < olen) {
3461e1ddd6cScth 			mpioc->mp_alen = olen;
3471e1ddd6cScth 			mpioc->mp_errno = MP_MORE_DATA;
3481e1ddd6cScth 		}
3491e1ddd6cScth 	}
3501e1ddd6cScth 	break;
3511e1ddd6cScth 
3521e1ddd6cScth 	case MP_GET_TPG_PROP:
3531e1ddd6cScth 	{
3541e1ddd6cScth 		olen = sizeof (mp_tpg_prop_t);
3551e1ddd6cScth 
3561e1ddd6cScth 		if ((mpioc->mp_ilen != sizeof (uint64_t)) ||
3571e1ddd6cScth 		    (mpioc->mp_ibuf == NULL) ||
3581e1ddd6cScth 		    (mpioc->mp_olen < olen) ||
3591e1ddd6cScth 		    (mpioc->mp_obuf == NULL) ||
3601e1ddd6cScth 		    (mpioc->mp_xfer != MP_XFER_READ)) {
3611e1ddd6cScth 			rval = EINVAL;
3621e1ddd6cScth 		}
3631e1ddd6cScth 		if (mpioc->mp_olen < olen) {
3641e1ddd6cScth 			mpioc->mp_alen = olen;
3651e1ddd6cScth 			mpioc->mp_errno = MP_MORE_DATA;
3661e1ddd6cScth 		}
3671e1ddd6cScth 	}
3681e1ddd6cScth 	break;
3691e1ddd6cScth 
3701e1ddd6cScth 	case MP_GET_PROPRIETARY_LOADBALANCE_PROP:
3711e1ddd6cScth 	{
3721e1ddd6cScth 		olen = sizeof (mp_proprietary_loadbalance_prop_t);
3731e1ddd6cScth 
3741e1ddd6cScth 		if ((mpioc->mp_ilen != sizeof (uint64_t)) ||
3751e1ddd6cScth 		    (mpioc->mp_ibuf == NULL) ||
3761e1ddd6cScth 		    (mpioc->mp_olen < olen) ||
3771e1ddd6cScth 		    (mpioc->mp_obuf == NULL) ||
3781e1ddd6cScth 		    (mpioc->mp_xfer != MP_XFER_READ)) {
3791e1ddd6cScth 			rval = EINVAL;
3801e1ddd6cScth 		}
3811e1ddd6cScth 		if (mpioc->mp_olen < olen) {
3821e1ddd6cScth 			mpioc->mp_alen = olen;
3831e1ddd6cScth 			mpioc->mp_errno = MP_MORE_DATA;
3841e1ddd6cScth 		}
3851e1ddd6cScth 	}
3861e1ddd6cScth 	break;
3871e1ddd6cScth 
3881e1ddd6cScth 	case MP_GET_PATH_LIST_FOR_MP_LU:
3891e1ddd6cScth 	case MP_GET_PATH_LIST_FOR_INIT_PORT:
3901e1ddd6cScth 	case MP_GET_PATH_LIST_FOR_TARGET_PORT:
3911e1ddd6cScth 	case MP_GET_LU_LIST_FROM_TPG:
3921e1ddd6cScth 	case MP_GET_TPG_LIST_FOR_LU:
3931e1ddd6cScth 	case MP_GET_TARGET_PORT_LIST_FOR_TPG:
3941e1ddd6cScth 	{
3951e1ddd6cScth 		if ((mpioc->mp_ilen != sizeof (uint64_t)) ||
3961e1ddd6cScth 		    (mpioc->mp_ibuf == NULL) ||
3971e1ddd6cScth 		    (mpioc->mp_olen == 0) ||
3981e1ddd6cScth 		    (mpioc->mp_obuf == NULL) ||
3991e1ddd6cScth 		    (mpioc->mp_xfer != MP_XFER_READ)) {
4001e1ddd6cScth 			rval = EINVAL;
4011e1ddd6cScth 		}
4021e1ddd6cScth 		if (mpioc->mp_olen == 0) {
4031e1ddd6cScth 			/* We don't know alen yet, No point trying to set it */
4041e1ddd6cScth 			mpioc->mp_errno = MP_MORE_DATA;
4051e1ddd6cScth 			rval = MP_MORE_DATA;
4061e1ddd6cScth 		}
4071e1ddd6cScth 	}
4081e1ddd6cScth 	break;
4091e1ddd6cScth 
4101e1ddd6cScth 	case MP_SET_TPG_ACCESS_STATE:
4111e1ddd6cScth 	{
4121e1ddd6cScth 		if (drv_priv(credp) != 0) {
4131e1ddd6cScth 			rval = EPERM;
4141e1ddd6cScth 			break;
4151e1ddd6cScth 		}
4161e1ddd6cScth 		if ((mpioc->mp_ilen != sizeof (mp_set_tpg_state_req_t)) ||
4171e1ddd6cScth 		    (mpioc->mp_ibuf == NULL) ||
4181e1ddd6cScth 		    (mpioc->mp_xfer != MP_XFER_WRITE)) {
4191e1ddd6cScth 			rval = EINVAL;
4201e1ddd6cScth 		}
4211e1ddd6cScth 	}
4221e1ddd6cScth 	break;
4231e1ddd6cScth 
4241e1ddd6cScth 	case MP_ENABLE_AUTO_FAILBACK:
4251e1ddd6cScth 	case MP_DISABLE_AUTO_FAILBACK:
4261e1ddd6cScth 	{
4271e1ddd6cScth 		if (drv_priv(credp) != 0) {
4281e1ddd6cScth 			rval = EPERM;
4291e1ddd6cScth 			break;
4301e1ddd6cScth 		}
4311e1ddd6cScth 		if ((mpioc->mp_ibuf == NULL) ||
4321e1ddd6cScth 		    (mpioc->mp_xfer !=  MP_XFER_WRITE)) {
4331e1ddd6cScth 			rval = EINVAL;
4341e1ddd6cScth 		}
4351e1ddd6cScth 	}
4361e1ddd6cScth 	break;
4371e1ddd6cScth 
4381e1ddd6cScth 	case MP_ENABLE_PATH:
4391e1ddd6cScth 	case MP_DISABLE_PATH:
4401e1ddd6cScth 	{
4411e1ddd6cScth 		if (drv_priv(credp) != 0) {
4421e1ddd6cScth 			rval = EPERM;
4431e1ddd6cScth 			break;
4441e1ddd6cScth 		}
4451e1ddd6cScth 		if ((mpioc->mp_ilen != sizeof (uint64_t)) ||
4461e1ddd6cScth 		    (mpioc->mp_ibuf == NULL) ||
4471e1ddd6cScth 		    (mpioc->mp_xfer !=  MP_XFER_WRITE)) {
4481e1ddd6cScth 			rval = EINVAL;
4491e1ddd6cScth 		}
4501e1ddd6cScth 	}
4511e1ddd6cScth 	break;
4521e1ddd6cScth 
4531e1ddd6cScth 	case MP_SEND_SCSI_CMD:
4541e1ddd6cScth 	{
4551e1ddd6cScth 		cred_t	*cr;
4561e1ddd6cScth 		int	olen = 0;
4571e1ddd6cScth 
4581e1ddd6cScth 		cr = ddi_get_cred();
4591e1ddd6cScth 		if (drv_priv(credp) != 0 && drv_priv(cr) != 0) {
4601e1ddd6cScth 			rval = EPERM;
4611e1ddd6cScth 			break;
4621e1ddd6cScth 		}
4631e1ddd6cScth 		if (mode32 == 1) {
4641e1ddd6cScth 			olen = sizeof (struct uscsi_cmd32);
4651e1ddd6cScth 		} else {
4661e1ddd6cScth 			olen = sizeof (struct uscsi_cmd);
4671e1ddd6cScth 		}
4681e1ddd6cScth 		/* oid is in the ibuf and the uscsi cmd is in the obuf */
4691e1ddd6cScth 		if ((mpioc->mp_ilen != sizeof (uint64_t)) ||
4701e1ddd6cScth 		    (mpioc->mp_ibuf == NULL) ||
4711e1ddd6cScth 		    (mpioc->mp_olen != olen) ||
4721e1ddd6cScth 		    (mpioc->mp_obuf == NULL)) {
4731e1ddd6cScth 			rval = EINVAL;
4741e1ddd6cScth 		}
4751e1ddd6cScth 	}
4761e1ddd6cScth 	break;
4771e1ddd6cScth 
4781e1ddd6cScth 	case MP_ASSIGN_LU_TO_TPG:
4791e1ddd6cScth 	{
4801e1ddd6cScth 		if (drv_priv(credp) != 0) {
4811e1ddd6cScth 			rval = EPERM;
4821e1ddd6cScth 			break;
4831e1ddd6cScth 		}
4841e1ddd6cScth 		if ((mpioc->mp_ilen != sizeof (mp_lu_tpg_pair_t)) ||
4851e1ddd6cScth 		    (mpioc->mp_ibuf == NULL) ||
4861e1ddd6cScth 		    (mpioc->mp_xfer !=  MP_XFER_WRITE)) {
4871e1ddd6cScth 			rval = EINVAL;
4881e1ddd6cScth 		}
4891e1ddd6cScth 	}
4901e1ddd6cScth 	break;
4911e1ddd6cScth 
4921e1ddd6cScth 	default:
4931e1ddd6cScth 	{
4941e1ddd6cScth 		rval = EINVAL;
4951e1ddd6cScth 	}
4961e1ddd6cScth 
4971e1ddd6cScth 	} /* Closing the main switch */
4981e1ddd6cScth 
4991e1ddd6cScth 	return (rval);
5001e1ddd6cScth }
5011e1ddd6cScth 
5021e1ddd6cScth /* ARGSUSED */
5031e1ddd6cScth static int
vhci_get_driver_prop(struct scsi_vhci * vhci,mp_iocdata_t * mpioc,void * input_data,void * output_data,int mode)5041e1ddd6cScth vhci_get_driver_prop(struct scsi_vhci *vhci, mp_iocdata_t *mpioc,
5051e1ddd6cScth     void *input_data, void *output_data, int mode)
5061e1ddd6cScth {
5071e1ddd6cScth 	int			rval = 0;
5081e1ddd6cScth 	mp_driver_prop_t	*mpdp = (mp_driver_prop_t *)output_data;
5091e1ddd6cScth 
5101e1ddd6cScth 	if (output_data == NULL) {
5111e1ddd6cScth 		return (EINVAL);
5121e1ddd6cScth 	}
5131e1ddd6cScth 
5141e1ddd6cScth 	(void) strlcpy(mpdp->driverVersion, vhci_version_name,
5151e1ddd6cScth 	    sizeof (mpdp->driverVersion));
5161e1ddd6cScth 	mpdp->supportedLoadBalanceTypes =
5171e1ddd6cScth 	    MP_DRVR_LOAD_BALANCE_TYPE_NONE |
5181e1ddd6cScth 	    MP_DRVR_LOAD_BALANCE_TYPE_ROUNDROBIN |
5191e1ddd6cScth 	    MP_DRVR_LOAD_BALANCE_TYPE_LBA_REGION;
5201e1ddd6cScth 	mpdp->canSetTPGAccess = B_TRUE;
5211e1ddd6cScth 	mpdp->canOverridePaths = B_FALSE;
5221e1ddd6cScth 	mpdp->exposesPathDeviceFiles = B_FALSE;
5231e1ddd6cScth 	(void) strlcpy(mpdp->deviceFileNamespace, "/devices/scsi_vhci",
5241e1ddd6cScth 	    sizeof (mpdp->deviceFileNamespace));
5251e1ddd6cScth 	mpdp->onlySupportsSpecifiedProducts = 1;
5261e1ddd6cScth 	mpdp->maximumWeight = 1;
5271e1ddd6cScth 	mpdp->failbackPollingRateMax = 0;
5281e1ddd6cScth 	mpdp->currentFailbackPollingRate = 0;
5291e1ddd6cScth 	mpdp->autoFailbackSupport = MP_DRVR_AUTO_FAILBACK_SUPPORT;
5301e1ddd6cScth 	mutex_enter(&vhci->vhci_mutex);
5311e1ddd6cScth 	mpdp->autoFailbackEnabled =
5321e1ddd6cScth 	    ((vhci->vhci_conf_flags & VHCI_CONF_FLAGS_AUTO_FAILBACK) ?
5331e1ddd6cScth 	    1 : 0);
5341e1ddd6cScth 	mutex_exit(&vhci->vhci_mutex);
5351e1ddd6cScth 	mpdp->defaultLoadBalanceType =
5361e1ddd6cScth 	    MP_DRVR_LOAD_BALANCE_TYPE_ROUNDROBIN;
5371e1ddd6cScth 	mpdp->probingPollingRateMax = 0;
5381e1ddd6cScth 	mpdp->currentProbingPollingRate = 0;
5391e1ddd6cScth 	mpdp->autoProbingSupport = 0;
5401e1ddd6cScth 	mpdp->autoProbingEnabled = 0;
5411e1ddd6cScth 
5421e1ddd6cScth 	if (ddi_copyout(output_data, (void *)mpioc->mp_obuf,
5431e1ddd6cScth 	    mpioc->mp_olen, mode) != 0) {
5441e1ddd6cScth 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_get_driver_prop: "
5451e1ddd6cScth 		    "ddi_copyout() for 64-bit failed"));
5461e1ddd6cScth 		mpioc->mp_errno = EFAULT;
5471e1ddd6cScth 	} else {
5481e1ddd6cScth 		mpioc->mp_errno = 0;
5491e1ddd6cScth 		mpioc->mp_alen = sizeof (mp_iocdata_t);
5501e1ddd6cScth 	}
5511e1ddd6cScth 
5521e1ddd6cScth 	return (rval);
5531e1ddd6cScth }
5541e1ddd6cScth 
5551e1ddd6cScth /* ARGSUSED */
5561e1ddd6cScth static int
vhci_get_dev_prod_list(struct scsi_vhci * vhci,mp_iocdata_t * mpioc,void * input_data,void * output_data,int mode)5571e1ddd6cScth vhci_get_dev_prod_list(struct scsi_vhci *vhci, mp_iocdata_t *mpioc,
5581e1ddd6cScth     void *input_data, void *output_data, int mode)
5591e1ddd6cScth {
5601e1ddd6cScth 	int			count = 0, rval = 0;
5614e40636aSToomas Soome 	int			list_len = mpioc->mp_olen / sizeof (uint64_t);
5621e1ddd6cScth 	uint64_t		*oid_list = (uint64_t *)(output_data);
5631e1ddd6cScth 	mpapi_item_list_t	*ilist;
5641e1ddd6cScth 
5651e1ddd6cScth 	if (output_data == NULL) {
5661e1ddd6cScth 		return (EINVAL);
5671e1ddd6cScth 	}
5681e1ddd6cScth 
5691e1ddd6cScth 	/*
5701e1ddd6cScth 	 * XXX: Get the Plugin OID from the input_data and apply below
5711e1ddd6cScth 	 * Currently, we know we have only 1 plugin, so it ok to directly
5721e1ddd6cScth 	 * return this only plugin's device product list.
5731e1ddd6cScth 	 */
5741e1ddd6cScth 
5751e1ddd6cScth 	ilist = vhci->mp_priv->
5761e1ddd6cScth 	    obj_hdr_list[MP_OBJECT_TYPE_DEVICE_PRODUCT]->head;
5771e1ddd6cScth 
5781e1ddd6cScth 	while (ilist != NULL) {
5791e1ddd6cScth 		if (count < list_len) {
5801e1ddd6cScth 			oid_list[count] = (uint64_t)ilist->item->oid.raw_oid;
5811e1ddd6cScth 		} else {
5821e1ddd6cScth 			rval = MP_MORE_DATA;
5831e1ddd6cScth 		}
5841e1ddd6cScth 		ilist = ilist->next;
5851e1ddd6cScth 		count++;
5861e1ddd6cScth 	}
5871e1ddd6cScth 
5881e1ddd6cScth 	mpioc->mp_alen = (uint32_t)(count * sizeof (uint64_t));
5891e1ddd6cScth 	if ((rval == MP_MORE_DATA) || (mpioc->mp_alen > mpioc->mp_olen)) {
5901e1ddd6cScth 		mpioc->mp_errno = MP_MORE_DATA;
5911e1ddd6cScth 		return (EINVAL);
5921e1ddd6cScth 	}
5931e1ddd6cScth 
5941e1ddd6cScth 	if (ddi_copyout(output_data, (void *)mpioc->mp_obuf,
5951e1ddd6cScth 	    (count * sizeof (uint64_t)), mode) != 0) {
5961e1ddd6cScth 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_get_dev_prod_list: "
5971e1ddd6cScth 		    "ddi_copyout() failed"));
5981e1ddd6cScth 		mpioc->mp_errno = EFAULT;
5991e1ddd6cScth 		rval = EINVAL;
6001e1ddd6cScth 	} else {
6011e1ddd6cScth 		mpioc->mp_errno = 0;
6021e1ddd6cScth 	}
6031e1ddd6cScth 
6041e1ddd6cScth 	return (rval);
6051e1ddd6cScth }
6061e1ddd6cScth 
6071e1ddd6cScth /* ARGSUSED */
6081e1ddd6cScth static int
vhci_get_dev_prod_prop(struct scsi_vhci * vhci,mp_iocdata_t * mpioc,void * input_data,void * output_data,int mode)6091e1ddd6cScth vhci_get_dev_prod_prop(struct scsi_vhci *vhci, mp_iocdata_t *mpioc,
6101e1ddd6cScth     void *input_data, void *output_data, int mode)
6111e1ddd6cScth {
6121e1ddd6cScth 	int			rval = 0;
6131e1ddd6cScth 	uint64_t		*oid = (uint64_t *)(input_data);
6141e1ddd6cScth 	mp_dev_prod_prop_t	*dev_prop = NULL;
6151e1ddd6cScth 	mpapi_item_list_t	*ilist;
6161e1ddd6cScth 
6171e1ddd6cScth 	if ((output_data == NULL) || (input_data == NULL)) {
6181e1ddd6cScth 		return (EINVAL);
6191e1ddd6cScth 	}
6201e1ddd6cScth 	ilist = vhci->mp_priv->
6211e1ddd6cScth 	    obj_hdr_list[MP_OBJECT_TYPE_DEVICE_PRODUCT]->head;
6221e1ddd6cScth 	while ((ilist != NULL) && (*oid != ilist->item->oid.raw_oid)) {
6231e1ddd6cScth 		ilist = ilist->next;
6241e1ddd6cScth 	}
6251e1ddd6cScth 	if (ilist != NULL) {
6261e1ddd6cScth 		dev_prop = (mp_dev_prod_prop_t *)(ilist->item->idata);
6271e1ddd6cScth 		if (dev_prop == NULL) {
6281e1ddd6cScth 			return (EINVAL);
6291e1ddd6cScth 		}
6301e1ddd6cScth 	} else {
6311e1ddd6cScth 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_get_dev_prod_prop: "
6321e1ddd6cScth 		    "OID NOT FOUND"));
6331e1ddd6cScth 		mpioc->mp_errno = MP_DRVR_INVALID_ID;
6341e1ddd6cScth 		return (EINVAL);
6351e1ddd6cScth 	}
6361e1ddd6cScth 	/*
6371e1ddd6cScth 	 * Here were are not using the 'output_data' that is
6381e1ddd6cScth 	 * passed as the required information is already
6391e1ddd6cScth 	 * in the required format!
6401e1ddd6cScth 	 */
6411e1ddd6cScth 	if (ddi_copyout((void *)dev_prop, mpioc->mp_obuf,
6421e1ddd6cScth 	    sizeof (mp_dev_prod_prop_t), mode) != 0) {
6431e1ddd6cScth 		return (EFAULT);
6441e1ddd6cScth 	}
6451e1ddd6cScth 	return (rval);
6461e1ddd6cScth }
6471e1ddd6cScth 
6481e1ddd6cScth /* ARGSUSED */
6491e1ddd6cScth static int
vhci_get_lu_list(struct scsi_vhci * vhci,mp_iocdata_t * mpioc,void * input_data,void * output_data,int mode)6501e1ddd6cScth vhci_get_lu_list(struct scsi_vhci *vhci, mp_iocdata_t *mpioc,
6511e1ddd6cScth     void *input_data, void *output_data, int mode)
6521e1ddd6cScth {
6531e1ddd6cScth 	int			count = 0, rval = 0;
6544e40636aSToomas Soome 	int			list_len = mpioc->mp_olen / sizeof (uint64_t);
6551e1ddd6cScth 	uint64_t		*oid_list = (uint64_t *)(output_data);
6561e1ddd6cScth 	mpapi_item_list_t	*ilist;
6571e1ddd6cScth 	mpapi_lu_data_t		*ld;
6581e1ddd6cScth 
6591e1ddd6cScth 	if (output_data == NULL) {
6601e1ddd6cScth 		return (EINVAL);
6611e1ddd6cScth 	}
6621e1ddd6cScth 
6631e1ddd6cScth 	ilist = vhci->mp_priv->obj_hdr_list[MP_OBJECT_TYPE_MULTIPATH_LU]->head;
6641e1ddd6cScth 
6651e1ddd6cScth 	while (ilist != NULL) {
6661e1ddd6cScth 		if (count < list_len) {
6671e1ddd6cScth 			oid_list[count] = (uint64_t)(ilist->item->oid.raw_oid);
6681e1ddd6cScth 		} else {
6691e1ddd6cScth 			rval = MP_MORE_DATA;
6701e1ddd6cScth 		}
6711e1ddd6cScth 		ld = ilist->item->idata;
6721e1ddd6cScth 		if (ld->valid == 0) {
6731e1ddd6cScth 			count--;
6741e1ddd6cScth 		}
6751e1ddd6cScth 		ilist = ilist->next;
6761e1ddd6cScth 		count++;
6771e1ddd6cScth 	}
6781e1ddd6cScth 
6791e1ddd6cScth 	mpioc->mp_alen = (uint32_t)(count * sizeof (uint64_t));
6801e1ddd6cScth 	if ((rval == MP_MORE_DATA) || (mpioc->mp_alen > mpioc->mp_olen)) {
6811e1ddd6cScth 		mpioc->mp_errno = MP_MORE_DATA;
6821e1ddd6cScth 		return (EINVAL);
6831e1ddd6cScth 	}
6841e1ddd6cScth 
6851e1ddd6cScth 	if (ddi_copyout(output_data, (void *)mpioc->mp_obuf,
6861e1ddd6cScth 	    (count * sizeof (uint64_t)), mode) != 0) {
6871e1ddd6cScth 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_get_lu_list: "
6881e1ddd6cScth 		    "ddi_copyout() FAILED"));
6891e1ddd6cScth 		mpioc->mp_errno = EFAULT;
6901e1ddd6cScth 		rval = EINVAL;
6911e1ddd6cScth 	} else {
6921e1ddd6cScth 		mpioc->mp_errno = 0;
6931e1ddd6cScth 	}
6941e1ddd6cScth 
6951e1ddd6cScth 	return (rval);
6961e1ddd6cScth }
6971e1ddd6cScth 
6981e1ddd6cScth /* ARGSUSED */
6991e1ddd6cScth static int
vhci_get_lu_list_from_tpg(struct scsi_vhci * vhci,mp_iocdata_t * mpioc,void * input_data,void * output_data,int mode)7001e1ddd6cScth vhci_get_lu_list_from_tpg(struct scsi_vhci *vhci, mp_iocdata_t *mpioc,
7011e1ddd6cScth     void *input_data, void *output_data, int mode)
7021e1ddd6cScth {
7031e1ddd6cScth 	int			count = 0, rval = 0;
7044e40636aSToomas Soome 	int			list_len = mpioc->mp_olen / sizeof (uint64_t);
7051e1ddd6cScth 	uint64_t		*oid_list = (uint64_t *)(output_data);
7061e1ddd6cScth 	uint64_t		*oid = (uint64_t *)(input_data);
7071e1ddd6cScth 	mpapi_item_list_t	*ilist, *tpg_lu_list = NULL;
7081e1ddd6cScth 	mpapi_tpg_data_t	*mptpglu;
7091e1ddd6cScth 	mpapi_lu_data_t		*ld;
7101e1ddd6cScth 
7111e1ddd6cScth 	ilist = vhci->mp_priv->obj_hdr_list[MP_OBJECT_TYPE_TARGET_PORT_GROUP]
7121e1ddd6cScth 	    ->head;
7131e1ddd6cScth 
7141e1ddd6cScth 	while ((ilist != NULL) && (*oid != ilist->item->oid.raw_oid))
7151e1ddd6cScth 		ilist = ilist->next;
7161e1ddd6cScth 
7171e1ddd6cScth 	if (ilist == NULL) {
7181e1ddd6cScth 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_get_lu_list_from_tpg: "
7191e1ddd6cScth 		    "OID NOT FOUND"));
7201e1ddd6cScth 		mpioc->mp_errno = MP_DRVR_INVALID_ID;
7211e1ddd6cScth 		rval = EINVAL;
7221e1ddd6cScth 	} else if (*oid == ilist->item->oid.raw_oid) {
7231e1ddd6cScth 		mptpglu = (mpapi_tpg_data_t *)(ilist->item->idata);
7241e1ddd6cScth 		if (mptpglu->valid == 0) {
7251e1ddd6cScth 			VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_get_lu_list_from_"
7261e1ddd6cScth 			    "tpg: OID NOT FOUND - TPG IS INVALID"));
7271e1ddd6cScth 			mpioc->mp_errno = MP_DRVR_INVALID_ID;
7281e1ddd6cScth 			return (EINVAL);
7291e1ddd6cScth 		}
7301e1ddd6cScth 		tpg_lu_list = mptpglu->lu_list->head;
7311e1ddd6cScth 	} else {
7321e1ddd6cScth 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_get_lu_list_from_tpg: "
7331e1ddd6cScth 		    "Unknown Error"));
7341e1ddd6cScth 	}
7351e1ddd6cScth 
7361e1ddd6cScth 	while (tpg_lu_list != NULL) {
7371e1ddd6cScth 		if (count < list_len) {
7381e1ddd6cScth 			oid_list[count] = (uint64_t)tpg_lu_list->
7391e1ddd6cScth 			    item->oid.raw_oid;
7401e1ddd6cScth 		} else {
7411e1ddd6cScth 			rval = MP_MORE_DATA;
7421e1ddd6cScth 		}
7431e1ddd6cScth 		/*
7441e1ddd6cScth 		 * Get rid of the latest entry if item is invalid
7451e1ddd6cScth 		 */
7461e1ddd6cScth 		ld = tpg_lu_list->item->idata;
7471e1ddd6cScth 		if (ld->valid == 0) {
7481e1ddd6cScth 			count--;
7491e1ddd6cScth 		}
7501e1ddd6cScth 		tpg_lu_list = tpg_lu_list->next;
7511e1ddd6cScth 		count++;
7521e1ddd6cScth 	}
7531e1ddd6cScth 
7541e1ddd6cScth 	mpioc->mp_alen = (uint32_t)(count * sizeof (uint64_t));
7551e1ddd6cScth 	if ((rval == MP_MORE_DATA) || (mpioc->mp_alen > mpioc->mp_olen)) {
7561e1ddd6cScth 		mpioc->mp_errno = MP_MORE_DATA;
7571e1ddd6cScth 		return (EINVAL);
7581e1ddd6cScth 	}
7591e1ddd6cScth 
7601e1ddd6cScth 	if ((count > 0) && (ddi_copyout(output_data, (void *)mpioc->mp_obuf,
7611e1ddd6cScth 	    (count * sizeof (uint64_t)), mode) != 0)) {
7621e1ddd6cScth 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_get_lu_list_from_tpg: "
7631e1ddd6cScth 		    "ddi_copyout() FAILED"));
7641e1ddd6cScth 		mpioc->mp_errno = EFAULT;
7651e1ddd6cScth 		rval = EINVAL;
7661e1ddd6cScth 	}
7671e1ddd6cScth 
7681e1ddd6cScth 	return (rval);
7691e1ddd6cScth }
7701e1ddd6cScth 
7711e1ddd6cScth /* ARGSUSED */
7721e1ddd6cScth static int
vhci_get_tpg_list_for_lu(struct scsi_vhci * vhci,mp_iocdata_t * mpioc,void * input_data,void * output_data,int mode)7731e1ddd6cScth vhci_get_tpg_list_for_lu(struct scsi_vhci *vhci, mp_iocdata_t *mpioc,
7741e1ddd6cScth     void *input_data, void *output_data, int mode)
7751e1ddd6cScth {
7761e1ddd6cScth 	int			count = 0, rval = 0;
7774e40636aSToomas Soome 	int			list_len = mpioc->mp_olen / sizeof (uint64_t);
7781e1ddd6cScth 	uint64_t		*oid_list = (uint64_t *)(output_data);
7791e1ddd6cScth 	uint64_t		*oid = (uint64_t *)(input_data);
7801e1ddd6cScth 	mpapi_item_list_t	*ilist, *mplu_tpg_list = NULL;
7811e1ddd6cScth 	mpapi_lu_data_t		*mplutpg;
7821e1ddd6cScth 	mpapi_tpg_data_t	*tpgd;
7831e1ddd6cScth 
7841e1ddd6cScth 	ilist = vhci->mp_priv->obj_hdr_list[MP_OBJECT_TYPE_MULTIPATH_LU]->head;
7851e1ddd6cScth 
7861e1ddd6cScth 	while ((ilist != NULL) && (*oid != ilist->item->oid.raw_oid))
7871e1ddd6cScth 		ilist = ilist->next;
7881e1ddd6cScth 
7891e1ddd6cScth 	if (ilist == NULL) {
7901e1ddd6cScth 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_get_tpg_list_for_lu: "
7911e1ddd6cScth 		    "OID NOT FOUND"));
7921e1ddd6cScth 		mpioc->mp_errno = MP_DRVR_INVALID_ID;
7931e1ddd6cScth 		rval = EINVAL;
7941e1ddd6cScth 	} else if (*oid == ilist->item->oid.raw_oid) {
7951e1ddd6cScth 		mplutpg = (mpapi_lu_data_t *)(ilist->item->idata);
7961e1ddd6cScth 		if (mplutpg->valid == 0) {
7971e1ddd6cScth 			VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_get_tpg_list_for_"
7981e1ddd6cScth 			    "lu: OID NOT FOUND - LU IS OFFLINE"));
7991e1ddd6cScth 			mpioc->mp_errno = MP_DRVR_INVALID_ID;
8001e1ddd6cScth 			return (EINVAL);
8011e1ddd6cScth 		}
8021e1ddd6cScth 		mplu_tpg_list = mplutpg->tpg_list->head;
8031e1ddd6cScth 	} else {
8041e1ddd6cScth 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_get_tpg_list_for_lu: "
8051e1ddd6cScth 		    "Unknown Error"));
8061e1ddd6cScth 	}
8071e1ddd6cScth 
8081e1ddd6cScth 	while (mplu_tpg_list != NULL) {
8091e1ddd6cScth 		if (count < list_len) {
8101e1ddd6cScth 			oid_list[count] =
8111e1ddd6cScth 			    (uint64_t)mplu_tpg_list->item->oid.raw_oid;
8121e1ddd6cScth 		} else {
8131e1ddd6cScth 			rval = MP_MORE_DATA;
8141e1ddd6cScth 		}
8151e1ddd6cScth 		tpgd = mplu_tpg_list->item->idata;
8161e1ddd6cScth 		if (tpgd->valid == 0) {
8171e1ddd6cScth 			count--;
8181e1ddd6cScth 		}
8191e1ddd6cScth 		mplu_tpg_list = mplu_tpg_list->next;
8201e1ddd6cScth 		count++;
8211e1ddd6cScth 	}
8221e1ddd6cScth 
8231e1ddd6cScth 	mpioc->mp_alen = (uint32_t)(count * sizeof (uint64_t));
8241e1ddd6cScth 	if ((rval == MP_MORE_DATA) || (mpioc->mp_alen > mpioc->mp_olen)) {
8251e1ddd6cScth 		mpioc->mp_errno = MP_MORE_DATA;
8261e1ddd6cScth 		return (EINVAL);
8271e1ddd6cScth 	}
8281e1ddd6cScth 
8291e1ddd6cScth 	if ((count > 0) && (ddi_copyout(output_data, (void *)mpioc->mp_obuf,
8301e1ddd6cScth 	    (count * sizeof (uint64_t)), mode) != 0)) {
8311e1ddd6cScth 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_get_tpg_list_for_lu: "
8321e1ddd6cScth 		    "ddi_copyout() FAILED"));
8331e1ddd6cScth 		mpioc->mp_errno = EFAULT;
8341e1ddd6cScth 		rval = EINVAL;
8351e1ddd6cScth 	}
8361e1ddd6cScth 
8371e1ddd6cScth 	return (rval);
8381e1ddd6cScth }
8391e1ddd6cScth 
8401e1ddd6cScth /* ARGSUSED */
8411e1ddd6cScth static int
vhci_get_lu_prop(struct scsi_vhci * vhci,mp_iocdata_t * mpioc,void * input_data,void * output_data,int mode)8421e1ddd6cScth vhci_get_lu_prop(struct scsi_vhci *vhci, mp_iocdata_t *mpioc,
8431e1ddd6cScth     void *input_data, void *output_data, int mode)
8441e1ddd6cScth {
8451e1ddd6cScth 	int			rval = 0;
8461e1ddd6cScth 	uint64_t		*oid = (uint64_t *)(input_data);
8471e1ddd6cScth 	mp_logical_unit_prop_t	*mplup_prop;
8481e1ddd6cScth 	mpapi_item_list_t	*ilist;
8491e1ddd6cScth 	mpapi_lu_data_t		*mplup;
8501e1ddd6cScth 
8511e1ddd6cScth 	mplup_prop = (mp_logical_unit_prop_t *)output_data;
8521e1ddd6cScth 	ilist = vhci->mp_priv->obj_hdr_list[MP_OBJECT_TYPE_MULTIPATH_LU]->head;
8531e1ddd6cScth 
8541e1ddd6cScth 	while ((ilist != NULL) && (*oid != ilist->item->oid.raw_oid)) {
8551e1ddd6cScth 		ilist = ilist->next;
8561e1ddd6cScth 	}
8571e1ddd6cScth 
8581e1ddd6cScth 	if (ilist != NULL) {
8591e1ddd6cScth 		mplup = (mpapi_lu_data_t *)(ilist->item->idata);
8601e1ddd6cScth 		if (mplup == NULL) {
8611e1ddd6cScth 			VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_get_lu_prop: "
8621e1ddd6cScth 			    "idata in ilist is NULL"));
8631e1ddd6cScth 			return (EINVAL);
8641e1ddd6cScth 		} else if (mplup->valid == 0) {
8651e1ddd6cScth 			VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_get_lu_prop: "
8661e1ddd6cScth 			    "OID NOT FOUND - LU GONE OFFLINE"));
8671e1ddd6cScth 			mpioc->mp_errno = MP_DRVR_INVALID_ID;
8681e1ddd6cScth 			return (EINVAL);
8691e1ddd6cScth 		}
8701e1ddd6cScth 		mplup_prop = (mp_logical_unit_prop_t *)(&mplup->prop);
8711e1ddd6cScth 	} else {
8721e1ddd6cScth 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_get_lu_prop: "
8731e1ddd6cScth 		    "OID NOT FOUND"));
8741e1ddd6cScth 		mpioc->mp_errno = MP_DRVR_INVALID_ID;
8751e1ddd6cScth 		return (EINVAL);
8761e1ddd6cScth 	}
8771e1ddd6cScth 
8781e1ddd6cScth 	/*
8791e1ddd6cScth 	 * Here were are not using the 'output_data' that is
8801e1ddd6cScth 	 * passed as the required information is already
8811e1ddd6cScth 	 * in the required format!
8821e1ddd6cScth 	 */
8831e1ddd6cScth 	if (ddi_copyout((void *)mplup_prop, mpioc->mp_obuf,
8841e1ddd6cScth 	    sizeof (mp_logical_unit_prop_t), mode) != 0) {
8851e1ddd6cScth 		return (EFAULT);
8861e1ddd6cScth 	}
8871e1ddd6cScth 	return (rval);
8881e1ddd6cScth }
8891e1ddd6cScth 
8901e1ddd6cScth /* ARGSUSED */
8911e1ddd6cScth static int
vhci_get_path_list_for_mp_lu(struct scsi_vhci * vhci,mp_iocdata_t * mpioc,void * input_data,void * output_data,int mode)8921e1ddd6cScth vhci_get_path_list_for_mp_lu(struct scsi_vhci *vhci, mp_iocdata_t *mpioc,
8931e1ddd6cScth     void *input_data, void *output_data, int mode)
8941e1ddd6cScth {
8951e1ddd6cScth 	int			count = 0, rval = 0;
8964e40636aSToomas Soome 	int			list_len = mpioc->mp_olen / sizeof (uint64_t);
8971e1ddd6cScth 	uint64_t		*oid_list = (uint64_t *)(output_data);
8981e1ddd6cScth 	uint64_t		*oid = (uint64_t *)(input_data);
8991e1ddd6cScth 	mpapi_item_list_t	*ilist, *mplu_path_list = NULL;
9001e1ddd6cScth 	mpapi_lu_data_t		*mplup;
9014c06356bSdh 	mpapi_path_data_t	*mppathp;
9024c06356bSdh 	mdi_pathinfo_t		*pip;
9031e1ddd6cScth 
9041e1ddd6cScth 	ilist = vhci->mp_priv->obj_hdr_list[MP_OBJECT_TYPE_MULTIPATH_LU]->head;
9051e1ddd6cScth 
9061e1ddd6cScth 	while ((ilist != NULL) && (*oid != ilist->item->oid.raw_oid))
9071e1ddd6cScth 		ilist = ilist->next;
9081e1ddd6cScth 
9091e1ddd6cScth 	if (ilist == NULL) {
9101e1ddd6cScth 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_get_path_list_for_mp_lu: "
9111e1ddd6cScth 		    "OID NOT FOUND"));
9121e1ddd6cScth 		mpioc->mp_errno = MP_DRVR_INVALID_ID;
9131e1ddd6cScth 		rval = EINVAL;
9141e1ddd6cScth 	} else if (*oid == ilist->item->oid.raw_oid) {
9151e1ddd6cScth 		mplup = (mpapi_lu_data_t *)(ilist->item->idata);
9161e1ddd6cScth 		if (mplup->valid == 0) {
9171e1ddd6cScth 			VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_get_path_list_for_"
9181e1ddd6cScth 			    "mp_lu: MP_DRVR_PATH_STATE_LU_ERR - LU OFFLINE"));
9191e1ddd6cScth 			mpioc->mp_errno = MP_DRVR_PATH_STATE_LU_ERR;
9201e1ddd6cScth 			return (EINVAL);
9211e1ddd6cScth 		}
9221e1ddd6cScth 		mplu_path_list = mplup->path_list->head;
9231e1ddd6cScth 	} else {
9241e1ddd6cScth 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_get_path_list_for_mp_lu: "
9251e1ddd6cScth 		    "Unknown Error"));
9261e1ddd6cScth 	}
9271e1ddd6cScth 
9281e1ddd6cScth 	while (mplu_path_list != NULL) {
9294c06356bSdh 		mppathp  = (mpapi_path_data_t *)(mplu_path_list->item->idata);
9304c06356bSdh 		/* skip a path that should be hidden. */
93129bb6f10SVictor Li 		if (!(mppathp->hide) && (mppathp->valid != 0)) {
9324c06356bSdh 			pip = (mdi_pathinfo_t *)mppathp->resp;
9334c06356bSdh 			mdi_hold_path(pip);
9344c06356bSdh 			/*
9354c06356bSdh 			 * check if the pip is marked as device removed.
9364c06356bSdh 			 * When pi_flag MDI_PATHINFO_FLAGS_DEVICE_REMOVED is set
9374c06356bSdh 			 * the node should have been destroyed but did not
9384c06356bSdh 			 * due to open on the client node.
9394c06356bSdh 			 * The driver tracks such a node through the hide flag
9404c06356bSdh 			 * and doesn't report it throuth ioctl response.
9414c06356bSdh 			 * The devinfo driver doesn't report such a path.
9424c06356bSdh 			 */
9434c06356bSdh 			if (!(MDI_PI_FLAGS_IS_DEVICE_REMOVED(pip))) {
9444c06356bSdh 				if (count < list_len) {
9454c06356bSdh 					oid_list[count] =
9464c06356bSdh 					    (uint64_t)mplu_path_list->
9474c06356bSdh 					    item->oid.raw_oid;
9484c06356bSdh 				} else {
9494c06356bSdh 					rval = MP_MORE_DATA;
9504c06356bSdh 				}
9514c06356bSdh 				count++;
9524c06356bSdh 			}
9534c06356bSdh 			mdi_rele_path(pip);
9541e1ddd6cScth 		}
9551e1ddd6cScth 		mplu_path_list = mplu_path_list->next;
9561e1ddd6cScth 	}
9571e1ddd6cScth 
9581e1ddd6cScth 	mpioc->mp_alen = (uint32_t)(count * sizeof (uint64_t));
9591e1ddd6cScth 	if ((rval == MP_MORE_DATA) || (mpioc->mp_alen > mpioc->mp_olen)) {
9601e1ddd6cScth 		mpioc->mp_errno = MP_MORE_DATA;
9611e1ddd6cScth 		return (EINVAL);
9621e1ddd6cScth 	}
9631e1ddd6cScth 
9641e1ddd6cScth 	if ((count > 0) && (ddi_copyout(output_data, (void *)mpioc->mp_obuf,
9651e1ddd6cScth 	    (count * sizeof (uint64_t)), mode) != 0)) {
9661e1ddd6cScth 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_get_path_list_for_mp_lu: "
9671e1ddd6cScth 		    "ddi_copyout() FAILED"));
9681e1ddd6cScth 		mpioc->mp_errno = EFAULT;
9691e1ddd6cScth 		rval = EINVAL;
9701e1ddd6cScth 	}
9711e1ddd6cScth 
9721e1ddd6cScth 	return (rval);
9731e1ddd6cScth }
9741e1ddd6cScth 
9751e1ddd6cScth /* ARGSUSED */
9761e1ddd6cScth static int
vhci_get_path_list_for_init_port(struct scsi_vhci * vhci,mp_iocdata_t * mpioc,void * input_data,void * output_data,int mode)9771e1ddd6cScth vhci_get_path_list_for_init_port(struct scsi_vhci *vhci, mp_iocdata_t *mpioc,
9781e1ddd6cScth     void *input_data, void *output_data, int mode)
9791e1ddd6cScth {
9801e1ddd6cScth 	int			count = 0, rval = 0;
9814e40636aSToomas Soome 	int			list_len = mpioc->mp_olen / sizeof (uint64_t);
9821e1ddd6cScth 	uint64_t		*oid_list = (uint64_t *)(output_data);
9831e1ddd6cScth 	uint64_t		*oid = (uint64_t *)(input_data);
9841e1ddd6cScth 	mpapi_item_list_t	*ilist, *mpinit_path_list = NULL;
9851e1ddd6cScth 	mpapi_initiator_data_t	*mpinitp;
9864c06356bSdh 	mpapi_path_data_t	*mppathp;
9874c06356bSdh 	mdi_pathinfo_t		*pip;
9881e1ddd6cScth 
9891e1ddd6cScth 	ilist = vhci->mp_priv->
9901e1ddd6cScth 	    obj_hdr_list[MP_OBJECT_TYPE_INITIATOR_PORT]->head;
9911e1ddd6cScth 
9921e1ddd6cScth 	/*
9931e1ddd6cScth 	 * While walking the mpapi database for initiator ports invalidate all
9941e1ddd6cScth 	 * initiator ports. The succeeding call to walk the phci list through
9951e1ddd6cScth 	 * MDI walker will validate the currently existing pHCIS.
9961e1ddd6cScth 	 */
9971e1ddd6cScth 	while (ilist != NULL) {
9981e1ddd6cScth 		mpinitp = ilist->item->idata;
9991e1ddd6cScth 		mpinitp->valid = 0;
10001e1ddd6cScth 		ilist = ilist->next;
10011e1ddd6cScth 	}
10021e1ddd6cScth 
10031e1ddd6cScth 	mdi_vhci_walk_phcis(vhci->vhci_dip, vhci_mpapi_sync_init_port_list,
10041e1ddd6cScth 	    vhci);
10051e1ddd6cScth 
10061e1ddd6cScth 	ilist = vhci->mp_priv->
10071e1ddd6cScth 	    obj_hdr_list[MP_OBJECT_TYPE_INITIATOR_PORT]->head;
10081e1ddd6cScth 
10091e1ddd6cScth 	while ((ilist != NULL) && (*oid != ilist->item->oid.raw_oid))
10101e1ddd6cScth 		ilist = ilist->next;
10111e1ddd6cScth 
10121e1ddd6cScth 	if (ilist == NULL) {
10131e1ddd6cScth 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_get_path_list_for_init_"
10141e1ddd6cScth 		    "port: OID NOT FOUND"));
10151e1ddd6cScth 		mpioc->mp_errno = MP_DRVR_INVALID_ID;
10161e1ddd6cScth 		rval = EINVAL;
10171e1ddd6cScth 	} else if (*oid == ilist->item->oid.raw_oid) {
10181e1ddd6cScth 		mpinitp = (mpapi_initiator_data_t *)(ilist->item->idata);
10191e1ddd6cScth 		if (mpinitp->valid == 0) {
10201e1ddd6cScth 			VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_get_path_list_for_"
10211e1ddd6cScth 			    "init_port: OID NOT FOUND - INIT PORT INVALID"));
10221e1ddd6cScth 			mpioc->mp_errno = MP_DRVR_INVALID_ID;
10231e1ddd6cScth 			return (EINVAL);
10241e1ddd6cScth 		}
10251e1ddd6cScth 		mpinit_path_list = mpinitp->path_list->head;
10261e1ddd6cScth 	} else {
10271e1ddd6cScth 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_get_path_list_for_init_"
10281e1ddd6cScth 		    "port: Unknown Error"));
10291e1ddd6cScth 	}
10301e1ddd6cScth 
10311e1ddd6cScth 	while (mpinit_path_list != NULL) {
10324c06356bSdh 		mppathp  = (mpapi_path_data_t *)(mpinit_path_list->item->idata);
10334c06356bSdh 		/* skip a path that should be hidden. */
10344c06356bSdh 		if (!(mppathp->hide)) {
10354c06356bSdh 			pip = (mdi_pathinfo_t *)mppathp->resp;
10364c06356bSdh 			mdi_hold_path(pip);
10374c06356bSdh 			/*
10384c06356bSdh 			 * check if the pip is marked as device removed.
10394c06356bSdh 			 * When pi_flag MDI_PATHINFO_FLAGS_DEVICE_REMOVED is set
10404c06356bSdh 			 * the node should have been destroyed but did not
10414c06356bSdh 			 * due to open on the client node.
10424c06356bSdh 			 * The driver tracks such a node through the hide flag
10434c06356bSdh 			 * and doesn't report it throuth ioctl response.
10444c06356bSdh 			 * The devinfo driver doesn't report such a path.
10454c06356bSdh 			 */
10464c06356bSdh 			if (!(MDI_PI_FLAGS_IS_DEVICE_REMOVED(pip))) {
10474c06356bSdh 				if (count < list_len) {
10484c06356bSdh 					oid_list[count] =
10494c06356bSdh 					    (uint64_t)mpinit_path_list->
10504c06356bSdh 					    item->oid.raw_oid;
10514c06356bSdh 				} else {
10524c06356bSdh 					rval = MP_MORE_DATA;
10534c06356bSdh 				}
10544c06356bSdh 				count++;
10554c06356bSdh 			}
10564c06356bSdh 			mdi_rele_path(pip);
10571e1ddd6cScth 		}
10581e1ddd6cScth 		mpinit_path_list = mpinit_path_list->next;
10591e1ddd6cScth 	}
10601e1ddd6cScth 
10611e1ddd6cScth 	mpioc->mp_alen = (uint32_t)(count * sizeof (uint64_t));
10621e1ddd6cScth 	if ((rval == MP_MORE_DATA) || (mpioc->mp_alen > mpioc->mp_olen)) {
10631e1ddd6cScth 		mpioc->mp_errno = MP_MORE_DATA;
10641e1ddd6cScth 		return (EINVAL);
10651e1ddd6cScth 	}
10661e1ddd6cScth 
10671e1ddd6cScth 	if ((count > 0) && (ddi_copyout(output_data, (void *)mpioc->mp_obuf,
10681e1ddd6cScth 	    (count * sizeof (uint64_t)), mode) != 0)) {
10691e1ddd6cScth 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_get_path_list_for_init_"
10701e1ddd6cScth 		    "port: ddi_copyout() FAILED"));
10711e1ddd6cScth 		mpioc->mp_errno = EFAULT;
10721e1ddd6cScth 		rval = EINVAL;
10731e1ddd6cScth 	}
10741e1ddd6cScth 
10751e1ddd6cScth 	return (rval);
10761e1ddd6cScth }
10771e1ddd6cScth 
10781e1ddd6cScth /* ARGSUSED */
10791e1ddd6cScth static int
vhci_get_path_list_for_target_port(struct scsi_vhci * vhci,mp_iocdata_t * mpioc,void * input_data,void * output_data,int mode)10801e1ddd6cScth vhci_get_path_list_for_target_port(struct scsi_vhci *vhci, mp_iocdata_t *mpioc,
10811e1ddd6cScth     void *input_data, void *output_data, int mode)
10821e1ddd6cScth {
10831e1ddd6cScth 	int			count = 0, rval = 0;
10844e40636aSToomas Soome 	int			list_len = mpioc->mp_olen / sizeof (uint64_t);
10851e1ddd6cScth 	uint64_t		*oid_list = (uint64_t *)(output_data);
10861e1ddd6cScth 	uint64_t		*oid = (uint64_t *)(input_data);
10871e1ddd6cScth 	mpapi_item_list_t	*ilist, *mptp_path_list = NULL;
10881e1ddd6cScth 	mpapi_tport_data_t	*mptpp;
10894c06356bSdh 	mpapi_path_data_t	*mppathp;
10904c06356bSdh 	mdi_pathinfo_t		*pip;
10911e1ddd6cScth 
10921e1ddd6cScth 	ilist = vhci->mp_priv->obj_hdr_list[MP_OBJECT_TYPE_TARGET_PORT]->head;
10931e1ddd6cScth 
10941e1ddd6cScth 	while ((ilist != NULL) && (*oid != ilist->item->oid.raw_oid))
10951e1ddd6cScth 		ilist = ilist->next;
10961e1ddd6cScth 
10971e1ddd6cScth 	if (ilist == NULL) {
10981e1ddd6cScth 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_get_path_list_for_target_"
10991e1ddd6cScth 		    "port: OID NOT FOUND"));
11001e1ddd6cScth 		mpioc->mp_errno = MP_DRVR_INVALID_ID;
11011e1ddd6cScth 		rval = EINVAL;
11021e1ddd6cScth 	} else if (*oid == ilist->item->oid.raw_oid) {
11031e1ddd6cScth 		mptpp = (mpapi_tport_data_t *)(ilist->item->idata);
11041e1ddd6cScth 		if (mptpp->valid == 0) {
11051e1ddd6cScth 			VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_get_path_list_for_"
11061e1ddd6cScth 			    "target_port: OID NOT FOUND - TGT PORT INVALID"));
11071e1ddd6cScth 			mpioc->mp_errno = MP_DRVR_INVALID_ID;
11081e1ddd6cScth 			return (EINVAL);
11091e1ddd6cScth 		}
11101e1ddd6cScth 		mptp_path_list = mptpp->path_list->head;
11111e1ddd6cScth 	} else {
11121e1ddd6cScth 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_get_path_list_for_target_"
11131e1ddd6cScth 		    "port: Unknown Error"));
11141e1ddd6cScth 	}
11151e1ddd6cScth 
11161e1ddd6cScth 	while (mptp_path_list != NULL) {
11174c06356bSdh 		mppathp  = (mpapi_path_data_t *)(mptp_path_list->item->idata);
11184c06356bSdh 		/* skip a path that should be hidden. */
11194c06356bSdh 		if (!(mppathp->hide)) {
11204c06356bSdh 			pip = (mdi_pathinfo_t *)mppathp->resp;
11214c06356bSdh 			mdi_hold_path(pip);
11224c06356bSdh 			/*
11234c06356bSdh 			 * check if the pip is marked as device removed.
11244c06356bSdh 			 * When pi_flag MDI_PATHINFO_FLAGS_DEVICE_REMOVED is set
11254c06356bSdh 			 * the node should have been destroyed but did not
11264c06356bSdh 			 * due to open on the client node.
11274c06356bSdh 			 * The driver tracks such a node through the hide flag
11284c06356bSdh 			 * and doesn't report it throuth ioctl response.
11294c06356bSdh 			 * The devinfo driver doesn't report such a path.
11304c06356bSdh 			 */
11314c06356bSdh 			if (!(MDI_PI_FLAGS_IS_DEVICE_REMOVED(pip))) {
11324c06356bSdh 				if (count < list_len) {
11334c06356bSdh 					oid_list[count] =
11344c06356bSdh 					    (uint64_t)mptp_path_list->
11354c06356bSdh 					    item->oid.raw_oid;
11364c06356bSdh 				} else {
11374c06356bSdh 					rval = MP_MORE_DATA;
11384c06356bSdh 				}
11394c06356bSdh 				count++;
11404c06356bSdh 			}
11414c06356bSdh 			mdi_rele_path(pip);
11421e1ddd6cScth 		}
11431e1ddd6cScth 		mptp_path_list = mptp_path_list->next;
11441e1ddd6cScth 	}
11451e1ddd6cScth 
11461e1ddd6cScth 	mpioc->mp_alen = (uint32_t)(count * sizeof (uint64_t));
11471e1ddd6cScth 	if ((rval == MP_MORE_DATA) || (mpioc->mp_alen > mpioc->mp_olen)) {
11481e1ddd6cScth 		mpioc->mp_errno = MP_MORE_DATA;
11491e1ddd6cScth 		return (EINVAL);
11501e1ddd6cScth 	}
11511e1ddd6cScth 
11521e1ddd6cScth 	if ((count > 0) && (ddi_copyout(output_data, (void *)mpioc->mp_obuf,
11531e1ddd6cScth 	    (count * sizeof (uint64_t)), mode) != 0)) {
11541e1ddd6cScth 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_get_path_list_for_target_"
11551e1ddd6cScth 		    "port: ddi_copyout() FAILED"));
11561e1ddd6cScth 		mpioc->mp_errno = EFAULT;
11571e1ddd6cScth 		rval = EINVAL;
11581e1ddd6cScth 	}
11591e1ddd6cScth 
11601e1ddd6cScth 	return (rval);
11611e1ddd6cScth }
11621e1ddd6cScth 
11631e1ddd6cScth /* ARGSUSED */
11641e1ddd6cScth static int
vhci_get_path_prop(struct scsi_vhci * vhci,mp_iocdata_t * mpioc,void * input_data,void * output_data,int mode)11651e1ddd6cScth vhci_get_path_prop(struct scsi_vhci *vhci, mp_iocdata_t *mpioc,
11661e1ddd6cScth     void *input_data, void *output_data, int mode)
11671e1ddd6cScth {
11681e1ddd6cScth 	int			rval = 0;
11691e1ddd6cScth 	uint64_t		oid;
11701e1ddd6cScth 	mp_path_prop_t		*mpp_prop = (mp_path_prop_t *)output_data;
11711e1ddd6cScth 	mpapi_item_list_t	*ilist;
11721e1ddd6cScth 	mpapi_path_data_t	*mpp;
11731e1ddd6cScth 
11741e1ddd6cScth 	ilist = vhci->mp_priv->obj_hdr_list[MP_OBJECT_TYPE_PATH_LU]->head;
11751e1ddd6cScth 
11761e1ddd6cScth 	rval = ddi_copyin(mpioc->mp_ibuf, &oid, mpioc->mp_ilen, mode);
11771e1ddd6cScth 
11781e1ddd6cScth 	while ((ilist != NULL) && (oid != ilist->item->oid.raw_oid))
11791e1ddd6cScth 		ilist = ilist->next;
11801e1ddd6cScth 
11811e1ddd6cScth 	if (ilist != NULL) {
11821e1ddd6cScth 		mpp = (mpapi_path_data_t *)(ilist->item->idata);
11831e1ddd6cScth 		if (mpp == NULL) {
11841e1ddd6cScth 			VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_get_path_prop: "
11851e1ddd6cScth 			    "idata in ilist is NULL"));
11861e1ddd6cScth 			return (EINVAL);
11871e1ddd6cScth 		}
11881e1ddd6cScth 		mpp_prop = (mp_path_prop_t *)(&mpp->prop);
11891e1ddd6cScth 	} else {
11901e1ddd6cScth 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_get_path_prop: "
11911e1ddd6cScth 		    "OID NOT FOUND"));
11921e1ddd6cScth 		mpioc->mp_errno = MP_DRVR_INVALID_ID;
11931e1ddd6cScth 		return (EINVAL);
11941e1ddd6cScth 	}
11951e1ddd6cScth 
11961e1ddd6cScth 	/*
11971e1ddd6cScth 	 * Here were are not using the 'output_data' that is
11981e1ddd6cScth 	 * passed as the required information is already
11991e1ddd6cScth 	 * in the required format!
12001e1ddd6cScth 	 */
12011e1ddd6cScth 	if (ddi_copyout((void *)mpp_prop, mpioc->mp_obuf,
12021e1ddd6cScth 	    sizeof (mp_path_prop_t), mode) != 0) {
12031e1ddd6cScth 		return (EFAULT);
12041e1ddd6cScth 	}
12051e1ddd6cScth 
12061e1ddd6cScth 	return (rval);
12071e1ddd6cScth }
12081e1ddd6cScth 
12091e1ddd6cScth /* ARGSUSED */
12101e1ddd6cScth static int
vhci_get_init_port_list(struct scsi_vhci * vhci,mp_iocdata_t * mpioc,void * input_data,void * output_data,int mode)12111e1ddd6cScth vhci_get_init_port_list(struct scsi_vhci *vhci, mp_iocdata_t *mpioc,
12121e1ddd6cScth     void *input_data, void *output_data, int mode)
12131e1ddd6cScth {
12141e1ddd6cScth 	int			count = 0, rval = 0;
12154e40636aSToomas Soome 	int			list_len = mpioc->mp_olen / sizeof (uint64_t);
12161e1ddd6cScth 	uint64_t		*oid_list = (uint64_t *)(output_data);
12171e1ddd6cScth 	mpapi_item_list_t	*ilist;
12181e1ddd6cScth 	mpapi_initiator_data_t	*initd;
12191e1ddd6cScth 
12201e1ddd6cScth 	ilist = vhci->mp_priv->
12211e1ddd6cScth 	    obj_hdr_list[MP_OBJECT_TYPE_INITIATOR_PORT]->head;
12221e1ddd6cScth 
12231e1ddd6cScth 	/*
12241e1ddd6cScth 	 * While walking the mpapi database for initiator ports invalidate all
12251e1ddd6cScth 	 * initiator ports. The succeeding call to walk the phci list through
12261e1ddd6cScth 	 * MDI walker will validate the currently existing pHCIS.
12271e1ddd6cScth 	 */
12281e1ddd6cScth 	while (ilist != NULL) {
12291e1ddd6cScth 		initd = ilist->item->idata;
12301e1ddd6cScth 		initd->valid = 0;
12311e1ddd6cScth 		ilist = ilist->next;
12321e1ddd6cScth 	}
12331e1ddd6cScth 
12341e1ddd6cScth 	mdi_vhci_walk_phcis(vhci->vhci_dip, vhci_mpapi_sync_init_port_list,
12351e1ddd6cScth 	    vhci);
12361e1ddd6cScth 
12371e1ddd6cScth 	ilist = vhci->mp_priv->
12381e1ddd6cScth 	    obj_hdr_list[MP_OBJECT_TYPE_INITIATOR_PORT]->head;
12391e1ddd6cScth 
12401e1ddd6cScth 	while (ilist != NULL) {
12411e1ddd6cScth 		if (count < list_len) {
12421e1ddd6cScth 			oid_list[count] = (uint64_t)ilist->item->oid.raw_oid;
12431e1ddd6cScth 		} else {
12441e1ddd6cScth 			rval = MP_MORE_DATA;
12451e1ddd6cScth 		}
12461e1ddd6cScth 		/*
12471e1ddd6cScth 		 * Get rid of the latest entry if item is invalid
12481e1ddd6cScth 		 */
12491e1ddd6cScth 		initd = ilist->item->idata;
12501e1ddd6cScth 		if (initd->valid == 0) {
12511e1ddd6cScth 			count--;
12521e1ddd6cScth 		}
12531e1ddd6cScth 		ilist = ilist->next;
12541e1ddd6cScth 		count++;
12551e1ddd6cScth 	}
12561e1ddd6cScth 
12571e1ddd6cScth 	mpioc->mp_alen = (uint32_t)(count * sizeof (uint64_t));
12581e1ddd6cScth 	if ((rval == MP_MORE_DATA) || (mpioc->mp_alen > mpioc->mp_olen)) {
12591e1ddd6cScth 		mpioc->mp_errno = MP_MORE_DATA;
12601e1ddd6cScth 		return (EINVAL);
12611e1ddd6cScth 	}
12621e1ddd6cScth 
12631e1ddd6cScth 	if (ddi_copyout(output_data, (void *)mpioc->mp_obuf,
12641e1ddd6cScth 	    (count * sizeof (uint64_t)), mode) != 0) {
12651e1ddd6cScth 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_get_init_port_list: "
12661e1ddd6cScth 		    "ddi_copyout() FAILED"));
12671e1ddd6cScth 		mpioc->mp_errno = EFAULT;
12681e1ddd6cScth 		rval = EINVAL;
12691e1ddd6cScth 	} else {
12701e1ddd6cScth 		mpioc->mp_errno = 0;
12711e1ddd6cScth 	}
12721e1ddd6cScth 
12731e1ddd6cScth 	return (rval);
12741e1ddd6cScth }
12751e1ddd6cScth 
12761e1ddd6cScth /* ARGSUSED */
12771e1ddd6cScth static int
vhci_get_init_port_prop(struct scsi_vhci * vhci,mp_iocdata_t * mpioc,void * input_data,void * output_data,int mode)12781e1ddd6cScth vhci_get_init_port_prop(struct scsi_vhci *vhci, mp_iocdata_t *mpioc,
12791e1ddd6cScth     void *input_data, void *output_data, int mode)
12801e1ddd6cScth {
12811e1ddd6cScth 	int			rval = 0;
12821e1ddd6cScth 	uint64_t		*oid = (uint64_t *)(input_data);
12831e1ddd6cScth 	mp_init_port_prop_t	*mpip_prop = (mp_init_port_prop_t *)output_data;
12841e1ddd6cScth 	mpapi_item_list_t	*ilist;
12851e1ddd6cScth 	mpapi_initiator_data_t	*mpip;
12861e1ddd6cScth 
12871e1ddd6cScth 	ilist = vhci->mp_priv->
12881e1ddd6cScth 	    obj_hdr_list[MP_OBJECT_TYPE_INITIATOR_PORT]->head;
12891e1ddd6cScth 
12901e1ddd6cScth 	/*
12911e1ddd6cScth 	 * While walking the mpapi database for initiator ports invalidate all
12921e1ddd6cScth 	 * initiator ports. The succeeding call to walk the phci list through
12931e1ddd6cScth 	 * MDI walker will validate the currently existing pHCIS.
12941e1ddd6cScth 	 */
12951e1ddd6cScth 	while (ilist != NULL) {
12961e1ddd6cScth 		mpip = ilist->item->idata;
12971e1ddd6cScth 		mpip->valid = 0;
12981e1ddd6cScth 		ilist = ilist->next;
12991e1ddd6cScth 	}
13001e1ddd6cScth 
13011e1ddd6cScth 	mdi_vhci_walk_phcis(vhci->vhci_dip, vhci_mpapi_sync_init_port_list,
13021e1ddd6cScth 	    vhci);
13031e1ddd6cScth 
13041e1ddd6cScth 	ilist = vhci->mp_priv->
13051e1ddd6cScth 	    obj_hdr_list[MP_OBJECT_TYPE_INITIATOR_PORT]->head;
13061e1ddd6cScth 
13071e1ddd6cScth 	while ((ilist != NULL) && (*oid != ilist->item->oid.raw_oid)) {
13081e1ddd6cScth 		ilist = ilist->next;
13091e1ddd6cScth 	}
13101e1ddd6cScth 
13111e1ddd6cScth 	if (ilist != NULL) {
13121e1ddd6cScth 		mpip = (mpapi_initiator_data_t *)(ilist->item->idata);
13131e1ddd6cScth 		if (mpip == NULL) {
13141e1ddd6cScth 			VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_get_init_port_prop:"
13151e1ddd6cScth 			    " idata in ilist is NULL"));
13161e1ddd6cScth 			return (EINVAL);
13171e1ddd6cScth 		} else if (mpip->valid == 0) {
13181e1ddd6cScth 			VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_get_init_port_prop"
13191e1ddd6cScth 			    ": OID NOT FOUND - INIT PORT IS INVALID"));
13201e1ddd6cScth 			mpioc->mp_errno = MP_DRVR_INVALID_ID;
13211e1ddd6cScth 			return (EINVAL);
13221e1ddd6cScth 		}
13231e1ddd6cScth 		mpip_prop = (mp_init_port_prop_t *)(&mpip->prop);
13241e1ddd6cScth 	} else {
13251e1ddd6cScth 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_get_init_port_prop: "
13261e1ddd6cScth 		    "OID NOT FOUND"));
13271e1ddd6cScth 		mpioc->mp_errno = MP_DRVR_INVALID_ID;
13281e1ddd6cScth 		return (EINVAL);
13291e1ddd6cScth 	}
13301e1ddd6cScth 
13311e1ddd6cScth 	/*
13321e1ddd6cScth 	 * Here were are not using the 'output_data' that is
13331e1ddd6cScth 	 * passed as the required information is already
13341e1ddd6cScth 	 * in the required format!
13351e1ddd6cScth 	 */
13361e1ddd6cScth 	if (ddi_copyout((void *)mpip_prop, mpioc->mp_obuf,
13371e1ddd6cScth 	    sizeof (mp_init_port_prop_t), mode) != 0) {
13381e1ddd6cScth 		return (EFAULT);
13391e1ddd6cScth 	}
13401e1ddd6cScth 	return (rval);
13411e1ddd6cScth }
13421e1ddd6cScth 
13431e1ddd6cScth /* ARGSUSED */
13441e1ddd6cScth static int
vhci_get_target_port_prop(struct scsi_vhci * vhci,mp_iocdata_t * mpioc,void * input_data,void * output_data,int mode)13451e1ddd6cScth vhci_get_target_port_prop(struct scsi_vhci *vhci, mp_iocdata_t *mpioc,
13461e1ddd6cScth     void *input_data, void *output_data, int mode)
13471e1ddd6cScth {
13481e1ddd6cScth 	int			rval = 0;
13491e1ddd6cScth 	uint64_t		*oid = (uint64_t *)(input_data);
13501e1ddd6cScth 	mp_target_port_prop_t	*mptp_prop;
13511e1ddd6cScth 	mpapi_item_list_t	*ilist;
13521e1ddd6cScth 	mpapi_tport_data_t	*mptp;
13531e1ddd6cScth 
13541e1ddd6cScth 	mptp_prop = (mp_target_port_prop_t *)output_data;
13551e1ddd6cScth 	ilist = vhci->mp_priv->obj_hdr_list[MP_OBJECT_TYPE_TARGET_PORT]->head;
13561e1ddd6cScth 
13571e1ddd6cScth 	while ((ilist != NULL) && (*oid != ilist->item->oid.raw_oid)) {
13581e1ddd6cScth 		ilist = ilist->next;
13591e1ddd6cScth 	}
13601e1ddd6cScth 
13611e1ddd6cScth 	if (ilist != NULL) {
13621e1ddd6cScth 		mptp = (mpapi_tport_data_t *)(ilist->item->idata);
13631e1ddd6cScth 		if (mptp == NULL) {
13641e1ddd6cScth 			VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_get_target_port_"
13651e1ddd6cScth 			    "prop: idata in ilist is NULL"));
13661e1ddd6cScth 			return (EINVAL);
13671e1ddd6cScth 		} else if (mptp->valid == 0) {
13681e1ddd6cScth 			VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_get_target_port_"
13691e1ddd6cScth 			    "prop: OID NOT FOUND - TARGET PORT INVALID"));
13701e1ddd6cScth 			mpioc->mp_errno = MP_DRVR_INVALID_ID;
13711e1ddd6cScth 			return (EINVAL);
13721e1ddd6cScth 		}
13731e1ddd6cScth 		mptp_prop = (mp_target_port_prop_t *)(&mptp->prop);
13741e1ddd6cScth 	} else {
13751e1ddd6cScth 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_get_target_port_prop: "
13761e1ddd6cScth 		    "OID NOT FOUND"));
13771e1ddd6cScth 		mpioc->mp_errno = MP_DRVR_INVALID_ID;
13781e1ddd6cScth 		return (EINVAL);
13791e1ddd6cScth 	}
13801e1ddd6cScth 	/*
13811e1ddd6cScth 	 * Here were are not using the 'output_data' that is
13821e1ddd6cScth 	 * passed as the required information is already
13831e1ddd6cScth 	 * in the required format!
13841e1ddd6cScth 	 */
13851e1ddd6cScth 	if (ddi_copyout((void *)mptp_prop, mpioc->mp_obuf,
13861e1ddd6cScth 	    sizeof (mp_target_port_prop_t), mode) != 0) {
13871e1ddd6cScth 		return (EFAULT);
13881e1ddd6cScth 	}
13891e1ddd6cScth 
13901e1ddd6cScth 	return (rval);
13911e1ddd6cScth }
13921e1ddd6cScth 
13931e1ddd6cScth /* ARGSUSED */
13941e1ddd6cScth static int
vhci_get_tpg_prop(struct scsi_vhci * vhci,mp_iocdata_t * mpioc,void * input_data,void * output_data,int mode)13951e1ddd6cScth vhci_get_tpg_prop(struct scsi_vhci *vhci, mp_iocdata_t *mpioc,
13961e1ddd6cScth     void *input_data, void *output_data, int mode)
13971e1ddd6cScth {
13981e1ddd6cScth 	int			rval = 0;
13991e1ddd6cScth 	uint64_t		*oid = (uint64_t *)(input_data);
14001e1ddd6cScth 	mp_tpg_prop_t		*mptpg_prop;
14011e1ddd6cScth 	mpapi_item_list_t	*ilist;
14021e1ddd6cScth 	mpapi_tpg_data_t	*mptpg;
14031e1ddd6cScth 
14041e1ddd6cScth 	mptpg_prop = (mp_tpg_prop_t *)output_data;
14051e1ddd6cScth 	ilist = vhci->mp_priv->obj_hdr_list[MP_OBJECT_TYPE_TARGET_PORT_GROUP]->
14061e1ddd6cScth 	    head;
14071e1ddd6cScth 
14081e1ddd6cScth 	while ((ilist != NULL) && (*oid != ilist->item->oid.raw_oid)) {
14091e1ddd6cScth 		ilist = ilist->next;
14101e1ddd6cScth 	}
14111e1ddd6cScth 
14121e1ddd6cScth 	if (ilist != NULL) {
14131e1ddd6cScth 		mptpg = (mpapi_tpg_data_t *)(ilist->item->idata);
14141e1ddd6cScth 		if (mptpg == NULL) {
14151e1ddd6cScth 			VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_get_tpg_prop: "
14161e1ddd6cScth 			    "idata in ilist is NULL"));
14171e1ddd6cScth 			return (EINVAL);
14181e1ddd6cScth 		} else if (mptpg->valid == 0) {
14191e1ddd6cScth 			VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_get_tpg_prop: "
14201e1ddd6cScth 			    "OID NOT FOUND - TPG INVALID"));
14211e1ddd6cScth 			mpioc->mp_errno = MP_DRVR_INVALID_ID;
14221e1ddd6cScth 			return (EINVAL);
14231e1ddd6cScth 		}
14241e1ddd6cScth 		mptpg_prop = (mp_tpg_prop_t *)(&mptpg->prop);
14251e1ddd6cScth 	} else {
14261e1ddd6cScth 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_get_tpg_prop: "
14271e1ddd6cScth 		    "OID NOT FOUND"));
14281e1ddd6cScth 		mpioc->mp_errno = MP_DRVR_INVALID_ID;
14291e1ddd6cScth 		return (EINVAL);
14301e1ddd6cScth 	}
14311e1ddd6cScth 	/*
14321e1ddd6cScth 	 * Here were are not using the 'output_data' that is
14331e1ddd6cScth 	 * passed as the required information is already
14341e1ddd6cScth 	 * in the required format!
14351e1ddd6cScth 	 */
14361e1ddd6cScth 	if (ddi_copyout((void *)mptpg_prop, mpioc->mp_obuf,
14371e1ddd6cScth 	    sizeof (mp_tpg_prop_t), mode) != 0) {
14381e1ddd6cScth 		return (EFAULT);
14391e1ddd6cScth 	}
14401e1ddd6cScth 
14411e1ddd6cScth 	return (rval);
14421e1ddd6cScth }
14431e1ddd6cScth 
14441e1ddd6cScth /* ARGSUSED */
14451e1ddd6cScth static int
vhci_get_target_port_list_for_tpg(struct scsi_vhci * vhci,mp_iocdata_t * mpioc,void * input_data,void * output_data,int mode)14461e1ddd6cScth vhci_get_target_port_list_for_tpg(struct scsi_vhci *vhci, mp_iocdata_t *mpioc,
14471e1ddd6cScth     void *input_data, void *output_data, int mode)
14481e1ddd6cScth {
14491e1ddd6cScth 	int			count = 0, rval = 0;
14504e40636aSToomas Soome 	int			list_len = mpioc->mp_olen / sizeof (uint64_t);
14511e1ddd6cScth 	uint64_t		*oid_list = (uint64_t *)(output_data);
14521e1ddd6cScth 	uint64_t		*oid = (uint64_t *)(input_data);
14531e1ddd6cScth 	mpapi_item_list_t	*ilist, *tpg_tp_list = NULL;
14541e1ddd6cScth 	mpapi_tpg_data_t	*mptpgtp;
14551e1ddd6cScth 	mpapi_tport_data_t	*mptpp;
14561e1ddd6cScth 
14571e1ddd6cScth 	ilist = vhci->mp_priv->obj_hdr_list[MP_OBJECT_TYPE_TARGET_PORT_GROUP]
14581e1ddd6cScth 	    ->head;
14591e1ddd6cScth 
14601e1ddd6cScth 	while ((ilist != NULL) && (*oid != ilist->item->oid.raw_oid))
14611e1ddd6cScth 		ilist = ilist->next;
14621e1ddd6cScth 
14631e1ddd6cScth 	if (ilist == NULL) {
14641e1ddd6cScth 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_get_target_port_list_for_"
14651e1ddd6cScth 		    "tpg: OID NOT FOUND"));
14661e1ddd6cScth 		mpioc->mp_errno = MP_DRVR_INVALID_ID;
14671e1ddd6cScth 		rval = EINVAL;
14681e1ddd6cScth 	} else if (*oid == ilist->item->oid.raw_oid) {
14691e1ddd6cScth 		mptpgtp = (mpapi_tpg_data_t *)(ilist->item->idata);
14701e1ddd6cScth 		if (mptpgtp->valid == 0) {
14711e1ddd6cScth 			VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_get_target_port_"
14721e1ddd6cScth 			    "list_for_tpg: OID NOT FOUND - TPG INVALID"));
14731e1ddd6cScth 			mpioc->mp_errno = MP_DRVR_INVALID_ID;
14741e1ddd6cScth 			return (EINVAL);
14751e1ddd6cScth 		}
14761e1ddd6cScth 		tpg_tp_list = mptpgtp->tport_list->head;
14771e1ddd6cScth 	} else {
14781e1ddd6cScth 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_get_target_port_list_for_"
14791e1ddd6cScth 		    "tpg: Unknown Error"));
14801e1ddd6cScth 	}
14811e1ddd6cScth 
14821e1ddd6cScth 	while (tpg_tp_list != NULL) {
14831e1ddd6cScth 		if (count < list_len) {
14841e1ddd6cScth 			oid_list[count] = (uint64_t)tpg_tp_list->
14851e1ddd6cScth 			    item->oid.raw_oid;
14861e1ddd6cScth 		} else {
14871e1ddd6cScth 			rval = MP_MORE_DATA;
14881e1ddd6cScth 		}
14891e1ddd6cScth 		mptpp = tpg_tp_list->item->idata;
14901e1ddd6cScth 		if (mptpp->valid == 0) {
14911e1ddd6cScth 			count--;
14921e1ddd6cScth 		}
14931e1ddd6cScth 		tpg_tp_list = tpg_tp_list->next;
14941e1ddd6cScth 		count++;
14951e1ddd6cScth 	}
14961e1ddd6cScth 
14971e1ddd6cScth 	mpioc->mp_alen = (uint32_t)(count * sizeof (uint64_t));
14981e1ddd6cScth 	if ((rval == MP_MORE_DATA) || (mpioc->mp_alen > mpioc->mp_olen)) {
14991e1ddd6cScth 		mpioc->mp_errno = MP_MORE_DATA;
15001e1ddd6cScth 		return (EINVAL);
15011e1ddd6cScth 	}
15021e1ddd6cScth 
15031e1ddd6cScth 	if ((count > 0) && (ddi_copyout(output_data, (void *)mpioc->mp_obuf,
15041e1ddd6cScth 	    (count * sizeof (uint64_t)), mode) != 0)) {
15051e1ddd6cScth 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_get_target_port_list_for_"
15061e1ddd6cScth 		    "tpg: ddi_copyout() FAILED"));
15071e1ddd6cScth 		mpioc->mp_errno = EFAULT;
15081e1ddd6cScth 		rval = EINVAL;
15091e1ddd6cScth 	}
15101e1ddd6cScth 
15111e1ddd6cScth 	return (rval);
15121e1ddd6cScth }
15131e1ddd6cScth 
15141e1ddd6cScth /* ARGSUSED */
15151e1ddd6cScth static int
vhci_set_tpg_access_state(struct scsi_vhci * vhci,mp_iocdata_t * mpioc,void * input_data,void * output_data,int mode)15161e1ddd6cScth vhci_set_tpg_access_state(struct scsi_vhci *vhci, mp_iocdata_t *mpioc,
15171e1ddd6cScth     void *input_data, void *output_data, int mode)
15181e1ddd6cScth {
15191e1ddd6cScth 	int			rval = 0, retval = 0, held = 0;
15201e1ddd6cScth 	uint32_t		desired_state, t10_tpgid;
15211e1ddd6cScth 	uint64_t		lu_oid, tpg_oid;
15221e1ddd6cScth 	mp_set_tpg_state_req_t	mp_set_tpg;
15231e1ddd6cScth 	mpapi_item_list_t	*lu_list, *tpg_list;
15241e1ddd6cScth 	mpapi_tpg_data_t	*mptpgd;
15251e1ddd6cScth 	scsi_vhci_lun_t		*svl;
15261e1ddd6cScth 	scsi_vhci_priv_t	*svp;
15271e1ddd6cScth 	mdi_pathinfo_t		*pip;
15281e1ddd6cScth 	struct scsi_address	*ap = NULL;
15291e1ddd6cScth 
15301e1ddd6cScth 	lu_list = vhci->mp_priv->obj_hdr_list[MP_OBJECT_TYPE_MULTIPATH_LU]
15311e1ddd6cScth 	    ->head;
15321e1ddd6cScth 	tpg_list = vhci->mp_priv->obj_hdr_list[MP_OBJECT_TYPE_TARGET_PORT_GROUP]
15331e1ddd6cScth 	    ->head;
15341e1ddd6cScth 
15351e1ddd6cScth 	rval = ddi_copyin(mpioc->mp_ibuf, &mp_set_tpg, mpioc->mp_ilen, mode);
15361e1ddd6cScth 	lu_oid = mp_set_tpg.luTpgPair.luId;
15371e1ddd6cScth 	tpg_oid = mp_set_tpg.luTpgPair.tpgId;
15381e1ddd6cScth 	desired_state = mp_set_tpg.desiredState;
15391e1ddd6cScth 
15401e1ddd6cScth 	VHCI_DEBUG(1, (CE_NOTE, NULL, "vhci_set_tpg_access_state: lu_oid: %lx,"
15411e1ddd6cScth 	    "tpg_oid: %lx, des_as: %x\n", (long)lu_oid, (long)tpg_oid,
15421e1ddd6cScth 	    desired_state));
15431e1ddd6cScth 
15441e1ddd6cScth 	while ((lu_list != NULL) && (lu_oid != lu_list->item->oid.raw_oid))
15451e1ddd6cScth 		lu_list = lu_list->next;
15461e1ddd6cScth 	while ((tpg_list != NULL) && (tpg_oid != tpg_list->item->oid.raw_oid))
15471e1ddd6cScth 		tpg_list = tpg_list->next;
15481e1ddd6cScth 
15491e1ddd6cScth 	if ((lu_list == NULL) || (tpg_list == NULL)) {
15501e1ddd6cScth 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_set_tpg_access_state: "
15511e1ddd6cScth 		    "OID NOT FOUND"));
15521e1ddd6cScth 		mpioc->mp_errno = MP_DRVR_INVALID_ID;
15531e1ddd6cScth 		return (EINVAL);
15541e1ddd6cScth 	}
15551e1ddd6cScth 	if ((desired_state != MP_DRVR_ACCESS_STATE_ACTIVE) &&
15561e1ddd6cScth 	    (desired_state != MP_DRVR_ACCESS_STATE_ACTIVE_OPTIMIZED) &&
15571e1ddd6cScth 	    (desired_state != MP_DRVR_ACCESS_STATE_ACTIVE_NONOPTIMIZED) &&
15581e1ddd6cScth 	    (desired_state != MP_DRVR_ACCESS_STATE_STANDBY)) {
15591e1ddd6cScth 		mpioc->mp_errno = MP_DRVR_ILLEGAL_ACCESS_STATE_REQUEST;
15601e1ddd6cScth 		return (EINVAL);
15611e1ddd6cScth 	}
15621e1ddd6cScth 	mptpgd = (mpapi_tpg_data_t *)(tpg_list->item->idata);
15631e1ddd6cScth 	if (desired_state == mptpgd->prop.accessState) {
15641e1ddd6cScth 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_set_tpg_access_"
15651e1ddd6cScth 		    "state: TPG already in desired State"));
15661e1ddd6cScth 		return (EINVAL);
15671e1ddd6cScth 	}
15681e1ddd6cScth 	t10_tpgid = mptpgd->prop.tpgId;
15691e1ddd6cScth 
15701e1ddd6cScth 	/*
15711e1ddd6cScth 	 * All input seems to be ok, Go ahead & change state.
15721e1ddd6cScth 	 */
15731e1ddd6cScth 	svl = ((mpapi_lu_data_t *)(lu_list->item->idata))->resp;
15741e1ddd6cScth 	if (!SCSI_FAILOVER_IS_TPGS(svl->svl_fops)) {
15751e1ddd6cScth 
15761e1ddd6cScth 		VHCI_HOLD_LUN(svl, VH_SLEEP, held);
15771e1ddd6cScth 		/*
15781e1ddd6cScth 		 * retval specifically cares about failover
15791e1ddd6cScth 		 * status and not about this routine's success.
15801e1ddd6cScth 		 */
15811e1ddd6cScth 		retval = mdi_failover(vhci->vhci_dip, svl->svl_dip,
15821e1ddd6cScth 		    MDI_FAILOVER_SYNC);
15831e1ddd6cScth 		if (retval != 0) {
15841e1ddd6cScth 			VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_set_tpg_access_"
15851e1ddd6cScth 			    "state: FAILOVER FAILED: %x", retval));
15861e1ddd6cScth 			VHCI_RELEASE_LUN(svl);
15871e1ddd6cScth 			return (EIO);
15881e1ddd6cScth 		} else {
15891e1ddd6cScth 			/*
15901e1ddd6cScth 			 * Don't set TPG's accessState here. Let mdi_failover's
15911e1ddd6cScth 			 * call-back routine "vhci_failover()" call
15921e1ddd6cScth 			 * vhci_mpapi_update_tpg_acc_state_for_lu().
15931e1ddd6cScth 			 */
15941e1ddd6cScth 			VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_set_tpg_access_"
15951e1ddd6cScth 			    "state: FAILOVER SUCCESS: %x", retval));
15961e1ddd6cScth 		}
15971e1ddd6cScth 		VHCI_RELEASE_LUN(svl);
15981e1ddd6cScth 	} else {
15991e1ddd6cScth 		/*
16001e1ddd6cScth 		 * Send SET_TARGET_PORT_GROUP SCSI Command. This is supported
16011e1ddd6cScth 		 * ONLY by devices which have TPGS EXPLICIT Failover support.
16021e1ddd6cScth 		 */
16031e1ddd6cScth 		retval = mdi_select_path(svl->svl_dip, NULL,
16041e1ddd6cScth 		    MDI_SELECT_ONLINE_PATH, NULL, &pip);
16051e1ddd6cScth 		if ((rval != MDI_SUCCESS) || (pip == NULL)) {
16061e1ddd6cScth 			VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_set_tpg_access_"
16071e1ddd6cScth 			    "state: Unable to find path: %x", retval));
16081e1ddd6cScth 			return (EINVAL);
16091e1ddd6cScth 		}
16101e1ddd6cScth 		svp = (scsi_vhci_priv_t *)mdi_pi_get_vhci_private(pip);
16111e1ddd6cScth 		if (svp == NULL) {
16121e1ddd6cScth 			VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_set_tpg_access_"
16131e1ddd6cScth 			    "state: Unable to find vhci private data"));
16141e1ddd6cScth 			mdi_rele_path(pip);
16151e1ddd6cScth 			return (EINVAL);
16161e1ddd6cScth 		}
16171e1ddd6cScth 		if (svp->svp_psd == NULL) {
16181e1ddd6cScth 			VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_set_tpg_access_"
16191e1ddd6cScth 			    "state: Unable to find scsi device"));
16201e1ddd6cScth 			mdi_rele_path(pip);
16211e1ddd6cScth 			return (EINVAL);
16221e1ddd6cScth 		}
16231e1ddd6cScth 		mdi_rele_path(pip);
16241e1ddd6cScth 		ap = &svp->svp_psd->sd_address;
16251e1ddd6cScth 		ASSERT(ap != NULL);
16261e1ddd6cScth 
16270205780bSrralphs 		retval = vhci_tpgs_set_target_groups(ap, desired_state,
16280205780bSrralphs 		    t10_tpgid);
16291e1ddd6cScth 		if (retval != 0) {
16301e1ddd6cScth 			VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_set_tpg_access_"
16311e1ddd6cScth 			    "state:(ALUA) FAILOVER FAILED: %x", retval));
16321e1ddd6cScth 			return (EIO);
16331e1ddd6cScth 		} else {
16341e1ddd6cScth 			/*
16351e1ddd6cScth 			 * Don't set accessState here.
16361e1ddd6cScth 			 * std_report_target_groups() call needs to sync up
16371e1ddd6cScth 			 * properly.
16381e1ddd6cScth 			 */
16391e1ddd6cScth 			VHCI_DEBUG(4, (CE_WARN, NULL, "vhci_set_tpg_access_"
16401e1ddd6cScth 			    "state:(ALUA) FAILOVER SUCCESS: %x", retval));
16411e1ddd6cScth 
16421e1ddd6cScth 			VHCI_HOLD_LUN(svl, VH_NOSLEEP, held);
16431e1ddd6cScth 			if (!held) {
16441e1ddd6cScth 				return (TRAN_BUSY);
16451e1ddd6cScth 			} else {
16461e1ddd6cScth 				vhci_update_pathstates((void *)svl);
16471e1ddd6cScth 			}
1648cc25db92SChris Liu 			if (desired_state != mptpgd->prop.accessState &&
1649cc25db92SChris Liu 			    (desired_state != MP_DRVR_ACCESS_STATE_ACTIVE ||
1650cc25db92SChris Liu 			    (mptpgd->prop.accessState !=
1651cc25db92SChris Liu 			    MP_DRVR_ACCESS_STATE_ACTIVE_OPTIMIZED &&
1652cc25db92SChris Liu 			    mptpgd->prop.accessState !=
1653cc25db92SChris Liu 			    MP_DRVR_ACCESS_STATE_ACTIVE_NONOPTIMIZED))) {
16541e1ddd6cScth 				VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_set_tpg_"
16551e1ddd6cScth 				    "access_state: TPGAccessState NOT Set: "
16561e1ddd6cScth 				    "des_state=%x, cur_state=%x", desired_state,
16571e1ddd6cScth 				    mptpgd->prop.accessState));
16581e1ddd6cScth 				return (EIO);
16591e1ddd6cScth 			}
16601e1ddd6cScth 
16611e1ddd6cScth 		}
16621e1ddd6cScth 	}
16631e1ddd6cScth 
16641e1ddd6cScth 	return (rval);
16651e1ddd6cScth }
16661e1ddd6cScth 
16671e1ddd6cScth /* ARGSUSED */
16681e1ddd6cScth static int
vhci_get_prop_lb_list(struct scsi_vhci * vhci,mp_iocdata_t * mpioc,void * input_data,void * output_data,int mode)16691e1ddd6cScth vhci_get_prop_lb_list(struct scsi_vhci *vhci, mp_iocdata_t *mpioc,
16701e1ddd6cScth     void *input_data, void *output_data, int mode)
16711e1ddd6cScth {
16721e1ddd6cScth 	int		rval = 0;
16731e1ddd6cScth 	uint64_t	*oid_list = (uint64_t *)(output_data);
16741e1ddd6cScth 
16754e40636aSToomas Soome 	oid_list[0] = 0;
16761e1ddd6cScth 
16771e1ddd6cScth 	if (ddi_copyout(output_data, (void *)mpioc->mp_obuf,
16781e1ddd6cScth 	    (sizeof (uint64_t)), mode) != 0) {
16791e1ddd6cScth 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_get_prop_lb_list: "
16801e1ddd6cScth 		    "ddi_copyout() FAILED"));
16811e1ddd6cScth 		mpioc->mp_errno = EFAULT;
16821e1ddd6cScth 		rval = EINVAL;
16831e1ddd6cScth 	} else {
16841e1ddd6cScth 		mpioc->mp_errno = 0;
16851e1ddd6cScth 	}
16861e1ddd6cScth 
16871e1ddd6cScth 	return (rval);
16881e1ddd6cScth }
16891e1ddd6cScth 
16901e1ddd6cScth /* ARGSUSED */
16911e1ddd6cScth static int
vhci_get_prop_lb_prop(struct scsi_vhci * vhci,mp_iocdata_t * mpioc,void * input_data,void * output_data,int mode)16921e1ddd6cScth vhci_get_prop_lb_prop(struct scsi_vhci *vhci, mp_iocdata_t *mpioc,
16931e1ddd6cScth     void *input_data, void *output_data, int mode)
16941e1ddd6cScth {
16951e1ddd6cScth 	int rval = EINVAL;
16961e1ddd6cScth 
16971e1ddd6cScth 	return (rval);
16981e1ddd6cScth }
16991e1ddd6cScth 
17001e1ddd6cScth /*
17011e1ddd6cScth  * Operation not supported currently as we do not know
17021e1ddd6cScth  * support any devices that allow this in the first place.
17031e1ddd6cScth  */
17041e1ddd6cScth /* ARGSUSED */
17051e1ddd6cScth static int
vhci_assign_lu_to_tpg(struct scsi_vhci * vhci,mp_iocdata_t * mpioc,void * input_data,void * output_data,int mode)17061e1ddd6cScth vhci_assign_lu_to_tpg(struct scsi_vhci *vhci, mp_iocdata_t *mpioc,
17071e1ddd6cScth     void *input_data, void *output_data, int mode)
17081e1ddd6cScth {
17091e1ddd6cScth 	int rval = ENOTSUP;
17101e1ddd6cScth 
17111e1ddd6cScth 	return (rval);
17121e1ddd6cScth }
17131e1ddd6cScth 
17141e1ddd6cScth /* ARGSUSED */
17151e1ddd6cScth static int
vhci_enable_auto_failback(struct scsi_vhci * vhci,mp_iocdata_t * mpioc,void * input_data,void * output_data,int mode)17161e1ddd6cScth vhci_enable_auto_failback(struct scsi_vhci *vhci, mp_iocdata_t *mpioc,
17171e1ddd6cScth     void *input_data, void *output_data, int mode)
17181e1ddd6cScth {
17191e1ddd6cScth 	int			rval = 0;
17201e1ddd6cScth 	mpapi_item_list_t	*ilist;
17211e1ddd6cScth 	mpapi_lu_data_t		*lud;
172217d71211SJiri Svoboda 	uint64_t		raw_oid;
17231e1ddd6cScth 
17241e1ddd6cScth 	mutex_enter(&vhci->vhci_mutex);
17251e1ddd6cScth 	vhci->vhci_conf_flags |= VHCI_CONF_FLAGS_AUTO_FAILBACK;
17261e1ddd6cScth 	mutex_exit(&vhci->vhci_mutex);
17271e1ddd6cScth 
17281e1ddd6cScth 	/* Enable auto-failback for each lun in MPAPI database */
17291e1ddd6cScth 	ilist = vhci->mp_priv->obj_hdr_list[MP_OBJECT_TYPE_MULTIPATH_LU]->head;
17301e1ddd6cScth 	while (ilist != NULL) {
17311e1ddd6cScth 		lud = ilist->item->idata;
17321e1ddd6cScth 		lud->prop.autoFailbackEnabled = 1;
17331e1ddd6cScth 		ilist = ilist->next;
17341e1ddd6cScth 	}
17351e1ddd6cScth 
173617d71211SJiri Svoboda 	/*
173717d71211SJiri Svoboda 	 * We don't really know the plugin OSN so just set 0, it will be ignored
173817d71211SJiri Svoboda 	 * by libmpscsi_vhci.
173917d71211SJiri Svoboda 	 */
174017d71211SJiri Svoboda 	raw_oid = 0;
174117d71211SJiri Svoboda 	vhci_mpapi_log_sysevent(vhci->vhci_dip, &raw_oid,
174217d71211SJiri Svoboda 	    ESC_SUN_MP_PLUGIN_CHANGE);
174317d71211SJiri Svoboda 
17441e1ddd6cScth 	return (rval);
17451e1ddd6cScth }
17461e1ddd6cScth 
17471e1ddd6cScth /* ARGSUSED */
17481e1ddd6cScth static int
vhci_disable_auto_failback(struct scsi_vhci * vhci,mp_iocdata_t * mpioc,void * input_data,void * output_data,int mode)17491e1ddd6cScth vhci_disable_auto_failback(struct scsi_vhci *vhci, mp_iocdata_t *mpioc,
17501e1ddd6cScth     void *input_data, void *output_data, int mode)
17511e1ddd6cScth {
17521e1ddd6cScth 	int			rval = 0;
17531e1ddd6cScth 	mpapi_item_list_t	*ilist;
17541e1ddd6cScth 	mpapi_lu_data_t		*lud;
175517d71211SJiri Svoboda 	uint64_t		raw_oid;
17561e1ddd6cScth 
17571e1ddd6cScth 	mutex_enter(&vhci->vhci_mutex);
17581e1ddd6cScth 	vhci->vhci_conf_flags &= ~VHCI_CONF_FLAGS_AUTO_FAILBACK;
17591e1ddd6cScth 	mutex_exit(&vhci->vhci_mutex);
17601e1ddd6cScth 
17611e1ddd6cScth 	/* Disable auto-failback for each lun in MPAPI database */
17621e1ddd6cScth 	ilist = vhci->mp_priv->obj_hdr_list[MP_OBJECT_TYPE_MULTIPATH_LU]->head;
17631e1ddd6cScth 	while (ilist != NULL) {
17641e1ddd6cScth 		lud = ilist->item->idata;
17651e1ddd6cScth 		lud->prop.autoFailbackEnabled = 0;
17661e1ddd6cScth 		ilist = ilist->next;
17671e1ddd6cScth 	}
17681e1ddd6cScth 
176917d71211SJiri Svoboda 	/*
177017d71211SJiri Svoboda 	 * We don't really know the plugin OSN so just set 0, it will be ignored
177117d71211SJiri Svoboda 	 * by libmpscsi_vhci.
177217d71211SJiri Svoboda 	 */
177317d71211SJiri Svoboda 	raw_oid = 0;
177417d71211SJiri Svoboda 	vhci_mpapi_log_sysevent(vhci->vhci_dip, &raw_oid,
177517d71211SJiri Svoboda 	    ESC_SUN_MP_PLUGIN_CHANGE);
177617d71211SJiri Svoboda 
17771e1ddd6cScth 	return (rval);
17781e1ddd6cScth }
17791e1ddd6cScth 
17801e1ddd6cScth /*
17811e1ddd6cScth  * Find the oid in the object type list. If found lock and return
17821e1ddd6cScth  * the item. If not found return NULL. The caller must unlock the item.
17831e1ddd6cScth  */
17841e1ddd6cScth void *
vhci_mpapi_hold_item(struct scsi_vhci * vhci,uint64_t * oid,uint8_t obj_type)17851e1ddd6cScth vhci_mpapi_hold_item(struct scsi_vhci *vhci, uint64_t *oid, uint8_t obj_type)
17861e1ddd6cScth {
17871e1ddd6cScth 	mpapi_item_list_t	*ilist;
17881e1ddd6cScth 
17891e1ddd6cScth 	ilist = vhci->mp_priv->obj_hdr_list[obj_type]->head;
17901e1ddd6cScth 	while ((ilist != NULL) && (*oid != ilist->item->oid.raw_oid))
17911e1ddd6cScth 		ilist = ilist->next;
17921e1ddd6cScth 
17931e1ddd6cScth 	if (ilist == NULL) {
17941e1ddd6cScth 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_mpapi_hold_item: "
17951e1ddd6cScth 		    "OID NOT FOUND. oid: %p", (void *)oid));
17961e1ddd6cScth 		return (NULL);
17971e1ddd6cScth 	}
17981e1ddd6cScth 	if (*oid == ilist->item->oid.raw_oid) {
17991e1ddd6cScth 		mutex_enter(&ilist->item->item_mutex);
18001e1ddd6cScth 		return (ilist);
18011e1ddd6cScth 	}
18021e1ddd6cScth 	VHCI_DEBUG(4, (CE_WARN, NULL, "vhci_mpapi_hold_item: "
18031e1ddd6cScth 	    "Unknown Error. oid: %p", (void *)oid));
18041e1ddd6cScth 	return (NULL);
18051e1ddd6cScth }
18061e1ddd6cScth 
18071e1ddd6cScth /*
18081e1ddd6cScth  * Check that the pip sent in by the user is still associated with
18091e1ddd6cScth  * the same oid. This is done through checking the path name.
18101e1ddd6cScth  */
18111e1ddd6cScth mdi_pathinfo_t *
vhci_mpapi_chk_path(struct scsi_vhci * vhci,mpapi_item_list_t * ilist)18121e1ddd6cScth vhci_mpapi_chk_path(struct scsi_vhci *vhci, mpapi_item_list_t *ilist)
18131e1ddd6cScth {
18141e1ddd6cScth 	mdi_pathinfo_t		*pip;
18151e1ddd6cScth 	mpapi_path_data_t	*mpp;
18161e1ddd6cScth 
18171e1ddd6cScth 	mpp = (mpapi_path_data_t *)(ilist->item->idata);
18181e1ddd6cScth 	if (mpp == NULL || mpp->valid == 0) {
18191e1ddd6cScth 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_mpapi_chk_path: "
18201e1ddd6cScth 		    "pathinfo is not valid: %p", (void *)mpp));
18211e1ddd6cScth 		return (NULL);
18221e1ddd6cScth 	}
18231e1ddd6cScth 	pip = mpp->resp;
18241e1ddd6cScth 	/* make sure it is the same pip by checking path */
18251e1ddd6cScth 	if (vhci_mpapi_match_pip(vhci, ilist, pip) == NULL) {
18261e1ddd6cScth 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_mpapi_chk_path: "
18271e1ddd6cScth 		    "Can not match pip: %p", (void *)pip));
18281e1ddd6cScth 		return (NULL);
18291e1ddd6cScth 	}
18301e1ddd6cScth 	return (pip);
18311e1ddd6cScth }
18321e1ddd6cScth 
18331e1ddd6cScth /*
18341e1ddd6cScth  * Get the pip from the oid passed in. the vhci_mpapi_chk_path
18351e1ddd6cScth  * will check the name with the passed in pip name.  the mdi_select_path()
18361e1ddd6cScth  * path will lock the pip and this should get released by the caller
18371e1ddd6cScth  */
18381e1ddd6cScth mdi_pathinfo_t *
vhci_mpapi_hold_pip(struct scsi_vhci * vhci,mpapi_item_list_t * ilist,int flags)18391e1ddd6cScth vhci_mpapi_hold_pip(struct scsi_vhci *vhci, mpapi_item_list_t *ilist, int flags)
18401e1ddd6cScth {
18411e1ddd6cScth 	mdi_pathinfo_t		*pip, *opip, *npip;
18421e1ddd6cScth 	scsi_vhci_lun_t		*svl;
18431e1ddd6cScth 	int			rval;
18441e1ddd6cScth 	mpapi_path_data_t	*mpp;
18451e1ddd6cScth 
18461e1ddd6cScth 	mpp = (mpapi_path_data_t *)(ilist->item->idata);
18471e1ddd6cScth 	pip = mpp->resp;
18481e1ddd6cScth 	/* make sure it is the same pip by checking path */
18491e1ddd6cScth 	if (vhci_mpapi_chk_path(vhci, ilist) == NULL) {
18501e1ddd6cScth 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_mpapi_hold_pip: "
18511e1ddd6cScth 		    "Can not match pip: %p", (void *)pip));
18521e1ddd6cScth 		return (NULL);
18531e1ddd6cScth 	}
18541e1ddd6cScth 
18551e1ddd6cScth 	svl = mdi_client_get_vhci_private(mdi_pi_get_client(pip));
18561e1ddd6cScth 	opip = npip = NULL;
18571e1ddd6cScth 
18581e1ddd6cScth 	/*
18591e1ddd6cScth 	 * use the select path to find the right pip since
18601e1ddd6cScth 	 * it does all the state checking and locks the pip
18611e1ddd6cScth 	 */
18621e1ddd6cScth 	rval = mdi_select_path(svl->svl_dip, NULL,
18631e1ddd6cScth 	    flags, NULL, &npip);
18641e1ddd6cScth 	do {
18651e1ddd6cScth 		if ((rval != MDI_SUCCESS) || (npip == NULL)) {
18661e1ddd6cScth 			VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_mpapi_hold_pip:"
18671e1ddd6cScth 			    " Unable to find path: %x.", rval));
18681e1ddd6cScth 			return (NULL);
18691e1ddd6cScth 		}
18701e1ddd6cScth 		if (npip == pip) {
18711e1ddd6cScth 			break;
18721e1ddd6cScth 		}
18731e1ddd6cScth 		opip = npip;
18741e1ddd6cScth 		rval = mdi_select_path(svl->svl_dip, NULL,
18751e1ddd6cScth 		    flags, opip, &npip);
18761e1ddd6cScth 		mdi_rele_path(opip);
18771e1ddd6cScth 	} while ((npip != NULL) && (rval == MDI_SUCCESS));
18781e1ddd6cScth 	return (npip);
18791e1ddd6cScth }
18801e1ddd6cScth 
18811e1ddd6cScth /*
18821e1ddd6cScth  * Initialize the uscsi command. Lock the pip and the item in
18831e1ddd6cScth  * the item list.
18841e1ddd6cScth  */
18851e1ddd6cScth static mp_uscsi_cmd_t *
vhci_init_uscsi_cmd(struct scsi_vhci * vhci,mp_iocdata_t * mpioc,uint64_t * oid,mpapi_item_list_t ** list)18861e1ddd6cScth vhci_init_uscsi_cmd(struct scsi_vhci *vhci,
18874e40636aSToomas Soome     mp_iocdata_t *mpioc, uint64_t *oid, mpapi_item_list_t **list)
18881e1ddd6cScth {
18891e1ddd6cScth 	int			arq_enabled;
18901e1ddd6cScth 	mp_uscsi_cmd_t		*mp_uscmdp;
18911e1ddd6cScth 	scsi_vhci_priv_t	*svp;
18921e1ddd6cScth 	struct scsi_address	*ap;
18931e1ddd6cScth 	mdi_pathinfo_t		*pip;
18941e1ddd6cScth 	mpapi_item_list_t	*ilist;
18951e1ddd6cScth 	struct buf		*bp;
18961e1ddd6cScth 
18971e1ddd6cScth 	VHCI_DEBUG(4, (CE_WARN, NULL,
18981e1ddd6cScth 	    "vhci_init_uscsi_cmd: enter"));
18991e1ddd6cScth 
19001e1ddd6cScth 	*list = NULL;
19011e1ddd6cScth 	/* lock the item */
19021e1ddd6cScth 	if ((ilist = (mpapi_item_list_t *)vhci_mpapi_hold_item(
19031e1ddd6cScth 	    vhci, oid, MP_OBJECT_TYPE_PATH_LU)) == NULL) {
19041e1ddd6cScth 		VHCI_DEBUG(1, (CE_WARN, NULL,
19051e1ddd6cScth 		    "vhci_init_uscsi_cmd: exit EINVAL"));
19061e1ddd6cScth 		mpioc->mp_errno = MP_DRVR_INVALID_ID;
19071e1ddd6cScth 		return (NULL);
19081e1ddd6cScth 	}
19091e1ddd6cScth 
19101e1ddd6cScth 	/* lock the pip */
19111e1ddd6cScth 	if ((pip = vhci_mpapi_hold_pip(vhci, ilist,
19124e40636aSToomas Soome 	    (MDI_SELECT_STANDBY_PATH | MDI_SELECT_ONLINE_PATH))) == 0) {
19131e1ddd6cScth 		VHCI_DEBUG(1, (CE_WARN, NULL,
19141e1ddd6cScth 		    "vhci_init_uscsi_cmd: exit PATH_UNAVAIL"));
19151e1ddd6cScth 		mpioc->mp_errno = MP_DRVR_PATH_UNAVAILABLE;
19161e1ddd6cScth 		mutex_exit(&ilist->item->item_mutex);
19171e1ddd6cScth 		return (NULL);
19181e1ddd6cScth 	};
19191e1ddd6cScth 
19201e1ddd6cScth 	/* get the address of the pip */
19211e1ddd6cScth 	svp = (scsi_vhci_priv_t *)mdi_pi_get_vhci_private(pip);
19221e1ddd6cScth 	if (svp == NULL) {
19231e1ddd6cScth 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_init_uscsi_cmd:"
19241e1ddd6cScth 		    " Unable to find vhci private data"));
19251e1ddd6cScth 		mpioc->mp_errno = MP_DRVR_PATH_UNAVAILABLE;
19261e1ddd6cScth 		mdi_rele_path(pip);
19271e1ddd6cScth 		mutex_exit(&ilist->item->item_mutex);
19281e1ddd6cScth 		return (NULL);
19291e1ddd6cScth 	}
19301e1ddd6cScth 	if (svp->svp_psd == NULL) {
19311e1ddd6cScth 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_init_uscsi_cmd:"
19321e1ddd6cScth 		    " Unable to find scsi device"));
19331e1ddd6cScth 		mpioc->mp_errno = MP_DRVR_PATH_UNAVAILABLE;
19341e1ddd6cScth 		mdi_rele_path(pip);
19351e1ddd6cScth 		mutex_exit(&ilist->item->item_mutex);
19361e1ddd6cScth 		return (NULL);
19371e1ddd6cScth 	}
19381e1ddd6cScth 	ap = &svp->svp_psd->sd_address;
19391e1ddd6cScth 	ASSERT(ap != NULL);
19401e1ddd6cScth 
19411e1ddd6cScth 	/* initialize the buffer */
19421e1ddd6cScth 	bp = getrbuf(KM_SLEEP);
19431e1ddd6cScth 	ASSERT(bp != NULL);
19441e1ddd6cScth 
19451e1ddd6cScth 	/* initialize the mp_uscsi_cmd */
19461e1ddd6cScth 	mp_uscmdp = kmem_zalloc((size_t)sizeof (mp_uscsi_cmd_t), KM_SLEEP);
19471e1ddd6cScth 	ASSERT(mp_uscmdp != NULL);
19481e1ddd6cScth 	mp_uscmdp->ap = ap;
19491e1ddd6cScth 	mp_uscmdp->pip = pip;
19501e1ddd6cScth 	mp_uscmdp->cmdbp = bp;
19511e1ddd6cScth 	mp_uscmdp->rqbp = NULL;
19521e1ddd6cScth 
19531e1ddd6cScth 	bp->b_private = mp_uscmdp;
19541e1ddd6cScth 
19551e1ddd6cScth 	/* used to debug a manual sense */
19561e1ddd6cScth 	if (vhci_force_manual_sense) {
19571e1ddd6cScth 		(void) scsi_ifsetcap(ap, "auto-rqsense", 0, 0);
19581e1ddd6cScth 	} else {
19591e1ddd6cScth 		if (scsi_ifgetcap(ap, "auto-rqsense", 1) != 1) {
19601e1ddd6cScth 			(void) scsi_ifsetcap(ap, "auto-rqsense", 1, 1);
19611e1ddd6cScth 		}
19621e1ddd6cScth 	}
19631e1ddd6cScth 	arq_enabled = scsi_ifgetcap(ap, "auto-rqsense", 1);
19641e1ddd6cScth 	if (arq_enabled == 1) {
19651e1ddd6cScth 		mp_uscmdp->arq_enabled = 1;
19661e1ddd6cScth 	} else {
19671e1ddd6cScth 		mp_uscmdp->arq_enabled = 0;
19681e1ddd6cScth 	}
19691e1ddd6cScth 	/* set the list pointer for the caller */
19701e1ddd6cScth 	*list = ilist;
19711e1ddd6cScth 	VHCI_DEBUG(4, (CE_WARN, NULL,
19721e1ddd6cScth 	    "vhci_init_uscsi_cmd: mp_uscmdp: %p ilist: %p mp_errno: %d "
19731e1ddd6cScth 	    "bp: %p arq: %d",
19741e1ddd6cScth 	    (void *)mp_uscmdp, (void *)*list, mpioc->mp_errno,
19751e1ddd6cScth 	    (void *)bp, arq_enabled));
19761e1ddd6cScth 
19771e1ddd6cScth 	return (mp_uscmdp);
19781e1ddd6cScth }
19791e1ddd6cScth 
19801e1ddd6cScth 
19811e1ddd6cScth /*
19821e1ddd6cScth  * Initialize the uscsi information and then issue the command.
19831e1ddd6cScth  */
19841e1ddd6cScth /* ARGSUSED */
19851e1ddd6cScth static int
vhci_send_uscsi_cmd(dev_t dev,struct scsi_vhci * vhci,mp_iocdata_t * mpioc,void * input_data,void * output_data,int mode)19861e1ddd6cScth vhci_send_uscsi_cmd(dev_t dev, struct scsi_vhci *vhci, mp_iocdata_t *mpioc,
19871e1ddd6cScth     void *input_data, void *output_data, int mode)
19881e1ddd6cScth {
19891e1ddd6cScth 	int			rval = 0, uioseg = 0;
19901e1ddd6cScth 	struct uscsi_cmd	*uscmdp;
19911e1ddd6cScth 	uint64_t		*oid = (uint64_t *)(input_data);
19921e1ddd6cScth 	mp_uscsi_cmd_t		*mp_uscmdp;
19931e1ddd6cScth 	mpapi_item_list_t	*ilist;
19941e1ddd6cScth 
19951e1ddd6cScth 	VHCI_DEBUG(4, (CE_WARN, NULL,
19961e1ddd6cScth 	    "vhci_send_uscsi_cmd: enter: mode: %x", mode));
19971e1ddd6cScth 	mpioc->mp_errno = 0;
19981e1ddd6cScth 	mp_uscmdp = vhci_init_uscsi_cmd(vhci, mpioc, oid, &ilist);
19991e1ddd6cScth 	if (mp_uscmdp == NULL) {
20001e1ddd6cScth 		VHCI_DEBUG(1, (CE_WARN, NULL,
20011e1ddd6cScth 		    "vhci_send_uscsi_cmd: exit INVALID_ID. rval: %d", rval));
20021e1ddd6cScth 		return (EINVAL);
20031e1ddd6cScth 	}
20041e1ddd6cScth 	rval = scsi_uscsi_alloc_and_copyin((intptr_t)mpioc->mp_obuf,
20051e1ddd6cScth 	    mode, mp_uscmdp->ap, &uscmdp);
20061e1ddd6cScth 	if (rval != 0) {
20071e1ddd6cScth 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_send_uscsi_cmd: "
20081e1ddd6cScth 		    "scsi_uscsi_alloc_and_copyin failed. rval: %d", rval));
20091e1ddd6cScth 		mpioc->mp_errno = EINVAL;
20101e1ddd6cScth 		mdi_rele_path(mp_uscmdp->pip);
20111e1ddd6cScth 		mutex_exit(&ilist->item->item_mutex);
20121e1ddd6cScth 		if (mp_uscmdp->cmdbp)
20131e1ddd6cScth 			freerbuf(mp_uscmdp->cmdbp);
20141e1ddd6cScth 		kmem_free(mp_uscmdp, sizeof (mp_uscsi_cmd_t));
20151e1ddd6cScth 		return (EINVAL);
20161e1ddd6cScth 	}
20171e1ddd6cScth 	/* initialize the mp_uscsi_cmd with the uscsi_cmd from uscsi_alloc */
20181e1ddd6cScth 	mp_uscmdp->uscmdp = uscmdp;
20191e1ddd6cScth 
20201e1ddd6cScth 	uioseg = (mode & FKIOCTL) ? UIO_SYSSPACE : UIO_USERSPACE;
20211e1ddd6cScth 
20221e1ddd6cScth 	/* start the command sending the buffer as an argument */
20231e1ddd6cScth 	rval = scsi_uscsi_handle_cmd(dev, uioseg,
20241e1ddd6cScth 	    uscmdp, vhci_uscsi_iostart, mp_uscmdp->cmdbp, mp_uscmdp);
20251e1ddd6cScth 	if (rval != 0) {
20261e1ddd6cScth 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_send_uscsi_cmd: "
20271e1ddd6cScth 		    "scsi_uscsi_handle_cmd failed. rval: %d", rval));
20281e1ddd6cScth 		mpioc->mp_errno = EIO;
20291e1ddd6cScth 	}
20301e1ddd6cScth 
20311e1ddd6cScth 	if (scsi_uscsi_copyout_and_free((intptr_t)mpioc->mp_obuf,
20321e1ddd6cScth 	    uscmdp) != 0 && rval == 0) {
20331e1ddd6cScth 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_send_uscsi_cmd: "
20341e1ddd6cScth 		    "scsi_uscsi_copyout_and_free failed. rval: %d", rval));
20351e1ddd6cScth 		mpioc->mp_errno = EFAULT;
20361e1ddd6cScth 		rval = EFAULT;
20371e1ddd6cScth 	}
20381e1ddd6cScth 	/* cleanup */
20391e1ddd6cScth 	mdi_rele_path(mp_uscmdp->pip);
20401e1ddd6cScth 	mutex_exit(&ilist->item->item_mutex);
20411e1ddd6cScth 	if (mp_uscmdp->cmdbp)
20421e1ddd6cScth 		freerbuf(mp_uscmdp->cmdbp);
20431e1ddd6cScth 	kmem_free(mp_uscmdp, sizeof (mp_uscsi_cmd_t));
20441e1ddd6cScth 	VHCI_DEBUG(4, (CE_WARN, NULL,
20451e1ddd6cScth 	    "vhci_send_uscsi_cmd: rval: %d mp_errno: %d",
20461e1ddd6cScth 	    rval, mpioc->mp_errno));
20471e1ddd6cScth 
20481e1ddd6cScth 	return (rval);
20491e1ddd6cScth }
20501e1ddd6cScth 
20511e1ddd6cScth /* ARGSUSED */
20521e1ddd6cScth static int
vhci_enable_path(struct scsi_vhci * vhci,mp_iocdata_t * mpioc,void * input_data,void * output_data,int mode)20531e1ddd6cScth vhci_enable_path(struct scsi_vhci *vhci, mp_iocdata_t *mpioc,
20541e1ddd6cScth     void *input_data, void *output_data, int mode)
20551e1ddd6cScth {
20561e1ddd6cScth 	int			rval = 0;
20571e1ddd6cScth 	uint64_t		*oid = (uint64_t *)(input_data);
20581e1ddd6cScth 	mdi_pathinfo_t		*pip;
20591e1ddd6cScth 	mpapi_item_list_t	*ilist;
20601e1ddd6cScth 	mpapi_path_data_t	*mpp;
20611e1ddd6cScth 
20621e1ddd6cScth 	if ((ilist = (mpapi_item_list_t *)vhci_mpapi_hold_item(vhci, oid,
20631e1ddd6cScth 	    MP_OBJECT_TYPE_PATH_LU)) == NULL) {
20641e1ddd6cScth 		mpioc->mp_errno = MP_DRVR_INVALID_ID;
20651e1ddd6cScth 		return (EINVAL);
20661e1ddd6cScth 	}
20671e1ddd6cScth 
20681e1ddd6cScth 	mpp = (mpapi_path_data_t *)(ilist->item->idata);
20691e1ddd6cScth 	pip = (mdi_pathinfo_t *)mpp->resp;
20701e1ddd6cScth 
20711e1ddd6cScth 	if (vhci_mpapi_chk_path(vhci, ilist) == NULL) {
20721e1ddd6cScth 		mutex_exit(&ilist->item->item_mutex);
20731e1ddd6cScth 		mpioc->mp_errno = MP_DRVR_INVALID_ID;
20741e1ddd6cScth 		return (EINVAL);
20751e1ddd6cScth 	}
20761e1ddd6cScth 
20771e1ddd6cScth 	if (mdi_pi_enable_path(pip, USER_DISABLE) != 0) {
20781e1ddd6cScth 		rval = EFAULT;
20791e1ddd6cScth 	} else {
20801e1ddd6cScth 		mpp->prop.disabled = 0;
20811e1ddd6cScth 		vhci_mpapi_log_sysevent(vhci->vhci_dip,
20821e1ddd6cScth 		    &(((mpoid_t *)oid)->raw_oid), ESC_SUN_MP_PATH_CHANGE);
20831e1ddd6cScth 	}
20841e1ddd6cScth 	mutex_exit(&ilist->item->item_mutex);
20851e1ddd6cScth 	return (rval);
20861e1ddd6cScth }
20871e1ddd6cScth 
20881e1ddd6cScth /* ARGSUSED */
20891e1ddd6cScth static int
vhci_disable_path(struct scsi_vhci * vhci,mp_iocdata_t * mpioc,void * input_data,void * output_data,int mode)20901e1ddd6cScth vhci_disable_path(struct scsi_vhci *vhci, mp_iocdata_t *mpioc,
20911e1ddd6cScth     void *input_data, void *output_data, int mode)
20921e1ddd6cScth {
20931e1ddd6cScth 	int			rval = 0;
20941e1ddd6cScth 	uint64_t		*oid = (uint64_t *)(input_data);
20951e1ddd6cScth 	mdi_pathinfo_t		*pip = NULL;
20961e1ddd6cScth 	mpapi_item_list_t	*ilist;
20971e1ddd6cScth 	mpapi_path_data_t	*mpp;
20981e1ddd6cScth 
20991e1ddd6cScth 	if ((ilist = (mpapi_item_list_t *)vhci_mpapi_hold_item(vhci, oid,
21001e1ddd6cScth 	    MP_OBJECT_TYPE_PATH_LU)) == NULL) {
21011e1ddd6cScth 		mpioc->mp_errno = MP_DRVR_INVALID_ID;
21021e1ddd6cScth 		return (EINVAL);
21031e1ddd6cScth 	}
21041e1ddd6cScth 
21051e1ddd6cScth 	mpp = (mpapi_path_data_t *)(ilist->item->idata);
21061e1ddd6cScth 	pip = (mdi_pathinfo_t *)mpp->resp;
21071e1ddd6cScth 
21081e1ddd6cScth 	if (vhci_mpapi_chk_path(vhci, ilist) == NULL) {
21091e1ddd6cScth 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_disable_path: Request "
21101e1ddd6cScth 		    "received to disable last path. Cant disable, Sorry!"));
21111e1ddd6cScth 		mutex_exit(&ilist->item->item_mutex);
21121e1ddd6cScth 		return (EINVAL);
21131e1ddd6cScth 	}
21141e1ddd6cScth 	if (vhci_mpapi_chk_last_path(pip) != 0) {
21151e1ddd6cScth 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_disable_path(1): Request "
21161e1ddd6cScth 		    "received to disable last path. Cant disable, Sorry!"));
21171e1ddd6cScth 		mutex_exit(&ilist->item->item_mutex);
21181e1ddd6cScth 		return (EINVAL);
21191e1ddd6cScth 	}
21201e1ddd6cScth 
21211e1ddd6cScth 	if (mdi_pi_disable_path(pip, USER_DISABLE) != 0) {
21221e1ddd6cScth 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_disable_path(2): Request "
21231e1ddd6cScth 		    "received to disable last path. Cant disable, Sorry!"));
21241e1ddd6cScth 		rval = EFAULT;
21251e1ddd6cScth 	} else {
21261e1ddd6cScth 		mpp->prop.disabled = 1;
21271e1ddd6cScth 		vhci_mpapi_log_sysevent(vhci->vhci_dip,
21281e1ddd6cScth 		    &(((mpoid_t *)oid)->raw_oid), ESC_SUN_MP_PATH_CHANGE);
21291e1ddd6cScth 	}
21301e1ddd6cScth 	mutex_exit(&ilist->item->item_mutex);
21311e1ddd6cScth 
21321e1ddd6cScth 	return (rval);
21331e1ddd6cScth }
21341e1ddd6cScth 
21351e1ddd6cScth /* ARGSUSED */
21361e1ddd6cScth static int
vhci_mpapi_ioctl(dev_t dev,struct scsi_vhci * vhci,void * udata,mp_iocdata_t * mpioc,int mode,cred_t * credp)21371e1ddd6cScth vhci_mpapi_ioctl(dev_t dev, struct scsi_vhci *vhci, void *udata,
21384e40636aSToomas Soome     mp_iocdata_t *mpioc, int mode, cred_t *credp)
21391e1ddd6cScth {
21401e1ddd6cScth 	int		rval = 0;
21411e1ddd6cScth 	uint64_t	oid;
21421e1ddd6cScth 	void		*input_data = NULL, *output_data = NULL;
21431e1ddd6cScth 
21441e1ddd6cScth 	/* validate mpioc */
21451e1ddd6cScth 	rval = vhci_mpapi_validate(udata, mpioc, mode, credp);
21461e1ddd6cScth 
21471e1ddd6cScth 	if (rval == EINVAL) {
21481e1ddd6cScth 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_mpapi_ioctl: "
21491e1ddd6cScth 		    " vhci_mpapi_validate() Returned %x: INVALID DATA", rval));
21501e1ddd6cScth 		if (vhci_mpapi_copyout_iocdata(mpioc, udata, mode)) {
21511e1ddd6cScth 			VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_mpapi_ioctl: "
21521e1ddd6cScth 			    "vhci_mpapi_copyout_iocdata FAILED in EINVAL"));
21531e1ddd6cScth 		}
21541e1ddd6cScth 		return (rval);
21551e1ddd6cScth 	} else if (rval == EPERM) {
21561e1ddd6cScth 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_mpapi_ioctl: "
21571e1ddd6cScth 		    " vhci_mpapi_validate() Returned %x: NO CREDS", rval));
21581e1ddd6cScth 		if (vhci_mpapi_copyout_iocdata(mpioc, udata, mode)) {
21591e1ddd6cScth 			VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_mpapi_ioctl: "
21601e1ddd6cScth 			    "vhci_mpapi_copyout_iocdata FAILED in EPERM"));
21611e1ddd6cScth 		}
21621e1ddd6cScth 		return (rval);
21631e1ddd6cScth 	/* Process good cases & also cases where we need to get correct alen */
21641e1ddd6cScth 	} else if ((rval == 0) || (rval == MP_MORE_DATA)) {
21651e1ddd6cScth 		/* allocate an input buffer */
21661e1ddd6cScth 		if ((mpioc->mp_ibuf) && (mpioc->mp_ilen != 0)) {
21671e1ddd6cScth 			input_data = kmem_zalloc(mpioc->mp_ilen,
21681e1ddd6cScth 			    KM_SLEEP);
21691e1ddd6cScth 			ASSERT(input_data != NULL);
21701e1ddd6cScth 			rval = ddi_copyin(mpioc->mp_ibuf,
21711e1ddd6cScth 			    input_data, mpioc->mp_ilen, mode);
21721e1ddd6cScth 			oid = (uint64_t)(*((uint64_t *)input_data));
21731e1ddd6cScth 
21741e1ddd6cScth 			VHCI_DEBUG(7, (CE_NOTE, NULL, "Requesting op for "
21751e1ddd6cScth 			    "OID = %lx w/ mpioc = %p mp_cmd = %x\n",
21761e1ddd6cScth 			    (long)oid, (void *)mpioc, mpioc->mp_cmd));
21771e1ddd6cScth 
21781e1ddd6cScth 		}
21791e1ddd6cScth 		if ((mpioc->mp_xfer == MP_XFER_READ) && (mpioc->mp_olen != 0)) {
21801e1ddd6cScth 			output_data = kmem_zalloc(mpioc->mp_olen, KM_SLEEP);
21811e1ddd6cScth 			ASSERT(output_data != NULL);
21821e1ddd6cScth 		}
21831e1ddd6cScth 	}
21841e1ddd6cScth 
21851e1ddd6cScth 	if (vhci_mpapi_sync_lu_oid_list(vhci) != 0) {
21861e1ddd6cScth 		VHCI_DEBUG(1, (CE_WARN, NULL, "!vhci_mpapi_ioctl: "
21871e1ddd6cScth 		    "vhci_mpapi_sync_lu_oid_list() failed"));
21881e1ddd6cScth 	}
21891e1ddd6cScth 	mdi_vhci_walk_phcis(vhci->vhci_dip,
21901e1ddd6cScth 	    vhci_mpapi_sync_init_port_list, vhci);
21911e1ddd6cScth 
21921e1ddd6cScth 	/* process ioctls */
21931e1ddd6cScth 	switch (mpioc->mp_cmd) {
21941e1ddd6cScth 	case MP_GET_DRIVER_PROP:
21951e1ddd6cScth 		rval = vhci_get_driver_prop(vhci, mpioc,
21961e1ddd6cScth 		    input_data, output_data, mode);
21971e1ddd6cScth 		break;
21981e1ddd6cScth 	case MP_GET_DEV_PROD_LIST:
21991e1ddd6cScth 		rval = vhci_get_dev_prod_list(vhci, mpioc,
22001e1ddd6cScth 		    input_data, output_data, mode);
22011e1ddd6cScth 		break;
22021e1ddd6cScth 	case MP_GET_DEV_PROD_PROP:
22031e1ddd6cScth 		rval = vhci_get_dev_prod_prop(vhci, mpioc,
22041e1ddd6cScth 		    input_data, output_data, mode);
22051e1ddd6cScth 		break;
22061e1ddd6cScth 	case MP_GET_LU_LIST:
22071e1ddd6cScth 		rval = vhci_get_lu_list(vhci, mpioc,
22081e1ddd6cScth 		    input_data, output_data, mode);
22091e1ddd6cScth 		break;
22101e1ddd6cScth 	case MP_GET_LU_LIST_FROM_TPG:
22111e1ddd6cScth 		rval = vhci_get_lu_list_from_tpg(vhci, mpioc,
22121e1ddd6cScth 		    input_data, output_data, mode);
22131e1ddd6cScth 		break;
22141e1ddd6cScth 	case MP_GET_TPG_LIST_FOR_LU:
22151e1ddd6cScth 		rval = vhci_get_tpg_list_for_lu(vhci, mpioc,
22161e1ddd6cScth 		    input_data, output_data, mode);
22171e1ddd6cScth 		break;
22181e1ddd6cScth 	case MP_GET_LU_PROP:
22191e1ddd6cScth 		rval = vhci_get_lu_prop(vhci, mpioc,
22201e1ddd6cScth 		    input_data, output_data, mode);
22211e1ddd6cScth 		break;
22221e1ddd6cScth 	case MP_GET_PATH_LIST_FOR_MP_LU:
22231e1ddd6cScth 		rval = vhci_get_path_list_for_mp_lu(vhci, mpioc,
22241e1ddd6cScth 		    input_data, output_data, mode);
22251e1ddd6cScth 		break;
22261e1ddd6cScth 	case MP_GET_PATH_LIST_FOR_INIT_PORT:
22271e1ddd6cScth 		rval = vhci_get_path_list_for_init_port(vhci, mpioc,
22281e1ddd6cScth 		    input_data, output_data, mode);
22291e1ddd6cScth 		break;
22301e1ddd6cScth 	case MP_GET_PATH_LIST_FOR_TARGET_PORT:
22311e1ddd6cScth 		rval = vhci_get_path_list_for_target_port(vhci, mpioc,
22321e1ddd6cScth 		    input_data, output_data, mode);
22331e1ddd6cScth 		break;
22341e1ddd6cScth 	case MP_GET_PATH_PROP:
22351e1ddd6cScth 		rval = vhci_get_path_prop(vhci, mpioc,
22361e1ddd6cScth 		    input_data, output_data, mode);
22371e1ddd6cScth 		break;
22381e1ddd6cScth 	case MP_GET_INIT_PORT_LIST: /* Not Required */
22391e1ddd6cScth 		rval = vhci_get_init_port_list(vhci, mpioc,
22401e1ddd6cScth 		    input_data, output_data, mode);
22411e1ddd6cScth 		break;
22421e1ddd6cScth 	case MP_GET_INIT_PORT_PROP:
22431e1ddd6cScth 		rval = vhci_get_init_port_prop(vhci, mpioc,
22441e1ddd6cScth 		    input_data, output_data, mode);
22451e1ddd6cScth 		break;
22461e1ddd6cScth 	case MP_GET_TARGET_PORT_PROP:
22471e1ddd6cScth 		rval = vhci_get_target_port_prop(vhci, mpioc,
22481e1ddd6cScth 		    input_data, output_data, mode);
22491e1ddd6cScth 		break;
22501e1ddd6cScth 	case MP_GET_TPG_LIST: /* Not Required */
22511e1ddd6cScth 		rval = vhci_get_tpg_list_for_lu(vhci, mpioc,
22521e1ddd6cScth 		    input_data, output_data, mode);
22531e1ddd6cScth 		break;
22541e1ddd6cScth 	case MP_GET_TPG_PROP:
22551e1ddd6cScth 		rval = vhci_get_tpg_prop(vhci, mpioc,
22561e1ddd6cScth 		    input_data, output_data, mode);
22571e1ddd6cScth 		break;
22581e1ddd6cScth 	case MP_GET_TARGET_PORT_LIST_FOR_TPG:
22591e1ddd6cScth 		rval = vhci_get_target_port_list_for_tpg(vhci, mpioc,
22601e1ddd6cScth 		    input_data, output_data, mode);
22611e1ddd6cScth 		break;
22621e1ddd6cScth 	case MP_SET_TPG_ACCESS_STATE:
22631e1ddd6cScth 		rval = vhci_set_tpg_access_state(vhci, mpioc,
22641e1ddd6cScth 		    input_data, output_data, mode);
22651e1ddd6cScth 		break;
22661e1ddd6cScth 	case MP_ASSIGN_LU_TO_TPG:
22671e1ddd6cScth 		rval = vhci_assign_lu_to_tpg(vhci, mpioc,
22681e1ddd6cScth 		    input_data, output_data, mode);
22691e1ddd6cScth 		break;
22701e1ddd6cScth 	case MP_GET_PROPRIETARY_LOADBALANCE_LIST:
22711e1ddd6cScth 		rval = vhci_get_prop_lb_list(vhci, mpioc,
22721e1ddd6cScth 		    input_data, output_data, mode);
22731e1ddd6cScth 		break;
22741e1ddd6cScth 	case MP_GET_PROPRIETARY_LOADBALANCE_PROP:
22751e1ddd6cScth 		rval = vhci_get_prop_lb_prop(vhci, mpioc,
22761e1ddd6cScth 		    input_data, output_data, mode);
22771e1ddd6cScth 		break;
22781e1ddd6cScth 	case MP_ENABLE_AUTO_FAILBACK:
22791e1ddd6cScth 		rval = vhci_enable_auto_failback(vhci, mpioc,
22801e1ddd6cScth 		    input_data, output_data, mode);
22811e1ddd6cScth 		break;
22821e1ddd6cScth 	case MP_DISABLE_AUTO_FAILBACK:
22831e1ddd6cScth 		rval = vhci_disable_auto_failback(vhci, mpioc,
22841e1ddd6cScth 		    input_data, output_data, mode);
22851e1ddd6cScth 		break;
22861e1ddd6cScth 	case MP_ENABLE_PATH:
22871e1ddd6cScth 		rval = vhci_enable_path(vhci, mpioc,
22881e1ddd6cScth 		    input_data, output_data, mode);
22891e1ddd6cScth 		break;
22901e1ddd6cScth 	case MP_DISABLE_PATH:
22911e1ddd6cScth 		rval = vhci_disable_path(vhci, mpioc,
22921e1ddd6cScth 		    input_data, output_data, mode);
22931e1ddd6cScth 		break;
22941e1ddd6cScth 	case MP_SEND_SCSI_CMD:
22951e1ddd6cScth 		rval = vhci_send_uscsi_cmd(dev, vhci, mpioc,
22961e1ddd6cScth 		    input_data, output_data, mode);
22971e1ddd6cScth 		break;
22981e1ddd6cScth 	default:
22991e1ddd6cScth 		rval = EINVAL;
23001e1ddd6cScth 		break;
23011e1ddd6cScth 	}
23021e1ddd6cScth 
23031e1ddd6cScth 	VHCI_DEBUG(6, (CE_NOTE, NULL, "vhci_mpapi_ioctl: output_data = %p, "
23041e1ddd6cScth 	    "mp_obuf = %p, mp_olen = %lx, mp_alen = %lx, mp_errno = %x, "
23051e1ddd6cScth 	    "mode = %x, rval=%x\n", (void *)output_data, (void *)mpioc->mp_obuf,
23061e1ddd6cScth 	    mpioc->mp_olen, mpioc->mp_alen, mpioc->mp_errno, mode, rval));
23071e1ddd6cScth 
23081e1ddd6cScth 	if (vhci_mpapi_copyout_iocdata(mpioc, udata, mode)) {
23091e1ddd6cScth 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_mpapi_ioctl: "
23101e1ddd6cScth 		    "vhci_mpapi_copyout_iocdata FAILED"));
23111e1ddd6cScth 		rval = EFAULT;
23121e1ddd6cScth 	}
23131e1ddd6cScth 
23141e1ddd6cScth 	if (input_data) {
23151e1ddd6cScth 		kmem_free(input_data, mpioc->mp_ilen);
23161e1ddd6cScth 	}
23171e1ddd6cScth 
23181e1ddd6cScth 	if (output_data) {
23191e1ddd6cScth 		kmem_free(output_data, mpioc->mp_olen);
23201e1ddd6cScth 	}
23211e1ddd6cScth 
23221e1ddd6cScth 	return (rval);
23231e1ddd6cScth }
23241e1ddd6cScth 
23251e1ddd6cScth /* ARGSUSED */
23261e1ddd6cScth int
vhci_mpapi_init(struct scsi_vhci * vhci)23271e1ddd6cScth vhci_mpapi_init(struct scsi_vhci *vhci)
23281e1ddd6cScth {
23291e1ddd6cScth 	mpapi_item_list_t	*ilist;
23301e1ddd6cScth 	mpapi_item_t		*item;
23311e1ddd6cScth 	mp_driver_prop_t	*drv;
23321e1ddd6cScth 	uint8_t			i;
23331e1ddd6cScth 
23341e1ddd6cScth 	/*
23351e1ddd6cScth 	 * This tstamp value is present in the upper 32-bits of all OIDs
23361e1ddd6cScth 	 * that are issued in this boot session. Use it to identify
23371e1ddd6cScth 	 * stale OIDs that an application/ioctl may pass to you and
23381e1ddd6cScth 	 * reject it - Done in vhci_mpapi_validate() routine.
23391e1ddd6cScth 	 */
23401e1ddd6cScth 	mutex_enter(&tod_lock);
23411e1ddd6cScth 	vhci->mp_priv->tstamp = (time32_t)(tod_get().tv_sec);
23421e1ddd6cScth 	mutex_exit(&tod_lock);
23431e1ddd6cScth 
23441e1ddd6cScth 	for (i = 0; i < MP_MAX_OBJECT_TYPE; i++) {
23451e1ddd6cScth 		vhci->mp_priv->obj_hdr_list[i] = vhci_mpapi_create_list_head();
23461e1ddd6cScth 	}
23471e1ddd6cScth 
23481e1ddd6cScth 	/*
23491e1ddd6cScth 	 * Let us now allocate and initialize the drv block.
23501e1ddd6cScth 	 */
23511e1ddd6cScth 	ilist = kmem_zalloc(sizeof (mpapi_item_list_t), KM_SLEEP);
23521e1ddd6cScth 	item = kmem_zalloc(sizeof (mpapi_item_t), KM_SLEEP);
23531e1ddd6cScth 	ilist->item = item;
23541e1ddd6cScth 	item->oid.raw_oid = vhci_mpapi_create_oid(vhci->mp_priv,
23551e1ddd6cScth 	    MP_OBJECT_TYPE_PLUGIN);
23561e1ddd6cScth 	drv = kmem_zalloc(sizeof (mp_driver_prop_t), KM_SLEEP);
23571e1ddd6cScth 	drv->driverVersion[0] = '\0';
23581e1ddd6cScth 	drv->supportedLoadBalanceTypes =
23591e1ddd6cScth 	    (MP_DRVR_LOAD_BALANCE_TYPE_ROUNDROBIN |
23601e1ddd6cScth 	    MP_DRVR_LOAD_BALANCE_TYPE_LBA_REGION);
23611e1ddd6cScth 	drv->canSetTPGAccess = TRUE;
23621e1ddd6cScth 	drv->canOverridePaths = FALSE;
23631e1ddd6cScth 	drv->exposesPathDeviceFiles = FALSE;
23641e1ddd6cScth 	drv->deviceFileNamespace[0] = '\0';
23651e1ddd6cScth 	drv->onlySupportsSpecifiedProducts = 1;
23661e1ddd6cScth 	drv->maximumWeight = 1;
23671e1ddd6cScth 	drv->failbackPollingRateMax = 0;
23681e1ddd6cScth 	drv->currentFailbackPollingRate = 0;
23691e1ddd6cScth 	drv->autoFailbackSupport = 1;
23701e1ddd6cScth 	drv->autoFailbackEnabled = 1;
23711e1ddd6cScth 	drv->defaultLoadBalanceType = MP_DRVR_LOAD_BALANCE_TYPE_ROUNDROBIN;
23721e1ddd6cScth 	drv->probingPollingRateMax = 0;
23731e1ddd6cScth 	drv->currentProbingPollingRate = 0;
23741e1ddd6cScth 	drv->autoProbingSupport = 0;
23751e1ddd6cScth 	drv->autoProbingEnabled = 0;
23761e1ddd6cScth 	item->idata = drv;
23771e1ddd6cScth 	mutex_init(&item->item_mutex, NULL, MUTEX_DRIVER, NULL);
23781e1ddd6cScth 	if (vhci_mpapi_add_to_list(vhci->mp_priv->obj_hdr_list
23791e1ddd6cScth 	    [MP_OBJECT_TYPE_PLUGIN], ilist) != 0) {
23801e1ddd6cScth 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_mpapi_init: "
23811e1ddd6cScth 		    "vhci_mpapi_create_add_to_list() of PLUGIN failed"));
23821e1ddd6cScth 		return (EFAULT);
23831e1ddd6cScth 
23841e1ddd6cScth 	}
23851e1ddd6cScth 	return (0);
23861e1ddd6cScth }
23871e1ddd6cScth 
23881e1ddd6cScth void
vhci_mpapi_add_dev_prod(struct scsi_vhci * vhci,char * vidpid)23891e1ddd6cScth vhci_mpapi_add_dev_prod(struct scsi_vhci *vhci, char *vidpid)
23901e1ddd6cScth {
23911e1ddd6cScth 	mpapi_item_list_t	*dev_prod_list;
23921e1ddd6cScth 	mpapi_item_t		*dev_prod_item;
23931e1ddd6cScth 	mp_dev_prod_prop_t	*dev_prod;
23941e1ddd6cScth 
23951e1ddd6cScth 	/* add to list */
23961e1ddd6cScth 	dev_prod_list = kmem_zalloc(sizeof (mpapi_item_list_t), KM_SLEEP);
23971e1ddd6cScth 	dev_prod_item = kmem_zalloc(sizeof (mpapi_item_t), KM_SLEEP);
23981e1ddd6cScth 	dev_prod_list->item = dev_prod_item;
23991e1ddd6cScth 	dev_prod_list->item->oid.raw_oid = vhci_mpapi_create_oid
24001e1ddd6cScth 	    (vhci->mp_priv, MP_OBJECT_TYPE_DEVICE_PRODUCT);
24011e1ddd6cScth 	dev_prod = kmem_zalloc(sizeof (mp_dev_prod_prop_t), KM_SLEEP);
24021e1ddd6cScth 
24031e1ddd6cScth 	(void) strncpy(dev_prod->prodInfo.vendor, vidpid, strlen(vidpid));
24041e1ddd6cScth 	dev_prod->supportedLoadBalanceTypes =
24051e1ddd6cScth 	    MP_DRVR_LOAD_BALANCE_TYPE_ROUNDROBIN;
24061e1ddd6cScth 	dev_prod->id = dev_prod_list->item->oid.raw_oid;
24071e1ddd6cScth 
24081e1ddd6cScth 	dev_prod_list->item->idata = dev_prod;
24091e1ddd6cScth 	(void) vhci_mpapi_add_to_list(vhci->mp_priv->obj_hdr_list
24101e1ddd6cScth 	    [MP_OBJECT_TYPE_DEVICE_PRODUCT], (void *)dev_prod_list);
24111e1ddd6cScth 	vhci_mpapi_log_sysevent(vhci->vhci_dip,
24121e1ddd6cScth 	    &(dev_prod_list->item->oid.raw_oid),
24131e1ddd6cScth 	    ESC_SUN_MP_DEV_PROD_ADD);
24141e1ddd6cScth }
24151e1ddd6cScth 
24161e1ddd6cScth /* ARGSUSED */
24171e1ddd6cScth static uint64_t
vhci_mpapi_create_oid(mpapi_priv_t * mp_priv,uint8_t obj_type)24181e1ddd6cScth vhci_mpapi_create_oid(mpapi_priv_t *mp_priv, uint8_t obj_type)
24191e1ddd6cScth {
24201e1ddd6cScth 	mpoid_t		oid;
24211e1ddd6cScth 
24221e1ddd6cScth 	oid.disc_oid.tstamp = mp_priv->tstamp;
24231e1ddd6cScth 	oid.disc_oid.type = obj_type;
24241e1ddd6cScth 	oid.disc_oid.seq_id = ++(mp_priv->oid_seq[obj_type]);
24251e1ddd6cScth 	return (oid.raw_oid);
24261e1ddd6cScth }
24271e1ddd6cScth 
24281e1ddd6cScth /* ARGSUSED */
24291e1ddd6cScth static int
vhci_mpapi_add_to_list(mpapi_list_header_t * hdr,mpapi_item_list_t * item)24301e1ddd6cScth vhci_mpapi_add_to_list(mpapi_list_header_t *hdr, mpapi_item_list_t *item)
24311e1ddd6cScth {
24321e1ddd6cScth 
24331e1ddd6cScth 	mpapi_list_header_t	*tmp_hdr = hdr;
24341e1ddd6cScth 	mpapi_item_list_t	*tmp_item = item;
24351e1ddd6cScth 
24361e1ddd6cScth 	if (item == NULL) {
24371e1ddd6cScth 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_mpapi_add_to_list: "
24381e1ddd6cScth 		    "NULL item passed"));
24391e1ddd6cScth 		return (EFAULT);
24401e1ddd6cScth 	}
24411e1ddd6cScth 	if (hdr == NULL) {
24421e1ddd6cScth 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_mpapi_add_to_list: "
24431e1ddd6cScth 		    "NULL hdr passed"));
24441e1ddd6cScth 		return (EFAULT);
24451e1ddd6cScth 	}
24461e1ddd6cScth 	/*
24471e1ddd6cScth 	 * Check if the item is already there in the list.
24481e1ddd6cScth 	 * Catches duplicates while assigning TPGs.
24491e1ddd6cScth 	 */
24501e1ddd6cScth 	tmp_item = tmp_hdr->head;
24511e1ddd6cScth 	while (tmp_item != NULL) {
24521e1ddd6cScth 		if (item == tmp_item) {
24531e1ddd6cScth 			VHCI_DEBUG(4, (CE_WARN, NULL, "vhci_mpapi_add_to_list: "
24541e1ddd6cScth 			    "Item already in list"));
24551e1ddd6cScth 			return (1);
24561e1ddd6cScth 		} else {
24571e1ddd6cScth 			tmp_item = tmp_item->next;
24581e1ddd6cScth 		}
24591e1ddd6cScth 	}
24601e1ddd6cScth 
24611e1ddd6cScth 	item->next = NULL;
24621e1ddd6cScth 	if (hdr->head == NULL) {
24631e1ddd6cScth 		hdr->head = item;
24641e1ddd6cScth 		hdr->tail = item;
24651e1ddd6cScth 	} else {
24661e1ddd6cScth 		hdr->tail->next = item;
24671e1ddd6cScth 		hdr->tail = item;
24681e1ddd6cScth 	}
24691e1ddd6cScth 
24701e1ddd6cScth 	return (0);
24711e1ddd6cScth }
24721e1ddd6cScth 
24731e1ddd6cScth /*
24741e1ddd6cScth  * Local convenience routine to fetch reference to a mpapi item entry if it
24751e1ddd6cScth  * exits based on the pointer to the vhci resource that is passed.
24761e1ddd6cScth  * Returns NULL if no entry is found.
24771e1ddd6cScth  */
24781e1ddd6cScth /* ARGSUSED */
24791e1ddd6cScth void*
vhci_get_mpapi_item(struct scsi_vhci * vhci,mpapi_list_header_t * list,uint8_t obj_type,void * res)24801e1ddd6cScth vhci_get_mpapi_item(struct scsi_vhci *vhci,  mpapi_list_header_t *list,
24811e1ddd6cScth     uint8_t obj_type, void* res)
24821e1ddd6cScth {
24831e1ddd6cScth 	mpapi_item_list_t	*ilist;
24841e1ddd6cScth 
24851e1ddd6cScth 	if (list == NULL) {
24861e1ddd6cScth 		/*
24871e1ddd6cScth 		 * Since the listhead is null, the search is being
24881e1ddd6cScth 		 * performed in implicit mode - that is to use the
24891e1ddd6cScth 		 * level one list.
24901e1ddd6cScth 		 */
24911e1ddd6cScth 		ilist = vhci->mp_priv->obj_hdr_list[obj_type]->head;
24921e1ddd6cScth 	} else {
24931e1ddd6cScth 		/*
24941e1ddd6cScth 		 * The search is being performed on a sublist within
24951e1ddd6cScth 		 * one of the toplevel list items. Use the listhead
24961e1ddd6cScth 		 * that is passed in.
24971e1ddd6cScth 		 */
24981e1ddd6cScth 		ilist = list->head;
24991e1ddd6cScth 	}
25001e1ddd6cScth 
25011e1ddd6cScth 	if (res == NULL) {
25021e1ddd6cScth 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_get_mpapi_item: "
25031e1ddd6cScth 		    " Got Item w/ NULL resource ptr"));
25041e1ddd6cScth 		return (NULL);
25051e1ddd6cScth 	}
25061e1ddd6cScth 
25071e1ddd6cScth 	/*
25081e1ddd6cScth 	 * Since the resource field within the item data is specific
25091e1ddd6cScth 	 * to a particular object type, we need to use the object type
25101e1ddd6cScth 	 * to enable us to perform the search and compare appropriately.
25111e1ddd6cScth 	 */
25121e1ddd6cScth 	switch (obj_type) {
25131e1ddd6cScth 		case	MP_OBJECT_TYPE_INITIATOR_PORT:
25141e1ddd6cScth 			while (ilist) {
25151e1ddd6cScth 				void	*wwn = ((mpapi_initiator_data_t *)
25161e1ddd6cScth 				    ilist->item->idata)->resp;
25171e1ddd6cScth 				if (strncmp(wwn, res, strlen(res)) == 0) {
25181e1ddd6cScth 					/* Found a match */
25191e1ddd6cScth 					return ((void*)ilist);
25201e1ddd6cScth 				}
25211e1ddd6cScth 				ilist = ilist->next;
25221e1ddd6cScth 			}
25231e1ddd6cScth 		break;
25241e1ddd6cScth 
25251e1ddd6cScth 		case	MP_OBJECT_TYPE_TARGET_PORT:
25261e1ddd6cScth 			while (ilist) {
25271e1ddd6cScth 				void	*wwn = ((mpapi_tport_data_t *)ilist->
25281e1ddd6cScth 				    item->idata)->resp;
25291e1ddd6cScth 				if (strncmp(wwn, res, strlen(res)) == 0) {
25301e1ddd6cScth 					/* Found a match */
25311e1ddd6cScth 					return ((void*)ilist);
25321e1ddd6cScth 				}
25331e1ddd6cScth 				ilist = ilist->next;
25341e1ddd6cScth 			}
25351e1ddd6cScth 		break;
25361e1ddd6cScth 
25371e1ddd6cScth 		case	MP_OBJECT_TYPE_TARGET_PORT_GROUP:
25381e1ddd6cScth 			/*
25391e1ddd6cScth 			 * For TPG Synthesis, Use TPG specific routines
25401e1ddd6cScth 			 * Use this case only for ALUA devices which give TPG ID
25411e1ddd6cScth 			 */
25421e1ddd6cScth 			while (ilist) {
25431e1ddd6cScth 				void	*tpg_id = ((mpapi_tpg_data_t *)ilist->
25441e1ddd6cScth 				    item->idata)->resp;
25451e1ddd6cScth 				if (strncmp(tpg_id, res, strlen(res)) == 0) {
25461e1ddd6cScth 					/* Found a match */
25471e1ddd6cScth 					return ((void*)ilist);
25481e1ddd6cScth 				}
25491e1ddd6cScth 				ilist = ilist->next;
25501e1ddd6cScth 			}
25511e1ddd6cScth 		break;
25521e1ddd6cScth 
25531e1ddd6cScth 		case	MP_OBJECT_TYPE_MULTIPATH_LU:
25541e1ddd6cScth 			return ((void *)(vhci_mpapi_match_lu
25551e1ddd6cScth 			    (vhci, ilist, res)));
25561e1ddd6cScth 
25571e1ddd6cScth 		case	MP_OBJECT_TYPE_PATH_LU:
25581e1ddd6cScth 			return ((void *)(vhci_mpapi_match_pip
25591e1ddd6cScth 			    (vhci, ilist, res)));
25601e1ddd6cScth 
25611e1ddd6cScth 		default:
25621e1ddd6cScth 			/*
25631e1ddd6cScth 			 * This should not happen
25641e1ddd6cScth 			 */
25651e1ddd6cScth 			VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_get_mpapi_item:"
25661e1ddd6cScth 			    "Got Unsupported OBJECT TYPE"));
25671e1ddd6cScth 			return (NULL);
25681e1ddd6cScth 	}
25691e1ddd6cScth 	return (NULL);
25701e1ddd6cScth }
25711e1ddd6cScth 
25721e1ddd6cScth /*
25731e1ddd6cScth  * Local convenience routine to create and initialize mpapi item
25741e1ddd6cScth  * based on the object type passed.
25751e1ddd6cScth  */
25761e1ddd6cScth /* ARGSUSED */
25771e1ddd6cScth static mpapi_item_list_t *
vhci_mpapi_create_item(struct scsi_vhci * vhci,uint8_t obj_type,void * res)25781e1ddd6cScth vhci_mpapi_create_item(struct scsi_vhci *vhci, uint8_t obj_type, void* res)
25791e1ddd6cScth {
25801e1ddd6cScth 	int			major;
25811e1ddd6cScth 	int			instance;
25821e1ddd6cScth 	mpapi_item_list_t	*ilist;
25831e1ddd6cScth 	mpapi_item_t		*item;
25841e1ddd6cScth 	char			*pname = NULL;
25851e1ddd6cScth 
25861e1ddd6cScth 	ilist = kmem_zalloc(sizeof (mpapi_item_list_t), KM_SLEEP);
25871e1ddd6cScth 	item = kmem_zalloc(sizeof (mpapi_item_t), KM_SLEEP);
25881e1ddd6cScth 	mutex_init(&item->item_mutex, NULL, MUTEX_DRIVER, NULL);
25891e1ddd6cScth 	ilist->item = item;
25901e1ddd6cScth 	item->oid.raw_oid = 0;
25911e1ddd6cScth 
25921e1ddd6cScth 	switch (obj_type) {
25931e1ddd6cScth 		case	MP_OBJECT_TYPE_INITIATOR_PORT:
25941e1ddd6cScth 		{
25951e1ddd6cScth 			mpapi_initiator_data_t	*init;
25961e1ddd6cScth 			dev_info_t		*pdip = res;
25971e1ddd6cScth 			char			*init_port_res;
25981e1ddd6cScth 			char			*interconnect;
25991e1ddd6cScth 			int			mp_interconnect_type, len;
26001e1ddd6cScth 			int			prop_not_ddi_alloced = 0;
26011e1ddd6cScth 
26021e1ddd6cScth 			pname = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
26031e1ddd6cScth 			major = (int)ddi_driver_major(pdip);
26041e1ddd6cScth 			instance = ddi_get_instance(pdip);
26051e1ddd6cScth 			(void) ddi_pathname(pdip, pname);
26061e1ddd6cScth 			item->oid.raw_oid =
26071e1ddd6cScth 			    MP_STORE_INST_TO_ID(instance, item->oid.raw_oid);
26081e1ddd6cScth 			item->oid.raw_oid =
26091e1ddd6cScth 			    MP_STORE_MAJOR_TO_ID(major, item->oid.raw_oid);
26101e1ddd6cScth 			/*
26111e1ddd6cScth 			 * Just make a call to keep correct Sequence count.
26121e1ddd6cScth 			 * Don't use the OID returned though.
26131e1ddd6cScth 			 */
26141e1ddd6cScth 			(void) vhci_mpapi_create_oid(vhci->mp_priv, obj_type);
26151e1ddd6cScth 			init_port_res = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
26161e1ddd6cScth 			(void) strlcpy(init_port_res, pname, MAXPATHLEN);
26171e1ddd6cScth 
26181e1ddd6cScth 			if ((ddi_prop_lookup_string(DDI_DEV_T_ANY, pdip, 0,
26191e1ddd6cScth 			    "initiator-interconnect-type",
26201e1ddd6cScth 			    &interconnect) != DDI_PROP_SUCCESS)) {
26211e1ddd6cScth 				/* XXX: initiator-interconnect-type not set */
26221e1ddd6cScth 				VHCI_DEBUG(1, (CE_WARN, NULL,
26231e1ddd6cScth 				    "vhci_mpapi_create_item: initiator-"
26241e1ddd6cScth 				    "-interconnect-type prop not found"));
26254e40636aSToomas Soome 				len = strlen("UNKNOWN") + 1;
26261e1ddd6cScth 				interconnect = kmem_zalloc(len, KM_SLEEP);
26271e1ddd6cScth 				(void) strlcpy(interconnect, "UNKNOWN", len);
26281e1ddd6cScth 				prop_not_ddi_alloced = 1;
26291e1ddd6cScth 			}
26301e1ddd6cScth 			/*
26311e1ddd6cScth 			 * Map the initiator-interconnect-type values between
26321e1ddd6cScth 			 * SCSA(as defined in services.h) and MPAPI
26331e1ddd6cScth 			 * (as defined in mpapi_impl.h)
26341e1ddd6cScth 			 */
26351e1ddd6cScth 			if (strncmp(interconnect,
26361e1ddd6cScth 			    INTERCONNECT_FABRIC_STR,
26371e1ddd6cScth 			    strlen(interconnect)) == 0) {
26384c06356bSdh 				mp_interconnect_type =
26394c06356bSdh 				    MP_DRVR_TRANSPORT_TYPE_FC;
26401e1ddd6cScth 			} else if (strncmp(interconnect,
26411e1ddd6cScth 			    INTERCONNECT_PARALLEL_STR,
26421e1ddd6cScth 			    strlen(interconnect)) == 0) {
26434c06356bSdh 				mp_interconnect_type =
26444c06356bSdh 				    MP_DRVR_TRANSPORT_TYPE_SPI;
26451e1ddd6cScth 			} else if (strncmp(interconnect,
26461e1ddd6cScth 			    INTERCONNECT_ISCSI_STR,
26471e1ddd6cScth 			    strlen(interconnect)) == 0) {
26484c06356bSdh 				mp_interconnect_type =
26494c06356bSdh 				    MP_DRVR_TRANSPORT_TYPE_ISCSI;
26501e1ddd6cScth 			} else if (strncmp(interconnect,
26511e1ddd6cScth 			    INTERCONNECT_IBSRP_STR,
26521e1ddd6cScth 			    strlen(interconnect)) == 0) {
26534c06356bSdh 				mp_interconnect_type =
26544c06356bSdh 				    MP_DRVR_TRANSPORT_TYPE_IFB;
26551e1ddd6cScth 			} else {
26564c06356bSdh 				mp_interconnect_type =
26574c06356bSdh 				    MP_DRVR_TRANSPORT_TYPE_UNKNOWN;
26581e1ddd6cScth 			}
26591e1ddd6cScth 
26601e1ddd6cScth 			init = kmem_zalloc(
26611e1ddd6cScth 			    sizeof (mpapi_initiator_data_t), KM_SLEEP);
26621e1ddd6cScth 			init->resp = init_port_res;
26631e1ddd6cScth 			init->valid = 1;
26641e1ddd6cScth 			init->prop.id = item->oid.raw_oid;
26651e1ddd6cScth 			init->prop.portType = mp_interconnect_type;
26661e1ddd6cScth 			(void) strlcpy(init->prop.portID, pname,
26671e1ddd6cScth 			    sizeof (init->prop.portID));
26681e1ddd6cScth 			(void) strlcpy(init->prop.osDeviceFile, "/devices",
26691e1ddd6cScth 			    sizeof (init->prop.osDeviceFile));
26701e1ddd6cScth 			(void) strlcat(init->prop.osDeviceFile, pname,
26711e1ddd6cScth 			    sizeof (init->prop.osDeviceFile));
26721e1ddd6cScth 			init->path_list = vhci_mpapi_create_list_head();
26731e1ddd6cScth 			item->idata = (void *)init;
26741e1ddd6cScth 			vhci_mpapi_log_sysevent(vhci->vhci_dip,
26751e1ddd6cScth 			    &(item->oid.raw_oid), ESC_SUN_MP_INIT_PORT_CHANGE);
26761e1ddd6cScth 
26771e1ddd6cScth 			if (prop_not_ddi_alloced != 1) {
26781e1ddd6cScth 				ddi_prop_free(interconnect);
26791e1ddd6cScth 			} else {
26801e1ddd6cScth 				kmem_free(interconnect, len);
26811e1ddd6cScth 			}
26821e1ddd6cScth 			if (pname) {
26831e1ddd6cScth 				kmem_free(pname, MAXPATHLEN);
26841e1ddd6cScth 			}
26851e1ddd6cScth 		}
26861e1ddd6cScth 		break;
26871e1ddd6cScth 
26881e1ddd6cScth 		case	MP_OBJECT_TYPE_TARGET_PORT:
26891e1ddd6cScth 		{
26901e1ddd6cScth 			mpapi_tport_data_t	*tport;
26911e1ddd6cScth 			char			*tgt_port_res;
26921e1ddd6cScth 
26931e1ddd6cScth 			item->oid.raw_oid =
26941e1ddd6cScth 			    vhci_mpapi_create_oid(vhci->mp_priv, obj_type);
26951e1ddd6cScth 			tport = kmem_zalloc(sizeof (mpapi_tport_data_t),
26961e1ddd6cScth 			    KM_SLEEP);
26974e40636aSToomas Soome 			tgt_port_res = kmem_zalloc(strlen(res) + 1, KM_SLEEP);
26984e40636aSToomas Soome 			(void) strlcpy(tgt_port_res, res, strlen(res) + 1);
26991e1ddd6cScth 			tport->resp = tgt_port_res;
27001e1ddd6cScth 			tport->valid = 1;
27011e1ddd6cScth 			tport->prop.id = item->oid.raw_oid;
27021e1ddd6cScth 			tport->prop.relativePortID = 0;
27031e1ddd6cScth 			(void) strlcpy(tport->prop.portName, res,
27041e1ddd6cScth 			    sizeof (tport->prop.portName));
27051e1ddd6cScth 			tport->path_list = vhci_mpapi_create_list_head();
27061e1ddd6cScth 			item->idata = (void *)tport;
27071e1ddd6cScth 			vhci_mpapi_log_sysevent(vhci->vhci_dip,
27081e1ddd6cScth 			    &(item->oid.raw_oid), ESC_SUN_MP_TARGET_PORT_ADD);
27091e1ddd6cScth 		}
27101e1ddd6cScth 		break;
27111e1ddd6cScth 
27121e1ddd6cScth 		case	MP_OBJECT_TYPE_TARGET_PORT_GROUP:
27131e1ddd6cScth 		{
27141e1ddd6cScth 			mpapi_tpg_data_t	*tpg;
27151e1ddd6cScth 			char			*tpg_res;
27161e1ddd6cScth 
27171e1ddd6cScth 			item->oid.raw_oid =
27181e1ddd6cScth 			    vhci_mpapi_create_oid(vhci->mp_priv, obj_type);
27191e1ddd6cScth 			tpg = kmem_zalloc(
27201e1ddd6cScth 			    sizeof (mpapi_tpg_data_t), KM_SLEEP);
27214e40636aSToomas Soome 			tpg_res = kmem_zalloc(strlen(res) + 1, KM_SLEEP);
27224e40636aSToomas Soome 			(void) strlcpy(tpg_res, res, strlen(res) + 1);
27231e1ddd6cScth 			tpg->resp = tpg_res;
27241e1ddd6cScth 			tpg->valid = 1;
27251e1ddd6cScth 			tpg->prop.id = item->oid.raw_oid;
27261e1ddd6cScth 			/*
27271e1ddd6cScth 			 * T10 TPG ID is a 2 byte value. Keep up with it.
27281e1ddd6cScth 			 */
27291e1ddd6cScth 			tpg->prop.tpgId =
27301e1ddd6cScth 			    ((item->oid.raw_oid) & 0x000000000000ffff);
27311e1ddd6cScth 			tpg->tport_list = vhci_mpapi_create_list_head();
27321e1ddd6cScth 			tpg->lu_list = vhci_mpapi_create_list_head();
27331e1ddd6cScth 			item->idata = (void *)tpg;
27341e1ddd6cScth 			vhci_mpapi_log_sysevent(vhci->vhci_dip,
27351e1ddd6cScth 			    &(item->oid.raw_oid), ESC_SUN_MP_TPG_ADD);
27361e1ddd6cScth 		}
27371e1ddd6cScth 		break;
27381e1ddd6cScth 
27391e1ddd6cScth 		case	MP_OBJECT_TYPE_MULTIPATH_LU:
27401e1ddd6cScth 		{
27411e1ddd6cScth 			mpapi_lu_data_t	*lu;
27421e1ddd6cScth 			scsi_vhci_lun_t	*svl = res;
27431c8dbe37SMilos Muzik 			client_lb_t	lb_policy;
27441e1ddd6cScth 			/*
27451e1ddd6cScth 			 * We cant use ddi_get_instance(svl->svl_dip) at this
27461e1ddd6cScth 			 * point because the dip is not yet in DS_READY state.
27471e1ddd6cScth 			 */
27481e1ddd6cScth 			item->oid.raw_oid =
27491e1ddd6cScth 			    vhci_mpapi_create_oid(vhci->mp_priv, obj_type);
27501e1ddd6cScth 
27511e1ddd6cScth 			lu = kmem_zalloc(sizeof (mpapi_lu_data_t), KM_SLEEP);
27521e1ddd6cScth 			lu->resp = res;
27531e1ddd6cScth 			lu->prop.id = (uint64_t)item->oid.raw_oid;
27541e1ddd6cScth 			/*
27551e1ddd6cScth 			 * XXX: luGroupID is currently unsupported
27561e1ddd6cScth 			 */
27571e1ddd6cScth 			lu->prop.luGroupID = 0xFFFFFFFF;
27581e1ddd6cScth 
27591e1ddd6cScth 			(void) strlcpy(lu->prop.name, svl->svl_lun_wwn,
27601e1ddd6cScth 			    sizeof (lu->prop.name));
27611e1ddd6cScth 
27620c034175SJiri Svoboda 			/*
27630c034175SJiri Svoboda 			 * deviceFileName field is currently not used.
27640c034175SJiri Svoboda 			 * Set to an empty string.
27650c034175SJiri Svoboda 			 */
27660c034175SJiri Svoboda 			lu->prop.deviceFileName[0] = '\0';
27671e1ddd6cScth 
2768860de861Shtk 			if ((svl != NULL) &&
2769222e2020Swl 			    (SCSI_FAILOVER_IS_ASYM(svl) ||
2770222e2020Swl 			    SCSI_FAILOVER_IS_TPGS(svl->svl_fops))) {
27711e1ddd6cScth 				lu->prop.asymmetric = 1;
27721e1ddd6cScth 			}
27731e1ddd6cScth 
27741e1ddd6cScth 			lu->prop.autoFailbackEnabled =
27751e1ddd6cScth 			    ((VHCI_CONF_FLAGS_AUTO_FAILBACK & vhci->
27761e1ddd6cScth 			    vhci_conf_flags) ? 1 : 0);
27771e1ddd6cScth 
27781c8dbe37SMilos Muzik 			/*
27791c8dbe37SMilos Muzik 			 * Retrieve current load balance policy from mdi client.
27801c8dbe37SMilos Muzik 			 * Both client and client's dip should already exist
27811c8dbe37SMilos Muzik 			 * here and the client should be initialized.
27821c8dbe37SMilos Muzik 			 */
27831c8dbe37SMilos Muzik 			lb_policy = mdi_get_lb_policy(svl->svl_dip);
27841c8dbe37SMilos Muzik 			if (lb_policy == LOAD_BALANCE_NONE) {
27851e1ddd6cScth 				lu->prop.currentLoadBalanceType =
27861e1ddd6cScth 				    MP_DRVR_LOAD_BALANCE_TYPE_NONE;
27871c8dbe37SMilos Muzik 			} else if (lb_policy == LOAD_BALANCE_RR) {
27881e1ddd6cScth 				lu->prop.currentLoadBalanceType =
27891e1ddd6cScth 				    MP_DRVR_LOAD_BALANCE_TYPE_ROUNDROBIN;
27901c8dbe37SMilos Muzik 			} else if (lb_policy == LOAD_BALANCE_LBA) {
27911e1ddd6cScth 				lu->prop.currentLoadBalanceType =
27921e1ddd6cScth 				    MP_DRVR_LOAD_BALANCE_TYPE_LBA_REGION;
27931e1ddd6cScth 			} else {
27941e1ddd6cScth 				/*
27951e1ddd6cScth 				 * We still map Load Balance Type to UNKNOWN
27961e1ddd6cScth 				 * although "none" also maps to the same case.
27971e1ddd6cScth 				 * MPAPI spec does not have a "NONE" LB type.
27981e1ddd6cScth 				 */
27991e1ddd6cScth 				lu->prop.currentLoadBalanceType =
28001e1ddd6cScth 				    MP_DRVR_LOAD_BALANCE_TYPE_UNKNOWN;
28011e1ddd6cScth 			}
28021e1ddd6cScth 			/*
28031e1ddd6cScth 			 * Allocate header lists for cross reference
28041e1ddd6cScth 			 */
28051e1ddd6cScth 			lu->path_list = vhci_mpapi_create_list_head();
28061e1ddd6cScth 			lu->tpg_list = vhci_mpapi_create_list_head();
28071e1ddd6cScth 			item->idata = (void *)lu;
280817d71211SJiri Svoboda 			vhci_mpapi_set_lu_valid(vhci, item, 1);
28091e1ddd6cScth 		}
28101e1ddd6cScth 		break;
28111e1ddd6cScth 
28121e1ddd6cScth 		case	MP_OBJECT_TYPE_PATH_LU:
28131e1ddd6cScth 		{
28141e1ddd6cScth 			mpapi_path_data_t	*path;
28151e1ddd6cScth 			mdi_pathinfo_t		*pip = res;
28161e1ddd6cScth 			scsi_vhci_lun_t		*svl;
28171e1ddd6cScth 			char			*iport, *tport;
28181e1ddd6cScth 
28191e1ddd6cScth 			item->oid.raw_oid =
28201e1ddd6cScth 			    vhci_mpapi_create_oid(vhci->mp_priv, obj_type);
28211e1ddd6cScth 			path = kmem_zalloc(
28221e1ddd6cScth 			    sizeof (mpapi_path_data_t), KM_SLEEP);
28231e1ddd6cScth 			pname = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
28241e1ddd6cScth 
28251e1ddd6cScth 			iport = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
28261e1ddd6cScth 			(void) ddi_pathname(mdi_pi_get_phci(pip), iport);
28271e1ddd6cScth 
282855e592a2SRandall Ralphs 			if (mdi_prop_lookup_string(pip,
282955e592a2SRandall Ralphs 			    SCSI_ADDR_PROP_TARGET_PORT, &tport) !=
283055e592a2SRandall Ralphs 			    DDI_PROP_SUCCESS) {
28311e1ddd6cScth 				/* XXX: target-port prop not found */
28321e1ddd6cScth 				tport = (char *)mdi_pi_get_addr(pip);
28331e1ddd6cScth 				VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_mpapi_"
28341e1ddd6cScth 				    "create_item: mdi_prop_lookup_string() "
28351e1ddd6cScth 				    "returned failure; "));
28361e1ddd6cScth 			}
28371e1ddd6cScth 
28381e1ddd6cScth 			svl = mdi_client_get_vhci_private
28391e1ddd6cScth 			    (mdi_pi_get_client(pip));
28401e1ddd6cScth 
28411e1ddd6cScth 			(void) strlcat(pname, iport, MAXPATHLEN);
28421e1ddd6cScth 			(void) strlcat(pname, tport, MAXPATHLEN);
28431e1ddd6cScth 			(void) strlcat(pname, svl->svl_lun_wwn, MAXPATHLEN);
28441e1ddd6cScth 			kmem_free(iport, MAXPATHLEN);
28451e1ddd6cScth 
28461e1ddd6cScth 			path->resp = res;
28471e1ddd6cScth 			path->path_name = pname;
28481e1ddd6cScth 			path->valid = 1;
28494c06356bSdh 			path->hide = 0;
28501e1ddd6cScth 			path->prop.id = item->oid.raw_oid;
28511e1ddd6cScth 			item->idata = (void *)path;
28521e1ddd6cScth 			vhci_mpapi_log_sysevent(vhci->vhci_dip,
28531e1ddd6cScth 			    &(item->oid.raw_oid), ESC_SUN_MP_PATH_ADD);
28541e1ddd6cScth 		}
28551e1ddd6cScth 		break;
28561e1ddd6cScth 
28571e1ddd6cScth 		case	MP_OBJECT_TYPE_DEVICE_PRODUCT:
28581e1ddd6cScth 			VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_mpapi_create_item:"
28591e1ddd6cScth 			    " DEVICE PRODUCT not handled here."));
28601e1ddd6cScth 		break;
28611e1ddd6cScth 
28621e1ddd6cScth 		default:
28631e1ddd6cScth 			/*
28641e1ddd6cScth 			 * This should not happen
28651e1ddd6cScth 			 */
28661e1ddd6cScth 			VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_mpapi_create_item:"
28671e1ddd6cScth 			    "Got Unsupported OBJECT TYPE"));
28681e1ddd6cScth 			return (NULL);
28691e1ddd6cScth 	}
28701e1ddd6cScth 
28711e1ddd6cScth 	(void) vhci_mpapi_add_to_list(vhci->mp_priv->obj_hdr_list[obj_type],
28721e1ddd6cScth 	    ilist);
28731e1ddd6cScth 	return (ilist);
28741e1ddd6cScth }
28751e1ddd6cScth 
28761e1ddd6cScth /*
28771e1ddd6cScth  * Local routine to allocate mpapi list header block
28781e1ddd6cScth  */
28791e1ddd6cScth /* ARGSUSED */
28801e1ddd6cScth static mpapi_list_header_t *
vhci_mpapi_create_list_head()28811e1ddd6cScth vhci_mpapi_create_list_head()
28821e1ddd6cScth {
28831e1ddd6cScth 	mpapi_list_header_t	*lh;
28841e1ddd6cScth 
28851e1ddd6cScth 	lh =  kmem_zalloc(sizeof (mpapi_list_header_t), KM_SLEEP);
28861e1ddd6cScth 	lh->head = lh->tail = NULL;
28871e1ddd6cScth 	return (lh);
28881e1ddd6cScth }
28891e1ddd6cScth 
28901e1ddd6cScth /*
28911e1ddd6cScth  * Routine to create Level 1 mpapi_private data structure and also
28921e1ddd6cScth  * establish cross references between the resources being managed
28931e1ddd6cScth  */
28941e1ddd6cScth /* ARGSUSED */
28951e1ddd6cScth void
vhci_update_mpapi_data(struct scsi_vhci * vhci,scsi_vhci_lun_t * vlun,mdi_pathinfo_t * pip)28961e1ddd6cScth vhci_update_mpapi_data(struct scsi_vhci *vhci, scsi_vhci_lun_t *vlun,
28971e1ddd6cScth     mdi_pathinfo_t *pip)
28981e1ddd6cScth {
28991e1ddd6cScth 	char			*tmp_wwn = NULL, *init = NULL, *path_class;
29001e1ddd6cScth 	dev_info_t		*pdip;
29011e1ddd6cScth 	mpapi_item_list_t	*lu_list, *path_list, *init_list, *tgt_list;
29021e1ddd6cScth 	mpapi_item_list_t	*tp_path_list, *init_path_list, *lu_path_list;
29031e1ddd6cScth 	mpapi_lu_data_t		*ld;
29041e1ddd6cScth 	mpapi_path_data_t	*pd;
29051e1ddd6cScth 	mpapi_tport_data_t	*tpd;
29061e1ddd6cScth 	mpapi_initiator_data_t	*initd;
29071e1ddd6cScth 	int			path_class_not_mdi_alloced = 0;
29081e1ddd6cScth 
29091e1ddd6cScth 	VHCI_DEBUG(6, (CE_NOTE, NULL, "vhci_update_mpapi_data: vhci: %p, "
29101e1ddd6cScth 	    "vlun: %p, pip: %p\n", (void *)vhci, (void *)vlun, (void *)pip));
29111e1ddd6cScth 
29121e1ddd6cScth 	/*
29131e1ddd6cScth 	 * Check that the lun is not a TPGS device
29141e1ddd6cScth 	 * TPGS devices create the same information in another routine.
29151e1ddd6cScth 	 */
29161e1ddd6cScth 	if (SCSI_FAILOVER_IS_TPGS(vlun->svl_fops)) {
29171e1ddd6cScth 		return;
29181e1ddd6cScth 	}
29191e1ddd6cScth 	/*
29201e1ddd6cScth 	 * LEVEL 1 - Actions:
29211e1ddd6cScth 	 * Check if the appropriate resource pointers already
29221e1ddd6cScth 	 * exist in the Level 1 list and add them if they are new.
29231e1ddd6cScth 	 */
29241e1ddd6cScth 
29251e1ddd6cScth 	/*
29261e1ddd6cScth 	 * Build MP LU list
29271e1ddd6cScth 	 */
29281e1ddd6cScth 	lu_list = vhci_get_mpapi_item(vhci, NULL,
29291e1ddd6cScth 	    MP_OBJECT_TYPE_MULTIPATH_LU, (void*)vlun);
29301e1ddd6cScth 	if (lu_list == NULL) {
29311e1ddd6cScth 		/* Need to create lu_list entry */
29321e1ddd6cScth 		lu_list = vhci_mpapi_create_item(vhci,
29331e1ddd6cScth 		    MP_OBJECT_TYPE_MULTIPATH_LU, (void*)vlun);
29341e1ddd6cScth 	} else {
29351e1ddd6cScth 		/*
29361e1ddd6cScth 		 * Matched this lu w/ an existing one in current lu list.
29371e1ddd6cScth 		 * SAME LUN came online!! So, update the resp in main list.
29381e1ddd6cScth 		 */
29391e1ddd6cScth 		ld = lu_list->item->idata;
294017d71211SJiri Svoboda 		vhci_mpapi_set_lu_valid(vhci, lu_list->item, 1);
29411e1ddd6cScth 		ld->resp = vlun;
29421e1ddd6cScth 	}
29431e1ddd6cScth 
29441e1ddd6cScth 	/*
29451e1ddd6cScth 	 * Find out the "path-class" property on the pip
29461e1ddd6cScth 	 */
29471e1ddd6cScth 	if (mdi_prop_lookup_string(pip, "path-class", &path_class)
29481e1ddd6cScth 	    != DDI_PROP_SUCCESS) {
29491e1ddd6cScth 		/* XXX: path-class prop not found */
29501e1ddd6cScth 		path_class = kmem_zalloc(MPAPI_SCSI_MAXPCLASSLEN, KM_SLEEP);
29511e1ddd6cScth 		(void) strlcpy(path_class, "NONE", MPAPI_SCSI_MAXPCLASSLEN);
29521e1ddd6cScth 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_update_mpapi_data: "
29531e1ddd6cScth 		    "mdi_prop_lookup_string() returned failure; "
29541e1ddd6cScth 		    "Hence path_class = NONE"));
29551e1ddd6cScth 		path_class_not_mdi_alloced = 1;
29561e1ddd6cScth 	}
29571e1ddd6cScth 
29581e1ddd6cScth 	/*
29591e1ddd6cScth 	 * Build Path LU list
29601e1ddd6cScth 	 */
29611e1ddd6cScth 	path_list = vhci_get_mpapi_item(vhci, NULL,
29621e1ddd6cScth 	    MP_OBJECT_TYPE_PATH_LU, (void*)pip);
29631e1ddd6cScth 	if (path_list == NULL) {
29641e1ddd6cScth 		/* Need to create path_list entry */
29651e1ddd6cScth 		path_list = vhci_mpapi_create_item(vhci,
29661e1ddd6cScth 		    MP_OBJECT_TYPE_PATH_LU, (void*)pip);
29671e1ddd6cScth 	} else {
29681e1ddd6cScth 		/*
29691e1ddd6cScth 		 * Matched this pip w/ an existing one in current pip list.
29701e1ddd6cScth 		 * SAME PATH came online!! So, update the resp in main list.
29711e1ddd6cScth 		 */
29721e1ddd6cScth 		pd = path_list->item->idata;
29731e1ddd6cScth 		pd->valid = 1;
29744c06356bSdh 		pd->hide = 0;
29751e1ddd6cScth 		pd->resp = pip;
29761e1ddd6cScth 	}
29771e1ddd6cScth 
29781e1ddd6cScth 	if (MDI_PI_IS_ONLINE(pip)) {
29791e1ddd6cScth 		vhci_mpapi_set_path_state(vhci->vhci_dip, pip,
29801e1ddd6cScth 		    MP_DRVR_PATH_STATE_ACTIVE);
29811e1ddd6cScth 	} else if (MDI_PI_IS_STANDBY(pip)) {
29821e1ddd6cScth 		vhci_mpapi_set_path_state(vhci->vhci_dip, pip,
29831e1ddd6cScth 		    MP_DRVR_PATH_STATE_PASSIVE);
29841e1ddd6cScth 	} else {
29851e1ddd6cScth 		vhci_mpapi_set_path_state(vhci->vhci_dip, pip,
29861e1ddd6cScth 		    MP_DRVR_PATH_STATE_UNKNOWN);
29871e1ddd6cScth 	}
29881e1ddd6cScth 
29891e1ddd6cScth 	/*
29901e1ddd6cScth 	 * Build Initiator Port list
29911e1ddd6cScth 	 */
29921e1ddd6cScth 	pdip = mdi_pi_get_phci(pip);
29931e1ddd6cScth 	init = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
29941e1ddd6cScth 	(void) ddi_pathname(pdip, init);
29951e1ddd6cScth 
29961e1ddd6cScth 	init_list = vhci_get_mpapi_item(vhci, NULL,
29971e1ddd6cScth 	    MP_OBJECT_TYPE_INITIATOR_PORT, (void*)init);
29981e1ddd6cScth 	if (init_list == NULL) {
29991e1ddd6cScth 		/*
30001e1ddd6cScth 		 * Need to create init_list entry
30011e1ddd6cScth 		 * The resource ptr is no really pdip. It will be changed
30021e1ddd6cScth 		 * in vhci_mpapi_create_item(). The real resource ptr
30031e1ddd6cScth 		 * is the Port ID. But we pass the pdip, to create OID.
30041e1ddd6cScth 		 */
30051e1ddd6cScth 		init_list = vhci_mpapi_create_item(vhci,
30061e1ddd6cScth 		    MP_OBJECT_TYPE_INITIATOR_PORT, (void*)pdip);
30071e1ddd6cScth 	} else {
30081e1ddd6cScth 		initd = init_list->item->idata;
30091e1ddd6cScth 		initd->valid = 1;
30101e1ddd6cScth 	}
30111e1ddd6cScth 	kmem_free(init, MAXPATHLEN);
30121e1ddd6cScth 
30131e1ddd6cScth 	/*
30141e1ddd6cScth 	 * Build Target Port list
30151e1ddd6cScth 	 * Can get the tdip: tdip = mdi_pi_get_client(pip);
30161e1ddd6cScth 	 * But what's the use? We want TARGET_PORT.
30171e1ddd6cScth 	 * So try getting Target Port's WWN which is unique per port.
30181e1ddd6cScth 	 */
30191e1ddd6cScth 	tmp_wwn = NULL;
302055e592a2SRandall Ralphs 	if (mdi_prop_lookup_string(pip, SCSI_ADDR_PROP_TARGET_PORT,
302155e592a2SRandall Ralphs 	    &tmp_wwn) != DDI_PROP_SUCCESS) {
30221e1ddd6cScth 		/* XXX: target-port prop not found */
30231e1ddd6cScth 		tmp_wwn = (char *)mdi_pi_get_addr(pip);
30241e1ddd6cScth 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_update_mpapi_data: "
30251e1ddd6cScth 		    "mdi_prop_lookup_string() returned failure; "
30261e1ddd6cScth 		    "Hence tmp_wwn = %p", (void *)tmp_wwn));
30271e1ddd6cScth 	}
30281e1ddd6cScth 
30291e1ddd6cScth 	tgt_list = vhci_get_mpapi_item(vhci, NULL,
30301e1ddd6cScth 	    MP_OBJECT_TYPE_TARGET_PORT, (void*)tmp_wwn);
30311e1ddd6cScth 	if (tgt_list == NULL) {
30321e1ddd6cScth 		/* Need to create tgt_list entry */
30331e1ddd6cScth 		tgt_list = vhci_mpapi_create_item(vhci,
30341e1ddd6cScth 		    MP_OBJECT_TYPE_TARGET_PORT, (void*)tmp_wwn);
30351e1ddd6cScth 	} else {
30361e1ddd6cScth 		tpd = tgt_list->item->idata;
30371e1ddd6cScth 		tpd->valid = 1;
30381e1ddd6cScth 	}
30391e1ddd6cScth 
30401e1ddd6cScth 	/*
30411e1ddd6cScth 	 * LEVEL 2 - Actions:
30421e1ddd6cScth 	 * Since all the Object type item lists are updated to account
30431e1ddd6cScth 	 * for the new resources, now lets cross-reference these
30441e1ddd6cScth 	 * resources (mainly through paths) to maintain the
30451e1ddd6cScth 	 * relationship between them.
30461e1ddd6cScth 	 */
30471e1ddd6cScth 
30481e1ddd6cScth 	ld = (mpapi_lu_data_t *)lu_list->item->idata;
30491e1ddd6cScth 	if (vhci_get_mpapi_item(vhci, ld->path_list,
30501e1ddd6cScth 	    MP_OBJECT_TYPE_PATH_LU, (void*)pip) == NULL) {
30511e1ddd6cScth 		lu_path_list = kmem_zalloc(sizeof (mpapi_item_list_t),
30521e1ddd6cScth 		    KM_SLEEP);
30531e1ddd6cScth 		lu_path_list->item = path_list->item;
30541e1ddd6cScth 		(void) vhci_mpapi_add_to_list(ld->path_list, lu_path_list);
30551e1ddd6cScth 	}
30561e1ddd6cScth 
30571e1ddd6cScth 	initd = (mpapi_initiator_data_t *)init_list->item->idata;
30581e1ddd6cScth 	if (vhci_get_mpapi_item(vhci, initd->path_list,
30591e1ddd6cScth 	    MP_OBJECT_TYPE_PATH_LU, (void*)pip) == NULL) {
30601e1ddd6cScth 		init_path_list = kmem_zalloc(sizeof (mpapi_item_list_t),
30611e1ddd6cScth 		    KM_SLEEP);
30621e1ddd6cScth 		init_path_list->item = path_list->item;
30631e1ddd6cScth 		(void) vhci_mpapi_add_to_list(initd->path_list, init_path_list);
30641e1ddd6cScth 	}
30651e1ddd6cScth 
30661e1ddd6cScth 	tpd = (mpapi_tport_data_t *)tgt_list->item->idata;
30671e1ddd6cScth 	if (vhci_get_mpapi_item(vhci, tpd->path_list,
30681e1ddd6cScth 	    MP_OBJECT_TYPE_PATH_LU, (void*)pip) == NULL) {
30691e1ddd6cScth 		tp_path_list = kmem_zalloc(
30701e1ddd6cScth 		    sizeof (mpapi_item_list_t), KM_SLEEP);
30711e1ddd6cScth 		tp_path_list->item = path_list->item;
30721e1ddd6cScth 		(void) vhci_mpapi_add_to_list(tpd->path_list, tp_path_list);
30731e1ddd6cScth 	}
30741e1ddd6cScth 
30751e1ddd6cScth 	/*
30761e1ddd6cScth 	 * Level-1: Fill-out Path Properties now, since we got all details.
30771e1ddd6cScth 	 * Actually, It is a structure copy, rather than just filling details.
30781e1ddd6cScth 	 */
30791e1ddd6cScth 	pd = path_list->item->idata;
30801e1ddd6cScth 	(void) strlcpy(pd->pclass, path_class, sizeof (pd->pclass));
30811e1ddd6cScth 	bcopy(&(ld->prop), &(pd->prop.logicalUnit),
30821e1ddd6cScth 	    sizeof (struct mp_logical_unit_prop));
30831e1ddd6cScth 	bcopy(&(initd->prop), &(pd->prop.initPort),
30841e1ddd6cScth 	    sizeof (struct mp_init_port_prop));
30851e1ddd6cScth 	bcopy(&(tpd->prop), &(pd->prop.targetPort),
30861e1ddd6cScth 	    sizeof (struct mp_target_port_prop));
30871e1ddd6cScth 
30881e1ddd6cScth 	vhci_mpapi_synthesize_tpg_data(vhci, vlun, pip);
30891e1ddd6cScth 
30901e1ddd6cScth 	if (path_class_not_mdi_alloced == 1) {
30911e1ddd6cScth 		kmem_free(path_class, MPAPI_SCSI_MAXPCLASSLEN);
30921e1ddd6cScth 	}
30931e1ddd6cScth 
30941e1ddd6cScth }
30951e1ddd6cScth 
30969b4f248cSChris Liu /*
30979b4f248cSChris Liu  * Routine to search (& return if found) a TPG object with a specified
30989b4f248cSChris Liu  * tpg_id and rel_tp_id for a specified vlun structure. Returns NULL
30999b4f248cSChris Liu  * if either TPG object or the lu item is not found.
31009b4f248cSChris Liu  * This routine is used for TPGS(ALUA) devices.
31019b4f248cSChris Liu  */
31029b4f248cSChris Liu /* ARGSUSED */
31039b4f248cSChris Liu static mpapi_item_list_t *
vhci_mpapi_get_alua_item(struct scsi_vhci * vhci,void * vlun,void * tpg_id,void * tp)31049b4f248cSChris Liu vhci_mpapi_get_alua_item(struct scsi_vhci *vhci, void *vlun, void *tpg_id,
31059b4f248cSChris Liu     void *tp)
31069b4f248cSChris Liu {
31079b4f248cSChris Liu 	mpapi_list_header_t	*this_tpghdr;
31089b4f248cSChris Liu 	mpapi_item_list_t	*tpglist, *this_lulist, *this_tpglist;
31099b4f248cSChris Liu 	mpapi_tpg_data_t	*tpgdata, *this_tpgdata;
31109b4f248cSChris Liu 
31119b4f248cSChris Liu 	VHCI_DEBUG(6, (CE_NOTE, NULL, "vhci_mpapi_get_alua_item: ENTER: vlun="
31129b4f248cSChris Liu 	    "%p, tpg_id=%s, tp=%s\n",
31139b4f248cSChris Liu 	    (void *)vlun, (char *)tpg_id, (char *)tp));
31149b4f248cSChris Liu 
31159b4f248cSChris Liu 	/*
31169b4f248cSChris Liu 	 * Check if target port is already in any existing group
31179b4f248cSChris Liu 	 */
31189b4f248cSChris Liu 	tpglist = vhci->mp_priv->obj_hdr_list[MP_OBJECT_TYPE_TARGET_PORT_GROUP]
31199b4f248cSChris Liu 	    ->head;
31209b4f248cSChris Liu 	while (tpglist != NULL) {
31219b4f248cSChris Liu 		tpgdata = tpglist->item->idata;
31229b4f248cSChris Liu 
31239b4f248cSChris Liu 		if ((tpgdata) &&
31249b4f248cSChris Liu 		    (vhci_mpapi_check_tp_in_tpg(tpgdata, tp) == 1) &&
31259b4f248cSChris Liu 		    (strcmp(tpgdata->resp, tpg_id) == 0)) {
31269b4f248cSChris Liu 			return (tpglist);
31279b4f248cSChris Liu 		} else {
31289b4f248cSChris Liu 			tpglist = tpglist->next;
31299b4f248cSChris Liu 		}
31309b4f248cSChris Liu 	}
31319b4f248cSChris Liu 
31329b4f248cSChris Liu 	/*
31339b4f248cSChris Liu 	 * If target port is not existed, search TPG associated
31349b4f248cSChris Liu 	 * with this LU to see if this LU has a TPG with the same
31359b4f248cSChris Liu 	 * tpg_id.
31369b4f248cSChris Liu 	 */
31379b4f248cSChris Liu 	this_lulist = vhci_get_mpapi_item(vhci, NULL,
31389b4f248cSChris Liu 	    MP_OBJECT_TYPE_MULTIPATH_LU, vlun);
31399b4f248cSChris Liu 	if (this_lulist != NULL) {
31409b4f248cSChris Liu 		this_tpghdr = ((mpapi_lu_data_t *)(this_lulist->item->idata))
31419b4f248cSChris Liu 		    ->tpg_list;
31429b4f248cSChris Liu 		this_tpglist = this_tpghdr->head;
31439b4f248cSChris Liu 		while (this_tpglist != NULL) {
31449b4f248cSChris Liu 			this_tpgdata = this_tpglist->item->idata;
31459b4f248cSChris Liu 			if ((this_tpgdata) &&
31469b4f248cSChris Liu 			    (strcmp(this_tpgdata->resp, tpg_id) == 0)) {
31479b4f248cSChris Liu 				return (this_tpglist);
31489b4f248cSChris Liu 			} else {
31499b4f248cSChris Liu 				this_tpglist = this_tpglist->next;
31509b4f248cSChris Liu 			}
31519b4f248cSChris Liu 		}
31529b4f248cSChris Liu 	}
31539b4f248cSChris Liu 
31549b4f248cSChris Liu 	VHCI_DEBUG(4, (CE_WARN, NULL, "vhci_mpapi_get_tpg_item: Returns NULL"));
31559b4f248cSChris Liu 
31569b4f248cSChris Liu 	return (NULL);
31579b4f248cSChris Liu }
31589b4f248cSChris Liu 
31591e1ddd6cScth /*
31601e1ddd6cScth  * Routine to search (& return if found) a TPG object with a specified
31611e1ddd6cScth  * accessState for a specified vlun structure. Returns NULL if either
31621e1ddd6cScth  * TPG object or the lu item is not found.
31631e1ddd6cScth  * This routine is used for NON-TPGS devices.
31641e1ddd6cScth  */
31651e1ddd6cScth /* ARGSUSED */
31661e1ddd6cScth static mpapi_item_list_t *
vhci_mpapi_get_tpg_item(struct scsi_vhci * vhci,uint32_t acc_state,void * vlun,char * pclass,void * tp)31671e1ddd6cScth vhci_mpapi_get_tpg_item(struct scsi_vhci *vhci, uint32_t acc_state, void *vlun,
31681e1ddd6cScth     char *pclass, void *tp)
31691e1ddd6cScth {
31701e1ddd6cScth 	mpapi_list_header_t	*tpghdr, *this_tpghdr;
31711e1ddd6cScth 	mpapi_item_list_t	*lulist, *tpglist, *this_lulist, *this_tpglist;
31721e1ddd6cScth 	mpapi_tpg_data_t	*tpgdata, *this_tpgdata;
31731e1ddd6cScth 
31741e1ddd6cScth 	VHCI_DEBUG(6, (CE_NOTE, NULL, "vhci_mpapi_get_tpg_item: ENTER: vlun="
31751e1ddd6cScth 	    "%p, acc_state=%x, pclass=%s, tp=%s\n",
31761e1ddd6cScth 	    (void *)vlun, acc_state, pclass, (char *)tp));
31771e1ddd6cScth 
31781e1ddd6cScth 	lulist = vhci->mp_priv->obj_hdr_list[MP_OBJECT_TYPE_MULTIPATH_LU]->head;
31791e1ddd6cScth 
31801e1ddd6cScth 	while (lulist != NULL) {
31811e1ddd6cScth 		tpghdr = ((mpapi_lu_data_t *)(lulist->item->idata))->tpg_list;
31821e1ddd6cScth 		tpglist = tpghdr->head;
31831e1ddd6cScth 		while (tpglist != NULL) {
31841e1ddd6cScth 			tpgdata = tpglist->item->idata;
31851e1ddd6cScth 
31861e1ddd6cScth 			if ((tpgdata) &&
31871e1ddd6cScth 			    (vhci_mpapi_check_tp_in_tpg(tpgdata, tp) == 1) &&
31881e1ddd6cScth 			    (strncmp(tpgdata->pclass, pclass,
31891e1ddd6cScth 			    strlen(pclass)) == 0)) {
31901e1ddd6cScth 				return (tpglist);
31911e1ddd6cScth 			} else {
31921e1ddd6cScth 				tpglist = tpglist->next;
31931e1ddd6cScth 			}
31941e1ddd6cScth 		}
31951e1ddd6cScth 		lulist = lulist->next;
31961e1ddd6cScth 	}
31971e1ddd6cScth 
31981e1ddd6cScth 	this_lulist = vhci_get_mpapi_item(vhci, NULL,
31991e1ddd6cScth 	    MP_OBJECT_TYPE_MULTIPATH_LU, vlun);
32001e1ddd6cScth 	if (this_lulist != NULL) {
32011e1ddd6cScth 		this_tpghdr = ((mpapi_lu_data_t *)(this_lulist->item->idata))
32021e1ddd6cScth 		    ->tpg_list;
32031e1ddd6cScth 		this_tpglist = this_tpghdr->head;
32041e1ddd6cScth 		while (this_tpglist != NULL) {
32051e1ddd6cScth 			this_tpgdata = this_tpglist->item->idata;
32061e1ddd6cScth 
32071e1ddd6cScth 			if ((this_tpgdata) &&
32081e1ddd6cScth 			    (strncmp(this_tpgdata->pclass, pclass,
32091e1ddd6cScth 			    strlen(pclass)) == 0)) {
32101e1ddd6cScth 				return (this_tpglist);
32111e1ddd6cScth 			} else {
32121e1ddd6cScth 				this_tpglist = this_tpglist->next;
32131e1ddd6cScth 			}
32141e1ddd6cScth 		}
32151e1ddd6cScth 	}
32161e1ddd6cScth 
32171e1ddd6cScth 	VHCI_DEBUG(4, (CE_WARN, NULL, "vhci_mpapi_get_tpg_item: Returns NULL"));
32181e1ddd6cScth 
32191e1ddd6cScth 	return (NULL);
32201e1ddd6cScth }
32211e1ddd6cScth 
32221e1ddd6cScth /*
32231e1ddd6cScth  * Routine to search (& return if found) a TPG object with a specified
32241e1ddd6cScth  * accessState for a specified vlun structure. Returns NULL if either
32251e1ddd6cScth  * TPG object or the lu item is not found.
32261e1ddd6cScth  * This routine is used for NON-TPGS devices.
32271e1ddd6cScth  */
32281e1ddd6cScth /* ARGSUSED */
32291e1ddd6cScth mpapi_item_list_t *
vhci_mpapi_get_tpg_for_lun(struct scsi_vhci * vhci,char * pclass,void * vlun,void * tp)32301e1ddd6cScth vhci_mpapi_get_tpg_for_lun(struct scsi_vhci *vhci, char *pclass,
32311e1ddd6cScth     void *vlun, void *tp)
32321e1ddd6cScth {
32331e1ddd6cScth 	mpapi_list_header_t	*this_tpghdr;
32341e1ddd6cScth 	mpapi_item_list_t	*this_lulist, *this_tpglist;
32351e1ddd6cScth 	mpapi_tpg_data_t	*this_tpgdata;
32361e1ddd6cScth 
32371e1ddd6cScth 	VHCI_DEBUG(4, (CE_NOTE, NULL, "vhci_mpapi_get_tpg_for_lun: ENTER: vlun="
32381e1ddd6cScth 	    "%p, pclass=%s, tp=%s\n", (void *)vlun, pclass, (char *)tp));
32391e1ddd6cScth 
32401e1ddd6cScth 	this_lulist = vhci_get_mpapi_item(vhci, NULL,
32411e1ddd6cScth 	    MP_OBJECT_TYPE_MULTIPATH_LU, vlun);
32421e1ddd6cScth 	if (this_lulist != NULL) {
32431e1ddd6cScth 		this_tpghdr = ((mpapi_lu_data_t *)(this_lulist->item->idata))
32441e1ddd6cScth 		    ->tpg_list;
32451e1ddd6cScth 		this_tpglist = this_tpghdr->head;
32461e1ddd6cScth 		while (this_tpglist != NULL) {
32471e1ddd6cScth 			this_tpgdata = this_tpglist->item->idata;
32481e1ddd6cScth 
32491e1ddd6cScth 			if ((this_tpgdata) &&
32501e1ddd6cScth 			    (vhci_mpapi_check_tp_in_tpg(this_tpgdata,
32511e1ddd6cScth 			    tp) == 1) && (strncmp(this_tpgdata->pclass, pclass,
32521e1ddd6cScth 			    strlen(pclass)) == 0)) {
32531e1ddd6cScth 				return (this_tpglist);
32541e1ddd6cScth 			}
32551e1ddd6cScth 			this_tpglist = this_tpglist->next;
32561e1ddd6cScth 		}
32571e1ddd6cScth 	}
32581e1ddd6cScth 
32591e1ddd6cScth 	VHCI_DEBUG(4, (CE_WARN, NULL, "vhci_mpapi_get_tpg_for_lun: Returns "
32601e1ddd6cScth 	    "NULL"));
32611e1ddd6cScth 
32621e1ddd6cScth 	return (NULL);
32631e1ddd6cScth }
32641e1ddd6cScth 
32651e1ddd6cScth /*
32661e1ddd6cScth  * Routine to search a Target Port in a TPG
32671e1ddd6cScth  */
32681e1ddd6cScth /* ARGSUSED */
32691e1ddd6cScth static int
vhci_mpapi_check_tp_in_tpg(mpapi_tpg_data_t * tpgdata,void * tp)32701e1ddd6cScth vhci_mpapi_check_tp_in_tpg(mpapi_tpg_data_t *tpgdata, void *tp)
32711e1ddd6cScth {
32721e1ddd6cScth 	mpapi_item_list_t	*tplist;
32731e1ddd6cScth 
32741e1ddd6cScth 	if (tpgdata) {
32751e1ddd6cScth 		tplist = tpgdata->tport_list->head;
32761e1ddd6cScth 	} else {
32771e1ddd6cScth 		return (0);
32781e1ddd6cScth 	}
32791e1ddd6cScth 
32801e1ddd6cScth 	while (tplist != NULL) {
32811e1ddd6cScth 		void	*resp = ((mpapi_tport_data_t *)tplist->
32821e1ddd6cScth 		    item->idata)->resp;
32831e1ddd6cScth 		if (strncmp(resp, tp, strlen(resp)) == 0) {
32841e1ddd6cScth 			/* Found a match */
32851e1ddd6cScth 			return (1);
32861e1ddd6cScth 		}
32871e1ddd6cScth 		tplist = tplist->next;
32881e1ddd6cScth 	}
32891e1ddd6cScth 
32901e1ddd6cScth 	return (0);
32911e1ddd6cScth }
32921e1ddd6cScth 
32931e1ddd6cScth /*
32941e1ddd6cScth  * Routine to create Level 1 mpapi_private data structure for TPG object &
32951e1ddd6cScth  * establish cross references between the TPG resources being managed.
32961e1ddd6cScth  * TPG SYNTHESIS MODE: Process for NON-SCSI_FAILOVER_IS_TPGS devices ONLY.
32971e1ddd6cScth  * SCSI_FAILOVER_IS_TPGS devices have TPGS(ALUA support) and provide
32981e1ddd6cScth  * REPORT_TARGET_PORT_GROUP data which we can parse directly in the next
32991e1ddd6cScth  * routine(vhci_mpapi_update_tpg_data) to create TPG list in mpapi_priv block.
33001e1ddd6cScth  */
33011e1ddd6cScth /* ARGSUSED */
33021e1ddd6cScth void
vhci_mpapi_synthesize_tpg_data(struct scsi_vhci * vhci,scsi_vhci_lun_t * vlun,mdi_pathinfo_t * pip)33031e1ddd6cScth vhci_mpapi_synthesize_tpg_data(struct scsi_vhci *vhci, scsi_vhci_lun_t *vlun,
33041e1ddd6cScth     mdi_pathinfo_t *pip)
33051e1ddd6cScth {
33061e1ddd6cScth 	uint32_t		as;
33071e1ddd6cScth 	char			*tmp_wwn = NULL, *path_class = NULL;
33081e1ddd6cScth 	mpapi_item_list_t	*tpg_tport_list, *tpg_lu_list, *lu_list;
33091e1ddd6cScth 	mpapi_item_list_t	*lu_tpg_list, *item_list, *tpg_list;
33101e1ddd6cScth 	mpapi_tpg_data_t	*tpg_data;
33111e1ddd6cScth 	int			path_class_not_mdi_alloced = 0;
33121e1ddd6cScth 
33131e1ddd6cScth 	/*
33141e1ddd6cScth 	 * Build Target Port Group list
33151e1ddd6cScth 	 * Start by finding out the affected Target Port.
33161e1ddd6cScth 	 */
331755e592a2SRandall Ralphs 	if (mdi_prop_lookup_string(pip, SCSI_ADDR_PROP_TARGET_PORT,
331855e592a2SRandall Ralphs 	    &tmp_wwn) != DDI_PROP_SUCCESS) {
33191e1ddd6cScth 		/* XXX: target-port prop not found */
33201e1ddd6cScth 		tmp_wwn = (char *)mdi_pi_get_addr(pip);
33211e1ddd6cScth 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_mpapi_synthesize_tpg_data: "
33221e1ddd6cScth 		    "mdi_prop_lookup_string() returned failure; "
33231e1ddd6cScth 		    "Hence tmp_wwn = %p", (void *)tmp_wwn));
33241e1ddd6cScth 	}
33251e1ddd6cScth 
33261e1ddd6cScth 	/*
33271e1ddd6cScth 	 * Finding out the "path-class" property
33281e1ddd6cScth 	 */
33291e1ddd6cScth 	if (mdi_prop_lookup_string(pip, "path-class", &path_class)
33301e1ddd6cScth 	    != DDI_PROP_SUCCESS) {
33311e1ddd6cScth 		/* XXX: path-class prop not found */
33321e1ddd6cScth 		path_class = kmem_zalloc(MPAPI_SCSI_MAXPCLASSLEN, KM_SLEEP);
33331e1ddd6cScth 		(void) strlcpy(path_class, "NONE", MPAPI_SCSI_MAXPCLASSLEN);
33341e1ddd6cScth 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_mpapi_synthesize_tpg_data: "
33351e1ddd6cScth 		    "mdi_prop_lookup_string() returned failure; "
33361e1ddd6cScth 		    "Hence path_class = NONE"));
33371e1ddd6cScth 		path_class_not_mdi_alloced = 1;
33381e1ddd6cScth 	}
33391e1ddd6cScth 
33401e1ddd6cScth 	/*
33411e1ddd6cScth 	 * Check the vlun's accessState through pip; we'll use it later.
33421e1ddd6cScth 	 */
33431e1ddd6cScth 	if (MDI_PI_IS_ONLINE(pip)) {
33441e1ddd6cScth 		as = MP_DRVR_ACCESS_STATE_ACTIVE;
33451e1ddd6cScth 	} else if (MDI_PI_IS_STANDBY(pip)) {
33461e1ddd6cScth 		as = MP_DRVR_ACCESS_STATE_STANDBY;
33471e1ddd6cScth 	} else {
33481e1ddd6cScth 		as = MP_DRVR_ACCESS_STATE_UNAVAILABLE;
33491e1ddd6cScth 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_mpapi_synthesize_tpg_data: "
33501e1ddd6cScth 		    "Unknown pip state seen in TPG synthesis"));
33511e1ddd6cScth 	}
33521e1ddd6cScth 
33531e1ddd6cScth 	VHCI_DEBUG(4, (CE_NOTE, NULL, "vhci_mpapi_synthesize_tpg_data: ENTER: "
33541e1ddd6cScth 	    "vlun=%s, acc_state=%x, path_class=%s, tp=%s\n",
33551e1ddd6cScth 	    vlun->svl_lun_wwn, as, path_class, tmp_wwn));
33561e1ddd6cScth 
33571e1ddd6cScth 	/*
33581e1ddd6cScth 	 * Create Level 1 and Level 2 data structures for type
33591e1ddd6cScth 	 */
33601e1ddd6cScth 	if (!SCSI_FAILOVER_IS_TPGS(vlun->svl_fops)) {
33611e1ddd6cScth 		/*
33621e1ddd6cScth 		 * First check if the lun has a TPG list in its level 2
33631e1ddd6cScth 		 * structure then, check if this lun is already
33641e1ddd6cScth 		 * accounted for through a different Target Port.
33651e1ddd6cScth 		 * If yes, get the ptr to the TPG & skip new TPG creation.
33661e1ddd6cScth 		 */
33671e1ddd6cScth 		lu_list = vhci_get_mpapi_item(vhci, NULL,
33681e1ddd6cScth 		    MP_OBJECT_TYPE_MULTIPATH_LU, vlun);
33691e1ddd6cScth 		tpg_list = vhci_mpapi_get_tpg_item(vhci, as, vlun, path_class,
33701e1ddd6cScth 		    (void *)tmp_wwn);
33711e1ddd6cScth 		if (tpg_list == NULL) {
33721e1ddd6cScth 			tpg_list = vhci_mpapi_create_item(vhci,
33731e1ddd6cScth 			    MP_OBJECT_TYPE_TARGET_PORT_GROUP, (void *)tmp_wwn);
33741e1ddd6cScth 			tpg_data = tpg_list->item->idata;
33751e1ddd6cScth 			(void) strlcpy(tpg_data->pclass, path_class,
33761e1ddd6cScth 			    sizeof (tpg_data->pclass));
33771e1ddd6cScth 			tpg_data->prop.accessState = as;
33781e1ddd6cScth 		} else {
33791e1ddd6cScth 			tpg_data = tpg_list->item->idata;
33801e1ddd6cScth 		}
33811e1ddd6cScth 
3382860de861Shtk 		if ((vlun != NULL) && SCSI_FAILOVER_IS_ASYM(vlun)) {
33831e1ddd6cScth 			tpg_data->prop.explicitFailover = 1;
33841e1ddd6cScth 		}
33851e1ddd6cScth 
33861e1ddd6cScth 		/*
33871e1ddd6cScth 		 * Level 2, Lun Cross referencing to TPG.
33881e1ddd6cScth 		 */
33891e1ddd6cScth 		if (vhci_get_mpapi_item(vhci, tpg_data->lu_list,
33901e1ddd6cScth 		    MP_OBJECT_TYPE_MULTIPATH_LU, (void *)vlun) == NULL) {
33911e1ddd6cScth 			tpg_lu_list = kmem_zalloc(sizeof (mpapi_item_list_t),
33921e1ddd6cScth 			    KM_SLEEP);
33931e1ddd6cScth 			item_list = vhci_get_mpapi_item(vhci, NULL,
33941e1ddd6cScth 			    MP_OBJECT_TYPE_MULTIPATH_LU, (void *)vlun);
33951e1ddd6cScth 			tpg_lu_list->item = item_list->item;
33961e1ddd6cScth 			(void) vhci_mpapi_add_to_list(tpg_data->lu_list,
33971e1ddd6cScth 			    tpg_lu_list);
33981e1ddd6cScth 		}
33991e1ddd6cScth 
34001e1ddd6cScth 		/*
34011e1ddd6cScth 		 * Level 2, Target Port Cross referencing to TPG.
34021e1ddd6cScth 		 */
34031e1ddd6cScth 		if (vhci_get_mpapi_item(vhci, tpg_data->tport_list,
34041e1ddd6cScth 		    MP_OBJECT_TYPE_TARGET_PORT, (void *)tmp_wwn) == NULL) {
34051e1ddd6cScth 			tpg_tport_list = kmem_zalloc(sizeof (mpapi_item_list_t),
34061e1ddd6cScth 			    KM_SLEEP);
34071e1ddd6cScth 			item_list = vhci_get_mpapi_item(vhci, NULL,
34081e1ddd6cScth 			    MP_OBJECT_TYPE_TARGET_PORT, (void *)tmp_wwn);
34091e1ddd6cScth 			tpg_tport_list->item = item_list->item;
34101e1ddd6cScth 			(void) vhci_mpapi_add_to_list(tpg_data->tport_list,
34111e1ddd6cScth 			    tpg_tport_list);
34121e1ddd6cScth 		}
34131e1ddd6cScth 
34141e1ddd6cScth 		/*
34151e1ddd6cScth 		 * Level 2, TPG Cross referencing to Lun.
34161e1ddd6cScth 		 */
34171e1ddd6cScth 		lu_tpg_list = vhci_mpapi_get_tpg_for_lun
34181e1ddd6cScth 		    (vhci, path_class, vlun, tmp_wwn);
34191e1ddd6cScth 		if (lu_tpg_list == NULL) {
34201e1ddd6cScth 			lu_tpg_list = kmem_zalloc(sizeof (mpapi_item_list_t),
34211e1ddd6cScth 			    KM_SLEEP);
34221e1ddd6cScth 			lu_tpg_list->item = tpg_list->item;
34231e1ddd6cScth 			(void) vhci_mpapi_add_to_list(((mpapi_lu_data_t *)
34241e1ddd6cScth 			    (lu_list->item->idata))->tpg_list, lu_tpg_list);
34251e1ddd6cScth 		}
34261e1ddd6cScth 
34271e1ddd6cScth 		/*
34281e1ddd6cScth 		 * Update the AccessState of related MPAPI TPGs
34291e1ddd6cScth 		 * This takes care of a special case where a failover doesn't
34301e1ddd6cScth 		 * happen but a TPG accessState needs to be updated from
34311e1ddd6cScth 		 * Unavailable to Standby
34321e1ddd6cScth 		 */
34331e1ddd6cScth 		(void) vhci_mpapi_update_tpg_acc_state_for_lu(vhci, vlun);
34341e1ddd6cScth 	}
34351e1ddd6cScth 
34361e1ddd6cScth 	if (path_class_not_mdi_alloced == 1) {
34371e1ddd6cScth 		kmem_free(path_class, MPAPI_SCSI_MAXPCLASSLEN);
34381e1ddd6cScth 	}
34391e1ddd6cScth 
34401e1ddd6cScth }
34411e1ddd6cScth 
34421e1ddd6cScth /*
34431e1ddd6cScth  * Routine to create Level 1 mpapi_private data structure for TPG object,
34441e1ddd6cScth  * for devices which support TPG and establish cross references between
34451e1ddd6cScth  * the TPG resources being managed. The RTPG response sent by std_asymmetric
34461e1ddd6cScth  * module is parsed in this routine and mpapi_priv data structure is updated.
34471e1ddd6cScth  */
34481e1ddd6cScth /* ARGSUSED */
34491e1ddd6cScth void
vhci_mpapi_update_tpg_data(struct scsi_address * ap,char * ptr,int rel_tgt_port)3450b1a03ab1SVictor Li vhci_mpapi_update_tpg_data(struct scsi_address *ap, char *ptr,
3451b1a03ab1SVictor Li     int rel_tgt_port)
34521e1ddd6cScth {
345361acaecbSChris Liu 	struct scsi_vhci_lun	*vlun;
345461acaecbSChris Liu 	struct scsi_vhci	*vhci;
345555e592a2SRandall Ralphs 	struct scsi_device	*psd = NULL;
34561e1ddd6cScth 	scsi_vhci_priv_t	*svp;
34571e1ddd6cScth 	mdi_pathinfo_t		*pip;
34581e1ddd6cScth 	dev_info_t		*pdip;
34591e1ddd6cScth 	char			tpg_id[16], *tgt_port, *init = NULL;
34601e1ddd6cScth 	uint32_t		int_tpg_id, rel_tid, as;
34611e1ddd6cScth 	int			i, rel_tport_cnt;
34621e1ddd6cScth 	mpapi_item_list_t	*path_list, *init_list;
34631e1ddd6cScth 	mpapi_item_list_t	*tp_path_list, *init_path_list, *lu_path_list;
34641e1ddd6cScth 	mpapi_item_list_t	*tpg_tport_list, *tpg_lu_list, *lu_list;
34651e1ddd6cScth 	mpapi_item_list_t	*lu_tpg_list, *item_list, *tpg_list, *tgt_list;
34661e1ddd6cScth 	mpapi_lu_data_t		*ld;
34671e1ddd6cScth 	mpapi_tpg_data_t	*tpg_data;
34681e1ddd6cScth 	mpapi_path_data_t	*pd;
34691e1ddd6cScth 	mpapi_tport_data_t	*tpd;
34701e1ddd6cScth 	mpapi_initiator_data_t	*initd;
34711e1ddd6cScth 
34721e1ddd6cScth 	/*
34731e1ddd6cScth 	 * Find out the TPG ID (resource ptr for TPG is T10 TPG ID)
34741e1ddd6cScth 	 */
34751e1ddd6cScth 	int_tpg_id = ((ptr[2] & 0xff) << 8) | (ptr[3] & 0xff);
34761e1ddd6cScth 	(void) sprintf(tpg_id, "%04x", int_tpg_id);
34771e1ddd6cScth 
34781e1ddd6cScth 	/*
34791e1ddd6cScth 	 * Check the TPG's accessState; we'll use it later.
34801e1ddd6cScth 	 */
34811e1ddd6cScth 	as = (ptr[0] & 0x0f);
34821e1ddd6cScth 	if (as == STD_ACTIVE_OPTIMIZED) {
34831e1ddd6cScth 		as = MP_DRVR_ACCESS_STATE_ACTIVE_OPTIMIZED;
34841e1ddd6cScth 	} else if (as == STD_ACTIVE_NONOPTIMIZED) {
34851e1ddd6cScth 		as = MP_DRVR_ACCESS_STATE_ACTIVE_NONOPTIMIZED;
34861e1ddd6cScth 	} else if (as == STD_STANDBY) {
34871e1ddd6cScth 		as = MP_DRVR_ACCESS_STATE_STANDBY;
34881e1ddd6cScth 	} else {
34891e1ddd6cScth 		as = MP_DRVR_ACCESS_STATE_UNAVAILABLE;
34901e1ddd6cScth 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_mpapi_update_tpg_data: "
34911e1ddd6cScth 		    "UNAVAILABLE accessState seen in ALUA TPG setup"));
34921e1ddd6cScth 	}
34931e1ddd6cScth 
34941e1ddd6cScth 	/*
349561acaecbSChris Liu 	 * The scsi_address passed is associated with a scsi_vhci allocated
349661acaecbSChris Liu 	 * scsi_device structure for a pathinfo node. Getting the vlun from
349761acaecbSChris Liu 	 * this is a bit complicated.
34981e1ddd6cScth 	 */
349953a7b6b6SChris Horne 	if (ap->a_hba_tran->tran_hba_flags & SCSI_HBA_ADDR_COMPLEX)
350053a7b6b6SChris Horne 		psd = scsi_address_device(ap);
350153a7b6b6SChris Horne 	else if (ap->a_hba_tran->tran_hba_flags & SCSI_HBA_TRAN_CLONE)
350253a7b6b6SChris Horne 		psd = ap->a_hba_tran->tran_sd;
350355e592a2SRandall Ralphs 	ASSERT(psd);
350455e592a2SRandall Ralphs 	pip = (mdi_pathinfo_t *)psd->sd_pathinfo;
350555e592a2SRandall Ralphs 
350655e592a2SRandall Ralphs 	/*
350755e592a2SRandall Ralphs 	 * It is possable for this code to be called without the sd_pathinfo
350855e592a2SRandall Ralphs 	 * being set. This may happen as part of a probe to see if a device
350955e592a2SRandall Ralphs 	 * should be mapped under mdi. At this point we know enough to answer
351055e592a2SRandall Ralphs 	 * correctly so we can return.
351155e592a2SRandall Ralphs 	 */
351255e592a2SRandall Ralphs 	if (pip == NULL)
351355e592a2SRandall Ralphs 		return;
35141e1ddd6cScth 	svp = (scsi_vhci_priv_t *)mdi_pi_get_vhci_private(pip);
35151e1ddd6cScth 	vlun = svp->svp_svl;
35161e1ddd6cScth 
35171e1ddd6cScth 	/*
35181e1ddd6cScth 	 * Now get the vhci ptr using the walker
35191e1ddd6cScth 	 */
35201e1ddd6cScth 	mdi_walk_vhcis(vhci_mpapi_get_vhci, &vhci);
35211e1ddd6cScth 
35221e1ddd6cScth 	VHCI_DEBUG(4, (CE_NOTE, NULL, "vhci_mpapi_update_tpg_data: vhci=%p, "
35231e1ddd6cScth 	    "(vlun)wwn=(%p)%s, pip=%p, ap=%p, ptr=%p, as=%x, tpg_id=%s, fops="
352461acaecbSChris Liu 	    "%p\n", (void *)vhci, (void *)vlun,
352561acaecbSChris Liu 	    vlun ? vlun->svl_lun_wwn : "NONE",
352661acaecbSChris Liu 	    (void *)pip, (void *)ap, (void *)ptr, as, tpg_id,
352761acaecbSChris Liu 	    (void *)(vlun ? vlun->svl_fops : NULL)));
35281e1ddd6cScth 
352955e592a2SRandall Ralphs 	if ((vhci == NULL) || (vlun == NULL) ||
35301e1ddd6cScth 	    !SCSI_FAILOVER_IS_TPGS(vlun->svl_fops)) {
35311e1ddd6cScth 		/* Cant help, unfortunate situation */
35321e1ddd6cScth 		return;
35331e1ddd6cScth 	}
35341e1ddd6cScth 
35351e1ddd6cScth 	/*
35361e1ddd6cScth 	 * LEVEL 1 - Actions:
35371e1ddd6cScth 	 * Check if the appropriate resource pointers already
35381e1ddd6cScth 	 * exist in the Level 1 list and add them if they are new.
35391e1ddd6cScth 	 */
35401e1ddd6cScth 
35411e1ddd6cScth 	/*
35421e1ddd6cScth 	 * Build MP LU list
35431e1ddd6cScth 	 */
35441e1ddd6cScth 	lu_list = vhci_get_mpapi_item(vhci, NULL,
35451e1ddd6cScth 	    MP_OBJECT_TYPE_MULTIPATH_LU, (void*)vlun);
35461e1ddd6cScth 	if (lu_list == NULL) {
35471e1ddd6cScth 		/* Need to create lu_list entry */
35481e1ddd6cScth 		lu_list = vhci_mpapi_create_item(vhci,
35491e1ddd6cScth 		    MP_OBJECT_TYPE_MULTIPATH_LU, (void*)vlun);
35501e1ddd6cScth 	} else {
35511e1ddd6cScth 		/*
35521e1ddd6cScth 		 * Matched this lu w/ an existing one in current lu list.
35531e1ddd6cScth 		 * SAME LUN came online!! So, update the resp in main list.
35541e1ddd6cScth 		 */
35551e1ddd6cScth 		ld = lu_list->item->idata;
355617d71211SJiri Svoboda 		vhci_mpapi_set_lu_valid(vhci, lu_list->item, 1);
35571e1ddd6cScth 		ld->resp = vlun;
35581e1ddd6cScth 	}
35591e1ddd6cScth 
35601e1ddd6cScth 	/*
35611e1ddd6cScth 	 * Build Path LU list
35621e1ddd6cScth 	 */
35631e1ddd6cScth 	path_list = vhci_get_mpapi_item(vhci, NULL,
35641e1ddd6cScth 	    MP_OBJECT_TYPE_PATH_LU, (void*)pip);
35651e1ddd6cScth 	if (path_list == NULL) {
35661e1ddd6cScth 		/* Need to create path_list entry */
35671e1ddd6cScth 		path_list = vhci_mpapi_create_item(vhci,
35681e1ddd6cScth 		    MP_OBJECT_TYPE_PATH_LU, (void*)pip);
35691e1ddd6cScth 	} else {
35701e1ddd6cScth 		/*
35711e1ddd6cScth 		 * Matched this pip w/ an existing one in current pip list.
35721e1ddd6cScth 		 * SAME PATH came online!! So, update the resp in main list.
35731e1ddd6cScth 		 */
35741e1ddd6cScth 		pd = path_list->item->idata;
35751e1ddd6cScth 		pd->valid = 1;
35761e1ddd6cScth 		pd->resp = pip;
35771e1ddd6cScth 	}
35781e1ddd6cScth 
35791e1ddd6cScth 	if (MDI_PI_IS_ONLINE(pip)) {
35801e1ddd6cScth 		vhci_mpapi_set_path_state(vhci->vhci_dip, pip,
35811e1ddd6cScth 		    MP_DRVR_PATH_STATE_ACTIVE);
35821e1ddd6cScth 	} else if (MDI_PI_IS_STANDBY(pip)) {
35831e1ddd6cScth 		vhci_mpapi_set_path_state(vhci->vhci_dip, pip,
35841e1ddd6cScth 		    MP_DRVR_PATH_STATE_PASSIVE);
35851e1ddd6cScth 	} else {
35861e1ddd6cScth 		vhci_mpapi_set_path_state(vhci->vhci_dip, pip,
35871e1ddd6cScth 		    MP_DRVR_PATH_STATE_UNKNOWN);
35881e1ddd6cScth 	}
35891e1ddd6cScth 
35901e1ddd6cScth 	/*
35911e1ddd6cScth 	 * Build Initiator Port list
35921e1ddd6cScth 	 */
35931e1ddd6cScth 	pdip = mdi_pi_get_phci(pip);
35941e1ddd6cScth 	init = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
35951e1ddd6cScth 	(void) ddi_pathname(pdip, init);
35961e1ddd6cScth 
35971e1ddd6cScth 	init_list = vhci_get_mpapi_item(vhci, NULL,
35981e1ddd6cScth 	    MP_OBJECT_TYPE_INITIATOR_PORT, (void*)init);
35991e1ddd6cScth 	if (init_list == NULL) {
36001e1ddd6cScth 		/*
36011e1ddd6cScth 		 * Need to create init_list entry
36021e1ddd6cScth 		 * The resource ptr is no really pdip. It will be changed
36031e1ddd6cScth 		 * in vhci_mpapi_create_item(). The real resource ptr
36041e1ddd6cScth 		 * is the Port ID. But we pass the pdip, to create OID.
36051e1ddd6cScth 		 */
36061e1ddd6cScth 		init_list = vhci_mpapi_create_item(vhci,
36071e1ddd6cScth 		    MP_OBJECT_TYPE_INITIATOR_PORT, (void*)pdip);
36081e1ddd6cScth 	} else {
36091e1ddd6cScth 		initd = init_list->item->idata;
36101e1ddd6cScth 		initd->valid = 1;
36111e1ddd6cScth 	}
36121e1ddd6cScth 	kmem_free(init, MAXPATHLEN);
36131e1ddd6cScth 
36141e1ddd6cScth 	/*
36151e1ddd6cScth 	 * LEVEL 2 - Actions:
36161e1ddd6cScth 	 * Since all the Object type item lists are updated to account
36171e1ddd6cScth 	 * for the new resources, now lets cross-reference these
36181e1ddd6cScth 	 * resources (mainly through paths) to maintain the
36191e1ddd6cScth 	 * relationship between them.
36201e1ddd6cScth 	 */
36211e1ddd6cScth 
36221e1ddd6cScth 	ld = (mpapi_lu_data_t *)lu_list->item->idata;
36231e1ddd6cScth 	if (vhci_get_mpapi_item(vhci, ld->path_list,
36241e1ddd6cScth 	    MP_OBJECT_TYPE_PATH_LU, (void*)pip) == NULL) {
36251e1ddd6cScth 		lu_path_list = kmem_zalloc(sizeof (mpapi_item_list_t),
36261e1ddd6cScth 		    KM_SLEEP);
36271e1ddd6cScth 		lu_path_list->item = path_list->item;
36281e1ddd6cScth 		(void) vhci_mpapi_add_to_list(ld->path_list, lu_path_list);
36291e1ddd6cScth 	}
36301e1ddd6cScth 
36311e1ddd6cScth 	initd = (mpapi_initiator_data_t *)init_list->item->idata;
36321e1ddd6cScth 	if (vhci_get_mpapi_item(vhci, initd->path_list,
36331e1ddd6cScth 	    MP_OBJECT_TYPE_PATH_LU, (void*)pip) == NULL) {
36341e1ddd6cScth 		init_path_list = kmem_zalloc(sizeof (mpapi_item_list_t),
36351e1ddd6cScth 		    KM_SLEEP);
36361e1ddd6cScth 		init_path_list->item = path_list->item;
36371e1ddd6cScth 		(void) vhci_mpapi_add_to_list(initd->path_list, init_path_list);
36381e1ddd6cScth 	}
36391e1ddd6cScth 
36401e1ddd6cScth 	/*
36419b4f248cSChris Liu 	 * Building Target Port list is different here.
36429b4f248cSChris Liu 	 * For each different Relative Target Port. we have a new MPAPI
36439b4f248cSChris Liu 	 * Target Port OID generated.
36449b4f248cSChris Liu 	 * Just find out the main Target Port property here.
36451e1ddd6cScth 	 */
36469b4f248cSChris Liu 	tgt_port = NULL;
36479b4f248cSChris Liu 	if (mdi_prop_lookup_string(pip, SCSI_ADDR_PROP_TARGET_PORT,
36489b4f248cSChris Liu 	    &tgt_port) != DDI_PROP_SUCCESS) {
36499b4f248cSChris Liu 		/* XXX: target-port prop not found */
36509b4f248cSChris Liu 		tgt_port = (char *)mdi_pi_get_addr(pip);
36519b4f248cSChris Liu 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_mpapi_update_tpg_data: "
36529b4f248cSChris Liu 		    "mdi_prop_lookup_string() returned failure; "
36539b4f248cSChris Liu 		    "Hence tgt_port = %p", (void *)tgt_port));
36549b4f248cSChris Liu 	}
36551e1ddd6cScth 
36569b4f248cSChris Liu 	/* Search for existing group that contains this target port */
36579b4f248cSChris Liu 	tpg_list = vhci_mpapi_get_alua_item(vhci, vlun, &tpg_id, tgt_port);
36581e1ddd6cScth 	if (tpg_list == NULL) {
36591e1ddd6cScth 		tpg_list = vhci_mpapi_create_item(vhci,
36601e1ddd6cScth 		    MP_OBJECT_TYPE_TARGET_PORT_GROUP, &tpg_id);
36611e1ddd6cScth 	}
36621e1ddd6cScth 	tpg_data = tpg_list->item->idata;
36631e1ddd6cScth 	tpg_data->prop.accessState = as;
36641e1ddd6cScth 	tpg_data->prop.tpgId = int_tpg_id;
36651e1ddd6cScth 
36661e1ddd6cScth 	/*
36671e1ddd6cScth 	 * Set explicitFailover for TPG -
36681e1ddd6cScth 	 * based on tpgs_bits setting in Std Inquiry response.
36691e1ddd6cScth 	 */
367055e592a2SRandall Ralphs 	switch (psd->sd_inq->inq_tpgs) {
367155e592a2SRandall Ralphs 	case TPGS_FAILOVER_EXPLICIT:
367255e592a2SRandall Ralphs 	case TPGS_FAILOVER_BOTH:
36731e1ddd6cScth 		tpg_data->prop.explicitFailover = 1;
367455e592a2SRandall Ralphs 		break;
367555e592a2SRandall Ralphs 	case TPGS_FAILOVER_IMPLICIT:
36761e1ddd6cScth 		tpg_data->prop.explicitFailover = 0;
367755e592a2SRandall Ralphs 		break;
367855e592a2SRandall Ralphs 	default:
367955e592a2SRandall Ralphs 		return;
36801e1ddd6cScth 	}
36811e1ddd6cScth 
36821e1ddd6cScth 	/*
36831e1ddd6cScth 	 * Level 2, Lun Cross referencing to TPG.
36841e1ddd6cScth 	 */
36851e1ddd6cScth 	if (vhci_get_mpapi_item(vhci, tpg_data->lu_list,
36861e1ddd6cScth 	    MP_OBJECT_TYPE_MULTIPATH_LU, (void *)vlun) == NULL) {
36871e1ddd6cScth 		tpg_lu_list = kmem_zalloc(sizeof (mpapi_item_list_t),
36881e1ddd6cScth 		    KM_SLEEP);
36891e1ddd6cScth 		item_list = vhci_get_mpapi_item(vhci, NULL,
36901e1ddd6cScth 		    MP_OBJECT_TYPE_MULTIPATH_LU, (void *)vlun);
36911e1ddd6cScth 		tpg_lu_list->item = item_list->item;
36921e1ddd6cScth 		(void) vhci_mpapi_add_to_list(tpg_data->lu_list,
36931e1ddd6cScth 		    tpg_lu_list);
36941e1ddd6cScth 	}
36951e1ddd6cScth 
36961e1ddd6cScth 	/*
36971e1ddd6cScth 	 * Level 2, TPG Cross referencing to Lun.
36981e1ddd6cScth 	 */
36991e1ddd6cScth 	if (vhci_get_mpapi_item(vhci, ld->tpg_list,
37001e1ddd6cScth 	    MP_OBJECT_TYPE_TARGET_PORT_GROUP, &tpg_id) == 0) {
37011e1ddd6cScth 		lu_tpg_list = kmem_zalloc(sizeof (mpapi_item_list_t),
37021e1ddd6cScth 		    KM_SLEEP);
37031e1ddd6cScth 		lu_tpg_list->item = tpg_list->item;
37041e1ddd6cScth 		(void) vhci_mpapi_add_to_list(((mpapi_lu_data_t *)
37051e1ddd6cScth 		    (lu_list->item->idata))->tpg_list, lu_tpg_list);
37061e1ddd6cScth 	}
37071e1ddd6cScth 
37081e1ddd6cScth 	/*
37091e1ddd6cScth 	 * Level 1, Relative Target Port + Target Port Creation
37101e1ddd6cScth 	 */
37111e1ddd6cScth 	rel_tport_cnt = (ptr[7] & 0xff);
37121e1ddd6cScth 	ptr += 8;
37131e1ddd6cScth 	for (i = 0; i < rel_tport_cnt; i++) {
37141e1ddd6cScth 		rel_tid = 0;
37151e1ddd6cScth 		rel_tid |= ((ptr[2] & 0Xff) << 8);
37161e1ddd6cScth 		rel_tid |= (ptr[3] & 0xff);
37171e1ddd6cScth 
3718b1a03ab1SVictor Li 		if (rel_tid != rel_tgt_port) {
3719b1a03ab1SVictor Li 			ptr += 4;
3720b1a03ab1SVictor Li 			continue;
3721b1a03ab1SVictor Li 		}
3722b1a03ab1SVictor Li 
37231e1ddd6cScth 		VHCI_DEBUG(4, (CE_NOTE, NULL, "vhci_mpapi_update_tpg_data: "
37241e1ddd6cScth 		    "TgtPort=%s, RelTgtPort=%x\n", tgt_port, rel_tid));
37251e1ddd6cScth 
37261e1ddd6cScth 		tgt_list = vhci_mpapi_get_rel_tport_pair(vhci, NULL,
37271e1ddd6cScth 		    (void *)tgt_port, rel_tid);
37281e1ddd6cScth 		if (tgt_list == NULL) {
37291e1ddd6cScth 			/* Need to create tgt_list entry */
37301e1ddd6cScth 			tgt_list = vhci_mpapi_create_item(vhci,
37311e1ddd6cScth 			    MP_OBJECT_TYPE_TARGET_PORT,
37321e1ddd6cScth 			    (void *)tgt_port);
37331e1ddd6cScth 			tpd = tgt_list->item->idata;
37341e1ddd6cScth 			tpd->valid = 1;
37351e1ddd6cScth 			tpd->prop.relativePortID = rel_tid;
37361e1ddd6cScth 		} else {
37371e1ddd6cScth 			tpd = tgt_list->item->idata;
37381e1ddd6cScth 			tpd->valid = 1;
37391e1ddd6cScth 		}
37401e1ddd6cScth 
37411e1ddd6cScth 		tpd = (mpapi_tport_data_t *)tgt_list->item->idata;
37421e1ddd6cScth 		if (vhci_get_mpapi_item(vhci, tpd->path_list,
37431e1ddd6cScth 		    MP_OBJECT_TYPE_PATH_LU, (void*)pip) == NULL) {
37441e1ddd6cScth 			tp_path_list = kmem_zalloc(sizeof (mpapi_item_list_t),
37451e1ddd6cScth 			    KM_SLEEP);
37461e1ddd6cScth 			tp_path_list->item = path_list->item;
37471e1ddd6cScth 			(void) vhci_mpapi_add_to_list(tpd->path_list,
37481e1ddd6cScth 			    tp_path_list);
37491e1ddd6cScth 		}
37501e1ddd6cScth 
37511e1ddd6cScth 		if (vhci_mpapi_get_rel_tport_pair(vhci,
37521e1ddd6cScth 		    tpg_data->tport_list, tgt_port, rel_tid) == NULL) {
37531e1ddd6cScth 			tpg_tport_list = kmem_zalloc
37541e1ddd6cScth 			    (sizeof (mpapi_item_list_t), KM_SLEEP);
37551e1ddd6cScth 			tpg_tport_list->item = tgt_list->item;
37561e1ddd6cScth 			(void) vhci_mpapi_add_to_list(tpg_data->
37571e1ddd6cScth 			    tport_list, tpg_tport_list);
37581e1ddd6cScth 		}
37591e1ddd6cScth 		ptr += 4;
37601e1ddd6cScth 	}
37611e1ddd6cScth 
37621e1ddd6cScth 	/*
37631e1ddd6cScth 	 * Level-1: Fill-out Path Properties now, since we got all details.
37641e1ddd6cScth 	 * Actually, It is a structure copy, rather than just filling details.
37651e1ddd6cScth 	 */
37661e1ddd6cScth 	pd = path_list->item->idata;
37671e1ddd6cScth 	bcopy(&(ld->prop), &(pd->prop.logicalUnit),
37681e1ddd6cScth 	    sizeof (struct mp_logical_unit_prop));
37691e1ddd6cScth 	bcopy(&(initd->prop), &(pd->prop.initPort),
37701e1ddd6cScth 	    sizeof (struct mp_init_port_prop));
37711e1ddd6cScth 	bcopy(&(tpd->prop), &(pd->prop.targetPort),
37721e1ddd6cScth 	    sizeof (struct mp_target_port_prop));
37731e1ddd6cScth }
37741e1ddd6cScth 
37751e1ddd6cScth /*
37761e1ddd6cScth  * Routine to get mpapi ioctl argument structure from userland.
37771e1ddd6cScth  */
37781e1ddd6cScth /* ARGSUSED */
37791e1ddd6cScth static int
vhci_get_mpiocdata(const void * data,mp_iocdata_t * mpioc,int mode)37801e1ddd6cScth vhci_get_mpiocdata(const void *data, mp_iocdata_t *mpioc, int mode)
37811e1ddd6cScth {
37821e1ddd6cScth 	int	retval = 0;
37831e1ddd6cScth 
37841e1ddd6cScth #ifdef  _MULTI_DATAMODEL
37851e1ddd6cScth 	switch (ddi_model_convert_from(mode & FMODELS)) {
37861e1ddd6cScth 	case DDI_MODEL_ILP32:
37871e1ddd6cScth 	{
37881e1ddd6cScth 		mp_iocdata32_t	ioc32;
37891e1ddd6cScth 
37901e1ddd6cScth 		VHCI_DEBUG(6, (CE_WARN, NULL, "vhci_get_mpiocdata: "
37911e1ddd6cScth 		    "Case DDI_MODEL_ILP32"));
37921e1ddd6cScth 		if (ddi_copyin((void *)data, (void *)&ioc32,
37931e1ddd6cScth 		    sizeof (mp_iocdata32_t), mode)) {
37941e1ddd6cScth 			VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_get_mpiocdata: "
37951e1ddd6cScth 			    "ddi_copyin() FAILED"));
37961e1ddd6cScth 			retval = EFAULT;
37971e1ddd6cScth 			break;
37981e1ddd6cScth 		}
37991e1ddd6cScth 		mpioc->mp_xfer	= (uint16_t)(uintptr_t)ioc32.mp_xfer;
38001e1ddd6cScth 		mpioc->mp_cmd	= (uint16_t)(uintptr_t)ioc32.mp_cmd;
38011e1ddd6cScth 		mpioc->mp_flags	= (uint16_t)(uintptr_t)ioc32.mp_flags;
38021e1ddd6cScth 		mpioc->mp_cmd_flags	= (uint16_t)ioc32.mp_cmd_flags;
38031e1ddd6cScth 		mpioc->mp_ilen	= (size_t)(uintptr_t)ioc32.mp_ilen;
38041e1ddd6cScth 		mpioc->mp_ibuf	= (caddr_t)(uintptr_t)ioc32.mp_ibuf;
38051e1ddd6cScth 		mpioc->mp_olen	= (size_t)(uintptr_t)ioc32.mp_olen;
38061e1ddd6cScth 		mpioc->mp_obuf	= (caddr_t)(uintptr_t)ioc32.mp_obuf;
38071e1ddd6cScth 		mpioc->mp_alen	= (size_t)(uintptr_t)ioc32.mp_alen;
38081e1ddd6cScth 		mpioc->mp_abuf	= (caddr_t)(uintptr_t)ioc32.mp_abuf;
38091e1ddd6cScth 		mpioc->mp_errno	= (int)(uintptr_t)ioc32.mp_errno;
38101e1ddd6cScth 		break;
38111e1ddd6cScth 	}
38121e1ddd6cScth 
38131e1ddd6cScth 	case DDI_MODEL_NONE:
38141e1ddd6cScth 		if (ddi_copyin(data, (void*)mpioc, sizeof (*mpioc), mode)) {
38151e1ddd6cScth 			retval = EFAULT;
38161e1ddd6cScth 			break;
38171e1ddd6cScth 		}
38181e1ddd6cScth 		break;
38191e1ddd6cScth 
38201e1ddd6cScth 	default:
38211e1ddd6cScth 		if (ddi_copyin(data, (void*)mpioc, sizeof (*mpioc), mode)) {
38221e1ddd6cScth 			retval = EFAULT;
38231e1ddd6cScth 			break;
38241e1ddd6cScth 		}
38251e1ddd6cScth 		break;
38261e1ddd6cScth 	}
38271e1ddd6cScth #else   /* _MULTI_DATAMODEL */
38281e1ddd6cScth 	if (ddi_copyin(data, (void *)mpioc, sizeof (*mpioc), mode)) {
38291e1ddd6cScth 		retval = EFAULT;
38301e1ddd6cScth 	}
38311e1ddd6cScth #endif  /* _MULTI_DATAMODEL */
38321e1ddd6cScth 
38331e1ddd6cScth 	if (retval) {
38341e1ddd6cScth 		VHCI_DEBUG(2, (CE_WARN, NULL, "vhci_get_mpiocdata: cmd <%x> "
38351e1ddd6cScth 		    "iocdata copyin failed", mpioc->mp_cmd));
38361e1ddd6cScth 	}
38371e1ddd6cScth 
38381e1ddd6cScth 	return (retval);
38391e1ddd6cScth }
38401e1ddd6cScth 
38411e1ddd6cScth /* ARGSUSED */
38421e1ddd6cScth static int
vhci_is_model_type32(int mode)38431e1ddd6cScth vhci_is_model_type32(int mode)
38441e1ddd6cScth {
38451e1ddd6cScth #ifdef  _MULTI_DATAMODEL
38461e1ddd6cScth 	switch (ddi_model_convert_from(mode & FMODELS)) {
38471e1ddd6cScth 		case DDI_MODEL_ILP32:
38481e1ddd6cScth 			return (1);
38491e1ddd6cScth 		default:
38501e1ddd6cScth 			return (0);
38511e1ddd6cScth 	}
38521e1ddd6cScth #else   /* _MULTI_DATAMODEL */
38531e1ddd6cScth 	return (0);
38541e1ddd6cScth #endif  /* _MULTI_DATAMODEL */
38551e1ddd6cScth }
38561e1ddd6cScth 
38571e1ddd6cScth /*
38581e1ddd6cScth  * Convenience routine to copy mp_iocdata(32) to user land
38591e1ddd6cScth  */
38601e1ddd6cScth /* ARGSUSED */
38611e1ddd6cScth static int
vhci_mpapi_copyout_iocdata(void * mpioc,void * udata,int mode)38621e1ddd6cScth vhci_mpapi_copyout_iocdata(void *mpioc, void *udata, int mode)
38631e1ddd6cScth {
38641e1ddd6cScth 	int	rval = 0;
38651e1ddd6cScth 
38661e1ddd6cScth 	if (vhci_is_model_type32(mode)) {
38671e1ddd6cScth 		mp_iocdata32_t	*mpioc32;
38681e1ddd6cScth 
38691e1ddd6cScth 		mpioc32 = (mp_iocdata32_t *)kmem_zalloc
38701e1ddd6cScth 		    (sizeof (mp_iocdata32_t), KM_SLEEP);
38711e1ddd6cScth 		mpioc32->mp_xfer = (uint16_t)((mp_iocdata_t *)mpioc)->mp_xfer;
38721e1ddd6cScth 		mpioc32->mp_cmd	 = (uint16_t)((mp_iocdata_t *)mpioc)->mp_cmd;
38731e1ddd6cScth 		mpioc32->mp_flags = (uint16_t)((mp_iocdata_t *)mpioc)->mp_flags;
38741e1ddd6cScth 		mpioc32->mp_cmd_flags = (uint16_t)((mp_iocdata_t *)
38751e1ddd6cScth 		    mpioc)->mp_cmd_flags;
38761e1ddd6cScth 		mpioc32->mp_ilen = (uint32_t)((mp_iocdata_t *)mpioc)->mp_ilen;
38771e1ddd6cScth 		mpioc32->mp_ibuf = (caddr32_t)((mp_iocdata32_t *)
38781e1ddd6cScth 		    mpioc)->mp_ibuf;
38791e1ddd6cScth 		mpioc32->mp_olen = (uint32_t)((mp_iocdata_t *)mpioc)->mp_olen;
38801e1ddd6cScth 		mpioc32->mp_obuf = (caddr32_t)((mp_iocdata32_t *)
38811e1ddd6cScth 		    mpioc)->mp_obuf;
38821e1ddd6cScth 		mpioc32->mp_alen = (uint32_t)((mp_iocdata_t *)mpioc)->mp_alen;
38831e1ddd6cScth 		mpioc32->mp_abuf = (caddr32_t)((mp_iocdata32_t *)
38841e1ddd6cScth 		    mpioc)->mp_abuf;
38851e1ddd6cScth 		mpioc32->mp_errno = (int32_t)((mp_iocdata_t *)mpioc)->mp_errno;
38861e1ddd6cScth 
38871e1ddd6cScth 		if (ddi_copyout(mpioc32, udata, sizeof (mp_iocdata32_t), mode)
38881e1ddd6cScth 		    != 0) {
38891e1ddd6cScth 			rval = EFAULT;
38901e1ddd6cScth 		}
38911e1ddd6cScth 		kmem_free(mpioc32, sizeof (mp_iocdata32_t));
38921e1ddd6cScth 	} else {
38931e1ddd6cScth 		/* 64-bit ddicopyout */
38941e1ddd6cScth 		if (ddi_copyout(mpioc, udata, sizeof (mp_iocdata_t), mode)
38951e1ddd6cScth 		    != 0) {
38961e1ddd6cScth 			rval = EFAULT;
38971e1ddd6cScth 		}
38981e1ddd6cScth 	}
38991e1ddd6cScth 
39001e1ddd6cScth 	return (rval);
39011e1ddd6cScth 
39021e1ddd6cScth }
39031e1ddd6cScth 
39041e1ddd6cScth /*
39051e1ddd6cScth  * Routine to sync OIDs of MPLU to match with the ssd instance# of the
39061e1ddd6cScth  * scsi_vhci lun, to accommodate the DINFOCACHE implementation of the plugin.
39071e1ddd6cScth  * ssd instance# = devi_instance from the dev_info structure.
39081e1ddd6cScth  * dev_info structure of the scsi_vhci lun is pointed by svl_dip field of
39091e1ddd6cScth  * scsi_vhci_lun structure.
39101e1ddd6cScth  */
39111e1ddd6cScth /* ARGSUSED */
39121e1ddd6cScth static int
vhci_mpapi_sync_lu_oid_list(struct scsi_vhci * vhci)39131e1ddd6cScth vhci_mpapi_sync_lu_oid_list(struct scsi_vhci *vhci)
39141e1ddd6cScth {
39151e1ddd6cScth 	int			rval = 0;
39161e1ddd6cScth 	mpapi_item_list_t	*ilist;
39171e1ddd6cScth 	mpapi_lu_data_t		*lud;
39181e1ddd6cScth 	mpapi_path_data_t	*pd;
39191e1ddd6cScth 	scsi_vhci_lun_t		*svl;
39201e1ddd6cScth 	dev_info_t		*lun_dip;
39210c034175SJiri Svoboda 	uint64_t		raw_oid;
39221e1ddd6cScth 
39231e1ddd6cScth 	ilist = vhci->mp_priv->obj_hdr_list[MP_OBJECT_TYPE_MULTIPATH_LU]->head;
39241e1ddd6cScth 
39251e1ddd6cScth 	while (ilist != NULL) {
392661acaecbSChris Liu 		lud = ilist->item->idata;
392761acaecbSChris Liu 		if (lud->valid == 1) {
392861acaecbSChris Liu 			svl = lud->resp;
39290c034175SJiri Svoboda 
39300c034175SJiri Svoboda 			/*
39310c034175SJiri Svoboda 			 * Compose OID from major number and instance number.
39320c034175SJiri Svoboda 			 */
39330c034175SJiri Svoboda 			raw_oid = 0;
39340c034175SJiri Svoboda 			raw_oid = MP_STORE_INST_TO_ID(
39350c034175SJiri Svoboda 			    ddi_get_instance(svl->svl_dip), raw_oid);
39360c034175SJiri Svoboda 			raw_oid = MP_STORE_MAJOR_TO_ID(
39370c034175SJiri Svoboda 			    ddi_driver_major(svl->svl_dip), raw_oid);
39380c034175SJiri Svoboda 
39390c034175SJiri Svoboda 			ilist->item->oid.raw_oid = raw_oid;
39400c034175SJiri Svoboda 			lud->prop.id = raw_oid;
39411e1ddd6cScth 		}
39421e1ddd6cScth 		ilist = ilist->next;
39431e1ddd6cScth 	}
39441e1ddd6cScth 
39451e1ddd6cScth 	ilist = vhci->mp_priv->obj_hdr_list[MP_OBJECT_TYPE_PATH_LU]->head;
39461e1ddd6cScth 	while (ilist != NULL) {
39471e1ddd6cScth 		pd = ilist->item->idata;
39480c034175SJiri Svoboda 		if (pd->valid == 1) {
39491e1ddd6cScth 			lun_dip = mdi_pi_get_client
39501e1ddd6cScth 			    ((mdi_pathinfo_t *)(pd->resp));
39510c034175SJiri Svoboda 
39520c034175SJiri Svoboda 			/*
39530c034175SJiri Svoboda 			 * Compose OID from major number and instance number.
39540c034175SJiri Svoboda 			 */
39550c034175SJiri Svoboda 			raw_oid = 0;
39560c034175SJiri Svoboda 			raw_oid = MP_STORE_INST_TO_ID(
39570c034175SJiri Svoboda 			    ddi_get_instance(lun_dip), raw_oid);
39580c034175SJiri Svoboda 			raw_oid = MP_STORE_MAJOR_TO_ID(
39590c034175SJiri Svoboda 			    ddi_driver_major(lun_dip), raw_oid);
39600c034175SJiri Svoboda 
39610c034175SJiri Svoboda 			pd->prop.logicalUnit.id = raw_oid;
39621e1ddd6cScth 		}
39631e1ddd6cScth 		ilist = ilist->next;
39641e1ddd6cScth 	}
39651e1ddd6cScth 
39661e1ddd6cScth 	return (rval);
39671e1ddd6cScth }
39681e1ddd6cScth 
396917d71211SJiri Svoboda /*
397017d71211SJiri Svoboda  * Set new value for the valid field of an MP LU.
397117d71211SJiri Svoboda  *
397217d71211SJiri Svoboda  * This should be called to set new value for the valid field instead of
397317d71211SJiri Svoboda  * accessing it directly. If the value has changed, the appropriate
397417d71211SJiri Svoboda  * sysevent is generated.
397517d71211SJiri Svoboda  *
397617d71211SJiri Svoboda  * An exception is when the LU is created an the valid field is set for
397717d71211SJiri Svoboda  * the first time. In this case we do not want to generate an event
397817d71211SJiri Svoboda  * so the field should be set directly instead of calling this function.
397917d71211SJiri Svoboda  *
398017d71211SJiri Svoboda  * Rationale for introducing ESC_SUN_MP_LU_{ADD|REMOVE}: When the last
398117d71211SJiri Svoboda  * path to a MPLU goes offline, the client node is offlined (not removed).
398217d71211SJiri Svoboda  * When a path to the MPLU goes back online, the client node is onlined.
398317d71211SJiri Svoboda  * There is no existing sysevent that whould announce this.
398417d71211SJiri Svoboda  * EC_DEVFS / ESC_DEVFS_DEVI_{ADD|REMOVE} do not work, because the
398517d71211SJiri Svoboda  * client node is just offlined/onlined, not removed/re-added.
398617d71211SJiri Svoboda  * EC_DEV_{ADD|REMOVE} / ESC_DISK only works for block devices, not
398717d71211SJiri Svoboda  * for other LUs (such as tape). Therefore special event subclasses
398817d71211SJiri Svoboda  * for addition/removal of a MPLU are needed.
398917d71211SJiri Svoboda  */
vhci_mpapi_set_lu_valid(struct scsi_vhci * vhci,mpapi_item_t * lu_item,int valid)399017d71211SJiri Svoboda static void vhci_mpapi_set_lu_valid(struct scsi_vhci *vhci,
399117d71211SJiri Svoboda     mpapi_item_t *lu_item, int valid)
399217d71211SJiri Svoboda {
399317d71211SJiri Svoboda 	mpapi_lu_data_t *lu_data;
399417d71211SJiri Svoboda 
399517d71211SJiri Svoboda 	lu_data = (mpapi_lu_data_t *)lu_item->idata;
399617d71211SJiri Svoboda 	if (valid == lu_data->valid)
399717d71211SJiri Svoboda 		return;
399817d71211SJiri Svoboda 	lu_data->valid = valid;
399917d71211SJiri Svoboda 
400017d71211SJiri Svoboda 	vhci_mpapi_log_sysevent(vhci->vhci_dip, &(lu_item->oid.raw_oid),
400117d71211SJiri Svoboda 	    valid ? ESC_SUN_MP_LU_ADD : ESC_SUN_MP_LU_REMOVE);
400217d71211SJiri Svoboda }
400317d71211SJiri Svoboda 
400417d71211SJiri Svoboda /*
400517d71211SJiri Svoboda  * Set new value for TPG accessState property.
400617d71211SJiri Svoboda  *
400717d71211SJiri Svoboda  * This should be called to set the new value instead of changing the field
400817d71211SJiri Svoboda  * directly. If the value has changed, the appropriate sysevent is generated.
400917d71211SJiri Svoboda  *
401017d71211SJiri Svoboda  * An exception is when the TPG is created and the accessState field is set
401117d71211SJiri Svoboda  * for the first time. In this case we do not want to generate an event
401217d71211SJiri Svoboda  * so the field should be set directly instead of calling this function.
401317d71211SJiri Svoboda  */
vhci_mpapi_set_tpg_as_prop(struct scsi_vhci * vhci,mpapi_item_t * tpg_item,uint32_t new_state)401417d71211SJiri Svoboda static void vhci_mpapi_set_tpg_as_prop(struct scsi_vhci *vhci,
401517d71211SJiri Svoboda     mpapi_item_t *tpg_item, uint32_t new_state)
401617d71211SJiri Svoboda {
401717d71211SJiri Svoboda 	mpapi_tpg_data_t *tpg_data;
401817d71211SJiri Svoboda 
401917d71211SJiri Svoboda 	tpg_data = (mpapi_tpg_data_t *)tpg_item->idata;
402017d71211SJiri Svoboda 	if (new_state == tpg_data->prop.accessState)
402117d71211SJiri Svoboda 		return;
402217d71211SJiri Svoboda 	tpg_data->prop.accessState = new_state;
402317d71211SJiri Svoboda 
402417d71211SJiri Svoboda 	vhci_mpapi_log_sysevent(vhci->vhci_dip, &(tpg_item->oid.raw_oid),
402517d71211SJiri Svoboda 	    ESC_SUN_MP_TPG_CHANGE);
402617d71211SJiri Svoboda }
402717d71211SJiri Svoboda 
40281e1ddd6cScth /*
40291e1ddd6cScth  * Routine to sync Initiator Port List with what MDI maintains. This means
40301e1ddd6cScth  * MP API knows about Initiator Ports which don't have a pip.
40311e1ddd6cScth  */
40321e1ddd6cScth /* ARGSUSED */
40331e1ddd6cScth int
vhci_mpapi_sync_init_port_list(dev_info_t * pdip,void * arg)40341e1ddd6cScth vhci_mpapi_sync_init_port_list(dev_info_t *pdip, void *arg)
40351e1ddd6cScth {
40361e1ddd6cScth 	int			init_not_ddi_alloced = 0;
40371e1ddd6cScth 	struct scsi_vhci	*vhci = arg;
40381e1ddd6cScth 	char			*init, *init_port_res;
40391e1ddd6cScth 	mpapi_item_list_t	*init_list;
40401e1ddd6cScth 	mpapi_initiator_data_t	*initd;
40411e1ddd6cScth 
404255e592a2SRandall Ralphs 	if ((ddi_prop_lookup_string(DDI_DEV_T_ANY, pdip, DDI_PROP_DONTPASS,
404355e592a2SRandall Ralphs 	    SCSI_ADDR_PROP_INITIATOR_PORT, &init) != DDI_PROP_SUCCESS)) {
40441e1ddd6cScth 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_mpapi_sync_init_port_list: "
404555e592a2SRandall Ralphs 		    SCSI_ADDR_PROP_INITIATOR_PORT " prop not found"));
40461e1ddd6cScth 		init = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
40471e1ddd6cScth 		init_not_ddi_alloced = 1;
40481e1ddd6cScth 		(void) ddi_pathname(pdip, init);
40491e1ddd6cScth 	}
40501e1ddd6cScth 
40511e1ddd6cScth 	init_port_res = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
40521e1ddd6cScth 	(void) ddi_pathname(pdip, init_port_res);
40531e1ddd6cScth 
40541e1ddd6cScth 	init_list = vhci_get_mpapi_item(vhci, NULL,
40551e1ddd6cScth 	    MP_OBJECT_TYPE_INITIATOR_PORT, (void*)init_port_res);
40561e1ddd6cScth 	if (init_list == NULL) {
40571e1ddd6cScth 		/*
40581e1ddd6cScth 		 * Need to create init_list entry
40591e1ddd6cScth 		 * The resource ptr is not really pdip. It will be changed
40601e1ddd6cScth 		 * in vhci_mpapi_create_item(). The real resource ptr
40611e1ddd6cScth 		 * is the Port ID. But we pass the pdip, to create OID.
40621e1ddd6cScth 		 */
40631e1ddd6cScth 		init_list = vhci_mpapi_create_item(vhci,
40641e1ddd6cScth 		    MP_OBJECT_TYPE_INITIATOR_PORT, (void*)pdip);
40651e1ddd6cScth 	}
40661e1ddd6cScth 
40671e1ddd6cScth 	initd = init_list->item->idata;
40681e1ddd6cScth 	initd->valid = 1;
40691e1ddd6cScth 	(void) strlcpy(initd->prop.portID, init, sizeof (initd->prop.portID));
40701e1ddd6cScth 
40711e1ddd6cScth 	if (init_not_ddi_alloced == 1) {
40721e1ddd6cScth 		kmem_free(init, MAXPATHLEN);
40731e1ddd6cScth 	} else if (init) {
40741e1ddd6cScth 		ddi_prop_free(init);
40751e1ddd6cScth 	}
40761e1ddd6cScth 	kmem_free(init_port_res, MAXPATHLEN);
40771e1ddd6cScth 
40781e1ddd6cScth 	return (DDI_WALK_CONTINUE);
40791e1ddd6cScth }
40801e1ddd6cScth 
40811e1ddd6cScth /* ARGSUSED */
40821e1ddd6cScth static void
vhci_mpapi_log_sysevent(dev_info_t * dip,uint64_t * oid,char * subclass)40831e1ddd6cScth vhci_mpapi_log_sysevent(dev_info_t *dip, uint64_t *oid, char *subclass)
40841e1ddd6cScth {
40851e1ddd6cScth 	nvlist_t	*attr_list;
40861e1ddd6cScth 
40871e1ddd6cScth 	if (nvlist_alloc(&attr_list, NV_UNIQUE_NAME_TYPE,
40881e1ddd6cScth 	    KM_SLEEP) != DDI_SUCCESS) {
40891e1ddd6cScth 		goto alloc_failed;
40901e1ddd6cScth 	}
40911e1ddd6cScth 
40921e1ddd6cScth 	if (nvlist_add_uint64_array(attr_list, "oid", oid, 1) != DDI_SUCCESS) {
40931e1ddd6cScth 		goto error;
40941e1ddd6cScth 	}
40951e1ddd6cScth 
40961e1ddd6cScth 	(void) ddi_log_sysevent(dip, DDI_VENDOR_SUNW, EC_SUN_MP, subclass,
40971e1ddd6cScth 	    attr_list, NULL, DDI_SLEEP);
40981e1ddd6cScth 
40991e1ddd6cScth error:
41001e1ddd6cScth 	nvlist_free(attr_list);
41011e1ddd6cScth 	return;
41021e1ddd6cScth 
41031e1ddd6cScth alloc_failed:
41041e1ddd6cScth 	VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_mpapi_log_sysevent: "
41051e1ddd6cScth 	    "Unable to send sysevent"));
41061e1ddd6cScth 
41071e1ddd6cScth }
41081e1ddd6cScth 
41091e1ddd6cScth /* ARGSUSED */
41101e1ddd6cScth void
vhci_mpapi_set_path_state(dev_info_t * vdip,mdi_pathinfo_t * pip,int state)41111e1ddd6cScth vhci_mpapi_set_path_state(dev_info_t *vdip, mdi_pathinfo_t *pip, int state)
41121e1ddd6cScth {
41131e1ddd6cScth 	struct scsi_vhci	*vhci;
41141e1ddd6cScth 	struct scsi_vhci_lun	*svl;
41151e1ddd6cScth 	scsi_vhci_priv_t	*svp;
41161e1ddd6cScth 	mpapi_item_list_t	*ilist, *lu_list;
41171e1ddd6cScth 	mpapi_path_data_t	*pp;
411817d71211SJiri Svoboda 	int			old_state;
411917d71211SJiri Svoboda 	int			old_in_okay, new_in_okay;
41201e1ddd6cScth 
41211e1ddd6cScth 	vhci = ddi_get_soft_state(vhci_softstate, ddi_get_instance(vdip));
41221e1ddd6cScth 
41231e1ddd6cScth 	ilist = vhci_get_mpapi_item(vhci, NULL, MP_OBJECT_TYPE_PATH_LU, pip);
41241e1ddd6cScth 
41251e1ddd6cScth 	if (ilist != NULL) {
41261e1ddd6cScth 		mutex_enter(&ilist->item->item_mutex);
41271e1ddd6cScth 		pp = ilist->item->idata;
412817d71211SJiri Svoboda 		old_state = pp->prop.pathState;
41291e1ddd6cScth 		pp->prop.pathState = state;
41301e1ddd6cScth 		pp->valid = 1;
413117d71211SJiri Svoboda 
413217d71211SJiri Svoboda 		/*
413317d71211SJiri Svoboda 		 * MP API does not distiguish between ACTIVE and PASSIVE
413417d71211SJiri Svoboda 		 * and thus libmpscsi_vhci renders both as MP_PATH_STATE_OKAY.
413517d71211SJiri Svoboda 		 * Therefore if we are transitioning between ACTIVE and PASSIVE
413617d71211SJiri Svoboda 		 * we do not want to generate an event.
413717d71211SJiri Svoboda 		 */
413817d71211SJiri Svoboda 
413917d71211SJiri Svoboda 		old_in_okay = (old_state == MP_DRVR_PATH_STATE_ACTIVE ||
414017d71211SJiri Svoboda 		    old_state == MP_DRVR_PATH_STATE_PASSIVE);
414117d71211SJiri Svoboda 		new_in_okay = (state == MP_DRVR_PATH_STATE_ACTIVE ||
414217d71211SJiri Svoboda 		    state == MP_DRVR_PATH_STATE_PASSIVE);
414317d71211SJiri Svoboda 
414417d71211SJiri Svoboda 		if (state != old_state && !(old_in_okay && new_in_okay)) {
414517d71211SJiri Svoboda 			vhci_mpapi_log_sysevent(vdip,
414617d71211SJiri Svoboda 			    &(ilist->item->oid.raw_oid),
414717d71211SJiri Svoboda 			    ESC_SUN_MP_PATH_CHANGE);
414817d71211SJiri Svoboda 		}
41491e1ddd6cScth 	} else {
41501e1ddd6cScth 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_mpapi_set_path_state: "
41511e1ddd6cScth 		    "pip(%p) not found", (void *)pip));
41521e1ddd6cScth 		return;
41531e1ddd6cScth 	}
41541e1ddd6cScth 
41554c06356bSdh 	/*
41564c06356bSdh 	 * Check if the pathinfo is uninitialized(destroyed).
41574c06356bSdh 	 */
41584c06356bSdh 	if (state == MP_DRVR_PATH_STATE_UNINIT) {
41594c06356bSdh 		pp->hide = 1;
41604c06356bSdh 		VHCI_DEBUG(6, (CE_NOTE, NULL, "vhci_mpapi_set_path_state: "
41614c06356bSdh 		    "path(pip: %p) is uninited(destroyed).",
41624c06356bSdh 		    (void *)pip));
41634c06356bSdh 	} else {
41644c06356bSdh 		pp->hide = 0;
41654c06356bSdh 	}
41661e1ddd6cScth 	/*
41671e1ddd6cScth 	 * Find if there are any paths at all to the lun
41681e1ddd6cScth 	 */
41691e1ddd6cScth 	if ((state == MP_DRVR_PATH_STATE_REMOVED) || (state ==
41701e1ddd6cScth 	    MP_DRVR_PATH_STATE_PATH_ERR) || (state ==
41711e1ddd6cScth 	    MP_DRVR_PATH_STATE_LU_ERR) || (state ==
41724c06356bSdh 	    MP_DRVR_PATH_STATE_UNKNOWN) || pp->hide) {
41731e1ddd6cScth 		pp->valid = 0;
41744c06356bSdh 		VHCI_DEBUG(6, (CE_NOTE, NULL, "vhci_mpapi_set_path_state: "
41754c06356bSdh 		    "path(pip: %p) is not okay state.  Set to invalid.",
41764c06356bSdh 		    (void *)pip));
41771e1ddd6cScth 		svp = (scsi_vhci_priv_t *)mdi_pi_get_vhci_private(pip);
41781e1ddd6cScth 		svl = svp->svp_svl;
41791e1ddd6cScth 		/*
41801e1ddd6cScth 		 * Update the AccessState of related MPAPI TPGs
41811e1ddd6cScth 		 * This takes care of a special case where a path goes offline
41821e1ddd6cScth 		 * & the TPG accessState may need an update from
41831e1ddd6cScth 		 * Active/Standby to Unavailable.
41841e1ddd6cScth 		 */
41851e1ddd6cScth 		if (!SCSI_FAILOVER_IS_TPGS(svl->svl_fops)) {
41861e1ddd6cScth 			(void) vhci_mpapi_update_tpg_acc_state_for_lu(vhci,
41871e1ddd6cScth 			    svl);
41881e1ddd6cScth 		}
41891e1ddd6cScth 
41901e1ddd6cScth 		/*
41911e1ddd6cScth 		 * Following means the lun is offline
41921e1ddd6cScth 		 */
41931e1ddd6cScth 		if (vhci_mpapi_chk_last_path(pip) == -1) {
41941e1ddd6cScth 			lu_list = vhci_get_mpapi_item(vhci, NULL,
41951e1ddd6cScth 			    MP_OBJECT_TYPE_MULTIPATH_LU, (void *)svl);
41961e1ddd6cScth 			if (lu_list != NULL) {
419717d71211SJiri Svoboda 				vhci_mpapi_set_lu_valid(vhci, lu_list->item, 0);
419817d71211SJiri Svoboda 
41994c06356bSdh 				VHCI_DEBUG(6, (CE_NOTE, NULL,
42004c06356bSdh 				    "vhci_mpapi_set_path_state: "
42014c06356bSdh 				    " Invalidated LU(%s)", svl->svl_lun_wwn));
42021e1ddd6cScth 			}
42031e1ddd6cScth 		}
42041e1ddd6cScth 	}
42051e1ddd6cScth 	mutex_exit(&ilist->item->item_mutex);
42061e1ddd6cScth 
42071e1ddd6cScth }
42081e1ddd6cScth 
42091e1ddd6cScth /* ARGSUSED */
42101e1ddd6cScth static mpapi_item_list_t *
vhci_mpapi_match_pip(struct scsi_vhci * vhci,mpapi_item_list_t * ilist,void * res)42111e1ddd6cScth vhci_mpapi_match_pip(struct scsi_vhci *vhci, mpapi_item_list_t *ilist,
42121e1ddd6cScth     void *res)
42131e1ddd6cScth {
42141e1ddd6cScth 	mpapi_path_data_t	*pd;
42151e1ddd6cScth 	scsi_vhci_lun_t		*this_svl;
42161e1ddd6cScth 	mdi_pathinfo_t		*this_pip;
42171e1ddd6cScth 	char			*this_iport;
42181e1ddd6cScth 	char			*this_tport;
42191e1ddd6cScth 	char			*pname;
42201e1ddd6cScth 
42211e1ddd6cScth 	this_pip = (mdi_pathinfo_t *)res;
42221e1ddd6cScth 	if ((this_pip == NULL) || (ilist == NULL)) {
42231e1ddd6cScth 		return (NULL);
42241e1ddd6cScth 	}
42251e1ddd6cScth 
42261e1ddd6cScth 	this_iport = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
42271e1ddd6cScth 	(void) ddi_pathname(mdi_pi_get_phci(this_pip), this_iport);
42281e1ddd6cScth 
422955e592a2SRandall Ralphs 	if (mdi_prop_lookup_string(this_pip, SCSI_ADDR_PROP_TARGET_PORT,
423055e592a2SRandall Ralphs 	    &this_tport) != DDI_PROP_SUCCESS) {
42311e1ddd6cScth 		/* XXX: target-port prop not found */
42321e1ddd6cScth 		this_tport = (char *)mdi_pi_get_addr(this_pip);
42331e1ddd6cScth 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_mpapi_match_pip: "
42341e1ddd6cScth 		    "mdi_prop_lookup_string() returned failure; "
42351e1ddd6cScth 		    "Hence this_tport = %p", (void *)this_tport));
42361e1ddd6cScth 	}
42371e1ddd6cScth 
42381e1ddd6cScth 	this_svl = mdi_client_get_vhci_private(mdi_pi_get_client(this_pip));
42391e1ddd6cScth 
42401e1ddd6cScth 	pname = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
42411e1ddd6cScth 	(void) strlcat(pname, this_iport, MAXPATHLEN);
42421e1ddd6cScth 	(void) strlcat(pname, this_tport, MAXPATHLEN);
42431e1ddd6cScth 	(void) strlcat(pname, this_svl->svl_lun_wwn, MAXPATHLEN);
42441e1ddd6cScth 	kmem_free(this_iport, MAXPATHLEN);
42451e1ddd6cScth 
42461e1ddd6cScth 	while (ilist != NULL) {
42471e1ddd6cScth 		pd = (mpapi_path_data_t *)(ilist->item->idata);
42481e1ddd6cScth 		if ((pd != NULL) && (strncmp
42491e1ddd6cScth 		    (pd->path_name, pname, strlen(pname)) == 0)) {
42501e1ddd6cScth 			VHCI_DEBUG(6, (CE_WARN, NULL, "vhci_mpapi_match_pip: "
42511e1ddd6cScth 			    "path_name = %s", pd->path_name));
42521e1ddd6cScth 			kmem_free(pname, MAXPATHLEN);
42531e1ddd6cScth 			return (ilist);
42541e1ddd6cScth 		}
42551e1ddd6cScth 		ilist = ilist->next;
42561e1ddd6cScth 	}
42571e1ddd6cScth 
42581e1ddd6cScth 	kmem_free(pname, MAXPATHLEN);
42591e1ddd6cScth 	return (NULL);
42601e1ddd6cScth }
42611e1ddd6cScth 
42621e1ddd6cScth /* ARGSUSED */
42631e1ddd6cScth static
vhci_mpapi_match_lu(struct scsi_vhci * vhci,mpapi_item_list_t * ilist,void * res)42641e1ddd6cScth mpapi_item_list_t *vhci_mpapi_match_lu(struct scsi_vhci *vhci,
42651e1ddd6cScth     mpapi_item_list_t *ilist, void *res)
42661e1ddd6cScth {
42671e1ddd6cScth 	mpapi_lu_data_t		*ld;
42681e1ddd6cScth 	scsi_vhci_lun_t		*this_svl;
42691e1ddd6cScth 
42701e1ddd6cScth 	this_svl = (scsi_vhci_lun_t *)res;
42711e1ddd6cScth 	if ((this_svl == NULL) || (ilist == NULL)) {
42721e1ddd6cScth 		return (NULL);
42731e1ddd6cScth 	}
42741e1ddd6cScth 
42751e1ddd6cScth 	while (ilist != NULL) {
42761e1ddd6cScth 		ld = (mpapi_lu_data_t *)(ilist->item->idata);
42771e1ddd6cScth 		if ((ld != NULL) && (strncmp
42781e1ddd6cScth 		    (ld->prop.name, this_svl->svl_lun_wwn,
42791e1ddd6cScth 		    strlen(this_svl->svl_lun_wwn)) == 0)) {
42801e1ddd6cScth 			VHCI_DEBUG(6, (CE_WARN, NULL, "vhci_mpapi_match_lu: "
42811e1ddd6cScth 			    "this_wwn = %s", this_svl->svl_lun_wwn));
42821e1ddd6cScth 			return (ilist);
42831e1ddd6cScth 		}
42841e1ddd6cScth 		ilist = ilist->next;
42851e1ddd6cScth 	}
42861e1ddd6cScth 
42871e1ddd6cScth 	return (NULL);
42881e1ddd6cScth }
42891e1ddd6cScth 
42901e1ddd6cScth /*
42911e1ddd6cScth  * Routine to handle TPG AccessState Change - Called after each LU failover
42921e1ddd6cScth  */
42931e1ddd6cScth int
vhci_mpapi_update_tpg_acc_state_for_lu(struct scsi_vhci * vhci,scsi_vhci_lun_t * vlun)42941e1ddd6cScth vhci_mpapi_update_tpg_acc_state_for_lu(struct scsi_vhci *vhci,
42951e1ddd6cScth     scsi_vhci_lun_t *vlun)
42961e1ddd6cScth {
42971e1ddd6cScth 	int			rval = 0;
42981e1ddd6cScth 	mpapi_item_list_t	*lu_list, *path_list, *tpg_list;
42991e1ddd6cScth 	mpapi_lu_data_t		*lu_data;
43001e1ddd6cScth 	mpapi_path_data_t	*path_data;
43011e1ddd6cScth 	mpapi_tpg_data_t	*tpg_data;
430271c438e0SVictor Li 	char			*tgt_port;
4303960c6305SJiri Svoboda 	boolean_t		set_lu_valid;
43041e1ddd6cScth 
43051e1ddd6cScth 	lu_list = vhci_get_mpapi_item(vhci, NULL, MP_OBJECT_TYPE_MULTIPATH_LU,
43061e1ddd6cScth 	    (void *)vlun);
43071e1ddd6cScth 	if (lu_list == NULL) {
43081e1ddd6cScth 		return (-1);
43091e1ddd6cScth 	}
43101e1ddd6cScth 	lu_data = lu_list->item->idata;
43111e1ddd6cScth 	if (lu_data == NULL) {
43121e1ddd6cScth 		return (-1);
43131e1ddd6cScth 	}
43141e1ddd6cScth 	lu_data->resp = vlun;
43151e1ddd6cScth 
43161e1ddd6cScth 	/*
43171e1ddd6cScth 	 * For each "pclass of PATH" and "pclass of TPG" match of this LU,
43181e1ddd6cScth 	 * Update the TPG AccessState to reflect the state of the path.
43191e1ddd6cScth 	 * Exit the inner loop after the 1st successful ACTIVE/STANDBY update
43201e1ddd6cScth 	 * is made, because subsequent matches also lead to the same TPG.
43211e1ddd6cScth 	 */
43221e1ddd6cScth 	tpg_list = lu_data->tpg_list->head;
4323960c6305SJiri Svoboda 	set_lu_valid = B_FALSE;
4324960c6305SJiri Svoboda 
43251e1ddd6cScth 	while (tpg_list != NULL) {
43261e1ddd6cScth 		tpg_data = tpg_list->item->idata;
43271e1ddd6cScth 		path_list = lu_data->path_list->head;
43281e1ddd6cScth 		while (path_list != NULL) {
43291e1ddd6cScth 			path_data = path_list->item->idata;
433071c438e0SVictor Li 			/*
433171c438e0SVictor Li 			 * path class is not reliable for ALUA if the
433271c438e0SVictor Li 			 * vhci has done the update on one of the class
433371c438e0SVictor Li 			 * but ignore to update on another one.
433471c438e0SVictor Li 			 */
433571c438e0SVictor Li 			tgt_port = NULL;
433621330c7fSVictor Li 			if (path_data->valid == 1 &&
433721330c7fSVictor Li 			    (mdi_prop_lookup_string(path_data->resp,
433871c438e0SVictor Li 			    SCSI_ADDR_PROP_TARGET_PORT,
433971c438e0SVictor Li 			    &tgt_port) == DDI_PROP_SUCCESS) &&
434071c438e0SVictor Li 			    tgt_port != NULL &&
434171c438e0SVictor Li 			    (vhci_mpapi_check_tp_in_tpg(
434271c438e0SVictor Li 			    tpg_data, tgt_port) == 1)) {
434321330c7fSVictor Li 				VHCI_DEBUG(4, (CE_NOTE, NULL,
434421330c7fSVictor Li 				    "vhci_mpapi_update_tpg_acc_state_"
434521330c7fSVictor Li 				    "for_ lu: Operating on LUN(%s), "
434621330c7fSVictor Li 				    " PATH(%p), TPG(%x: %s)\n",
434721330c7fSVictor Li 				    lu_data->prop.name, path_data->resp,
434821330c7fSVictor Li 				    tpg_data->prop.tpgId,
434921330c7fSVictor Li 				    tpg_data->pclass));
435021330c7fSVictor Li 				if (MDI_PI_IS_ONLINE(path_data->resp)) {
435117d71211SJiri Svoboda 					vhci_mpapi_set_tpg_as_prop(vhci,
435217d71211SJiri Svoboda 					    tpg_list->item,
435317d71211SJiri Svoboda 					    MP_DRVR_ACCESS_STATE_ACTIVE);
4354960c6305SJiri Svoboda 					set_lu_valid = B_TRUE;
435521330c7fSVictor Li 					break;
435621330c7fSVictor Li 				} else if (MDI_PI_IS_STANDBY(path_data->resp)) {
435717d71211SJiri Svoboda 					vhci_mpapi_set_tpg_as_prop(vhci,
435817d71211SJiri Svoboda 					    tpg_list->item,
435917d71211SJiri Svoboda 					    MP_DRVR_ACCESS_STATE_STANDBY);
4360960c6305SJiri Svoboda 					set_lu_valid = B_TRUE;
436121330c7fSVictor Li 					break;
43621e1ddd6cScth 				} else {
436317d71211SJiri Svoboda 					vhci_mpapi_set_tpg_as_prop(vhci,
436417d71211SJiri Svoboda 					    tpg_list->item,
436517d71211SJiri Svoboda 					    MP_DRVR_ACCESS_STATE_UNAVAILABLE);
43661e1ddd6cScth 				}
43671e1ddd6cScth 			}
43681e1ddd6cScth 			path_list = path_list->next;
43691e1ddd6cScth 		}
43701e1ddd6cScth 		tpg_list = tpg_list->next;
43711e1ddd6cScth 	}
43721e1ddd6cScth 
4373960c6305SJiri Svoboda 	/*
4374960c6305SJiri Svoboda 	 * Only make LU valid if the encountered path was active or standby.
4375960c6305SJiri Svoboda 	 * Otherwise we would cause the LU to reappear transiently after
4376960c6305SJiri Svoboda 	 * the last path to it has gone and before it is finally marked
4377960c6305SJiri Svoboda 	 * invalid by vhci_mpapi_set_path_state(), causing bogus visibility
4378960c6305SJiri Svoboda 	 * events.
4379960c6305SJiri Svoboda 	 */
4380960c6305SJiri Svoboda 	if (set_lu_valid != B_FALSE)
438117d71211SJiri Svoboda 		vhci_mpapi_set_lu_valid(vhci, lu_list->item, 1);
438217d71211SJiri Svoboda 
43831e1ddd6cScth 	return (rval);
43841e1ddd6cScth }
43851e1ddd6cScth 
43861e1ddd6cScth int
vhci_mpapi_get_vhci(dev_info_t * vdip,void * ptr2vhci)43871e1ddd6cScth vhci_mpapi_get_vhci(dev_info_t *vdip, void *ptr2vhci)
43881e1ddd6cScth {
43891e1ddd6cScth 	struct scsi_vhci	*local_vhci;
43901e1ddd6cScth 
43911e1ddd6cScth 	if (strncmp("scsi_vhci", ddi_get_name(vdip),
43921e1ddd6cScth 	    strlen("scsi_vhci")) == 0) {
43931e1ddd6cScth 		local_vhci = ddi_get_soft_state(vhci_softstate,
43941e1ddd6cScth 		    ddi_get_instance(vdip));
43951e1ddd6cScth 		bcopy(&local_vhci, ptr2vhci, sizeof (local_vhci));
43961e1ddd6cScth 		return (DDI_WALK_TERMINATE);
43971e1ddd6cScth 	}
43981e1ddd6cScth 
43991e1ddd6cScth 	return (DDI_WALK_CONTINUE);
44001e1ddd6cScth 
44011e1ddd6cScth }
44021e1ddd6cScth 
44031e1ddd6cScth /* ARGSUSED */
44041e1ddd6cScth void *
vhci_mpapi_get_rel_tport_pair(struct scsi_vhci * vhci,mpapi_list_header_t * list,void * tgt_port,uint32_t rel_tid)44051e1ddd6cScth vhci_mpapi_get_rel_tport_pair(struct scsi_vhci *vhci, mpapi_list_header_t *list,
44061e1ddd6cScth     void *tgt_port, uint32_t rel_tid)
44071e1ddd6cScth {
44081e1ddd6cScth 	mpapi_item_list_t	*ilist;
44091e1ddd6cScth 	mpapi_tport_data_t	*tpd;
44101e1ddd6cScth 
44111e1ddd6cScth 	if (list == NULL) {
44121e1ddd6cScth 		/*
44131e1ddd6cScth 		 * Since the listhead is null, the search is being
44141e1ddd6cScth 		 * performed in implicit mode - that is to use the
44151e1ddd6cScth 		 * level one list.
44161e1ddd6cScth 		 */
44171e1ddd6cScth 		ilist = vhci->mp_priv->obj_hdr_list[MP_OBJECT_TYPE_TARGET_PORT]
44181e1ddd6cScth 		    ->head;
44191e1ddd6cScth 	} else {
44201e1ddd6cScth 		/*
44211e1ddd6cScth 		 * The search is being performed on a sublist within
44221e1ddd6cScth 		 * one of the toplevel list items. Use the listhead
44231e1ddd6cScth 		 * that is passed in.
44241e1ddd6cScth 		 */
44251e1ddd6cScth 		ilist = list->head;
44261e1ddd6cScth 	}
44271e1ddd6cScth 
44281e1ddd6cScth 	if (tgt_port == NULL) {
44291e1ddd6cScth 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_get_mpapi_item: "
44301e1ddd6cScth 		    " Got Target Port w/ NULL resource"));
44311e1ddd6cScth 		return (NULL);
44321e1ddd6cScth 	}
44331e1ddd6cScth 
44341e1ddd6cScth 	while (ilist) {
44351e1ddd6cScth 		tpd = (mpapi_tport_data_t *)ilist->item->idata;
44361e1ddd6cScth 		if ((strncmp(tpd->resp, tgt_port, strlen(tgt_port)) == 0) &&
44371e1ddd6cScth 		    (tpd->prop.relativePortID == rel_tid)) {
44381e1ddd6cScth 			/* Match */
44391e1ddd6cScth 			return ((void*)ilist);
44401e1ddd6cScth 		} else {
44411e1ddd6cScth 			ilist = ilist->next;
44421e1ddd6cScth 		}
44431e1ddd6cScth 	}
44441e1ddd6cScth 
44451e1ddd6cScth 	return (NULL);
44461e1ddd6cScth }
44471e1ddd6cScth 
44481e1ddd6cScth /*
44491e1ddd6cScth  * Returns 0, if 2 more paths are available to the lun;
44501e1ddd6cScth  * Returns 1, if ONLY 1 path is available to the lun;
44511e1ddd6cScth  * Return -1 for all other cases.
44521e1ddd6cScth  */
44531e1ddd6cScth static int
vhci_mpapi_chk_last_path(mdi_pathinfo_t * pip)44541e1ddd6cScth vhci_mpapi_chk_last_path(mdi_pathinfo_t *pip)
44551e1ddd6cScth {
44561e1ddd6cScth 	dev_info_t	*pdip = NULL, *cdip = NULL;
4457*3fe80ca4SDan Cross 	int		count = 0;
44581e1ddd6cScth 	mdi_pathinfo_t	*ret_pip;
44591e1ddd6cScth 
44601e1ddd6cScth 	if (pip == NULL) {
44611e1ddd6cScth 		return (-1);
44621e1ddd6cScth 	} else {
44631e1ddd6cScth 		pdip = mdi_pi_get_phci(pip);
44641e1ddd6cScth 		cdip = mdi_pi_get_client(pip);
44651e1ddd6cScth 	}
44661e1ddd6cScth 
44671e1ddd6cScth 	if ((pdip == NULL) || (cdip == NULL)) {
44681e1ddd6cScth 		return (-1);
44691e1ddd6cScth 	}
44701e1ddd6cScth 
4471*3fe80ca4SDan Cross 	ndi_devi_enter(cdip);
44721e1ddd6cScth 	ret_pip = mdi_get_next_phci_path(cdip, NULL);
44731e1ddd6cScth 
44741e1ddd6cScth 	while ((ret_pip != NULL) && (count < 2)) {
44751e1ddd6cScth 		mdi_pi_lock(ret_pip);
44761e1ddd6cScth 		if ((MDI_PI_IS_ONLINE(ret_pip) ||
44771e1ddd6cScth 		    MDI_PI_IS_STANDBY(ret_pip) ||
44781e1ddd6cScth 		    MDI_PI_IS_INIT(ret_pip)) &&
44791e1ddd6cScth 		    !(MDI_PI_IS_DISABLE(ret_pip) ||
44804c06356bSdh 		    MDI_PI_IS_TRANSIENT(ret_pip) ||
44814c06356bSdh 		    MDI_PI_FLAGS_IS_DEVICE_REMOVED(ret_pip))) {
44821e1ddd6cScth 			count++;
44831e1ddd6cScth 		}
44841e1ddd6cScth 		mdi_pi_unlock(ret_pip);
44851e1ddd6cScth 		ret_pip = mdi_get_next_phci_path(cdip, ret_pip);
44861e1ddd6cScth 	}
4487*3fe80ca4SDan Cross 	ndi_devi_exit(cdip);
44881e1ddd6cScth 
44891e1ddd6cScth 	if (count > 1) {
44901e1ddd6cScth 		return (0);
44911e1ddd6cScth 	} else if (count == 1) {
44921e1ddd6cScth 		return (1);
44931e1ddd6cScth 	}
44941e1ddd6cScth 
44951e1ddd6cScth 	return (-1);
44961e1ddd6cScth }
4497