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