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 2009 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 
4198 	lu_list = vhci_get_mpapi_item(vhci, NULL, MP_OBJECT_TYPE_MULTIPATH_LU,
4199 	    (void *)vlun);
4200 	if (lu_list == NULL) {
4201 		return (-1);
4202 	}
4203 	lu_data = lu_list->item->idata;
4204 	if (lu_data == NULL) {
4205 		return (-1);
4206 	}
4207 	lu_data->resp = vlun;
4208 	lu_data->valid = 1;
4209 
4210 	/*
4211 	 * For each "pclass of PATH" and "pclass of TPG" match of this LU,
4212 	 * Update the TPG AccessState to reflect the state of the path.
4213 	 * Exit the inner loop after the 1st successful ACTIVE/STANDBY update
4214 	 * is made, because subsequent matches also lead to the same TPG.
4215 	 */
4216 	tpg_list = lu_data->tpg_list->head;
4217 	while (tpg_list != NULL) {
4218 		tpg_data = tpg_list->item->idata;
4219 		path_list = lu_data->path_list->head;
4220 		while (path_list != NULL) {
4221 			path_data = path_list->item->idata;
4222 			if (strncmp(path_data->pclass, tpg_data->pclass,
4223 			    strlen(tpg_data->pclass)) == 0) {
4224 				if (path_data->valid == 1) {
4225 					VHCI_DEBUG(4, (CE_NOTE, NULL,
4226 					    "vhci_mpapi_update_tpg_acc_state_"
4227 					    "for_ lu: Operating on LUN(%s), "
4228 					    " PATH(%p), TPG(%x: %s)\n",
4229 					    lu_data->prop.name, path_data->resp,
4230 					    tpg_data->prop.tpgId,
4231 					    tpg_data->pclass));
4232 					if (MDI_PI_IS_ONLINE(path_data->resp)) {
4233 						tpg_data->prop.accessState =
4234 						    MP_DRVR_ACCESS_STATE_ACTIVE;
4235 						break;
4236 					} else if (MDI_PI_IS_STANDBY(
4237 					    path_data->resp)) {
4238 					tpg_data->prop.accessState =
4239 					    MP_DRVR_ACCESS_STATE_STANDBY;
4240 						break;
4241 					} else {
4242 					tpg_data->prop.accessState =
4243 					    MP_DRVR_ACCESS_STATE_UNAVAILABLE;
4244 					}
4245 				} else {
4246 					/*
4247 					 * if path is not valid any more,
4248 					 * mark the associated tpg as
4249 					 * unavailable.
4250 					 */
4251 					tpg_data->prop.accessState =
4252 					    MP_DRVR_ACCESS_STATE_UNAVAILABLE;
4253 				}
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