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