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