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