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 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26
27
28 #include "FCSyseventBridge.h"
29 #include "Exceptions.h"
30 #include "Trace.h"
31 #include "AdapterAddEvent.h"
32 #include "AdapterEvent.h"
33 #include "AdapterPortEvent.h"
34 #include "AdapterDeviceEvent.h"
35 #include "TargetEvent.h"
36 #include "sun_fc.h"
37 #include <libnvpair.h>
38 #include <iostream>
39
40 using namespace std;
41
42 FCSyseventBridge* FCSyseventBridge::_instance = NULL;
43
getInstance()44 FCSyseventBridge* FCSyseventBridge::getInstance() {
45 Trace log("FCSyseventBridge::getInstance");
46 if (_instance == NULL) {
47 _instance = new FCSyseventBridge();
48 }
49 return (_instance);
50
51 }
52
53
addListener(AdapterAddEventListener * listener)54 void FCSyseventBridge::addListener(AdapterAddEventListener *listener) {
55 lock();
56 try {
57 adapterAddEventListeners.insert(adapterAddEventListeners.begin(),
58 listener);
59 validateRegistration();
60 unlock();
61 } catch (...) {
62 unlock();
63 throw;
64 }
65 }
addListener(AdapterEventListener * listener,HBA * hba)66 void FCSyseventBridge::addListener(AdapterEventListener *listener, HBA *hba) {
67 lock();
68 try {
69 adapterEventListeners.insert(adapterEventListeners.begin(), listener);
70 validateRegistration();
71 unlock();
72 } catch (...) {
73 unlock();
74 throw;
75 }
76 }
addListener(AdapterPortEventListener * listener,HBAPort * port)77 void FCSyseventBridge::addListener(AdapterPortEventListener *listener,
78 HBAPort *port) {
79 lock();
80 try {
81 adapterPortEventListeners.insert(adapterPortEventListeners.begin(),
82 listener);
83 validateRegistration();
84 unlock();
85 } catch (...) {
86 unlock();
87 throw;
88 }
89 }
addListener(AdapterDeviceEventListener * listener,HBAPort * port)90 void FCSyseventBridge::addListener(AdapterDeviceEventListener *listener,
91 HBAPort *port) {
92 lock();
93 try {
94 adapterDeviceEventListeners.insert(adapterDeviceEventListeners.begin(),
95 listener);
96 validateRegistration();
97 unlock();
98 } catch (...) {
99 unlock();
100 throw;
101 }
102 }
addListener(TargetEventListener * listener,HBAPort * port,uint64_t targetWWN,bool filter)103 void FCSyseventBridge::addListener(TargetEventListener *listener,
104 HBAPort *port, uint64_t targetWWN, bool filter) {
105 lock();
106 try {
107 targetEventListeners.insert(targetEventListeners.begin(), listener);
108 validateRegistration();
109 unlock();
110 } catch (...) {
111 unlock();
112 throw;
113 }
114 }
115
removeListener(AdapterAddEventListener * listener)116 void FCSyseventBridge::removeListener(AdapterAddEventListener *listener) {
117 lock();
118 try {
119 typedef vector<AdapterAddEventListener *>::iterator Iter;
120 for (Iter tmp = adapterAddEventListeners.begin();
121 tmp != adapterAddEventListeners.end(); tmp++) {
122 if (*tmp == listener) {
123 adapterAddEventListeners.erase(tmp);
124 unlock();
125 return;
126 }
127 }
128 throw InvalidHandleException();
129 } catch (...) {
130 unlock();
131 throw;
132 }
133 }
134
removeListener(AdapterEventListener * listener)135 void FCSyseventBridge::removeListener(AdapterEventListener *listener) {
136 lock();
137 try {
138 typedef vector<AdapterEventListener *>::iterator Iter;
139 for (Iter tmp = adapterEventListeners.begin();
140 tmp != adapterEventListeners.end(); tmp++) {
141 if (*tmp == listener) {
142 adapterEventListeners.erase(tmp);
143 unlock();
144 return;
145 }
146 }
147 throw InvalidHandleException();
148 } catch (...) {
149 unlock();
150 throw;
151 }
152 }
153
removeListener(AdapterPortEventListener * listener)154 void FCSyseventBridge::removeListener(AdapterPortEventListener *listener) {
155 lock();
156 try {
157 typedef vector<AdapterPortEventListener *>::iterator Iter;
158 for (Iter tmp = adapterPortEventListeners.begin();
159 tmp != adapterPortEventListeners.end(); tmp++) {
160 if (*tmp == listener) {
161 adapterPortEventListeners.erase(tmp);
162 unlock();
163 return;
164 }
165 }
166 throw InvalidHandleException();
167 } catch (...) {
168 unlock();
169 throw;
170 }
171 }
172
removeListener(AdapterDeviceEventListener * listener)173 void FCSyseventBridge::removeListener(AdapterDeviceEventListener *listener) {
174 lock();
175 try {
176 typedef vector<AdapterDeviceEventListener *>::iterator Iter;
177 for (Iter tmp = adapterDeviceEventListeners.begin();
178 tmp != adapterDeviceEventListeners.end(); tmp++) {
179 if (*tmp == listener) {
180 adapterDeviceEventListeners.erase(tmp);
181 unlock();
182 return;
183 }
184 }
185 throw InvalidHandleException();
186 } catch (...) {
187 unlock();
188 throw;
189 }
190 }
191
removeListener(TargetEventListener * listener)192 void 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
static_dispatch(sysevent_t * ev)211 extern "C" void static_dispatch(sysevent_t *ev) {
212 Trace log("static_dispatch");
213 FCSyseventBridge::getInstance()->dispatch(ev);
214 }
215
dispatch(sysevent_t * ev)216 void 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
validateRegistration()511 void 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
getMaxListener()550 int32_t FCSyseventBridge::getMaxListener() {
551 return (INT_MAX);
552 }
553