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