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