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