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