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