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