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