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