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, Version 1.0 only
6 * (the "License").  You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22/*
23 * Copyright 1995-2003 Sun Microsystems, Inc.  All rights reserved.
24 * Use is subject to license terms.
25 */
26
27#pragma ident	"%Z%%M%	%I%	%E% SMI"
28
29/*
30 * Just in case we're not in a build environment, make sure that
31 * TEXT_DOMAIN gets set to something.
32 */
33#if !defined(TEXT_DOMAIN)
34#define	TEXT_DOMAIN "SYS_TEST"
35#endif
36
37/*
38 * libmeta wrappers for event notification
39 */
40
41#include <meta.h>
42#include <sys/lvm/md_notify.h>
43
44#if defined(DEBUG)
45#include <assert.h>
46#endif /* DEBUG */
47
48struct tag2obj_type {
49	md_tags_t	tag;
50	ev_obj_t	obj;
51} tag2obj_typetab[] =
52{
53	{ TAG_EMPTY,		EVO_EMPTY	},
54	{ TAG_METADEVICE,	EVO_METADEV	},
55	{ TAG_REPLICA,		EVO_REPLICA	},
56	{ TAG_HSP,		EVO_HSP		},
57	{ TAG_HS,		EVO_HS		},
58	{ TAG_SET,		EVO_SET		},
59	{ TAG_DRIVE,		EVO_DRIVE	},
60	{ TAG_HOST,		EVO_HOST	},
61	{ TAG_MEDIATOR,		EVO_MEDIATOR	},
62	{ TAG_UNK,		EVO_UNSPECIFIED	},
63
64	{ TAG_LAST,		EVO_LAST	}
65};
66
67struct evdrv2evlib_type {
68	md_event_type_t	drv;
69	evid_t		lib;
70} evdrv2evlib_typetab[] =
71{
72	{ EQ_EMPTY,		EV_EMPTY		},
73	{ EQ_CREATE,		EV_CREATE		},
74	{ EQ_DELETE,		EV_DELETE		},
75	{ EQ_ADD,		EV_ADD			},
76	{ EQ_REMOVE,		EV_REMOVE		},
77	{ EQ_REPLACE,		EV_REPLACE		},
78	{ EQ_MEDIATOR_ADD,	EV_MEDIATOR_ADD		},
79	{ EQ_MEDIATOR_DELETE,	EV_MEDIATOR_DELETE	},
80	{ EQ_HOST_ADD,		EV_HOST_ADD		},
81	{ EQ_HOST_DELETE,	EV_HOST_DELETE		},
82	{ EQ_DRIVE_ADD,		EV_DRIVE_ADD		},
83	{ EQ_DRIVE_DELETE,	EV_DRIVE_DELETE		},
84	{ EQ_RENAME_SRC,	EV_RENAME_SRC		},
85	{ EQ_RENAME_DST,	EV_RENAME_DST		},
86	{ EQ_INIT_START,	EV_INIT_START		},
87	{ EQ_INIT_FAILED,	EV_INIT_FAILED		},
88	{ EQ_INIT_FATAL,	EV_INIT_FATAL		},
89	{ EQ_INIT_SUCCESS,	EV_INIT_SUCCESS		},
90	{ EQ_IOERR,		EV_IOERR		},
91	{ EQ_ERRED,		EV_ERRED		},
92	{ EQ_LASTERRED,		EV_LASTERRED		},
93	{ EQ_OK,		EV_OK			},
94	{ EQ_ENABLE,		EV_ENABLE		},
95	{ EQ_RESYNC_START,	EV_RESYNC_START		},
96	{ EQ_RESYNC_FAILED,	EV_RESYNC_FAILED	},
97	{ EQ_RESYNC_SUCCESS,	EV_RESYNC_SUCCESS	},
98	{ EQ_RESYNC_DONE,	EV_RESYNC_DONE		},
99	{ EQ_HOTSPARED,		EV_HOTSPARED		},
100	{ EQ_HS_FREED,		EV_HS_FREED		},
101	{ EQ_TAKEOVER,		EV_TAKEOVER		},
102	{ EQ_RELEASE,		EV_RELEASE		},
103	{ EQ_OPEN_FAIL,		EV_OPEN_FAIL		},
104	{ EQ_OFFLINE,		EV_OFFLINE		},
105	{ EQ_ONLINE,		EV_ONLINE		},
106	{ EQ_GROW,		EV_GROW			},
107	{ EQ_DETACH,		EV_DETACH		},
108	{ EQ_DETACHING,		EV_DETACHING		},
109	{ EQ_ATTACH,		EV_ATTACH		},
110	{ EQ_ATTACHING,		EV_ATTACHING		},
111	{ EQ_CHANGE,		EV_CHANGE		},
112	{ EQ_EXCHANGE,		EV_EXCHANGE		},
113	{ EQ_REGEN_START,	EV_REGEN_START		},
114	{ EQ_REGEN_DONE,	EV_REGEN_DONE		},
115	{ EQ_REGEN_FAILED,	EV_REGEN_FAILED		},
116	{ EQ_USER,		EV_USER			},
117	{ EQ_NOTIFY_LOST,	EV_NOTIFY_LOST		},
118
119	{ EQ_LAST,		EV_LAST }
120};
121
122static ev_obj_t
123dev2tag(md_dev64_t dev, set_t setno, md_error_t *ep)
124{
125	mdname_t	*np	= NULL;
126	mdsetname_t	*sp	= NULL;
127	ev_obj_t	 obj	= EVO_METADEV;
128	char		*miscname;
129
130	if ((sp = metasetnosetname(setno, ep)) == NULL) {
131		goto out;
132	}
133	if (!(np = metamnumname(&sp, meta_getminor(dev), 0, ep))) {
134		goto out;
135	}
136
137	/* need to invalidate name in case rename or delete/create done */
138	meta_invalidate_name(np);
139
140	if (!(miscname = metagetmiscname(np, ep))) {
141		goto out;
142	}
143	if (strcmp(miscname, MD_STRIPE) == 0) {
144		obj = EVO_STRIPE;
145	} else if (strcmp(miscname, MD_MIRROR) == 0) {
146		obj = EVO_MIRROR;
147	} else if (strcmp(miscname, MD_RAID) == 0) {
148		obj = EVO_RAID5;
149	} else if (strcmp(miscname, MD_TRANS) == 0) {
150		obj = EVO_TRANS;
151	}
152out:
153	return (obj);
154}
155
156static ev_obj_t
157tagdrv_2_objlib(md_tags_t tag)
158{
159	int i;
160
161	for (i = 0; tag2obj_typetab[i].tag != TAG_LAST; i++) {
162		if (tag2obj_typetab[i].tag == tag)
163			return (tag2obj_typetab[i].obj);
164	}
165	return (EVO_UNSPECIFIED);
166}
167
168static md_tags_t
169objlib_2_tagdrv(ev_obj_t obj)
170{
171	int i;
172
173	for (i = 0; tag2obj_typetab[i].tag != TAG_LAST; i++) {
174		if (tag2obj_typetab[i].obj == obj)
175			return (tag2obj_typetab[i].tag);
176	}
177	return (TAG_UNK);
178}
179
180
181static evid_t
182evdrv_2_evlib(md_event_type_t drv_ev)
183{
184	int	i;
185
186	for (i = 0; evdrv2evlib_typetab[i].drv != EQ_LAST; i++) {
187		if (evdrv2evlib_typetab[i].drv == drv_ev)
188			return (evdrv2evlib_typetab[i].lib);
189	}
190	return (EV_UNK);
191}
192
193static md_event_type_t
194evlib_2_evdrv(evid_t lib_ev)
195{
196	int	i;
197
198	for (i = 0; evdrv2evlib_typetab[i].drv != EQ_LAST; i++) {
199		if (evdrv2evlib_typetab[i].lib == lib_ev)
200			return (evdrv2evlib_typetab[i].drv);
201	}
202	return (EQ_EMPTY);
203}
204
205
206/*
207 * meta_event
208 *  returns 0 on succcess or < 0 to indicate error.
209 *  abs(return code) = errno
210 */
211static int
212meta_event(md_event_ioctl_t *evctl, md_error_t *ep)
213{
214	int	l;
215
216	if (!evctl || !ep)
217		return (-EINVAL);
218
219	l = strlen(evctl->mdn_name);
220	if ((l == 0 && evctl->mdn_cmd != EQ_PUT) || l >= MD_NOTIFY_NAME_SIZE) {
221		return (-EINVAL);
222	}
223
224	MD_SETDRIVERNAME(evctl, MD_NOTIFY, 0);
225	mdclrerror(ep);
226	errno = 0;
227
228	if (metaioctl(MD_IOCNOTIFY, evctl, ep, evctl->mdn_name) != 0) {
229		if (errno == 0) {
230			errno = EINVAL;
231		}
232		if (mdisok(ep)) {
233			(void) mdsyserror(ep, errno, evctl->mdn_name);
234		}
235		return (-errno);
236	}
237
238	return (0);
239}
240
241static void
242init_evctl(char *qname,
243	md_tags_t tag,
244	md_event_type_t ev,
245	uint_t flags,
246	set_t set,
247	md_dev64_t dev,
248	md_event_cmds_t cmd,
249	u_longlong_t udata,
250	md_event_ioctl_t *evctlp)
251{
252
253	assert(evctlp);
254
255	(void) memset(evctlp, 0, sizeof (md_event_ioctl_t));
256
257	evctlp->mdn_magic	= MD_EVENT_ID;
258	evctlp->mdn_rev		= MD_NOTIFY_REVISION;
259
260	if (qname)
261		(void) strncpy(evctlp->mdn_name, qname, MD_NOTIFY_NAME_SIZE-1);
262	else
263		(void) memset(evctlp->mdn_name, 0, MD_NOTIFY_NAME_SIZE);
264
265	evctlp->mdn_tag		= tag;
266	evctlp->mdn_event	= ev;
267	evctlp->mdn_flags	= flags;
268	evctlp->mdn_set		= set;
269	evctlp->mdn_dev		= dev;
270	evctlp->mdn_cmd		= cmd;
271	evctlp->mdn_user	= udata;
272}
273
274/*
275 * meta_notify_createq
276 * - creates an eventq
277 * - returns 0 on success or errno and sets ep
278 */
279int
280meta_notify_createq(char *qname, ulong_t flags, md_error_t *ep)
281{
282	md_event_ioctl_t	evctl;
283	int			err	= 0;
284
285	mdclrerror(ep);
286	if (!qname || strlen(qname) == 0) {
287		(void) mdsyserror(ep, EINVAL,
288		    dgettext(TEXT_DOMAIN,
289			"null or zero-length queue name"));
290		return (EINVAL);
291	}
292
293	init_evctl(qname,
294			TAG_EMPTY,
295			EQ_EMPTY,
296			(flags & EVFLG_PERMANENT) != 0? EQ_Q_PERM: 0,
297			/* set */ 0,
298			/* dev */ 0,
299			EQ_ON,
300			/* user-defined event data */ 0,
301			&evctl);
302
303	err = meta_event(&evctl, ep);
304
305	if (err == -EEXIST && !(flags & EVFLG_EXISTERR)) {
306		err = 0;
307		mdclrerror(ep);
308	}
309	if (!mdisok(ep) && mdanysyserror(ep)) {
310		err = (ep)->info.md_error_info_t_u.ds_error.errnum;
311	}
312	return (-err);
313}
314
315/*
316 * meta_notify_deleteq
317 * - deletes an eventq
318 * - free's any underlying resources
319 * - returns 0 on success or errno and sets ep
320 */
321int
322meta_notify_deleteq(char *qname, md_error_t *ep)
323{
324	md_event_ioctl_t	evctl;
325	int			err;
326
327	init_evctl(qname,
328			TAG_EMPTY,
329			EQ_EMPTY,
330			/* flags */ 0,
331			/* set */ 0,
332			/* dev */ 0,
333			EQ_OFF,
334			/* user-defined event data */ 0,
335			&evctl);
336
337	err = meta_event(&evctl, ep);
338	return (-err);
339}
340
341/*
342 * meta_notify_validq
343 * - verifies that the queue exists
344 * - returns true or false, ep may be changed as a side-effect
345 */
346bool_t
347meta_notify_validq(char *qname, md_error_t *ep)
348{
349	md_event_ioctl_t	evctl;
350
351	init_evctl(qname,
352			TAG_EMPTY,
353			EQ_EMPTY,
354			/* flags */ 0,
355			/* set */ 0,
356			/* dev */ 0,
357			EQ_ON,
358			/* user-defined event data */ 0,
359			&evctl);
360
361	return (meta_event(&evctl, ep) == -EEXIST);
362}
363
364/*
365 * meta_notify_listq
366 * - returns number of (currently) active queus or -errno
367 * - allocates qnames array and sets user's pointer to it,
368 *   fills in array with vector of qnames
369 */
370int
371meta_notify_listq(char ***qnames, md_error_t *ep)
372{
373
374#ifdef lint
375	qnames = qnames;
376#endif /* lint */
377
378	mdclrerror(ep);
379	(void) mdsyserror(ep, EOPNOTSUPP, "EOPNOTSUPP");
380	return (-EOPNOTSUPP);
381}
382
383/*
384 * meta_notify_flushq
385 * - calls the underlying notify driver to flush all events
386 *   from the named queue
387 * - returns 0 on success or errno and sets ep as necessary
388 */
389int
390meta_notify_flushq(char *qname, md_error_t *ep)
391{
392
393#ifdef lint
394	qname = qname;
395#endif /* lint */
396
397	mdclrerror(ep);
398	(void) mdsyserror(ep, EOPNOTSUPP, "EOPNOTSUPP");
399	return (EOPNOTSUPP);
400}
401
402static void
403cook_ev(md_event_ioctl_t *evctlp, md_ev_t *evp, md_error_t *ep)
404{
405	assert(evctlp);
406	assert(evp);
407
408	evp->obj_type = tagdrv_2_objlib(evctlp->mdn_tag);
409
410	if (evp->obj_type == EVO_METADEV) {
411		evp->obj_type = dev2tag(evctlp->mdn_dev, evctlp->mdn_set, ep);
412	}
413
414	evp->setno	= evctlp->mdn_set;
415	evp->ev		= evdrv_2_evlib(evctlp->mdn_event);
416	evp->obj	= evctlp->mdn_dev;
417	evp->uev	= evctlp->mdn_user;
418}
419
420/*
421 * meta_notify_getev
422 * - collects up to 1 event and stores it into md_ev_t
423 * - returns number of events found (0 or 1) on success or -errno
424 * - flags governs whether an empty queue is waited upon (EVFLG_WAIT)
425 */
426int
427meta_notify_getev(char *qname, ulong_t flags, md_ev_t *evp, md_error_t *ep)
428{
429	md_event_ioctl_t	evctl;
430	int			n_ev;
431	int			err	= -EINVAL;
432
433	if (!evp) {
434		goto out;
435	}
436
437	init_evctl(qname,
438			TAG_EMPTY,
439			EQ_EMPTY,
440			/* flags (unused in get) */ 0,
441			(evp->setno == EV_ALLSETS)? MD_ALLSETS: evp->setno,
442			(evp->obj == EV_ALLOBJS)? MD_ALLDEVS: evp->obj,
443			(flags & EVFLG_WAIT) != 0? EQ_GET_WAIT: EQ_GET_NOWAIT,
444			/* user-defined event data */ 0,
445			&evctl);
446
447	err = meta_event(&evctl, ep);
448
449	/*
450	 * trap EAGAIN so that EV_EMPTY events get returned, but
451	 * be sure n_ev = 0 so that users who just watch the count
452	 * will also work
453	 */
454	switch (err) {
455	case -EAGAIN:
456		err = n_ev = 0;
457		cook_ev(&evctl, evp, ep);
458		break;
459	case 0:
460		n_ev = 1;
461		cook_ev(&evctl, evp, ep);
462		break;
463	}
464out:
465	return (err == 0? n_ev: err);
466}
467
468
469/*
470 * meta_notify_getevlist
471 * - collects all pending events in the named queue and allocates
472 *   an md_evlist_t * to return them
473 * - returns the number of events found (may be 0 if !WAIT) on success
474 *   or -errno and sets ep as necessary
475 */
476int
477meta_notify_getevlist(char *qname,
478			ulong_t  flags,
479			md_evlist_t **evpp_arg,
480			md_error_t *ep)
481{
482	md_ev_t		*evp		= NULL;
483	md_evlist_t	*evlp		= NULL;
484	md_evlist_t	*evlp_head	= NULL;
485	md_evlist_t	*new		= NULL;
486	int		 n_ev		= 0;
487	int		 err		= -EINVAL;
488
489	mdclrerror(ep);
490	if (!evpp_arg) {
491		(void) mdsyserror(ep, EINVAL, dgettext(TEXT_DOMAIN,
492		    "No event list pointer"));
493		goto out;
494	}
495
496	if (!qname || strlen(qname) == 0) {
497		(void) mdsyserror(ep, EINVAL, dgettext(TEXT_DOMAIN,
498		    "Null or zero-length queue name"));
499		goto out;
500	}
501
502	do {
503		if (!(evp = (md_ev_t *)Malloc(sizeof (md_ev_t)))) {
504			(void) mdsyserror(ep, ENOMEM, qname);
505			continue;
506		}
507		evp->obj_type	= EVO_EMPTY;
508		evp->setno	= EV_ALLSETS;
509		evp->ev		= EV_EMPTY;
510		evp->obj	= EV_ALLOBJS;
511		evp->uev	= 0ULL;
512
513		err = meta_notify_getev(qname, flags, evp, ep);
514
515		if (evp->ev != EV_EMPTY) {
516			new = (md_evlist_t *)Zalloc(sizeof (md_evlist_t));
517			if (evlp_head == NULL) {
518				evlp = evlp_head = new;
519			} else {
520				evlp->next = new;
521				evlp = new;
522			}
523			evlp->evp = evp;
524			n_ev++;
525		}
526
527	} while (err >= 0 && evp && evp->ev != EV_EMPTY);
528out:
529	if (err == -EAGAIN) {
530		err = 0;
531	}
532
533	if (err < 0) {
534		meta_notify_freeevlist(evlp_head);
535		evlp_head = NULL;
536		return (err);
537	} else if ((err == 0) && (evp->ev == EV_EMPTY)) {
538	    Free(evp);
539	    evp = NULL;
540	}
541
542	if (evpp_arg) {
543		*evpp_arg = evlp_head;
544	}
545
546	return (n_ev);
547}
548
549
550/*
551 * the guts of meta_notify_putev() and meta_notify_sendev()
552 * are within this function.
553 *
554 * meta_notify_putev() is intended for general use by user-level code,
555 * such as the GUI, to send user-defined events.
556 *
557 * meta_notify_sendev() is for "user-level driver" code, such as
558 * set manipulation and the multi-host daemon to generate events.
559 *
560 * Note- only convention enforces this usage.
561 */
562int
563meta_notify_doputev(md_ev_t *evp, md_error_t *ep)
564{
565	md_event_ioctl_t	evctl;
566
567	if (!evp || !ep) {
568		return (EINVAL);
569	}
570
571	/*
572	 * users may only put events of type EQ_USER
573	 */
574	init_evctl(/* qname (unused in put) */ NULL,
575			TAG_EMPTY,
576			EQ_EMPTY,
577			/* flags (unused in put) */ 0,
578			(evp->setno == EV_ALLSETS)? MD_ALLSETS: evp->setno,
579			(evp->obj == EV_ALLOBJS)? MD_ALLDEVS: evp->obj,
580			EQ_PUT,
581			evp->uev,
582			&evctl);
583
584	evctl.mdn_tag	= objlib_2_tagdrv(evp->obj_type);
585	evctl.mdn_event	= evlib_2_evdrv(evp->ev);
586
587	return (-meta_event(&evctl, ep));
588}
589
590/*
591 * meta_notify_putev
592 * - sends an event down to the notify driver (hence, all queues)
593 * - returns 0 on success or errno
594 */
595int
596meta_notify_putev(md_ev_t *evp, md_error_t *ep)
597{
598	if (!evp || !ep) {
599		return (EINVAL);
600	}
601
602	evp->ev = EV_USER;	/* by definition */
603
604	return (meta_notify_doputev(evp, ep));
605}
606
607/*
608 * alternate put event entry point which allows
609 * more control of event innards (for use by md "user-level drivers")
610 *
611 * Since this routine isn't for use by clients, the user event data
612 * is always forced to be 0. That is only meaningful for events
613 * of type EQ_USER (and those go through meta_notify_putev()), so
614 * this is consistent.
615 */
616int
617meta_notify_sendev(
618	ev_obj_t	tag,
619	set_t		set,
620	md_dev64_t	dev,
621	evid_t		ev)
622{
623	md_error_t		 status	= mdnullerror;
624	md_error_t		*ep	= &status;
625	md_ev_t			 ev_packet;
626	int			 rc;
627
628	ev_packet.obj_type	= tag;
629	ev_packet.setno		= set;
630	ev_packet.obj		= dev;
631	ev_packet.ev		= ev;
632	ev_packet.uev		= 0ULL;
633
634	rc = meta_notify_doputev(&ev_packet, ep);
635
636	if (0 == rc && !mdisok(ep)) {
637		rc = EINVAL;
638		mdclrerror(ep);
639	}
640	return (rc);
641}
642
643/*
644 * meta_notify_putevlist
645 * - sends all of the events in the event list
646 * - returns number of events sent (>= 0) on success or -errno
647 */
648int
649meta_notify_putevlist(md_evlist_t *evlp, md_error_t *ep)
650{
651	md_evlist_t	*evlpi;
652	int		 n_ev	= 0;
653	int		 err;
654
655	if (!evlp) {
656		err = 0;
657		goto out;	/* that was easy */
658	}
659
660	for (n_ev = 0, evlpi = evlp; evlpi; evlpi = evlpi->next) {
661		if ((err = meta_notify_putev(evlpi->evp, ep)) < 0) {
662			goto out;
663		}
664		n_ev++;
665	}
666out:
667	return (err != 0? err: n_ev);
668}
669
670/*
671 * meta_notify_freevlist
672 * - frees any memory allocated within the event list
673 * - returns 0 on success or errno and sets ep as necessary
674 */
675void
676meta_notify_freeevlist(md_evlist_t *evlp)
677{
678	md_evlist_t	*i;
679	md_evlist_t	*next;
680
681	for (i = evlp; i; i = i->next) {
682		if (i && i->evp) {
683			Free(i->evp);
684			i->evp = NULL;
685		}
686	}
687	for (i = evlp; i; /* NULL */) {
688		next = i->next;
689		Free(i);
690		i = next;
691	}
692}
693