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