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