FCSyseventBridge.cc revision 7836:4e95154b5b7a
133965Sjdp/* 2218822Sdim * CDDL HEADER START 377298Sobrien * 433965Sjdp * The contents of this file are subject to the terms of the 533965Sjdp * Common Development and Distribution License (the "License"). 633965Sjdp * You may not use this file except in compliance with the License. 733965Sjdp * 833965Sjdp * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 933965Sjdp * or http://www.opensolaris.org/os/licensing. 1033965Sjdp * See the License for the specific language governing permissions 1133965Sjdp * and limitations under the License. 1233965Sjdp * 1333965Sjdp * When distributing Covered Code, include this CDDL HEADER in each 1433965Sjdp * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 1533965Sjdp * If applicable, add the following below this CDDL HEADER, with the 1633965Sjdp * fields enclosed by brackets "[]" replaced with your own identifying 1733965Sjdp * information: Portions Copyright [yyyy] [name of copyright owner] 1833965Sjdp * 1933965Sjdp * CDDL HEADER END 2033965Sjdp */ 2133965Sjdp/* 22104834Sobrien * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 2333965Sjdp * Use is subject to license terms. 2433965Sjdp */ 2533965Sjdp 2677298Sobrien 2733965Sjdp 2833965Sjdp#include "FCSyseventBridge.h" 2933965Sjdp#include "Exceptions.h" 3033965Sjdp#include "Trace.h" 3177298Sobrien#include "AdapterAddEvent.h" 3233965Sjdp#include "AdapterEvent.h" 3333965Sjdp#include "AdapterPortEvent.h" 3433965Sjdp#include "AdapterDeviceEvent.h" 3533965Sjdp#include "TargetEvent.h" 3677298Sobrien#include "sun_fc.h" 3733965Sjdp#include <libnvpair.h> 3833965Sjdp#include <iostream> 3933965Sjdp 4033965Sjdpusing namespace std; 4177298Sobrien 4233965SjdpFCSyseventBridge* FCSyseventBridge::_instance = NULL; 4333965Sjdp 4433965SjdpFCSyseventBridge* FCSyseventBridge::getInstance() { 4533965Sjdp Trace log("FCSyseventBridge::getInstance"); 4633965Sjdp if (_instance == NULL) { 4733965Sjdp _instance = new FCSyseventBridge(); 4833965Sjdp } 4933965Sjdp return (_instance); 5033965Sjdp 5133965Sjdp} 5233965Sjdp 5333965Sjdp 5433965Sjdpvoid FCSyseventBridge::addListener(AdapterAddEventListener *listener) { 5533965Sjdp lock(); 5633965Sjdp try { 5777298Sobrien adapterAddEventListeners.insert(adapterAddEventListeners.begin(), 5833965Sjdp listener); 5977298Sobrien validateRegistration(); 6033965Sjdp unlock(); 6133965Sjdp } catch (...) { 6277298Sobrien unlock(); 6333965Sjdp throw; 6433965Sjdp } 6533965Sjdp} 6633965Sjdpvoid FCSyseventBridge::addListener(AdapterEventListener *listener, HBA *hba) { 6777298Sobrien lock(); 6833965Sjdp try { 6933965Sjdp adapterEventListeners.insert(adapterEventListeners.begin(), listener); 7033965Sjdp validateRegistration(); 7177298Sobrien unlock(); 7233965Sjdp } catch (...) { 7377298Sobrien unlock(); 74130561Sobrien throw; 75130561Sobrien } 7633965Sjdp} 7777298Sobrienvoid FCSyseventBridge::addListener(AdapterPortEventListener *listener, 7877298Sobrien HBAPort *port) { 7977298Sobrien lock(); 8077298Sobrien try { 8177298Sobrien adapterPortEventListeners.insert(adapterPortEventListeners.begin(), 8233965Sjdp listener); 8333965Sjdp validateRegistration(); 8433965Sjdp unlock(); 8533965Sjdp } catch (...) { 8633965Sjdp unlock(); 8777298Sobrien throw; 8877298Sobrien } 8933965Sjdp} 9077298Sobrienvoid FCSyseventBridge::addListener(AdapterDeviceEventListener *listener, 9177298Sobrien HBAPort *port) { 9233965Sjdp lock(); 9377298Sobrien try { 9477298Sobrien adapterDeviceEventListeners.insert(adapterDeviceEventListeners.begin(), 9533965Sjdp listener); 9677298Sobrien validateRegistration(); 9733965Sjdp unlock(); 9833965Sjdp } catch (...) { 9933965Sjdp unlock(); 10033965Sjdp throw; 10133965Sjdp } 10233965Sjdp} 10333965Sjdpvoid FCSyseventBridge::addListener(TargetEventListener *listener, 10433965Sjdp HBAPort *port, uint64_t targetWWN, bool filter) { 10533965Sjdp lock(); 10633965Sjdp try { 10733965Sjdp targetEventListeners.insert(targetEventListeners.begin(), listener); 10833965Sjdp validateRegistration(); 10977298Sobrien unlock(); 11077298Sobrien } catch (...) { 11133965Sjdp unlock(); 11233965Sjdp throw; 11333965Sjdp } 11433965Sjdp} 11533965Sjdp 11633965Sjdpvoid FCSyseventBridge::removeListener(AdapterAddEventListener *listener) { 11733965Sjdp lock(); 11833965Sjdp try { 11933965Sjdp typedef vector<AdapterAddEventListener *>::iterator Iter; 12033965Sjdp for (Iter tmp = adapterAddEventListeners.begin(); 12133965Sjdp tmp != adapterAddEventListeners.end(); tmp++) { 12233965Sjdp if (*tmp == listener) { 12333965Sjdp adapterAddEventListeners.erase(tmp); 12433965Sjdp unlock(); 12533965Sjdp return; 12633965Sjdp } 12733965Sjdp } 12877298Sobrien throw InvalidHandleException(); 12977298Sobrien } catch (...) { 13033965Sjdp unlock(); 13133965Sjdp throw; 13233965Sjdp } 13333965Sjdp} 13433965Sjdp 13533965Sjdpvoid FCSyseventBridge::removeListener(AdapterEventListener *listener) { 13633965Sjdp lock(); 13733965Sjdp try { 13833965Sjdp typedef vector<AdapterEventListener *>::iterator Iter; 13933965Sjdp for (Iter tmp = adapterEventListeners.begin(); 14033965Sjdp tmp != adapterEventListeners.end(); tmp++) { 14133965Sjdp if (*tmp == listener) { 14233965Sjdp adapterEventListeners.erase(tmp); 14333965Sjdp unlock(); 14433965Sjdp return; 14533965Sjdp } 14633965Sjdp } 14733965Sjdp throw InvalidHandleException(); 14833965Sjdp } catch (...) { 14933965Sjdp unlock(); 15033965Sjdp throw; 15133965Sjdp } 15233965Sjdp} 15333965Sjdp 15433965Sjdpvoid FCSyseventBridge::removeListener(AdapterPortEventListener *listener) { 15533965Sjdp lock(); 15633965Sjdp try { 15733965Sjdp typedef vector<AdapterPortEventListener *>::iterator Iter; 15833965Sjdp for (Iter tmp = adapterPortEventListeners.begin(); 15933965Sjdp tmp != adapterPortEventListeners.end(); tmp++) { 16033965Sjdp if (*tmp == listener) { 16177298Sobrien adapterPortEventListeners.erase(tmp); 16277298Sobrien unlock(); 16333965Sjdp return; 16433965Sjdp } 16533965Sjdp } 16633965Sjdp throw InvalidHandleException(); 16733965Sjdp } catch (...) { 16833965Sjdp unlock(); 16977298Sobrien throw; 17033965Sjdp } 17133965Sjdp} 17277298Sobrien 17377298Sobrienvoid FCSyseventBridge::removeListener(AdapterDeviceEventListener *listener) { 17433965Sjdp lock(); 17533965Sjdp try { 17633965Sjdp typedef vector<AdapterDeviceEventListener *>::iterator Iter; 17733965Sjdp for (Iter tmp = adapterDeviceEventListeners.begin(); 17833965Sjdp tmp != adapterDeviceEventListeners.end(); tmp++) { 17933965Sjdp if (*tmp == listener) { 18033965Sjdp adapterDeviceEventListeners.erase(tmp); 18133965Sjdp unlock(); 18233965Sjdp return; 18333965Sjdp } 18433965Sjdp } 18577298Sobrien throw InvalidHandleException(); 18633965Sjdp } catch (...) { 18733965Sjdp unlock(); 18833965Sjdp throw; 189 } 190} 191 192void FCSyseventBridge::removeListener(TargetEventListener *listener) { 193 lock(); 194 try { 195 typedef vector<TargetEventListener *>::iterator Iter; 196 for (Iter tmp = targetEventListeners.begin(); 197 tmp != targetEventListeners.end(); tmp++) { 198 if (*tmp == listener) { 199 targetEventListeners.erase(tmp); 200 unlock(); 201 return; 202 } 203 } 204 throw InvalidHandleException(); 205 } catch (...) { 206 unlock(); 207 throw; 208 } 209} 210 211extern "C" void static_dispatch(sysevent_t *ev) { 212 Trace log("static_dispatch"); 213 FCSyseventBridge::getInstance()->dispatch(ev); 214} 215 216void FCSyseventBridge::dispatch(sysevent_t *ev) { 217 Trace log("FCSyseventBridge::dispatch"); 218 nvlist_t *list = NULL; 219 hrtime_t when; 220 221 if (ev == NULL) { 222 log.debug("Null event."); 223 return; 224 } 225 226 if (sysevent_get_attr_list(ev, &list) || list == NULL) { 227 log.debug("Empty event."); 228 return; 229 } 230 231 string eventVendor = sysevent_get_vendor_name(ev); 232 string eventPublisher = sysevent_get_pub_name(ev); 233 string eventClass = sysevent_get_class_name(ev); 234 string eventSubClass = sysevent_get_subclass_name(ev); 235 236 sysevent_get_time(ev, &when); 237 238 // Now that we know what type of event it is, handle it accordingly 239 if (eventClass == "EC_sunfc") { 240 241 // All events of this class type have instance and port-wwn for 242 // the HBA port. 243 uint32_t instance; 244 if (nvlist_lookup_uint32(list, (char *)"instance", 245 &instance)) { 246 log.genericIOError( 247 "Improperly formed event: no instance field."); 248 nvlist_free(list); 249 return; 250 } 251 uchar_t *rawPortWWN; 252 uint32_t rawPortWWNLength; 253 254 if (nvlist_lookup_byte_array(list, (char *)"port-wwn", 255 &rawPortWWN, &rawPortWWNLength)) { 256 log.genericIOError( 257 "Improperly formed event: no port-wwn field."); 258 nvlist_free(list); 259 return; 260 } 261 262 // Now deal with the specific details of each subclass type 263 if (eventSubClass == "ESC_sunfc_port_offline") { 264 265 // Create event instance 266 AdapterPortEvent event( 267 wwnConversion(rawPortWWN), 268 AdapterPortEvent::OFFLINE, 269 0); 270 271 // Dispatch to interested parties. 272 lock(); 273 try { 274 typedef vector<AdapterPortEventListener *>::iterator Iter; 275 for (Iter tmp = adapterPortEventListeners.begin(); 276 tmp != adapterPortEventListeners.end(); tmp++) { 277 (*tmp)->dispatch(event); 278 } 279 } catch (...) { 280 unlock(); 281 nvlist_free(list); 282 throw; 283 } 284 unlock(); 285 286 } else if (eventSubClass == "ESC_sunfc_port_online") { 287 288 // Create event instance 289 AdapterPortEvent event( 290 wwnConversion(rawPortWWN), 291 AdapterPortEvent::ONLINE, 292 0); 293 294 // Dispatch to interested parties. 295 lock(); 296 try { 297 typedef vector<AdapterPortEventListener *>::iterator Iter; 298 for (Iter tmp = adapterPortEventListeners.begin(); 299 tmp != adapterPortEventListeners.end(); tmp++) { 300 (*tmp)->dispatch(event); 301 } 302 } catch (...) { 303 unlock(); 304 nvlist_free(list); 305 throw; 306 } 307 unlock(); 308 309 } else if (eventSubClass == "ESC_sunfc_device_online") { 310 AdapterDeviceEvent event( 311 wwnConversion(rawPortWWN), 312 AdapterDeviceEvent::ONLINE, 313 0); 314 lock(); 315 try { 316 typedef vector<AdapterDeviceEventListener *>::iterator Iter; 317 for (Iter tmp = adapterDeviceEventListeners.begin(); 318 tmp != adapterDeviceEventListeners.end(); tmp++) { 319 (*tmp)->dispatch(event); 320 } 321 } catch (...) { 322 unlock(); 323 nvlist_free(list); 324 throw; 325 } 326 unlock(); 327 328 } else if (eventSubClass == "ESC_sunfc_device_offline") { 329 AdapterDeviceEvent event( 330 wwnConversion(rawPortWWN), 331 AdapterDeviceEvent::OFFLINE, 332 0); 333 lock(); 334 try { 335 typedef vector<AdapterDeviceEventListener *>::iterator Iter; 336 for (Iter tmp = adapterDeviceEventListeners.begin(); 337 tmp != adapterDeviceEventListeners.end(); tmp++) { 338 (*tmp)->dispatch(event); 339 } 340 } catch (...) { 341 unlock(); 342 nvlist_free(list); 343 throw; 344 } 345 unlock(); 346 347 } else if (eventSubClass == "ESC_sunfc_port_rscn") { 348 /* 349 * RSCNs are a little tricky. There can be multiple 350 * affected page properties, each numbered. To make sure 351 * we get them all, we loop through all properties 352 * in the nvlist and if their name begins with "affected_page_" 353 * then we send an event for them. 354 */ 355 uint32_t affected_page; 356 nvpair_t *attr = NULL; 357 for (attr = nvlist_next_nvpair(list, NULL); 358 attr != NULL; 359 attr = nvlist_next_nvpair(list, attr)) { 360 string name = nvpair_name(attr); 361 if (name.find("affected_page_") != name.npos) { 362 363 if (nvpair_value_uint32(attr, &affected_page)) { 364 log.genericIOError( 365 "Improperly formed event: " 366 "corrupt affected_page field"); 367 continue; 368 } 369 // Create event instance 370 AdapterPortEvent event( 371 wwnConversion(rawPortWWN), 372 AdapterPortEvent::FABRIC, 373 affected_page); 374 375 // Dispatch to interested parties. 376 lock(); 377 typedef vector<AdapterPortEventListener *>::iterator Iter; 378 try { 379 for (Iter tmp = adapterPortEventListeners.begin(); 380 tmp != adapterPortEventListeners.end(); tmp++) { 381 (*tmp)->dispatch(event); 382 } 383 } catch (...) { 384 unlock(); 385 nvlist_free(list); 386 throw; 387 } 388 unlock(); 389 } 390 } 391 } else if (eventSubClass == "ESC_sunfc_target_add") { 392 uchar_t *rawTargetPortWWN; 393 uint32_t rawTargetPortWWNLength; 394 395 if (nvlist_lookup_byte_array(list, (char *)"target-port-wwn", 396 &rawTargetPortWWN, &rawTargetPortWWNLength)) { 397 log.genericIOError( 398 "Improperly formed event: no target-port-wwn field."); 399 nvlist_free(list); 400 return; 401 } 402 403 // Create event instance 404 AdapterPortEvent event( 405 wwnConversion(rawPortWWN), 406 AdapterPortEvent::NEW_TARGETS, 407 0); 408 409 // Dispatch to interested parties. 410 lock(); 411 try { 412 typedef vector<AdapterPortEventListener *>::iterator Iter; 413 for (Iter tmp = adapterPortEventListeners.begin(); 414 tmp != adapterPortEventListeners.end(); tmp++) { 415 (*tmp)->dispatch(event); 416 } 417 } catch (...) { 418 unlock(); 419 nvlist_free(list); 420 throw; 421 } 422 unlock(); 423 } else if (eventSubClass == "ESC_sunfc_target_remove") { 424 uchar_t *rawTargetPortWWN; 425 uint32_t rawTargetPortWWNLength; 426 427 if (nvlist_lookup_byte_array(list, (char *)"target-port-wwn", 428 &rawTargetPortWWN, &rawTargetPortWWNLength)) { 429 log.genericIOError( 430 "Improperly formed event: no target-port-wwn field."); 431 nvlist_free(list); 432 return; 433 } 434 // Create event instance 435 TargetEvent event( 436 wwnConversion(rawPortWWN), 437 wwnConversion(rawTargetPortWWN), 438 TargetEvent::REMOVED); 439 440 // Dispatch to interested parties. 441 lock(); 442 try { 443 typedef vector<TargetEventListener *>::iterator Iter; 444 for (Iter tmp = targetEventListeners.begin(); 445 tmp != targetEventListeners.end(); tmp++) { 446 (*tmp)->dispatch(event); 447 } 448 } catch (...) { 449 unlock(); 450 nvlist_free(list); 451 throw; 452 } 453 unlock(); 454 } else if (eventSubClass == "ESC_sunfc_port_attach") { 455 // Create event instance 456 AdapterAddEvent event(wwnConversion(rawPortWWN)); 457 // Dispatch to interested parties. 458 lock(); 459 try { 460 typedef vector<AdapterAddEventListener *>::iterator Iter; 461 for (Iter tmp = adapterAddEventListeners.begin(); 462 tmp != adapterAddEventListeners.end(); tmp++) { 463 (*tmp)->dispatch(event); 464 } 465 } catch (...) { 466 unlock(); 467 nvlist_free(list); 468 throw; 469 } 470 unlock(); 471 } else if (eventSubClass == "ESC_sunfc_port_detach") { 472 // Technically, we should probably try to coalesce 473 // all detach events for the same multi-ported adapter 474 // and only send one event to the client, but for now, 475 // we'll just blindly send duplicates. 476 477 // Create event instance 478 AdapterEvent event( 479 wwnConversion(rawPortWWN), 480 AdapterEvent::REMOVE); 481 482 // Dispatch to interested parties. 483 lock(); 484 try { 485 typedef vector<AdapterEventListener *>::iterator Iter; 486 for (Iter tmp = adapterEventListeners.begin(); 487 tmp != adapterEventListeners.end(); tmp++) { 488 (*tmp)->dispatch(event); 489 } 490 } catch (...) { 491 unlock(); 492 nvlist_free(list); 493 throw; 494 } 495 unlock(); 496 497 } else { 498 log.genericIOError( 499 "Unrecognized subclass \"%s\": Ignoring event", 500 eventSubClass.c_str()); 501 } 502 } else { 503 // This should not happen, as we only asked for specific classes. 504 log.genericIOError( 505 "Unrecognized class \"%s\": Ignoring event", 506 eventClass.c_str()); 507 } 508 nvlist_free(list); 509} 510 511void FCSyseventBridge::validateRegistration() { 512 Trace log("FCSyseventBridge::validateRegistration"); 513 uint64_t count = 0; 514 count = adapterAddEventListeners.size() + 515 adapterEventListeners.size() + 516 adapterPortEventListeners.size() + 517 targetEventListeners.size(); 518 if (count == 1) { 519 handle = sysevent_bind_handle(static_dispatch); 520 if (handle == NULL) { 521 log.genericIOError( 522 "Unable to bind sysevent handle."); 523 return; 524 } 525 const char *subclass_list[9] = { 526 "ESC_sunfc_port_attach", 527 "ESC_sunfc_port_detach", 528 "ESC_sunfc_port_offline", 529 "ESC_sunfc_port_online", 530 "ESC_sunfc_port_rscn", 531 "ESC_sunfc_target_add", 532 "ESC_sunfc_target_remove", 533 "ESC_sunfc_device_online", 534 "ESC_sunfc_device_offline" 535 }; 536 if (sysevent_subscribe_event(handle, 537 "EC_sunfc", (const char **)subclass_list, 9)) { 538 log.genericIOError( 539 "Unable to subscribe to sun_fc events."); 540 sysevent_unbind_handle(handle); 541 handle = NULL; 542 } 543 } else if (count == 0 && handle != NULL) { 544 // Remove subscription 545 sysevent_unbind_handle(handle); 546 handle == NULL; 547 } // Else do nothing 548} 549 550int32_t FCSyseventBridge::getMaxListener() { 551 return (INT_MAX); 552} 553