1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. 23 * Copyright 2025 Hans Rosenfeld 24 */ 25 26 #include "mp_utils.h" 27 #include <sys/sunddi.h> 28 29 #ifndef OIDLIST 30 #define OIDLIST "oid" 31 #endif 32 33 34 /* Remove these 5 when this source can compile with sunddi.h */ 35 #ifndef EC_DDI 36 #define EC_DDI "EC_ddi" 37 #endif 38 39 #ifndef ESC_DDI_INITIATOR_REGISTER 40 #define ESC_DDI_INITIATOR_REGISTER "ESC_ddi_initiator_register" 41 #endif 42 43 #ifndef ESC_DDI_INITIATOR_UNREGISTER 44 #define ESC_DDI_INITIATOR_UNREGISTER "ESC_ddi_initiator_unregister" 45 #endif 46 47 #ifndef DDI_DRIVER_MAJOR 48 #define DDI_DRIVER_MAJOR "ddi.major" 49 #endif 50 51 #ifndef DDI_INSTANCE 52 #define DDI_INSTANCE "ddi.instance" 53 #endif 54 55 56 #define VISA_CHANGE 1 57 #define PROP_CHANGE 2 58 59 60 61 MP_STATUS 62 getStatus4ErrorCode(int driverError) 63 { 64 MP_STATUS mpStatus = MP_STATUS_FAILED; 65 66 log(LOG_INFO, "getStatus4ErrorCode()", "- enter"); 67 68 switch (driverError) { 69 70 case MP_DRVR_INVALID_ID: 71 log(LOG_INFO, "getStatus4ErrorCode()", 72 " received mp_errno=MP_DRVR_INVALID_ID" 73 " from driver call."); 74 log(LOG_INFO, "getStatus4ErrorCode()", 75 " returning MP_STATUS_OBJECT_NOT_FOUND" 76 " to caller."); 77 mpStatus = MP_STATUS_OBJECT_NOT_FOUND; 78 break; 79 80 81 case MP_DRVR_ID_OBSOLETE: 82 log(LOG_INFO, "getStatus4ErrorCode()", 83 " received mp_errno=MP_DRVR_ID_OBSOLETE" 84 " from driver call."); 85 log(LOG_INFO, "getStatus4ErrorCode()", 86 " returning MP_STATUS_OBJECT_NOT_FOUND" 87 " to caller."); 88 mpStatus = MP_STATUS_OBJECT_NOT_FOUND; 89 break; 90 91 92 case MP_DRVR_ACCESS_SYMMETRIC: 93 log(LOG_INFO, "getStatus4ErrorCode()", 94 " received mp_errno=MP_DRVR_ACCESS_SYMMETRIC" 95 " from driver call."); 96 log(LOG_INFO, "getStatus4ErrorCode()", 97 " returning MP_STATUS_INVALID_PARAMETER" 98 " to caller."); 99 mpStatus = MP_STATUS_INVALID_PARAMETER; 100 break; 101 102 103 case MP_DRVR_PATH_UNAVAILABLE: 104 log(LOG_INFO, "getStatus4ErrorCode()", 105 " received mp_errno=MP_DRVR_PATH_UNAVAILABLE" 106 " from driver call."); 107 log(LOG_INFO, "getStatus4ErrorCode()", 108 " returning MP_STATUS_PATH_NONOPERATIONAL" 109 " to caller."); 110 mpStatus = MP_STATUS_PATH_NONOPERATIONAL; 111 break; 112 113 114 case MP_DRVR_IDS_NOT_ASSOCIATED: 115 log(LOG_INFO, "getStatus4ErrorCode()", 116 " received mp_errno=MP_DRVR_IDS_NOT_ASSOCIATED" 117 " from driver call."); 118 log(LOG_INFO, "getStatus4ErrorCode()", 119 " returning MP_STATUS_INVALID_PARAMETER" 120 " to caller."); 121 mpStatus = MP_STATUS_INVALID_PARAMETER; 122 break; 123 124 125 case MP_DRVR_ILLEGAL_ACCESS_STATE_REQUEST: 126 log(LOG_INFO, "getStatus4ErrorCode()", 127 " received mp_errno=" 128 "MP_DRVR_ILLEGAL_ACCESS_STATE_REQUEST" 129 " from driver call."); 130 log(LOG_INFO, "getStatus4ErrorCode()", 131 " returning MP_STATUS_INVALID_PARAMETER" 132 " to caller."); 133 mpStatus = MP_STATUS_ACCESS_STATE_INVALID; 134 break; 135 136 137 case MP_DRVR_ILLEGAL_LOAD_BALANCING_TYPE: 138 log(LOG_INFO, "getStatus4ErrorCode()", 139 " received mp_errno=" 140 "MP_DRVR_ILLEGAL_LOAD_BALANCING_TYPE" 141 " from driver call."); 142 log(LOG_INFO, "getStatus4ErrorCode()", 143 " returning MP_STATUS_INVALID_PARAMETER" 144 " to caller."); 145 mpStatus = MP_STATUS_INVALID_PARAMETER; 146 break; 147 148 default: 149 log(LOG_INFO, "getStatus4ErrorCode()", 150 " - received (unsupported) mp_errno=%d from" 151 " driver call.", driverError); 152 log(LOG_INFO, "getStatus4ErrorCode()", 153 " - returning MP_STATUS_FAILED to caller."); 154 mpStatus = MP_STATUS_FAILED; 155 } 156 157 log(LOG_INFO, "getStatus4ErrorCode()", "- exit"); 158 159 return (mpStatus); 160 } 161 162 163 164 MP_OID_LIST 165 *createOidList(int size) { 166 167 MP_OID_LIST *pOidList = NULL; 168 169 170 log(LOG_INFO, "createOidList()", "- enter"); 171 172 173 if (size < 1) { 174 175 log(LOG_INFO, "createOidList()", 176 "requested size is less than 1"); 177 log(LOG_INFO, "createOidList()", 178 " - error exit"); 179 return (NULL); 180 181 } else { 182 183 pOidList = (MP_OID_LIST*)calloc(1, 184 sizeof (MP_OID_LIST) + 185 ((size - 1) * 186 sizeof (MP_OID))); 187 188 if (NULL == pOidList) { 189 log(LOG_INFO, "createOidList()", 190 "no memory for pOidList"); 191 log(LOG_INFO, "createOidList()", 192 " - error exit"); 193 return (NULL); 194 } 195 196 log(LOG_INFO, 197 "createOidList()", 198 "- exit(%d)", 199 size); 200 201 return (pOidList); 202 } 203 } 204 205 /* Calls the client callback function, if one is registered */ 206 static void 207 notifyClient(sysevent_t *ev) 208 { 209 nvlist_t *attr_list = NULL; 210 211 uint64_t *val = NULL; 212 int32_t *instance = NULL; 213 int32_t *major = NULL; 214 215 int valAllocated = 0; 216 217 uint_t nelem = 0; 218 219 int i = 0; 220 int eventType = 0; 221 int index = -1; 222 223 void *pCallerData = NULL; 224 225 char subClassName[256]; 226 227 MP_BOOL becomingVisible = MP_FALSE; 228 229 MP_OID_LIST *oidList = NULL; 230 231 232 log(LOG_INFO, "notifyClient()", "- enter"); 233 234 235 (void) strncpy(subClassName, sysevent_get_subclass_name(ev), 256); 236 237 if (strstr(subClassName, "change")) { 238 239 eventType = PROP_CHANGE; 240 241 log(LOG_INFO, "notifyClient()", "- got a change event"); 242 log(LOG_INFO, "notifyClient()", ": [%s]", 243 subClassName); 244 245 if (strncmp(subClassName, ESC_SUN_MP_PLUGIN_CHANGE, 255) 246 == 0) { 247 248 index = MP_OBJECT_TYPE_PLUGIN; 249 250 } else if (strncmp(subClassName, ESC_SUN_MP_LU_CHANGE, 255) 251 == 0) { 252 253 index = MP_OBJECT_TYPE_MULTIPATH_LU; 254 255 } else if (strncmp(subClassName, ESC_SUN_MP_PATH_CHANGE, 255) 256 == 0) { 257 258 index = MP_OBJECT_TYPE_PATH_LU; 259 260 } else if (strncmp(subClassName, ESC_SUN_MP_INIT_PORT_CHANGE, 261 255) == 0) { 262 263 index = MP_OBJECT_TYPE_INITIATOR_PORT; 264 265 } else if (strncmp(subClassName, ESC_SUN_MP_TPG_CHANGE, 255) 266 == 0) { 267 268 index = MP_OBJECT_TYPE_TARGET_PORT_GROUP; 269 270 } else if (strncmp(subClassName, ESC_SUN_MP_TARGET_PORT_CHANGE, 271 255) == 0) { 272 273 index = MP_OBJECT_TYPE_TARGET_PORT; 274 275 } else if (strncmp(subClassName, ESC_SUN_MP_DEV_PROD_CHANGE, 276 255) == 0) { 277 278 index = MP_OBJECT_TYPE_DEVICE_PRODUCT; 279 } 280 281 } else if ((strstr(subClassName, "add")) || 282 (strstr(subClassName, "initiator_register"))) { 283 284 eventType = VISA_CHANGE; 285 becomingVisible = MP_TRUE; 286 287 log(LOG_INFO, "notifyClient()", "- got a visibility" 288 " add event"); 289 log(LOG_INFO, "notifyClient()", ": [%s]", 290 subClassName); 291 292 if (strncmp(subClassName, ESC_SUN_MP_LU_ADD, 255) == 0) { 293 294 index = MP_OBJECT_TYPE_MULTIPATH_LU; 295 296 } else if (strncmp(subClassName, ESC_SUN_MP_PATH_ADD, 255) 297 == 0) { 298 299 index = MP_OBJECT_TYPE_PATH_LU; 300 301 } else if (strncmp(subClassName, ESC_DDI_INITIATOR_REGISTER, 302 244) == 0) { 303 304 index = MP_OBJECT_TYPE_INITIATOR_PORT; 305 306 } else if (strncmp(subClassName, ESC_SUN_MP_TPG_ADD, 307 255) == 0) { 308 309 index = MP_OBJECT_TYPE_TARGET_PORT_GROUP; 310 311 } else if (strncmp(subClassName, ESC_SUN_MP_TARGET_PORT_ADD, 312 255) == 0) { 313 314 index = MP_OBJECT_TYPE_TARGET_PORT; 315 316 } else if (strncmp(subClassName, ESC_SUN_MP_DEV_PROD_ADD, 255) 317 == 0) { 318 319 index = MP_OBJECT_TYPE_DEVICE_PRODUCT; 320 } 321 322 323 } else if ((strstr(subClassName, "remove")) || 324 (strstr(subClassName, "initiator_unregister"))) { 325 326 eventType = VISA_CHANGE; 327 becomingVisible = MP_FALSE; 328 329 log(LOG_INFO, "notifyClient()", "- got a visibility" 330 " remove event"); 331 log(LOG_INFO, "notifyClient()", ": [%s]", 332 subClassName); 333 334 if (strncmp(subClassName, ESC_SUN_MP_LU_REMOVE, 255) == 0) { 335 336 index = MP_OBJECT_TYPE_MULTIPATH_LU; 337 338 } else if (strncmp(subClassName, ESC_SUN_MP_PATH_REMOVE, 255) 339 == 0) { 340 341 index = MP_OBJECT_TYPE_PATH_LU; 342 343 } else if (strncmp(subClassName, ESC_DDI_INITIATOR_UNREGISTER, 344 255) == 0) { 345 346 index = MP_OBJECT_TYPE_INITIATOR_PORT; 347 348 } else if (strncmp(subClassName, ESC_SUN_MP_TPG_REMOVE, 255) 349 == 0) { 350 351 index = MP_OBJECT_TYPE_TARGET_PORT_GROUP; 352 353 } else if (strncmp(subClassName, ESC_SUN_MP_TARGET_PORT_REMOVE, 354 255) == 0) { 355 356 index = MP_OBJECT_TYPE_TARGET_PORT; 357 358 } else if (strncmp(subClassName, ESC_SUN_MP_DEV_PROD_REMOVE, 359 255) == 0) { 360 361 index = MP_OBJECT_TYPE_DEVICE_PRODUCT; 362 } 363 364 365 } else { 366 log(LOG_INFO, "notifyClient()", "- got an unsupported event"); 367 return; 368 } 369 370 if (index < 0) { 371 372 log(LOG_INFO, "notifyClient()", "- index is less than zero"); 373 return; 374 } 375 376 if (eventType == VISA_CHANGE) { 377 378 (void) pthread_mutex_lock(&g_visa_mutex); 379 380 if (NULL == g_Visibility_Callback_List[index].pClientFn) { 381 382 log(LOG_INFO, "notifyClient()", 383 "- no visibility change callback to notify"); 384 385 (void) pthread_mutex_unlock(&g_visa_mutex); 386 387 return; 388 } 389 390 (void) pthread_mutex_unlock(&g_visa_mutex); 391 } 392 393 if (eventType == PROP_CHANGE) { 394 395 (void) pthread_mutex_lock(&g_prop_mutex); 396 397 if (NULL == g_Property_Callback_List[index].pClientFn) { 398 399 log(LOG_INFO, "notifyClient()", 400 "- no property change callback to notify"); 401 402 (void) pthread_mutex_unlock(&g_prop_mutex); 403 404 return; 405 } 406 407 (void) pthread_mutex_unlock(&g_prop_mutex); 408 } 409 410 (void) sysevent_get_attr_list(ev, &attr_list); 411 if (NULL != attr_list) { 412 413 if ((VISA_CHANGE == eventType) && 414 (MP_OBJECT_TYPE_PLUGIN == index)) { 415 416 val = (uint64_t *)malloc(sizeof (uint64_t)); 417 valAllocated = 1; 418 419 /* 420 * We have no well-defined way to determine our OSN. 421 * Currently the common library uses 0 as OSN for every 422 * plugin, so just use 0. If the OSN assigned by the 423 * common library changed, this code would have to be 424 * updated. 425 */ 426 *val = 0; 427 nelem = 1; 428 429 } else if ((VISA_CHANGE == eventType) && 430 (MP_OBJECT_TYPE_INITIATOR_PORT == index)) { 431 432 (void) nvlist_lookup_int32_array(attr_list, 433 DDI_INSTANCE, &instance, &nelem); 434 435 log(LOG_INFO, "notifyClient()", 436 "- event (PHCI_INSTANCE) has [%d] elements", 437 nelem); 438 439 (void) nvlist_lookup_int32_array(attr_list, 440 DDI_DRIVER_MAJOR, &major, &nelem); 441 442 log(LOG_INFO, "notifyClient()", 443 "- event (PHCI_DRIVER_MAJOR) has [%d] elements", 444 nelem); 445 446 if ((NULL != instance) & (NULL != major)) { 447 448 val = (uint64_t *)malloc(sizeof (uint64_t)); 449 450 valAllocated = 1; 451 452 *val = 0; 453 *val = MP_STORE_INST_TO_ID(*instance, *val); 454 *val = MP_STORE_MAJOR_TO_ID(*major, *val); 455 456 nelem = 1; 457 458 } else { 459 460 nelem = 0; 461 } 462 463 } else { 464 465 (void) nvlist_lookup_uint64_array(attr_list, OIDLIST, 466 &val, &nelem); 467 468 log(LOG_INFO, "notifyClient()", 469 "- event has [%d] elements", 470 nelem); 471 } 472 473 if (nelem > 0) { 474 475 for (i = 0; i < nelem; i++) { 476 477 log(LOG_INFO, "notifyClient()", 478 "- event [%d] = %llx", 479 i, val[i]); 480 } 481 482 oidList = createOidList(nelem); 483 if (NULL == oidList) { 484 485 log(LOG_INFO, "notifyClient()", 486 "- unable to create MP_OID_LIST"); 487 488 log(LOG_INFO, "notifyClient()", 489 "- error exit"); 490 491 nvlist_free(attr_list); 492 493 return; 494 } 495 496 oidList->oidCount = nelem; 497 498 for (i = 0; i < nelem; i++) { 499 500 oidList->oids[i].objectType = index; 501 oidList->oids[i].ownerId = g_pluginOwnerID; 502 oidList->oids[i].objectSequenceNumber = val[i]; 503 } 504 505 if (valAllocated) { 506 507 free(val); 508 } 509 510 for (i = 0; i < oidList->oidCount; i++) { 511 512 log(LOG_INFO, "notifyClient()", 513 "oidList->oids[%d].objectType" 514 " = %d", 515 i, oidList->oids[i].objectType); 516 log(LOG_INFO, "notifyClient()", 517 "oidList->oids[%d].ownerId" 518 " = %d", 519 i, oidList->oids[i].ownerId); 520 log(LOG_INFO, "notifyClient()", 521 "oidList->oids[%d].objectSequenceNumber" 522 " = %llx", 523 i, oidList->oids[i].objectSequenceNumber); 524 } 525 526 if (eventType == PROP_CHANGE) { 527 528 (void) pthread_mutex_lock(&g_prop_mutex); 529 530 pCallerData = g_Property_Callback_List[index]. 531 pCallerData; 532 533 (g_Property_Callback_List[index].pClientFn) 534 (oidList, pCallerData); 535 536 (void) pthread_mutex_unlock(&g_prop_mutex); 537 538 } else if (eventType == VISA_CHANGE) { 539 540 (void) pthread_mutex_lock(&g_visa_mutex); 541 542 pCallerData = g_Visibility_Callback_List[index]. 543 pCallerData; 544 545 (g_Visibility_Callback_List[index].pClientFn) 546 (becomingVisible, oidList, pCallerData); 547 548 (void) pthread_mutex_unlock(&g_visa_mutex); 549 550 } 551 } 552 553 nvlist_free(attr_list); 554 } 555 556 557 log(LOG_INFO, "notifyClient()", "- exit"); 558 } 559 560 /* Event handler called by system */ 561 static void 562 sysevent_handler(sysevent_t *ev) 563 { 564 log(LOG_INFO, "sysevent_handler()", "- enter"); 565 566 /* Is the event one of ours? */ 567 if ((strncmp(EC_SUN_MP, sysevent_get_class_name(ev), 9) != 0) && 568 (strncmp(EC_DDI, sysevent_get_class_name(ev), 6) != 0)) { 569 570 return; 571 } 572 573 /* Notify client if it cares */ 574 notifyClient(ev); 575 576 577 log(LOG_INFO, "sysevent_handler()", "- exit"); 578 } 579 580 /* Registers the plugin to the sysevent framework */ 581 MP_STATUS 582 init_sysevents(void) 583 { 584 585 const char *subclass_list[] = { 586 587 ESC_SUN_MP_PLUGIN_CHANGE, 588 589 ESC_SUN_MP_LU_CHANGE, 590 ESC_SUN_MP_LU_ADD, 591 ESC_SUN_MP_LU_REMOVE, 592 593 ESC_SUN_MP_PATH_CHANGE, 594 ESC_SUN_MP_PATH_ADD, 595 ESC_SUN_MP_PATH_REMOVE, 596 597 ESC_SUN_MP_INIT_PORT_CHANGE, 598 599 ESC_SUN_MP_TPG_CHANGE, 600 ESC_SUN_MP_TPG_ADD, 601 ESC_SUN_MP_TPG_REMOVE, 602 603 ESC_SUN_MP_TARGET_PORT_CHANGE, 604 ESC_SUN_MP_TARGET_PORT_ADD, 605 ESC_SUN_MP_TARGET_PORT_REMOVE, 606 607 ESC_SUN_MP_DEV_PROD_CHANGE, 608 ESC_SUN_MP_DEV_PROD_ADD, 609 ESC_SUN_MP_DEV_PROD_REMOVE 610 611 }; 612 613 const char *init_port_subclass_list[] = { 614 615 ESC_DDI_INITIATOR_REGISTER, 616 ESC_DDI_INITIATOR_UNREGISTER 617 }; 618 619 620 621 log(LOG_INFO, "init_sysevents()", "- enter"); 622 623 624 g_SysEventHandle = sysevent_bind_handle(sysevent_handler); 625 if (g_SysEventHandle == NULL) { 626 627 log(LOG_INFO, "init_sysevents()", 628 "- sysevent_bind_handle() failed"); 629 630 log(LOG_INFO, "init_sysevents()", "- error exit"); 631 632 return (MP_STATUS_FAILED); 633 } 634 635 if (sysevent_subscribe_event(g_SysEventHandle, EC_SUN_MP, 636 subclass_list, sizeof (subclass_list) / sizeof (subclass_list[0])) 637 != 0) { 638 639 640 log(LOG_INFO, "init_sysevents()", 641 "- sysevent_subscribe_event() failed for subclass_list"); 642 643 log(LOG_INFO, "init_sysevents()", "- error exit"); 644 645 sysevent_unbind_handle(g_SysEventHandle); 646 647 return (MP_STATUS_FAILED); 648 } 649 650 if (sysevent_subscribe_event(g_SysEventHandle, EC_DDI, 651 init_port_subclass_list, sizeof (init_port_subclass_list) / 652 sizeof (init_port_subclass_list[0])) != 0) { 653 654 655 log(LOG_INFO, "init_sysevents()", 656 "- sysevent_subscribe_event() failed " 657 "for init_port_subclass_list"); 658 659 log(LOG_INFO, "init_sysevents()", "- error exit"); 660 661 sysevent_unbind_handle(g_SysEventHandle); 662 663 return (MP_STATUS_FAILED); 664 } 665 666 667 log(LOG_INFO, "init_sysevents()", "- exit"); 668 669 return (MP_STATUS_SUCCESS); 670 } 671