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