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