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 #include "FCSyseventBridge.h"
27 #include "Exceptions.h"
28 #include "Trace.h"
29 #include "AdapterAddEvent.h"
30 #include "AdapterEvent.h"
31 #include "AdapterPortEvent.h"
32 #include "AdapterDeviceEvent.h"
33 #include "TargetEvent.h"
34 #include "sun_fc.h"
35 #include <libnvpair.h>
36 #include <iostream>
37 #include <climits>
38
39 using namespace std;
40
41 FCSyseventBridge* FCSyseventBridge::_instance = NULL;
42
getInstance()43 FCSyseventBridge* FCSyseventBridge::getInstance() {
44 Trace log("FCSyseventBridge::getInstance");
45 if (_instance == NULL) {
46 _instance = new FCSyseventBridge();
47 }
48 return (_instance);
49
50 }
51
52
addListener(AdapterAddEventListener * listener)53 void FCSyseventBridge::addListener(AdapterAddEventListener *listener) {
54 lock();
55 try {
56 adapterAddEventListeners.insert(adapterAddEventListeners.begin(),
57 listener);
58 validateRegistration();
59 unlock();
60 } catch (...) {
61 unlock();
62 throw;
63 }
64 }
addListener(AdapterEventListener * listener,HBA * hba)65 void FCSyseventBridge::addListener(AdapterEventListener *listener, HBA *hba) {
66 lock();
67 try {
68 adapterEventListeners.insert(adapterEventListeners.begin(), listener);
69 validateRegistration();
70 unlock();
71 } catch (...) {
72 unlock();
73 throw;
74 }
75 }
addListener(AdapterPortEventListener * listener,HBAPort * port)76 void FCSyseventBridge::addListener(AdapterPortEventListener *listener,
77 HBAPort *port) {
78 lock();
79 try {
80 adapterPortEventListeners.insert(adapterPortEventListeners.begin(),
81 listener);
82 validateRegistration();
83 unlock();
84 } catch (...) {
85 unlock();
86 throw;
87 }
88 }
addListener(AdapterDeviceEventListener * listener,HBAPort * port)89 void FCSyseventBridge::addListener(AdapterDeviceEventListener *listener,
90 HBAPort *port) {
91 lock();
92 try {
93 adapterDeviceEventListeners.insert(adapterDeviceEventListeners.begin(),
94 listener);
95 validateRegistration();
96 unlock();
97 } catch (...) {
98 unlock();
99 throw;
100 }
101 }
addListener(TargetEventListener * listener,HBAPort * port,uint64_t targetWWN,bool filter)102 void FCSyseventBridge::addListener(TargetEventListener *listener,
103 HBAPort *port, uint64_t targetWWN, bool filter) {
104 lock();
105 try {
106 targetEventListeners.insert(targetEventListeners.begin(), listener);
107 validateRegistration();
108 unlock();
109 } catch (...) {
110 unlock();
111 throw;
112 }
113 }
114
removeListener(AdapterAddEventListener * listener)115 void FCSyseventBridge::removeListener(AdapterAddEventListener *listener) {
116 lock();
117 try {
118 typedef vector<AdapterAddEventListener *>::iterator Iter;
119 for (Iter tmp = adapterAddEventListeners.begin();
120 tmp != adapterAddEventListeners.end(); tmp++) {
121 if (*tmp == listener) {
122 adapterAddEventListeners.erase(tmp);
123 unlock();
124 return;
125 }
126 }
127 throw InvalidHandleException();
128 } catch (...) {
129 unlock();
130 throw;
131 }
132 }
133
removeListener(AdapterEventListener * listener)134 void FCSyseventBridge::removeListener(AdapterEventListener *listener) {
135 lock();
136 try {
137 typedef vector<AdapterEventListener *>::iterator Iter;
138 for (Iter tmp = adapterEventListeners.begin();
139 tmp != adapterEventListeners.end(); tmp++) {
140 if (*tmp == listener) {
141 adapterEventListeners.erase(tmp);
142 unlock();
143 return;
144 }
145 }
146 throw InvalidHandleException();
147 } catch (...) {
148 unlock();
149 throw;
150 }
151 }
152
removeListener(AdapterPortEventListener * listener)153 void FCSyseventBridge::removeListener(AdapterPortEventListener *listener) {
154 lock();
155 try {
156 typedef vector<AdapterPortEventListener *>::iterator Iter;
157 for (Iter tmp = adapterPortEventListeners.begin();
158 tmp != adapterPortEventListeners.end(); tmp++) {
159 if (*tmp == listener) {
160 adapterPortEventListeners.erase(tmp);
161 unlock();
162 return;
163 }
164 }
165 throw InvalidHandleException();
166 } catch (...) {
167 unlock();
168 throw;
169 }
170 }
171
removeListener(AdapterDeviceEventListener * listener)172 void FCSyseventBridge::removeListener(AdapterDeviceEventListener *listener) {
173 lock();
174 try {
175 typedef vector<AdapterDeviceEventListener *>::iterator Iter;
176 for (Iter tmp = adapterDeviceEventListeners.begin();
177 tmp != adapterDeviceEventListeners.end(); tmp++) {
178 if (*tmp == listener) {
179 adapterDeviceEventListeners.erase(tmp);
180 unlock();
181 return;
182 }
183 }
184 throw InvalidHandleException();
185 } catch (...) {
186 unlock();
187 throw;
188 }
189 }
190
removeListener(TargetEventListener * listener)191 void FCSyseventBridge::removeListener(TargetEventListener *listener) {
192 lock();
193 try {
194 typedef vector<TargetEventListener *>::iterator Iter;
195 for (Iter tmp = targetEventListeners.begin();
196 tmp != targetEventListeners.end(); tmp++) {
197 if (*tmp == listener) {
198 targetEventListeners.erase(tmp);
199 unlock();
200 return;
201 }
202 }
203 throw InvalidHandleException();
204 } catch (...) {
205 unlock();
206 throw;
207 }
208 }
209
static_dispatch(sysevent_t * ev)210 extern "C" void static_dispatch(sysevent_t *ev) {
211 Trace log("static_dispatch");
212 FCSyseventBridge::getInstance()->dispatch(ev);
213 }
214
dispatch(sysevent_t * ev)215 void FCSyseventBridge::dispatch(sysevent_t *ev) {
216 Trace log("FCSyseventBridge::dispatch");
217 nvlist_t *list = NULL;
218 hrtime_t when;
219
220 if (ev == NULL) {
221 log.debug("Null event.");
222 return;
223 }
224
225 if (sysevent_get_attr_list(ev, &list) || list == NULL) {
226 log.debug("Empty event.");
227 return;
228 }
229
230 string eventVendor = sysevent_get_vendor_name(ev);
231 string eventPublisher = sysevent_get_pub_name(ev);
232 string eventClass = sysevent_get_class_name(ev);
233 string eventSubClass = sysevent_get_subclass_name(ev);
234
235 sysevent_get_time(ev, &when);
236
237 // Now that we know what type of event it is, handle it accordingly
238 if (eventClass == "EC_sunfc") {
239
240 // All events of this class type have instance and port-wwn for
241 // the HBA port.
242 uint32_t instance;
243 if (nvlist_lookup_uint32(list, (char *)"instance",
244 &instance)) {
245 log.genericIOError(
246 "Improperly formed event: no instance field.");
247 nvlist_free(list);
248 return;
249 }
250 uchar_t *rawPortWWN;
251 uint32_t rawPortWWNLength;
252
253 if (nvlist_lookup_byte_array(list, (char *)"port-wwn",
254 &rawPortWWN, &rawPortWWNLength)) {
255 log.genericIOError(
256 "Improperly formed event: no port-wwn field.");
257 nvlist_free(list);
258 return;
259 }
260
261 // Now deal with the specific details of each subclass type
262 if (eventSubClass == "ESC_sunfc_port_offline") {
263
264 // Create event instance
265 AdapterPortEvent event(
266 wwnConversion(rawPortWWN),
267 AdapterPortEvent::OFFLINE,
268 0);
269
270 // Dispatch to interested parties.
271 lock();
272 try {
273 typedef vector<AdapterPortEventListener *>::iterator Iter;
274 for (Iter tmp = adapterPortEventListeners.begin();
275 tmp != adapterPortEventListeners.end(); tmp++) {
276 (*tmp)->dispatch(event);
277 }
278 } catch (...) {
279 unlock();
280 nvlist_free(list);
281 throw;
282 }
283 unlock();
284
285 } else if (eventSubClass == "ESC_sunfc_port_online") {
286
287 // Create event instance
288 AdapterPortEvent event(
289 wwnConversion(rawPortWWN),
290 AdapterPortEvent::ONLINE,
291 0);
292
293 // Dispatch to interested parties.
294 lock();
295 try {
296 typedef vector<AdapterPortEventListener *>::iterator Iter;
297 for (Iter tmp = adapterPortEventListeners.begin();
298 tmp != adapterPortEventListeners.end(); tmp++) {
299 (*tmp)->dispatch(event);
300 }
301 } catch (...) {
302 unlock();
303 nvlist_free(list);
304 throw;
305 }
306 unlock();
307
308 } else if (eventSubClass == "ESC_sunfc_device_online") {
309 AdapterDeviceEvent event(
310 wwnConversion(rawPortWWN),
311 AdapterDeviceEvent::ONLINE,
312 0);
313 lock();
314 try {
315 typedef vector<AdapterDeviceEventListener *>::iterator Iter;
316 for (Iter tmp = adapterDeviceEventListeners.begin();
317 tmp != adapterDeviceEventListeners.end(); tmp++) {
318 (*tmp)->dispatch(event);
319 }
320 } catch (...) {
321 unlock();
322 nvlist_free(list);
323 throw;
324 }
325 unlock();
326
327 } else if (eventSubClass == "ESC_sunfc_device_offline") {
328 AdapterDeviceEvent event(
329 wwnConversion(rawPortWWN),
330 AdapterDeviceEvent::OFFLINE,
331 0);
332 lock();
333 try {
334 typedef vector<AdapterDeviceEventListener *>::iterator Iter;
335 for (Iter tmp = adapterDeviceEventListeners.begin();
336 tmp != adapterDeviceEventListeners.end(); tmp++) {
337 (*tmp)->dispatch(event);
338 }
339 } catch (...) {
340 unlock();
341 nvlist_free(list);
342 throw;
343 }
344 unlock();
345
346 } else if (eventSubClass == "ESC_sunfc_port_rscn") {
347 /*
348 * RSCNs are a little tricky. There can be multiple
349 * affected page properties, each numbered. To make sure
350 * we get them all, we loop through all properties
351 * in the nvlist and if their name begins with "affected_page_"
352 * then we send an event for them.
353 */
354 uint32_t affected_page;
355 nvpair_t *attr = NULL;
356 for (attr = nvlist_next_nvpair(list, NULL);
357 attr != NULL;
358 attr = nvlist_next_nvpair(list, attr)) {
359 string name = nvpair_name(attr);
360 if (name.find("affected_page_") != name.npos) {
361
362 if (nvpair_value_uint32(attr, &affected_page)) {
363 log.genericIOError(
364 "Improperly formed event: "
365 "corrupt affected_page field");
366 continue;
367 }
368 // Create event instance
369 AdapterPortEvent event(
370 wwnConversion(rawPortWWN),
371 AdapterPortEvent::FABRIC,
372 affected_page);
373
374 // Dispatch to interested parties.
375 lock();
376 typedef vector<AdapterPortEventListener *>::iterator Iter;
377 try {
378 for (Iter tmp = adapterPortEventListeners.begin();
379 tmp != adapterPortEventListeners.end(); tmp++) {
380 (*tmp)->dispatch(event);
381 }
382 } catch (...) {
383 unlock();
384 nvlist_free(list);
385 throw;
386 }
387 unlock();
388 }
389 }
390 } else if (eventSubClass == "ESC_sunfc_target_add") {
391 uchar_t *rawTargetPortWWN;
392 uint32_t rawTargetPortWWNLength;
393
394 if (nvlist_lookup_byte_array(list, (char *)"target-port-wwn",
395 &rawTargetPortWWN, &rawTargetPortWWNLength)) {
396 log.genericIOError(
397 "Improperly formed event: no target-port-wwn field.");
398 nvlist_free(list);
399 return;
400 }
401
402 // Create event instance
403 AdapterPortEvent event(
404 wwnConversion(rawPortWWN),
405 AdapterPortEvent::NEW_TARGETS,
406 0);
407
408 // Dispatch to interested parties.
409 lock();
410 try {
411 typedef vector<AdapterPortEventListener *>::iterator Iter;
412 for (Iter tmp = adapterPortEventListeners.begin();
413 tmp != adapterPortEventListeners.end(); tmp++) {
414 (*tmp)->dispatch(event);
415 }
416 } catch (...) {
417 unlock();
418 nvlist_free(list);
419 throw;
420 }
421 unlock();
422 } else if (eventSubClass == "ESC_sunfc_target_remove") {
423 uchar_t *rawTargetPortWWN;
424 uint32_t rawTargetPortWWNLength;
425
426 if (nvlist_lookup_byte_array(list, (char *)"target-port-wwn",
427 &rawTargetPortWWN, &rawTargetPortWWNLength)) {
428 log.genericIOError(
429 "Improperly formed event: no target-port-wwn field.");
430 nvlist_free(list);
431 return;
432 }
433 // Create event instance
434 TargetEvent event(
435 wwnConversion(rawPortWWN),
436 wwnConversion(rawTargetPortWWN),
437 TargetEvent::REMOVED);
438
439 // Dispatch to interested parties.
440 lock();
441 try {
442 typedef vector<TargetEventListener *>::iterator Iter;
443 for (Iter tmp = targetEventListeners.begin();
444 tmp != targetEventListeners.end(); tmp++) {
445 (*tmp)->dispatch(event);
446 }
447 } catch (...) {
448 unlock();
449 nvlist_free(list);
450 throw;
451 }
452 unlock();
453 } else if (eventSubClass == "ESC_sunfc_port_attach") {
454 // Create event instance
455 AdapterAddEvent event(wwnConversion(rawPortWWN));
456 // Dispatch to interested parties.
457 lock();
458 try {
459 typedef vector<AdapterAddEventListener *>::iterator Iter;
460 for (Iter tmp = adapterAddEventListeners.begin();
461 tmp != adapterAddEventListeners.end(); tmp++) {
462 (*tmp)->dispatch(event);
463 }
464 } catch (...) {
465 unlock();
466 nvlist_free(list);
467 throw;
468 }
469 unlock();
470 } else if (eventSubClass == "ESC_sunfc_port_detach") {
471 // Technically, we should probably try to coalesce
472 // all detach events for the same multi-ported adapter
473 // and only send one event to the client, but for now,
474 // we'll just blindly send duplicates.
475
476 // Create event instance
477 AdapterEvent event(
478 wwnConversion(rawPortWWN),
479 AdapterEvent::REMOVE);
480
481 // Dispatch to interested parties.
482 lock();
483 try {
484 typedef vector<AdapterEventListener *>::iterator Iter;
485 for (Iter tmp = adapterEventListeners.begin();
486 tmp != adapterEventListeners.end(); tmp++) {
487 (*tmp)->dispatch(event);
488 }
489 } catch (...) {
490 unlock();
491 nvlist_free(list);
492 throw;
493 }
494 unlock();
495
496 } else {
497 log.genericIOError(
498 "Unrecognized subclass \"%s\": Ignoring event",
499 eventSubClass.c_str());
500 }
501 } else {
502 // This should not happen, as we only asked for specific classes.
503 log.genericIOError(
504 "Unrecognized class \"%s\": Ignoring event",
505 eventClass.c_str());
506 }
507 nvlist_free(list);
508 }
509
validateRegistration()510 void FCSyseventBridge::validateRegistration() {
511 Trace log("FCSyseventBridge::validateRegistration");
512 uint64_t count = 0;
513 count = adapterAddEventListeners.size() +
514 adapterEventListeners.size() +
515 adapterPortEventListeners.size() +
516 targetEventListeners.size();
517 if (count == 1) {
518 handle = sysevent_bind_handle(static_dispatch);
519 if (handle == NULL) {
520 log.genericIOError(
521 "Unable to bind sysevent handle.");
522 return;
523 }
524 const char *subclass_list[9] = {
525 "ESC_sunfc_port_attach",
526 "ESC_sunfc_port_detach",
527 "ESC_sunfc_port_offline",
528 "ESC_sunfc_port_online",
529 "ESC_sunfc_port_rscn",
530 "ESC_sunfc_target_add",
531 "ESC_sunfc_target_remove",
532 "ESC_sunfc_device_online",
533 "ESC_sunfc_device_offline"
534 };
535 if (sysevent_subscribe_event(handle,
536 "EC_sunfc", (const char **)subclass_list, 9)) {
537 log.genericIOError(
538 "Unable to subscribe to sun_fc events.");
539 sysevent_unbind_handle(handle);
540 handle = NULL;
541 }
542 } else if (count == 0 && handle != NULL) {
543 // Remove subscription
544 sysevent_unbind_handle(handle);
545 handle == NULL;
546 } // Else do nothing
547 }
548
getMaxListener()549 int32_t FCSyseventBridge::getMaxListener() {
550 return (INT_MAX);
551 }
552