xref: /illumos-gate/usr/src/lib/mpapi/libmpscsi_vhci/common/mp_utils.c (revision fd71220ba0fafcc9cf5ea0785db206f3f31336e7)
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