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] = NULL; 1690 1691 if (ddi_copyout(output_data, (void *)mpioc->mp_obuf, 1692 (sizeof (uint64_t)), mode) != 0) { 1693 VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_get_prop_lb_list: " 1694 "ddi_copyout() FAILED")); 1695 mpioc->mp_errno = EFAULT; 1696 rval = EINVAL; 1697 } else { 1698 mpioc->mp_errno = 0; 1699 } 1700 1701 return (rval); 1702 } 1703 1704 /* ARGSUSED */ 1705 static int 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 /* 2758 * We cant use ddi_get_instance(svl->svl_dip) at this 2759 * point because the dip is not yet in DS_READY state. 2760 */ 2761 item->oid.raw_oid = 2762 vhci_mpapi_create_oid(vhci->mp_priv, obj_type); 2763 2764 lu = kmem_zalloc(sizeof (mpapi_lu_data_t), KM_SLEEP); 2765 lu->resp = res; 2766 lu->prop.id = (uint64_t)item->oid.raw_oid; 2767 /* 2768 * XXX: luGroupID is currently unsupported 2769 */ 2770 lu->prop.luGroupID = 0xFFFFFFFF; 2771 2772 (void) strlcpy(lu->prop.name, svl->svl_lun_wwn, 2773 sizeof (lu->prop.name)); 2774 2775 /* 2776 * deviceFileName field is currently not used. 2777 * Set to an empty string. 2778 */ 2779 lu->prop.deviceFileName[0] = '\0'; 2780 2781 if ((svl != NULL) && 2782 (SCSI_FAILOVER_IS_ASYM(svl) || 2783 SCSI_FAILOVER_IS_TPGS(svl->svl_fops))) { 2784 lu->prop.asymmetric = 1; 2785 } 2786 2787 lu->prop.autoFailbackEnabled = 2788 ((VHCI_CONF_FLAGS_AUTO_FAILBACK & vhci-> 2789 vhci_conf_flags) ? 1 : 0); 2790 2791 if (svl->svl_lb_policy_save == LOAD_BALANCE_NONE) { 2792 lu->prop.currentLoadBalanceType = 2793 MP_DRVR_LOAD_BALANCE_TYPE_NONE; 2794 } else if (svl->svl_lb_policy_save == LOAD_BALANCE_RR) { 2795 lu->prop.currentLoadBalanceType = 2796 MP_DRVR_LOAD_BALANCE_TYPE_ROUNDROBIN; 2797 } else if (svl->svl_lb_policy_save == 2798 LOAD_BALANCE_LBA) { 2799 lu->prop.currentLoadBalanceType = 2800 MP_DRVR_LOAD_BALANCE_TYPE_LBA_REGION; 2801 } else { 2802 /* 2803 * We still map Load Balance Type to UNKNOWN 2804 * although "none" also maps to the same case. 2805 * MPAPI spec does not have a "NONE" LB type. 2806 */ 2807 lu->prop.currentLoadBalanceType = 2808 MP_DRVR_LOAD_BALANCE_TYPE_UNKNOWN; 2809 } 2810 /* 2811 * Allocate header lists for cross reference 2812 */ 2813 lu->path_list = vhci_mpapi_create_list_head(); 2814 lu->tpg_list = vhci_mpapi_create_list_head(); 2815 item->idata = (void *)lu; 2816 vhci_mpapi_set_lu_valid(vhci, item, 1); 2817 } 2818 break; 2819 2820 case MP_OBJECT_TYPE_PATH_LU: 2821 { 2822 mpapi_path_data_t *path; 2823 mdi_pathinfo_t *pip = res; 2824 scsi_vhci_lun_t *svl; 2825 char *iport, *tport; 2826 2827 item->oid.raw_oid = 2828 vhci_mpapi_create_oid(vhci->mp_priv, obj_type); 2829 path = kmem_zalloc( 2830 sizeof (mpapi_path_data_t), KM_SLEEP); 2831 pname = kmem_zalloc(MAXPATHLEN, KM_SLEEP); 2832 2833 iport = kmem_zalloc(MAXPATHLEN, KM_SLEEP); 2834 (void) ddi_pathname(mdi_pi_get_phci(pip), iport); 2835 2836 if (mdi_prop_lookup_string(pip, 2837 SCSI_ADDR_PROP_TARGET_PORT, &tport) != 2838 DDI_PROP_SUCCESS) { 2839 /* XXX: target-port prop not found */ 2840 tport = (char *)mdi_pi_get_addr(pip); 2841 VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_mpapi_" 2842 "create_item: mdi_prop_lookup_string() " 2843 "returned failure; ")); 2844 } 2845 2846 svl = mdi_client_get_vhci_private 2847 (mdi_pi_get_client(pip)); 2848 2849 (void) strlcat(pname, iport, MAXPATHLEN); 2850 (void) strlcat(pname, tport, MAXPATHLEN); 2851 (void) strlcat(pname, svl->svl_lun_wwn, MAXPATHLEN); 2852 kmem_free(iport, MAXPATHLEN); 2853 2854 path->resp = res; 2855 path->path_name = pname; 2856 path->valid = 1; 2857 path->hide = 0; 2858 path->prop.id = item->oid.raw_oid; 2859 item->idata = (void *)path; 2860 vhci_mpapi_log_sysevent(vhci->vhci_dip, 2861 &(item->oid.raw_oid), ESC_SUN_MP_PATH_ADD); 2862 } 2863 break; 2864 2865 case MP_OBJECT_TYPE_DEVICE_PRODUCT: 2866 VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_mpapi_create_item:" 2867 " DEVICE PRODUCT not handled here.")); 2868 break; 2869 2870 default: 2871 /* 2872 * This should not happen 2873 */ 2874 VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_mpapi_create_item:" 2875 "Got Unsupported OBJECT TYPE")); 2876 return (NULL); 2877 } 2878 2879 (void) vhci_mpapi_add_to_list(vhci->mp_priv->obj_hdr_list[obj_type], 2880 ilist); 2881 return (ilist); 2882 } 2883 2884 /* 2885 * Local routine to allocate mpapi list header block 2886 */ 2887 /* ARGSUSED */ 2888 static mpapi_list_header_t * 2889 vhci_mpapi_create_list_head() 2890 { 2891 mpapi_list_header_t *lh; 2892 2893 lh = kmem_zalloc(sizeof (mpapi_list_header_t), KM_SLEEP); 2894 lh->head = lh->tail = NULL; 2895 return (lh); 2896 } 2897 2898 /* 2899 * Routine to create Level 1 mpapi_private data structure and also 2900 * establish cross references between the resources being managed 2901 */ 2902 /* ARGSUSED */ 2903 void 2904 vhci_update_mpapi_data(struct scsi_vhci *vhci, scsi_vhci_lun_t *vlun, 2905 mdi_pathinfo_t *pip) 2906 { 2907 char *tmp_wwn = NULL, *init = NULL, *path_class; 2908 dev_info_t *pdip; 2909 mpapi_item_list_t *lu_list, *path_list, *init_list, *tgt_list; 2910 mpapi_item_list_t *tp_path_list, *init_path_list, *lu_path_list; 2911 mpapi_lu_data_t *ld; 2912 mpapi_path_data_t *pd; 2913 mpapi_tport_data_t *tpd; 2914 mpapi_initiator_data_t *initd; 2915 int path_class_not_mdi_alloced = 0; 2916 2917 VHCI_DEBUG(6, (CE_NOTE, NULL, "vhci_update_mpapi_data: vhci: %p, " 2918 "vlun: %p, pip: %p\n", (void *)vhci, (void *)vlun, (void *)pip)); 2919 2920 /* 2921 * Check that the lun is not a TPGS device 2922 * TPGS devices create the same information in another routine. 2923 */ 2924 if (SCSI_FAILOVER_IS_TPGS(vlun->svl_fops)) { 2925 return; 2926 } 2927 /* 2928 * LEVEL 1 - Actions: 2929 * Check if the appropriate resource pointers already 2930 * exist in the Level 1 list and add them if they are new. 2931 */ 2932 2933 /* 2934 * Build MP LU list 2935 */ 2936 lu_list = vhci_get_mpapi_item(vhci, NULL, 2937 MP_OBJECT_TYPE_MULTIPATH_LU, (void*)vlun); 2938 if (lu_list == NULL) { 2939 /* Need to create lu_list entry */ 2940 lu_list = vhci_mpapi_create_item(vhci, 2941 MP_OBJECT_TYPE_MULTIPATH_LU, (void*)vlun); 2942 } else { 2943 /* 2944 * Matched this lu w/ an existing one in current lu list. 2945 * SAME LUN came online!! So, update the resp in main list. 2946 */ 2947 ld = lu_list->item->idata; 2948 vhci_mpapi_set_lu_valid(vhci, lu_list->item, 1); 2949 ld->resp = vlun; 2950 } 2951 2952 /* 2953 * Find out the "path-class" property on the pip 2954 */ 2955 if (mdi_prop_lookup_string(pip, "path-class", &path_class) 2956 != DDI_PROP_SUCCESS) { 2957 /* XXX: path-class prop not found */ 2958 path_class = kmem_zalloc(MPAPI_SCSI_MAXPCLASSLEN, KM_SLEEP); 2959 (void) strlcpy(path_class, "NONE", MPAPI_SCSI_MAXPCLASSLEN); 2960 VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_update_mpapi_data: " 2961 "mdi_prop_lookup_string() returned failure; " 2962 "Hence path_class = NONE")); 2963 path_class_not_mdi_alloced = 1; 2964 } 2965 2966 /* 2967 * Build Path LU list 2968 */ 2969 path_list = vhci_get_mpapi_item(vhci, NULL, 2970 MP_OBJECT_TYPE_PATH_LU, (void*)pip); 2971 if (path_list == NULL) { 2972 /* Need to create path_list entry */ 2973 path_list = vhci_mpapi_create_item(vhci, 2974 MP_OBJECT_TYPE_PATH_LU, (void*)pip); 2975 } else { 2976 /* 2977 * Matched this pip w/ an existing one in current pip list. 2978 * SAME PATH came online!! So, update the resp in main list. 2979 */ 2980 pd = path_list->item->idata; 2981 pd->valid = 1; 2982 pd->hide = 0; 2983 pd->resp = pip; 2984 } 2985 2986 if (MDI_PI_IS_ONLINE(pip)) { 2987 vhci_mpapi_set_path_state(vhci->vhci_dip, pip, 2988 MP_DRVR_PATH_STATE_ACTIVE); 2989 } else if (MDI_PI_IS_STANDBY(pip)) { 2990 vhci_mpapi_set_path_state(vhci->vhci_dip, pip, 2991 MP_DRVR_PATH_STATE_PASSIVE); 2992 } else { 2993 vhci_mpapi_set_path_state(vhci->vhci_dip, pip, 2994 MP_DRVR_PATH_STATE_UNKNOWN); 2995 } 2996 2997 /* 2998 * Build Initiator Port list 2999 */ 3000 pdip = mdi_pi_get_phci(pip); 3001 init = kmem_zalloc(MAXPATHLEN, KM_SLEEP); 3002 (void) ddi_pathname(pdip, init); 3003 3004 init_list = vhci_get_mpapi_item(vhci, NULL, 3005 MP_OBJECT_TYPE_INITIATOR_PORT, (void*)init); 3006 if (init_list == NULL) { 3007 /* 3008 * Need to create init_list entry 3009 * The resource ptr is no really pdip. It will be changed 3010 * in vhci_mpapi_create_item(). The real resource ptr 3011 * is the Port ID. But we pass the pdip, to create OID. 3012 */ 3013 init_list = vhci_mpapi_create_item(vhci, 3014 MP_OBJECT_TYPE_INITIATOR_PORT, (void*)pdip); 3015 } else { 3016 initd = init_list->item->idata; 3017 initd->valid = 1; 3018 } 3019 kmem_free(init, MAXPATHLEN); 3020 3021 /* 3022 * Build Target Port list 3023 * Can get the tdip: tdip = mdi_pi_get_client(pip); 3024 * But what's the use? We want TARGET_PORT. 3025 * So try getting Target Port's WWN which is unique per port. 3026 */ 3027 tmp_wwn = NULL; 3028 if (mdi_prop_lookup_string(pip, SCSI_ADDR_PROP_TARGET_PORT, 3029 &tmp_wwn) != DDI_PROP_SUCCESS) { 3030 /* XXX: target-port prop not found */ 3031 tmp_wwn = (char *)mdi_pi_get_addr(pip); 3032 VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_update_mpapi_data: " 3033 "mdi_prop_lookup_string() returned failure; " 3034 "Hence tmp_wwn = %p", (void *)tmp_wwn)); 3035 } 3036 3037 tgt_list = vhci_get_mpapi_item(vhci, NULL, 3038 MP_OBJECT_TYPE_TARGET_PORT, (void*)tmp_wwn); 3039 if (tgt_list == NULL) { 3040 /* Need to create tgt_list entry */ 3041 tgt_list = vhci_mpapi_create_item(vhci, 3042 MP_OBJECT_TYPE_TARGET_PORT, (void*)tmp_wwn); 3043 } else { 3044 tpd = tgt_list->item->idata; 3045 tpd->valid = 1; 3046 } 3047 3048 /* 3049 * LEVEL 2 - Actions: 3050 * Since all the Object type item lists are updated to account 3051 * for the new resources, now lets cross-reference these 3052 * resources (mainly through paths) to maintain the 3053 * relationship between them. 3054 */ 3055 3056 ld = (mpapi_lu_data_t *)lu_list->item->idata; 3057 if (vhci_get_mpapi_item(vhci, ld->path_list, 3058 MP_OBJECT_TYPE_PATH_LU, (void*)pip) == NULL) { 3059 lu_path_list = kmem_zalloc(sizeof (mpapi_item_list_t), 3060 KM_SLEEP); 3061 lu_path_list->item = path_list->item; 3062 (void) vhci_mpapi_add_to_list(ld->path_list, lu_path_list); 3063 } 3064 3065 initd = (mpapi_initiator_data_t *)init_list->item->idata; 3066 if (vhci_get_mpapi_item(vhci, initd->path_list, 3067 MP_OBJECT_TYPE_PATH_LU, (void*)pip) == NULL) { 3068 init_path_list = kmem_zalloc(sizeof (mpapi_item_list_t), 3069 KM_SLEEP); 3070 init_path_list->item = path_list->item; 3071 (void) vhci_mpapi_add_to_list(initd->path_list, init_path_list); 3072 } 3073 3074 tpd = (mpapi_tport_data_t *)tgt_list->item->idata; 3075 if (vhci_get_mpapi_item(vhci, tpd->path_list, 3076 MP_OBJECT_TYPE_PATH_LU, (void*)pip) == NULL) { 3077 tp_path_list = kmem_zalloc( 3078 sizeof (mpapi_item_list_t), KM_SLEEP); 3079 tp_path_list->item = path_list->item; 3080 (void) vhci_mpapi_add_to_list(tpd->path_list, tp_path_list); 3081 } 3082 3083 /* 3084 * Level-1: Fill-out Path Properties now, since we got all details. 3085 * Actually, It is a structure copy, rather than just filling details. 3086 */ 3087 pd = path_list->item->idata; 3088 (void) strlcpy(pd->pclass, path_class, sizeof (pd->pclass)); 3089 bcopy(&(ld->prop), &(pd->prop.logicalUnit), 3090 sizeof (struct mp_logical_unit_prop)); 3091 bcopy(&(initd->prop), &(pd->prop.initPort), 3092 sizeof (struct mp_init_port_prop)); 3093 bcopy(&(tpd->prop), &(pd->prop.targetPort), 3094 sizeof (struct mp_target_port_prop)); 3095 3096 vhci_mpapi_synthesize_tpg_data(vhci, vlun, pip); 3097 3098 if (path_class_not_mdi_alloced == 1) { 3099 kmem_free(path_class, MPAPI_SCSI_MAXPCLASSLEN); 3100 } 3101 3102 } 3103 3104 /* 3105 * Routine to search (& return if found) a TPG object with a specified 3106 * tpg_id and rel_tp_id for a specified vlun structure. Returns NULL 3107 * if either TPG object or the lu item is not found. 3108 * This routine is used for TPGS(ALUA) devices. 3109 */ 3110 /* ARGSUSED */ 3111 static mpapi_item_list_t * 3112 vhci_mpapi_get_alua_item(struct scsi_vhci *vhci, void *vlun, void *tpg_id, 3113 void *tp) 3114 { 3115 mpapi_list_header_t *this_tpghdr; 3116 mpapi_item_list_t *tpglist, *this_lulist, *this_tpglist; 3117 mpapi_tpg_data_t *tpgdata, *this_tpgdata; 3118 3119 VHCI_DEBUG(6, (CE_NOTE, NULL, "vhci_mpapi_get_alua_item: ENTER: vlun=" 3120 "%p, tpg_id=%s, tp=%s\n", 3121 (void *)vlun, (char *)tpg_id, (char *)tp)); 3122 3123 /* 3124 * Check if target port is already in any existing group 3125 */ 3126 tpglist = vhci->mp_priv->obj_hdr_list[MP_OBJECT_TYPE_TARGET_PORT_GROUP] 3127 ->head; 3128 while (tpglist != NULL) { 3129 tpgdata = tpglist->item->idata; 3130 3131 if ((tpgdata) && 3132 (vhci_mpapi_check_tp_in_tpg(tpgdata, tp) == 1) && 3133 (strcmp(tpgdata->resp, tpg_id) == 0)) { 3134 return (tpglist); 3135 } else { 3136 tpglist = tpglist->next; 3137 } 3138 } 3139 3140 /* 3141 * If target port is not existed, search TPG associated 3142 * with this LU to see if this LU has a TPG with the same 3143 * tpg_id. 3144 */ 3145 this_lulist = vhci_get_mpapi_item(vhci, NULL, 3146 MP_OBJECT_TYPE_MULTIPATH_LU, vlun); 3147 if (this_lulist != NULL) { 3148 this_tpghdr = ((mpapi_lu_data_t *)(this_lulist->item->idata)) 3149 ->tpg_list; 3150 this_tpglist = this_tpghdr->head; 3151 while (this_tpglist != NULL) { 3152 this_tpgdata = this_tpglist->item->idata; 3153 if ((this_tpgdata) && 3154 (strcmp(this_tpgdata->resp, tpg_id) == 0)) { 3155 return (this_tpglist); 3156 } else { 3157 this_tpglist = this_tpglist->next; 3158 } 3159 } 3160 } 3161 3162 VHCI_DEBUG(4, (CE_WARN, NULL, "vhci_mpapi_get_tpg_item: Returns NULL")); 3163 3164 return (NULL); 3165 } 3166 3167 /* 3168 * Routine to search (& return if found) a TPG object with a specified 3169 * accessState for a specified vlun structure. Returns NULL if either 3170 * TPG object or the lu item is not found. 3171 * This routine is used for NON-TPGS devices. 3172 */ 3173 /* ARGSUSED */ 3174 static mpapi_item_list_t * 3175 vhci_mpapi_get_tpg_item(struct scsi_vhci *vhci, uint32_t acc_state, void *vlun, 3176 char *pclass, void *tp) 3177 { 3178 mpapi_list_header_t *tpghdr, *this_tpghdr; 3179 mpapi_item_list_t *lulist, *tpglist, *this_lulist, *this_tpglist; 3180 mpapi_tpg_data_t *tpgdata, *this_tpgdata; 3181 3182 VHCI_DEBUG(6, (CE_NOTE, NULL, "vhci_mpapi_get_tpg_item: ENTER: vlun=" 3183 "%p, acc_state=%x, pclass=%s, tp=%s\n", 3184 (void *)vlun, acc_state, pclass, (char *)tp)); 3185 3186 lulist = vhci->mp_priv->obj_hdr_list[MP_OBJECT_TYPE_MULTIPATH_LU]->head; 3187 3188 while (lulist != NULL) { 3189 tpghdr = ((mpapi_lu_data_t *)(lulist->item->idata))->tpg_list; 3190 tpglist = tpghdr->head; 3191 while (tpglist != NULL) { 3192 tpgdata = tpglist->item->idata; 3193 3194 if ((tpgdata) && 3195 (vhci_mpapi_check_tp_in_tpg(tpgdata, tp) == 1) && 3196 (strncmp(tpgdata->pclass, pclass, 3197 strlen(pclass)) == 0)) { 3198 return (tpglist); 3199 } else { 3200 tpglist = tpglist->next; 3201 } 3202 } 3203 lulist = lulist->next; 3204 } 3205 3206 this_lulist = vhci_get_mpapi_item(vhci, NULL, 3207 MP_OBJECT_TYPE_MULTIPATH_LU, vlun); 3208 if (this_lulist != NULL) { 3209 this_tpghdr = ((mpapi_lu_data_t *)(this_lulist->item->idata)) 3210 ->tpg_list; 3211 this_tpglist = this_tpghdr->head; 3212 while (this_tpglist != NULL) { 3213 this_tpgdata = this_tpglist->item->idata; 3214 3215 if ((this_tpgdata) && 3216 (strncmp(this_tpgdata->pclass, pclass, 3217 strlen(pclass)) == 0)) { 3218 return (this_tpglist); 3219 } else { 3220 this_tpglist = this_tpglist->next; 3221 } 3222 } 3223 } 3224 3225 VHCI_DEBUG(4, (CE_WARN, NULL, "vhci_mpapi_get_tpg_item: Returns NULL")); 3226 3227 return (NULL); 3228 } 3229 3230 /* 3231 * Routine to search (& return if found) a TPG object with a specified 3232 * accessState for a specified vlun structure. Returns NULL if either 3233 * TPG object or the lu item is not found. 3234 * This routine is used for NON-TPGS devices. 3235 */ 3236 /* ARGSUSED */ 3237 mpapi_item_list_t * 3238 vhci_mpapi_get_tpg_for_lun(struct scsi_vhci *vhci, char *pclass, 3239 void *vlun, void *tp) 3240 { 3241 mpapi_list_header_t *this_tpghdr; 3242 mpapi_item_list_t *this_lulist, *this_tpglist; 3243 mpapi_tpg_data_t *this_tpgdata; 3244 3245 VHCI_DEBUG(4, (CE_NOTE, NULL, "vhci_mpapi_get_tpg_for_lun: ENTER: vlun=" 3246 "%p, pclass=%s, tp=%s\n", (void *)vlun, pclass, (char *)tp)); 3247 3248 this_lulist = vhci_get_mpapi_item(vhci, NULL, 3249 MP_OBJECT_TYPE_MULTIPATH_LU, vlun); 3250 if (this_lulist != NULL) { 3251 this_tpghdr = ((mpapi_lu_data_t *)(this_lulist->item->idata)) 3252 ->tpg_list; 3253 this_tpglist = this_tpghdr->head; 3254 while (this_tpglist != NULL) { 3255 this_tpgdata = this_tpglist->item->idata; 3256 3257 if ((this_tpgdata) && 3258 (vhci_mpapi_check_tp_in_tpg(this_tpgdata, 3259 tp) == 1) && (strncmp(this_tpgdata->pclass, pclass, 3260 strlen(pclass)) == 0)) { 3261 return (this_tpglist); 3262 } 3263 this_tpglist = this_tpglist->next; 3264 } 3265 } 3266 3267 VHCI_DEBUG(4, (CE_WARN, NULL, "vhci_mpapi_get_tpg_for_lun: Returns " 3268 "NULL")); 3269 3270 return (NULL); 3271 } 3272 3273 /* 3274 * Routine to search a Target Port in a TPG 3275 */ 3276 /* ARGSUSED */ 3277 static int 3278 vhci_mpapi_check_tp_in_tpg(mpapi_tpg_data_t *tpgdata, void *tp) 3279 { 3280 mpapi_item_list_t *tplist; 3281 3282 if (tpgdata) { 3283 tplist = tpgdata->tport_list->head; 3284 } else { 3285 return (0); 3286 } 3287 3288 while (tplist != NULL) { 3289 void *resp = ((mpapi_tport_data_t *)tplist-> 3290 item->idata)->resp; 3291 if (strncmp(resp, tp, strlen(resp)) == 0) { 3292 /* Found a match */ 3293 return (1); 3294 } 3295 tplist = tplist->next; 3296 } 3297 3298 return (0); 3299 } 3300 3301 /* 3302 * Routine to create Level 1 mpapi_private data structure for TPG object & 3303 * establish cross references between the TPG resources being managed. 3304 * TPG SYNTHESIS MODE: Process for NON-SCSI_FAILOVER_IS_TPGS devices ONLY. 3305 * SCSI_FAILOVER_IS_TPGS devices have TPGS(ALUA support) and provide 3306 * REPORT_TARGET_PORT_GROUP data which we can parse directly in the next 3307 * routine(vhci_mpapi_update_tpg_data) to create TPG list in mpapi_priv block. 3308 */ 3309 /* ARGSUSED */ 3310 void 3311 vhci_mpapi_synthesize_tpg_data(struct scsi_vhci *vhci, scsi_vhci_lun_t *vlun, 3312 mdi_pathinfo_t *pip) 3313 { 3314 uint32_t as; 3315 char *tmp_wwn = NULL, *path_class = NULL; 3316 mpapi_item_list_t *tpg_tport_list, *tpg_lu_list, *lu_list; 3317 mpapi_item_list_t *lu_tpg_list, *item_list, *tpg_list; 3318 mpapi_tpg_data_t *tpg_data; 3319 int path_class_not_mdi_alloced = 0; 3320 3321 /* 3322 * Build Target Port Group list 3323 * Start by finding out the affected Target Port. 3324 */ 3325 if (mdi_prop_lookup_string(pip, SCSI_ADDR_PROP_TARGET_PORT, 3326 &tmp_wwn) != DDI_PROP_SUCCESS) { 3327 /* XXX: target-port prop not found */ 3328 tmp_wwn = (char *)mdi_pi_get_addr(pip); 3329 VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_mpapi_synthesize_tpg_data: " 3330 "mdi_prop_lookup_string() returned failure; " 3331 "Hence tmp_wwn = %p", (void *)tmp_wwn)); 3332 } 3333 3334 /* 3335 * Finding out the "path-class" property 3336 */ 3337 if (mdi_prop_lookup_string(pip, "path-class", &path_class) 3338 != DDI_PROP_SUCCESS) { 3339 /* XXX: path-class prop not found */ 3340 path_class = kmem_zalloc(MPAPI_SCSI_MAXPCLASSLEN, KM_SLEEP); 3341 (void) strlcpy(path_class, "NONE", MPAPI_SCSI_MAXPCLASSLEN); 3342 VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_mpapi_synthesize_tpg_data: " 3343 "mdi_prop_lookup_string() returned failure; " 3344 "Hence path_class = NONE")); 3345 path_class_not_mdi_alloced = 1; 3346 } 3347 3348 /* 3349 * Check the vlun's accessState through pip; we'll use it later. 3350 */ 3351 if (MDI_PI_IS_ONLINE(pip)) { 3352 as = MP_DRVR_ACCESS_STATE_ACTIVE; 3353 } else if (MDI_PI_IS_STANDBY(pip)) { 3354 as = MP_DRVR_ACCESS_STATE_STANDBY; 3355 } else { 3356 as = MP_DRVR_ACCESS_STATE_UNAVAILABLE; 3357 VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_mpapi_synthesize_tpg_data: " 3358 "Unknown pip state seen in TPG synthesis")); 3359 } 3360 3361 VHCI_DEBUG(4, (CE_NOTE, NULL, "vhci_mpapi_synthesize_tpg_data: ENTER: " 3362 "vlun=%s, acc_state=%x, path_class=%s, tp=%s\n", 3363 vlun->svl_lun_wwn, as, path_class, tmp_wwn)); 3364 3365 /* 3366 * Create Level 1 and Level 2 data structures for type 3367 */ 3368 if (!SCSI_FAILOVER_IS_TPGS(vlun->svl_fops)) { 3369 /* 3370 * First check if the lun has a TPG list in its level 2 3371 * structure then, check if this lun is already 3372 * accounted for through a different Target Port. 3373 * If yes, get the ptr to the TPG & skip new TPG creation. 3374 */ 3375 lu_list = vhci_get_mpapi_item(vhci, NULL, 3376 MP_OBJECT_TYPE_MULTIPATH_LU, vlun); 3377 tpg_list = vhci_mpapi_get_tpg_item(vhci, as, vlun, path_class, 3378 (void *)tmp_wwn); 3379 if (tpg_list == NULL) { 3380 tpg_list = vhci_mpapi_create_item(vhci, 3381 MP_OBJECT_TYPE_TARGET_PORT_GROUP, (void *)tmp_wwn); 3382 tpg_data = tpg_list->item->idata; 3383 (void) strlcpy(tpg_data->pclass, path_class, 3384 sizeof (tpg_data->pclass)); 3385 tpg_data->prop.accessState = as; 3386 } else { 3387 tpg_data = tpg_list->item->idata; 3388 } 3389 3390 if ((vlun != NULL) && SCSI_FAILOVER_IS_ASYM(vlun)) { 3391 tpg_data->prop.explicitFailover = 1; 3392 } 3393 3394 /* 3395 * Level 2, Lun Cross referencing to TPG. 3396 */ 3397 if (vhci_get_mpapi_item(vhci, tpg_data->lu_list, 3398 MP_OBJECT_TYPE_MULTIPATH_LU, (void *)vlun) == NULL) { 3399 tpg_lu_list = kmem_zalloc(sizeof (mpapi_item_list_t), 3400 KM_SLEEP); 3401 item_list = vhci_get_mpapi_item(vhci, NULL, 3402 MP_OBJECT_TYPE_MULTIPATH_LU, (void *)vlun); 3403 tpg_lu_list->item = item_list->item; 3404 (void) vhci_mpapi_add_to_list(tpg_data->lu_list, 3405 tpg_lu_list); 3406 } 3407 3408 /* 3409 * Level 2, Target Port Cross referencing to TPG. 3410 */ 3411 if (vhci_get_mpapi_item(vhci, tpg_data->tport_list, 3412 MP_OBJECT_TYPE_TARGET_PORT, (void *)tmp_wwn) == NULL) { 3413 tpg_tport_list = kmem_zalloc(sizeof (mpapi_item_list_t), 3414 KM_SLEEP); 3415 item_list = vhci_get_mpapi_item(vhci, NULL, 3416 MP_OBJECT_TYPE_TARGET_PORT, (void *)tmp_wwn); 3417 tpg_tport_list->item = item_list->item; 3418 (void) vhci_mpapi_add_to_list(tpg_data->tport_list, 3419 tpg_tport_list); 3420 } 3421 3422 /* 3423 * Level 2, TPG Cross referencing to Lun. 3424 */ 3425 lu_tpg_list = vhci_mpapi_get_tpg_for_lun 3426 (vhci, path_class, vlun, tmp_wwn); 3427 if (lu_tpg_list == NULL) { 3428 lu_tpg_list = kmem_zalloc(sizeof (mpapi_item_list_t), 3429 KM_SLEEP); 3430 lu_tpg_list->item = tpg_list->item; 3431 (void) vhci_mpapi_add_to_list(((mpapi_lu_data_t *) 3432 (lu_list->item->idata))->tpg_list, lu_tpg_list); 3433 } 3434 3435 /* 3436 * Update the AccessState of related MPAPI TPGs 3437 * This takes care of a special case where a failover doesn't 3438 * happen but a TPG accessState needs to be updated from 3439 * Unavailable to Standby 3440 */ 3441 (void) vhci_mpapi_update_tpg_acc_state_for_lu(vhci, vlun); 3442 } 3443 3444 if (path_class_not_mdi_alloced == 1) { 3445 kmem_free(path_class, MPAPI_SCSI_MAXPCLASSLEN); 3446 } 3447 3448 } 3449 3450 /* 3451 * Routine to create Level 1 mpapi_private data structure for TPG object, 3452 * for devices which support TPG and establish cross references between 3453 * the TPG resources being managed. The RTPG response sent by std_asymmetric 3454 * module is parsed in this routine and mpapi_priv data structure is updated. 3455 */ 3456 /* ARGSUSED */ 3457 void 3458 vhci_mpapi_update_tpg_data(struct scsi_address *ap, char *ptr, 3459 int rel_tgt_port) 3460 { 3461 struct scsi_vhci_lun *vlun; 3462 struct scsi_vhci *vhci; 3463 struct scsi_device *psd = NULL; 3464 scsi_vhci_priv_t *svp; 3465 mdi_pathinfo_t *pip; 3466 dev_info_t *pdip; 3467 char tpg_id[16], *tgt_port, *init = NULL; 3468 uint32_t int_tpg_id, rel_tid, as; 3469 int i, rel_tport_cnt; 3470 mpapi_item_list_t *path_list, *init_list; 3471 mpapi_item_list_t *tp_path_list, *init_path_list, *lu_path_list; 3472 mpapi_item_list_t *tpg_tport_list, *tpg_lu_list, *lu_list; 3473 mpapi_item_list_t *lu_tpg_list, *item_list, *tpg_list, *tgt_list; 3474 mpapi_lu_data_t *ld; 3475 mpapi_tpg_data_t *tpg_data; 3476 mpapi_path_data_t *pd; 3477 mpapi_tport_data_t *tpd; 3478 mpapi_initiator_data_t *initd; 3479 3480 /* 3481 * Find out the TPG ID (resource ptr for TPG is T10 TPG ID) 3482 */ 3483 int_tpg_id = ((ptr[2] & 0xff) << 8) | (ptr[3] & 0xff); 3484 (void) sprintf(tpg_id, "%04x", int_tpg_id); 3485 3486 /* 3487 * Check the TPG's accessState; we'll use it later. 3488 */ 3489 as = (ptr[0] & 0x0f); 3490 if (as == STD_ACTIVE_OPTIMIZED) { 3491 as = MP_DRVR_ACCESS_STATE_ACTIVE_OPTIMIZED; 3492 } else if (as == STD_ACTIVE_NONOPTIMIZED) { 3493 as = MP_DRVR_ACCESS_STATE_ACTIVE_NONOPTIMIZED; 3494 } else if (as == STD_STANDBY) { 3495 as = MP_DRVR_ACCESS_STATE_STANDBY; 3496 } else { 3497 as = MP_DRVR_ACCESS_STATE_UNAVAILABLE; 3498 VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_mpapi_update_tpg_data: " 3499 "UNAVAILABLE accessState seen in ALUA TPG setup")); 3500 } 3501 3502 /* 3503 * The scsi_address passed is associated with a scsi_vhci allocated 3504 * scsi_device structure for a pathinfo node. Getting the vlun from 3505 * this is a bit complicated. 3506 */ 3507 if (ap->a_hba_tran->tran_hba_flags & SCSI_HBA_ADDR_COMPLEX) 3508 psd = scsi_address_device(ap); 3509 else if (ap->a_hba_tran->tran_hba_flags & SCSI_HBA_TRAN_CLONE) 3510 psd = ap->a_hba_tran->tran_sd; 3511 ASSERT(psd); 3512 pip = (mdi_pathinfo_t *)psd->sd_pathinfo; 3513 3514 /* 3515 * It is possable for this code to be called without the sd_pathinfo 3516 * being set. This may happen as part of a probe to see if a device 3517 * should be mapped under mdi. At this point we know enough to answer 3518 * correctly so we can return. 3519 */ 3520 if (pip == NULL) 3521 return; 3522 svp = (scsi_vhci_priv_t *)mdi_pi_get_vhci_private(pip); 3523 vlun = svp->svp_svl; 3524 3525 /* 3526 * Now get the vhci ptr using the walker 3527 */ 3528 mdi_walk_vhcis(vhci_mpapi_get_vhci, &vhci); 3529 3530 VHCI_DEBUG(4, (CE_NOTE, NULL, "vhci_mpapi_update_tpg_data: vhci=%p, " 3531 "(vlun)wwn=(%p)%s, pip=%p, ap=%p, ptr=%p, as=%x, tpg_id=%s, fops=" 3532 "%p\n", (void *)vhci, (void *)vlun, 3533 vlun ? vlun->svl_lun_wwn : "NONE", 3534 (void *)pip, (void *)ap, (void *)ptr, as, tpg_id, 3535 (void *)(vlun ? vlun->svl_fops : NULL))); 3536 3537 if ((vhci == NULL) || (vlun == NULL) || 3538 !SCSI_FAILOVER_IS_TPGS(vlun->svl_fops)) { 3539 /* Cant help, unfortunate situation */ 3540 return; 3541 } 3542 3543 /* 3544 * LEVEL 1 - Actions: 3545 * Check if the appropriate resource pointers already 3546 * exist in the Level 1 list and add them if they are new. 3547 */ 3548 3549 /* 3550 * Build MP LU list 3551 */ 3552 lu_list = vhci_get_mpapi_item(vhci, NULL, 3553 MP_OBJECT_TYPE_MULTIPATH_LU, (void*)vlun); 3554 if (lu_list == NULL) { 3555 /* Need to create lu_list entry */ 3556 lu_list = vhci_mpapi_create_item(vhci, 3557 MP_OBJECT_TYPE_MULTIPATH_LU, (void*)vlun); 3558 } else { 3559 /* 3560 * Matched this lu w/ an existing one in current lu list. 3561 * SAME LUN came online!! So, update the resp in main list. 3562 */ 3563 ld = lu_list->item->idata; 3564 vhci_mpapi_set_lu_valid(vhci, lu_list->item, 1); 3565 ld->resp = vlun; 3566 } 3567 3568 /* 3569 * Build Path LU list 3570 */ 3571 path_list = vhci_get_mpapi_item(vhci, NULL, 3572 MP_OBJECT_TYPE_PATH_LU, (void*)pip); 3573 if (path_list == NULL) { 3574 /* Need to create path_list entry */ 3575 path_list = vhci_mpapi_create_item(vhci, 3576 MP_OBJECT_TYPE_PATH_LU, (void*)pip); 3577 } else { 3578 /* 3579 * Matched this pip w/ an existing one in current pip list. 3580 * SAME PATH came online!! So, update the resp in main list. 3581 */ 3582 pd = path_list->item->idata; 3583 pd->valid = 1; 3584 pd->resp = pip; 3585 } 3586 3587 if (MDI_PI_IS_ONLINE(pip)) { 3588 vhci_mpapi_set_path_state(vhci->vhci_dip, pip, 3589 MP_DRVR_PATH_STATE_ACTIVE); 3590 } else if (MDI_PI_IS_STANDBY(pip)) { 3591 vhci_mpapi_set_path_state(vhci->vhci_dip, pip, 3592 MP_DRVR_PATH_STATE_PASSIVE); 3593 } else { 3594 vhci_mpapi_set_path_state(vhci->vhci_dip, pip, 3595 MP_DRVR_PATH_STATE_UNKNOWN); 3596 } 3597 3598 /* 3599 * Build Initiator Port list 3600 */ 3601 pdip = mdi_pi_get_phci(pip); 3602 init = kmem_zalloc(MAXPATHLEN, KM_SLEEP); 3603 (void) ddi_pathname(pdip, init); 3604 3605 init_list = vhci_get_mpapi_item(vhci, NULL, 3606 MP_OBJECT_TYPE_INITIATOR_PORT, (void*)init); 3607 if (init_list == NULL) { 3608 /* 3609 * Need to create init_list entry 3610 * The resource ptr is no really pdip. It will be changed 3611 * in vhci_mpapi_create_item(). The real resource ptr 3612 * is the Port ID. But we pass the pdip, to create OID. 3613 */ 3614 init_list = vhci_mpapi_create_item(vhci, 3615 MP_OBJECT_TYPE_INITIATOR_PORT, (void*)pdip); 3616 } else { 3617 initd = init_list->item->idata; 3618 initd->valid = 1; 3619 } 3620 kmem_free(init, MAXPATHLEN); 3621 3622 /* 3623 * LEVEL 2 - Actions: 3624 * Since all the Object type item lists are updated to account 3625 * for the new resources, now lets cross-reference these 3626 * resources (mainly through paths) to maintain the 3627 * relationship between them. 3628 */ 3629 3630 ld = (mpapi_lu_data_t *)lu_list->item->idata; 3631 if (vhci_get_mpapi_item(vhci, ld->path_list, 3632 MP_OBJECT_TYPE_PATH_LU, (void*)pip) == NULL) { 3633 lu_path_list = kmem_zalloc(sizeof (mpapi_item_list_t), 3634 KM_SLEEP); 3635 lu_path_list->item = path_list->item; 3636 (void) vhci_mpapi_add_to_list(ld->path_list, lu_path_list); 3637 } 3638 3639 initd = (mpapi_initiator_data_t *)init_list->item->idata; 3640 if (vhci_get_mpapi_item(vhci, initd->path_list, 3641 MP_OBJECT_TYPE_PATH_LU, (void*)pip) == NULL) { 3642 init_path_list = kmem_zalloc(sizeof (mpapi_item_list_t), 3643 KM_SLEEP); 3644 init_path_list->item = path_list->item; 3645 (void) vhci_mpapi_add_to_list(initd->path_list, init_path_list); 3646 } 3647 3648 /* 3649 * Building Target Port list is different here. 3650 * For each different Relative Target Port. we have a new MPAPI 3651 * Target Port OID generated. 3652 * Just find out the main Target Port property here. 3653 */ 3654 tgt_port = NULL; 3655 if (mdi_prop_lookup_string(pip, SCSI_ADDR_PROP_TARGET_PORT, 3656 &tgt_port) != DDI_PROP_SUCCESS) { 3657 /* XXX: target-port prop not found */ 3658 tgt_port = (char *)mdi_pi_get_addr(pip); 3659 VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_mpapi_update_tpg_data: " 3660 "mdi_prop_lookup_string() returned failure; " 3661 "Hence tgt_port = %p", (void *)tgt_port)); 3662 } 3663 3664 /* Search for existing group that contains this target port */ 3665 tpg_list = vhci_mpapi_get_alua_item(vhci, vlun, &tpg_id, tgt_port); 3666 if (tpg_list == NULL) { 3667 tpg_list = vhci_mpapi_create_item(vhci, 3668 MP_OBJECT_TYPE_TARGET_PORT_GROUP, &tpg_id); 3669 } 3670 tpg_data = tpg_list->item->idata; 3671 tpg_data->prop.accessState = as; 3672 tpg_data->prop.tpgId = int_tpg_id; 3673 3674 /* 3675 * Set explicitFailover for TPG - 3676 * based on tpgs_bits setting in Std Inquiry response. 3677 */ 3678 switch (psd->sd_inq->inq_tpgs) { 3679 case TPGS_FAILOVER_EXPLICIT: 3680 case TPGS_FAILOVER_BOTH: 3681 tpg_data->prop.explicitFailover = 1; 3682 break; 3683 case TPGS_FAILOVER_IMPLICIT: 3684 tpg_data->prop.explicitFailover = 0; 3685 break; 3686 default: 3687 return; 3688 } 3689 3690 /* 3691 * Level 2, Lun Cross referencing to TPG. 3692 */ 3693 if (vhci_get_mpapi_item(vhci, tpg_data->lu_list, 3694 MP_OBJECT_TYPE_MULTIPATH_LU, (void *)vlun) == NULL) { 3695 tpg_lu_list = kmem_zalloc(sizeof (mpapi_item_list_t), 3696 KM_SLEEP); 3697 item_list = vhci_get_mpapi_item(vhci, NULL, 3698 MP_OBJECT_TYPE_MULTIPATH_LU, (void *)vlun); 3699 tpg_lu_list->item = item_list->item; 3700 (void) vhci_mpapi_add_to_list(tpg_data->lu_list, 3701 tpg_lu_list); 3702 } 3703 3704 /* 3705 * Level 2, TPG Cross referencing to Lun. 3706 */ 3707 if (vhci_get_mpapi_item(vhci, ld->tpg_list, 3708 MP_OBJECT_TYPE_TARGET_PORT_GROUP, &tpg_id) == 0) { 3709 lu_tpg_list = kmem_zalloc(sizeof (mpapi_item_list_t), 3710 KM_SLEEP); 3711 lu_tpg_list->item = tpg_list->item; 3712 (void) vhci_mpapi_add_to_list(((mpapi_lu_data_t *) 3713 (lu_list->item->idata))->tpg_list, lu_tpg_list); 3714 } 3715 3716 /* 3717 * Level 1, Relative Target Port + Target Port Creation 3718 */ 3719 rel_tport_cnt = (ptr[7] & 0xff); 3720 ptr += 8; 3721 for (i = 0; i < rel_tport_cnt; i++) { 3722 rel_tid = 0; 3723 rel_tid |= ((ptr[2] & 0Xff) << 8); 3724 rel_tid |= (ptr[3] & 0xff); 3725 3726 if (rel_tid != rel_tgt_port) { 3727 ptr += 4; 3728 continue; 3729 } 3730 3731 VHCI_DEBUG(4, (CE_NOTE, NULL, "vhci_mpapi_update_tpg_data: " 3732 "TgtPort=%s, RelTgtPort=%x\n", tgt_port, rel_tid)); 3733 3734 tgt_list = vhci_mpapi_get_rel_tport_pair(vhci, NULL, 3735 (void *)tgt_port, rel_tid); 3736 if (tgt_list == NULL) { 3737 /* Need to create tgt_list entry */ 3738 tgt_list = vhci_mpapi_create_item(vhci, 3739 MP_OBJECT_TYPE_TARGET_PORT, 3740 (void *)tgt_port); 3741 tpd = tgt_list->item->idata; 3742 tpd->valid = 1; 3743 tpd->prop.relativePortID = rel_tid; 3744 } else { 3745 tpd = tgt_list->item->idata; 3746 tpd->valid = 1; 3747 } 3748 3749 tpd = (mpapi_tport_data_t *)tgt_list->item->idata; 3750 if (vhci_get_mpapi_item(vhci, tpd->path_list, 3751 MP_OBJECT_TYPE_PATH_LU, (void*)pip) == NULL) { 3752 tp_path_list = kmem_zalloc(sizeof (mpapi_item_list_t), 3753 KM_SLEEP); 3754 tp_path_list->item = path_list->item; 3755 (void) vhci_mpapi_add_to_list(tpd->path_list, 3756 tp_path_list); 3757 } 3758 3759 if (vhci_mpapi_get_rel_tport_pair(vhci, 3760 tpg_data->tport_list, tgt_port, rel_tid) == NULL) { 3761 tpg_tport_list = kmem_zalloc 3762 (sizeof (mpapi_item_list_t), KM_SLEEP); 3763 tpg_tport_list->item = tgt_list->item; 3764 (void) vhci_mpapi_add_to_list(tpg_data-> 3765 tport_list, tpg_tport_list); 3766 } 3767 ptr += 4; 3768 } 3769 3770 /* 3771 * Level-1: Fill-out Path Properties now, since we got all details. 3772 * Actually, It is a structure copy, rather than just filling details. 3773 */ 3774 pd = path_list->item->idata; 3775 bcopy(&(ld->prop), &(pd->prop.logicalUnit), 3776 sizeof (struct mp_logical_unit_prop)); 3777 bcopy(&(initd->prop), &(pd->prop.initPort), 3778 sizeof (struct mp_init_port_prop)); 3779 bcopy(&(tpd->prop), &(pd->prop.targetPort), 3780 sizeof (struct mp_target_port_prop)); 3781 } 3782 3783 /* 3784 * Routine to get mpapi ioctl argument structure from userland. 3785 */ 3786 /* ARGSUSED */ 3787 static int 3788 vhci_get_mpiocdata(const void *data, mp_iocdata_t *mpioc, int mode) 3789 { 3790 int retval = 0; 3791 3792 #ifdef _MULTI_DATAMODEL 3793 switch (ddi_model_convert_from(mode & FMODELS)) { 3794 case DDI_MODEL_ILP32: 3795 { 3796 mp_iocdata32_t ioc32; 3797 3798 VHCI_DEBUG(6, (CE_WARN, NULL, "vhci_get_mpiocdata: " 3799 "Case DDI_MODEL_ILP32")); 3800 if (ddi_copyin((void *)data, (void *)&ioc32, 3801 sizeof (mp_iocdata32_t), mode)) { 3802 VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_get_mpiocdata: " 3803 "ddi_copyin() FAILED")); 3804 retval = EFAULT; 3805 break; 3806 } 3807 mpioc->mp_xfer = (uint16_t)(uintptr_t)ioc32.mp_xfer; 3808 mpioc->mp_cmd = (uint16_t)(uintptr_t)ioc32.mp_cmd; 3809 mpioc->mp_flags = (uint16_t)(uintptr_t)ioc32.mp_flags; 3810 mpioc->mp_cmd_flags = (uint16_t)ioc32.mp_cmd_flags; 3811 mpioc->mp_ilen = (size_t)(uintptr_t)ioc32.mp_ilen; 3812 mpioc->mp_ibuf = (caddr_t)(uintptr_t)ioc32.mp_ibuf; 3813 mpioc->mp_olen = (size_t)(uintptr_t)ioc32.mp_olen; 3814 mpioc->mp_obuf = (caddr_t)(uintptr_t)ioc32.mp_obuf; 3815 mpioc->mp_alen = (size_t)(uintptr_t)ioc32.mp_alen; 3816 mpioc->mp_abuf = (caddr_t)(uintptr_t)ioc32.mp_abuf; 3817 mpioc->mp_errno = (int)(uintptr_t)ioc32.mp_errno; 3818 break; 3819 } 3820 3821 case DDI_MODEL_NONE: 3822 if (ddi_copyin(data, (void*)mpioc, sizeof (*mpioc), mode)) { 3823 retval = EFAULT; 3824 break; 3825 } 3826 break; 3827 3828 default: 3829 if (ddi_copyin(data, (void*)mpioc, sizeof (*mpioc), mode)) { 3830 retval = EFAULT; 3831 break; 3832 } 3833 break; 3834 } 3835 #else /* _MULTI_DATAMODEL */ 3836 if (ddi_copyin(data, (void *)mpioc, sizeof (*mpioc), mode)) { 3837 retval = EFAULT; 3838 } 3839 #endif /* _MULTI_DATAMODEL */ 3840 3841 if (retval) { 3842 VHCI_DEBUG(2, (CE_WARN, NULL, "vhci_get_mpiocdata: cmd <%x> " 3843 "iocdata copyin failed", mpioc->mp_cmd)); 3844 } 3845 3846 return (retval); 3847 } 3848 3849 /* ARGSUSED */ 3850 static int 3851 vhci_is_model_type32(int mode) 3852 { 3853 #ifdef _MULTI_DATAMODEL 3854 switch (ddi_model_convert_from(mode & FMODELS)) { 3855 case DDI_MODEL_ILP32: 3856 return (1); 3857 default: 3858 return (0); 3859 } 3860 #else /* _MULTI_DATAMODEL */ 3861 return (0); 3862 #endif /* _MULTI_DATAMODEL */ 3863 } 3864 3865 /* 3866 * Convenience routine to copy mp_iocdata(32) to user land 3867 */ 3868 /* ARGSUSED */ 3869 static int 3870 vhci_mpapi_copyout_iocdata(void *mpioc, void *udata, int mode) 3871 { 3872 int rval = 0; 3873 3874 if (vhci_is_model_type32(mode)) { 3875 mp_iocdata32_t *mpioc32; 3876 3877 mpioc32 = (mp_iocdata32_t *)kmem_zalloc 3878 (sizeof (mp_iocdata32_t), KM_SLEEP); 3879 mpioc32->mp_xfer = (uint16_t)((mp_iocdata_t *)mpioc)->mp_xfer; 3880 mpioc32->mp_cmd = (uint16_t)((mp_iocdata_t *)mpioc)->mp_cmd; 3881 mpioc32->mp_flags = (uint16_t)((mp_iocdata_t *)mpioc)->mp_flags; 3882 mpioc32->mp_cmd_flags = (uint16_t)((mp_iocdata_t *) 3883 mpioc)->mp_cmd_flags; 3884 mpioc32->mp_ilen = (uint32_t)((mp_iocdata_t *)mpioc)->mp_ilen; 3885 mpioc32->mp_ibuf = (caddr32_t)((mp_iocdata32_t *) 3886 mpioc)->mp_ibuf; 3887 mpioc32->mp_olen = (uint32_t)((mp_iocdata_t *)mpioc)->mp_olen; 3888 mpioc32->mp_obuf = (caddr32_t)((mp_iocdata32_t *) 3889 mpioc)->mp_obuf; 3890 mpioc32->mp_alen = (uint32_t)((mp_iocdata_t *)mpioc)->mp_alen; 3891 mpioc32->mp_abuf = (caddr32_t)((mp_iocdata32_t *) 3892 mpioc)->mp_abuf; 3893 mpioc32->mp_errno = (int32_t)((mp_iocdata_t *)mpioc)->mp_errno; 3894 3895 if (ddi_copyout(mpioc32, udata, sizeof (mp_iocdata32_t), mode) 3896 != 0) { 3897 rval = EFAULT; 3898 } 3899 kmem_free(mpioc32, sizeof (mp_iocdata32_t)); 3900 } else { 3901 /* 64-bit ddicopyout */ 3902 if (ddi_copyout(mpioc, udata, sizeof (mp_iocdata_t), mode) 3903 != 0) { 3904 rval = EFAULT; 3905 } 3906 } 3907 3908 return (rval); 3909 3910 } 3911 3912 /* 3913 * Routine to sync OIDs of MPLU to match with the ssd instance# of the 3914 * scsi_vhci lun, to accommodate the DINFOCACHE implementation of the plugin. 3915 * ssd instance# = devi_instance from the dev_info structure. 3916 * dev_info structure of the scsi_vhci lun is pointed by svl_dip field of 3917 * scsi_vhci_lun structure. 3918 */ 3919 /* ARGSUSED */ 3920 static int 3921 vhci_mpapi_sync_lu_oid_list(struct scsi_vhci *vhci) 3922 { 3923 int rval = 0; 3924 mpapi_item_list_t *ilist; 3925 mpapi_lu_data_t *lud; 3926 mpapi_path_data_t *pd; 3927 scsi_vhci_lun_t *svl; 3928 dev_info_t *lun_dip; 3929 uint64_t raw_oid; 3930 3931 ilist = vhci->mp_priv->obj_hdr_list[MP_OBJECT_TYPE_MULTIPATH_LU]->head; 3932 3933 while (ilist != NULL) { 3934 lud = ilist->item->idata; 3935 if (lud->valid == 1) { 3936 svl = lud->resp; 3937 3938 /* 3939 * Compose OID from major number and instance number. 3940 */ 3941 raw_oid = 0; 3942 raw_oid = MP_STORE_INST_TO_ID( 3943 ddi_get_instance(svl->svl_dip), raw_oid); 3944 raw_oid = MP_STORE_MAJOR_TO_ID( 3945 ddi_driver_major(svl->svl_dip), raw_oid); 3946 3947 ilist->item->oid.raw_oid = raw_oid; 3948 lud->prop.id = raw_oid; 3949 } 3950 ilist = ilist->next; 3951 } 3952 3953 ilist = vhci->mp_priv->obj_hdr_list[MP_OBJECT_TYPE_PATH_LU]->head; 3954 while (ilist != NULL) { 3955 pd = ilist->item->idata; 3956 if (pd->valid == 1) { 3957 lun_dip = mdi_pi_get_client 3958 ((mdi_pathinfo_t *)(pd->resp)); 3959 3960 /* 3961 * Compose OID from major number and instance number. 3962 */ 3963 raw_oid = 0; 3964 raw_oid = MP_STORE_INST_TO_ID( 3965 ddi_get_instance(lun_dip), raw_oid); 3966 raw_oid = MP_STORE_MAJOR_TO_ID( 3967 ddi_driver_major(lun_dip), raw_oid); 3968 3969 pd->prop.logicalUnit.id = raw_oid; 3970 } 3971 ilist = ilist->next; 3972 } 3973 3974 return (rval); 3975 } 3976 3977 /* 3978 * Set new value for the valid field of an MP LU. 3979 * 3980 * This should be called to set new value for the valid field instead of 3981 * accessing it directly. If the value has changed, the appropriate 3982 * sysevent is generated. 3983 * 3984 * An exception is when the LU is created an the valid field is set for 3985 * the first time. In this case we do not want to generate an event 3986 * so the field should be set directly instead of calling this function. 3987 * 3988 * Rationale for introducing ESC_SUN_MP_LU_{ADD|REMOVE}: When the last 3989 * path to a MPLU goes offline, the client node is offlined (not removed). 3990 * When a path to the MPLU goes back online, the client node is onlined. 3991 * There is no existing sysevent that whould announce this. 3992 * EC_DEVFS / ESC_DEVFS_DEVI_{ADD|REMOVE} do not work, because the 3993 * client node is just offlined/onlined, not removed/re-added. 3994 * EC_DEV_{ADD|REMOVE} / ESC_DISK only works for block devices, not 3995 * for other LUs (such as tape). Therefore special event subclasses 3996 * for addition/removal of a MPLU are needed. 3997 */ 3998 static void vhci_mpapi_set_lu_valid(struct scsi_vhci *vhci, 3999 mpapi_item_t *lu_item, int valid) 4000 { 4001 mpapi_lu_data_t *lu_data; 4002 4003 lu_data = (mpapi_lu_data_t *)lu_item->idata; 4004 if (valid == lu_data->valid) 4005 return; 4006 lu_data->valid = valid; 4007 4008 vhci_mpapi_log_sysevent(vhci->vhci_dip, &(lu_item->oid.raw_oid), 4009 valid ? ESC_SUN_MP_LU_ADD : ESC_SUN_MP_LU_REMOVE); 4010 } 4011 4012 /* 4013 * Set new value for TPG accessState property. 4014 * 4015 * This should be called to set the new value instead of changing the field 4016 * directly. If the value has changed, the appropriate sysevent is generated. 4017 * 4018 * An exception is when the TPG is created and the accessState field is set 4019 * for the first time. In this case we do not want to generate an event 4020 * so the field should be set directly instead of calling this function. 4021 */ 4022 static void vhci_mpapi_set_tpg_as_prop(struct scsi_vhci *vhci, 4023 mpapi_item_t *tpg_item, uint32_t new_state) 4024 { 4025 mpapi_tpg_data_t *tpg_data; 4026 4027 tpg_data = (mpapi_tpg_data_t *)tpg_item->idata; 4028 if (new_state == tpg_data->prop.accessState) 4029 return; 4030 tpg_data->prop.accessState = new_state; 4031 4032 vhci_mpapi_log_sysevent(vhci->vhci_dip, &(tpg_item->oid.raw_oid), 4033 ESC_SUN_MP_TPG_CHANGE); 4034 } 4035 4036 /* 4037 * Routine to sync Initiator Port List with what MDI maintains. This means 4038 * MP API knows about Initiator Ports which don't have a pip. 4039 */ 4040 /* ARGSUSED */ 4041 int 4042 vhci_mpapi_sync_init_port_list(dev_info_t *pdip, void *arg) 4043 { 4044 int init_not_ddi_alloced = 0; 4045 struct scsi_vhci *vhci = arg; 4046 char *init, *init_port_res; 4047 mpapi_item_list_t *init_list; 4048 mpapi_initiator_data_t *initd; 4049 4050 if ((ddi_prop_lookup_string(DDI_DEV_T_ANY, pdip, DDI_PROP_DONTPASS, 4051 SCSI_ADDR_PROP_INITIATOR_PORT, &init) != DDI_PROP_SUCCESS)) { 4052 VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_mpapi_sync_init_port_list: " 4053 SCSI_ADDR_PROP_INITIATOR_PORT " prop not found")); 4054 init = kmem_zalloc(MAXPATHLEN, KM_SLEEP); 4055 init_not_ddi_alloced = 1; 4056 (void) ddi_pathname(pdip, init); 4057 } 4058 4059 init_port_res = kmem_zalloc(MAXPATHLEN, KM_SLEEP); 4060 (void) ddi_pathname(pdip, init_port_res); 4061 4062 init_list = vhci_get_mpapi_item(vhci, NULL, 4063 MP_OBJECT_TYPE_INITIATOR_PORT, (void*)init_port_res); 4064 if (init_list == NULL) { 4065 /* 4066 * Need to create init_list entry 4067 * The resource ptr is not really pdip. It will be changed 4068 * in vhci_mpapi_create_item(). The real resource ptr 4069 * is the Port ID. But we pass the pdip, to create OID. 4070 */ 4071 init_list = vhci_mpapi_create_item(vhci, 4072 MP_OBJECT_TYPE_INITIATOR_PORT, (void*)pdip); 4073 } 4074 4075 initd = init_list->item->idata; 4076 initd->valid = 1; 4077 (void) strlcpy(initd->prop.portID, init, sizeof (initd->prop.portID)); 4078 4079 if (init_not_ddi_alloced == 1) { 4080 kmem_free(init, MAXPATHLEN); 4081 } else if (init) { 4082 ddi_prop_free(init); 4083 } 4084 kmem_free(init_port_res, MAXPATHLEN); 4085 4086 return (DDI_WALK_CONTINUE); 4087 } 4088 4089 /* ARGSUSED */ 4090 static void 4091 vhci_mpapi_log_sysevent(dev_info_t *dip, uint64_t *oid, char *subclass) 4092 { 4093 nvlist_t *attr_list; 4094 4095 if (nvlist_alloc(&attr_list, NV_UNIQUE_NAME_TYPE, 4096 KM_SLEEP) != DDI_SUCCESS) { 4097 goto alloc_failed; 4098 } 4099 4100 if (nvlist_add_uint64_array(attr_list, "oid", oid, 1) != DDI_SUCCESS) { 4101 goto error; 4102 } 4103 4104 (void) ddi_log_sysevent(dip, DDI_VENDOR_SUNW, EC_SUN_MP, subclass, 4105 attr_list, NULL, DDI_SLEEP); 4106 4107 error: 4108 nvlist_free(attr_list); 4109 return; 4110 4111 alloc_failed: 4112 VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_mpapi_log_sysevent: " 4113 "Unable to send sysevent")); 4114 4115 } 4116 4117 /* ARGSUSED */ 4118 void 4119 vhci_mpapi_set_path_state(dev_info_t *vdip, mdi_pathinfo_t *pip, int state) 4120 { 4121 struct scsi_vhci *vhci; 4122 struct scsi_vhci_lun *svl; 4123 scsi_vhci_priv_t *svp; 4124 mpapi_item_list_t *ilist, *lu_list; 4125 mpapi_path_data_t *pp; 4126 int old_state; 4127 int old_in_okay, new_in_okay; 4128 4129 vhci = ddi_get_soft_state(vhci_softstate, ddi_get_instance(vdip)); 4130 4131 ilist = vhci_get_mpapi_item(vhci, NULL, MP_OBJECT_TYPE_PATH_LU, pip); 4132 4133 if (ilist != NULL) { 4134 mutex_enter(&ilist->item->item_mutex); 4135 pp = ilist->item->idata; 4136 old_state = pp->prop.pathState; 4137 pp->prop.pathState = state; 4138 pp->valid = 1; 4139 4140 /* 4141 * MP API does not distiguish between ACTIVE and PASSIVE 4142 * and thus libmpscsi_vhci renders both as MP_PATH_STATE_OKAY. 4143 * Therefore if we are transitioning between ACTIVE and PASSIVE 4144 * we do not want to generate an event. 4145 */ 4146 4147 old_in_okay = (old_state == MP_DRVR_PATH_STATE_ACTIVE || 4148 old_state == MP_DRVR_PATH_STATE_PASSIVE); 4149 new_in_okay = (state == MP_DRVR_PATH_STATE_ACTIVE || 4150 state == MP_DRVR_PATH_STATE_PASSIVE); 4151 4152 if (state != old_state && !(old_in_okay && new_in_okay)) { 4153 vhci_mpapi_log_sysevent(vdip, 4154 &(ilist->item->oid.raw_oid), 4155 ESC_SUN_MP_PATH_CHANGE); 4156 } 4157 } else { 4158 VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_mpapi_set_path_state: " 4159 "pip(%p) not found", (void *)pip)); 4160 return; 4161 } 4162 4163 /* 4164 * Check if the pathinfo is uninitialized(destroyed). 4165 */ 4166 if (state == MP_DRVR_PATH_STATE_UNINIT) { 4167 pp->hide = 1; 4168 VHCI_DEBUG(6, (CE_NOTE, NULL, "vhci_mpapi_set_path_state: " 4169 "path(pip: %p) is uninited(destroyed).", 4170 (void *)pip)); 4171 } else { 4172 pp->hide = 0; 4173 } 4174 /* 4175 * Find if there are any paths at all to the lun 4176 */ 4177 if ((state == MP_DRVR_PATH_STATE_REMOVED) || (state == 4178 MP_DRVR_PATH_STATE_PATH_ERR) || (state == 4179 MP_DRVR_PATH_STATE_LU_ERR) || (state == 4180 MP_DRVR_PATH_STATE_UNKNOWN) || pp->hide) { 4181 pp->valid = 0; 4182 VHCI_DEBUG(6, (CE_NOTE, NULL, "vhci_mpapi_set_path_state: " 4183 "path(pip: %p) is not okay state. Set to invalid.", 4184 (void *)pip)); 4185 svp = (scsi_vhci_priv_t *)mdi_pi_get_vhci_private(pip); 4186 svl = svp->svp_svl; 4187 /* 4188 * Update the AccessState of related MPAPI TPGs 4189 * This takes care of a special case where a path goes offline 4190 * & the TPG accessState may need an update from 4191 * Active/Standby to Unavailable. 4192 */ 4193 if (!SCSI_FAILOVER_IS_TPGS(svl->svl_fops)) { 4194 (void) vhci_mpapi_update_tpg_acc_state_for_lu(vhci, 4195 svl); 4196 } 4197 4198 /* 4199 * Following means the lun is offline 4200 */ 4201 if (vhci_mpapi_chk_last_path(pip) == -1) { 4202 lu_list = vhci_get_mpapi_item(vhci, NULL, 4203 MP_OBJECT_TYPE_MULTIPATH_LU, (void *)svl); 4204 if (lu_list != NULL) { 4205 vhci_mpapi_set_lu_valid(vhci, lu_list->item, 0); 4206 4207 VHCI_DEBUG(6, (CE_NOTE, NULL, 4208 "vhci_mpapi_set_path_state: " 4209 " Invalidated LU(%s)", svl->svl_lun_wwn)); 4210 } 4211 } 4212 } 4213 mutex_exit(&ilist->item->item_mutex); 4214 4215 } 4216 4217 /* ARGSUSED */ 4218 static mpapi_item_list_t * 4219 vhci_mpapi_match_pip(struct scsi_vhci *vhci, mpapi_item_list_t *ilist, 4220 void *res) 4221 { 4222 mpapi_path_data_t *pd; 4223 scsi_vhci_lun_t *this_svl; 4224 mdi_pathinfo_t *this_pip; 4225 char *this_iport; 4226 char *this_tport; 4227 char *pname; 4228 4229 this_pip = (mdi_pathinfo_t *)res; 4230 if ((this_pip == NULL) || (ilist == NULL)) { 4231 return (NULL); 4232 } 4233 4234 this_iport = kmem_zalloc(MAXPATHLEN, KM_SLEEP); 4235 (void) ddi_pathname(mdi_pi_get_phci(this_pip), this_iport); 4236 4237 if (mdi_prop_lookup_string(this_pip, SCSI_ADDR_PROP_TARGET_PORT, 4238 &this_tport) != DDI_PROP_SUCCESS) { 4239 /* XXX: target-port prop not found */ 4240 this_tport = (char *)mdi_pi_get_addr(this_pip); 4241 VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_mpapi_match_pip: " 4242 "mdi_prop_lookup_string() returned failure; " 4243 "Hence this_tport = %p", (void *)this_tport)); 4244 } 4245 4246 this_svl = mdi_client_get_vhci_private(mdi_pi_get_client(this_pip)); 4247 4248 pname = kmem_zalloc(MAXPATHLEN, KM_SLEEP); 4249 (void) strlcat(pname, this_iport, MAXPATHLEN); 4250 (void) strlcat(pname, this_tport, MAXPATHLEN); 4251 (void) strlcat(pname, this_svl->svl_lun_wwn, MAXPATHLEN); 4252 kmem_free(this_iport, MAXPATHLEN); 4253 4254 while (ilist != NULL) { 4255 pd = (mpapi_path_data_t *)(ilist->item->idata); 4256 if ((pd != NULL) && (strncmp 4257 (pd->path_name, pname, strlen(pname)) == 0)) { 4258 VHCI_DEBUG(6, (CE_WARN, NULL, "vhci_mpapi_match_pip: " 4259 "path_name = %s", pd->path_name)); 4260 kmem_free(pname, MAXPATHLEN); 4261 return (ilist); 4262 } 4263 ilist = ilist->next; 4264 } 4265 4266 kmem_free(pname, MAXPATHLEN); 4267 return (NULL); 4268 } 4269 4270 /* ARGSUSED */ 4271 static 4272 mpapi_item_list_t *vhci_mpapi_match_lu(struct scsi_vhci *vhci, 4273 mpapi_item_list_t *ilist, void *res) 4274 { 4275 mpapi_lu_data_t *ld; 4276 scsi_vhci_lun_t *this_svl; 4277 4278 this_svl = (scsi_vhci_lun_t *)res; 4279 if ((this_svl == NULL) || (ilist == NULL)) { 4280 return (NULL); 4281 } 4282 4283 while (ilist != NULL) { 4284 ld = (mpapi_lu_data_t *)(ilist->item->idata); 4285 if ((ld != NULL) && (strncmp 4286 (ld->prop.name, this_svl->svl_lun_wwn, 4287 strlen(this_svl->svl_lun_wwn)) == 0)) { 4288 VHCI_DEBUG(6, (CE_WARN, NULL, "vhci_mpapi_match_lu: " 4289 "this_wwn = %s", this_svl->svl_lun_wwn)); 4290 return (ilist); 4291 } 4292 ilist = ilist->next; 4293 } 4294 4295 return (NULL); 4296 } 4297 4298 /* 4299 * Routine to handle TPG AccessState Change - Called after each LU failover 4300 */ 4301 int 4302 vhci_mpapi_update_tpg_acc_state_for_lu(struct scsi_vhci *vhci, 4303 scsi_vhci_lun_t *vlun) 4304 { 4305 int rval = 0; 4306 mpapi_item_list_t *lu_list, *path_list, *tpg_list; 4307 mpapi_lu_data_t *lu_data; 4308 mpapi_path_data_t *path_data; 4309 mpapi_tpg_data_t *tpg_data; 4310 char *tgt_port; 4311 boolean_t set_lu_valid; 4312 4313 lu_list = vhci_get_mpapi_item(vhci, NULL, MP_OBJECT_TYPE_MULTIPATH_LU, 4314 (void *)vlun); 4315 if (lu_list == NULL) { 4316 return (-1); 4317 } 4318 lu_data = lu_list->item->idata; 4319 if (lu_data == NULL) { 4320 return (-1); 4321 } 4322 lu_data->resp = vlun; 4323 4324 /* 4325 * For each "pclass of PATH" and "pclass of TPG" match of this LU, 4326 * Update the TPG AccessState to reflect the state of the path. 4327 * Exit the inner loop after the 1st successful ACTIVE/STANDBY update 4328 * is made, because subsequent matches also lead to the same TPG. 4329 */ 4330 tpg_list = lu_data->tpg_list->head; 4331 set_lu_valid = B_FALSE; 4332 4333 while (tpg_list != NULL) { 4334 tpg_data = tpg_list->item->idata; 4335 path_list = lu_data->path_list->head; 4336 while (path_list != NULL) { 4337 path_data = path_list->item->idata; 4338 /* 4339 * path class is not reliable for ALUA if the 4340 * vhci has done the update on one of the class 4341 * but ignore to update on another one. 4342 */ 4343 tgt_port = NULL; 4344 if (path_data->valid == 1 && 4345 (mdi_prop_lookup_string(path_data->resp, 4346 SCSI_ADDR_PROP_TARGET_PORT, 4347 &tgt_port) == DDI_PROP_SUCCESS) && 4348 tgt_port != NULL && 4349 (vhci_mpapi_check_tp_in_tpg( 4350 tpg_data, tgt_port) == 1)) { 4351 VHCI_DEBUG(4, (CE_NOTE, NULL, 4352 "vhci_mpapi_update_tpg_acc_state_" 4353 "for_ lu: Operating on LUN(%s), " 4354 " PATH(%p), TPG(%x: %s)\n", 4355 lu_data->prop.name, path_data->resp, 4356 tpg_data->prop.tpgId, 4357 tpg_data->pclass)); 4358 if (MDI_PI_IS_ONLINE(path_data->resp)) { 4359 vhci_mpapi_set_tpg_as_prop(vhci, 4360 tpg_list->item, 4361 MP_DRVR_ACCESS_STATE_ACTIVE); 4362 set_lu_valid = B_TRUE; 4363 break; 4364 } else if (MDI_PI_IS_STANDBY(path_data->resp)) { 4365 vhci_mpapi_set_tpg_as_prop(vhci, 4366 tpg_list->item, 4367 MP_DRVR_ACCESS_STATE_STANDBY); 4368 set_lu_valid = B_TRUE; 4369 break; 4370 } else { 4371 vhci_mpapi_set_tpg_as_prop(vhci, 4372 tpg_list->item, 4373 MP_DRVR_ACCESS_STATE_UNAVAILABLE); 4374 } 4375 } 4376 path_list = path_list->next; 4377 } 4378 tpg_list = tpg_list->next; 4379 } 4380 4381 /* 4382 * Only make LU valid if the encountered path was active or standby. 4383 * Otherwise we would cause the LU to reappear transiently after 4384 * the last path to it has gone and before it is finally marked 4385 * invalid by vhci_mpapi_set_path_state(), causing bogus visibility 4386 * events. 4387 */ 4388 if (set_lu_valid != B_FALSE) 4389 vhci_mpapi_set_lu_valid(vhci, lu_list->item, 1); 4390 4391 return (rval); 4392 } 4393 4394 int 4395 vhci_mpapi_get_vhci(dev_info_t *vdip, void *ptr2vhci) 4396 { 4397 struct scsi_vhci *local_vhci; 4398 4399 if (strncmp("scsi_vhci", ddi_get_name(vdip), 4400 strlen("scsi_vhci")) == 0) { 4401 local_vhci = ddi_get_soft_state(vhci_softstate, 4402 ddi_get_instance(vdip)); 4403 bcopy(&local_vhci, ptr2vhci, sizeof (local_vhci)); 4404 return (DDI_WALK_TERMINATE); 4405 } 4406 4407 return (DDI_WALK_CONTINUE); 4408 4409 } 4410 4411 /* ARGSUSED */ 4412 void * 4413 vhci_mpapi_get_rel_tport_pair(struct scsi_vhci *vhci, mpapi_list_header_t *list, 4414 void *tgt_port, uint32_t rel_tid) 4415 { 4416 mpapi_item_list_t *ilist; 4417 mpapi_tport_data_t *tpd; 4418 4419 if (list == NULL) { 4420 /* 4421 * Since the listhead is null, the search is being 4422 * performed in implicit mode - that is to use the 4423 * level one list. 4424 */ 4425 ilist = vhci->mp_priv->obj_hdr_list[MP_OBJECT_TYPE_TARGET_PORT] 4426 ->head; 4427 } else { 4428 /* 4429 * The search is being performed on a sublist within 4430 * one of the toplevel list items. Use the listhead 4431 * that is passed in. 4432 */ 4433 ilist = list->head; 4434 } 4435 4436 if (tgt_port == NULL) { 4437 VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_get_mpapi_item: " 4438 " Got Target Port w/ NULL resource")); 4439 return (NULL); 4440 } 4441 4442 while (ilist) { 4443 tpd = (mpapi_tport_data_t *)ilist->item->idata; 4444 if ((strncmp(tpd->resp, tgt_port, strlen(tgt_port)) == 0) && 4445 (tpd->prop.relativePortID == rel_tid)) { 4446 /* Match */ 4447 return ((void*)ilist); 4448 } else { 4449 ilist = ilist->next; 4450 } 4451 } 4452 4453 return (NULL); 4454 } 4455 4456 /* 4457 * Returns 0, if 2 more paths are available to the lun; 4458 * Returns 1, if ONLY 1 path is available to the lun; 4459 * Return -1 for all other cases. 4460 */ 4461 static int 4462 vhci_mpapi_chk_last_path(mdi_pathinfo_t *pip) 4463 { 4464 dev_info_t *pdip = NULL, *cdip = NULL; 4465 int count = 0, circular; 4466 mdi_pathinfo_t *ret_pip; 4467 4468 if (pip == NULL) { 4469 return (-1); 4470 } else { 4471 pdip = mdi_pi_get_phci(pip); 4472 cdip = mdi_pi_get_client(pip); 4473 } 4474 4475 if ((pdip == NULL) || (cdip == NULL)) { 4476 return (-1); 4477 } 4478 4479 ndi_devi_enter(cdip, &circular); 4480 ret_pip = mdi_get_next_phci_path(cdip, NULL); 4481 4482 while ((ret_pip != NULL) && (count < 2)) { 4483 mdi_pi_lock(ret_pip); 4484 if ((MDI_PI_IS_ONLINE(ret_pip) || 4485 MDI_PI_IS_STANDBY(ret_pip) || 4486 MDI_PI_IS_INIT(ret_pip)) && 4487 !(MDI_PI_IS_DISABLE(ret_pip) || 4488 MDI_PI_IS_TRANSIENT(ret_pip) || 4489 MDI_PI_FLAGS_IS_DEVICE_REMOVED(ret_pip))) { 4490 count++; 4491 } 4492 mdi_pi_unlock(ret_pip); 4493 ret_pip = mdi_get_next_phci_path(cdip, ret_pip); 4494 } 4495 ndi_devi_exit(cdip, circular); 4496 4497 if (count > 1) { 4498 return (0); 4499 } else if (count == 1) { 4500 return (1); 4501 } 4502 4503 return (-1); 4504 } 4505