Home | History | Annotate | Download | only in scsi_vhci
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 /*
     22  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  */
     25 
     26 /*
     27  * SNIA Multipath Management API implementation
     28  */
     29 
     30 #include <sys/conf.h>
     31 #include <sys/file.h>
     32 #include <sys/disp.h>
     33 #include <sys/ddi.h>
     34 #include <sys/sunddi.h>
     35 #include <sys/sunmdi.h>
     36 #include <sys/mdi_impldefs.h>
     37 #include <sys/scsi/scsi.h>
     38 #include <sys/scsi/impl/services.h>
     39 #include <sys/scsi/impl/scsi_reset_notify.h>
     40 #include <sys/scsi/adapters/scsi_vhci.h>
     41 
     42 /* used to manually force a request sense */
     43 int vhci_force_manual_sense = 0;
     44 
     45 #define	STD_ACTIVE_OPTIMIZED	0x0
     46 #define	STD_ACTIVE_NONOPTIMIZED	0x1
     47 #define	STD_STANDBY		0x2
     48 #define	STD_UNAVAILABLE		0x3
     49 #define	STD_TRANSITIONING	0xf
     50 
     51 /*
     52  * MP-API Prototypes
     53  */
     54 int vhci_mpapi_init(struct scsi_vhci *);
     55 void vhci_mpapi_add_dev_prod(struct scsi_vhci *, char *);
     56 int vhci_mpapi_ctl(dev_t, int, intptr_t, int, cred_t *, int *);
     57 void vhci_update_mpapi_data(struct scsi_vhci *,
     58     scsi_vhci_lun_t *, mdi_pathinfo_t *);
     59 void* vhci_get_mpapi_item(struct scsi_vhci *, mpapi_list_header_t *,
     60     uint8_t, void*);
     61 int vhci_mpapi_sync_init_port_list(dev_info_t *, void *);
     62 int vhci_mpapi_get_vhci(dev_info_t *, void *);
     63 void vhci_mpapi_set_path_state(dev_info_t *, mdi_pathinfo_t *, int);
     64 void vhci_mpapi_synthesize_tpg_data(struct scsi_vhci *, scsi_vhci_lun_t *,
     65     mdi_pathinfo_t *);
     66 void vhci_mpapi_update_tpg_data(struct scsi_address *, char *, int);
     67 int vhci_mpapi_update_tpg_acc_state_for_lu(struct scsi_vhci *,
     68     scsi_vhci_lun_t *);
     69 
     70 /* Static Functions */
     71 static int vhci_get_driver_prop(struct scsi_vhci *, mp_iocdata_t *,
     72     void *, void *, int);
     73 static int vhci_get_dev_prod_list(struct scsi_vhci *, mp_iocdata_t *,
     74     void *, void *, int);
     75 static int vhci_get_dev_prod_prop(struct scsi_vhci *, mp_iocdata_t *,
     76     void *, void *, int);
     77 static int vhci_get_lu_list(struct scsi_vhci *, mp_iocdata_t *,
     78     void *, void *, int);
     79 static int vhci_get_lu_list_from_tpg(struct scsi_vhci *, mp_iocdata_t *,
     80     void *, void *, int);
     81 static int vhci_get_tpg_list_for_lu(struct scsi_vhci *, mp_iocdata_t *,
     82     void *, void *, int);
     83 static int vhci_get_lu_prop(struct scsi_vhci *, mp_iocdata_t *,
     84     void *, void *, int);
     85 static int vhci_get_path_list_for_mp_lu(struct scsi_vhci *, mp_iocdata_t *,
     86     void *, void *, int);
     87 static int vhci_get_path_list_for_init_port(struct scsi_vhci *, mp_iocdata_t *,
     88     void *, void *, int);
     89 static int vhci_get_path_list_for_target_port(struct scsi_vhci *,
     90     mp_iocdata_t *, void *, void *, int);
     91 static int vhci_get_path_prop(struct scsi_vhci *, mp_iocdata_t *,
     92     void *, void *, int);
     93 static int vhci_get_init_port_list(struct scsi_vhci *, mp_iocdata_t *,
     94     void *, void *, int);
     95 static int vhci_get_init_port_prop(struct scsi_vhci *, mp_iocdata_t *,
     96     void *, void *, int);
     97 static int vhci_get_target_port_prop(struct scsi_vhci *, mp_iocdata_t *,
     98     void *, void *, int);
     99 static int vhci_get_tpg_prop(struct scsi_vhci *, mp_iocdata_t *,
    100     void *, void *, int);
    101 static int vhci_get_target_port_list_for_tpg(struct scsi_vhci *, mp_iocdata_t *,
    102     void *, void *, int);
    103 static int vhci_set_tpg_access_state(struct scsi_vhci *, mp_iocdata_t *,
    104     void *, void *, int);
    105 static int vhci_get_prop_lb_list(struct scsi_vhci *, mp_iocdata_t *,
    106     void *, void *, int);
    107 static int vhci_get_prop_lb_prop(struct scsi_vhci *, mp_iocdata_t *,
    108     void *, void *, int);
    109 static int vhci_assign_lu_to_tpg(struct scsi_vhci *, mp_iocdata_t *,
    110     void *, void *, int);
    111 static int vhci_enable_auto_failback(struct scsi_vhci *, mp_iocdata_t *,
    112     void *, void *, int);
    113 static int vhci_disable_auto_failback(struct scsi_vhci *, mp_iocdata_t *,
    114     void *, void *, int);
    115 static int vhci_enable_path(struct scsi_vhci *, mp_iocdata_t *,
    116     void *, void *, int);
    117 static int vhci_disable_path(struct scsi_vhci *, mp_iocdata_t *,
    118     void *, void *, int);
    119 static int vhci_send_uscsi_cmd(dev_t dev, struct scsi_vhci *, mp_iocdata_t *,
    120     void *, void *, int);
    121 static int vhci_mpapi_validate(void *, mp_iocdata_t *, int, cred_t *);
    122 static uint64_t vhci_mpapi_create_oid(mpapi_priv_t *, uint8_t);
    123 static int vhci_mpapi_ioctl(dev_t dev, struct scsi_vhci *, void *,
    124     mp_iocdata_t *, int, cred_t *);
    125 static int vhci_mpapi_add_to_list(mpapi_list_header_t *, mpapi_item_list_t *);
    126 static mpapi_item_list_t *vhci_mpapi_create_item(struct scsi_vhci *,
    127     uint8_t, void *);
    128 static mpapi_item_list_t *vhci_mpapi_get_alua_item(struct scsi_vhci *,
    129     void *, void *, void *);
    130 static mpapi_item_list_t *vhci_mpapi_get_tpg_item(struct scsi_vhci *,
    131     uint32_t, void *, char *, void *);
    132 static mpapi_list_header_t *vhci_mpapi_create_list_head();
    133 static int vhci_get_mpiocdata(const void *, mp_iocdata_t *, int);
    134 static int vhci_is_model_type32(int);
    135 static int vhci_mpapi_copyout_iocdata(void *, void *, int);
    136 static int vhci_mpapi_chk_last_path(mdi_pathinfo_t *);
    137 static int vhci_mpapi_sync_lu_oid_list(struct scsi_vhci *);
    138 static mpapi_item_list_t *vhci_mpapi_get_tpg_for_lun(struct scsi_vhci *,
    139     char *, void *, void *);
    140 static int vhci_mpapi_check_tp_in_tpg(mpapi_tpg_data_t *tpgdata, void *tp);
    141 static void vhci_mpapi_log_sysevent(dev_info_t *, uint64_t *, char *);
    142 static mpapi_item_list_t *vhci_mpapi_match_pip(struct scsi_vhci *,
    143     mpapi_item_list_t *, void *);
    144 static mpapi_item_list_t *vhci_mpapi_match_lu(struct scsi_vhci *,
    145     mpapi_item_list_t *, void *);
    146 static void *vhci_mpapi_get_rel_tport_pair(struct scsi_vhci *vhci,
    147     mpapi_list_header_t *list, void *tgt_port, uint32_t rel_tid);
    148 
    149 /*
    150  * Extern variables, structures and functions
    151  */
    152 extern void	*vhci_softstate;
    153 extern char	vhci_version_name[];
    154 extern int vhci_tpgs_set_target_groups(struct scsi_address *, int, int);
    155 
    156 
    157 extern void mdi_vhci_walk_phcis(dev_info_t *,
    158     int (*)(dev_info_t *, void *), void *);
    159 extern void vhci_update_pathstates(void *);
    160 extern int vhci_uscsi_iostart(struct buf *bp);
    161 
    162 /*
    163  * Routine for SCSI VHCI MPAPI IOCTL implementation.
    164  */
    165 /* ARGSUSED */
    166 int
    167 vhci_mpapi_ctl(dev_t dev, int cm, intptr_t data, int mode,
    168     cred_t *credp, int *rval)
    169 {
    170 	struct scsi_vhci		*vhci;
    171 	dev_info_t			*vdip;
    172 	int				retval = 0;
    173 	mp_iocdata_t			mpio_blk;
    174 	mp_iocdata_t			*mpioc = &mpio_blk;
    175 
    176 	/* Check for validity of vhci structure */
    177 	vhci = ddi_get_soft_state(vhci_softstate, MINOR2INST(getminor(dev)));
    178 	if (vhci == NULL) {
    179 		return (ENXIO);
    180 	}
    181 
    182 	mutex_enter(&vhci->vhci_mutex);
    183 	if ((vhci->vhci_state & VHCI_STATE_OPEN) == 0) {
    184 		mutex_exit(&vhci->vhci_mutex);
    185 		return (ENXIO);
    186 	}
    187 	mutex_exit(&vhci->vhci_mutex);
    188 
    189 	/* Get the vhci dip */
    190 	vdip = vhci->vhci_dip;
    191 	ASSERT(vdip != NULL);
    192 
    193 	/*
    194 	 * Get IOCTL parameters from userland
    195 	 */
    196 	if (vhci_get_mpiocdata((const void *)data, mpioc, mode) != 0) {
    197 		VHCI_DEBUG(1, (CE_WARN, NULL, "!vhci_mpapi_ctl: "
    198 		    "vhci_get_mpiocdata() failed"));
    199 	}
    200 	if (mpioc->mp_cmd < MP_API_SUBCMD_MIN ||
    201 	    mpioc->mp_cmd > MP_API_SUBCMD_MAX) {
    202 		return (ENXIO);
    203 	}
    204 
    205 	retval = vhci_mpapi_ioctl(dev, vhci, (void *)data, mpioc, mode, credp);
    206 
    207 	return (retval);
    208 }
    209 
    210 /* ARGSUSED */
    211 static int
    212 vhci_mpapi_validate(void *udata, mp_iocdata_t *mpioc, int mode, cred_t *credp)
    213 {
    214 	int		rval = 0, olen = 0;
    215 	int		mode32 = 0;
    216 
    217 	if (vhci_is_model_type32(mode) == 1) {
    218 		mode32 = 1;
    219 	}
    220 
    221 	switch (mpioc->mp_cmd) {
    222 
    223 	case MP_GET_DEV_PROD_LIST:
    224 	case MP_GET_LU_LIST: /* XXX: This wont come; Plugin already has it */
    225 	case MP_GET_INIT_PORT_LIST: /* XXX: This call wont come either */
    226 	case MP_GET_TPG_LIST:
    227 	case MP_GET_PROPRIETARY_LOADBALANCE_LIST:
    228 	{
    229 		if ((mpioc->mp_olen == 0) ||
    230 		    (mpioc->mp_obuf == NULL) ||
    231 		    (mpioc->mp_xfer != MP_XFER_READ)) {
    232 			rval = EINVAL;
    233 		}
    234 		if (mpioc->mp_olen == 0) {
    235 			/* We don't know alen yet, No point trying to set it */
    236 			mpioc->mp_errno = MP_MORE_DATA;
    237 			rval = MP_MORE_DATA;
    238 		}
    239 	}
    240 	break;
    241 
    242 	case MP_GET_DRIVER_PROP:
    243 	{
    244 		olen = sizeof (mp_driver_prop_t);
    245 		/* Adjust olen to account for the caddr_t in 32-bit mode */
    246 		if (mode32 == 1) {
    247 			olen -= 4;
    248 		}
    249 
    250 		if ((mpioc->mp_obuf == NULL) ||
    251 		    (mpioc->mp_olen < olen) ||
    252 		    (mpioc->mp_xfer != MP_XFER_READ)) {
    253 			rval = EINVAL;
    254 		}
    255 		if (mpioc->mp_olen < olen) {
    256 			mpioc->mp_alen = olen;
    257 			mpioc->mp_errno = MP_MORE_DATA;
    258 		}
    259 	}
    260 	break;
    261 
    262 	case MP_GET_DEV_PROD_PROP:
    263 	{
    264 		olen = sizeof (mp_dev_prod_prop_t);
    265 
    266 		if ((mpioc->mp_olen < olen) ||
    267 		    (mpioc->mp_ilen < sizeof (uint64_t)) ||
    268 		    (mpioc->mp_obuf == NULL) ||
    269 		    (mpioc->mp_ibuf == NULL) ||
    270 		    (mpioc->mp_xfer != MP_XFER_READ)) {
    271 			rval = EINVAL;
    272 		}
    273 		if (mpioc->mp_olen < olen) {
    274 			mpioc->mp_alen = olen;
    275 			mpioc->mp_errno = MP_MORE_DATA;
    276 		}
    277 	}
    278 	break;
    279 
    280 	case MP_GET_LU_PROP:
    281 	{
    282 		olen = sizeof (mp_logical_unit_prop_t);
    283 		/* Adjust olen to account for the caddr_t in 32-bit mode */
    284 		if (mode32 == 1) {
    285 			olen -= 4;
    286 		}
    287 
    288 		if ((mpioc->mp_ilen != sizeof (uint64_t)) ||
    289 		    (mpioc->mp_ibuf == NULL) ||
    290 		    (mpioc->mp_olen < olen) ||
    291 		    (mpioc->mp_obuf == NULL) ||
    292 		    (mpioc->mp_xfer != MP_XFER_READ)) {
    293 			rval = EINVAL;
    294 		}
    295 		if (mpioc->mp_olen < olen) {
    296 			mpioc->mp_alen = olen;
    297 			mpioc->mp_errno = MP_MORE_DATA;
    298 		}
    299 	}
    300 	break;
    301 
    302 	case MP_GET_PATH_PROP:
    303 	{
    304 		olen = sizeof (mp_path_prop_t);
    305 		/* Adjust olen to account for the caddr_t in 32-bit mode */
    306 		if (mode32 == 1) {
    307 			olen -= 4;
    308 		}
    309 
    310 		if ((mpioc->mp_ilen != sizeof (uint64_t)) ||
    311 		    (mpioc->mp_ibuf == NULL) ||
    312 		    (mpioc->mp_olen < olen) ||
    313 		    (mpioc->mp_obuf == NULL) ||
    314 		    (mpioc->mp_xfer != MP_XFER_READ)) {
    315 			rval = EINVAL;
    316 		}
    317 		if (mpioc->mp_olen < olen) {
    318 			mpioc->mp_alen = olen;
    319 			mpioc->mp_errno = MP_MORE_DATA;
    320 		}
    321 	}
    322 	break;
    323 
    324 	case MP_GET_INIT_PORT_PROP:
    325 	{
    326 		olen = sizeof (mp_init_port_prop_t);
    327 
    328 		if ((mpioc->mp_ilen != sizeof (uint64_t)) ||
    329 		    (mpioc->mp_ibuf == NULL) ||
    330 		    (mpioc->mp_olen < olen) ||
    331 		    (mpioc->mp_obuf == NULL) ||
    332 		    (mpioc->mp_xfer != MP_XFER_READ)) {
    333 			rval = EINVAL;
    334 		}
    335 		if (mpioc->mp_olen < olen) {
    336 			mpioc->mp_alen = olen;
    337 			mpioc->mp_errno = MP_MORE_DATA;
    338 		}
    339 	}
    340 	break;
    341 
    342 	case MP_GET_TARGET_PORT_PROP:
    343 	{
    344 		olen = sizeof (mp_target_port_prop_t);
    345 
    346 		if ((mpioc->mp_ilen != sizeof (uint64_t)) ||
    347 		    (mpioc->mp_ibuf == NULL) ||
    348 		    (mpioc->mp_olen < olen) ||
    349 		    (mpioc->mp_obuf == NULL) ||
    350 		    (mpioc->mp_xfer != MP_XFER_READ)) {
    351 			rval = EINVAL;
    352 		}
    353 		if (mpioc->mp_olen < olen) {
    354 			mpioc->mp_alen = olen;
    355 			mpioc->mp_errno = MP_MORE_DATA;
    356 		}
    357 	}
    358 	break;
    359 
    360 	case MP_GET_TPG_PROP:
    361 	{
    362 		olen = sizeof (mp_tpg_prop_t);
    363 
    364 		if ((mpioc->mp_ilen != sizeof (uint64_t)) ||
    365 		    (mpioc->mp_ibuf == NULL) ||
    366 		    (mpioc->mp_olen < olen) ||
    367 		    (mpioc->mp_obuf == NULL) ||
    368 		    (mpioc->mp_xfer != MP_XFER_READ)) {
    369 			rval = EINVAL;
    370 		}
    371 		if (mpioc->mp_olen < olen) {
    372 			mpioc->mp_alen = olen;
    373 			mpioc->mp_errno = MP_MORE_DATA;
    374 		}
    375 	}
    376 	break;
    377 
    378 	case MP_GET_PROPRIETARY_LOADBALANCE_PROP:
    379 	{
    380 		olen = sizeof (mp_proprietary_loadbalance_prop_t);
    381 		/* Adjust olen to account for the caddr_t in 32-bit mode */
    382 		if (mode32 == 1) {
    383 			olen -= 4;
    384 		}
    385 
    386 		if ((mpioc->mp_ilen != sizeof (uint64_t)) ||
    387 		    (mpioc->mp_ibuf == NULL) ||
    388 		    (mpioc->mp_olen < olen) ||
    389 		    (mpioc->mp_obuf == NULL) ||
    390 		    (mpioc->mp_xfer != MP_XFER_READ)) {
    391 			rval = EINVAL;
    392 		}
    393 		if (mpioc->mp_olen < olen) {
    394 			mpioc->mp_alen = olen;
    395 			mpioc->mp_errno = MP_MORE_DATA;
    396 		}
    397 	}
    398 	break;
    399 
    400 	case MP_GET_PATH_LIST_FOR_MP_LU:
    401 	case MP_GET_PATH_LIST_FOR_INIT_PORT:
    402 	case MP_GET_PATH_LIST_FOR_TARGET_PORT:
    403 	case MP_GET_LU_LIST_FROM_TPG:
    404 	case MP_GET_TPG_LIST_FOR_LU:
    405 	case MP_GET_TARGET_PORT_LIST_FOR_TPG:
    406 	{
    407 		if ((mpioc->mp_ilen != sizeof (uint64_t)) ||
    408 		    (mpioc->mp_ibuf == NULL) ||
    409 		    (mpioc->mp_olen == 0) ||
    410 		    (mpioc->mp_obuf == NULL) ||
    411 		    (mpioc->mp_xfer != MP_XFER_READ)) {
    412 			rval = EINVAL;
    413 		}
    414 		if (mpioc->mp_olen == 0) {
    415 			/* We don't know alen yet, No point trying to set it */
    416 			mpioc->mp_errno = MP_MORE_DATA;
    417 			rval = MP_MORE_DATA;
    418 		}
    419 	}
    420 	break;
    421 
    422 	case MP_SET_TPG_ACCESS_STATE:
    423 	{
    424 		if (drv_priv(credp) != 0) {
    425 			rval = EPERM;
    426 			break;
    427 		}
    428 		if ((mpioc->mp_ilen != sizeof (mp_set_tpg_state_req_t)) ||
    429 		    (mpioc->mp_ibuf == NULL) ||
    430 		    (mpioc->mp_xfer != MP_XFER_WRITE)) {
    431 			rval = EINVAL;
    432 		}
    433 	}
    434 	break;
    435 
    436 	case MP_ENABLE_AUTO_FAILBACK:
    437 	case MP_DISABLE_AUTO_FAILBACK:
    438 	{
    439 		if (drv_priv(credp) != 0) {
    440 			rval = EPERM;
    441 			break;
    442 		}
    443 		if ((mpioc->mp_ibuf == NULL) ||
    444 		    (mpioc->mp_xfer !=  MP_XFER_WRITE)) {
    445 			rval = EINVAL;
    446 		}
    447 	}
    448 	break;
    449 
    450 	case MP_ENABLE_PATH:
    451 	case MP_DISABLE_PATH:
    452 	{
    453 		if (drv_priv(credp) != 0) {
    454 			rval = EPERM;
    455 			break;
    456 		}
    457 		if ((mpioc->mp_ilen != sizeof (uint64_t)) ||
    458 		    (mpioc->mp_ibuf == NULL) ||
    459 		    (mpioc->mp_xfer !=  MP_XFER_WRITE)) {
    460 			rval = EINVAL;
    461 		}
    462 	}
    463 	break;
    464 
    465 	case MP_SEND_SCSI_CMD:
    466 	{
    467 		cred_t	*cr;
    468 		int	olen = 0;
    469 
    470 		cr = ddi_get_cred();
    471 		if (drv_priv(credp) != 0 && drv_priv(cr) != 0) {
    472 			rval = EPERM;
    473 			break;
    474 		}
    475 		if (mode32 == 1) {
    476 			olen = sizeof (struct uscsi_cmd32);
    477 		} else {
    478 			olen = sizeof (struct uscsi_cmd);
    479 		}
    480 		/* oid is in the ibuf and the uscsi cmd is in the obuf */
    481 		if ((mpioc->mp_ilen != sizeof (uint64_t)) ||
    482 		    (mpioc->mp_ibuf == NULL) ||
    483 		    (mpioc->mp_olen != olen) ||
    484 		    (mpioc->mp_obuf == NULL)) {
    485 			rval = EINVAL;
    486 		}
    487 	}
    488 	break;
    489 
    490 	case MP_ASSIGN_LU_TO_TPG:
    491 	{
    492 		if (drv_priv(credp) != 0) {
    493 			rval = EPERM;
    494 			break;
    495 		}
    496 		if ((mpioc->mp_ilen != sizeof (mp_lu_tpg_pair_t)) ||
    497 		    (mpioc->mp_ibuf == NULL) ||
    498 		    (mpioc->mp_xfer !=  MP_XFER_WRITE)) {
    499 			rval = EINVAL;
    500 		}
    501 	}
    502 	break;
    503 
    504 	default:
    505 	{
    506 		rval = EINVAL;
    507 	}
    508 
    509 	} /* Closing the main switch */
    510 
    511 	return (rval);
    512 }
    513 
    514 /* ARGSUSED */
    515 static int
    516 vhci_get_driver_prop(struct scsi_vhci *vhci, mp_iocdata_t *mpioc,
    517     void *input_data, void *output_data, int mode)
    518 {
    519 	int			rval = 0;
    520 	mp_driver_prop_t	*mpdp = (mp_driver_prop_t *)output_data;
    521 
    522 	if (output_data == NULL) {
    523 		return (EINVAL);
    524 	}
    525 
    526 	(void) strlcpy(mpdp->driverVersion, vhci_version_name,
    527 	    sizeof (mpdp->driverVersion));
    528 	mpdp->supportedLoadBalanceTypes =
    529 	    MP_DRVR_LOAD_BALANCE_TYPE_NONE |
    530 	    MP_DRVR_LOAD_BALANCE_TYPE_ROUNDROBIN |
    531 	    MP_DRVR_LOAD_BALANCE_TYPE_LBA_REGION;
    532 	mpdp->canSetTPGAccess = B_TRUE;
    533 	mpdp->canOverridePaths = B_FALSE;
    534 	mpdp->exposesPathDeviceFiles = B_FALSE;
    535 	(void) strlcpy(mpdp->deviceFileNamespace, "/devices/scsi_vhci",
    536 	    sizeof (mpdp->deviceFileNamespace));
    537 	mpdp->onlySupportsSpecifiedProducts = 1;
    538 	mpdp->maximumWeight = 1;
    539 	mpdp->failbackPollingRateMax = 0;
    540 	mpdp->currentFailbackPollingRate = 0;
    541 	mpdp->autoFailbackSupport = MP_DRVR_AUTO_FAILBACK_SUPPORT;
    542 	mutex_enter(&vhci->vhci_mutex);
    543 	mpdp->autoFailbackEnabled =
    544 	    ((vhci->vhci_conf_flags & VHCI_CONF_FLAGS_AUTO_FAILBACK) ?
    545 	    1 : 0);
    546 	mutex_exit(&vhci->vhci_mutex);
    547 	mpdp->defaultLoadBalanceType =
    548 	    MP_DRVR_LOAD_BALANCE_TYPE_ROUNDROBIN;
    549 	mpdp->probingPollingRateMax = 0;
    550 	mpdp->currentProbingPollingRate = 0;
    551 	mpdp->autoProbingSupport = 0;
    552 	mpdp->autoProbingEnabled = 0;
    553 
    554 	if (ddi_copyout(output_data, (void *)mpioc->mp_obuf,
    555 	    mpioc->mp_olen, mode) != 0) {
    556 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_get_driver_prop: "
    557 		    "ddi_copyout() for 64-bit failed"));
    558 		mpioc->mp_errno = EFAULT;
    559 	} else {
    560 		mpioc->mp_errno = 0;
    561 		mpioc->mp_alen = sizeof (mp_iocdata_t);
    562 	}
    563 
    564 	return (rval);
    565 }
    566 
    567 /* ARGSUSED */
    568 static int
    569 vhci_get_dev_prod_list(struct scsi_vhci *vhci, mp_iocdata_t *mpioc,
    570     void *input_data, void *output_data, int mode)
    571 {
    572 	int			count = 0, rval = 0;
    573 	int			list_len = mpioc->mp_olen/sizeof (uint64_t);
    574 	uint64_t		*oid_list = (uint64_t *)(output_data);
    575 	mpapi_item_list_t	*ilist;
    576 
    577 	if (output_data == NULL) {
    578 		return (EINVAL);
    579 	}
    580 
    581 	/*
    582 	 * XXX: Get the Plugin OID from the input_data and apply below
    583 	 * Currently, we know we have only 1 plugin, so it ok to directly
    584 	 * return this only plugin's device product list.
    585 	 */
    586 
    587 	ilist = vhci->mp_priv->
    588 	    obj_hdr_list[MP_OBJECT_TYPE_DEVICE_PRODUCT]->head;
    589 
    590 	while (ilist != NULL) {
    591 		if (count < list_len) {
    592 			oid_list[count] = (uint64_t)ilist->item->oid.raw_oid;
    593 		} else {
    594 			rval = MP_MORE_DATA;
    595 		}
    596 		ilist = ilist->next;
    597 		count++;
    598 	}
    599 
    600 	mpioc->mp_alen = (uint32_t)(count * sizeof (uint64_t));
    601 	if ((rval == MP_MORE_DATA) || (mpioc->mp_alen > mpioc->mp_olen)) {
    602 		mpioc->mp_errno = MP_MORE_DATA;
    603 		return (EINVAL);
    604 	}
    605 
    606 	if (ddi_copyout(output_data, (void *)mpioc->mp_obuf,
    607 	    (count * sizeof (uint64_t)), mode) != 0) {
    608 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_get_dev_prod_list: "
    609 		    "ddi_copyout() failed"));
    610 		mpioc->mp_errno = EFAULT;
    611 		rval = EINVAL;
    612 	} else {
    613 		mpioc->mp_errno = 0;
    614 	}
    615 
    616 	return (rval);
    617 }
    618 
    619 /* ARGSUSED */
    620 static int
    621 vhci_get_dev_prod_prop(struct scsi_vhci *vhci, mp_iocdata_t *mpioc,
    622     void *input_data, void *output_data, int mode)
    623 {
    624 	int			rval = 0;
    625 	uint64_t		*oid = (uint64_t *)(input_data);
    626 	mp_dev_prod_prop_t	*dev_prop = NULL;
    627 	mpapi_item_list_t	*ilist;
    628 
    629 	if ((output_data == NULL) || (input_data == NULL)) {
    630 		return (EINVAL);
    631 	}
    632 	ilist = vhci->mp_priv->
    633 	    obj_hdr_list[MP_OBJECT_TYPE_DEVICE_PRODUCT]->head;
    634 	while ((ilist != NULL) && (*oid != ilist->item->oid.raw_oid)) {
    635 		ilist = ilist->next;
    636 	}
    637 	if (ilist != NULL) {
    638 		dev_prop = (mp_dev_prod_prop_t *)(ilist->item->idata);
    639 		if (dev_prop == NULL) {
    640 			return (EINVAL);
    641 		}
    642 	} else {
    643 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_get_dev_prod_prop: "
    644 		    "OID NOT FOUND"));
    645 		mpioc->mp_errno = MP_DRVR_INVALID_ID;
    646 		return (EINVAL);
    647 	}
    648 	/*
    649 	 * Here were are not using the 'output_data' that is
    650 	 * passed as the required information is already
    651 	 * in the required format!
    652 	 */
    653 	if (ddi_copyout((void *)dev_prop, mpioc->mp_obuf,
    654 	    sizeof (mp_dev_prod_prop_t), mode) != 0) {
    655 		return (EFAULT);
    656 	}
    657 	return (rval);
    658 }
    659 
    660 /* ARGSUSED */
    661 static int
    662 vhci_get_lu_list(struct scsi_vhci *vhci, mp_iocdata_t *mpioc,
    663     void *input_data, void *output_data, int mode)
    664 {
    665 	int			count = 0, rval = 0;
    666 	int			list_len = mpioc->mp_olen/sizeof (uint64_t);
    667 	uint64_t		*oid_list = (uint64_t *)(output_data);
    668 	mpapi_item_list_t	*ilist;
    669 	mpapi_lu_data_t		*ld;
    670 
    671 	if (output_data == NULL) {
    672 		return (EINVAL);
    673 	}
    674 
    675 	ilist = vhci->mp_priv->obj_hdr_list[MP_OBJECT_TYPE_MULTIPATH_LU]->head;
    676 
    677 	while (ilist != NULL) {
    678 		if (count < list_len) {
    679 			oid_list[count] = (uint64_t)(ilist->item->oid.raw_oid);
    680 		} else {
    681 			rval = MP_MORE_DATA;
    682 		}
    683 		ld = ilist->item->idata;
    684 		if (ld->valid == 0) {
    685 			count--;
    686 		}
    687 		ilist = ilist->next;
    688 		count++;
    689 	}
    690 
    691 	mpioc->mp_alen = (uint32_t)(count * sizeof (uint64_t));
    692 	if ((rval == MP_MORE_DATA) || (mpioc->mp_alen > mpioc->mp_olen)) {
    693 		mpioc->mp_errno = MP_MORE_DATA;
    694 		return (EINVAL);
    695 	}
    696 
    697 	if (ddi_copyout(output_data, (void *)mpioc->mp_obuf,
    698 	    (count * sizeof (uint64_t)), mode) != 0) {
    699 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_get_lu_list: "
    700 		    "ddi_copyout() FAILED"));
    701 		mpioc->mp_errno = EFAULT;
    702 		rval = EINVAL;
    703 	} else {
    704 		mpioc->mp_errno = 0;
    705 	}
    706 
    707 	return (rval);
    708 }
    709 
    710 /* ARGSUSED */
    711 static int
    712 vhci_get_lu_list_from_tpg(struct scsi_vhci *vhci, mp_iocdata_t *mpioc,
    713     void *input_data, void *output_data, int mode)
    714 {
    715 	int			count = 0, rval = 0;
    716 	int			list_len = mpioc->mp_olen/sizeof (uint64_t);
    717 	uint64_t		*oid_list = (uint64_t *)(output_data);
    718 	uint64_t		*oid = (uint64_t *)(input_data);
    719 	mpapi_item_list_t	*ilist, *tpg_lu_list = NULL;
    720 	mpapi_tpg_data_t	*mptpglu;
    721 	mpapi_lu_data_t		*ld;
    722 
    723 	ilist = vhci->mp_priv->obj_hdr_list[MP_OBJECT_TYPE_TARGET_PORT_GROUP]
    724 	    ->head;
    725 
    726 	while ((ilist != NULL) && (*oid != ilist->item->oid.raw_oid))
    727 		ilist = ilist->next;
    728 
    729 	if (ilist == NULL) {
    730 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_get_lu_list_from_tpg: "
    731 		    "OID NOT FOUND"));
    732 		mpioc->mp_errno = MP_DRVR_INVALID_ID;
    733 		rval = EINVAL;
    734 	} else if (*oid == ilist->item->oid.raw_oid) {
    735 		mptpglu = (mpapi_tpg_data_t *)(ilist->item->idata);
    736 		if (mptpglu->valid == 0) {
    737 			VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_get_lu_list_from_"
    738 			    "tpg: OID NOT FOUND - TPG IS INVALID"));
    739 			mpioc->mp_errno = MP_DRVR_INVALID_ID;
    740 			return (EINVAL);
    741 		}
    742 		tpg_lu_list = mptpglu->lu_list->head;
    743 	} else {
    744 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_get_lu_list_from_tpg: "
    745 		    "Unknown Error"));
    746 	}
    747 
    748 	while (tpg_lu_list != NULL) {
    749 		if (count < list_len) {
    750 			oid_list[count] = (uint64_t)tpg_lu_list->
    751 			    item->oid.raw_oid;
    752 		} else {
    753 			rval = MP_MORE_DATA;
    754 		}
    755 		/*
    756 		 * Get rid of the latest entry if item is invalid
    757 		 */
    758 		ld = tpg_lu_list->item->idata;
    759 		if (ld->valid == 0) {
    760 			count--;
    761 		}
    762 		tpg_lu_list = tpg_lu_list->next;
    763 		count++;
    764 	}
    765 
    766 	mpioc->mp_alen = (uint32_t)(count * sizeof (uint64_t));
    767 	if ((rval == MP_MORE_DATA) || (mpioc->mp_alen > mpioc->mp_olen)) {
    768 		mpioc->mp_errno = MP_MORE_DATA;
    769 		return (EINVAL);
    770 	}
    771 
    772 	if ((count > 0) && (ddi_copyout(output_data, (void *)mpioc->mp_obuf,
    773 	    (count * sizeof (uint64_t)), mode) != 0)) {
    774 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_get_lu_list_from_tpg: "
    775 		    "ddi_copyout() FAILED"));
    776 		mpioc->mp_errno = EFAULT;
    777 		rval = EINVAL;
    778 	}
    779 
    780 	return (rval);
    781 }
    782 
    783 /* ARGSUSED */
    784 static int
    785 vhci_get_tpg_list_for_lu(struct scsi_vhci *vhci, mp_iocdata_t *mpioc,
    786     void *input_data, void *output_data, int mode)
    787 {
    788 	int			count = 0, rval = 0;
    789 	int			list_len = mpioc->mp_olen/sizeof (uint64_t);
    790 	uint64_t		*oid_list = (uint64_t *)(output_data);
    791 	uint64_t		*oid = (uint64_t *)(input_data);
    792 	mpapi_item_list_t	*ilist, *mplu_tpg_list = NULL;
    793 	mpapi_lu_data_t		*mplutpg;
    794 	mpapi_tpg_data_t	*tpgd;
    795 
    796 	ilist = vhci->mp_priv->obj_hdr_list[MP_OBJECT_TYPE_MULTIPATH_LU]->head;
    797 
    798 	while ((ilist != NULL) && (*oid != ilist->item->oid.raw_oid))
    799 		ilist = ilist->next;
    800 
    801 	if (ilist == NULL) {
    802 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_get_tpg_list_for_lu: "
    803 		    "OID NOT FOUND"));
    804 		mpioc->mp_errno = MP_DRVR_INVALID_ID;
    805 		rval = EINVAL;
    806 	} else if (*oid == ilist->item->oid.raw_oid) {
    807 		mplutpg = (mpapi_lu_data_t *)(ilist->item->idata);
    808 		if (mplutpg->valid == 0) {
    809 			VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_get_tpg_list_for_"
    810 			    "lu: OID NOT FOUND - LU IS OFFLINE"));
    811 			mpioc->mp_errno = MP_DRVR_INVALID_ID;
    812 			return (EINVAL);
    813 		}
    814 		mplu_tpg_list = mplutpg->tpg_list->head;
    815 	} else {
    816 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_get_tpg_list_for_lu: "
    817 		    "Unknown Error"));
    818 	}
    819 
    820 	while (mplu_tpg_list != NULL) {
    821 		if (count < list_len) {
    822 			oid_list[count] =
    823 			    (uint64_t)mplu_tpg_list->item->oid.raw_oid;
    824 		} else {
    825 			rval = MP_MORE_DATA;
    826 		}
    827 		tpgd = mplu_tpg_list->item->idata;
    828 		if (tpgd->valid == 0) {
    829 			count--;
    830 		}
    831 		mplu_tpg_list = mplu_tpg_list->next;
    832 		count++;
    833 	}
    834 
    835 	mpioc->mp_alen = (uint32_t)(count * sizeof (uint64_t));
    836 	if ((rval == MP_MORE_DATA) || (mpioc->mp_alen > mpioc->mp_olen)) {
    837 		mpioc->mp_errno = MP_MORE_DATA;
    838 		return (EINVAL);
    839 	}
    840 
    841 	if ((count > 0) && (ddi_copyout(output_data, (void *)mpioc->mp_obuf,
    842 	    (count * sizeof (uint64_t)), mode) != 0)) {
    843 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_get_tpg_list_for_lu: "
    844 		    "ddi_copyout() FAILED"));
    845 		mpioc->mp_errno = EFAULT;
    846 		rval = EINVAL;
    847 	}
    848 
    849 	return (rval);
    850 }
    851 
    852 /* ARGSUSED */
    853 static int
    854 vhci_get_lu_prop(struct scsi_vhci *vhci, mp_iocdata_t *mpioc,
    855     void *input_data, void *output_data, int mode)
    856 {
    857 	int			rval = 0;
    858 	uint64_t		*oid = (uint64_t *)(input_data);
    859 	mp_logical_unit_prop_t	*mplup_prop;
    860 	mpapi_item_list_t	*ilist;
    861 	mpapi_lu_data_t		*mplup;
    862 
    863 	mplup_prop = (mp_logical_unit_prop_t *)output_data;
    864 	ilist = vhci->mp_priv->obj_hdr_list[MP_OBJECT_TYPE_MULTIPATH_LU]->head;
    865 
    866 	while ((ilist != NULL) && (*oid != ilist->item->oid.raw_oid)) {
    867 		ilist = ilist->next;
    868 	}
    869 
    870 	if (ilist != NULL) {
    871 		mplup = (mpapi_lu_data_t *)(ilist->item->idata);
    872 		if (mplup == NULL) {
    873 			VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_get_lu_prop: "
    874 			    "idata in ilist is NULL"));
    875 			return (EINVAL);
    876 		} else if (mplup->valid == 0) {
    877 			VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_get_lu_prop: "
    878 			    "OID NOT FOUND - LU GONE OFFLINE"));
    879 			mpioc->mp_errno = MP_DRVR_INVALID_ID;
    880 			return (EINVAL);
    881 		}
    882 		mplup_prop = (mp_logical_unit_prop_t *)(&mplup->prop);
    883 	} else {
    884 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_get_lu_prop: "
    885 		    "OID NOT FOUND"));
    886 		mpioc->mp_errno = MP_DRVR_INVALID_ID;
    887 		return (EINVAL);
    888 	}
    889 
    890 	/*
    891 	 * Here were are not using the 'output_data' that is
    892 	 * passed as the required information is already
    893 	 * in the required format!
    894 	 */
    895 	if (ddi_copyout((void *)mplup_prop, mpioc->mp_obuf,
    896 	    sizeof (mp_logical_unit_prop_t), mode) != 0) {
    897 		return (EFAULT);
    898 	}
    899 	return (rval);
    900 }
    901 
    902 /* ARGSUSED */
    903 static int
    904 vhci_get_path_list_for_mp_lu(struct scsi_vhci *vhci, mp_iocdata_t *mpioc,
    905     void *input_data, void *output_data, int mode)
    906 {
    907 	int			count = 0, rval = 0;
    908 	int			list_len = mpioc->mp_olen/sizeof (uint64_t);
    909 	uint64_t		*oid_list = (uint64_t *)(output_data);
    910 	uint64_t		*oid = (uint64_t *)(input_data);
    911 	mpapi_item_list_t	*ilist, *mplu_path_list = NULL;
    912 	mpapi_lu_data_t		*mplup;
    913 	mpapi_path_data_t	*mppathp;
    914 	mdi_pathinfo_t		*pip;
    915 
    916 	ilist = vhci->mp_priv->obj_hdr_list[MP_OBJECT_TYPE_MULTIPATH_LU]->head;
    917 
    918 	while ((ilist != NULL) && (*oid != ilist->item->oid.raw_oid))
    919 		ilist = ilist->next;
    920 
    921 	if (ilist == NULL) {
    922 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_get_path_list_for_mp_lu: "
    923 		    "OID NOT FOUND"));
    924 		mpioc->mp_errno = MP_DRVR_INVALID_ID;
    925 		rval = EINVAL;
    926 	} else if (*oid == ilist->item->oid.raw_oid) {
    927 		mplup = (mpapi_lu_data_t *)(ilist->item->idata);
    928 		if (mplup->valid == 0) {
    929 			VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_get_path_list_for_"
    930 			    "mp_lu: MP_DRVR_PATH_STATE_LU_ERR - LU OFFLINE"));
    931 			mpioc->mp_errno = MP_DRVR_PATH_STATE_LU_ERR;
    932 			return (EINVAL);
    933 		}
    934 		mplu_path_list = mplup->path_list->head;
    935 	} else {
    936 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_get_path_list_for_mp_lu: "
    937 		    "Unknown Error"));
    938 	}
    939 
    940 	while (mplu_path_list != NULL) {
    941 		mppathp  = (mpapi_path_data_t *)(mplu_path_list->item->idata);
    942 		/* skip a path that should be hidden. */
    943 		if (!(mppathp->hide)) {
    944 			pip = (mdi_pathinfo_t *)mppathp->resp;
    945 			mdi_hold_path(pip);
    946 			/*
    947 			 * check if the pip is marked as device removed.
    948 			 * When pi_flag MDI_PATHINFO_FLAGS_DEVICE_REMOVED is set
    949 			 * the node should have been destroyed but did not
    950 			 * due to open on the client node.
    951 			 * The driver tracks such a node through the hide flag
    952 			 * and doesn't report it throuth ioctl response.
    953 			 * The devinfo driver doesn't report such a path.
    954 			 */
    955 			if (!(MDI_PI_FLAGS_IS_DEVICE_REMOVED(pip))) {
    956 				if (count < list_len) {
    957 					oid_list[count] =
    958 					    (uint64_t)mplu_path_list->
    959 					    item->oid.raw_oid;
    960 				} else {
    961 					rval = MP_MORE_DATA;
    962 				}
    963 				count++;
    964 			}
    965 			mdi_rele_path(pip);
    966 		}
    967 		mplu_path_list = mplu_path_list->next;
    968 	}
    969 
    970 	mpioc->mp_alen = (uint32_t)(count * sizeof (uint64_t));
    971 	if ((rval == MP_MORE_DATA) || (mpioc->mp_alen > mpioc->mp_olen)) {
    972 		mpioc->mp_errno = MP_MORE_DATA;
    973 		return (EINVAL);
    974 	}
    975 
    976 	if ((count > 0) && (ddi_copyout(output_data, (void *)mpioc->mp_obuf,
    977 	    (count * sizeof (uint64_t)), mode) != 0)) {
    978 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_get_path_list_for_mp_lu: "
    979 		    "ddi_copyout() FAILED"));
    980 		mpioc->mp_errno = EFAULT;
    981 		rval = EINVAL;
    982 	}
    983 
    984 	return (rval);
    985 }
    986 
    987 /* ARGSUSED */
    988 static int
    989 vhci_get_path_list_for_init_port(struct scsi_vhci *vhci, mp_iocdata_t *mpioc,
    990     void *input_data, void *output_data, int mode)
    991 {
    992 	int			count = 0, rval = 0;
    993 	int			list_len = mpioc->mp_olen/sizeof (uint64_t);
    994 	uint64_t		*oid_list = (uint64_t *)(output_data);
    995 	uint64_t		*oid = (uint64_t *)(input_data);
    996 	mpapi_item_list_t	*ilist, *mpinit_path_list = NULL;
    997 	mpapi_initiator_data_t	*mpinitp;
    998 	mpapi_path_data_t	*mppathp;
    999 	mdi_pathinfo_t		*pip;
   1000 
   1001 	ilist = vhci->mp_priv->
   1002 	    obj_hdr_list[MP_OBJECT_TYPE_INITIATOR_PORT]->head;
   1003 
   1004 	/*
   1005 	 * While walking the mpapi database for initiator ports invalidate all
   1006 	 * initiator ports. The succeeding call to walk the phci list through
   1007 	 * MDI walker will validate the currently existing pHCIS.
   1008 	 */
   1009 	while (ilist != NULL) {
   1010 		mpinitp = ilist->item->idata;
   1011 		mpinitp->valid = 0;
   1012 		ilist = ilist->next;
   1013 	}
   1014 
   1015 	mdi_vhci_walk_phcis(vhci->vhci_dip, vhci_mpapi_sync_init_port_list,
   1016 	    vhci);
   1017 
   1018 	ilist = vhci->mp_priv->
   1019 	    obj_hdr_list[MP_OBJECT_TYPE_INITIATOR_PORT]->head;
   1020 
   1021 	while ((ilist != NULL) && (*oid != ilist->item->oid.raw_oid))
   1022 		ilist = ilist->next;
   1023 
   1024 	if (ilist == NULL) {
   1025 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_get_path_list_for_init_"
   1026 		    "port: OID NOT FOUND"));
   1027 		mpioc->mp_errno = MP_DRVR_INVALID_ID;
   1028 		rval = EINVAL;
   1029 	} else if (*oid == ilist->item->oid.raw_oid) {
   1030 		mpinitp = (mpapi_initiator_data_t *)(ilist->item->idata);
   1031 		if (mpinitp->valid == 0) {
   1032 			VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_get_path_list_for_"
   1033 			    "init_port: OID NOT FOUND - INIT PORT INVALID"));
   1034 			mpioc->mp_errno = MP_DRVR_INVALID_ID;
   1035 			return (EINVAL);
   1036 		}
   1037 		mpinit_path_list = mpinitp->path_list->head;
   1038 	} else {
   1039 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_get_path_list_for_init_"
   1040 		    "port: Unknown Error"));
   1041 	}
   1042 
   1043 	while (mpinit_path_list != NULL) {
   1044 		mppathp  = (mpapi_path_data_t *)(mpinit_path_list->item->idata);
   1045 		/* skip a path that should be hidden. */
   1046 		if (!(mppathp->hide)) {
   1047 			pip = (mdi_pathinfo_t *)mppathp->resp;
   1048 			mdi_hold_path(pip);
   1049 			/*
   1050 			 * check if the pip is marked as device removed.
   1051 			 * When pi_flag MDI_PATHINFO_FLAGS_DEVICE_REMOVED is set
   1052 			 * the node should have been destroyed but did not
   1053 			 * due to open on the client node.
   1054 			 * The driver tracks such a node through the hide flag
   1055 			 * and doesn't report it throuth ioctl response.
   1056 			 * The devinfo driver doesn't report such a path.
   1057 			 */
   1058 			if (!(MDI_PI_FLAGS_IS_DEVICE_REMOVED(pip))) {
   1059 				if (count < list_len) {
   1060 					oid_list[count] =
   1061 					    (uint64_t)mpinit_path_list->
   1062 					    item->oid.raw_oid;
   1063 				} else {
   1064 					rval = MP_MORE_DATA;
   1065 				}
   1066 				count++;
   1067 			}
   1068 			mdi_rele_path(pip);
   1069 		}
   1070 		mpinit_path_list = mpinit_path_list->next;
   1071 	}
   1072 
   1073 	mpioc->mp_alen = (uint32_t)(count * sizeof (uint64_t));
   1074 	if ((rval == MP_MORE_DATA) || (mpioc->mp_alen > mpioc->mp_olen)) {
   1075 		mpioc->mp_errno = MP_MORE_DATA;
   1076 		return (EINVAL);
   1077 	}
   1078 
   1079 	if ((count > 0) && (ddi_copyout(output_data, (void *)mpioc->mp_obuf,
   1080 	    (count * sizeof (uint64_t)), mode) != 0)) {
   1081 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_get_path_list_for_init_"
   1082 		    "port: ddi_copyout() FAILED"));
   1083 		mpioc->mp_errno = EFAULT;
   1084 		rval = EINVAL;
   1085 	}
   1086 
   1087 	return (rval);
   1088 }
   1089 
   1090 /* ARGSUSED */
   1091 static int
   1092 vhci_get_path_list_for_target_port(struct scsi_vhci *vhci, mp_iocdata_t *mpioc,
   1093     void *input_data, void *output_data, int mode)
   1094 {
   1095 	int			count = 0, rval = 0;
   1096 	int			list_len = mpioc->mp_olen/sizeof (uint64_t);
   1097 	uint64_t		*oid_list = (uint64_t *)(output_data);
   1098 	uint64_t		*oid = (uint64_t *)(input_data);
   1099 	mpapi_item_list_t	*ilist, *mptp_path_list = NULL;
   1100 	mpapi_tport_data_t	*mptpp;
   1101 	mpapi_path_data_t	*mppathp;
   1102 	mdi_pathinfo_t		*pip;
   1103 
   1104 	ilist = vhci->mp_priv->obj_hdr_list[MP_OBJECT_TYPE_TARGET_PORT]->head;
   1105 
   1106 	while ((ilist != NULL) && (*oid != ilist->item->oid.raw_oid))
   1107 		ilist = ilist->next;
   1108 
   1109 	if (ilist == NULL) {
   1110 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_get_path_list_for_target_"
   1111 		    "port: OID NOT FOUND"));
   1112 		mpioc->mp_errno = MP_DRVR_INVALID_ID;
   1113 		rval = EINVAL;
   1114 	} else if (*oid == ilist->item->oid.raw_oid) {
   1115 		mptpp = (mpapi_tport_data_t *)(ilist->item->idata);
   1116 		if (mptpp->valid == 0) {
   1117 			VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_get_path_list_for_"
   1118 			    "target_port: OID NOT FOUND - TGT PORT INVALID"));
   1119 			mpioc->mp_errno = MP_DRVR_INVALID_ID;
   1120 			return (EINVAL);
   1121 		}
   1122 		mptp_path_list = mptpp->path_list->head;
   1123 	} else {
   1124 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_get_path_list_for_target_"
   1125 		    "port: Unknown Error"));
   1126 	}
   1127 
   1128 	while (mptp_path_list != NULL) {
   1129 		mppathp  = (mpapi_path_data_t *)(mptp_path_list->item->idata);
   1130 		/* skip a path that should be hidden. */
   1131 		if (!(mppathp->hide)) {
   1132 			pip = (mdi_pathinfo_t *)mppathp->resp;
   1133 			mdi_hold_path(pip);
   1134 			/*
   1135 			 * check if the pip is marked as device removed.
   1136 			 * When pi_flag MDI_PATHINFO_FLAGS_DEVICE_REMOVED is set
   1137 			 * the node should have been destroyed but did not
   1138 			 * due to open on the client node.
   1139 			 * The driver tracks such a node through the hide flag
   1140 			 * and doesn't report it throuth ioctl response.
   1141 			 * The devinfo driver doesn't report such a path.
   1142 			 */
   1143 			if (!(MDI_PI_FLAGS_IS_DEVICE_REMOVED(pip))) {
   1144 				if (count < list_len) {
   1145 					oid_list[count] =
   1146 					    (uint64_t)mptp_path_list->
   1147 					    item->oid.raw_oid;
   1148 				} else {
   1149 					rval = MP_MORE_DATA;
   1150 				}
   1151 				count++;
   1152 			}
   1153 			mdi_rele_path(pip);
   1154 		}
   1155 		mptp_path_list = mptp_path_list->next;
   1156 	}
   1157 
   1158 	mpioc->mp_alen = (uint32_t)(count * sizeof (uint64_t));
   1159 	if ((rval == MP_MORE_DATA) || (mpioc->mp_alen > mpioc->mp_olen)) {
   1160 		mpioc->mp_errno = MP_MORE_DATA;
   1161 		return (EINVAL);
   1162 	}
   1163 
   1164 	if ((count > 0) && (ddi_copyout(output_data, (void *)mpioc->mp_obuf,
   1165 	    (count * sizeof (uint64_t)), mode) != 0)) {
   1166 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_get_path_list_for_target_"
   1167 		    "port: ddi_copyout() FAILED"));
   1168 		mpioc->mp_errno = EFAULT;
   1169 		rval = EINVAL;
   1170 	}
   1171 
   1172 	return (rval);
   1173 }
   1174 
   1175 /* ARGSUSED */
   1176 static int
   1177 vhci_get_path_prop(struct scsi_vhci *vhci, mp_iocdata_t *mpioc,
   1178     void *input_data, void *output_data, int mode)
   1179 {
   1180 	int			rval = 0;
   1181 	uint64_t		oid;
   1182 	mp_path_prop_t		*mpp_prop = (mp_path_prop_t *)output_data;
   1183 	mpapi_item_list_t	*ilist;
   1184 	mpapi_path_data_t	*mpp;
   1185 
   1186 	ilist = vhci->mp_priv->obj_hdr_list[MP_OBJECT_TYPE_PATH_LU]->head;
   1187 
   1188 	rval = ddi_copyin(mpioc->mp_ibuf, &oid, mpioc->mp_ilen, mode);
   1189 
   1190 	while ((ilist != NULL) && (oid != ilist->item->oid.raw_oid))
   1191 		ilist = ilist->next;
   1192 
   1193 	if (ilist != NULL) {
   1194 		mpp = (mpapi_path_data_t *)(ilist->item->idata);
   1195 		if (mpp == NULL) {
   1196 			VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_get_path_prop: "
   1197 			    "idata in ilist is NULL"));
   1198 			return (EINVAL);
   1199 		}
   1200 		mpp_prop = (mp_path_prop_t *)(&mpp->prop);
   1201 	} else {
   1202 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_get_path_prop: "
   1203 		    "OID NOT FOUND"));
   1204 		mpioc->mp_errno = MP_DRVR_INVALID_ID;
   1205 		return (EINVAL);
   1206 	}
   1207 
   1208 	/*
   1209 	 * Here were are not using the 'output_data' that is
   1210 	 * passed as the required information is already
   1211 	 * in the required format!
   1212 	 */
   1213 	if (ddi_copyout((void *)mpp_prop, mpioc->mp_obuf,
   1214 	    sizeof (mp_path_prop_t), mode) != 0) {
   1215 		return (EFAULT);
   1216 	}
   1217 
   1218 	return (rval);
   1219 }
   1220 
   1221 /* ARGSUSED */
   1222 static int
   1223 vhci_get_init_port_list(struct scsi_vhci *vhci, mp_iocdata_t *mpioc,
   1224     void *input_data, void *output_data, int mode)
   1225 {
   1226 	int			count = 0, rval = 0;
   1227 	int			list_len = mpioc->mp_olen/sizeof (uint64_t);
   1228 	uint64_t		*oid_list = (uint64_t *)(output_data);
   1229 	mpapi_item_list_t	*ilist;
   1230 	mpapi_initiator_data_t	*initd;
   1231 
   1232 	ilist = vhci->mp_priv->
   1233 	    obj_hdr_list[MP_OBJECT_TYPE_INITIATOR_PORT]->head;
   1234 
   1235 	/*
   1236 	 * While walking the mpapi database for initiator ports invalidate all
   1237 	 * initiator ports. The succeeding call to walk the phci list through
   1238 	 * MDI walker will validate the currently existing pHCIS.
   1239 	 */
   1240 	while (ilist != NULL) {
   1241 		initd = ilist->item->idata;
   1242 		initd->valid = 0;
   1243 		ilist = ilist->next;
   1244 	}
   1245 
   1246 	mdi_vhci_walk_phcis(vhci->vhci_dip, vhci_mpapi_sync_init_port_list,
   1247 	    vhci);
   1248 
   1249 	ilist = vhci->mp_priv->
   1250 	    obj_hdr_list[MP_OBJECT_TYPE_INITIATOR_PORT]->head;
   1251 
   1252 	while (ilist != NULL) {
   1253 		if (count < list_len) {
   1254 			oid_list[count] = (uint64_t)ilist->item->oid.raw_oid;
   1255 		} else {
   1256 			rval = MP_MORE_DATA;
   1257 		}
   1258 		/*
   1259 		 * Get rid of the latest entry if item is invalid
   1260 		 */
   1261 		initd = ilist->item->idata;
   1262 		if (initd->valid == 0) {
   1263 			count--;
   1264 		}
   1265 		ilist = ilist->next;
   1266 		count++;
   1267 	}
   1268 
   1269 	mpioc->mp_alen = (uint32_t)(count * sizeof (uint64_t));
   1270 	if ((rval == MP_MORE_DATA) || (mpioc->mp_alen > mpioc->mp_olen)) {
   1271 		mpioc->mp_errno = MP_MORE_DATA;
   1272 		return (EINVAL);
   1273 	}
   1274 
   1275 	if (ddi_copyout(output_data, (void *)mpioc->mp_obuf,
   1276 	    (count * sizeof (uint64_t)), mode) != 0) {
   1277 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_get_init_port_list: "
   1278 		    "ddi_copyout() FAILED"));
   1279 		mpioc->mp_errno = EFAULT;
   1280 		rval = EINVAL;
   1281 	} else {
   1282 		mpioc->mp_errno = 0;
   1283 	}
   1284 
   1285 	return (rval);
   1286 }
   1287 
   1288 /* ARGSUSED */
   1289 static int
   1290 vhci_get_init_port_prop(struct scsi_vhci *vhci, mp_iocdata_t *mpioc,
   1291     void *input_data, void *output_data, int mode)
   1292 {
   1293 	int			rval = 0;
   1294 	uint64_t		*oid = (uint64_t *)(input_data);
   1295 	mp_init_port_prop_t	*mpip_prop = (mp_init_port_prop_t *)output_data;
   1296 	mpapi_item_list_t	*ilist;
   1297 	mpapi_initiator_data_t	*mpip;
   1298 
   1299 	ilist = vhci->mp_priv->
   1300 	    obj_hdr_list[MP_OBJECT_TYPE_INITIATOR_PORT]->head;
   1301 
   1302 	/*
   1303 	 * While walking the mpapi database for initiator ports invalidate all
   1304 	 * initiator ports. The succeeding call to walk the phci list through
   1305 	 * MDI walker will validate the currently existing pHCIS.
   1306 	 */
   1307 	while (ilist != NULL) {
   1308 		mpip = ilist->item->idata;
   1309 		mpip->valid = 0;
   1310 		ilist = ilist->next;
   1311 	}
   1312 
   1313 	mdi_vhci_walk_phcis(vhci->vhci_dip, vhci_mpapi_sync_init_port_list,
   1314 	    vhci);
   1315 
   1316 	ilist = vhci->mp_priv->
   1317 	    obj_hdr_list[MP_OBJECT_TYPE_INITIATOR_PORT]->head;
   1318 
   1319 	while ((ilist != NULL) && (*oid != ilist->item->oid.raw_oid)) {
   1320 		ilist = ilist->next;
   1321 	}
   1322 
   1323 	if (ilist != NULL) {
   1324 		mpip = (mpapi_initiator_data_t *)(ilist->item->idata);
   1325 		if (mpip == NULL) {
   1326 			VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_get_init_port_prop:"
   1327 			    " idata in ilist is NULL"));
   1328 			return (EINVAL);
   1329 		} else if (mpip->valid == 0) {
   1330 			VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_get_init_port_prop"
   1331 			    ": OID NOT FOUND - INIT PORT IS INVALID"));
   1332 			mpioc->mp_errno = MP_DRVR_INVALID_ID;
   1333 			return (EINVAL);
   1334 		}
   1335 		mpip_prop = (mp_init_port_prop_t *)(&mpip->prop);
   1336 	} else {
   1337 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_get_init_port_prop: "
   1338 		    "OID NOT FOUND"));
   1339 		mpioc->mp_errno = MP_DRVR_INVALID_ID;
   1340 		return (EINVAL);
   1341 	}
   1342 
   1343 	/*
   1344 	 * Here were are not using the 'output_data' that is
   1345 	 * passed as the required information is already
   1346 	 * in the required format!
   1347 	 */
   1348 	if (ddi_copyout((void *)mpip_prop, mpioc->mp_obuf,
   1349 	    sizeof (mp_init_port_prop_t), mode) != 0) {
   1350 		return (EFAULT);
   1351 	}
   1352 	return (rval);
   1353 }
   1354 
   1355 /* ARGSUSED */
   1356 static int
   1357 vhci_get_target_port_prop(struct scsi_vhci *vhci, mp_iocdata_t *mpioc,
   1358     void *input_data, void *output_data, int mode)
   1359 {
   1360 	int			rval = 0;
   1361 	uint64_t		*oid = (uint64_t *)(input_data);
   1362 	mp_target_port_prop_t	*mptp_prop;
   1363 	mpapi_item_list_t	*ilist;
   1364 	mpapi_tport_data_t	*mptp;
   1365 
   1366 	mptp_prop = (mp_target_port_prop_t *)output_data;
   1367 	ilist = vhci->mp_priv->obj_hdr_list[MP_OBJECT_TYPE_TARGET_PORT]->head;
   1368 
   1369 	while ((ilist != NULL) && (*oid != ilist->item->oid.raw_oid)) {
   1370 		ilist = ilist->next;
   1371 	}
   1372 
   1373 	if (ilist != NULL) {
   1374 		mptp = (mpapi_tport_data_t *)(ilist->item->idata);
   1375 		if (mptp == NULL) {
   1376 			VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_get_target_port_"
   1377 			    "prop: idata in ilist is NULL"));
   1378 			return (EINVAL);
   1379 		} else if (mptp->valid == 0) {
   1380 			VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_get_target_port_"
   1381 			    "prop: OID NOT FOUND - TARGET PORT INVALID"));
   1382 			mpioc->mp_errno = MP_DRVR_INVALID_ID;
   1383 			return (EINVAL);
   1384 		}
   1385 		mptp_prop = (mp_target_port_prop_t *)(&mptp->prop);
   1386 	} else {
   1387 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_get_target_port_prop: "
   1388 		    "OID NOT FOUND"));
   1389 		mpioc->mp_errno = MP_DRVR_INVALID_ID;
   1390 		return (EINVAL);
   1391 	}
   1392 	/*
   1393 	 * Here were are not using the 'output_data' that is
   1394 	 * passed as the required information is already
   1395 	 * in the required format!
   1396 	 */
   1397 	if (ddi_copyout((void *)mptp_prop, mpioc->mp_obuf,
   1398 	    sizeof (mp_target_port_prop_t), mode) != 0) {
   1399 		return (EFAULT);
   1400 	}
   1401 
   1402 	return (rval);
   1403 }
   1404 
   1405 /* ARGSUSED */
   1406 static int
   1407 vhci_get_tpg_prop(struct scsi_vhci *vhci, mp_iocdata_t *mpioc,
   1408     void *input_data, void *output_data, int mode)
   1409 {
   1410 	int			rval = 0;
   1411 	uint64_t		*oid = (uint64_t *)(input_data);
   1412 	mp_tpg_prop_t		*mptpg_prop;
   1413 	mpapi_item_list_t	*ilist;
   1414 	mpapi_tpg_data_t	*mptpg;
   1415 
   1416 	mptpg_prop = (mp_tpg_prop_t *)output_data;
   1417 	ilist = vhci->mp_priv->obj_hdr_list[MP_OBJECT_TYPE_TARGET_PORT_GROUP]->
   1418 	    head;
   1419 
   1420 	while ((ilist != NULL) && (*oid != ilist->item->oid.raw_oid)) {
   1421 		ilist = ilist->next;
   1422 	}
   1423 
   1424 	if (ilist != NULL) {
   1425 		mptpg = (mpapi_tpg_data_t *)(ilist->item->idata);
   1426 		if (mptpg == NULL) {
   1427 			VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_get_tpg_prop: "
   1428 			    "idata in ilist is NULL"));
   1429 			return (EINVAL);
   1430 		} else if (mptpg->valid == 0) {
   1431 			VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_get_tpg_prop: "
   1432 			    "OID NOT FOUND - TPG INVALID"));
   1433 			mpioc->mp_errno = MP_DRVR_INVALID_ID;
   1434 			return (EINVAL);
   1435 		}
   1436 		mptpg_prop = (mp_tpg_prop_t *)(&mptpg->prop);
   1437 	} else {
   1438 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_get_tpg_prop: "
   1439 		    "OID NOT FOUND"));
   1440 		mpioc->mp_errno = MP_DRVR_INVALID_ID;
   1441 		return (EINVAL);
   1442 	}
   1443 	/*
   1444 	 * Here were are not using the 'output_data' that is
   1445 	 * passed as the required information is already
   1446 	 * in the required format!
   1447 	 */
   1448 	if (ddi_copyout((void *)mptpg_prop, mpioc->mp_obuf,
   1449 	    sizeof (mp_tpg_prop_t), mode) != 0) {
   1450 		return (EFAULT);
   1451 	}
   1452 
   1453 	return (rval);
   1454 }
   1455 
   1456 /* ARGSUSED */
   1457 static int
   1458 vhci_get_target_port_list_for_tpg(struct scsi_vhci *vhci, mp_iocdata_t *mpioc,
   1459     void *input_data, void *output_data, int mode)
   1460 {
   1461 	int			count = 0, rval = 0;
   1462 	int			list_len = mpioc->mp_olen/sizeof (uint64_t);
   1463 	uint64_t		*oid_list = (uint64_t *)(output_data);
   1464 	uint64_t		*oid = (uint64_t *)(input_data);
   1465 	mpapi_item_list_t	*ilist, *tpg_tp_list = NULL;
   1466 	mpapi_tpg_data_t	*mptpgtp;
   1467 	mpapi_tport_data_t	*mptpp;
   1468 
   1469 	ilist = vhci->mp_priv->obj_hdr_list[MP_OBJECT_TYPE_TARGET_PORT_GROUP]
   1470 	    ->head;
   1471 
   1472 	while ((ilist != NULL) && (*oid != ilist->item->oid.raw_oid))
   1473 		ilist = ilist->next;
   1474 
   1475 	if (ilist == NULL) {
   1476 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_get_target_port_list_for_"
   1477 		    "tpg: OID NOT FOUND"));
   1478 		mpioc->mp_errno = MP_DRVR_INVALID_ID;
   1479 		rval = EINVAL;
   1480 	} else if (*oid == ilist->item->oid.raw_oid) {
   1481 		mptpgtp = (mpapi_tpg_data_t *)(ilist->item->idata);
   1482 		if (mptpgtp->valid == 0) {
   1483 			VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_get_target_port_"
   1484 			    "list_for_tpg: OID NOT FOUND - TPG INVALID"));
   1485 			mpioc->mp_errno = MP_DRVR_INVALID_ID;
   1486 			return (EINVAL);
   1487 		}
   1488 		tpg_tp_list = mptpgtp->tport_list->head;
   1489 	} else {
   1490 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_get_target_port_list_for_"
   1491 		    "tpg: Unknown Error"));
   1492 	}
   1493 
   1494 	while (tpg_tp_list != NULL) {
   1495 		if (count < list_len) {
   1496 			oid_list[count] = (uint64_t)tpg_tp_list->
   1497 			    item->oid.raw_oid;
   1498 		} else {
   1499 			rval = MP_MORE_DATA;
   1500 		}
   1501 		mptpp = tpg_tp_list->item->idata;
   1502 		if (mptpp->valid == 0) {
   1503 			count--;
   1504 		}
   1505 		tpg_tp_list = tpg_tp_list->next;
   1506 		count++;
   1507 	}
   1508 
   1509 	mpioc->mp_alen = (uint32_t)(count * sizeof (uint64_t));
   1510 	if ((rval == MP_MORE_DATA) || (mpioc->mp_alen > mpioc->mp_olen)) {
   1511 		mpioc->mp_errno = MP_MORE_DATA;
   1512 		return (EINVAL);
   1513 	}
   1514 
   1515 	if ((count > 0) && (ddi_copyout(output_data, (void *)mpioc->mp_obuf,
   1516 	    (count * sizeof (uint64_t)), mode) != 0)) {
   1517 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_get_target_port_list_for_"
   1518 		    "tpg: ddi_copyout() FAILED"));
   1519 		mpioc->mp_errno = EFAULT;
   1520 		rval = EINVAL;
   1521 	}
   1522 
   1523 	return (rval);
   1524 }
   1525 
   1526 /* ARGSUSED */
   1527 static int
   1528 vhci_set_tpg_access_state(struct scsi_vhci *vhci, mp_iocdata_t *mpioc,
   1529     void *input_data, void *output_data, int mode)
   1530 {
   1531 	int			rval = 0, retval = 0, held = 0;
   1532 	uint32_t		desired_state, t10_tpgid;
   1533 	uint64_t		lu_oid, tpg_oid;
   1534 	mp_set_tpg_state_req_t	mp_set_tpg;
   1535 	mpapi_item_list_t	*lu_list, *tpg_list;
   1536 	mpapi_tpg_data_t	*mptpgd;
   1537 	scsi_vhci_lun_t		*svl;
   1538 	scsi_vhci_priv_t	*svp;
   1539 	mdi_pathinfo_t		*pip;
   1540 	struct scsi_address	*ap = NULL;
   1541 
   1542 	lu_list = vhci->mp_priv->obj_hdr_list[MP_OBJECT_TYPE_MULTIPATH_LU]
   1543 	    ->head;
   1544 	tpg_list = vhci->mp_priv->obj_hdr_list[MP_OBJECT_TYPE_TARGET_PORT_GROUP]
   1545 	    ->head;
   1546 
   1547 	rval = ddi_copyin(mpioc->mp_ibuf, &mp_set_tpg, mpioc->mp_ilen, mode);
   1548 	lu_oid = mp_set_tpg.luTpgPair.luId;
   1549 	tpg_oid = mp_set_tpg.luTpgPair.tpgId;
   1550 	desired_state = mp_set_tpg.desiredState;
   1551 
   1552 	VHCI_DEBUG(1, (CE_NOTE, NULL, "vhci_set_tpg_access_state: lu_oid: %lx,"
   1553 	    "tpg_oid: %lx, des_as: %x\n", (long)lu_oid, (long)tpg_oid,
   1554 	    desired_state));
   1555 
   1556 	while ((lu_list != NULL) && (lu_oid != lu_list->item->oid.raw_oid))
   1557 		lu_list = lu_list->next;
   1558 	while ((tpg_list != NULL) && (tpg_oid != tpg_list->item->oid.raw_oid))
   1559 		tpg_list = tpg_list->next;
   1560 
   1561 	if ((lu_list == NULL) || (tpg_list == NULL)) {
   1562 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_set_tpg_access_state: "
   1563 		    "OID NOT FOUND"));
   1564 		mpioc->mp_errno = MP_DRVR_INVALID_ID;
   1565 		return (EINVAL);
   1566 	}
   1567 	if ((desired_state != MP_DRVR_ACCESS_STATE_ACTIVE) &&
   1568 	    (desired_state != MP_DRVR_ACCESS_STATE_ACTIVE_OPTIMIZED) &&
   1569 	    (desired_state != MP_DRVR_ACCESS_STATE_ACTIVE_NONOPTIMIZED) &&
   1570 	    (desired_state != MP_DRVR_ACCESS_STATE_STANDBY)) {
   1571 		mpioc->mp_errno = MP_DRVR_ILLEGAL_ACCESS_STATE_REQUEST;
   1572 		return (EINVAL);
   1573 	}
   1574 	mptpgd = (mpapi_tpg_data_t *)(tpg_list->item->idata);
   1575 	if (desired_state == mptpgd->prop.accessState) {
   1576 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_set_tpg_access_"
   1577 		    "state: TPG already in desired State"));
   1578 		return (EINVAL);
   1579 	}
   1580 	t10_tpgid = mptpgd->prop.tpgId;
   1581 
   1582 	/*
   1583 	 * All input seems to be ok, Go ahead & change state.
   1584 	 */
   1585 	svl = ((mpapi_lu_data_t *)(lu_list->item->idata))->resp;
   1586 	if (!SCSI_FAILOVER_IS_TPGS(svl->svl_fops)) {
   1587 
   1588 		VHCI_HOLD_LUN(svl, VH_SLEEP, held);
   1589 		/*
   1590 		 * retval specifically cares about failover
   1591 		 * status and not about this routine's success.
   1592 		 */
   1593 		retval = mdi_failover(vhci->vhci_dip, svl->svl_dip,
   1594 		    MDI_FAILOVER_SYNC);
   1595 		if (retval != 0) {
   1596 			VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_set_tpg_access_"
   1597 			    "state: FAILOVER FAILED: %x", retval));
   1598 			VHCI_RELEASE_LUN(svl);
   1599 			return (EIO);
   1600 		} else {
   1601 			/*
   1602 			 * Don't set TPG's accessState here. Let mdi_failover's
   1603 			 * call-back routine "vhci_failover()" call
   1604 			 * vhci_mpapi_update_tpg_acc_state_for_lu().
   1605 			 */
   1606 			VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_set_tpg_access_"
   1607 			    "state: FAILOVER SUCCESS: %x", retval));
   1608 		}
   1609 		VHCI_RELEASE_LUN(svl);
   1610 	} else {
   1611 		/*
   1612 		 * Send SET_TARGET_PORT_GROUP SCSI Command. This is supported
   1613 		 * ONLY by devices which have TPGS EXPLICIT Failover support.
   1614 		 */
   1615 		retval = mdi_select_path(svl->svl_dip, NULL,
   1616 		    MDI_SELECT_ONLINE_PATH, NULL, &pip);
   1617 		if ((rval != MDI_SUCCESS) || (pip == NULL)) {
   1618 			VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_set_tpg_access_"
   1619 			    "state: Unable to find path: %x", retval));
   1620 			return (EINVAL);
   1621 		}
   1622 		svp = (scsi_vhci_priv_t *)mdi_pi_get_vhci_private(pip);
   1623 		if (svp == NULL) {
   1624 			VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_set_tpg_access_"
   1625 			    "state: Unable to find vhci private data"));
   1626 			mdi_rele_path(pip);
   1627 			return (EINVAL);
   1628 		}
   1629 		if (svp->svp_psd == NULL) {
   1630 			VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_set_tpg_access_"
   1631 			    "state: Unable to find scsi device"));
   1632 			mdi_rele_path(pip);
   1633 			return (EINVAL);
   1634 		}
   1635 		mdi_rele_path(pip);
   1636 		ap = &svp->svp_psd->sd_address;
   1637 		ASSERT(ap != NULL);
   1638 
   1639 		retval = vhci_tpgs_set_target_groups(ap, desired_state,
   1640 		    t10_tpgid);
   1641 		if (retval != 0) {
   1642 			VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_set_tpg_access_"
   1643 			    "state:(ALUA) FAILOVER FAILED: %x", retval));
   1644 			return (EIO);
   1645 		} else {
   1646 			/*
   1647 			 * Don't set accessState here.
   1648 			 * std_report_target_groups() call needs to sync up
   1649 			 * properly.
   1650 			 */
   1651 			VHCI_DEBUG(4, (CE_WARN, NULL, "vhci_set_tpg_access_"
   1652 			    "state:(ALUA) FAILOVER SUCCESS: %x", retval));
   1653 
   1654 			VHCI_HOLD_LUN(svl, VH_NOSLEEP, held);
   1655 			if (!held) {
   1656 				return (TRAN_BUSY);
   1657 			} else {
   1658 				vhci_update_pathstates((void *)svl);
   1659 			}
   1660 			if (desired_state != mptpgd->prop.accessState &&
   1661 			    (desired_state != MP_DRVR_ACCESS_STATE_ACTIVE ||
   1662 			    (mptpgd->prop.accessState !=
   1663 			    MP_DRVR_ACCESS_STATE_ACTIVE_OPTIMIZED &&
   1664 			    mptpgd->prop.accessState !=
   1665 			    MP_DRVR_ACCESS_STATE_ACTIVE_NONOPTIMIZED))) {
   1666 				VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_set_tpg_"
   1667 				    "access_state: TPGAccessState NOT Set: "
   1668 				    "des_state=%x, cur_state=%x", desired_state,
   1669 				    mptpgd->prop.accessState));
   1670 				return (EIO);
   1671 			}
   1672 
   1673 		}
   1674 	}
   1675 
   1676 	return (rval);
   1677 }
   1678 
   1679 /* ARGSUSED */
   1680 static int
   1681 vhci_get_prop_lb_list(struct scsi_vhci *vhci, mp_iocdata_t *mpioc,
   1682     void *input_data, void *output_data, int mode)
   1683 {
   1684 	int		rval = 0;
   1685 	uint64_t	*oid_list = (uint64_t *)(output_data);
   1686 
   1687 	oid_list[0] = NULL;
   1688 
   1689 	if (ddi_copyout(output_data, (void *)mpioc->mp_obuf,
   1690 	    (sizeof (uint64_t)), mode) != 0) {
   1691 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_get_prop_lb_list: "
   1692 		    "ddi_copyout() FAILED"));
   1693 		mpioc->mp_errno = EFAULT;
   1694 		rval = EINVAL;
   1695 	} else {
   1696 		mpioc->mp_errno = 0;
   1697 	}
   1698 
   1699 	return (rval);
   1700 }
   1701 
   1702 /* ARGSUSED */
   1703 static int
   1704 vhci_get_prop_lb_prop(struct scsi_vhci *vhci, mp_iocdata_t *mpioc,
   1705     void *input_data, void *output_data, int mode)
   1706 {
   1707 	int rval = EINVAL;
   1708 
   1709 	return (rval);
   1710 }
   1711 
   1712 /*
   1713  * Operation not supported currently as we do not know
   1714  * support any devices that allow this in the first place.
   1715  */
   1716 /* ARGSUSED */
   1717 static int
   1718 vhci_assign_lu_to_tpg(struct scsi_vhci *vhci, mp_iocdata_t *mpioc,
   1719     void *input_data, void *output_data, int mode)
   1720 {
   1721 	int rval = ENOTSUP;
   1722 
   1723 	return (rval);
   1724 }
   1725 
   1726 /* ARGSUSED */
   1727 static int
   1728 vhci_enable_auto_failback(struct scsi_vhci *vhci, mp_iocdata_t *mpioc,
   1729     void *input_data, void *output_data, int mode)
   1730 {
   1731 	int			rval = 0;
   1732 	mpapi_item_list_t	*ilist;
   1733 	mpapi_lu_data_t		*lud;
   1734 
   1735 	mutex_enter(&vhci->vhci_mutex);
   1736 	vhci->vhci_conf_flags |= VHCI_CONF_FLAGS_AUTO_FAILBACK;
   1737 	mutex_exit(&vhci->vhci_mutex);
   1738 
   1739 	/* Enable auto-failback for each lun in MPAPI database */
   1740 	ilist = vhci->mp_priv->obj_hdr_list[MP_OBJECT_TYPE_MULTIPATH_LU]->head;
   1741 	while (ilist != NULL) {
   1742 		lud = ilist->item->idata;
   1743 		lud->prop.autoFailbackEnabled = 1;
   1744 		ilist = ilist->next;
   1745 	}
   1746 
   1747 	return (rval);
   1748 }
   1749 
   1750 /* ARGSUSED */
   1751 static int
   1752 vhci_disable_auto_failback(struct scsi_vhci *vhci, mp_iocdata_t *mpioc,
   1753     void *input_data, void *output_data, int mode)
   1754 {
   1755 	int			rval = 0;
   1756 	mpapi_item_list_t	*ilist;
   1757 	mpapi_lu_data_t		*lud;
   1758 
   1759 	mutex_enter(&vhci->vhci_mutex);
   1760 	vhci->vhci_conf_flags &= ~VHCI_CONF_FLAGS_AUTO_FAILBACK;
   1761 	mutex_exit(&vhci->vhci_mutex);
   1762 
   1763 	/* Disable auto-failback for each lun in MPAPI database */
   1764 	ilist = vhci->mp_priv->obj_hdr_list[MP_OBJECT_TYPE_MULTIPATH_LU]->head;
   1765 	while (ilist != NULL) {
   1766 		lud = ilist->item->idata;
   1767 		lud->prop.autoFailbackEnabled = 0;
   1768 		ilist = ilist->next;
   1769 	}
   1770 
   1771 	return (rval);
   1772 }
   1773 
   1774 /*
   1775  * Find the oid in the object type list. If found lock and return
   1776  * the item. If not found return NULL. The caller must unlock the item.
   1777  */
   1778 void *
   1779 vhci_mpapi_hold_item(struct scsi_vhci *vhci, uint64_t *oid, uint8_t obj_type)
   1780 {
   1781 	mpapi_item_list_t	*ilist;
   1782 
   1783 	ilist = vhci->mp_priv->obj_hdr_list[obj_type]->head;
   1784 	while ((ilist != NULL) && (*oid != ilist->item->oid.raw_oid))
   1785 		ilist = ilist->next;
   1786 
   1787 	if (ilist == NULL) {
   1788 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_mpapi_hold_item: "
   1789 		    "OID NOT FOUND. oid: %p", (void *)oid));
   1790 		return (NULL);
   1791 	}
   1792 	if (*oid == ilist->item->oid.raw_oid) {
   1793 		mutex_enter(&ilist->item->item_mutex);
   1794 		return (ilist);
   1795 	}
   1796 	VHCI_DEBUG(4, (CE_WARN, NULL, "vhci_mpapi_hold_item: "
   1797 	    "Unknown Error. oid: %p", (void *)oid));
   1798 	return (NULL);
   1799 }
   1800 
   1801 /*
   1802  * Check that the pip sent in by the user is still associated with
   1803  * the same oid. This is done through checking the path name.
   1804  */
   1805 mdi_pathinfo_t *
   1806 vhci_mpapi_chk_path(struct scsi_vhci *vhci, mpapi_item_list_t *ilist)
   1807 {
   1808 	mdi_pathinfo_t		*pip;
   1809 	mpapi_path_data_t	*mpp;
   1810 
   1811 	mpp = (mpapi_path_data_t *)(ilist->item->idata);
   1812 	if (mpp == NULL || mpp->valid == 0) {
   1813 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_mpapi_chk_path: "
   1814 		    "pathinfo is not valid: %p", (void *)mpp));
   1815 		return (NULL);
   1816 	}
   1817 	pip = mpp->resp;
   1818 	/* make sure it is the same pip by checking path */
   1819 	if (vhci_mpapi_match_pip(vhci, ilist, pip) == NULL) {
   1820 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_mpapi_chk_path: "
   1821 		    "Can not match pip: %p", (void *)pip));
   1822 		return (NULL);
   1823 	}
   1824 	return (pip);
   1825 }
   1826 
   1827 /*
   1828  * Get the pip from the oid passed in. the vhci_mpapi_chk_path
   1829  * will check the name with the passed in pip name.  the mdi_select_path()
   1830  * path will lock the pip and this should get released by the caller
   1831  */
   1832 mdi_pathinfo_t *
   1833 vhci_mpapi_hold_pip(struct scsi_vhci *vhci, mpapi_item_list_t *ilist, int flags)
   1834 {
   1835 	mdi_pathinfo_t		*pip, *opip, *npip;
   1836 	scsi_vhci_lun_t		*svl;
   1837 	int			rval;
   1838 	mpapi_path_data_t	*mpp;
   1839 
   1840 	mpp = (mpapi_path_data_t *)(ilist->item->idata);
   1841 	pip = mpp->resp;
   1842 	/* make sure it is the same pip by checking path */
   1843 	if (vhci_mpapi_chk_path(vhci, ilist) == NULL) {
   1844 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_mpapi_hold_pip: "
   1845 		    "Can not match pip: %p", (void *)pip));
   1846 		return (NULL);
   1847 	}
   1848 
   1849 	svl = mdi_client_get_vhci_private(mdi_pi_get_client(pip));
   1850 	opip = npip = NULL;
   1851 
   1852 	/*
   1853 	 * use the select path to find the right pip since
   1854 	 * it does all the state checking and locks the pip
   1855 	 */
   1856 	rval = mdi_select_path(svl->svl_dip, NULL,
   1857 	    flags, NULL, &npip);
   1858 	do {
   1859 		if ((rval != MDI_SUCCESS) || (npip == NULL)) {
   1860 			VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_mpapi_hold_pip:"
   1861 			    " Unable to find path: %x.", rval));
   1862 			return (NULL);
   1863 		}
   1864 		if (npip == pip) {
   1865 			break;
   1866 		}
   1867 		opip = npip;
   1868 		rval = mdi_select_path(svl->svl_dip, NULL,
   1869 		    flags, opip, &npip);
   1870 		mdi_rele_path(opip);
   1871 	} while ((npip != NULL) && (rval == MDI_SUCCESS));
   1872 	return (npip);
   1873 }
   1874 
   1875 /*
   1876  * Initialize the uscsi command. Lock the pip and the item in
   1877  * the item list.
   1878  */
   1879 static mp_uscsi_cmd_t *
   1880 vhci_init_uscsi_cmd(struct scsi_vhci *vhci,
   1881 	mp_iocdata_t *mpioc, uint64_t *oid, mpapi_item_list_t **list)
   1882 {
   1883 	int			arq_enabled;
   1884 	mp_uscsi_cmd_t		*mp_uscmdp;
   1885 	scsi_vhci_priv_t	*svp;
   1886 	struct scsi_address	*ap;
   1887 	mdi_pathinfo_t		*pip;
   1888 	mpapi_item_list_t	*ilist;
   1889 	struct buf		*bp;
   1890 
   1891 	VHCI_DEBUG(4, (CE_WARN, NULL,
   1892 	    "vhci_init_uscsi_cmd: enter"));
   1893 
   1894 	*list = NULL;
   1895 	/* lock the item */
   1896 	if ((ilist = (mpapi_item_list_t *)vhci_mpapi_hold_item(
   1897 	    vhci, oid, MP_OBJECT_TYPE_PATH_LU)) == NULL) {
   1898 		VHCI_DEBUG(1, (CE_WARN, NULL,
   1899 		    "vhci_init_uscsi_cmd: exit EINVAL"));
   1900 		mpioc->mp_errno = MP_DRVR_INVALID_ID;
   1901 		return (NULL);
   1902 	}
   1903 
   1904 	/* lock the pip */
   1905 	if ((pip = vhci_mpapi_hold_pip(vhci, ilist,
   1906 	    (MDI_SELECT_STANDBY_PATH|MDI_SELECT_ONLINE_PATH))) == 0) {
   1907 		VHCI_DEBUG(1, (CE_WARN, NULL,
   1908 		    "vhci_init_uscsi_cmd: exit PATH_UNAVAIL"));
   1909 		mpioc->mp_errno = MP_DRVR_PATH_UNAVAILABLE;
   1910 		mutex_exit(&ilist->item->item_mutex);
   1911 		return (NULL);
   1912 	};
   1913 
   1914 	/* get the address of the pip */
   1915 	svp = (scsi_vhci_priv_t *)mdi_pi_get_vhci_private(pip);
   1916 	if (svp == NULL) {
   1917 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_init_uscsi_cmd:"
   1918 		    " Unable to find vhci private data"));
   1919 		mpioc->mp_errno = MP_DRVR_PATH_UNAVAILABLE;
   1920 		mdi_rele_path(pip);
   1921 		mutex_exit(&ilist->item->item_mutex);
   1922 		return (NULL);
   1923 	}
   1924 	if (svp->svp_psd == NULL) {
   1925 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_init_uscsi_cmd:"
   1926 		    " Unable to find scsi device"));
   1927 		mpioc->mp_errno = MP_DRVR_PATH_UNAVAILABLE;
   1928 		mdi_rele_path(pip);
   1929 		mutex_exit(&ilist->item->item_mutex);
   1930 		return (NULL);
   1931 	}
   1932 	ap = &svp->svp_psd->sd_address;
   1933 	ASSERT(ap != NULL);
   1934 
   1935 	/* initialize the buffer */
   1936 	bp = getrbuf(KM_SLEEP);
   1937 	ASSERT(bp != NULL);
   1938 
   1939 	/* initialize the mp_uscsi_cmd */
   1940 	mp_uscmdp = kmem_zalloc((size_t)sizeof (mp_uscsi_cmd_t), KM_SLEEP);
   1941 	ASSERT(mp_uscmdp != NULL);
   1942 	mp_uscmdp->ap = ap;
   1943 	mp_uscmdp->pip = pip;
   1944 	mp_uscmdp->cmdbp = bp;
   1945 	mp_uscmdp->rqbp = NULL;
   1946 
   1947 	bp->b_private = mp_uscmdp;
   1948 
   1949 	/* used to debug a manual sense */
   1950 	if (vhci_force_manual_sense) {
   1951 		(void) scsi_ifsetcap(ap, "auto-rqsense", 0, 0);
   1952 	} else {
   1953 		if (scsi_ifgetcap(ap, "auto-rqsense", 1) != 1) {
   1954 			(void) scsi_ifsetcap(ap, "auto-rqsense", 1, 1);
   1955 		}
   1956 	}
   1957 	arq_enabled = scsi_ifgetcap(ap, "auto-rqsense", 1);
   1958 	if (arq_enabled == 1) {
   1959 		mp_uscmdp->arq_enabled = 1;
   1960 	} else {
   1961 		mp_uscmdp->arq_enabled = 0;
   1962 	}
   1963 	/* set the list pointer for the caller */
   1964 	*list = ilist;
   1965 	VHCI_DEBUG(4, (CE_WARN, NULL,
   1966 	    "vhci_init_uscsi_cmd: mp_uscmdp: %p ilist: %p mp_errno: %d "
   1967 	    "bp: %p arq: %d",
   1968 	    (void *)mp_uscmdp, (void *)*list, mpioc->mp_errno,
   1969 	    (void *)bp, arq_enabled));
   1970 
   1971 	return (mp_uscmdp);
   1972 }
   1973 
   1974 
   1975 /*
   1976  * Initialize the uscsi information and then issue the command.
   1977  */
   1978 /* ARGSUSED */
   1979 static int
   1980 vhci_send_uscsi_cmd(dev_t dev, struct scsi_vhci *vhci, mp_iocdata_t *mpioc,
   1981     void *input_data, void *output_data, int mode)
   1982 {
   1983 	int			rval = 0, uioseg = 0;
   1984 	struct uscsi_cmd	*uscmdp;
   1985 	uint64_t		*oid = (uint64_t *)(input_data);
   1986 	mp_uscsi_cmd_t		*mp_uscmdp;
   1987 	mpapi_item_list_t	*ilist;
   1988 
   1989 	VHCI_DEBUG(4, (CE_WARN, NULL,
   1990 	    "vhci_send_uscsi_cmd: enter: mode: %x", mode));
   1991 	mpioc->mp_errno = 0;
   1992 	mp_uscmdp = vhci_init_uscsi_cmd(vhci, mpioc, oid, &ilist);
   1993 	if (mp_uscmdp == NULL) {
   1994 		VHCI_DEBUG(1, (CE_WARN, NULL,
   1995 		    "vhci_send_uscsi_cmd: exit INVALID_ID. rval: %d", rval));
   1996 		return (EINVAL);
   1997 	}
   1998 	rval = scsi_uscsi_alloc_and_copyin((intptr_t)mpioc->mp_obuf,
   1999 	    mode, mp_uscmdp->ap, &uscmdp);
   2000 	if (rval != 0) {
   2001 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_send_uscsi_cmd: "
   2002 		    "scsi_uscsi_alloc_and_copyin failed. rval: %d", rval));
   2003 		mpioc->mp_errno = EINVAL;
   2004 		mdi_rele_path(mp_uscmdp->pip);
   2005 		mutex_exit(&ilist->item->item_mutex);
   2006 		if (mp_uscmdp->cmdbp)
   2007 			freerbuf(mp_uscmdp->cmdbp);
   2008 		kmem_free(mp_uscmdp, sizeof (mp_uscsi_cmd_t));
   2009 		return (EINVAL);
   2010 	}
   2011 	/* initialize the mp_uscsi_cmd with the uscsi_cmd from uscsi_alloc */
   2012 	mp_uscmdp->uscmdp = uscmdp;
   2013 
   2014 	uioseg = (mode & FKIOCTL) ? UIO_SYSSPACE : UIO_USERSPACE;
   2015 
   2016 	/* start the command sending the buffer as an argument */
   2017 	rval = scsi_uscsi_handle_cmd(dev, uioseg,
   2018 	    uscmdp, vhci_uscsi_iostart, mp_uscmdp->cmdbp, mp_uscmdp);
   2019 	if (rval != 0) {
   2020 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_send_uscsi_cmd: "
   2021 		    "scsi_uscsi_handle_cmd failed. rval: %d", rval));
   2022 		mpioc->mp_errno = EIO;
   2023 	}
   2024 
   2025 	if (scsi_uscsi_copyout_and_free((intptr_t)mpioc->mp_obuf,
   2026 	    uscmdp) != 0 && rval == 0) {
   2027 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_send_uscsi_cmd: "
   2028 		    "scsi_uscsi_copyout_and_free failed. rval: %d", rval));
   2029 		mpioc->mp_errno = EFAULT;
   2030 		rval = EFAULT;
   2031 	}
   2032 	/* cleanup */
   2033 	mdi_rele_path(mp_uscmdp->pip);
   2034 	mutex_exit(&ilist->item->item_mutex);
   2035 	if (mp_uscmdp->cmdbp)
   2036 		freerbuf(mp_uscmdp->cmdbp);
   2037 	kmem_free(mp_uscmdp, sizeof (mp_uscsi_cmd_t));
   2038 	VHCI_DEBUG(4, (CE_WARN, NULL,
   2039 	    "vhci_send_uscsi_cmd: rval: %d mp_errno: %d",
   2040 	    rval, mpioc->mp_errno));
   2041 
   2042 	return (rval);
   2043 }
   2044 
   2045 /* ARGSUSED */
   2046 static int
   2047 vhci_enable_path(struct scsi_vhci *vhci, mp_iocdata_t *mpioc,
   2048     void *input_data, void *output_data, int mode)
   2049 {
   2050 	int			rval = 0;
   2051 	uint64_t		*oid = (uint64_t *)(input_data);
   2052 	mdi_pathinfo_t		*pip;
   2053 	mpapi_item_list_t	*ilist;
   2054 	mpapi_path_data_t	*mpp;
   2055 
   2056 	if ((ilist = (mpapi_item_list_t *)vhci_mpapi_hold_item(vhci, oid,
   2057 	    MP_OBJECT_TYPE_PATH_LU)) == NULL) {
   2058 		mpioc->mp_errno = MP_DRVR_INVALID_ID;
   2059 		return (EINVAL);
   2060 	}
   2061 
   2062 	mpp = (mpapi_path_data_t *)(ilist->item->idata);
   2063 	pip = (mdi_pathinfo_t *)mpp->resp;
   2064 
   2065 	if (vhci_mpapi_chk_path(vhci, ilist) == NULL) {
   2066 		mutex_exit(&ilist->item->item_mutex);
   2067 		mpioc->mp_errno = MP_DRVR_INVALID_ID;
   2068 		return (EINVAL);
   2069 	}
   2070 
   2071 	if (mdi_pi_enable_path(pip, USER_DISABLE) != 0) {
   2072 		rval = EFAULT;
   2073 	} else {
   2074 		mpp->prop.disabled = 0;
   2075 		vhci_mpapi_log_sysevent(vhci->vhci_dip,
   2076 		    &(((mpoid_t *)oid)->raw_oid), ESC_SUN_MP_PATH_CHANGE);
   2077 	}
   2078 	mutex_exit(&ilist->item->item_mutex);
   2079 	return (rval);
   2080 }
   2081 
   2082 /* ARGSUSED */
   2083 static int
   2084 vhci_disable_path(struct scsi_vhci *vhci, mp_iocdata_t *mpioc,
   2085     void *input_data, void *output_data, int mode)
   2086 {
   2087 	int			rval = 0;
   2088 	uint64_t		*oid = (uint64_t *)(input_data);
   2089 	mdi_pathinfo_t		*pip = NULL;
   2090 	mpapi_item_list_t	*ilist;
   2091 	mpapi_path_data_t	*mpp;
   2092 
   2093 	if ((ilist = (mpapi_item_list_t *)vhci_mpapi_hold_item(vhci, oid,
   2094 	    MP_OBJECT_TYPE_PATH_LU)) == NULL) {
   2095 		mpioc->mp_errno = MP_DRVR_INVALID_ID;
   2096 		return (EINVAL);
   2097 	}
   2098 
   2099 	mpp = (mpapi_path_data_t *)(ilist->item->idata);
   2100 	pip = (mdi_pathinfo_t *)mpp->resp;
   2101 
   2102 	if (vhci_mpapi_chk_path(vhci, ilist) == NULL) {
   2103 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_disable_path: Request "
   2104 		    "received to disable last path. Cant disable, Sorry!"));
   2105 		mutex_exit(&ilist->item->item_mutex);
   2106 		return (EINVAL);
   2107 	}
   2108 	if (vhci_mpapi_chk_last_path(pip) != 0) {
   2109 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_disable_path(1): Request "
   2110 		    "received to disable last path. Cant disable, Sorry!"));
   2111 		mutex_exit(&ilist->item->item_mutex);
   2112 		return (EINVAL);
   2113 	}
   2114 
   2115 	if (mdi_pi_disable_path(pip, USER_DISABLE) != 0) {
   2116 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_disable_path(2): Request "
   2117 		    "received to disable last path. Cant disable, Sorry!"));
   2118 		rval = EFAULT;
   2119 	} else {
   2120 		mpp->prop.disabled = 1;
   2121 		vhci_mpapi_log_sysevent(vhci->vhci_dip,
   2122 		    &(((mpoid_t *)oid)->raw_oid), ESC_SUN_MP_PATH_CHANGE);
   2123 	}
   2124 	mutex_exit(&ilist->item->item_mutex);
   2125 
   2126 	return (rval);
   2127 }
   2128 
   2129 /* ARGSUSED */
   2130 static int
   2131 vhci_mpapi_ioctl(dev_t dev, struct scsi_vhci *vhci, void *udata,
   2132 	mp_iocdata_t *mpioc, int mode, cred_t *credp)
   2133 {
   2134 	int		rval = 0;
   2135 	uint64_t	oid;
   2136 	void		*input_data = NULL, *output_data = NULL;
   2137 
   2138 	/* validate mpioc */
   2139 	rval = vhci_mpapi_validate(udata, mpioc, mode, credp);
   2140 
   2141 	if (rval == EINVAL) {
   2142 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_mpapi_ioctl: "
   2143 		    " vhci_mpapi_validate() Returned %x: INVALID DATA", rval));
   2144 		if (vhci_mpapi_copyout_iocdata(mpioc, udata, mode)) {
   2145 			VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_mpapi_ioctl: "
   2146 			    "vhci_mpapi_copyout_iocdata FAILED in EINVAL"));
   2147 		}
   2148 		return (rval);
   2149 	} else if (rval == EPERM) {
   2150 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_mpapi_ioctl: "
   2151 		    " vhci_mpapi_validate() Returned %x: NO CREDS", rval));
   2152 		if (vhci_mpapi_copyout_iocdata(mpioc, udata, mode)) {
   2153 			VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_mpapi_ioctl: "
   2154 			    "vhci_mpapi_copyout_iocdata FAILED in EPERM"));
   2155 		}
   2156 		return (rval);
   2157 	/* Process good cases & also cases where we need to get correct alen */
   2158 	} else if ((rval == 0) || (rval == MP_MORE_DATA)) {
   2159 		/* allocate an input buffer */
   2160 		if ((mpioc->mp_ibuf) && (mpioc->mp_ilen != 0)) {
   2161 			input_data = kmem_zalloc(mpioc->mp_ilen,
   2162 			    KM_SLEEP);
   2163 			ASSERT(input_data != NULL);
   2164 			rval = ddi_copyin(mpioc->mp_ibuf,
   2165 			    input_data, mpioc->mp_ilen, mode);
   2166 			oid = (uint64_t)(*((uint64_t *)input_data));
   2167 
   2168 			VHCI_DEBUG(7, (CE_NOTE, NULL, "Requesting op for "
   2169 			    "OID = %lx w/ mpioc = %p mp_cmd = %x\n",
   2170 			    (long)oid, (void *)mpioc, mpioc->mp_cmd));
   2171 
   2172 		}
   2173 		if ((mpioc->mp_xfer == MP_XFER_READ) && (mpioc->mp_olen != 0)) {
   2174 			output_data = kmem_zalloc(mpioc->mp_olen, KM_SLEEP);
   2175 			ASSERT(output_data != NULL);
   2176 		}
   2177 	}
   2178 
   2179 	if (vhci_mpapi_sync_lu_oid_list(vhci) != 0) {
   2180 		VHCI_DEBUG(1, (CE_WARN, NULL, "!vhci_mpapi_ioctl: "
   2181 		    "vhci_mpapi_sync_lu_oid_list() failed"));
   2182 	}
   2183 	mdi_vhci_walk_phcis(vhci->vhci_dip,
   2184 	    vhci_mpapi_sync_init_port_list, vhci);
   2185 
   2186 	/* process ioctls */
   2187 	switch (mpioc->mp_cmd) {
   2188 	case MP_GET_DRIVER_PROP:
   2189 		rval = vhci_get_driver_prop(vhci, mpioc,
   2190 		    input_data, output_data, mode);
   2191 		break;
   2192 	case MP_GET_DEV_PROD_LIST:
   2193 		rval = vhci_get_dev_prod_list(vhci, mpioc,
   2194 		    input_data, output_data, mode);
   2195 		break;
   2196 	case MP_GET_DEV_PROD_PROP:
   2197 		rval = vhci_get_dev_prod_prop(vhci, mpioc,
   2198 		    input_data, output_data, mode);
   2199 		break;
   2200 	case MP_GET_LU_LIST:
   2201 		rval = vhci_get_lu_list(vhci, mpioc,
   2202 		    input_data, output_data, mode);
   2203 		break;
   2204 	case MP_GET_LU_LIST_FROM_TPG:
   2205 		rval = vhci_get_lu_list_from_tpg(vhci, mpioc,
   2206 		    input_data, output_data, mode);
   2207 		break;
   2208 	case MP_GET_TPG_LIST_FOR_LU:
   2209 		rval = vhci_get_tpg_list_for_lu(vhci, mpioc,
   2210 		    input_data, output_data, mode);
   2211 		break;
   2212 	case MP_GET_LU_PROP:
   2213 		rval = vhci_get_lu_prop(vhci, mpioc,
   2214 		    input_data, output_data, mode);
   2215 		break;
   2216 	case MP_GET_PATH_LIST_FOR_MP_LU:
   2217 		rval = vhci_get_path_list_for_mp_lu(vhci, mpioc,
   2218 		    input_data, output_data, mode);
   2219 		break;
   2220 	case MP_GET_PATH_LIST_FOR_INIT_PORT:
   2221 		rval = vhci_get_path_list_for_init_port(vhci, mpioc,
   2222 		    input_data, output_data, mode);
   2223 		break;
   2224 	case MP_GET_PATH_LIST_FOR_TARGET_PORT:
   2225 		rval = vhci_get_path_list_for_target_port(vhci, mpioc,
   2226 		    input_data, output_data, mode);
   2227 		break;
   2228 	case MP_GET_PATH_PROP:
   2229 		rval = vhci_get_path_prop(vhci, mpioc,
   2230 		    input_data, output_data, mode);
   2231 		break;
   2232 	case MP_GET_INIT_PORT_LIST: /* Not Required */
   2233 		rval = vhci_get_init_port_list(vhci, mpioc,
   2234 		    input_data, output_data, mode);
   2235 		break;
   2236 	case MP_GET_INIT_PORT_PROP:
   2237 		rval = vhci_get_init_port_prop(vhci, mpioc,
   2238 		    input_data, output_data, mode);
   2239 		break;
   2240 	case MP_GET_TARGET_PORT_PROP:
   2241 		rval = vhci_get_target_port_prop(vhci, mpioc,
   2242 		    input_data, output_data, mode);
   2243 		break;
   2244 	case MP_GET_TPG_LIST: /* Not Required */
   2245 		rval = vhci_get_tpg_list_for_lu(vhci, mpioc,
   2246 		    input_data, output_data, mode);
   2247 		break;
   2248 	case MP_GET_TPG_PROP:
   2249 		rval = vhci_get_tpg_prop(vhci, mpioc,
   2250 		    input_data, output_data, mode);
   2251 		break;
   2252 	case MP_GET_TARGET_PORT_LIST_FOR_TPG:
   2253 		rval = vhci_get_target_port_list_for_tpg(vhci, mpioc,
   2254 		    input_data, output_data, mode);
   2255 		break;
   2256 	case MP_SET_TPG_ACCESS_STATE:
   2257 		rval = vhci_set_tpg_access_state(vhci, mpioc,
   2258 		    input_data, output_data, mode);
   2259 		break;
   2260 	case MP_ASSIGN_LU_TO_TPG:
   2261 		rval = vhci_assign_lu_to_tpg(vhci, mpioc,
   2262 		    input_data, output_data, mode);
   2263 		break;
   2264 	case MP_GET_PROPRIETARY_LOADBALANCE_LIST:
   2265 		rval = vhci_get_prop_lb_list(vhci, mpioc,
   2266 		    input_data, output_data, mode);
   2267 		break;
   2268 	case MP_GET_PROPRIETARY_LOADBALANCE_PROP:
   2269 		rval = vhci_get_prop_lb_prop(vhci, mpioc,
   2270 		    input_data, output_data, mode);
   2271 		break;
   2272 	case MP_ENABLE_AUTO_FAILBACK:
   2273 		rval = vhci_enable_auto_failback(vhci, mpioc,
   2274 		    input_data, output_data, mode);
   2275 		break;
   2276 	case MP_DISABLE_AUTO_FAILBACK:
   2277 		rval = vhci_disable_auto_failback(vhci, mpioc,
   2278 		    input_data, output_data, mode);
   2279 		break;
   2280 	case MP_ENABLE_PATH:
   2281 		rval = vhci_enable_path(vhci, mpioc,
   2282 		    input_data, output_data, mode);
   2283 		break;
   2284 	case MP_DISABLE_PATH:
   2285 		rval = vhci_disable_path(vhci, mpioc,
   2286 		    input_data, output_data, mode);
   2287 		break;
   2288 	case MP_SEND_SCSI_CMD:
   2289 		rval = vhci_send_uscsi_cmd(dev, vhci, mpioc,
   2290 		    input_data, output_data, mode);
   2291 		break;
   2292 	default:
   2293 		rval = EINVAL;
   2294 		break;
   2295 	}
   2296 
   2297 	VHCI_DEBUG(6, (CE_NOTE, NULL, "vhci_mpapi_ioctl: output_data = %p, "
   2298 	    "mp_obuf = %p, mp_olen = %lx, mp_alen = %lx, mp_errno = %x, "
   2299 	    "mode = %x, rval=%x\n", (void *)output_data, (void *)mpioc->mp_obuf,
   2300 	    mpioc->mp_olen, mpioc->mp_alen, mpioc->mp_errno, mode, rval));
   2301 
   2302 	if (vhci_mpapi_copyout_iocdata(mpioc, udata, mode)) {
   2303 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_mpapi_ioctl: "
   2304 		    "vhci_mpapi_copyout_iocdata FAILED"));
   2305 		rval = EFAULT;
   2306 	}
   2307 
   2308 	if (input_data) {
   2309 		kmem_free(input_data, mpioc->mp_ilen);
   2310 	}
   2311 
   2312 	if (output_data) {
   2313 		kmem_free(output_data, mpioc->mp_olen);
   2314 	}
   2315 
   2316 	return (rval);
   2317 }
   2318 
   2319 /* ARGSUSED */
   2320 int
   2321 vhci_mpapi_init(struct scsi_vhci *vhci)
   2322 {
   2323 	mpapi_item_list_t	*ilist;
   2324 	mpapi_item_t		*item;
   2325 	mp_driver_prop_t	*drv;
   2326 	uint8_t			i;
   2327 
   2328 	/*
   2329 	 * This tstamp value is present in the upper 32-bits of all OIDs
   2330 	 * that are issued in this boot session. Use it to identify
   2331 	 * stale OIDs that an application/ioctl may pass to you and
   2332 	 * reject it - Done in vhci_mpapi_validate() routine.
   2333 	 */
   2334 	mutex_enter(&tod_lock);
   2335 	vhci->mp_priv->tstamp = (time32_t)(tod_get().tv_sec);
   2336 	mutex_exit(&tod_lock);
   2337 
   2338 	for (i = 0; i < MP_MAX_OBJECT_TYPE; i++) {
   2339 		vhci->mp_priv->obj_hdr_list[i] = vhci_mpapi_create_list_head();
   2340 	}
   2341 
   2342 	/*
   2343 	 * Let us now allocate and initialize the drv block.
   2344 	 */
   2345 	ilist = kmem_zalloc(sizeof (mpapi_item_list_t), KM_SLEEP);
   2346 	item = kmem_zalloc(sizeof (mpapi_item_t), KM_SLEEP);
   2347 	ilist->item = item;
   2348 	item->oid.raw_oid = vhci_mpapi_create_oid(vhci->mp_priv,
   2349 	    MP_OBJECT_TYPE_PLUGIN);
   2350 	drv = kmem_zalloc(sizeof (mp_driver_prop_t), KM_SLEEP);
   2351 	drv->driverVersion[0] = '\0';
   2352 	drv->supportedLoadBalanceTypes =
   2353 	    (MP_DRVR_LOAD_BALANCE_TYPE_ROUNDROBIN |
   2354 	    MP_DRVR_LOAD_BALANCE_TYPE_LBA_REGION);
   2355 	drv->canSetTPGAccess = TRUE;
   2356 	drv->canOverridePaths = FALSE;
   2357 	drv->exposesPathDeviceFiles = FALSE;
   2358 	drv->deviceFileNamespace[0] = '\0';
   2359 	drv->onlySupportsSpecifiedProducts = 1;
   2360 	drv->maximumWeight = 1;
   2361 	drv->failbackPollingRateMax = 0;
   2362 	drv->currentFailbackPollingRate = 0;
   2363 	drv->autoFailbackSupport = 1;
   2364 	drv->autoFailbackEnabled = 1;
   2365 	drv->defaultLoadBalanceType = MP_DRVR_LOAD_BALANCE_TYPE_ROUNDROBIN;
   2366 	drv->probingPollingRateMax = 0;
   2367 	drv->currentProbingPollingRate = 0;
   2368 	drv->autoProbingSupport = 0;
   2369 	drv->autoProbingEnabled = 0;
   2370 	item->idata = drv;
   2371 	mutex_init(&item->item_mutex, NULL, MUTEX_DRIVER, NULL);
   2372 	if (vhci_mpapi_add_to_list(vhci->mp_priv->obj_hdr_list
   2373 	    [MP_OBJECT_TYPE_PLUGIN], ilist) != 0) {
   2374 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_mpapi_init: "
   2375 		    "vhci_mpapi_create_add_to_list() of PLUGIN failed"));
   2376 		return (EFAULT);
   2377 
   2378 	}
   2379 	return (0);
   2380 }
   2381 
   2382 void
   2383 vhci_mpapi_add_dev_prod(struct scsi_vhci *vhci, char *vidpid)
   2384 {
   2385 	mpapi_item_list_t	*dev_prod_list;
   2386 	mpapi_item_t		*dev_prod_item;
   2387 	mp_dev_prod_prop_t	*dev_prod;
   2388 
   2389 	/* add to list */
   2390 	dev_prod_list = kmem_zalloc(sizeof (mpapi_item_list_t), KM_SLEEP);
   2391 	dev_prod_item = kmem_zalloc(sizeof (mpapi_item_t), KM_SLEEP);
   2392 	dev_prod_list->item = dev_prod_item;
   2393 	dev_prod_list->item->oid.raw_oid = vhci_mpapi_create_oid
   2394 	    (vhci->mp_priv, MP_OBJECT_TYPE_DEVICE_PRODUCT);
   2395 	dev_prod = kmem_zalloc(sizeof (mp_dev_prod_prop_t), KM_SLEEP);
   2396 
   2397 	(void) strncpy(dev_prod->prodInfo.vendor, vidpid, strlen(vidpid));
   2398 	dev_prod->supportedLoadBalanceTypes =
   2399 	    MP_DRVR_LOAD_BALANCE_TYPE_ROUNDROBIN;
   2400 	dev_prod->id = dev_prod_list->item->oid.raw_oid;
   2401 
   2402 	dev_prod_list->item->idata = dev_prod;
   2403 	(void) vhci_mpapi_add_to_list(vhci->mp_priv->obj_hdr_list
   2404 	    [MP_OBJECT_TYPE_DEVICE_PRODUCT], (void *)dev_prod_list);
   2405 	vhci_mpapi_log_sysevent(vhci->vhci_dip,
   2406 	    &(dev_prod_list->item->oid.raw_oid),
   2407 	    ESC_SUN_MP_DEV_PROD_ADD);
   2408 }
   2409 
   2410 /* ARGSUSED */
   2411 static uint64_t
   2412 vhci_mpapi_create_oid(mpapi_priv_t *mp_priv, uint8_t obj_type)
   2413 {
   2414 	mpoid_t		oid;
   2415 
   2416 	oid.disc_oid.tstamp = mp_priv->tstamp;
   2417 	oid.disc_oid.type = obj_type;
   2418 	oid.disc_oid.seq_id = ++(mp_priv->oid_seq[obj_type]);
   2419 	return (oid.raw_oid);
   2420 }
   2421 
   2422 /* ARGSUSED */
   2423 static int
   2424 vhci_mpapi_add_to_list(mpapi_list_header_t *hdr, mpapi_item_list_t *item)
   2425 {
   2426 
   2427 	mpapi_list_header_t	*tmp_hdr = hdr;
   2428 	mpapi_item_list_t	*tmp_item = item;
   2429 
   2430 	if (item == NULL) {
   2431 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_mpapi_add_to_list: "
   2432 		    "NULL item passed"));
   2433 		return (EFAULT);
   2434 	}
   2435 	if (hdr == NULL) {
   2436 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_mpapi_add_to_list: "
   2437 		    "NULL hdr passed"));
   2438 		return (EFAULT);
   2439 	}
   2440 	/*
   2441 	 * Check if the item is already there in the list.
   2442 	 * Catches duplicates while assigning TPGs.
   2443 	 */
   2444 	tmp_item = tmp_hdr->head;
   2445 	while (tmp_item != NULL) {
   2446 		if (item == tmp_item) {
   2447 			VHCI_DEBUG(4, (CE_WARN, NULL, "vhci_mpapi_add_to_list: "
   2448 			    "Item already in list"));
   2449 			return (1);
   2450 		} else {
   2451 			tmp_item = tmp_item->next;
   2452 		}
   2453 	}
   2454 
   2455 	item->next = NULL;
   2456 	if (hdr->head == NULL) {
   2457 		hdr->head = item;
   2458 		hdr->tail = item;
   2459 	} else {
   2460 		hdr->tail->next = item;
   2461 		hdr->tail = item;
   2462 	}
   2463 
   2464 	return (0);
   2465 }
   2466 
   2467 /*
   2468  * Local convenience routine to fetch reference to a mpapi item entry if it
   2469  * exits based on the pointer to the vhci resource that is passed.
   2470  * Returns NULL if no entry is found.
   2471  */
   2472 /* ARGSUSED */
   2473 void*
   2474 vhci_get_mpapi_item(struct scsi_vhci *vhci,  mpapi_list_header_t *list,
   2475     uint8_t obj_type, void* res)
   2476 {
   2477 	mpapi_item_list_t	*ilist;
   2478 
   2479 	if (list == NULL) {
   2480 		/*
   2481 		 * Since the listhead is null, the search is being
   2482 		 * performed in implicit mode - that is to use the
   2483 		 * level one list.
   2484 		 */
   2485 		ilist = vhci->mp_priv->obj_hdr_list[obj_type]->head;
   2486 	} else {
   2487 		/*
   2488 		 * The search is being performed on a sublist within
   2489 		 * one of the toplevel list items. Use the listhead
   2490 		 * that is passed in.
   2491 		 */
   2492 		ilist = list->head;
   2493 	}
   2494 
   2495 	if (res == NULL) {
   2496 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_get_mpapi_item: "
   2497 		    " Got Item w/ NULL resource ptr"));
   2498 		return (NULL);
   2499 	}
   2500 
   2501 	/*
   2502 	 * Since the resource field within the item data is specific
   2503 	 * to a particular object type, we need to use the object type
   2504 	 * to enable us to perform the search and compare appropriately.
   2505 	 */
   2506 	switch (obj_type) {
   2507 		case	MP_OBJECT_TYPE_INITIATOR_PORT:
   2508 			while (ilist) {
   2509 				void	*wwn = ((mpapi_initiator_data_t *)
   2510 				    ilist->item->idata)->resp;
   2511 				if (strncmp(wwn, res, strlen(res)) == 0) {
   2512 					/* Found a match */
   2513 					return ((void*)ilist);
   2514 				}
   2515 				ilist = ilist->next;
   2516 			}
   2517 		break;
   2518 
   2519 		case	MP_OBJECT_TYPE_TARGET_PORT:
   2520 			while (ilist) {
   2521 				void	*wwn = ((mpapi_tport_data_t *)ilist->
   2522 				    item->idata)->resp;
   2523 				if (strncmp(wwn, res, strlen(res)) == 0) {
   2524 					/* Found a match */
   2525 					return ((void*)ilist);
   2526 				}
   2527 				ilist = ilist->next;
   2528 			}
   2529 		break;
   2530 
   2531 		case	MP_OBJECT_TYPE_TARGET_PORT_GROUP:
   2532 			/*
   2533 			 * For TPG Synthesis, Use TPG specific routines
   2534 			 * Use this case only for ALUA devices which give TPG ID
   2535 			 */
   2536 			while (ilist) {
   2537 				void	*tpg_id = ((mpapi_tpg_data_t *)ilist->
   2538 				    item->idata)->resp;
   2539 				if (strncmp(tpg_id, res, strlen(res)) == 0) {
   2540 					/* Found a match */
   2541 					return ((void*)ilist);
   2542 				}
   2543 				ilist = ilist->next;
   2544 			}
   2545 		break;
   2546 
   2547 		case	MP_OBJECT_TYPE_MULTIPATH_LU:
   2548 			return ((void *)(vhci_mpapi_match_lu
   2549 			    (vhci, ilist, res)));
   2550 
   2551 		case	MP_OBJECT_TYPE_PATH_LU:
   2552 			return ((void *)(vhci_mpapi_match_pip
   2553 			    (vhci, ilist, res)));
   2554 
   2555 		default:
   2556 			/*
   2557 			 * This should not happen
   2558 			 */
   2559 			VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_get_mpapi_item:"
   2560 			    "Got Unsupported OBJECT TYPE"));
   2561 			return (NULL);
   2562 	}
   2563 	return (NULL);
   2564 }
   2565 
   2566 /*
   2567  * Local convenience routine to create and initialize mpapi item
   2568  * based on the object type passed.
   2569  */
   2570 /* ARGSUSED */
   2571 static mpapi_item_list_t *
   2572 vhci_mpapi_create_item(struct scsi_vhci *vhci, uint8_t obj_type, void* res)
   2573 {
   2574 	int			major;
   2575 	int			instance;
   2576 	mpapi_item_list_t	*ilist;
   2577 	mpapi_item_t		*item;
   2578 	char			*pname = NULL;
   2579 
   2580 	ilist = kmem_zalloc(sizeof (mpapi_item_list_t), KM_SLEEP);
   2581 	item = kmem_zalloc(sizeof (mpapi_item_t), KM_SLEEP);
   2582 	mutex_init(&item->item_mutex, NULL, MUTEX_DRIVER, NULL);
   2583 	ilist->item = item;
   2584 	item->oid.raw_oid = 0;
   2585 
   2586 	switch (obj_type) {
   2587 		case	MP_OBJECT_TYPE_INITIATOR_PORT:
   2588 		{
   2589 			mpapi_initiator_data_t	*init;
   2590 			dev_info_t		*pdip = res;
   2591 			char			*init_port_res;
   2592 			char			*interconnect;
   2593 			int			mp_interconnect_type, len;
   2594 			int			prop_not_ddi_alloced = 0;
   2595 
   2596 			pname = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
   2597 			major = (int)ddi_driver_major(pdip);
   2598 			instance = ddi_get_instance(pdip);
   2599 			(void) ddi_pathname(pdip, pname);
   2600 			item->oid.raw_oid =
   2601 			    MP_STORE_INST_TO_ID(instance, item->oid.raw_oid);
   2602 			item->oid.raw_oid =
   2603 			    MP_STORE_MAJOR_TO_ID(major, item->oid.raw_oid);
   2604 			/*
   2605 			 * Just make a call to keep correct Sequence count.
   2606 			 * Don't use the OID returned though.
   2607 			 */
   2608 			(void) vhci_mpapi_create_oid(vhci->mp_priv, obj_type);
   2609 			init_port_res = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
   2610 			(void) strlcpy(init_port_res, pname, MAXPATHLEN);
   2611 
   2612 			if ((ddi_prop_lookup_string(DDI_DEV_T_ANY, pdip, 0,
   2613 			    "initiator-interconnect-type",
   2614 			    &interconnect) != DDI_PROP_SUCCESS)) {
   2615 				/* XXX: initiator-interconnect-type not set */
   2616 				VHCI_DEBUG(1, (CE_WARN, NULL,
   2617 				    "vhci_mpapi_create_item: initiator-"
   2618 				    "-interconnect-type prop not found"));
   2619 				len = strlen("UNKNOWN")+1;
   2620 				interconnect = kmem_zalloc(len, KM_SLEEP);
   2621 				(void) strlcpy(interconnect, "UNKNOWN", len);
   2622 				prop_not_ddi_alloced = 1;
   2623 			}
   2624 			/*
   2625 			 * Map the initiator-interconnect-type values between
   2626 			 * SCSA(as defined in services.h) and MPAPI
   2627 			 * (as defined in mpapi_impl.h)
   2628 			 */
   2629 			if (strncmp(interconnect,
   2630 			    INTERCONNECT_FABRIC_STR,
   2631 			    strlen(interconnect)) == 0) {
   2632 				mp_interconnect_type =
   2633 				    MP_DRVR_TRANSPORT_TYPE_FC;
   2634 			} else if (strncmp(interconnect,
   2635 			    INTERCONNECT_PARALLEL_STR,
   2636 			    strlen(interconnect)) == 0) {
   2637 				mp_interconnect_type =
   2638 				    MP_DRVR_TRANSPORT_TYPE_SPI;
   2639 			} else if (strncmp(interconnect,
   2640 			    INTERCONNECT_ISCSI_STR,
   2641 			    strlen(interconnect)) == 0) {
   2642 				mp_interconnect_type =
   2643 				    MP_DRVR_TRANSPORT_TYPE_ISCSI;
   2644 			} else if (strncmp(interconnect,
   2645 			    INTERCONNECT_IBSRP_STR,
   2646 			    strlen(interconnect)) == 0) {
   2647 				mp_interconnect_type =
   2648 				    MP_DRVR_TRANSPORT_TYPE_IFB;
   2649 			} else {
   2650 				mp_interconnect_type =
   2651 				    MP_DRVR_TRANSPORT_TYPE_UNKNOWN;
   2652 			}
   2653 
   2654 			init = kmem_zalloc(
   2655 			    sizeof (mpapi_initiator_data_t), KM_SLEEP);
   2656 			init->resp = init_port_res;
   2657 			init->valid = 1;
   2658 			init->prop.id = item->oid.raw_oid;
   2659 			init->prop.portType = mp_interconnect_type;
   2660 			(void) strlcpy(init->prop.portID, pname,
   2661 			    sizeof (init->prop.portID));
   2662 			(void) strlcpy(init->prop.osDeviceFile, "/devices",
   2663 			    sizeof (init->prop.osDeviceFile));
   2664 			(void) strlcat(init->prop.osDeviceFile, pname,
   2665 			    sizeof (init->prop.osDeviceFile));
   2666 			init->path_list = vhci_mpapi_create_list_head();
   2667 			item->idata = (void *)init;
   2668 			vhci_mpapi_log_sysevent(vhci->vhci_dip,
   2669 			    &(item->oid.raw_oid), ESC_SUN_MP_INIT_PORT_CHANGE);
   2670 
   2671 			if (prop_not_ddi_alloced != 1) {
   2672 				ddi_prop_free(interconnect);
   2673 			} else {
   2674 				kmem_free(interconnect, len);
   2675 			}
   2676 			if (pname) {
   2677 				kmem_free(pname, MAXPATHLEN);
   2678 			}
   2679 		}
   2680 		break;
   2681 
   2682 		case	MP_OBJECT_TYPE_TARGET_PORT:
   2683 		{
   2684 			mpapi_tport_data_t	*tport;
   2685 			char			*tgt_port_res;
   2686 
   2687 			item->oid.raw_oid =
   2688 			    vhci_mpapi_create_oid(vhci->mp_priv, obj_type);
   2689 			tport = kmem_zalloc(sizeof (mpapi_tport_data_t),
   2690 			    KM_SLEEP);
   2691 			tgt_port_res = kmem_zalloc(strlen(res)+1, KM_SLEEP);
   2692 			(void) strlcpy(tgt_port_res, res, strlen(res)+1);
   2693 			tport->resp = tgt_port_res;
   2694 			tport->valid = 1;
   2695 			tport->prop.id = item->oid.raw_oid;
   2696 			tport->prop.relativePortID = 0;
   2697 			(void) strlcpy(tport->prop.portName, res,
   2698 			    sizeof (tport->prop.portName));
   2699 			tport->path_list = vhci_mpapi_create_list_head();
   2700 			item->idata = (void *)tport;
   2701 			vhci_mpapi_log_sysevent(vhci->vhci_dip,
   2702 			    &(item->oid.raw_oid), ESC_SUN_MP_TARGET_PORT_ADD);
   2703 		}
   2704 		break;
   2705 
   2706 		case	MP_OBJECT_TYPE_TARGET_PORT_GROUP:
   2707 		{
   2708 			mpapi_tpg_data_t	*tpg;
   2709 			char			*tpg_res;
   2710 
   2711 			item->oid.raw_oid =
   2712 			    vhci_mpapi_create_oid(vhci->mp_priv, obj_type);
   2713 			tpg = kmem_zalloc(
   2714 			    sizeof (mpapi_tpg_data_t), KM_SLEEP);
   2715 			tpg_res = kmem_zalloc(strlen(res)+1, KM_SLEEP);
   2716 			(void) strlcpy(tpg_res, res, strlen(res)+1);
   2717 			tpg->resp = tpg_res;
   2718 			tpg->valid = 1;
   2719 			tpg->prop.id = item->oid.raw_oid;
   2720 			/*
   2721 			 * T10 TPG ID is a 2 byte value. Keep up with it.
   2722 			 */
   2723 			tpg->prop.tpgId =
   2724 			    ((item->oid.raw_oid) & 0x000000000000ffff);
   2725 			tpg->tport_list = vhci_mpapi_create_list_head();
   2726 			tpg->lu_list = vhci_mpapi_create_list_head();
   2727 			item->idata = (void *)tpg;
   2728 			vhci_mpapi_log_sysevent(vhci->vhci_dip,
   2729 			    &(item->oid.raw_oid), ESC_SUN_MP_TPG_ADD);
   2730 		}
   2731 		break;
   2732 
   2733 		case	MP_OBJECT_TYPE_MULTIPATH_LU:
   2734 		{
   2735 			mpapi_lu_data_t	*lu;
   2736 			scsi_vhci_lun_t	*svl = res;
   2737 			/*
   2738 			 * We cant use ddi_get_instance(svl->svl_dip) at this
   2739 			 * point because the dip is not yet in DS_READY state.
   2740 			 */
   2741 			item->oid.raw_oid =
   2742 			    vhci_mpapi_create_oid(vhci->mp_priv, obj_type);
   2743 
   2744 			lu = kmem_zalloc(sizeof (mpapi_lu_data_t), KM_SLEEP);
   2745 			lu->resp = res;
   2746 			lu->valid = 1;
   2747 			lu->prop.id = (uint64_t)item->oid.raw_oid;
   2748 			/*
   2749 			 * XXX: luGroupID is currently unsupported
   2750 			 */
   2751 			lu->prop.luGroupID = 0xFFFFFFFF;
   2752 
   2753 			(void) strlcpy(lu->prop.name, svl->svl_lun_wwn,
   2754 			    sizeof (lu->prop.name));
   2755 
   2756 			(void) strlcpy(lu->prop.deviceFileName,
   2757 			    "/devices/scsi_vhci/ssd@g",
   2758 			    sizeof (lu->prop.deviceFileName));
   2759 			(void) strlcat(lu->prop.deviceFileName, lu->prop.name,
   2760 			    sizeof (lu->prop.deviceFileName));
   2761 
   2762 			if ((svl != NULL) &&
   2763 			    (SCSI_FAILOVER_IS_ASYM(svl) ||
   2764 			    SCSI_FAILOVER_IS_TPGS(svl->svl_fops))) {
   2765 				lu->prop.asymmetric = 1;
   2766 			}
   2767 
   2768 			lu->prop.autoFailbackEnabled =
   2769 			    ((VHCI_CONF_FLAGS_AUTO_FAILBACK & vhci->
   2770 			    vhci_conf_flags) ? 1 : 0);
   2771 
   2772 			if (svl->svl_lb_policy_save == LOAD_BALANCE_NONE) {
   2773 				lu->prop.currentLoadBalanceType =
   2774 				    MP_DRVR_LOAD_BALANCE_TYPE_NONE;
   2775 			} else if (svl->svl_lb_policy_save == LOAD_BALANCE_RR) {
   2776 				lu->prop.currentLoadBalanceType =
   2777 				    MP_DRVR_LOAD_BALANCE_TYPE_ROUNDROBIN;
   2778 			} else if (svl->svl_lb_policy_save ==
   2779 			    LOAD_BALANCE_LBA) {
   2780 				lu->prop.currentLoadBalanceType =
   2781 				    MP_DRVR_LOAD_BALANCE_TYPE_LBA_REGION;
   2782 			} else {
   2783 				/*
   2784 				 * We still map Load Balance Type to UNKNOWN
   2785 				 * although "none" also maps to the same case.
   2786 				 * MPAPI spec does not have a "NONE" LB type.
   2787 				 */
   2788 				lu->prop.currentLoadBalanceType =
   2789 				    MP_DRVR_LOAD_BALANCE_TYPE_UNKNOWN;
   2790 			}
   2791 			/*
   2792 			 * Allocate header lists for cross reference
   2793 			 */
   2794 			lu->path_list = vhci_mpapi_create_list_head();
   2795 			lu->tpg_list = vhci_mpapi_create_list_head();
   2796 			item->idata = (void *)lu;
   2797 			vhci_mpapi_log_sysevent(vhci->vhci_dip,
   2798 			    &(item->oid.raw_oid), ESC_SUN_MP_LU_CHANGE);
   2799 
   2800 		}
   2801 		break;
   2802 
   2803 		case	MP_OBJECT_TYPE_PATH_LU:
   2804 		{
   2805 			mpapi_path_data_t	*path;
   2806 			mdi_pathinfo_t		*pip = res;
   2807 			scsi_vhci_lun_t		*svl;
   2808 			char			*iport, *tport;
   2809 
   2810 			item->oid.raw_oid =
   2811 			    vhci_mpapi_create_oid(vhci->mp_priv, obj_type);
   2812 			path = kmem_zalloc(
   2813 			    sizeof (mpapi_path_data_t), KM_SLEEP);
   2814 			pname = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
   2815 
   2816 			iport = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
   2817 			(void) ddi_pathname(mdi_pi_get_phci(pip), iport);
   2818 
   2819 			if (mdi_prop_lookup_string(pip,
   2820 			    SCSI_ADDR_PROP_TARGET_PORT, &tport) !=
   2821 			    DDI_PROP_SUCCESS) {
   2822 				/* XXX: target-port prop not found */
   2823 				tport = (char *)mdi_pi_get_addr(pip);
   2824 				VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_mpapi_"
   2825 				    "create_item: mdi_prop_lookup_string() "
   2826 				    "returned failure; "));
   2827 			}
   2828 
   2829 			svl = mdi_client_get_vhci_private
   2830 			    (mdi_pi_get_client(pip));
   2831 
   2832 			(void) strlcat(pname, iport, MAXPATHLEN);
   2833 			(void) strlcat(pname, tport, MAXPATHLEN);
   2834 			(void) strlcat(pname, svl->svl_lun_wwn, MAXPATHLEN);
   2835 			kmem_free(iport, MAXPATHLEN);
   2836 
   2837 			path->resp = res;
   2838 			path->path_name = pname;
   2839 			path->valid = 1;
   2840 			path->hide = 0;
   2841 			path->prop.id = item->oid.raw_oid;
   2842 			item->idata = (void *)path;
   2843 			vhci_mpapi_log_sysevent(vhci->vhci_dip,
   2844 			    &(item->oid.raw_oid), ESC_SUN_MP_PATH_ADD);
   2845 		}
   2846 		break;
   2847 
   2848 		case	MP_OBJECT_TYPE_DEVICE_PRODUCT:
   2849 			VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_mpapi_create_item:"
   2850 			    " DEVICE PRODUCT not handled here."));
   2851 		break;
   2852 
   2853 		default:
   2854 			/*
   2855 			 * This should not happen
   2856 			 */
   2857 			VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_mpapi_create_item:"
   2858 			    "Got Unsupported OBJECT TYPE"));
   2859 			return (NULL);
   2860 	}
   2861 
   2862 	(void) vhci_mpapi_add_to_list(vhci->mp_priv->obj_hdr_list[obj_type],
   2863 	    ilist);
   2864 	return (ilist);
   2865 }
   2866 
   2867 /*
   2868  * Local routine to allocate mpapi list header block
   2869  */
   2870 /* ARGSUSED */
   2871 static mpapi_list_header_t *
   2872 vhci_mpapi_create_list_head()
   2873 {
   2874 	mpapi_list_header_t	*lh;
   2875 
   2876 	lh =  kmem_zalloc(sizeof (mpapi_list_header_t), KM_SLEEP);
   2877 	lh->head = lh->tail = NULL;
   2878 	return (lh);
   2879 }
   2880 
   2881 /*
   2882  * Routine to create Level 1 mpapi_private data structure and also
   2883  * establish cross references between the resources being managed
   2884  */
   2885 /* ARGSUSED */
   2886 void
   2887 vhci_update_mpapi_data(struct scsi_vhci *vhci, scsi_vhci_lun_t *vlun,
   2888     mdi_pathinfo_t *pip)
   2889 {
   2890 	char			*tmp_wwn = NULL, *init = NULL, *path_class;
   2891 	dev_info_t		*pdip;
   2892 	mpapi_item_list_t	*lu_list, *path_list, *init_list, *tgt_list;
   2893 	mpapi_item_list_t	*tp_path_list, *init_path_list, *lu_path_list;
   2894 	mpapi_lu_data_t		*ld;
   2895 	mpapi_path_data_t	*pd;
   2896 	mpapi_tport_data_t	*tpd;
   2897 	mpapi_initiator_data_t	*initd;
   2898 	int			path_class_not_mdi_alloced = 0;
   2899 
   2900 	VHCI_DEBUG(6, (CE_NOTE, NULL, "vhci_update_mpapi_data: vhci: %p, "
   2901 	    "vlun: %p, pip: %p\n", (void *)vhci, (void *)vlun, (void *)pip));
   2902 
   2903 	/*
   2904 	 * Check that the lun is not a TPGS device
   2905 	 * TPGS devices create the same information in another routine.
   2906 	 */
   2907 	if (SCSI_FAILOVER_IS_TPGS(vlun->svl_fops)) {
   2908 		return;
   2909 	}
   2910 	/*
   2911 	 * LEVEL 1 - Actions:
   2912 	 * Check if the appropriate resource pointers already
   2913 	 * exist in the Level 1 list and add them if they are new.
   2914 	 */
   2915 
   2916 	/*
   2917 	 * Build MP LU list
   2918 	 */
   2919 	lu_list = vhci_get_mpapi_item(vhci, NULL,
   2920 	    MP_OBJECT_TYPE_MULTIPATH_LU, (void*)vlun);
   2921 	if (lu_list == NULL) {
   2922 		/* Need to create lu_list entry */
   2923 		lu_list = vhci_mpapi_create_item(vhci,
   2924 		    MP_OBJECT_TYPE_MULTIPATH_LU, (void*)vlun);
   2925 	} else {
   2926 		/*
   2927 		 * Matched this lu w/ an existing one in current lu list.
   2928 		 * SAME LUN came online!! So, update the resp in main list.
   2929 		 */
   2930 		ld = lu_list->item->idata;
   2931 		ld->valid = 1;
   2932 		ld->resp = vlun;
   2933 	}
   2934 
   2935 	/*
   2936 	 * Find out the "path-class" property on the pip
   2937 	 */
   2938 	if (mdi_prop_lookup_string(pip, "path-class", &path_class)
   2939 	    != DDI_PROP_SUCCESS) {
   2940 		/* XXX: path-class prop not found */
   2941 		path_class = kmem_zalloc(MPAPI_SCSI_MAXPCLASSLEN, KM_SLEEP);
   2942 		(void) strlcpy(path_class, "NONE", MPAPI_SCSI_MAXPCLASSLEN);
   2943 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_update_mpapi_data: "
   2944 		    "mdi_prop_lookup_string() returned failure; "
   2945 		    "Hence path_class = NONE"));
   2946 		path_class_not_mdi_alloced = 1;
   2947 	}
   2948 
   2949 	/*
   2950 	 * Build Path LU list
   2951 	 */
   2952 	path_list = vhci_get_mpapi_item(vhci, NULL,
   2953 	    MP_OBJECT_TYPE_PATH_LU, (void*)pip);
   2954 	if (path_list == NULL) {
   2955 		/* Need to create path_list entry */
   2956 		path_list = vhci_mpapi_create_item(vhci,
   2957 		    MP_OBJECT_TYPE_PATH_LU, (void*)pip);
   2958 	} else {
   2959 		/*
   2960 		 * Matched this pip w/ an existing one in current pip list.
   2961 		 * SAME PATH came online!! So, update the resp in main list.
   2962 		 */
   2963 		pd = path_list->item->idata;
   2964 		pd->valid = 1;
   2965 		pd->hide = 0;
   2966 		pd->resp = pip;
   2967 	}
   2968 
   2969 	if (MDI_PI_IS_ONLINE(pip)) {
   2970 		vhci_mpapi_set_path_state(vhci->vhci_dip, pip,
   2971 		    MP_DRVR_PATH_STATE_ACTIVE);
   2972 	} else if (MDI_PI_IS_STANDBY(pip)) {
   2973 		vhci_mpapi_set_path_state(vhci->vhci_dip, pip,
   2974 		    MP_DRVR_PATH_STATE_PASSIVE);
   2975 	} else {
   2976 		vhci_mpapi_set_path_state(vhci->vhci_dip, pip,
   2977 		    MP_DRVR_PATH_STATE_UNKNOWN);
   2978 	}
   2979 
   2980 	/*
   2981 	 * Build Initiator Port list
   2982 	 */
   2983 	pdip = mdi_pi_get_phci(pip);
   2984 	init = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
   2985 	(void) ddi_pathname(pdip, init);
   2986 
   2987 	init_list = vhci_get_mpapi_item(vhci, NULL,
   2988 	    MP_OBJECT_TYPE_INITIATOR_PORT, (void*)init);
   2989 	if (init_list == NULL) {
   2990 		/*
   2991 		 * Need to create init_list entry
   2992 		 * The resource ptr is no really pdip. It will be changed
   2993 		 * in vhci_mpapi_create_item(). The real resource ptr
   2994 		 * is the Port ID. But we pass the pdip, to create OID.
   2995 		 */
   2996 		init_list = vhci_mpapi_create_item(vhci,
   2997 		    MP_OBJECT_TYPE_INITIATOR_PORT, (void*)pdip);
   2998 	} else {
   2999 		initd = init_list->item->idata;
   3000 		initd->valid = 1;
   3001 	}
   3002 	kmem_free(init, MAXPATHLEN);
   3003 
   3004 	/*
   3005 	 * Build Target Port list
   3006 	 * Can get the tdip: tdip = mdi_pi_get_client(pip);
   3007 	 * But what's the use? We want TARGET_PORT.
   3008 	 * So try getting Target Port's WWN which is unique per port.
   3009 	 */
   3010 	tmp_wwn = NULL;
   3011 	if (mdi_prop_lookup_string(pip, SCSI_ADDR_PROP_TARGET_PORT,
   3012 	    &tmp_wwn) != DDI_PROP_SUCCESS) {
   3013 		/* XXX: target-port prop not found */
   3014 		tmp_wwn = (char *)mdi_pi_get_addr(pip);
   3015 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_update_mpapi_data: "
   3016 		    "mdi_prop_lookup_string() returned failure; "
   3017 		    "Hence tmp_wwn = %p", (void *)tmp_wwn));
   3018 	}
   3019 
   3020 	tgt_list = vhci_get_mpapi_item(vhci, NULL,
   3021 	    MP_OBJECT_TYPE_TARGET_PORT, (void*)tmp_wwn);
   3022 	if (tgt_list == NULL) {
   3023 		/* Need to create tgt_list entry */
   3024 		tgt_list = vhci_mpapi_create_item(vhci,
   3025 		    MP_OBJECT_TYPE_TARGET_PORT, (void*)tmp_wwn);
   3026 	} else {
   3027 		tpd = tgt_list->item->idata;
   3028 		tpd->valid = 1;
   3029 	}
   3030 
   3031 	/*
   3032 	 * LEVEL 2 - Actions:
   3033 	 * Since all the Object type item lists are updated to account
   3034 	 * for the new resources, now lets cross-reference these
   3035 	 * resources (mainly through paths) to maintain the
   3036 	 * relationship between them.
   3037 	 */
   3038 
   3039 	ld = (mpapi_lu_data_t *)lu_list->item->idata;
   3040 	if (vhci_get_mpapi_item(vhci, ld->path_list,
   3041 	    MP_OBJECT_TYPE_PATH_LU, (void*)pip) == NULL) {
   3042 		lu_path_list = kmem_zalloc(sizeof (mpapi_item_list_t),
   3043 		    KM_SLEEP);
   3044 		lu_path_list->item = path_list->item;
   3045 		(void) vhci_mpapi_add_to_list(ld->path_list, lu_path_list);
   3046 	}
   3047 
   3048 	initd = (mpapi_initiator_data_t *)init_list->item->idata;
   3049 	if (vhci_get_mpapi_item(vhci, initd->path_list,
   3050 	    MP_OBJECT_TYPE_PATH_LU, (void*)pip) == NULL) {
   3051 		init_path_list = kmem_zalloc(sizeof (mpapi_item_list_t),
   3052 		    KM_SLEEP);
   3053 		init_path_list->item = path_list->item;
   3054 		(void) vhci_mpapi_add_to_list(initd->path_list, init_path_list);
   3055 	}
   3056 
   3057 	tpd = (mpapi_tport_data_t *)tgt_list->item->idata;
   3058 	if (vhci_get_mpapi_item(vhci, tpd->path_list,
   3059 	    MP_OBJECT_TYPE_PATH_LU, (void*)pip) == NULL) {
   3060 		tp_path_list = kmem_zalloc(
   3061 		    sizeof (mpapi_item_list_t), KM_SLEEP);
   3062 		tp_path_list->item = path_list->item;
   3063 		(void) vhci_mpapi_add_to_list(tpd->path_list, tp_path_list);
   3064 	}
   3065 
   3066 	/*
   3067 	 * Level-1: Fill-out Path Properties now, since we got all details.
   3068 	 * Actually, It is a structure copy, rather than just filling details.
   3069 	 */
   3070 	pd = path_list->item->idata;
   3071 	(void) strlcpy(pd->pclass, path_class, sizeof (pd->pclass));
   3072 	bcopy(&(ld->prop), &(pd->prop.logicalUnit),
   3073 	    sizeof (struct mp_logical_unit_prop));
   3074 	bcopy(&(initd->prop), &(pd->prop.initPort),
   3075 	    sizeof (struct mp_init_port_prop));
   3076 	bcopy(&(tpd->prop), &(pd->prop.targetPort),
   3077 	    sizeof (struct mp_target_port_prop));
   3078 
   3079 	vhci_mpapi_synthesize_tpg_data(vhci, vlun, pip);
   3080 
   3081 	if (path_class_not_mdi_alloced == 1) {
   3082 		kmem_free(path_class, MPAPI_SCSI_MAXPCLASSLEN);
   3083 	}
   3084 
   3085 }
   3086 
   3087 /*
   3088  * Routine to search (& return if found) a TPG object with a specified
   3089  * tpg_id and rel_tp_id for a specified vlun structure. Returns NULL
   3090  * if either TPG object or the lu item is not found.
   3091  * This routine is used for TPGS(ALUA) devices.
   3092  */
   3093 /* ARGSUSED */
   3094 static mpapi_item_list_t *
   3095 vhci_mpapi_get_alua_item(struct scsi_vhci *vhci, void *vlun, void *tpg_id,
   3096     void *tp)
   3097 {
   3098 	mpapi_list_header_t	*this_tpghdr;
   3099 	mpapi_item_list_t	*tpglist, *this_lulist, *this_tpglist;
   3100 	mpapi_tpg_data_t	*tpgdata, *this_tpgdata;
   3101 
   3102 	VHCI_DEBUG(6, (CE_NOTE, NULL, "vhci_mpapi_get_alua_item: ENTER: vlun="
   3103 	    "%p, tpg_id=%s, tp=%s\n",
   3104 	    (void *)vlun, (char *)tpg_id, (char *)tp));
   3105 
   3106 	/*
   3107 	 * Check if target port is already in any existing group
   3108 	 */
   3109 	tpglist = vhci->mp_priv->obj_hdr_list[MP_OBJECT_TYPE_TARGET_PORT_GROUP]
   3110 	    ->head;
   3111 	while (tpglist != NULL) {
   3112 		tpgdata = tpglist->item->idata;
   3113 
   3114 		if ((tpgdata) &&
   3115 		    (vhci_mpapi_check_tp_in_tpg(tpgdata, tp) == 1) &&
   3116 		    (strcmp(tpgdata->resp, tpg_id) == 0)) {
   3117 			return (tpglist);
   3118 		} else {
   3119 			tpglist = tpglist->next;
   3120 		}
   3121 	}
   3122 
   3123 	/*
   3124 	 * If target port is not existed, search TPG associated
   3125 	 * with this LU to see if this LU has a TPG with the same
   3126 	 * tpg_id.
   3127 	 */
   3128 	this_lulist = vhci_get_mpapi_item(vhci, NULL,
   3129 	    MP_OBJECT_TYPE_MULTIPATH_LU, vlun);
   3130 	if (this_lulist != NULL) {
   3131 		this_tpghdr = ((mpapi_lu_data_t *)(this_lulist->item->idata))
   3132 		    ->tpg_list;
   3133 		this_tpglist = this_tpghdr->head;
   3134 		while (this_tpglist != NULL) {
   3135 			this_tpgdata = this_tpglist->item->idata;
   3136 			if ((this_tpgdata) &&
   3137 			    (strcmp(this_tpgdata->resp, tpg_id) == 0)) {
   3138 				return (this_tpglist);
   3139 			} else {
   3140 				this_tpglist = this_tpglist->next;
   3141 			}
   3142 		}
   3143 	}
   3144 
   3145 	VHCI_DEBUG(4, (CE_WARN, NULL, "vhci_mpapi_get_tpg_item: Returns NULL"));
   3146 
   3147 	return (NULL);
   3148 }
   3149 
   3150 /*
   3151  * Routine to search (& return if found) a TPG object with a specified
   3152  * accessState for a specified vlun structure. Returns NULL if either
   3153  * TPG object or the lu item is not found.
   3154  * This routine is used for NON-TPGS devices.
   3155  */
   3156 /* ARGSUSED */
   3157 static mpapi_item_list_t *
   3158 vhci_mpapi_get_tpg_item(struct scsi_vhci *vhci, uint32_t acc_state, void *vlun,
   3159     char *pclass, void *tp)
   3160 {
   3161 	mpapi_list_header_t	*tpghdr, *this_tpghdr;
   3162 	mpapi_item_list_t	*lulist, *tpglist, *this_lulist, *this_tpglist;
   3163 	mpapi_tpg_data_t	*tpgdata, *this_tpgdata;
   3164 
   3165 	VHCI_DEBUG(6, (CE_NOTE, NULL, "vhci_mpapi_get_tpg_item: ENTER: vlun="
   3166 	    "%p, acc_state=%x, pclass=%s, tp=%s\n",
   3167 	    (void *)vlun, acc_state, pclass, (char *)tp));
   3168 
   3169 	lulist = vhci->mp_priv->obj_hdr_list[MP_OBJECT_TYPE_MULTIPATH_LU]->head;
   3170 
   3171 	while (lulist != NULL) {
   3172 		tpghdr = ((mpapi_lu_data_t *)(lulist->item->idata))->tpg_list;
   3173 		tpglist = tpghdr->head;
   3174 		while (tpglist != NULL) {
   3175 			tpgdata = tpglist->item->idata;
   3176 
   3177 			if ((tpgdata) &&
   3178 			    (vhci_mpapi_check_tp_in_tpg(tpgdata, tp) == 1) &&
   3179 			    (strncmp(tpgdata->pclass, pclass,
   3180 			    strlen(pclass)) == 0)) {
   3181 				return (tpglist);
   3182 			} else {
   3183 				tpglist = tpglist->next;
   3184 			}
   3185 		}
   3186 		lulist = lulist->next;
   3187 	}
   3188 
   3189 	this_lulist = vhci_get_mpapi_item(vhci, NULL,
   3190 	    MP_OBJECT_TYPE_MULTIPATH_LU, vlun);
   3191 	if (this_lulist != NULL) {
   3192 		this_tpghdr = ((mpapi_lu_data_t *)(this_lulist->item->idata))
   3193 		    ->tpg_list;
   3194 		this_tpglist = this_tpghdr->head;
   3195 		while (this_tpglist != NULL) {
   3196 			this_tpgdata = this_tpglist->item->idata;
   3197 
   3198 			if ((this_tpgdata) &&
   3199 			    (strncmp(this_tpgdata->pclass, pclass,
   3200 			    strlen(pclass)) == 0)) {
   3201 				return (this_tpglist);
   3202 			} else {
   3203 				this_tpglist = this_tpglist->next;
   3204 			}
   3205 		}
   3206 	}
   3207 
   3208 	VHCI_DEBUG(4, (CE_WARN, NULL, "vhci_mpapi_get_tpg_item: Returns NULL"));
   3209 
   3210 	return (NULL);
   3211 }
   3212 
   3213 /*
   3214  * Routine to search (& return if found) a TPG object with a specified
   3215  * accessState for a specified vlun structure. Returns NULL if either
   3216  * TPG object or the lu item is not found.
   3217  * This routine is used for NON-TPGS devices.
   3218  */
   3219 /* ARGSUSED */
   3220 mpapi_item_list_t *
   3221 vhci_mpapi_get_tpg_for_lun(struct scsi_vhci *vhci, char *pclass,
   3222     void *vlun, void *tp)
   3223 {
   3224 	mpapi_list_header_t	*this_tpghdr;
   3225 	mpapi_item_list_t	*this_lulist, *this_tpglist;
   3226 	mpapi_tpg_data_t	*this_tpgdata;
   3227 
   3228 	VHCI_DEBUG(4, (CE_NOTE, NULL, "vhci_mpapi_get_tpg_for_lun: ENTER: vlun="
   3229 	    "%p, pclass=%s, tp=%s\n", (void *)vlun, pclass, (char *)tp));
   3230 
   3231 	this_lulist = vhci_get_mpapi_item(vhci, NULL,
   3232 	    MP_OBJECT_TYPE_MULTIPATH_LU, vlun);
   3233 	if (this_lulist != NULL) {
   3234 		this_tpghdr = ((mpapi_lu_data_t *)(this_lulist->item->idata))
   3235 		    ->tpg_list;
   3236 		this_tpglist = this_tpghdr->head;
   3237 		while (this_tpglist != NULL) {
   3238 			this_tpgdata = this_tpglist->item->idata;
   3239 
   3240 			if ((this_tpgdata) &&
   3241 			    (vhci_mpapi_check_tp_in_tpg(this_tpgdata,
   3242 			    tp) == 1) && (strncmp(this_tpgdata->pclass, pclass,
   3243 			    strlen(pclass)) == 0)) {
   3244 				return (this_tpglist);
   3245 			}
   3246 			this_tpglist = this_tpglist->next;
   3247 		}
   3248 	}
   3249 
   3250 	VHCI_DEBUG(4, (CE_WARN, NULL, "vhci_mpapi_get_tpg_for_lun: Returns "
   3251 	    "NULL"));
   3252 
   3253 	return (NULL);
   3254 }
   3255 
   3256 /*
   3257  * Routine to search a Target Port in a TPG
   3258  */
   3259 /* ARGSUSED */
   3260 static int
   3261 vhci_mpapi_check_tp_in_tpg(mpapi_tpg_data_t *tpgdata, void *tp)
   3262 {
   3263 	mpapi_item_list_t	*tplist;
   3264 
   3265 	if (tpgdata) {
   3266 		tplist = tpgdata->tport_list->head;
   3267 	} else {
   3268 		return (0);
   3269 	}
   3270 
   3271 	while (tplist != NULL) {
   3272 		void	*resp = ((mpapi_tport_data_t *)tplist->
   3273 		    item->idata)->resp;
   3274 		if (strncmp(resp, tp, strlen(resp)) == 0) {
   3275 			/* Found a match */
   3276 			return (1);
   3277 		}
   3278 		tplist = tplist->next;
   3279 	}
   3280 
   3281 	return (0);
   3282 }
   3283 
   3284 /*
   3285  * Routine to create Level 1 mpapi_private data structure for TPG object &
   3286  * establish cross references between the TPG resources being managed.
   3287  * TPG SYNTHESIS MODE: Process for NON-SCSI_FAILOVER_IS_TPGS devices ONLY.
   3288  * SCSI_FAILOVER_IS_TPGS devices have TPGS(ALUA support) and provide
   3289  * REPORT_TARGET_PORT_GROUP data which we can parse directly in the next
   3290  * routine(vhci_mpapi_update_tpg_data) to create TPG list in mpapi_priv block.
   3291  */
   3292 /* ARGSUSED */
   3293 void
   3294 vhci_mpapi_synthesize_tpg_data(struct scsi_vhci *vhci, scsi_vhci_lun_t *vlun,
   3295     mdi_pathinfo_t *pip)
   3296 {
   3297 	uint32_t		as;
   3298 	char			*tmp_wwn = NULL, *path_class = NULL;
   3299 	mpapi_item_list_t	*tpg_tport_list, *tpg_lu_list, *lu_list;
   3300 	mpapi_item_list_t	*lu_tpg_list, *item_list, *tpg_list;
   3301 	mpapi_tpg_data_t	*tpg_data;
   3302 	int			path_class_not_mdi_alloced = 0;
   3303 
   3304 	/*
   3305 	 * Build Target Port Group list
   3306 	 * Start by finding out the affected Target Port.
   3307 	 */
   3308 	if (mdi_prop_lookup_string(pip, SCSI_ADDR_PROP_TARGET_PORT,
   3309 	    &tmp_wwn) != DDI_PROP_SUCCESS) {
   3310 		/* XXX: target-port prop not found */
   3311 		tmp_wwn = (char *)mdi_pi_get_addr(pip);
   3312 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_mpapi_synthesize_tpg_data: "
   3313 		    "mdi_prop_lookup_string() returned failure; "
   3314 		    "Hence tmp_wwn = %p", (void *)tmp_wwn));
   3315 	}
   3316 
   3317 	/*
   3318 	 * Finding out the "path-class" property
   3319 	 */
   3320 	if (mdi_prop_lookup_string(pip, "path-class", &path_class)
   3321 	    != DDI_PROP_SUCCESS) {
   3322 		/* XXX: path-class prop not found */
   3323 		path_class = kmem_zalloc(MPAPI_SCSI_MAXPCLASSLEN, KM_SLEEP);
   3324 		(void) strlcpy(path_class, "NONE", MPAPI_SCSI_MAXPCLASSLEN);
   3325 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_mpapi_synthesize_tpg_data: "
   3326 		    "mdi_prop_lookup_string() returned failure; "
   3327 		    "Hence path_class = NONE"));
   3328 		path_class_not_mdi_alloced = 1;
   3329 	}
   3330 
   3331 	/*
   3332 	 * Check the vlun's accessState through pip; we'll use it later.
   3333 	 */
   3334 	if (MDI_PI_IS_ONLINE(pip)) {
   3335 		as = MP_DRVR_ACCESS_STATE_ACTIVE;
   3336 	} else if (MDI_PI_IS_STANDBY(pip)) {
   3337 		as = MP_DRVR_ACCESS_STATE_STANDBY;
   3338 	} else {
   3339 		as = MP_DRVR_ACCESS_STATE_UNAVAILABLE;
   3340 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_mpapi_synthesize_tpg_data: "
   3341 		    "Unknown pip state seen in TPG synthesis"));
   3342 	}
   3343 
   3344 	VHCI_DEBUG(4, (CE_NOTE, NULL, "vhci_mpapi_synthesize_tpg_data: ENTER: "
   3345 	    "vlun=%s, acc_state=%x, path_class=%s, tp=%s\n",
   3346 	    vlun->svl_lun_wwn, as, path_class, tmp_wwn));
   3347 
   3348 	/*
   3349 	 * Create Level 1 and Level 2 data structures for type
   3350 	 */
   3351 	if (!SCSI_FAILOVER_IS_TPGS(vlun->svl_fops)) {
   3352 		/*
   3353 		 * First check if the lun has a TPG list in its level 2
   3354 		 * structure then, check if this lun is already
   3355 		 * accounted for through a different Target Port.
   3356 		 * If yes, get the ptr to the TPG & skip new TPG creation.
   3357 		 */
   3358 		lu_list = vhci_get_mpapi_item(vhci, NULL,
   3359 		    MP_OBJECT_TYPE_MULTIPATH_LU, vlun);
   3360 		tpg_list = vhci_mpapi_get_tpg_item(vhci, as, vlun, path_class,
   3361 		    (void *)tmp_wwn);
   3362 		if (tpg_list == NULL) {
   3363 			tpg_list = vhci_mpapi_create_item(vhci,
   3364 			    MP_OBJECT_TYPE_TARGET_PORT_GROUP, (void *)tmp_wwn);
   3365 			tpg_data = tpg_list->item->idata;
   3366 			(void) strlcpy(tpg_data->pclass, path_class,
   3367 			    sizeof (tpg_data->pclass));
   3368 			tpg_data->prop.accessState = as;
   3369 		} else {
   3370 			tpg_data = tpg_list->item->idata;
   3371 		}
   3372 
   3373 		if ((vlun != NULL) && SCSI_FAILOVER_IS_ASYM(vlun)) {
   3374 			tpg_data->prop.explicitFailover = 1;
   3375 		}
   3376 
   3377 		/*
   3378 		 * Level 2, Lun Cross referencing to TPG.
   3379 		 */
   3380 		if (vhci_get_mpapi_item(vhci, tpg_data->lu_list,
   3381 		    MP_OBJECT_TYPE_MULTIPATH_LU, (void *)vlun) == NULL) {
   3382 			tpg_lu_list = kmem_zalloc(sizeof (mpapi_item_list_t),
   3383 			    KM_SLEEP);
   3384 			item_list = vhci_get_mpapi_item(vhci, NULL,
   3385 			    MP_OBJECT_TYPE_MULTIPATH_LU, (void *)vlun);
   3386 			tpg_lu_list->item = item_list->item;
   3387 			(void) vhci_mpapi_add_to_list(tpg_data->lu_list,
   3388 			    tpg_lu_list);
   3389 		}
   3390 
   3391 		/*
   3392 		 * Level 2, Target Port Cross referencing to TPG.
   3393 		 */
   3394 		if (vhci_get_mpapi_item(vhci, tpg_data->tport_list,
   3395 		    MP_OBJECT_TYPE_TARGET_PORT, (void *)tmp_wwn) == NULL) {
   3396 			tpg_tport_list = kmem_zalloc(sizeof (mpapi_item_list_t),
   3397 			    KM_SLEEP);
   3398 			item_list = vhci_get_mpapi_item(vhci, NULL,
   3399 			    MP_OBJECT_TYPE_TARGET_PORT, (void *)tmp_wwn);
   3400 			tpg_tport_list->item = item_list->item;
   3401 			(void) vhci_mpapi_add_to_list(tpg_data->tport_list,
   3402 			    tpg_tport_list);
   3403 		}
   3404 
   3405 		/*
   3406 		 * Level 2, TPG Cross referencing to Lun.
   3407 		 */
   3408 		lu_tpg_list = vhci_mpapi_get_tpg_for_lun
   3409 		    (vhci, path_class, vlun, tmp_wwn);
   3410 		if (lu_tpg_list == NULL) {
   3411 			lu_tpg_list = kmem_zalloc(sizeof (mpapi_item_list_t),
   3412 			    KM_SLEEP);
   3413 			lu_tpg_list->item = tpg_list->item;
   3414 			(void) vhci_mpapi_add_to_list(((mpapi_lu_data_t *)
   3415 			    (lu_list->item->idata))->tpg_list, lu_tpg_list);
   3416 		}
   3417 
   3418 		/*
   3419 		 * Update the AccessState of related MPAPI TPGs
   3420 		 * This takes care of a special case where a failover doesn't
   3421 		 * happen but a TPG accessState needs to be updated from
   3422 		 * Unavailable to Standby
   3423 		 */
   3424 		(void) vhci_mpapi_update_tpg_acc_state_for_lu(vhci, vlun);
   3425 	}
   3426 
   3427 	if (path_class_not_mdi_alloced == 1) {
   3428 		kmem_free(path_class, MPAPI_SCSI_MAXPCLASSLEN);
   3429 	}
   3430 
   3431 }
   3432 
   3433 /*
   3434  * Routine to create Level 1 mpapi_private data structure for TPG object,
   3435  * for devices which support TPG and establish cross references between
   3436  * the TPG resources being managed. The RTPG response sent by std_asymmetric
   3437  * module is parsed in this routine and mpapi_priv data structure is updated.
   3438  */
   3439 /* ARGSUSED */
   3440 void
   3441 vhci_mpapi_update_tpg_data(struct scsi_address *ap, char *ptr,
   3442     int rel_tgt_port)
   3443 {
   3444 	struct scsi_vhci_lun	*vlun;
   3445 	struct scsi_vhci	*vhci;
   3446 	struct scsi_device	*psd = NULL;
   3447 	scsi_vhci_priv_t	*svp;
   3448 	mdi_pathinfo_t		*pip;
   3449 	dev_info_t		*pdip;
   3450 	char			tpg_id[16], *tgt_port, *init = NULL;
   3451 	uint32_t		int_tpg_id, rel_tid, as;
   3452 	int			i, rel_tport_cnt;
   3453 	mpapi_item_list_t	*path_list, *init_list;
   3454 	mpapi_item_list_t	*tp_path_list, *init_path_list, *lu_path_list;
   3455 	mpapi_item_list_t	*tpg_tport_list, *tpg_lu_list, *lu_list;
   3456 	mpapi_item_list_t	*lu_tpg_list, *item_list, *tpg_list, *tgt_list;
   3457 	mpapi_lu_data_t		*ld;
   3458 	mpapi_tpg_data_t	*tpg_data;
   3459 	mpapi_path_data_t	*pd;
   3460 	mpapi_tport_data_t	*tpd;
   3461 	mpapi_initiator_data_t	*initd;
   3462 
   3463 	/*
   3464 	 * Find out the TPG ID (resource ptr for TPG is T10 TPG ID)
   3465 	 */
   3466 	int_tpg_id = ((ptr[2] & 0xff) << 8) | (ptr[3] & 0xff);
   3467 	(void) sprintf(tpg_id, "%04x", int_tpg_id);
   3468 
   3469 	/*
   3470 	 * Check the TPG's accessState; we'll use it later.
   3471 	 */
   3472 	as = (ptr[0] & 0x0f);
   3473 	if (as == STD_ACTIVE_OPTIMIZED) {
   3474 		as = MP_DRVR_ACCESS_STATE_ACTIVE_OPTIMIZED;
   3475 	} else if (as == STD_ACTIVE_NONOPTIMIZED) {
   3476 		as = MP_DRVR_ACCESS_STATE_ACTIVE_NONOPTIMIZED;
   3477 	} else if (as == STD_STANDBY) {
   3478 		as = MP_DRVR_ACCESS_STATE_STANDBY;
   3479 	} else {
   3480 		as = MP_DRVR_ACCESS_STATE_UNAVAILABLE;
   3481 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_mpapi_update_tpg_data: "
   3482 		    "UNAVAILABLE accessState seen in ALUA TPG setup"));
   3483 	}
   3484 
   3485 	/*
   3486 	 * The scsi_address passed is associated with a scsi_vhci allocated
   3487 	 * scsi_device structure for a pathinfo node. Getting the vlun from
   3488 	 * this is a bit complicated.
   3489 	 */
   3490 	if (ap->a_hba_tran->tran_hba_flags & SCSI_HBA_ADDR_COMPLEX)
   3491 		psd = scsi_address_device(ap);
   3492 	else if (ap->a_hba_tran->tran_hba_flags & SCSI_HBA_TRAN_CLONE)
   3493 		psd = ap->a_hba_tran->tran_sd;
   3494 	ASSERT(psd);
   3495 	pip = (mdi_pathinfo_t *)psd->sd_pathinfo;
   3496 
   3497 	/*
   3498 	 * It is possable for this code to be called without the sd_pathinfo
   3499 	 * being set. This may happen as part of a probe to see if a device
   3500 	 * should be mapped under mdi. At this point we know enough to answer
   3501 	 * correctly so we can return.
   3502 	 */
   3503 	if (pip == NULL)
   3504 		return;
   3505 	svp = (scsi_vhci_priv_t *)mdi_pi_get_vhci_private(pip);
   3506 	vlun = svp->svp_svl;
   3507 
   3508 	/*
   3509 	 * Now get the vhci ptr using the walker
   3510 	 */
   3511 	mdi_walk_vhcis(vhci_mpapi_get_vhci, &vhci);
   3512 
   3513 	VHCI_DEBUG(4, (CE_NOTE, NULL, "vhci_mpapi_update_tpg_data: vhci=%p, "
   3514 	    "(vlun)wwn=(%p)%s, pip=%p, ap=%p, ptr=%p, as=%x, tpg_id=%s, fops="
   3515 	    "%p\n", (void *)vhci, (void *)vlun,
   3516 	    vlun ? vlun->svl_lun_wwn : "NONE",
   3517 	    (void *)pip, (void *)ap, (void *)ptr, as, tpg_id,
   3518 	    (void *)(vlun ? vlun->svl_fops : NULL)));
   3519 
   3520 	if ((vhci == NULL) || (vlun == NULL) ||
   3521 	    !SCSI_FAILOVER_IS_TPGS(vlun->svl_fops)) {
   3522 		/* Cant help, unfortunate situation */
   3523 		return;
   3524 	}
   3525 
   3526 	/*
   3527 	 * LEVEL 1 - Actions:
   3528 	 * Check if the appropriate resource pointers already
   3529 	 * exist in the Level 1 list and add them if they are new.
   3530 	 */
   3531 
   3532 	/*
   3533 	 * Build MP LU list
   3534 	 */
   3535 	lu_list = vhci_get_mpapi_item(vhci, NULL,
   3536 	    MP_OBJECT_TYPE_MULTIPATH_LU, (void*)vlun);
   3537 	if (lu_list == NULL) {
   3538 		/* Need to create lu_list entry */
   3539 		lu_list = vhci_mpapi_create_item(vhci,
   3540 		    MP_OBJECT_TYPE_MULTIPATH_LU, (void*)vlun);
   3541 	} else {
   3542 		/*
   3543 		 * Matched this lu w/ an existing one in current lu list.
   3544 		 * SAME LUN came online!! So, update the resp in main list.
   3545 		 */
   3546 		ld = lu_list->item->idata;
   3547 		ld->valid = 1;
   3548 		ld->resp = vlun;
   3549 	}
   3550 
   3551 	/*
   3552 	 * Build Path LU list
   3553 	 */
   3554 	path_list = vhci_get_mpapi_item(vhci, NULL,
   3555 	    MP_OBJECT_TYPE_PATH_LU, (void*)pip);
   3556 	if (path_list == NULL) {
   3557 		/* Need to create path_list entry */
   3558 		path_list = vhci_mpapi_create_item(vhci,
   3559 		    MP_OBJECT_TYPE_PATH_LU, (void*)pip);
   3560 	} else {
   3561 		/*
   3562 		 * Matched this pip w/ an existing one in current pip list.
   3563 		 * SAME PATH came online!! So, update the resp in main list.
   3564 		 */
   3565 		pd = path_list->item->idata;
   3566 		pd->valid = 1;
   3567 		pd->resp = pip;
   3568 	}
   3569 
   3570 	if (MDI_PI_IS_ONLINE(pip)) {
   3571 		vhci_mpapi_set_path_state(vhci->vhci_dip, pip,
   3572 		    MP_DRVR_PATH_STATE_ACTIVE);
   3573 	} else if (MDI_PI_IS_STANDBY(pip)) {
   3574 		vhci_mpapi_set_path_state(vhci->vhci_dip, pip,
   3575 		    MP_DRVR_PATH_STATE_PASSIVE);
   3576 	} else {
   3577 		vhci_mpapi_set_path_state(vhci->vhci_dip, pip,
   3578 		    MP_DRVR_PATH_STATE_UNKNOWN);
   3579 	}
   3580 
   3581 	/*
   3582 	 * Build Initiator Port list
   3583 	 */
   3584 	pdip = mdi_pi_get_phci(pip);
   3585 	init = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
   3586 	(void) ddi_pathname(pdip, init);
   3587 
   3588 	init_list = vhci_get_mpapi_item(vhci, NULL,
   3589 	    MP_OBJECT_TYPE_INITIATOR_PORT, (void*)init);
   3590 	if (init_list == NULL) {
   3591 		/*
   3592 		 * Need to create init_list entry
   3593 		 * The resource ptr is no really pdip. It will be changed
   3594 		 * in vhci_mpapi_create_item(). The real resource ptr
   3595 		 * is the Port ID. But we pass the pdip, to create OID.
   3596 		 */
   3597 		init_list = vhci_mpapi_create_item(vhci,
   3598 		    MP_OBJECT_TYPE_INITIATOR_PORT, (void*)pdip);
   3599 	} else {
   3600 		initd = init_list->item->idata;
   3601 		initd->valid = 1;
   3602 	}
   3603 	kmem_free(init, MAXPATHLEN);
   3604 
   3605 	/*
   3606 	 * LEVEL 2 - Actions:
   3607 	 * Since all the Object type item lists are updated to account
   3608 	 * for the new resources, now lets cross-reference these
   3609 	 * resources (mainly through paths) to maintain the
   3610 	 * relationship between them.
   3611 	 */
   3612 
   3613 	ld = (mpapi_lu_data_t *)lu_list->item->idata;
   3614 	if (vhci_get_mpapi_item(vhci, ld->path_list,
   3615 	    MP_OBJECT_TYPE_PATH_LU, (void*)pip) == NULL) {
   3616 		lu_path_list = kmem_zalloc(sizeof (mpapi_item_list_t),
   3617 		    KM_SLEEP);
   3618 		lu_path_list->item = path_list->item;
   3619 		(void) vhci_mpapi_add_to_list(ld->path_list, lu_path_list);
   3620 	}
   3621 
   3622 	initd = (mpapi_initiator_data_t *)init_list->item->idata;
   3623 	if (vhci_get_mpapi_item(vhci, initd->path_list,
   3624 	    MP_OBJECT_TYPE_PATH_LU, (void*)pip) == NULL) {
   3625 		init_path_list = kmem_zalloc(sizeof (mpapi_item_list_t),
   3626 		    KM_SLEEP);
   3627 		init_path_list->item = path_list->item;
   3628 		(void) vhci_mpapi_add_to_list(initd->path_list, init_path_list);
   3629 	}
   3630 
   3631 	/*
   3632 	 * Building Target Port list is different here.
   3633 	 * For each different Relative Target Port. we have a new MPAPI
   3634 	 * Target Port OID generated.
   3635 	 * Just find out the main Target Port property here.
   3636 	 */
   3637 	tgt_port = NULL;
   3638 	if (mdi_prop_lookup_string(pip, SCSI_ADDR_PROP_TARGET_PORT,
   3639 	    &tgt_port) != DDI_PROP_SUCCESS) {
   3640 		/* XXX: target-port prop not found */
   3641 		tgt_port = (char *)mdi_pi_get_addr(pip);
   3642 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_mpapi_update_tpg_data: "
   3643 		    "mdi_prop_lookup_string() returned failure; "
   3644 		    "Hence tgt_port = %p", (void *)tgt_port));
   3645 	}
   3646 
   3647 	/* Search for existing group that contains this target port */
   3648 	tpg_list = vhci_mpapi_get_alua_item(vhci, vlun, &tpg_id, tgt_port);
   3649 	if (tpg_list == NULL) {
   3650 		tpg_list = vhci_mpapi_create_item(vhci,
   3651 		    MP_OBJECT_TYPE_TARGET_PORT_GROUP, &tpg_id);
   3652 	}
   3653 	tpg_data = tpg_list->item->idata;
   3654 	tpg_data->prop.accessState = as;
   3655 	tpg_data->prop.tpgId = int_tpg_id;
   3656 
   3657 	/*
   3658 	 * Set explicitFailover for TPG -
   3659 	 * based on tpgs_bits setting in Std Inquiry response.
   3660 	 */
   3661 	switch (psd->sd_inq->inq_tpgs) {
   3662 	case TPGS_FAILOVER_EXPLICIT:
   3663 	case TPGS_FAILOVER_BOTH:
   3664 		tpg_data->prop.explicitFailover = 1;
   3665 		break;
   3666 	case TPGS_FAILOVER_IMPLICIT:
   3667 		tpg_data->prop.explicitFailover = 0;
   3668 		break;
   3669 	default:
   3670 		return;
   3671 	}
   3672 
   3673 	/*
   3674 	 * Level 2, Lun Cross referencing to TPG.
   3675 	 */
   3676 	if (vhci_get_mpapi_item(vhci, tpg_data->lu_list,
   3677 	    MP_OBJECT_TYPE_MULTIPATH_LU, (void *)vlun) == NULL) {
   3678 		tpg_lu_list = kmem_zalloc(sizeof (mpapi_item_list_t),
   3679 		    KM_SLEEP);
   3680 		item_list = vhci_get_mpapi_item(vhci, NULL,
   3681 		    MP_OBJECT_TYPE_MULTIPATH_LU, (void *)vlun);
   3682 		tpg_lu_list->item = item_list->item;
   3683 		(void) vhci_mpapi_add_to_list(tpg_data->lu_list,
   3684 		    tpg_lu_list);
   3685 	}
   3686 
   3687 	/*
   3688 	 * Level 2, TPG Cross referencing to Lun.
   3689 	 */
   3690 	if (vhci_get_mpapi_item(vhci, ld->tpg_list,
   3691 	    MP_OBJECT_TYPE_TARGET_PORT_GROUP, &tpg_id) == 0) {
   3692 		lu_tpg_list = kmem_zalloc(sizeof (mpapi_item_list_t),
   3693 		    KM_SLEEP);
   3694 		lu_tpg_list->item = tpg_list->item;
   3695 		(void) vhci_mpapi_add_to_list(((mpapi_lu_data_t *)
   3696 		    (lu_list->item->idata))->tpg_list, lu_tpg_list);
   3697 	}
   3698 
   3699 	/*
   3700 	 * Level 1, Relative Target Port + Target Port Creation
   3701 	 */
   3702 	rel_tport_cnt = (ptr[7] & 0xff);
   3703 	ptr += 8;
   3704 	for (i = 0; i < rel_tport_cnt; i++) {
   3705 		rel_tid = 0;
   3706 		rel_tid |= ((ptr[2] & 0Xff) << 8);
   3707 		rel_tid |= (ptr[3] & 0xff);
   3708 
   3709 		if (rel_tid != rel_tgt_port) {
   3710 			ptr += 4;
   3711 			continue;
   3712 		}
   3713 
   3714 		VHCI_DEBUG(4, (CE_NOTE, NULL, "vhci_mpapi_update_tpg_data: "
   3715 		    "TgtPort=%s, RelTgtPort=%x\n", tgt_port, rel_tid));
   3716 
   3717 		tgt_list = vhci_mpapi_get_rel_tport_pair(vhci, NULL,
   3718 		    (void *)tgt_port, rel_tid);
   3719 		if (tgt_list == NULL) {
   3720 			/* Need to create tgt_list entry */
   3721 			tgt_list = vhci_mpapi_create_item(vhci,
   3722 			    MP_OBJECT_TYPE_TARGET_PORT,
   3723 			    (void *)tgt_port);
   3724 			tpd = tgt_list->item->idata;
   3725 			tpd->valid = 1;
   3726 			tpd->prop.relativePortID = rel_tid;
   3727 		} else {
   3728 			tpd = tgt_list->item->idata;
   3729 			tpd->valid = 1;
   3730 		}
   3731 
   3732 		tpd = (mpapi_tport_data_t *)tgt_list->item->idata;
   3733 		if (vhci_get_mpapi_item(vhci, tpd->path_list,
   3734 		    MP_OBJECT_TYPE_PATH_LU, (void*)pip) == NULL) {
   3735 			tp_path_list = kmem_zalloc(sizeof (mpapi_item_list_t),
   3736 			    KM_SLEEP);
   3737 			tp_path_list->item = path_list->item;
   3738 			(void) vhci_mpapi_add_to_list(tpd->path_list,
   3739 			    tp_path_list);
   3740 		}
   3741 
   3742 		if (vhci_mpapi_get_rel_tport_pair(vhci,
   3743 		    tpg_data->tport_list, tgt_port, rel_tid) == NULL) {
   3744 			tpg_tport_list = kmem_zalloc
   3745 			    (sizeof (mpapi_item_list_t), KM_SLEEP);
   3746 			tpg_tport_list->item = tgt_list->item;
   3747 			(void) vhci_mpapi_add_to_list(tpg_data->
   3748 			    tport_list, tpg_tport_list);
   3749 		}
   3750 		ptr += 4;
   3751 	}
   3752 
   3753 	/*
   3754 	 * Level-1: Fill-out Path Properties now, since we got all details.
   3755 	 * Actually, It is a structure copy, rather than just filling details.
   3756 	 */
   3757 	pd = path_list->item->idata;
   3758 	bcopy(&(ld->prop), &(pd->prop.logicalUnit),
   3759 	    sizeof (struct mp_logical_unit_prop));
   3760 	bcopy(&(initd->prop), &(pd->prop.initPort),
   3761 	    sizeof (struct mp_init_port_prop));
   3762 	bcopy(&(tpd->prop), &(pd->prop.targetPort),
   3763 	    sizeof (struct mp_target_port_prop));
   3764 }
   3765 
   3766 /*
   3767  * Routine to get mpapi ioctl argument structure from userland.
   3768  */
   3769 /* ARGSUSED */
   3770 static int
   3771 vhci_get_mpiocdata(const void *data, mp_iocdata_t *mpioc, int mode)
   3772 {
   3773 	int	retval = 0;
   3774 
   3775 #ifdef  _MULTI_DATAMODEL
   3776 	switch (ddi_model_convert_from(mode & FMODELS)) {
   3777 	case DDI_MODEL_ILP32:
   3778 	{
   3779 		mp_iocdata32_t	ioc32;
   3780 
   3781 		VHCI_DEBUG(6, (CE_WARN, NULL, "vhci_get_mpiocdata: "
   3782 		    "Case DDI_MODEL_ILP32"));
   3783 		if (ddi_copyin((void *)data, (void *)&ioc32,
   3784 		    sizeof (mp_iocdata32_t), mode)) {
   3785 			VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_get_mpiocdata: "
   3786 			    "ddi_copyin() FAILED"));
   3787 			retval = EFAULT;
   3788 			break;
   3789 		}
   3790 		mpioc->mp_xfer	= (uint16_t)(uintptr_t)ioc32.mp_xfer;
   3791 		mpioc->mp_cmd	= (uint16_t)(uintptr_t)ioc32.mp_cmd;
   3792 		mpioc->mp_flags	= (uint16_t)(uintptr_t)ioc32.mp_flags;
   3793 		mpioc->mp_cmd_flags	= (uint16_t)ioc32.mp_cmd_flags;
   3794 		mpioc->mp_ilen	= (size_t)(uintptr_t)ioc32.mp_ilen;
   3795 		mpioc->mp_ibuf	= (caddr_t)(uintptr_t)ioc32.mp_ibuf;
   3796 		mpioc->mp_olen	= (size_t)(uintptr_t)ioc32.mp_olen;
   3797 		mpioc->mp_obuf	= (caddr_t)(uintptr_t)ioc32.mp_obuf;
   3798 		mpioc->mp_alen	= (size_t)(uintptr_t)ioc32.mp_alen;
   3799 		mpioc->mp_abuf	= (caddr_t)(uintptr_t)ioc32.mp_abuf;
   3800 		mpioc->mp_errno	= (int)(uintptr_t)ioc32.mp_errno;
   3801 		break;
   3802 	}
   3803 
   3804 	case DDI_MODEL_NONE:
   3805 		if (ddi_copyin(data, (void*)mpioc, sizeof (*mpioc), mode)) {
   3806 			retval = EFAULT;
   3807 			break;
   3808 		}
   3809 		break;
   3810 
   3811 	default:
   3812 		if (ddi_copyin(data, (void*)mpioc, sizeof (*mpioc), mode)) {
   3813 			retval = EFAULT;
   3814 			break;
   3815 		}
   3816 		break;
   3817 	}
   3818 #else   /* _MULTI_DATAMODEL */
   3819 	if (ddi_copyin(data, (void *)mpioc, sizeof (*mpioc), mode)) {
   3820 		retval = EFAULT;
   3821 	}
   3822 #endif  /* _MULTI_DATAMODEL */
   3823 
   3824 	if (retval) {
   3825 		VHCI_DEBUG(2, (CE_WARN, NULL, "vhci_get_mpiocdata: cmd <%x> "
   3826 		    "iocdata copyin failed", mpioc->mp_cmd));
   3827 	}
   3828 
   3829 	return (retval);
   3830 }
   3831 
   3832 /* ARGSUSED */
   3833 static int
   3834 vhci_is_model_type32(int mode)
   3835 {
   3836 #ifdef  _MULTI_DATAMODEL
   3837 	switch (ddi_model_convert_from(mode & FMODELS)) {
   3838 		case DDI_MODEL_ILP32:
   3839 			return (1);
   3840 		default:
   3841 			return (0);
   3842 	}
   3843 #else   /* _MULTI_DATAMODEL */
   3844 	return (0);
   3845 #endif  /* _MULTI_DATAMODEL */
   3846 }
   3847 
   3848 /*
   3849  * Convenience routine to copy mp_iocdata(32) to user land
   3850  */
   3851 /* ARGSUSED */
   3852 static int
   3853 vhci_mpapi_copyout_iocdata(void *mpioc, void *udata, int mode)
   3854 {
   3855 	int	rval = 0;
   3856 
   3857 	if (vhci_is_model_type32(mode)) {
   3858 		mp_iocdata32_t	*mpioc32;
   3859 
   3860 		mpioc32 = (mp_iocdata32_t *)kmem_zalloc
   3861 		    (sizeof (mp_iocdata32_t), KM_SLEEP);
   3862 		mpioc32->mp_xfer = (uint16_t)((mp_iocdata_t *)mpioc)->mp_xfer;
   3863 		mpioc32->mp_cmd	 = (uint16_t)((mp_iocdata_t *)mpioc)->mp_cmd;
   3864 		mpioc32->mp_flags = (uint16_t)((mp_iocdata_t *)mpioc)->mp_flags;
   3865 		mpioc32->mp_cmd_flags = (uint16_t)((mp_iocdata_t *)
   3866 		    mpioc)->mp_cmd_flags;
   3867 		mpioc32->mp_ilen = (uint32_t)((mp_iocdata_t *)mpioc)->mp_ilen;
   3868 		mpioc32->mp_ibuf = (caddr32_t)((mp_iocdata32_t *)
   3869 		    mpioc)->mp_ibuf;
   3870 		mpioc32->mp_olen = (uint32_t)((mp_iocdata_t *)mpioc)->mp_olen;
   3871 		mpioc32->mp_obuf = (caddr32_t)((mp_iocdata32_t *)
   3872 		    mpioc)->mp_obuf;
   3873 		mpioc32->mp_alen = (uint32_t)((mp_iocdata_t *)mpioc)->mp_alen;
   3874 		mpioc32->mp_abuf = (caddr32_t)((mp_iocdata32_t *)
   3875 		    mpioc)->mp_abuf;
   3876 		mpioc32->mp_errno = (int32_t)((mp_iocdata_t *)mpioc)->mp_errno;
   3877 
   3878 		if (ddi_copyout(mpioc32, udata, sizeof (mp_iocdata32_t), mode)
   3879 		    != 0) {
   3880 			rval = EFAULT;
   3881 		}
   3882 		kmem_free(mpioc32, sizeof (mp_iocdata32_t));
   3883 	} else {
   3884 		/* 64-bit ddicopyout */
   3885 		if (ddi_copyout(mpioc, udata, sizeof (mp_iocdata_t), mode)
   3886 		    != 0) {
   3887 			rval = EFAULT;
   3888 		}
   3889 	}
   3890 
   3891 	return (rval);
   3892 
   3893 }
   3894 
   3895 /*
   3896  * Routine to sync OIDs of MPLU to match with the ssd instance# of the
   3897  * scsi_vhci lun, to accommodate the DINFOCACHE implementation of the plugin.
   3898  * ssd instance# = devi_instance from the dev_info structure.
   3899  * dev_info structure of the scsi_vhci lun is pointed by svl_dip field of
   3900  * scsi_vhci_lun structure.
   3901  */
   3902 /* ARGSUSED */
   3903 static int
   3904 vhci_mpapi_sync_lu_oid_list(struct scsi_vhci *vhci)
   3905 {
   3906 	int			rval = 0;
   3907 	mpapi_item_list_t	*ilist;
   3908 	mpapi_lu_data_t		*lud;
   3909 	mpapi_path_data_t	*pd;
   3910 	scsi_vhci_lun_t		*svl;
   3911 	dev_info_t		*lun_dip;
   3912 
   3913 	ilist = vhci->mp_priv->obj_hdr_list[MP_OBJECT_TYPE_MULTIPATH_LU]->head;
   3914 
   3915 	while (ilist != NULL) {
   3916 		lud = ilist->item->idata;
   3917 		if (lud->valid == 1) {
   3918 			svl = lud->resp;
   3919 			ilist->item->oid.raw_oid =
   3920 			    (uint64_t)ddi_get_instance(svl->svl_dip);
   3921 			lud->prop.id =
   3922 			    (uint64_t)ddi_get_instance(svl->svl_dip);
   3923 		}
   3924 		ilist = ilist->next;
   3925 	}
   3926 
   3927 	ilist = vhci->mp_priv->obj_hdr_list[MP_OBJECT_TYPE_PATH_LU]->head;
   3928 	while (ilist != NULL) {
   3929 		pd = ilist->item->idata;
   3930 		if ((pd->valid == 1) && (MP_GET_MAJOR_FROM_ID((uint64_t)
   3931 		    (pd->prop.logicalUnit.id)) != 0)) {
   3932 			lun_dip = mdi_pi_get_client
   3933 			    ((mdi_pathinfo_t *)(pd->resp));
   3934 			pd->prop.logicalUnit.id =
   3935 			    (uint64_t)ddi_get_instance(lun_dip);
   3936 		}
   3937 		ilist = ilist->next;
   3938 	}
   3939 
   3940 	return (rval);
   3941 }
   3942 
   3943 /*
   3944  * Routine to sync Initiator Port List with what MDI maintains. This means
   3945  * MP API knows about Initiator Ports which don't have a pip.
   3946  */
   3947 /* ARGSUSED */
   3948 int
   3949 vhci_mpapi_sync_init_port_list(dev_info_t *pdip, void *arg)
   3950 {
   3951 	int			init_not_ddi_alloced = 0;
   3952 	struct scsi_vhci	*vhci = arg;
   3953 	char			*init, *init_port_res;
   3954 	mpapi_item_list_t	*init_list;
   3955 	mpapi_initiator_data_t	*initd;
   3956 
   3957 	if ((ddi_prop_lookup_string(DDI_DEV_T_ANY, pdip, DDI_PROP_DONTPASS,
   3958 	    SCSI_ADDR_PROP_INITIATOR_PORT, &init) != DDI_PROP_SUCCESS)) {
   3959 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_mpapi_sync_init_port_list: "
   3960 		    SCSI_ADDR_PROP_INITIATOR_PORT " prop not found"));
   3961 		init = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
   3962 		init_not_ddi_alloced = 1;
   3963 		(void) ddi_pathname(pdip, init);
   3964 	}
   3965 
   3966 	init_port_res = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
   3967 	(void) ddi_pathname(pdip, init_port_res);
   3968 
   3969 	init_list = vhci_get_mpapi_item(vhci, NULL,
   3970 	    MP_OBJECT_TYPE_INITIATOR_PORT, (void*)init_port_res);
   3971 	if (init_list == NULL) {
   3972 		/*
   3973 		 * Need to create init_list entry
   3974 		 * The resource ptr is not really pdip. It will be changed
   3975 		 * in vhci_mpapi_create_item(). The real resource ptr
   3976 		 * is the Port ID. But we pass the pdip, to create OID.
   3977 		 */
   3978 		init_list = vhci_mpapi_create_item(vhci,
   3979 		    MP_OBJECT_TYPE_INITIATOR_PORT, (void*)pdip);
   3980 	}
   3981 
   3982 	initd = init_list->item->idata;
   3983 	initd->valid = 1;
   3984 	(void) strlcpy(initd->prop.portID, init, sizeof (initd->prop.portID));
   3985 
   3986 	if (init_not_ddi_alloced == 1) {
   3987 		kmem_free(init, MAXPATHLEN);
   3988 	} else if (init) {
   3989 		ddi_prop_free(init);
   3990 	}
   3991 	kmem_free(init_port_res, MAXPATHLEN);
   3992 
   3993 	return (DDI_WALK_CONTINUE);
   3994 }
   3995 
   3996 /* ARGSUSED */
   3997 static void
   3998 vhci_mpapi_log_sysevent(dev_info_t *dip, uint64_t *oid, char *subclass)
   3999 {
   4000 	nvlist_t	*attr_list;
   4001 
   4002 	if (nvlist_alloc(&attr_list, NV_UNIQUE_NAME_TYPE,
   4003 	    KM_SLEEP) != DDI_SUCCESS) {
   4004 		goto alloc_failed;
   4005 	}
   4006 
   4007 	if (nvlist_add_uint64_array(attr_list, "oid", oid, 1) != DDI_SUCCESS) {
   4008 		goto error;
   4009 	}
   4010 
   4011 	(void) ddi_log_sysevent(dip, DDI_VENDOR_SUNW, EC_SUN_MP, subclass,
   4012 	    attr_list, NULL, DDI_SLEEP);
   4013 
   4014 error:
   4015 	nvlist_free(attr_list);
   4016 	return;
   4017 
   4018 alloc_failed:
   4019 	VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_mpapi_log_sysevent: "
   4020 	    "Unable to send sysevent"));
   4021 
   4022 }
   4023 
   4024 /* ARGSUSED */
   4025 void
   4026 vhci_mpapi_set_path_state(dev_info_t *vdip, mdi_pathinfo_t *pip, int state)
   4027 {
   4028 	struct scsi_vhci	*vhci;
   4029 	struct scsi_vhci_lun	*svl;
   4030 	scsi_vhci_priv_t	*svp;
   4031 	mpapi_item_list_t	*ilist, *lu_list;
   4032 	mpapi_path_data_t	*pp;
   4033 	mpapi_lu_data_t		*ld;
   4034 
   4035 	vhci = ddi_get_soft_state(vhci_softstate, ddi_get_instance(vdip));
   4036 
   4037 	ilist = vhci_get_mpapi_item(vhci, NULL, MP_OBJECT_TYPE_PATH_LU, pip);
   4038 
   4039 	if (ilist != NULL) {
   4040 		mutex_enter(&ilist->item->item_mutex);
   4041 		pp = ilist->item->idata;
   4042 		pp->prop.pathState = state;
   4043 		pp->valid = 1;
   4044 	} else {
   4045 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_mpapi_set_path_state: "
   4046 		    "pip(%p) not found", (void *)pip));
   4047 		return;
   4048 	}
   4049 
   4050 	/*
   4051 	 * Check if the pathinfo is uninitialized(destroyed).
   4052 	 */
   4053 	if (state == MP_DRVR_PATH_STATE_UNINIT) {
   4054 		pp->hide = 1;
   4055 		VHCI_DEBUG(6, (CE_NOTE, NULL, "vhci_mpapi_set_path_state: "
   4056 		    "path(pip: %p) is uninited(destroyed).",
   4057 		    (void *)pip));
   4058 	} else {
   4059 		pp->hide = 0;
   4060 	}
   4061 	/*
   4062 	 * Find if there are any paths at all to the lun
   4063 	 */
   4064 	if ((state == MP_DRVR_PATH_STATE_REMOVED) || (state ==
   4065 	    MP_DRVR_PATH_STATE_PATH_ERR) || (state ==
   4066 	    MP_DRVR_PATH_STATE_LU_ERR) || (state ==
   4067 	    MP_DRVR_PATH_STATE_UNKNOWN) || pp->hide) {
   4068 		pp->valid = 0;
   4069 		VHCI_DEBUG(6, (CE_NOTE, NULL, "vhci_mpapi_set_path_state: "
   4070 		    "path(pip: %p) is not okay state.  Set to invalid.",
   4071 		    (void *)pip));
   4072 		svp = (scsi_vhci_priv_t *)mdi_pi_get_vhci_private(pip);
   4073 		svl = svp->svp_svl;
   4074 		/*
   4075 		 * Update the AccessState of related MPAPI TPGs
   4076 		 * This takes care of a special case where a path goes offline
   4077 		 * & the TPG accessState may need an update from
   4078 		 * Active/Standby to Unavailable.
   4079 		 */
   4080 		if (!SCSI_FAILOVER_IS_TPGS(svl->svl_fops)) {
   4081 			(void) vhci_mpapi_update_tpg_acc_state_for_lu(vhci,
   4082 			    svl);
   4083 		}
   4084 
   4085 		/*
   4086 		 * Following means the lun is offline
   4087 		 */
   4088 		if (vhci_mpapi_chk_last_path(pip) == -1) {
   4089 			lu_list = vhci_get_mpapi_item(vhci, NULL,
   4090 			    MP_OBJECT_TYPE_MULTIPATH_LU, (void *)svl);
   4091 			if (lu_list != NULL) {
   4092 				ld = lu_list->item->idata;
   4093 				ld->valid = 0;
   4094 				VHCI_DEBUG(6, (CE_NOTE, NULL,
   4095 				    "vhci_mpapi_set_path_state: "
   4096 				    " Invalidated LU(%s)", svl->svl_lun_wwn));
   4097 			}
   4098 		}
   4099 	}
   4100 	mutex_exit(&ilist->item->item_mutex);
   4101 
   4102 }
   4103 
   4104 /* ARGSUSED */
   4105 static mpapi_item_list_t *
   4106 vhci_mpapi_match_pip(struct scsi_vhci *vhci, mpapi_item_list_t *ilist,
   4107     void *res)
   4108 {
   4109 	mpapi_path_data_t	*pd;
   4110 	scsi_vhci_lun_t		*this_svl;
   4111 	mdi_pathinfo_t		*this_pip;
   4112 	char			*this_iport;
   4113 	char			*this_tport;
   4114 	char			*pname;
   4115 
   4116 	this_pip = (mdi_pathinfo_t *)res;
   4117 	if ((this_pip == NULL) || (ilist == NULL)) {
   4118 		return (NULL);
   4119 	}
   4120 
   4121 	this_iport = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
   4122 	(void) ddi_pathname(mdi_pi_get_phci(this_pip), this_iport);
   4123 
   4124 	if (mdi_prop_lookup_string(this_pip, SCSI_ADDR_PROP_TARGET_PORT,
   4125 	    &this_tport) != DDI_PROP_SUCCESS) {
   4126 		/* XXX: target-port prop not found */
   4127 		this_tport = (char *)mdi_pi_get_addr(this_pip);
   4128 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_mpapi_match_pip: "
   4129 		    "mdi_prop_lookup_string() returned failure; "
   4130 		    "Hence this_tport = %p", (void *)this_tport));
   4131 	}
   4132 
   4133 	this_svl = mdi_client_get_vhci_private(mdi_pi_get_client(this_pip));
   4134 
   4135 	pname = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
   4136 	(void) strlcat(pname, this_iport, MAXPATHLEN);
   4137 	(void) strlcat(pname, this_tport, MAXPATHLEN);
   4138 	(void) strlcat(pname, this_svl->svl_lun_wwn, MAXPATHLEN);
   4139 	kmem_free(this_iport, MAXPATHLEN);
   4140 
   4141 	while (ilist != NULL) {
   4142 		pd = (mpapi_path_data_t *)(ilist->item->idata);
   4143 		if ((pd != NULL) && (strncmp
   4144 		    (pd->path_name, pname, strlen(pname)) == 0)) {
   4145 			VHCI_DEBUG(6, (CE_WARN, NULL, "vhci_mpapi_match_pip: "
   4146 			    "path_name = %s", pd->path_name));
   4147 			kmem_free(pname, MAXPATHLEN);
   4148 			return (ilist);
   4149 		}
   4150 		ilist = ilist->next;
   4151 	}
   4152 
   4153 	kmem_free(pname, MAXPATHLEN);
   4154 	return (NULL);
   4155 }
   4156 
   4157 /* ARGSUSED */
   4158 static
   4159 mpapi_item_list_t *vhci_mpapi_match_lu(struct scsi_vhci *vhci,
   4160     mpapi_item_list_t *ilist, void *res)
   4161 {
   4162 	mpapi_lu_data_t		*ld;
   4163 	scsi_vhci_lun_t		*this_svl;
   4164 
   4165 	this_svl = (scsi_vhci_lun_t *)res;
   4166 	if ((this_svl == NULL) || (ilist == NULL)) {
   4167 		return (NULL);
   4168 	}
   4169 
   4170 	while (ilist != NULL) {
   4171 		ld = (mpapi_lu_data_t *)(ilist->item->idata);
   4172 		if ((ld != NULL) && (strncmp
   4173 		    (ld->prop.name, this_svl->svl_lun_wwn,
   4174 		    strlen(this_svl->svl_lun_wwn)) == 0)) {
   4175 			VHCI_DEBUG(6, (CE_WARN, NULL, "vhci_mpapi_match_lu: "
   4176 			    "this_wwn = %s", this_svl->svl_lun_wwn));
   4177 			return (ilist);
   4178 		}
   4179 		ilist = ilist->next;
   4180 	}
   4181 
   4182 	return (NULL);
   4183 }
   4184 
   4185 /*
   4186  * Routine to handle TPG AccessState Change - Called after each LU failover
   4187  */
   4188 int
   4189 vhci_mpapi_update_tpg_acc_state_for_lu(struct scsi_vhci *vhci,
   4190     scsi_vhci_lun_t *vlun)
   4191 {
   4192 	int			rval = 0;
   4193 	mpapi_item_list_t	*lu_list, *path_list, *tpg_list;
   4194 	mpapi_lu_data_t		*lu_data;
   4195 	mpapi_path_data_t	*path_data;
   4196 	mpapi_tpg_data_t	*tpg_data;
   4197 	char			*tgt_port;
   4198 
   4199 	lu_list = vhci_get_mpapi_item(vhci, NULL, MP_OBJECT_TYPE_MULTIPATH_LU,
   4200 	    (void *)vlun);
   4201 	if (lu_list == NULL) {
   4202 		return (-1);
   4203 	}
   4204 	lu_data = lu_list->item->idata;
   4205 	if (lu_data == NULL) {
   4206 		return (-1);
   4207 	}
   4208 	lu_data->resp = vlun;
   4209 	lu_data->valid = 1;
   4210 
   4211 	/*
   4212 	 * For each "pclass of PATH" and "pclass of TPG" match of this LU,
   4213 	 * Update the TPG AccessState to reflect the state of the path.
   4214 	 * Exit the inner loop after the 1st successful ACTIVE/STANDBY update
   4215 	 * is made, because subsequent matches also lead to the same TPG.
   4216 	 */
   4217 	tpg_list = lu_data->tpg_list->head;
   4218 	while (tpg_list != NULL) {
   4219 		tpg_data = tpg_list->item->idata;
   4220 		path_list = lu_data->path_list->head;
   4221 		while (path_list != NULL) {
   4222 			path_data = path_list->item->idata;
   4223 			/*
   4224 			 * path class is not reliable for ALUA if the
   4225 			 * vhci has done the update on one of the class
   4226 			 * but ignore to update on another one.
   4227 			 */
   4228 			tgt_port = NULL;
   4229 			if (path_data->valid == 1 &&
   4230 			    (mdi_prop_lookup_string(path_data->resp,
   4231 			    SCSI_ADDR_PROP_TARGET_PORT,
   4232 			    &tgt_port) == DDI_PROP_SUCCESS) &&
   4233 			    tgt_port != NULL &&
   4234 			    (vhci_mpapi_check_tp_in_tpg(
   4235 			    tpg_data, tgt_port) == 1)) {
   4236 				VHCI_DEBUG(4, (CE_NOTE, NULL,
   4237 				    "vhci_mpapi_update_tpg_acc_state_"
   4238 				    "for_ lu: Operating on LUN(%s), "
   4239 				    " PATH(%p), TPG(%x: %s)\n",
   4240 				    lu_data->prop.name, path_data->resp,
   4241 				    tpg_data->prop.tpgId,
   4242 				    tpg_data->pclass));
   4243 				if (MDI_PI_IS_ONLINE(path_data->resp)) {
   4244 					tpg_data->prop.accessState =
   4245 					    MP_DRVR_ACCESS_STATE_ACTIVE;
   4246 					break;
   4247 				} else if (MDI_PI_IS_STANDBY(path_data->resp)) {
   4248 					tpg_data->prop.accessState =
   4249 					    MP_DRVR_ACCESS_STATE_STANDBY;
   4250 					break;
   4251 				} else {
   4252 					tpg_data->prop.accessState =
   4253 					    MP_DRVR_ACCESS_STATE_UNAVAILABLE;
   4254 				}
   4255 			}
   4256 			path_list = path_list->next;
   4257 		}
   4258 		tpg_list = tpg_list->next;
   4259 	}
   4260 
   4261 	return (rval);
   4262 }
   4263 
   4264 int
   4265 vhci_mpapi_get_vhci(dev_info_t *vdip, void *ptr2vhci)
   4266 {
   4267 	struct scsi_vhci	*local_vhci;
   4268 
   4269 	if (strncmp("scsi_vhci", ddi_get_name(vdip),
   4270 	    strlen("scsi_vhci")) == 0) {
   4271 		local_vhci = ddi_get_soft_state(vhci_softstate,
   4272 		    ddi_get_instance(vdip));
   4273 		bcopy(&local_vhci, ptr2vhci, sizeof (local_vhci));
   4274 		return (DDI_WALK_TERMINATE);
   4275 	}
   4276 
   4277 	return (DDI_WALK_CONTINUE);
   4278 
   4279 }
   4280 
   4281 /* ARGSUSED */
   4282 void *
   4283 vhci_mpapi_get_rel_tport_pair(struct scsi_vhci *vhci, mpapi_list_header_t *list,
   4284     void *tgt_port, uint32_t rel_tid)
   4285 {
   4286 	mpapi_item_list_t	*ilist;
   4287 	mpapi_tport_data_t	*tpd;
   4288 
   4289 	if (list == NULL) {
   4290 		/*
   4291 		 * Since the listhead is null, the search is being
   4292 		 * performed in implicit mode - that is to use the
   4293 		 * level one list.
   4294 		 */
   4295 		ilist = vhci->mp_priv->obj_hdr_list[MP_OBJECT_TYPE_TARGET_PORT]
   4296 		    ->head;
   4297 	} else {
   4298 		/*
   4299 		 * The search is being performed on a sublist within
   4300 		 * one of the toplevel list items. Use the listhead
   4301 		 * that is passed in.
   4302 		 */
   4303 		ilist = list->head;
   4304 	}
   4305 
   4306 	if (tgt_port == NULL) {
   4307 		VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_get_mpapi_item: "
   4308 		    " Got Target Port w/ NULL resource"));
   4309 		return (NULL);
   4310 	}
   4311 
   4312 	while (ilist) {
   4313 		tpd = (mpapi_tport_data_t *)ilist->item->idata;
   4314 		if ((strncmp(tpd->resp, tgt_port, strlen(tgt_port)) == 0) &&
   4315 		    (tpd->prop.relativePortID == rel_tid)) {
   4316 			/* Match */
   4317 			return ((void*)ilist);
   4318 		} else {
   4319 			ilist = ilist->next;
   4320 		}
   4321 	}
   4322 
   4323 	return (NULL);
   4324 }
   4325 
   4326 /*
   4327  * Returns 0, if 2 more paths are available to the lun;
   4328  * Returns 1, if ONLY 1 path is available to the lun;
   4329  * Return -1 for all other cases.
   4330  */
   4331 static int
   4332 vhci_mpapi_chk_last_path(mdi_pathinfo_t *pip)
   4333 {
   4334 	dev_info_t	*pdip = NULL, *cdip = NULL;
   4335 	int		count = 0, circular;
   4336 	mdi_pathinfo_t	*ret_pip;
   4337 
   4338 	if (pip == NULL) {
   4339 		return (-1);
   4340 	} else {
   4341 		pdip = mdi_pi_get_phci(pip);
   4342 		cdip = mdi_pi_get_client(pip);
   4343 	}
   4344 
   4345 	if ((pdip == NULL) || (cdip == NULL)) {
   4346 		return (-1);
   4347 	}
   4348 
   4349 	ndi_devi_enter(cdip, &circular);
   4350 	ret_pip = mdi_get_next_phci_path(cdip, NULL);
   4351 
   4352 	while ((ret_pip != NULL) && (count < 2)) {
   4353 		mdi_pi_lock(ret_pip);
   4354 		if ((MDI_PI_IS_ONLINE(ret_pip) ||
   4355 		    MDI_PI_IS_STANDBY(ret_pip) ||
   4356 		    MDI_PI_IS_INIT(ret_pip)) &&
   4357 		    !(MDI_PI_IS_DISABLE(ret_pip) ||
   4358 		    MDI_PI_IS_TRANSIENT(ret_pip) ||
   4359 		    MDI_PI_FLAGS_IS_DEVICE_REMOVED(ret_pip))) {
   4360 			count++;
   4361 		}
   4362 		mdi_pi_unlock(ret_pip);
   4363 		ret_pip = mdi_get_next_phci_path(cdip, ret_pip);
   4364 	}
   4365 	ndi_devi_exit(cdip, circular);
   4366 
   4367 	if (count > 1) {
   4368 		return (0);
   4369 	} else if (count == 1) {
   4370 		return (1);
   4371 	}
   4372 
   4373 	return (-1);
   4374 }
   4375