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