1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* 27 * SNIA Multipath Management API implementation 28 */ 29 30 #include <sys/conf.h> 31 #include <sys/file.h> 32 #include <sys/disp.h> 33 #include <sys/ddi.h> 34 #include <sys/sunddi.h> 35 #include <sys/sunmdi.h> 36 #include <sys/mdi_impldefs.h> 37 #include <sys/scsi/scsi.h> 38 #include <sys/scsi/impl/services.h> 39 #include <sys/scsi/impl/scsi_reset_notify.h> 40 #include <sys/scsi/adapters/scsi_vhci.h> 41 42 /* used to manually force a request sense */ 43 int vhci_force_manual_sense = 0; 44 45 #define STD_ACTIVE_OPTIMIZED 0x0 46 #define STD_ACTIVE_NONOPTIMIZED 0x1 47 #define STD_STANDBY 0x2 48 #define STD_UNAVAILABLE 0x3 49 #define STD_TRANSITIONING 0xf 50 51 /* 52 * MP-API Prototypes 53 */ 54 int vhci_mpapi_init(struct scsi_vhci *); 55 void vhci_mpapi_add_dev_prod(struct scsi_vhci *, char *); 56 int vhci_mpapi_ctl(dev_t, int, intptr_t, int, cred_t *, int *); 57 void vhci_update_mpapi_data(struct scsi_vhci *, 58 scsi_vhci_lun_t *, mdi_pathinfo_t *); 59 void* vhci_get_mpapi_item(struct scsi_vhci *, mpapi_list_header_t *, 60 uint8_t, void*); 61 int vhci_mpapi_sync_init_port_list(dev_info_t *, void *); 62 int vhci_mpapi_get_vhci(dev_info_t *, void *); 63 void vhci_mpapi_set_path_state(dev_info_t *, mdi_pathinfo_t *, int); 64 void vhci_mpapi_synthesize_tpg_data(struct scsi_vhci *, scsi_vhci_lun_t *, 65 mdi_pathinfo_t *); 66 void vhci_mpapi_update_tpg_data(struct scsi_address *, char *); 67 int vhci_mpapi_update_tpg_acc_state_for_lu(struct scsi_vhci *, 68 scsi_vhci_lun_t *); 69 70 /* Static Functions */ 71 static int vhci_get_driver_prop(struct scsi_vhci *, mp_iocdata_t *, 72 void *, void *, int); 73 static int vhci_get_dev_prod_list(struct scsi_vhci *, mp_iocdata_t *, 74 void *, void *, int); 75 static int vhci_get_dev_prod_prop(struct scsi_vhci *, mp_iocdata_t *, 76 void *, void *, int); 77 static int vhci_get_lu_list(struct scsi_vhci *, mp_iocdata_t *, 78 void *, void *, int); 79 static int vhci_get_lu_list_from_tpg(struct scsi_vhci *, mp_iocdata_t *, 80 void *, void *, int); 81 static int vhci_get_tpg_list_for_lu(struct scsi_vhci *, mp_iocdata_t *, 82 void *, void *, int); 83 static int vhci_get_lu_prop(struct scsi_vhci *, mp_iocdata_t *, 84 void *, void *, int); 85 static int vhci_get_path_list_for_mp_lu(struct scsi_vhci *, mp_iocdata_t *, 86 void *, void *, int); 87 static int vhci_get_path_list_for_init_port(struct scsi_vhci *, mp_iocdata_t *, 88 void *, void *, int); 89 static int vhci_get_path_list_for_target_port(struct scsi_vhci *, 90 mp_iocdata_t *, void *, void *, int); 91 static int vhci_get_path_prop(struct scsi_vhci *, mp_iocdata_t *, 92 void *, void *, int); 93 static int vhci_get_init_port_list(struct scsi_vhci *, mp_iocdata_t *, 94 void *, void *, int); 95 static int vhci_get_init_port_prop(struct scsi_vhci *, mp_iocdata_t *, 96 void *, void *, int); 97 static int vhci_get_target_port_prop(struct scsi_vhci *, mp_iocdata_t *, 98 void *, void *, int); 99 static int vhci_get_tpg_prop(struct scsi_vhci *, mp_iocdata_t *, 100 void *, void *, int); 101 static int vhci_get_target_port_list_for_tpg(struct scsi_vhci *, mp_iocdata_t *, 102 void *, void *, int); 103 static int vhci_set_tpg_access_state(struct scsi_vhci *, mp_iocdata_t *, 104 void *, void *, int); 105 static int vhci_get_prop_lb_list(struct scsi_vhci *, mp_iocdata_t *, 106 void *, void *, int); 107 static int vhci_get_prop_lb_prop(struct scsi_vhci *, mp_iocdata_t *, 108 void *, void *, int); 109 static int vhci_assign_lu_to_tpg(struct scsi_vhci *, mp_iocdata_t *, 110 void *, void *, int); 111 static int vhci_enable_auto_failback(struct scsi_vhci *, mp_iocdata_t *, 112 void *, void *, int); 113 static int vhci_disable_auto_failback(struct scsi_vhci *, mp_iocdata_t *, 114 void *, void *, int); 115 static int vhci_enable_path(struct scsi_vhci *, mp_iocdata_t *, 116 void *, void *, int); 117 static int vhci_disable_path(struct scsi_vhci *, mp_iocdata_t *, 118 void *, void *, int); 119 static int vhci_send_uscsi_cmd(dev_t dev, struct scsi_vhci *, mp_iocdata_t *, 120 void *, void *, int); 121 static int vhci_mpapi_validate(void *, mp_iocdata_t *, int, cred_t *); 122 static uint64_t vhci_mpapi_create_oid(mpapi_priv_t *, uint8_t); 123 static int vhci_mpapi_ioctl(dev_t dev, struct scsi_vhci *, void *, 124 mp_iocdata_t *, int, cred_t *); 125 static int vhci_mpapi_add_to_list(mpapi_list_header_t *, mpapi_item_list_t *); 126 static mpapi_item_list_t *vhci_mpapi_create_item(struct scsi_vhci *, 127 uint8_t, void *); 128 static mpapi_item_list_t *vhci_mpapi_get_tpg_item(struct scsi_vhci *, 129 uint32_t, void *, char *, void *); 130 static mpapi_list_header_t *vhci_mpapi_create_list_head(); 131 static int vhci_get_mpiocdata(const void *, mp_iocdata_t *, int); 132 static int vhci_is_model_type32(int); 133 static int vhci_mpapi_copyout_iocdata(void *, void *, int); 134 static int vhci_mpapi_chk_last_path(mdi_pathinfo_t *); 135 static int vhci_mpapi_sync_lu_oid_list(struct scsi_vhci *); 136 static mpapi_item_list_t *vhci_mpapi_get_tpg_for_lun(struct scsi_vhci *, 137 char *, void *, void *); 138 static int vhci_mpapi_check_tp_in_tpg(mpapi_tpg_data_t *tpgdata, void *tp); 139 static void vhci_mpapi_log_sysevent(dev_info_t *, uint64_t *, char *); 140 static mpapi_item_list_t *vhci_mpapi_match_pip(struct scsi_vhci *, 141 mpapi_item_list_t *, void *); 142 static mpapi_item_list_t *vhci_mpapi_match_lu(struct scsi_vhci *, 143 mpapi_item_list_t *, void *); 144 static void *vhci_mpapi_get_rel_tport_pair(struct scsi_vhci *vhci, 145 mpapi_list_header_t *list, void *tgt_port, uint32_t rel_tid); 146 147 /* 148 * Extern variables, structures and functions 149 */ 150 extern void *vhci_softstate; 151 extern char vhci_version_name[]; 152 extern int vhci_tpgs_set_target_groups(struct scsi_address *, int, int); 153 154 155 extern void mdi_vhci_walk_phcis(dev_info_t *, 156 int (*)(dev_info_t *, void *), void *); 157 extern void vhci_update_pathstates(void *); 158 extern int vhci_uscsi_iostart(struct buf *bp); 159 160 /* 161 * Routine for SCSI VHCI MPAPI IOCTL implementation. 162 */ 163 /* ARGSUSED */ 164 int 165 vhci_mpapi_ctl(dev_t dev, int cm, intptr_t data, int mode, 166 cred_t *credp, int *rval) 167 { 168 struct scsi_vhci *vhci; 169 dev_info_t *vdip; 170 int retval = 0; 171 mp_iocdata_t mpio_blk; 172 mp_iocdata_t *mpioc = &mpio_blk; 173 174 /* Check for validity of vhci structure */ 175 vhci = ddi_get_soft_state(vhci_softstate, MINOR2INST(getminor(dev))); 176 if (vhci == NULL) { 177 return (ENXIO); 178 } 179 180 mutex_enter(&vhci->vhci_mutex); 181 if ((vhci->vhci_state & VHCI_STATE_OPEN) == 0) { 182 mutex_exit(&vhci->vhci_mutex); 183 return (ENXIO); 184 } 185 mutex_exit(&vhci->vhci_mutex); 186 187 /* Get the vhci dip */ 188 vdip = vhci->vhci_dip; 189 ASSERT(vdip != NULL); 190 191 /* 192 * Get IOCTL parameters from userland 193 */ 194 if (vhci_get_mpiocdata((const void *)data, mpioc, mode) != 0) { 195 VHCI_DEBUG(1, (CE_WARN, NULL, "!vhci_mpapi_ctl: " 196 "vhci_get_mpiocdata() failed")); 197 } 198 if (mpioc->mp_cmd < MP_API_SUBCMD_MIN || 199 mpioc->mp_cmd > MP_API_SUBCMD_MAX) { 200 return (ENXIO); 201 } 202 203 retval = vhci_mpapi_ioctl(dev, vhci, (void *)data, mpioc, mode, credp); 204 205 return (retval); 206 } 207 208 /* ARGSUSED */ 209 static int 210 vhci_mpapi_validate(void *udata, mp_iocdata_t *mpioc, int mode, cred_t *credp) 211 { 212 int rval = 0, olen = 0; 213 int mode32 = 0; 214 215 if (vhci_is_model_type32(mode) == 1) { 216 mode32 = 1; 217 } 218 219 switch (mpioc->mp_cmd) { 220 221 case MP_GET_DEV_PROD_LIST: 222 case MP_GET_LU_LIST: /* XXX: This wont come; Plugin already has it */ 223 case MP_GET_INIT_PORT_LIST: /* XXX: This call wont come either */ 224 case MP_GET_TPG_LIST: 225 case MP_GET_PROPRIETARY_LOADBALANCE_LIST: 226 { 227 if ((mpioc->mp_olen == 0) || 228 (mpioc->mp_obuf == NULL) || 229 (mpioc->mp_xfer != MP_XFER_READ)) { 230 rval = EINVAL; 231 } 232 if (mpioc->mp_olen == 0) { 233 /* We don't know alen yet, No point trying to set it */ 234 mpioc->mp_errno = MP_MORE_DATA; 235 rval = MP_MORE_DATA; 236 } 237 } 238 break; 239 240 case MP_GET_DRIVER_PROP: 241 { 242 olen = sizeof (mp_driver_prop_t); 243 /* Adjust olen to account for the caddr_t in 32-bit mode */ 244 if (mode32 == 1) { 245 olen -= 4; 246 } 247 248 if ((mpioc->mp_obuf == NULL) || 249 (mpioc->mp_olen < olen) || 250 (mpioc->mp_xfer != MP_XFER_READ)) { 251 rval = EINVAL; 252 } 253 if (mpioc->mp_olen < olen) { 254 mpioc->mp_alen = olen; 255 mpioc->mp_errno = MP_MORE_DATA; 256 } 257 } 258 break; 259 260 case MP_GET_DEV_PROD_PROP: 261 { 262 olen = sizeof (mp_dev_prod_prop_t); 263 264 if ((mpioc->mp_olen < olen) || 265 (mpioc->mp_ilen < sizeof (uint64_t)) || 266 (mpioc->mp_obuf == NULL) || 267 (mpioc->mp_ibuf == NULL) || 268 (mpioc->mp_xfer != MP_XFER_READ)) { 269 rval = EINVAL; 270 } 271 if (mpioc->mp_olen < olen) { 272 mpioc->mp_alen = olen; 273 mpioc->mp_errno = MP_MORE_DATA; 274 } 275 } 276 break; 277 278 case MP_GET_LU_PROP: 279 { 280 olen = sizeof (mp_logical_unit_prop_t); 281 /* Adjust olen to account for the caddr_t in 32-bit mode */ 282 if (mode32 == 1) { 283 olen -= 4; 284 } 285 286 if ((mpioc->mp_ilen != sizeof (uint64_t)) || 287 (mpioc->mp_ibuf == NULL) || 288 (mpioc->mp_olen < olen) || 289 (mpioc->mp_obuf == NULL) || 290 (mpioc->mp_xfer != MP_XFER_READ)) { 291 rval = EINVAL; 292 } 293 if (mpioc->mp_olen < olen) { 294 mpioc->mp_alen = olen; 295 mpioc->mp_errno = MP_MORE_DATA; 296 } 297 } 298 break; 299 300 case MP_GET_PATH_PROP: 301 { 302 olen = sizeof (mp_path_prop_t); 303 /* Adjust olen to account for the caddr_t in 32-bit mode */ 304 if (mode32 == 1) { 305 olen -= 4; 306 } 307 308 if ((mpioc->mp_ilen != sizeof (uint64_t)) || 309 (mpioc->mp_ibuf == NULL) || 310 (mpioc->mp_olen < olen) || 311 (mpioc->mp_obuf == NULL) || 312 (mpioc->mp_xfer != MP_XFER_READ)) { 313 rval = EINVAL; 314 } 315 if (mpioc->mp_olen < olen) { 316 mpioc->mp_alen = olen; 317 mpioc->mp_errno = MP_MORE_DATA; 318 } 319 } 320 break; 321 322 case MP_GET_INIT_PORT_PROP: 323 { 324 olen = sizeof (mp_init_port_prop_t); 325 326 if ((mpioc->mp_ilen != sizeof (uint64_t)) || 327 (mpioc->mp_ibuf == NULL) || 328 (mpioc->mp_olen < olen) || 329 (mpioc->mp_obuf == NULL) || 330 (mpioc->mp_xfer != MP_XFER_READ)) { 331 rval = EINVAL; 332 } 333 if (mpioc->mp_olen < olen) { 334 mpioc->mp_alen = olen; 335 mpioc->mp_errno = MP_MORE_DATA; 336 } 337 } 338 break; 339 340 case MP_GET_TARGET_PORT_PROP: 341 { 342 olen = sizeof (mp_target_port_prop_t); 343 344 if ((mpioc->mp_ilen != sizeof (uint64_t)) || 345 (mpioc->mp_ibuf == NULL) || 346 (mpioc->mp_olen < olen) || 347 (mpioc->mp_obuf == NULL) || 348 (mpioc->mp_xfer != MP_XFER_READ)) { 349 rval = EINVAL; 350 } 351 if (mpioc->mp_olen < olen) { 352 mpioc->mp_alen = olen; 353 mpioc->mp_errno = MP_MORE_DATA; 354 } 355 } 356 break; 357 358 case MP_GET_TPG_PROP: 359 { 360 olen = sizeof (mp_tpg_prop_t); 361 362 if ((mpioc->mp_ilen != sizeof (uint64_t)) || 363 (mpioc->mp_ibuf == NULL) || 364 (mpioc->mp_olen < olen) || 365 (mpioc->mp_obuf == NULL) || 366 (mpioc->mp_xfer != MP_XFER_READ)) { 367 rval = EINVAL; 368 } 369 if (mpioc->mp_olen < olen) { 370 mpioc->mp_alen = olen; 371 mpioc->mp_errno = MP_MORE_DATA; 372 } 373 } 374 break; 375 376 case MP_GET_PROPRIETARY_LOADBALANCE_PROP: 377 { 378 olen = sizeof (mp_proprietary_loadbalance_prop_t); 379 /* Adjust olen to account for the caddr_t in 32-bit mode */ 380 if (mode32 == 1) { 381 olen -= 4; 382 } 383 384 if ((mpioc->mp_ilen != sizeof (uint64_t)) || 385 (mpioc->mp_ibuf == NULL) || 386 (mpioc->mp_olen < olen) || 387 (mpioc->mp_obuf == NULL) || 388 (mpioc->mp_xfer != MP_XFER_READ)) { 389 rval = EINVAL; 390 } 391 if (mpioc->mp_olen < olen) { 392 mpioc->mp_alen = olen; 393 mpioc->mp_errno = MP_MORE_DATA; 394 } 395 } 396 break; 397 398 case MP_GET_PATH_LIST_FOR_MP_LU: 399 case MP_GET_PATH_LIST_FOR_INIT_PORT: 400 case MP_GET_PATH_LIST_FOR_TARGET_PORT: 401 case MP_GET_LU_LIST_FROM_TPG: 402 case MP_GET_TPG_LIST_FOR_LU: 403 case MP_GET_TARGET_PORT_LIST_FOR_TPG: 404 { 405 if ((mpioc->mp_ilen != sizeof (uint64_t)) || 406 (mpioc->mp_ibuf == NULL) || 407 (mpioc->mp_olen == 0) || 408 (mpioc->mp_obuf == NULL) || 409 (mpioc->mp_xfer != MP_XFER_READ)) { 410 rval = EINVAL; 411 } 412 if (mpioc->mp_olen == 0) { 413 /* We don't know alen yet, No point trying to set it */ 414 mpioc->mp_errno = MP_MORE_DATA; 415 rval = MP_MORE_DATA; 416 } 417 } 418 break; 419 420 case MP_SET_TPG_ACCESS_STATE: 421 { 422 if (drv_priv(credp) != 0) { 423 rval = EPERM; 424 break; 425 } 426 if ((mpioc->mp_ilen != sizeof (mp_set_tpg_state_req_t)) || 427 (mpioc->mp_ibuf == NULL) || 428 (mpioc->mp_xfer != MP_XFER_WRITE)) { 429 rval = EINVAL; 430 } 431 } 432 break; 433 434 case MP_ENABLE_AUTO_FAILBACK: 435 case MP_DISABLE_AUTO_FAILBACK: 436 { 437 if (drv_priv(credp) != 0) { 438 rval = EPERM; 439 break; 440 } 441 if ((mpioc->mp_ibuf == NULL) || 442 (mpioc->mp_xfer != MP_XFER_WRITE)) { 443 rval = EINVAL; 444 } 445 } 446 break; 447 448 case MP_ENABLE_PATH: 449 case MP_DISABLE_PATH: 450 { 451 if (drv_priv(credp) != 0) { 452 rval = EPERM; 453 break; 454 } 455 if ((mpioc->mp_ilen != sizeof (uint64_t)) || 456 (mpioc->mp_ibuf == NULL) || 457 (mpioc->mp_xfer != MP_XFER_WRITE)) { 458 rval = EINVAL; 459 } 460 } 461 break; 462 463 case MP_SEND_SCSI_CMD: 464 { 465 cred_t *cr; 466 int olen = 0; 467 468 cr = ddi_get_cred(); 469 if (drv_priv(credp) != 0 && drv_priv(cr) != 0) { 470 rval = EPERM; 471 break; 472 } 473 if (mode32 == 1) { 474 olen = sizeof (struct uscsi_cmd32); 475 } else { 476 olen = sizeof (struct uscsi_cmd); 477 } 478 /* oid is in the ibuf and the uscsi cmd is in the obuf */ 479 if ((mpioc->mp_ilen != sizeof (uint64_t)) || 480 (mpioc->mp_ibuf == NULL) || 481 (mpioc->mp_olen != olen) || 482 (mpioc->mp_obuf == NULL)) { 483 rval = EINVAL; 484 } 485 } 486 break; 487 488 case MP_ASSIGN_LU_TO_TPG: 489 { 490 if (drv_priv(credp) != 0) { 491 rval = EPERM; 492 break; 493 } 494 if ((mpioc->mp_ilen != sizeof (mp_lu_tpg_pair_t)) || 495 (mpioc->mp_ibuf == NULL) || 496 (mpioc->mp_xfer != MP_XFER_WRITE)) { 497 rval = EINVAL; 498 } 499 } 500 break; 501 502 default: 503 { 504 rval = EINVAL; 505 } 506 507 } /* Closing the main switch */ 508 509 return (rval); 510 } 511 512 /* ARGSUSED */ 513 static int 514 vhci_get_driver_prop(struct scsi_vhci *vhci, mp_iocdata_t *mpioc, 515 void *input_data, void *output_data, int mode) 516 { 517 int rval = 0; 518 mp_driver_prop_t *mpdp = (mp_driver_prop_t *)output_data; 519 520 if (output_data == NULL) { 521 return (EINVAL); 522 } 523 524 (void) strlcpy(mpdp->driverVersion, vhci_version_name, 525 sizeof (mpdp->driverVersion)); 526 mpdp->supportedLoadBalanceTypes = 527 MP_DRVR_LOAD_BALANCE_TYPE_NONE | 528 MP_DRVR_LOAD_BALANCE_TYPE_ROUNDROBIN | 529 MP_DRVR_LOAD_BALANCE_TYPE_LBA_REGION; 530 mpdp->canSetTPGAccess = B_TRUE; 531 mpdp->canOverridePaths = B_FALSE; 532 mpdp->exposesPathDeviceFiles = B_FALSE; 533 (void) strlcpy(mpdp->deviceFileNamespace, "/devices/scsi_vhci", 534 sizeof (mpdp->deviceFileNamespace)); 535 mpdp->onlySupportsSpecifiedProducts = 1; 536 mpdp->maximumWeight = 1; 537 mpdp->failbackPollingRateMax = 0; 538 mpdp->currentFailbackPollingRate = 0; 539 mpdp->autoFailbackSupport = MP_DRVR_AUTO_FAILBACK_SUPPORT; 540 mutex_enter(&vhci->vhci_mutex); 541 mpdp->autoFailbackEnabled = 542 ((vhci->vhci_conf_flags & VHCI_CONF_FLAGS_AUTO_FAILBACK) ? 543 1 : 0); 544 mutex_exit(&vhci->vhci_mutex); 545 mpdp->defaultLoadBalanceType = 546 MP_DRVR_LOAD_BALANCE_TYPE_ROUNDROBIN; 547 mpdp->probingPollingRateMax = 0; 548 mpdp->currentProbingPollingRate = 0; 549 mpdp->autoProbingSupport = 0; 550 mpdp->autoProbingEnabled = 0; 551 552 if (ddi_copyout(output_data, (void *)mpioc->mp_obuf, 553 mpioc->mp_olen, mode) != 0) { 554 VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_get_driver_prop: " 555 "ddi_copyout() for 64-bit failed")); 556 mpioc->mp_errno = EFAULT; 557 } else { 558 mpioc->mp_errno = 0; 559 mpioc->mp_alen = sizeof (mp_iocdata_t); 560 } 561 562 return (rval); 563 } 564 565 /* ARGSUSED */ 566 static int 567 vhci_get_dev_prod_list(struct scsi_vhci *vhci, mp_iocdata_t *mpioc, 568 void *input_data, void *output_data, int mode) 569 { 570 int count = 0, rval = 0; 571 int list_len = mpioc->mp_olen/sizeof (uint64_t); 572 uint64_t *oid_list = (uint64_t *)(output_data); 573 mpapi_item_list_t *ilist; 574 575 if (output_data == NULL) { 576 return (EINVAL); 577 } 578 579 /* 580 * XXX: Get the Plugin OID from the input_data and apply below 581 * Currently, we know we have only 1 plugin, so it ok to directly 582 * return this only plugin's device product list. 583 */ 584 585 ilist = vhci->mp_priv-> 586 obj_hdr_list[MP_OBJECT_TYPE_DEVICE_PRODUCT]->head; 587 588 while (ilist != NULL) { 589 if (count < list_len) { 590 oid_list[count] = (uint64_t)ilist->item->oid.raw_oid; 591 } else { 592 rval = MP_MORE_DATA; 593 } 594 ilist = ilist->next; 595 count++; 596 } 597 598 mpioc->mp_alen = (uint32_t)(count * sizeof (uint64_t)); 599 if ((rval == MP_MORE_DATA) || (mpioc->mp_alen > mpioc->mp_olen)) { 600 mpioc->mp_errno = MP_MORE_DATA; 601 return (EINVAL); 602 } 603 604 if (ddi_copyout(output_data, (void *)mpioc->mp_obuf, 605 (count * sizeof (uint64_t)), mode) != 0) { 606 VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_get_dev_prod_list: " 607 "ddi_copyout() failed")); 608 mpioc->mp_errno = EFAULT; 609 rval = EINVAL; 610 } else { 611 mpioc->mp_errno = 0; 612 } 613 614 return (rval); 615 } 616 617 /* ARGSUSED */ 618 static int 619 vhci_get_dev_prod_prop(struct scsi_vhci *vhci, mp_iocdata_t *mpioc, 620 void *input_data, void *output_data, int mode) 621 { 622 int rval = 0; 623 uint64_t *oid = (uint64_t *)(input_data); 624 mp_dev_prod_prop_t *dev_prop = NULL; 625 mpapi_item_list_t *ilist; 626 627 if ((output_data == NULL) || (input_data == NULL)) { 628 return (EINVAL); 629 } 630 ilist = vhci->mp_priv-> 631 obj_hdr_list[MP_OBJECT_TYPE_DEVICE_PRODUCT]->head; 632 while ((ilist != NULL) && (*oid != ilist->item->oid.raw_oid)) { 633 ilist = ilist->next; 634 } 635 if (ilist != NULL) { 636 dev_prop = (mp_dev_prod_prop_t *)(ilist->item->idata); 637 if (dev_prop == NULL) { 638 return (EINVAL); 639 } 640 } else { 641 VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_get_dev_prod_prop: " 642 "OID NOT FOUND")); 643 mpioc->mp_errno = MP_DRVR_INVALID_ID; 644 return (EINVAL); 645 } 646 /* 647 * Here were are not using the 'output_data' that is 648 * passed as the required information is already 649 * in the required format! 650 */ 651 if (ddi_copyout((void *)dev_prop, mpioc->mp_obuf, 652 sizeof (mp_dev_prod_prop_t), mode) != 0) { 653 return (EFAULT); 654 } 655 return (rval); 656 } 657 658 /* ARGSUSED */ 659 static int 660 vhci_get_lu_list(struct scsi_vhci *vhci, mp_iocdata_t *mpioc, 661 void *input_data, void *output_data, int mode) 662 { 663 int count = 0, rval = 0; 664 int list_len = mpioc->mp_olen/sizeof (uint64_t); 665 uint64_t *oid_list = (uint64_t *)(output_data); 666 mpapi_item_list_t *ilist; 667 mpapi_lu_data_t *ld; 668 669 if (output_data == NULL) { 670 return (EINVAL); 671 } 672 673 ilist = vhci->mp_priv->obj_hdr_list[MP_OBJECT_TYPE_MULTIPATH_LU]->head; 674 675 while (ilist != NULL) { 676 if (count < list_len) { 677 oid_list[count] = (uint64_t)(ilist->item->oid.raw_oid); 678 } else { 679 rval = MP_MORE_DATA; 680 } 681 ld = ilist->item->idata; 682 if (ld->valid == 0) { 683 count--; 684 } 685 ilist = ilist->next; 686 count++; 687 } 688 689 mpioc->mp_alen = (uint32_t)(count * sizeof (uint64_t)); 690 if ((rval == MP_MORE_DATA) || (mpioc->mp_alen > mpioc->mp_olen)) { 691 mpioc->mp_errno = MP_MORE_DATA; 692 return (EINVAL); 693 } 694 695 if (ddi_copyout(output_data, (void *)mpioc->mp_obuf, 696 (count * sizeof (uint64_t)), mode) != 0) { 697 VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_get_lu_list: " 698 "ddi_copyout() FAILED")); 699 mpioc->mp_errno = EFAULT; 700 rval = EINVAL; 701 } else { 702 mpioc->mp_errno = 0; 703 } 704 705 return (rval); 706 } 707 708 /* ARGSUSED */ 709 static int 710 vhci_get_lu_list_from_tpg(struct scsi_vhci *vhci, mp_iocdata_t *mpioc, 711 void *input_data, void *output_data, int mode) 712 { 713 int count = 0, rval = 0; 714 int list_len = mpioc->mp_olen/sizeof (uint64_t); 715 uint64_t *oid_list = (uint64_t *)(output_data); 716 uint64_t *oid = (uint64_t *)(input_data); 717 mpapi_item_list_t *ilist, *tpg_lu_list = NULL; 718 mpapi_tpg_data_t *mptpglu; 719 mpapi_lu_data_t *ld; 720 721 ilist = vhci->mp_priv->obj_hdr_list[MP_OBJECT_TYPE_TARGET_PORT_GROUP] 722 ->head; 723 724 while ((ilist != NULL) && (*oid != ilist->item->oid.raw_oid)) 725 ilist = ilist->next; 726 727 if (ilist == NULL) { 728 VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_get_lu_list_from_tpg: " 729 "OID NOT FOUND")); 730 mpioc->mp_errno = MP_DRVR_INVALID_ID; 731 rval = EINVAL; 732 } else if (*oid == ilist->item->oid.raw_oid) { 733 mptpglu = (mpapi_tpg_data_t *)(ilist->item->idata); 734 if (mptpglu->valid == 0) { 735 VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_get_lu_list_from_" 736 "tpg: OID NOT FOUND - TPG IS INVALID")); 737 mpioc->mp_errno = MP_DRVR_INVALID_ID; 738 return (EINVAL); 739 } 740 tpg_lu_list = mptpglu->lu_list->head; 741 } else { 742 VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_get_lu_list_from_tpg: " 743 "Unknown Error")); 744 } 745 746 while (tpg_lu_list != NULL) { 747 if (count < list_len) { 748 oid_list[count] = (uint64_t)tpg_lu_list-> 749 item->oid.raw_oid; 750 } else { 751 rval = MP_MORE_DATA; 752 } 753 /* 754 * Get rid of the latest entry if item is invalid 755 */ 756 ld = tpg_lu_list->item->idata; 757 if (ld->valid == 0) { 758 count--; 759 } 760 tpg_lu_list = tpg_lu_list->next; 761 count++; 762 } 763 764 mpioc->mp_alen = (uint32_t)(count * sizeof (uint64_t)); 765 if ((rval == MP_MORE_DATA) || (mpioc->mp_alen > mpioc->mp_olen)) { 766 mpioc->mp_errno = MP_MORE_DATA; 767 return (EINVAL); 768 } 769 770 if ((count > 0) && (ddi_copyout(output_data, (void *)mpioc->mp_obuf, 771 (count * sizeof (uint64_t)), mode) != 0)) { 772 VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_get_lu_list_from_tpg: " 773 "ddi_copyout() FAILED")); 774 mpioc->mp_errno = EFAULT; 775 rval = EINVAL; 776 } 777 778 return (rval); 779 } 780 781 /* ARGSUSED */ 782 static int 783 vhci_get_tpg_list_for_lu(struct scsi_vhci *vhci, mp_iocdata_t *mpioc, 784 void *input_data, void *output_data, int mode) 785 { 786 int count = 0, rval = 0; 787 int list_len = mpioc->mp_olen/sizeof (uint64_t); 788 uint64_t *oid_list = (uint64_t *)(output_data); 789 uint64_t *oid = (uint64_t *)(input_data); 790 mpapi_item_list_t *ilist, *mplu_tpg_list = NULL; 791 mpapi_lu_data_t *mplutpg; 792 mpapi_tpg_data_t *tpgd; 793 794 ilist = vhci->mp_priv->obj_hdr_list[MP_OBJECT_TYPE_MULTIPATH_LU]->head; 795 796 while ((ilist != NULL) && (*oid != ilist->item->oid.raw_oid)) 797 ilist = ilist->next; 798 799 if (ilist == NULL) { 800 VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_get_tpg_list_for_lu: " 801 "OID NOT FOUND")); 802 mpioc->mp_errno = MP_DRVR_INVALID_ID; 803 rval = EINVAL; 804 } else if (*oid == ilist->item->oid.raw_oid) { 805 mplutpg = (mpapi_lu_data_t *)(ilist->item->idata); 806 if (mplutpg->valid == 0) { 807 VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_get_tpg_list_for_" 808 "lu: OID NOT FOUND - LU IS OFFLINE")); 809 mpioc->mp_errno = MP_DRVR_INVALID_ID; 810 return (EINVAL); 811 } 812 mplu_tpg_list = mplutpg->tpg_list->head; 813 } else { 814 VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_get_tpg_list_for_lu: " 815 "Unknown Error")); 816 } 817 818 while (mplu_tpg_list != NULL) { 819 if (count < list_len) { 820 oid_list[count] = 821 (uint64_t)mplu_tpg_list->item->oid.raw_oid; 822 } else { 823 rval = MP_MORE_DATA; 824 } 825 tpgd = mplu_tpg_list->item->idata; 826 if (tpgd->valid == 0) { 827 count--; 828 } 829 mplu_tpg_list = mplu_tpg_list->next; 830 count++; 831 } 832 833 mpioc->mp_alen = (uint32_t)(count * sizeof (uint64_t)); 834 if ((rval == MP_MORE_DATA) || (mpioc->mp_alen > mpioc->mp_olen)) { 835 mpioc->mp_errno = MP_MORE_DATA; 836 return (EINVAL); 837 } 838 839 if ((count > 0) && (ddi_copyout(output_data, (void *)mpioc->mp_obuf, 840 (count * sizeof (uint64_t)), mode) != 0)) { 841 VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_get_tpg_list_for_lu: " 842 "ddi_copyout() FAILED")); 843 mpioc->mp_errno = EFAULT; 844 rval = EINVAL; 845 } 846 847 return (rval); 848 } 849 850 /* ARGSUSED */ 851 static int 852 vhci_get_lu_prop(struct scsi_vhci *vhci, mp_iocdata_t *mpioc, 853 void *input_data, void *output_data, int mode) 854 { 855 int rval = 0; 856 uint64_t *oid = (uint64_t *)(input_data); 857 mp_logical_unit_prop_t *mplup_prop; 858 mpapi_item_list_t *ilist; 859 mpapi_lu_data_t *mplup; 860 861 mplup_prop = (mp_logical_unit_prop_t *)output_data; 862 ilist = vhci->mp_priv->obj_hdr_list[MP_OBJECT_TYPE_MULTIPATH_LU]->head; 863 864 while ((ilist != NULL) && (*oid != ilist->item->oid.raw_oid)) { 865 ilist = ilist->next; 866 } 867 868 if (ilist != NULL) { 869 mplup = (mpapi_lu_data_t *)(ilist->item->idata); 870 if (mplup == NULL) { 871 VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_get_lu_prop: " 872 "idata in ilist is NULL")); 873 return (EINVAL); 874 } else if (mplup->valid == 0) { 875 VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_get_lu_prop: " 876 "OID NOT FOUND - LU GONE OFFLINE")); 877 mpioc->mp_errno = MP_DRVR_INVALID_ID; 878 return (EINVAL); 879 } 880 mplup_prop = (mp_logical_unit_prop_t *)(&mplup->prop); 881 } else { 882 VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_get_lu_prop: " 883 "OID NOT FOUND")); 884 mpioc->mp_errno = MP_DRVR_INVALID_ID; 885 return (EINVAL); 886 } 887 888 /* 889 * Here were are not using the 'output_data' that is 890 * passed as the required information is already 891 * in the required format! 892 */ 893 if (ddi_copyout((void *)mplup_prop, mpioc->mp_obuf, 894 sizeof (mp_logical_unit_prop_t), mode) != 0) { 895 return (EFAULT); 896 } 897 return (rval); 898 } 899 900 /* ARGSUSED */ 901 static int 902 vhci_get_path_list_for_mp_lu(struct scsi_vhci *vhci, mp_iocdata_t *mpioc, 903 void *input_data, void *output_data, int mode) 904 { 905 int count = 0, rval = 0; 906 int list_len = mpioc->mp_olen/sizeof (uint64_t); 907 uint64_t *oid_list = (uint64_t *)(output_data); 908 uint64_t *oid = (uint64_t *)(input_data); 909 mpapi_item_list_t *ilist, *mplu_path_list = NULL; 910 mpapi_lu_data_t *mplup; 911 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 { 3373 struct scsi_vhci_lun *vlun; 3374 struct scsi_vhci *vhci; 3375 struct scsi_device *psd = NULL; 3376 scsi_vhci_priv_t *svp; 3377 mdi_pathinfo_t *pip; 3378 dev_info_t *pdip; 3379 char tpg_id[16], *tgt_port, *init = NULL; 3380 uint32_t int_tpg_id, rel_tid, as; 3381 int i, rel_tport_cnt; 3382 mpapi_item_list_t *path_list, *init_list; 3383 mpapi_item_list_t *tp_path_list, *init_path_list, *lu_path_list; 3384 mpapi_item_list_t *tpg_tport_list, *tpg_lu_list, *lu_list; 3385 mpapi_item_list_t *lu_tpg_list, *item_list, *tpg_list, *tgt_list; 3386 mpapi_lu_data_t *ld; 3387 mpapi_tpg_data_t *tpg_data; 3388 mpapi_path_data_t *pd; 3389 mpapi_tport_data_t *tpd; 3390 mpapi_initiator_data_t *initd; 3391 3392 /* 3393 * Find out the TPG ID (resource ptr for TPG is T10 TPG ID) 3394 */ 3395 int_tpg_id = ((ptr[2] & 0xff) << 8) | (ptr[3] & 0xff); 3396 (void) sprintf(tpg_id, "%04x", int_tpg_id); 3397 3398 /* 3399 * Check the TPG's accessState; we'll use it later. 3400 */ 3401 as = (ptr[0] & 0x0f); 3402 if (as == STD_ACTIVE_OPTIMIZED) { 3403 as = MP_DRVR_ACCESS_STATE_ACTIVE_OPTIMIZED; 3404 } else if (as == STD_ACTIVE_NONOPTIMIZED) { 3405 as = MP_DRVR_ACCESS_STATE_ACTIVE_NONOPTIMIZED; 3406 } else if (as == STD_STANDBY) { 3407 as = MP_DRVR_ACCESS_STATE_STANDBY; 3408 } else { 3409 as = MP_DRVR_ACCESS_STATE_UNAVAILABLE; 3410 VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_mpapi_update_tpg_data: " 3411 "UNAVAILABLE accessState seen in ALUA TPG setup")); 3412 } 3413 3414 /* 3415 * The scsi_address passed is associated with a scsi_vhci allocated 3416 * scsi_device structure for a pathinfo node. Getting the vlun from 3417 * this is a bit complicated. 3418 */ 3419 if (ap->a_hba_tran->tran_hba_flags & SCSI_HBA_ADDR_COMPLEX) 3420 psd = scsi_address_device(ap); 3421 else if (ap->a_hba_tran->tran_hba_flags & SCSI_HBA_TRAN_CLONE) 3422 psd = ap->a_hba_tran->tran_sd; 3423 ASSERT(psd); 3424 pip = (mdi_pathinfo_t *)psd->sd_pathinfo; 3425 3426 /* 3427 * It is possable for this code to be called without the sd_pathinfo 3428 * being set. This may happen as part of a probe to see if a device 3429 * should be mapped under mdi. At this point we know enough to answer 3430 * correctly so we can return. 3431 */ 3432 if (pip == NULL) 3433 return; 3434 svp = (scsi_vhci_priv_t *)mdi_pi_get_vhci_private(pip); 3435 vlun = svp->svp_svl; 3436 3437 /* 3438 * Now get the vhci ptr using the walker 3439 */ 3440 mdi_walk_vhcis(vhci_mpapi_get_vhci, &vhci); 3441 3442 VHCI_DEBUG(4, (CE_NOTE, NULL, "vhci_mpapi_update_tpg_data: vhci=%p, " 3443 "(vlun)wwn=(%p)%s, pip=%p, ap=%p, ptr=%p, as=%x, tpg_id=%s, fops=" 3444 "%p\n", (void *)vhci, (void *)vlun, 3445 vlun ? vlun->svl_lun_wwn : "NONE", 3446 (void *)pip, (void *)ap, (void *)ptr, as, tpg_id, 3447 (void *)(vlun ? vlun->svl_fops : NULL))); 3448 3449 if ((vhci == NULL) || (vlun == NULL) || 3450 !SCSI_FAILOVER_IS_TPGS(vlun->svl_fops)) { 3451 /* Cant help, unfortunate situation */ 3452 return; 3453 } 3454 3455 /* 3456 * LEVEL 1 - Actions: 3457 * Check if the appropriate resource pointers already 3458 * exist in the Level 1 list and add them if they are new. 3459 */ 3460 3461 /* 3462 * Build MP LU list 3463 */ 3464 lu_list = vhci_get_mpapi_item(vhci, NULL, 3465 MP_OBJECT_TYPE_MULTIPATH_LU, (void*)vlun); 3466 if (lu_list == NULL) { 3467 /* Need to create lu_list entry */ 3468 lu_list = vhci_mpapi_create_item(vhci, 3469 MP_OBJECT_TYPE_MULTIPATH_LU, (void*)vlun); 3470 } else { 3471 /* 3472 * Matched this lu w/ an existing one in current lu list. 3473 * SAME LUN came online!! So, update the resp in main list. 3474 */ 3475 ld = lu_list->item->idata; 3476 ld->valid = 1; 3477 ld->resp = vlun; 3478 } 3479 3480 /* 3481 * Build Path LU list 3482 */ 3483 path_list = vhci_get_mpapi_item(vhci, NULL, 3484 MP_OBJECT_TYPE_PATH_LU, (void*)pip); 3485 if (path_list == NULL) { 3486 /* Need to create path_list entry */ 3487 path_list = vhci_mpapi_create_item(vhci, 3488 MP_OBJECT_TYPE_PATH_LU, (void*)pip); 3489 } else { 3490 /* 3491 * Matched this pip w/ an existing one in current pip list. 3492 * SAME PATH came online!! So, update the resp in main list. 3493 */ 3494 pd = path_list->item->idata; 3495 pd->valid = 1; 3496 pd->resp = pip; 3497 } 3498 3499 if (MDI_PI_IS_ONLINE(pip)) { 3500 vhci_mpapi_set_path_state(vhci->vhci_dip, pip, 3501 MP_DRVR_PATH_STATE_ACTIVE); 3502 } else if (MDI_PI_IS_STANDBY(pip)) { 3503 vhci_mpapi_set_path_state(vhci->vhci_dip, pip, 3504 MP_DRVR_PATH_STATE_PASSIVE); 3505 } else { 3506 vhci_mpapi_set_path_state(vhci->vhci_dip, pip, 3507 MP_DRVR_PATH_STATE_UNKNOWN); 3508 } 3509 3510 /* 3511 * Build Initiator Port list 3512 */ 3513 pdip = mdi_pi_get_phci(pip); 3514 init = kmem_zalloc(MAXPATHLEN, KM_SLEEP); 3515 (void) ddi_pathname(pdip, init); 3516 3517 init_list = vhci_get_mpapi_item(vhci, NULL, 3518 MP_OBJECT_TYPE_INITIATOR_PORT, (void*)init); 3519 if (init_list == NULL) { 3520 /* 3521 * Need to create init_list entry 3522 * The resource ptr is no really pdip. It will be changed 3523 * in vhci_mpapi_create_item(). The real resource ptr 3524 * is the Port ID. But we pass the pdip, to create OID. 3525 */ 3526 init_list = vhci_mpapi_create_item(vhci, 3527 MP_OBJECT_TYPE_INITIATOR_PORT, (void*)pdip); 3528 } else { 3529 initd = init_list->item->idata; 3530 initd->valid = 1; 3531 } 3532 kmem_free(init, MAXPATHLEN); 3533 3534 /* 3535 * LEVEL 2 - Actions: 3536 * Since all the Object type item lists are updated to account 3537 * for the new resources, now lets cross-reference these 3538 * resources (mainly through paths) to maintain the 3539 * relationship between them. 3540 */ 3541 3542 ld = (mpapi_lu_data_t *)lu_list->item->idata; 3543 if (vhci_get_mpapi_item(vhci, ld->path_list, 3544 MP_OBJECT_TYPE_PATH_LU, (void*)pip) == NULL) { 3545 lu_path_list = kmem_zalloc(sizeof (mpapi_item_list_t), 3546 KM_SLEEP); 3547 lu_path_list->item = path_list->item; 3548 (void) vhci_mpapi_add_to_list(ld->path_list, lu_path_list); 3549 } 3550 3551 initd = (mpapi_initiator_data_t *)init_list->item->idata; 3552 if (vhci_get_mpapi_item(vhci, initd->path_list, 3553 MP_OBJECT_TYPE_PATH_LU, (void*)pip) == NULL) { 3554 init_path_list = kmem_zalloc(sizeof (mpapi_item_list_t), 3555 KM_SLEEP); 3556 init_path_list->item = path_list->item; 3557 (void) vhci_mpapi_add_to_list(initd->path_list, init_path_list); 3558 } 3559 3560 /* 3561 * Create Level 1 & Level 2 data structures 3562 * Parse REPORT_TARGET_PORT_GROUP data & update mpapi database. 3563 */ 3564 3565 tpg_list = vhci_get_mpapi_item(vhci, NULL, 3566 MP_OBJECT_TYPE_TARGET_PORT_GROUP, &tpg_id); 3567 if (tpg_list == NULL) { 3568 tpg_list = vhci_mpapi_create_item(vhci, 3569 MP_OBJECT_TYPE_TARGET_PORT_GROUP, &tpg_id); 3570 } 3571 tpg_data = tpg_list->item->idata; 3572 tpg_data->prop.accessState = as; 3573 tpg_data->prop.tpgId = int_tpg_id; 3574 3575 /* 3576 * Set explicitFailover for TPG - 3577 * based on tpgs_bits setting in Std Inquiry response. 3578 */ 3579 switch (psd->sd_inq->inq_tpgs) { 3580 case TPGS_FAILOVER_EXPLICIT: 3581 case TPGS_FAILOVER_BOTH: 3582 tpg_data->prop.explicitFailover = 1; 3583 break; 3584 case TPGS_FAILOVER_IMPLICIT: 3585 tpg_data->prop.explicitFailover = 0; 3586 break; 3587 default: 3588 return; 3589 } 3590 3591 /* 3592 * Level 2, Lun Cross referencing to TPG. 3593 */ 3594 if (vhci_get_mpapi_item(vhci, tpg_data->lu_list, 3595 MP_OBJECT_TYPE_MULTIPATH_LU, (void *)vlun) == NULL) { 3596 tpg_lu_list = kmem_zalloc(sizeof (mpapi_item_list_t), 3597 KM_SLEEP); 3598 item_list = vhci_get_mpapi_item(vhci, NULL, 3599 MP_OBJECT_TYPE_MULTIPATH_LU, (void *)vlun); 3600 tpg_lu_list->item = item_list->item; 3601 (void) vhci_mpapi_add_to_list(tpg_data->lu_list, 3602 tpg_lu_list); 3603 } 3604 3605 /* 3606 * Level 2, TPG Cross referencing to Lun. 3607 */ 3608 if (vhci_get_mpapi_item(vhci, ld->tpg_list, 3609 MP_OBJECT_TYPE_TARGET_PORT_GROUP, &tpg_id) == 0) { 3610 lu_tpg_list = kmem_zalloc(sizeof (mpapi_item_list_t), 3611 KM_SLEEP); 3612 lu_tpg_list->item = tpg_list->item; 3613 (void) vhci_mpapi_add_to_list(((mpapi_lu_data_t *) 3614 (lu_list->item->idata))->tpg_list, lu_tpg_list); 3615 } 3616 3617 /* 3618 * Building Target Port list is different here. 3619 * For each different Relative Target Port. we have a new MPAPI 3620 * Target Port OID generated. 3621 * Just find out the main Target Port property here. 3622 */ 3623 tgt_port = NULL; 3624 if (mdi_prop_lookup_string(pip, SCSI_ADDR_PROP_TARGET_PORT, 3625 &tgt_port) != DDI_PROP_SUCCESS) { 3626 /* XXX: target-port prop not found */ 3627 tgt_port = (char *)mdi_pi_get_addr(pip); 3628 VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_mpapi_update_tpg_data: " 3629 "mdi_prop_lookup_string() returned failure; " 3630 "Hence tgt_port = %p", (void *)tgt_port)); 3631 } 3632 3633 /* 3634 * Level 1, Relative Target Port + Target Port Creation 3635 */ 3636 rel_tport_cnt = (ptr[7] & 0xff); 3637 ptr += 8; 3638 for (i = 0; i < rel_tport_cnt; i++) { 3639 rel_tid = 0; 3640 rel_tid |= ((ptr[2] & 0Xff) << 8); 3641 rel_tid |= (ptr[3] & 0xff); 3642 3643 VHCI_DEBUG(4, (CE_NOTE, NULL, "vhci_mpapi_update_tpg_data: " 3644 "TgtPort=%s, RelTgtPort=%x\n", tgt_port, rel_tid)); 3645 3646 tgt_list = vhci_mpapi_get_rel_tport_pair(vhci, NULL, 3647 (void *)tgt_port, rel_tid); 3648 if (tgt_list == NULL) { 3649 /* Need to create tgt_list entry */ 3650 tgt_list = vhci_mpapi_create_item(vhci, 3651 MP_OBJECT_TYPE_TARGET_PORT, 3652 (void *)tgt_port); 3653 tpd = tgt_list->item->idata; 3654 tpd->valid = 1; 3655 tpd->prop.relativePortID = rel_tid; 3656 } else { 3657 tpd = tgt_list->item->idata; 3658 tpd->valid = 1; 3659 } 3660 3661 tpd = (mpapi_tport_data_t *)tgt_list->item->idata; 3662 if (vhci_get_mpapi_item(vhci, tpd->path_list, 3663 MP_OBJECT_TYPE_PATH_LU, (void*)pip) == NULL) { 3664 tp_path_list = kmem_zalloc(sizeof (mpapi_item_list_t), 3665 KM_SLEEP); 3666 tp_path_list->item = path_list->item; 3667 (void) vhci_mpapi_add_to_list(tpd->path_list, 3668 tp_path_list); 3669 } 3670 3671 if (vhci_mpapi_get_rel_tport_pair(vhci, 3672 tpg_data->tport_list, tgt_port, rel_tid) == NULL) { 3673 tpg_tport_list = kmem_zalloc 3674 (sizeof (mpapi_item_list_t), KM_SLEEP); 3675 tpg_tport_list->item = tgt_list->item; 3676 (void) vhci_mpapi_add_to_list(tpg_data-> 3677 tport_list, tpg_tport_list); 3678 } 3679 ptr += 4; 3680 } 3681 3682 /* 3683 * Level-1: Fill-out Path Properties now, since we got all details. 3684 * Actually, It is a structure copy, rather than just filling details. 3685 */ 3686 pd = path_list->item->idata; 3687 bcopy(&(ld->prop), &(pd->prop.logicalUnit), 3688 sizeof (struct mp_logical_unit_prop)); 3689 bcopy(&(initd->prop), &(pd->prop.initPort), 3690 sizeof (struct mp_init_port_prop)); 3691 bcopy(&(tpd->prop), &(pd->prop.targetPort), 3692 sizeof (struct mp_target_port_prop)); 3693 } 3694 3695 /* 3696 * Routine to get mpapi ioctl argument structure from userland. 3697 */ 3698 /* ARGSUSED */ 3699 static int 3700 vhci_get_mpiocdata(const void *data, mp_iocdata_t *mpioc, int mode) 3701 { 3702 int retval = 0; 3703 3704 #ifdef _MULTI_DATAMODEL 3705 switch (ddi_model_convert_from(mode & FMODELS)) { 3706 case DDI_MODEL_ILP32: 3707 { 3708 mp_iocdata32_t ioc32; 3709 3710 VHCI_DEBUG(6, (CE_WARN, NULL, "vhci_get_mpiocdata: " 3711 "Case DDI_MODEL_ILP32")); 3712 if (ddi_copyin((void *)data, (void *)&ioc32, 3713 sizeof (mp_iocdata32_t), mode)) { 3714 VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_get_mpiocdata: " 3715 "ddi_copyin() FAILED")); 3716 retval = EFAULT; 3717 break; 3718 } 3719 mpioc->mp_xfer = (uint16_t)(uintptr_t)ioc32.mp_xfer; 3720 mpioc->mp_cmd = (uint16_t)(uintptr_t)ioc32.mp_cmd; 3721 mpioc->mp_flags = (uint16_t)(uintptr_t)ioc32.mp_flags; 3722 mpioc->mp_cmd_flags = (uint16_t)ioc32.mp_cmd_flags; 3723 mpioc->mp_ilen = (size_t)(uintptr_t)ioc32.mp_ilen; 3724 mpioc->mp_ibuf = (caddr_t)(uintptr_t)ioc32.mp_ibuf; 3725 mpioc->mp_olen = (size_t)(uintptr_t)ioc32.mp_olen; 3726 mpioc->mp_obuf = (caddr_t)(uintptr_t)ioc32.mp_obuf; 3727 mpioc->mp_alen = (size_t)(uintptr_t)ioc32.mp_alen; 3728 mpioc->mp_abuf = (caddr_t)(uintptr_t)ioc32.mp_abuf; 3729 mpioc->mp_errno = (int)(uintptr_t)ioc32.mp_errno; 3730 break; 3731 } 3732 3733 case DDI_MODEL_NONE: 3734 if (ddi_copyin(data, (void*)mpioc, sizeof (*mpioc), mode)) { 3735 retval = EFAULT; 3736 break; 3737 } 3738 break; 3739 3740 default: 3741 if (ddi_copyin(data, (void*)mpioc, sizeof (*mpioc), mode)) { 3742 retval = EFAULT; 3743 break; 3744 } 3745 break; 3746 } 3747 #else /* _MULTI_DATAMODEL */ 3748 if (ddi_copyin(data, (void *)mpioc, sizeof (*mpioc), mode)) { 3749 retval = EFAULT; 3750 } 3751 #endif /* _MULTI_DATAMODEL */ 3752 3753 if (retval) { 3754 VHCI_DEBUG(2, (CE_WARN, NULL, "vhci_get_mpiocdata: cmd <%x> " 3755 "iocdata copyin failed", mpioc->mp_cmd)); 3756 } 3757 3758 return (retval); 3759 } 3760 3761 /* ARGSUSED */ 3762 static int 3763 vhci_is_model_type32(int mode) 3764 { 3765 #ifdef _MULTI_DATAMODEL 3766 switch (ddi_model_convert_from(mode & FMODELS)) { 3767 case DDI_MODEL_ILP32: 3768 return (1); 3769 default: 3770 return (0); 3771 } 3772 #else /* _MULTI_DATAMODEL */ 3773 return (0); 3774 #endif /* _MULTI_DATAMODEL */ 3775 } 3776 3777 /* 3778 * Convenience routine to copy mp_iocdata(32) to user land 3779 */ 3780 /* ARGSUSED */ 3781 static int 3782 vhci_mpapi_copyout_iocdata(void *mpioc, void *udata, int mode) 3783 { 3784 int rval = 0; 3785 3786 if (vhci_is_model_type32(mode)) { 3787 mp_iocdata32_t *mpioc32; 3788 3789 mpioc32 = (mp_iocdata32_t *)kmem_zalloc 3790 (sizeof (mp_iocdata32_t), KM_SLEEP); 3791 mpioc32->mp_xfer = (uint16_t)((mp_iocdata_t *)mpioc)->mp_xfer; 3792 mpioc32->mp_cmd = (uint16_t)((mp_iocdata_t *)mpioc)->mp_cmd; 3793 mpioc32->mp_flags = (uint16_t)((mp_iocdata_t *)mpioc)->mp_flags; 3794 mpioc32->mp_cmd_flags = (uint16_t)((mp_iocdata_t *) 3795 mpioc)->mp_cmd_flags; 3796 mpioc32->mp_ilen = (uint32_t)((mp_iocdata_t *)mpioc)->mp_ilen; 3797 mpioc32->mp_ibuf = (caddr32_t)((mp_iocdata32_t *) 3798 mpioc)->mp_ibuf; 3799 mpioc32->mp_olen = (uint32_t)((mp_iocdata_t *)mpioc)->mp_olen; 3800 mpioc32->mp_obuf = (caddr32_t)((mp_iocdata32_t *) 3801 mpioc)->mp_obuf; 3802 mpioc32->mp_alen = (uint32_t)((mp_iocdata_t *)mpioc)->mp_alen; 3803 mpioc32->mp_abuf = (caddr32_t)((mp_iocdata32_t *) 3804 mpioc)->mp_abuf; 3805 mpioc32->mp_errno = (int32_t)((mp_iocdata_t *)mpioc)->mp_errno; 3806 3807 if (ddi_copyout(mpioc32, udata, sizeof (mp_iocdata32_t), mode) 3808 != 0) { 3809 rval = EFAULT; 3810 } 3811 kmem_free(mpioc32, sizeof (mp_iocdata32_t)); 3812 } else { 3813 /* 64-bit ddicopyout */ 3814 if (ddi_copyout(mpioc, udata, sizeof (mp_iocdata_t), mode) 3815 != 0) { 3816 rval = EFAULT; 3817 } 3818 } 3819 3820 return (rval); 3821 3822 } 3823 3824 /* 3825 * Routine to sync OIDs of MPLU to match with the ssd instance# of the 3826 * scsi_vhci lun, to accommodate the DINFOCACHE implementation of the plugin. 3827 * ssd instance# = devi_instance from the dev_info structure. 3828 * dev_info structure of the scsi_vhci lun is pointed by svl_dip field of 3829 * scsi_vhci_lun structure. 3830 */ 3831 /* ARGSUSED */ 3832 static int 3833 vhci_mpapi_sync_lu_oid_list(struct scsi_vhci *vhci) 3834 { 3835 int rval = 0; 3836 mpapi_item_list_t *ilist; 3837 mpapi_lu_data_t *lud; 3838 mpapi_path_data_t *pd; 3839 scsi_vhci_lun_t *svl; 3840 dev_info_t *lun_dip; 3841 3842 ilist = vhci->mp_priv->obj_hdr_list[MP_OBJECT_TYPE_MULTIPATH_LU]->head; 3843 3844 while (ilist != NULL) { 3845 lud = ilist->item->idata; 3846 if (lud->valid == 1) { 3847 svl = lud->resp; 3848 ilist->item->oid.raw_oid = 3849 (uint64_t)ddi_get_instance(svl->svl_dip); 3850 lud->prop.id = 3851 (uint64_t)ddi_get_instance(svl->svl_dip); 3852 } 3853 ilist = ilist->next; 3854 } 3855 3856 ilist = vhci->mp_priv->obj_hdr_list[MP_OBJECT_TYPE_PATH_LU]->head; 3857 while (ilist != NULL) { 3858 pd = ilist->item->idata; 3859 if ((pd->valid == 1) && (MP_GET_MAJOR_FROM_ID((uint64_t) 3860 (pd->prop.logicalUnit.id)) != 0)) { 3861 lun_dip = mdi_pi_get_client 3862 ((mdi_pathinfo_t *)(pd->resp)); 3863 pd->prop.logicalUnit.id = 3864 (uint64_t)ddi_get_instance(lun_dip); 3865 } 3866 ilist = ilist->next; 3867 } 3868 3869 return (rval); 3870 } 3871 3872 /* 3873 * Routine to sync Initiator Port List with what MDI maintains. This means 3874 * MP API knows about Initiator Ports which don't have a pip. 3875 */ 3876 /* ARGSUSED */ 3877 int 3878 vhci_mpapi_sync_init_port_list(dev_info_t *pdip, void *arg) 3879 { 3880 int init_not_ddi_alloced = 0; 3881 struct scsi_vhci *vhci = arg; 3882 char *init, *init_port_res; 3883 mpapi_item_list_t *init_list; 3884 mpapi_initiator_data_t *initd; 3885 3886 if ((ddi_prop_lookup_string(DDI_DEV_T_ANY, pdip, DDI_PROP_DONTPASS, 3887 SCSI_ADDR_PROP_INITIATOR_PORT, &init) != DDI_PROP_SUCCESS)) { 3888 VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_mpapi_sync_init_port_list: " 3889 SCSI_ADDR_PROP_INITIATOR_PORT " prop not found")); 3890 init = kmem_zalloc(MAXPATHLEN, KM_SLEEP); 3891 init_not_ddi_alloced = 1; 3892 (void) ddi_pathname(pdip, init); 3893 } 3894 3895 init_port_res = kmem_zalloc(MAXPATHLEN, KM_SLEEP); 3896 (void) ddi_pathname(pdip, init_port_res); 3897 3898 init_list = vhci_get_mpapi_item(vhci, NULL, 3899 MP_OBJECT_TYPE_INITIATOR_PORT, (void*)init_port_res); 3900 if (init_list == NULL) { 3901 /* 3902 * Need to create init_list entry 3903 * The resource ptr is not really pdip. It will be changed 3904 * in vhci_mpapi_create_item(). The real resource ptr 3905 * is the Port ID. But we pass the pdip, to create OID. 3906 */ 3907 init_list = vhci_mpapi_create_item(vhci, 3908 MP_OBJECT_TYPE_INITIATOR_PORT, (void*)pdip); 3909 } 3910 3911 initd = init_list->item->idata; 3912 initd->valid = 1; 3913 (void) strlcpy(initd->prop.portID, init, sizeof (initd->prop.portID)); 3914 3915 if (init_not_ddi_alloced == 1) { 3916 kmem_free(init, MAXPATHLEN); 3917 } else if (init) { 3918 ddi_prop_free(init); 3919 } 3920 kmem_free(init_port_res, MAXPATHLEN); 3921 3922 return (DDI_WALK_CONTINUE); 3923 } 3924 3925 /* ARGSUSED */ 3926 static void 3927 vhci_mpapi_log_sysevent(dev_info_t *dip, uint64_t *oid, char *subclass) 3928 { 3929 nvlist_t *attr_list; 3930 3931 if (nvlist_alloc(&attr_list, NV_UNIQUE_NAME_TYPE, 3932 KM_SLEEP) != DDI_SUCCESS) { 3933 goto alloc_failed; 3934 } 3935 3936 if (nvlist_add_uint64_array(attr_list, "oid", oid, 1) != DDI_SUCCESS) { 3937 goto error; 3938 } 3939 3940 (void) ddi_log_sysevent(dip, DDI_VENDOR_SUNW, EC_SUN_MP, subclass, 3941 attr_list, NULL, DDI_SLEEP); 3942 3943 error: 3944 nvlist_free(attr_list); 3945 return; 3946 3947 alloc_failed: 3948 VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_mpapi_log_sysevent: " 3949 "Unable to send sysevent")); 3950 3951 } 3952 3953 /* ARGSUSED */ 3954 void 3955 vhci_mpapi_set_path_state(dev_info_t *vdip, mdi_pathinfo_t *pip, int state) 3956 { 3957 struct scsi_vhci *vhci; 3958 struct scsi_vhci_lun *svl; 3959 scsi_vhci_priv_t *svp; 3960 mpapi_item_list_t *ilist, *lu_list; 3961 mpapi_path_data_t *pp; 3962 mpapi_lu_data_t *ld; 3963 3964 vhci = ddi_get_soft_state(vhci_softstate, ddi_get_instance(vdip)); 3965 3966 ilist = vhci_get_mpapi_item(vhci, NULL, MP_OBJECT_TYPE_PATH_LU, pip); 3967 3968 if (ilist != NULL) { 3969 mutex_enter(&ilist->item->item_mutex); 3970 pp = ilist->item->idata; 3971 pp->prop.pathState = state; 3972 pp->valid = 1; 3973 } else { 3974 VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_mpapi_set_path_state: " 3975 "pip(%p) not found", (void *)pip)); 3976 return; 3977 } 3978 3979 /* 3980 * Check if the pathinfo is uninitialized(destroyed). 3981 */ 3982 if (state == MP_DRVR_PATH_STATE_UNINIT) { 3983 pp->hide = 1; 3984 VHCI_DEBUG(6, (CE_NOTE, NULL, "vhci_mpapi_set_path_state: " 3985 "path(pip: %p) is uninited(destroyed).", 3986 (void *)pip)); 3987 } else { 3988 pp->hide = 0; 3989 } 3990 /* 3991 * Find if there are any paths at all to the lun 3992 */ 3993 if ((state == MP_DRVR_PATH_STATE_REMOVED) || (state == 3994 MP_DRVR_PATH_STATE_PATH_ERR) || (state == 3995 MP_DRVR_PATH_STATE_LU_ERR) || (state == 3996 MP_DRVR_PATH_STATE_UNKNOWN) || pp->hide) { 3997 pp->valid = 0; 3998 VHCI_DEBUG(6, (CE_NOTE, NULL, "vhci_mpapi_set_path_state: " 3999 "path(pip: %p) is not okay state. Set to invalid.", 4000 (void *)pip)); 4001 svp = (scsi_vhci_priv_t *)mdi_pi_get_vhci_private(pip); 4002 svl = svp->svp_svl; 4003 /* 4004 * Update the AccessState of related MPAPI TPGs 4005 * This takes care of a special case where a path goes offline 4006 * & the TPG accessState may need an update from 4007 * Active/Standby to Unavailable. 4008 */ 4009 if (!SCSI_FAILOVER_IS_TPGS(svl->svl_fops)) { 4010 (void) vhci_mpapi_update_tpg_acc_state_for_lu(vhci, 4011 svl); 4012 } 4013 4014 /* 4015 * Following means the lun is offline 4016 */ 4017 if (vhci_mpapi_chk_last_path(pip) == -1) { 4018 lu_list = vhci_get_mpapi_item(vhci, NULL, 4019 MP_OBJECT_TYPE_MULTIPATH_LU, (void *)svl); 4020 if (lu_list != NULL) { 4021 ld = lu_list->item->idata; 4022 ld->valid = 0; 4023 VHCI_DEBUG(6, (CE_NOTE, NULL, 4024 "vhci_mpapi_set_path_state: " 4025 " Invalidated LU(%s)", svl->svl_lun_wwn)); 4026 } 4027 } 4028 } 4029 mutex_exit(&ilist->item->item_mutex); 4030 4031 } 4032 4033 /* ARGSUSED */ 4034 static mpapi_item_list_t * 4035 vhci_mpapi_match_pip(struct scsi_vhci *vhci, mpapi_item_list_t *ilist, 4036 void *res) 4037 { 4038 mpapi_path_data_t *pd; 4039 scsi_vhci_lun_t *this_svl; 4040 mdi_pathinfo_t *this_pip; 4041 char *this_iport; 4042 char *this_tport; 4043 char *pname; 4044 4045 this_pip = (mdi_pathinfo_t *)res; 4046 if ((this_pip == NULL) || (ilist == NULL)) { 4047 return (NULL); 4048 } 4049 4050 this_iport = kmem_zalloc(MAXPATHLEN, KM_SLEEP); 4051 (void) ddi_pathname(mdi_pi_get_phci(this_pip), this_iport); 4052 4053 if (mdi_prop_lookup_string(this_pip, SCSI_ADDR_PROP_TARGET_PORT, 4054 &this_tport) != DDI_PROP_SUCCESS) { 4055 /* XXX: target-port prop not found */ 4056 this_tport = (char *)mdi_pi_get_addr(this_pip); 4057 VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_mpapi_match_pip: " 4058 "mdi_prop_lookup_string() returned failure; " 4059 "Hence this_tport = %p", (void *)this_tport)); 4060 } 4061 4062 this_svl = mdi_client_get_vhci_private(mdi_pi_get_client(this_pip)); 4063 4064 pname = kmem_zalloc(MAXPATHLEN, KM_SLEEP); 4065 (void) strlcat(pname, this_iport, MAXPATHLEN); 4066 (void) strlcat(pname, this_tport, MAXPATHLEN); 4067 (void) strlcat(pname, this_svl->svl_lun_wwn, MAXPATHLEN); 4068 kmem_free(this_iport, MAXPATHLEN); 4069 4070 while (ilist != NULL) { 4071 pd = (mpapi_path_data_t *)(ilist->item->idata); 4072 if ((pd != NULL) && (strncmp 4073 (pd->path_name, pname, strlen(pname)) == 0)) { 4074 VHCI_DEBUG(6, (CE_WARN, NULL, "vhci_mpapi_match_pip: " 4075 "path_name = %s", pd->path_name)); 4076 kmem_free(pname, MAXPATHLEN); 4077 return (ilist); 4078 } 4079 ilist = ilist->next; 4080 } 4081 4082 kmem_free(pname, MAXPATHLEN); 4083 return (NULL); 4084 } 4085 4086 /* ARGSUSED */ 4087 static 4088 mpapi_item_list_t *vhci_mpapi_match_lu(struct scsi_vhci *vhci, 4089 mpapi_item_list_t *ilist, void *res) 4090 { 4091 mpapi_lu_data_t *ld; 4092 scsi_vhci_lun_t *this_svl; 4093 4094 this_svl = (scsi_vhci_lun_t *)res; 4095 if ((this_svl == NULL) || (ilist == NULL)) { 4096 return (NULL); 4097 } 4098 4099 while (ilist != NULL) { 4100 ld = (mpapi_lu_data_t *)(ilist->item->idata); 4101 if ((ld != NULL) && (strncmp 4102 (ld->prop.name, this_svl->svl_lun_wwn, 4103 strlen(this_svl->svl_lun_wwn)) == 0)) { 4104 VHCI_DEBUG(6, (CE_WARN, NULL, "vhci_mpapi_match_lu: " 4105 "this_wwn = %s", this_svl->svl_lun_wwn)); 4106 return (ilist); 4107 } 4108 ilist = ilist->next; 4109 } 4110 4111 return (NULL); 4112 } 4113 4114 /* 4115 * Routine to handle TPG AccessState Change - Called after each LU failover 4116 */ 4117 int 4118 vhci_mpapi_update_tpg_acc_state_for_lu(struct scsi_vhci *vhci, 4119 scsi_vhci_lun_t *vlun) 4120 { 4121 int rval = 0; 4122 mpapi_item_list_t *lu_list, *path_list, *tpg_list; 4123 mpapi_lu_data_t *lu_data; 4124 mpapi_path_data_t *path_data; 4125 mpapi_tpg_data_t *tpg_data; 4126 4127 lu_list = vhci_get_mpapi_item(vhci, NULL, MP_OBJECT_TYPE_MULTIPATH_LU, 4128 (void *)vlun); 4129 if (lu_list == NULL) { 4130 return (-1); 4131 } 4132 lu_data = lu_list->item->idata; 4133 if (lu_data == NULL) { 4134 return (-1); 4135 } 4136 lu_data->resp = vlun; 4137 lu_data->valid = 1; 4138 4139 /* 4140 * For each "pclass of PATH" and "pclass of TPG" match of this LU, 4141 * Update the TPG AccessState to reflect the state of the path. 4142 * Exit the inner loop after the 1st successful ACTIVE/STANDBY update 4143 * is made, because subsequent matches also lead to the same TPG. 4144 */ 4145 tpg_list = lu_data->tpg_list->head; 4146 while (tpg_list != NULL) { 4147 tpg_data = tpg_list->item->idata; 4148 path_list = lu_data->path_list->head; 4149 while (path_list != NULL) { 4150 path_data = path_list->item->idata; 4151 if (strncmp(path_data->pclass, tpg_data->pclass, 4152 strlen(tpg_data->pclass)) == 0) { 4153 if (path_data->valid == 1) { 4154 VHCI_DEBUG(4, (CE_NOTE, NULL, 4155 "vhci_mpapi_update_tpg_acc_state_" 4156 "for_ lu: Operating on LUN(%s), " 4157 " PATH(%p), TPG(%x: %s)\n", 4158 lu_data->prop.name, path_data->resp, 4159 tpg_data->prop.tpgId, 4160 tpg_data->pclass)); 4161 if (MDI_PI_IS_ONLINE(path_data->resp)) { 4162 tpg_data->prop.accessState = 4163 MP_DRVR_ACCESS_STATE_ACTIVE; 4164 break; 4165 } else if (MDI_PI_IS_STANDBY( 4166 path_data->resp)) { 4167 tpg_data->prop.accessState = 4168 MP_DRVR_ACCESS_STATE_STANDBY; 4169 break; 4170 } else { 4171 tpg_data->prop.accessState = 4172 MP_DRVR_ACCESS_STATE_UNAVAILABLE; 4173 } 4174 } else { 4175 /* 4176 * if path is not valid any more, 4177 * mark the associated tpg as 4178 * unavailable. 4179 */ 4180 tpg_data->prop.accessState = 4181 MP_DRVR_ACCESS_STATE_UNAVAILABLE; 4182 } 4183 } 4184 4185 path_list = path_list->next; 4186 } 4187 tpg_list = tpg_list->next; 4188 } 4189 4190 return (rval); 4191 } 4192 4193 int 4194 vhci_mpapi_get_vhci(dev_info_t *vdip, void *ptr2vhci) 4195 { 4196 struct scsi_vhci *local_vhci; 4197 4198 if (strncmp("scsi_vhci", ddi_get_name(vdip), 4199 strlen("scsi_vhci")) == 0) { 4200 local_vhci = ddi_get_soft_state(vhci_softstate, 4201 ddi_get_instance(vdip)); 4202 bcopy(&local_vhci, ptr2vhci, sizeof (local_vhci)); 4203 return (DDI_WALK_TERMINATE); 4204 } 4205 4206 return (DDI_WALK_CONTINUE); 4207 4208 } 4209 4210 /* ARGSUSED */ 4211 void * 4212 vhci_mpapi_get_rel_tport_pair(struct scsi_vhci *vhci, mpapi_list_header_t *list, 4213 void *tgt_port, uint32_t rel_tid) 4214 { 4215 mpapi_item_list_t *ilist; 4216 mpapi_tport_data_t *tpd; 4217 4218 if (list == NULL) { 4219 /* 4220 * Since the listhead is null, the search is being 4221 * performed in implicit mode - that is to use the 4222 * level one list. 4223 */ 4224 ilist = vhci->mp_priv->obj_hdr_list[MP_OBJECT_TYPE_TARGET_PORT] 4225 ->head; 4226 } else { 4227 /* 4228 * The search is being performed on a sublist within 4229 * one of the toplevel list items. Use the listhead 4230 * that is passed in. 4231 */ 4232 ilist = list->head; 4233 } 4234 4235 if (tgt_port == NULL) { 4236 VHCI_DEBUG(1, (CE_WARN, NULL, "vhci_get_mpapi_item: " 4237 " Got Target Port w/ NULL resource")); 4238 return (NULL); 4239 } 4240 4241 while (ilist) { 4242 tpd = (mpapi_tport_data_t *)ilist->item->idata; 4243 if ((strncmp(tpd->resp, tgt_port, strlen(tgt_port)) == 0) && 4244 (tpd->prop.relativePortID == rel_tid)) { 4245 /* Match */ 4246 return ((void*)ilist); 4247 } else { 4248 ilist = ilist->next; 4249 } 4250 } 4251 4252 return (NULL); 4253 } 4254 4255 /* 4256 * Returns 0, if 2 more paths are available to the lun; 4257 * Returns 1, if ONLY 1 path is available to the lun; 4258 * Return -1 for all other cases. 4259 */ 4260 static int 4261 vhci_mpapi_chk_last_path(mdi_pathinfo_t *pip) 4262 { 4263 dev_info_t *pdip = NULL, *cdip = NULL; 4264 int count = 0, circular; 4265 mdi_pathinfo_t *ret_pip; 4266 4267 if (pip == NULL) { 4268 return (-1); 4269 } else { 4270 pdip = mdi_pi_get_phci(pip); 4271 cdip = mdi_pi_get_client(pip); 4272 } 4273 4274 if ((pdip == NULL) || (cdip == NULL)) { 4275 return (-1); 4276 } 4277 4278 ndi_devi_enter(cdip, &circular); 4279 ret_pip = mdi_get_next_phci_path(cdip, NULL); 4280 4281 while ((ret_pip != NULL) && (count < 2)) { 4282 mdi_pi_lock(ret_pip); 4283 if ((MDI_PI_IS_ONLINE(ret_pip) || 4284 MDI_PI_IS_STANDBY(ret_pip) || 4285 MDI_PI_IS_INIT(ret_pip)) && 4286 !(MDI_PI_IS_DISABLE(ret_pip) || 4287 MDI_PI_IS_TRANSIENT(ret_pip) || 4288 MDI_PI_FLAGS_IS_DEVICE_REMOVED(ret_pip))) { 4289 count++; 4290 } 4291 mdi_pi_unlock(ret_pip); 4292 ret_pip = mdi_get_next_phci_path(cdip, ret_pip); 4293 } 4294 ndi_devi_exit(cdip, circular); 4295 4296 if (count > 1) { 4297 return (0); 4298 } else if (count == 1) { 4299 return (1); 4300 } 4301 4302 return (-1); 4303 } 4304