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