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