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