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