1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate *
4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate * with the License.
8*7c478bd9Sstevel@tonic-gate *
9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate *
14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate *
20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate */
26*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
27*7c478bd9Sstevel@tonic-gate
28*7c478bd9Sstevel@tonic-gate #include <stdio.h>
29*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
30*7c478bd9Sstevel@tonic-gate #include <stdarg.h>
31*7c478bd9Sstevel@tonic-gate #include <unistd.h>
32*7c478bd9Sstevel@tonic-gate #include <assert.h>
33*7c478bd9Sstevel@tonic-gate #include <string.h>
34*7c478bd9Sstevel@tonic-gate #include <limits.h>
35*7c478bd9Sstevel@tonic-gate #include <synch.h>
36*7c478bd9Sstevel@tonic-gate #include <libintl.h>
37*7c478bd9Sstevel@tonic-gate #include <errno.h>
38*7c478bd9Sstevel@tonic-gate #include <libdevinfo.h>
39*7c478bd9Sstevel@tonic-gate #include <sys/uio.h>
40*7c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
41*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
42*7c478bd9Sstevel@tonic-gate #include <stropts.h>
43*7c478bd9Sstevel@tonic-gate #include <sys/stream.h>
44*7c478bd9Sstevel@tonic-gate #include <fcntl.h>
45*7c478bd9Sstevel@tonic-gate #include <sys/stat.h>
46*7c478bd9Sstevel@tonic-gate #include <sys/mkdev.h>
47*7c478bd9Sstevel@tonic-gate
48*7c478bd9Sstevel@tonic-gate #include <sys/param.h>
49*7c478bd9Sstevel@tonic-gate #include <sys/openpromio.h>
50*7c478bd9Sstevel@tonic-gate #include <sys/ttymuxuser.h>
51*7c478bd9Sstevel@tonic-gate
52*7c478bd9Sstevel@tonic-gate #include "ttymux_rcm_impl.h"
53*7c478bd9Sstevel@tonic-gate #include "rcm_module.h"
54*7c478bd9Sstevel@tonic-gate
55*7c478bd9Sstevel@tonic-gate #define TTYMUX_OFFLINE_ERR gettext("Resource is in use by")
56*7c478bd9Sstevel@tonic-gate #define TTYMUX_UNKNOWN_ERR gettext("Unknown Operation attempted")
57*7c478bd9Sstevel@tonic-gate #define TTYMUX_ONLINE_ERR gettext("Failed to connect under multiplexer")
58*7c478bd9Sstevel@tonic-gate #define TTYMUX_INVALID_ERR gettext("Invalid Operation on this resource")
59*7c478bd9Sstevel@tonic-gate #define TTYMUX_OFFLINE_FAIL gettext("Failed to disconnect from multiplexer")
60*7c478bd9Sstevel@tonic-gate #define TTYMUX_MEMORY_ERR gettext("TTYMUX: strdup failure\n")
61*7c478bd9Sstevel@tonic-gate
62*7c478bd9Sstevel@tonic-gate
63*7c478bd9Sstevel@tonic-gate static int msglvl = 6; /* print messages less than this level */
64*7c478bd9Sstevel@tonic-gate #define TEST(cond, stmt) { if (cond) stmt; }
65*7c478bd9Sstevel@tonic-gate #define _msg(lvl, args) TEST(msglvl > (lvl), trace args)
66*7c478bd9Sstevel@tonic-gate
67*7c478bd9Sstevel@tonic-gate static int oflags = O_EXCL|O_RDWR|O_NONBLOCK|O_NOCTTY;
68*7c478bd9Sstevel@tonic-gate static dev_t cn_dev = NODEV;
69*7c478bd9Sstevel@tonic-gate static rsrc_t *cn_rsrc = NULL;
70*7c478bd9Sstevel@tonic-gate static rsrc_t cache_head;
71*7c478bd9Sstevel@tonic-gate static rsrc_t cache_tail;
72*7c478bd9Sstevel@tonic-gate static mutex_t cache_lock;
73*7c478bd9Sstevel@tonic-gate static char muxctl[PATH_MAX] = {0};
74*7c478bd9Sstevel@tonic-gate static char muxcon[PATH_MAX] = {0};
75*7c478bd9Sstevel@tonic-gate static int muxfd;
76*7c478bd9Sstevel@tonic-gate static boolean_t register_rsrcs;
77*7c478bd9Sstevel@tonic-gate
78*7c478bd9Sstevel@tonic-gate /* module interface routines */
79*7c478bd9Sstevel@tonic-gate static int tty_register(rcm_handle_t *);
80*7c478bd9Sstevel@tonic-gate static int tty_unregister(rcm_handle_t *);
81*7c478bd9Sstevel@tonic-gate static int tty_getinfo(rcm_handle_t *, char *, id_t, uint_t, char **,
82*7c478bd9Sstevel@tonic-gate char **, nvlist_t *, rcm_info_t **);
83*7c478bd9Sstevel@tonic-gate static int tty_suspend(rcm_handle_t *, char *, id_t,
84*7c478bd9Sstevel@tonic-gate timespec_t *, uint_t, char **, rcm_info_t **);
85*7c478bd9Sstevel@tonic-gate static int tty_resume(rcm_handle_t *, char *, id_t, uint_t, char **,
86*7c478bd9Sstevel@tonic-gate rcm_info_t **);
87*7c478bd9Sstevel@tonic-gate static int tty_offline(rcm_handle_t *, char *, id_t, uint_t, char **,
88*7c478bd9Sstevel@tonic-gate rcm_info_t **);
89*7c478bd9Sstevel@tonic-gate static int tty_online(rcm_handle_t *, char *, id_t, uint_t, char **,
90*7c478bd9Sstevel@tonic-gate rcm_info_t **);
91*7c478bd9Sstevel@tonic-gate static int tty_remove(rcm_handle_t *, char *, id_t, uint_t, char **,
92*7c478bd9Sstevel@tonic-gate rcm_info_t **);
93*7c478bd9Sstevel@tonic-gate
94*7c478bd9Sstevel@tonic-gate static int get_devpath(char *, char **, dev_t *);
95*7c478bd9Sstevel@tonic-gate
96*7c478bd9Sstevel@tonic-gate /*
97*7c478bd9Sstevel@tonic-gate * Module-Private data
98*7c478bd9Sstevel@tonic-gate */
99*7c478bd9Sstevel@tonic-gate static struct rcm_mod_ops tty_ops = {
100*7c478bd9Sstevel@tonic-gate RCM_MOD_OPS_VERSION,
101*7c478bd9Sstevel@tonic-gate tty_register,
102*7c478bd9Sstevel@tonic-gate tty_unregister,
103*7c478bd9Sstevel@tonic-gate tty_getinfo,
104*7c478bd9Sstevel@tonic-gate tty_suspend,
105*7c478bd9Sstevel@tonic-gate tty_resume,
106*7c478bd9Sstevel@tonic-gate tty_offline,
107*7c478bd9Sstevel@tonic-gate tty_online,
108*7c478bd9Sstevel@tonic-gate tty_remove,
109*7c478bd9Sstevel@tonic-gate NULL,
110*7c478bd9Sstevel@tonic-gate NULL
111*7c478bd9Sstevel@tonic-gate };
112*7c478bd9Sstevel@tonic-gate
113*7c478bd9Sstevel@tonic-gate /*PRINTFLIKE1*/
114*7c478bd9Sstevel@tonic-gate static void
trace(char * fmt,...)115*7c478bd9Sstevel@tonic-gate trace(char *fmt, ...)
116*7c478bd9Sstevel@tonic-gate {
117*7c478bd9Sstevel@tonic-gate va_list args;
118*7c478bd9Sstevel@tonic-gate char buf[256];
119*7c478bd9Sstevel@tonic-gate int sz;
120*7c478bd9Sstevel@tonic-gate
121*7c478bd9Sstevel@tonic-gate va_start(args, fmt);
122*7c478bd9Sstevel@tonic-gate sz = vsnprintf(buf, sizeof (buf), fmt, args);
123*7c478bd9Sstevel@tonic-gate va_end(args);
124*7c478bd9Sstevel@tonic-gate
125*7c478bd9Sstevel@tonic-gate if (sz < 0)
126*7c478bd9Sstevel@tonic-gate rcm_log_message(RCM_TRACE1,
127*7c478bd9Sstevel@tonic-gate _("TTYMUX: vsnprintf parse error\n"));
128*7c478bd9Sstevel@tonic-gate else if (sz > sizeof (buf)) {
129*7c478bd9Sstevel@tonic-gate char *b = malloc(sz + 1);
130*7c478bd9Sstevel@tonic-gate
131*7c478bd9Sstevel@tonic-gate if (b != NULL) {
132*7c478bd9Sstevel@tonic-gate va_start(args, fmt);
133*7c478bd9Sstevel@tonic-gate sz = vsnprintf(b, sz + 1, fmt, args);
134*7c478bd9Sstevel@tonic-gate va_end(args);
135*7c478bd9Sstevel@tonic-gate if (sz > 0)
136*7c478bd9Sstevel@tonic-gate rcm_log_message(RCM_TRACE1, _("%s"), b);
137*7c478bd9Sstevel@tonic-gate free(b);
138*7c478bd9Sstevel@tonic-gate }
139*7c478bd9Sstevel@tonic-gate } else {
140*7c478bd9Sstevel@tonic-gate rcm_log_message(RCM_TRACE1, _("%s"), buf);
141*7c478bd9Sstevel@tonic-gate }
142*7c478bd9Sstevel@tonic-gate }
143*7c478bd9Sstevel@tonic-gate
144*7c478bd9Sstevel@tonic-gate /*
145*7c478bd9Sstevel@tonic-gate * CACHE MANAGEMENT
146*7c478bd9Sstevel@tonic-gate * Resources managed by this module are stored in a list of rsrc_t
147*7c478bd9Sstevel@tonic-gate * structures.
148*7c478bd9Sstevel@tonic-gate */
149*7c478bd9Sstevel@tonic-gate
150*7c478bd9Sstevel@tonic-gate /*
151*7c478bd9Sstevel@tonic-gate * cache_lookup()
152*7c478bd9Sstevel@tonic-gate *
153*7c478bd9Sstevel@tonic-gate * Get a cache node for a resource. Call with cache lock held.
154*7c478bd9Sstevel@tonic-gate */
155*7c478bd9Sstevel@tonic-gate static rsrc_t *
cache_lookup(const char * resource)156*7c478bd9Sstevel@tonic-gate cache_lookup(const char *resource)
157*7c478bd9Sstevel@tonic-gate {
158*7c478bd9Sstevel@tonic-gate rsrc_t *rsrc;
159*7c478bd9Sstevel@tonic-gate rsrc = cache_head.next;
160*7c478bd9Sstevel@tonic-gate while (rsrc != &cache_tail) {
161*7c478bd9Sstevel@tonic-gate if (rsrc->id && strcmp(resource, rsrc->id) == 0) {
162*7c478bd9Sstevel@tonic-gate return (rsrc);
163*7c478bd9Sstevel@tonic-gate }
164*7c478bd9Sstevel@tonic-gate rsrc = rsrc->next;
165*7c478bd9Sstevel@tonic-gate }
166*7c478bd9Sstevel@tonic-gate return (NULL);
167*7c478bd9Sstevel@tonic-gate }
168*7c478bd9Sstevel@tonic-gate
169*7c478bd9Sstevel@tonic-gate /*
170*7c478bd9Sstevel@tonic-gate * Get a cache node for a minor node. Call with cache lock held.
171*7c478bd9Sstevel@tonic-gate */
172*7c478bd9Sstevel@tonic-gate static rsrc_t *
cache_lookup_bydevt(dev_t devt)173*7c478bd9Sstevel@tonic-gate cache_lookup_bydevt(dev_t devt)
174*7c478bd9Sstevel@tonic-gate {
175*7c478bd9Sstevel@tonic-gate rsrc_t *rsrc;
176*7c478bd9Sstevel@tonic-gate rsrc = cache_head.next;
177*7c478bd9Sstevel@tonic-gate while (rsrc != &cache_tail) {
178*7c478bd9Sstevel@tonic-gate if (rsrc->dev == devt)
179*7c478bd9Sstevel@tonic-gate return (rsrc);
180*7c478bd9Sstevel@tonic-gate rsrc = rsrc->next;
181*7c478bd9Sstevel@tonic-gate }
182*7c478bd9Sstevel@tonic-gate return (NULL);
183*7c478bd9Sstevel@tonic-gate }
184*7c478bd9Sstevel@tonic-gate
185*7c478bd9Sstevel@tonic-gate /*
186*7c478bd9Sstevel@tonic-gate * free_node()
187*7c478bd9Sstevel@tonic-gate *
188*7c478bd9Sstevel@tonic-gate * Free a node. Make sure it isn't in the list!
189*7c478bd9Sstevel@tonic-gate */
190*7c478bd9Sstevel@tonic-gate static void
free_node(rsrc_t * node)191*7c478bd9Sstevel@tonic-gate free_node(rsrc_t *node)
192*7c478bd9Sstevel@tonic-gate {
193*7c478bd9Sstevel@tonic-gate if (node) {
194*7c478bd9Sstevel@tonic-gate if (node->id) {
195*7c478bd9Sstevel@tonic-gate free(node->id);
196*7c478bd9Sstevel@tonic-gate }
197*7c478bd9Sstevel@tonic-gate free(node);
198*7c478bd9Sstevel@tonic-gate }
199*7c478bd9Sstevel@tonic-gate }
200*7c478bd9Sstevel@tonic-gate
201*7c478bd9Sstevel@tonic-gate /*
202*7c478bd9Sstevel@tonic-gate * cache_insert()
203*7c478bd9Sstevel@tonic-gate *
204*7c478bd9Sstevel@tonic-gate * Call with the cache_lock held.
205*7c478bd9Sstevel@tonic-gate */
206*7c478bd9Sstevel@tonic-gate static void
cache_insert(rsrc_t * node)207*7c478bd9Sstevel@tonic-gate cache_insert(rsrc_t *node)
208*7c478bd9Sstevel@tonic-gate {
209*7c478bd9Sstevel@tonic-gate /* insert at the head for best performance */
210*7c478bd9Sstevel@tonic-gate node->next = cache_head.next;
211*7c478bd9Sstevel@tonic-gate node->prev = &cache_head;
212*7c478bd9Sstevel@tonic-gate
213*7c478bd9Sstevel@tonic-gate node->next->prev = node;
214*7c478bd9Sstevel@tonic-gate node->prev->next = node;
215*7c478bd9Sstevel@tonic-gate }
216*7c478bd9Sstevel@tonic-gate
217*7c478bd9Sstevel@tonic-gate /*
218*7c478bd9Sstevel@tonic-gate * cache_create()
219*7c478bd9Sstevel@tonic-gate *
220*7c478bd9Sstevel@tonic-gate * Call with the cache_lock held.
221*7c478bd9Sstevel@tonic-gate */
222*7c478bd9Sstevel@tonic-gate static rsrc_t *
cache_create(const char * resource,dev_t dev)223*7c478bd9Sstevel@tonic-gate cache_create(const char *resource, dev_t dev)
224*7c478bd9Sstevel@tonic-gate {
225*7c478bd9Sstevel@tonic-gate rsrc_t *rsrc = malloc(sizeof (rsrc_t));
226*7c478bd9Sstevel@tonic-gate
227*7c478bd9Sstevel@tonic-gate if (rsrc != NULL) {
228*7c478bd9Sstevel@tonic-gate if ((rsrc->id = strdup(resource)) != NULL) {
229*7c478bd9Sstevel@tonic-gate rsrc->dev = dev;
230*7c478bd9Sstevel@tonic-gate rsrc->flags = 0;
231*7c478bd9Sstevel@tonic-gate rsrc->dependencies = NULL;
232*7c478bd9Sstevel@tonic-gate cache_insert(rsrc);
233*7c478bd9Sstevel@tonic-gate } else {
234*7c478bd9Sstevel@tonic-gate free(rsrc);
235*7c478bd9Sstevel@tonic-gate rsrc = NULL;
236*7c478bd9Sstevel@tonic-gate }
237*7c478bd9Sstevel@tonic-gate } else {
238*7c478bd9Sstevel@tonic-gate _msg(0, ("TTYMUX: malloc failure for resource %s.\n",
239*7c478bd9Sstevel@tonic-gate resource));
240*7c478bd9Sstevel@tonic-gate }
241*7c478bd9Sstevel@tonic-gate return (rsrc);
242*7c478bd9Sstevel@tonic-gate }
243*7c478bd9Sstevel@tonic-gate
244*7c478bd9Sstevel@tonic-gate /*
245*7c478bd9Sstevel@tonic-gate * cache_get()
246*7c478bd9Sstevel@tonic-gate *
247*7c478bd9Sstevel@tonic-gate * Call with the cache_lock held.
248*7c478bd9Sstevel@tonic-gate */
249*7c478bd9Sstevel@tonic-gate static rsrc_t *
cache_get(const char * resource)250*7c478bd9Sstevel@tonic-gate cache_get(const char *resource)
251*7c478bd9Sstevel@tonic-gate {
252*7c478bd9Sstevel@tonic-gate rsrc_t *rsrc = cache_lookup(resource);
253*7c478bd9Sstevel@tonic-gate if (rsrc == NULL) {
254*7c478bd9Sstevel@tonic-gate dev_t dev;
255*7c478bd9Sstevel@tonic-gate
256*7c478bd9Sstevel@tonic-gate (void) get_devpath((char *)resource, NULL, &dev);
257*7c478bd9Sstevel@tonic-gate rsrc = cache_create(resource, dev);
258*7c478bd9Sstevel@tonic-gate }
259*7c478bd9Sstevel@tonic-gate return (rsrc);
260*7c478bd9Sstevel@tonic-gate }
261*7c478bd9Sstevel@tonic-gate
262*7c478bd9Sstevel@tonic-gate /*
263*7c478bd9Sstevel@tonic-gate * cache_remove()
264*7c478bd9Sstevel@tonic-gate *
265*7c478bd9Sstevel@tonic-gate * Call with the cache_lock held.
266*7c478bd9Sstevel@tonic-gate */
267*7c478bd9Sstevel@tonic-gate static void
cache_remove(rsrc_t * node)268*7c478bd9Sstevel@tonic-gate cache_remove(rsrc_t *node)
269*7c478bd9Sstevel@tonic-gate {
270*7c478bd9Sstevel@tonic-gate node->next->prev = node->prev;
271*7c478bd9Sstevel@tonic-gate node->prev->next = node->next;
272*7c478bd9Sstevel@tonic-gate node->next = NULL;
273*7c478bd9Sstevel@tonic-gate node->prev = NULL;
274*7c478bd9Sstevel@tonic-gate }
275*7c478bd9Sstevel@tonic-gate
276*7c478bd9Sstevel@tonic-gate /*
277*7c478bd9Sstevel@tonic-gate * Open a file identified by fname with the given open flags.
278*7c478bd9Sstevel@tonic-gate * If the request is to open a file with exclusive access and the open
279*7c478bd9Sstevel@tonic-gate * fails then backoff exponentially and then retry the open.
280*7c478bd9Sstevel@tonic-gate * Do not wait for longer than about a second (since this may be an rcm
281*7c478bd9Sstevel@tonic-gate * framework thread).
282*7c478bd9Sstevel@tonic-gate */
283*7c478bd9Sstevel@tonic-gate static int
open_file(char * fname,int flags)284*7c478bd9Sstevel@tonic-gate open_file(char *fname, int flags)
285*7c478bd9Sstevel@tonic-gate {
286*7c478bd9Sstevel@tonic-gate int fd, cnt;
287*7c478bd9Sstevel@tonic-gate struct timespec ts;
288*7c478bd9Sstevel@tonic-gate
289*7c478bd9Sstevel@tonic-gate if ((flags & O_EXCL) == 0)
290*7c478bd9Sstevel@tonic-gate return (open(fname, flags));
291*7c478bd9Sstevel@tonic-gate
292*7c478bd9Sstevel@tonic-gate ts.tv_sec = 0;
293*7c478bd9Sstevel@tonic-gate ts.tv_nsec = 16000000; /* 16 milliseconds */
294*7c478bd9Sstevel@tonic-gate
295*7c478bd9Sstevel@tonic-gate for (cnt = 0; cnt < 5 && (fd = open(fname, flags)) == -1; cnt++) {
296*7c478bd9Sstevel@tonic-gate (void) nanosleep(&ts, NULL);
297*7c478bd9Sstevel@tonic-gate ts.tv_nsec *= 2;
298*7c478bd9Sstevel@tonic-gate }
299*7c478bd9Sstevel@tonic-gate return (fd);
300*7c478bd9Sstevel@tonic-gate }
301*7c478bd9Sstevel@tonic-gate
302*7c478bd9Sstevel@tonic-gate /*
303*7c478bd9Sstevel@tonic-gate * No-op for creating an association between a pair of resources.
304*7c478bd9Sstevel@tonic-gate */
305*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
306*7c478bd9Sstevel@tonic-gate static int
nullconnect(link_t * link)307*7c478bd9Sstevel@tonic-gate nullconnect(link_t *link)
308*7c478bd9Sstevel@tonic-gate {
309*7c478bd9Sstevel@tonic-gate return (0);
310*7c478bd9Sstevel@tonic-gate }
311*7c478bd9Sstevel@tonic-gate
312*7c478bd9Sstevel@tonic-gate /*
313*7c478bd9Sstevel@tonic-gate * No-op for destroying an association between a pair of resources.
314*7c478bd9Sstevel@tonic-gate */
315*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
316*7c478bd9Sstevel@tonic-gate static int
nulldisconnect(link_t * link)317*7c478bd9Sstevel@tonic-gate nulldisconnect(link_t *link)
318*7c478bd9Sstevel@tonic-gate {
319*7c478bd9Sstevel@tonic-gate return (0);
320*7c478bd9Sstevel@tonic-gate }
321*7c478bd9Sstevel@tonic-gate
322*7c478bd9Sstevel@tonic-gate /*
323*7c478bd9Sstevel@tonic-gate * Record an actual or desired association between two resources
324*7c478bd9Sstevel@tonic-gate * identified by their rsrc_t structures.
325*7c478bd9Sstevel@tonic-gate */
326*7c478bd9Sstevel@tonic-gate static link_t *
add_dependency(rsrc_t * user,rsrc_t * used)327*7c478bd9Sstevel@tonic-gate add_dependency(rsrc_t *user, rsrc_t *used)
328*7c478bd9Sstevel@tonic-gate {
329*7c478bd9Sstevel@tonic-gate link_t *linkhead;
330*7c478bd9Sstevel@tonic-gate link_t *link;
331*7c478bd9Sstevel@tonic-gate
332*7c478bd9Sstevel@tonic-gate if (user == NULL || used == NULL)
333*7c478bd9Sstevel@tonic-gate return (NULL);
334*7c478bd9Sstevel@tonic-gate
335*7c478bd9Sstevel@tonic-gate if (user->id && used->id && strcmp(user->id, used->id) == 0) {
336*7c478bd9Sstevel@tonic-gate _msg(2, ("TTYMUX: attempt to connect devices created by "
337*7c478bd9Sstevel@tonic-gate "the same driver\n"));
338*7c478bd9Sstevel@tonic-gate return (NULL);
339*7c478bd9Sstevel@tonic-gate }
340*7c478bd9Sstevel@tonic-gate
341*7c478bd9Sstevel@tonic-gate /*
342*7c478bd9Sstevel@tonic-gate * Search for all resources that this resource user is depending
343*7c478bd9Sstevel@tonic-gate * upon.
344*7c478bd9Sstevel@tonic-gate */
345*7c478bd9Sstevel@tonic-gate linkhead = user->dependencies;
346*7c478bd9Sstevel@tonic-gate for (link = linkhead; link != NULL; link = link->next) {
347*7c478bd9Sstevel@tonic-gate /*
348*7c478bd9Sstevel@tonic-gate * Does the using resource already depends on the used
349*7c478bd9Sstevel@tonic-gate * resource
350*7c478bd9Sstevel@tonic-gate */
351*7c478bd9Sstevel@tonic-gate if (link->used == used)
352*7c478bd9Sstevel@tonic-gate return (link);
353*7c478bd9Sstevel@tonic-gate }
354*7c478bd9Sstevel@tonic-gate
355*7c478bd9Sstevel@tonic-gate link = malloc(sizeof (link_t));
356*7c478bd9Sstevel@tonic-gate
357*7c478bd9Sstevel@tonic-gate if (link == NULL) {
358*7c478bd9Sstevel@tonic-gate rcm_log_message(RCM_ERROR, _("TTYMUX: Out of memory\n"));
359*7c478bd9Sstevel@tonic-gate return (NULL);
360*7c478bd9Sstevel@tonic-gate }
361*7c478bd9Sstevel@tonic-gate
362*7c478bd9Sstevel@tonic-gate _msg(6, ("TTYMUX: New link user %s used %s\n", user->id, used->id));
363*7c478bd9Sstevel@tonic-gate
364*7c478bd9Sstevel@tonic-gate link->user = user;
365*7c478bd9Sstevel@tonic-gate link->used = used;
366*7c478bd9Sstevel@tonic-gate link->linkid = 0;
367*7c478bd9Sstevel@tonic-gate link->state = UNKNOWN;
368*7c478bd9Sstevel@tonic-gate link->flags = 0;
369*7c478bd9Sstevel@tonic-gate
370*7c478bd9Sstevel@tonic-gate link->connect = nullconnect;
371*7c478bd9Sstevel@tonic-gate link->disconnect = nulldisconnect;
372*7c478bd9Sstevel@tonic-gate link->next = linkhead;
373*7c478bd9Sstevel@tonic-gate
374*7c478bd9Sstevel@tonic-gate user->dependencies = link;
375*7c478bd9Sstevel@tonic-gate
376*7c478bd9Sstevel@tonic-gate return (link);
377*7c478bd9Sstevel@tonic-gate }
378*7c478bd9Sstevel@tonic-gate
379*7c478bd9Sstevel@tonic-gate /*
380*7c478bd9Sstevel@tonic-gate * Send an I_STR stream ioctl to a device
381*7c478bd9Sstevel@tonic-gate */
382*7c478bd9Sstevel@tonic-gate static int
istrioctl(int fd,int cmd,void * data,int datalen,int * bytes)383*7c478bd9Sstevel@tonic-gate istrioctl(int fd, int cmd, void *data, int datalen, int *bytes) {
384*7c478bd9Sstevel@tonic-gate struct strioctl ios;
385*7c478bd9Sstevel@tonic-gate int rval;
386*7c478bd9Sstevel@tonic-gate
387*7c478bd9Sstevel@tonic-gate ios.ic_timout = 0; /* use the default */
388*7c478bd9Sstevel@tonic-gate ios.ic_cmd = cmd;
389*7c478bd9Sstevel@tonic-gate ios.ic_dp = (char *)data;
390*7c478bd9Sstevel@tonic-gate ios.ic_len = datalen;
391*7c478bd9Sstevel@tonic-gate
392*7c478bd9Sstevel@tonic-gate rval = ioctl(fd, I_STR, (char *)&ios);
393*7c478bd9Sstevel@tonic-gate if (bytes)
394*7c478bd9Sstevel@tonic-gate *bytes = ios.ic_len;
395*7c478bd9Sstevel@tonic-gate return (rval);
396*7c478bd9Sstevel@tonic-gate }
397*7c478bd9Sstevel@tonic-gate
398*7c478bd9Sstevel@tonic-gate /*
399*7c478bd9Sstevel@tonic-gate * Streams link the driver identified by fd underneath a mux
400*7c478bd9Sstevel@tonic-gate * identified by ctrl_fd.
401*7c478bd9Sstevel@tonic-gate */
402*7c478bd9Sstevel@tonic-gate static int
plink(int ctrl_fd,int fd)403*7c478bd9Sstevel@tonic-gate plink(int ctrl_fd, int fd)
404*7c478bd9Sstevel@tonic-gate {
405*7c478bd9Sstevel@tonic-gate int linkid;
406*7c478bd9Sstevel@tonic-gate
407*7c478bd9Sstevel@tonic-gate /*
408*7c478bd9Sstevel@tonic-gate * pop any modules off the lower stream.
409*7c478bd9Sstevel@tonic-gate */
410*7c478bd9Sstevel@tonic-gate while (ioctl(fd, I_POP, 0) == 0)
411*7c478bd9Sstevel@tonic-gate ;
412*7c478bd9Sstevel@tonic-gate
413*7c478bd9Sstevel@tonic-gate if ((linkid = ioctl(ctrl_fd, I_PLINK, fd)) < 0)
414*7c478bd9Sstevel@tonic-gate rcm_log_message(RCM_ERROR,
415*7c478bd9Sstevel@tonic-gate _("TTYMUX: I_PLINK error %d.\n"), errno);
416*7c478bd9Sstevel@tonic-gate return (linkid);
417*7c478bd9Sstevel@tonic-gate }
418*7c478bd9Sstevel@tonic-gate
419*7c478bd9Sstevel@tonic-gate /*
420*7c478bd9Sstevel@tonic-gate * Streams unlink the STREAM identified by linkid from a mux
421*7c478bd9Sstevel@tonic-gate * identified by ctrl_fd.
422*7c478bd9Sstevel@tonic-gate */
423*7c478bd9Sstevel@tonic-gate static int
punlink(int ctrl_fd,int linkid)424*7c478bd9Sstevel@tonic-gate punlink(int ctrl_fd, int linkid)
425*7c478bd9Sstevel@tonic-gate {
426*7c478bd9Sstevel@tonic-gate if (ioctl(ctrl_fd, I_PUNLINK, linkid) < 0)
427*7c478bd9Sstevel@tonic-gate return (errno);
428*7c478bd9Sstevel@tonic-gate else
429*7c478bd9Sstevel@tonic-gate return (0);
430*7c478bd9Sstevel@tonic-gate }
431*7c478bd9Sstevel@tonic-gate
432*7c478bd9Sstevel@tonic-gate /*
433*7c478bd9Sstevel@tonic-gate * Connect a pair of resources by establishing the dependency association.
434*7c478bd9Sstevel@tonic-gate * Only works for devices that support the TTYMUX ioctls.
435*7c478bd9Sstevel@tonic-gate */
436*7c478bd9Sstevel@tonic-gate static int
mux_connect(link_t * link)437*7c478bd9Sstevel@tonic-gate mux_connect(link_t *link)
438*7c478bd9Sstevel@tonic-gate {
439*7c478bd9Sstevel@tonic-gate int lfd;
440*7c478bd9Sstevel@tonic-gate int rv;
441*7c478bd9Sstevel@tonic-gate ttymux_assoc_t as;
442*7c478bd9Sstevel@tonic-gate uint8_t ioflags;
443*7c478bd9Sstevel@tonic-gate
444*7c478bd9Sstevel@tonic-gate _msg(6, ("TTYMUX: mux_connect (%ld:%ld<->%ld:%ld %s <-> %s\n",
445*7c478bd9Sstevel@tonic-gate major(link->user->dev), minor(link->user->dev),
446*7c478bd9Sstevel@tonic-gate major(link->used->dev), minor(link->used->dev),
447*7c478bd9Sstevel@tonic-gate link->user->id, link->used->id));
448*7c478bd9Sstevel@tonic-gate
449*7c478bd9Sstevel@tonic-gate _msg(12, ("TTYMUX: struct size = %d (plen %d)\n",
450*7c478bd9Sstevel@tonic-gate sizeof (as), PATH_MAX));
451*7c478bd9Sstevel@tonic-gate
452*7c478bd9Sstevel@tonic-gate if (link->user->dev == NODEV || link->used->dev == NODEV) {
453*7c478bd9Sstevel@tonic-gate /*
454*7c478bd9Sstevel@tonic-gate * One of the resources in the association is not
455*7c478bd9Sstevel@tonic-gate * present (wait for the online notification before
456*7c478bd9Sstevel@tonic-gate * attempting to establish the dependency association.
457*7c478bd9Sstevel@tonic-gate */
458*7c478bd9Sstevel@tonic-gate return (EAGAIN);
459*7c478bd9Sstevel@tonic-gate }
460*7c478bd9Sstevel@tonic-gate if (major(link->user->dev) == major(link->used->dev)) {
461*7c478bd9Sstevel@tonic-gate _msg(2, ("TTYMUX: attempt to link devices created by "
462*7c478bd9Sstevel@tonic-gate "the same driver\n"));
463*7c478bd9Sstevel@tonic-gate return (EINVAL);
464*7c478bd9Sstevel@tonic-gate }
465*7c478bd9Sstevel@tonic-gate /*
466*7c478bd9Sstevel@tonic-gate * Explicitly check for attempts to plumb the system console -
467*7c478bd9Sstevel@tonic-gate * required becuase not all serial devices support the
468*7c478bd9Sstevel@tonic-gate * O_EXCL open flag.
469*7c478bd9Sstevel@tonic-gate */
470*7c478bd9Sstevel@tonic-gate if (link->used->dev == cn_dev) {
471*7c478bd9Sstevel@tonic-gate rcm_log_message(RCM_WARNING, _("TTYMUX: Request to link the "
472*7c478bd9Sstevel@tonic-gate " system console under another device not allowed!\n"));
473*7c478bd9Sstevel@tonic-gate
474*7c478bd9Sstevel@tonic-gate return (EPERM);
475*7c478bd9Sstevel@tonic-gate }
476*7c478bd9Sstevel@tonic-gate
477*7c478bd9Sstevel@tonic-gate /*
478*7c478bd9Sstevel@tonic-gate * Ensure that the input/output mode of the dependent is reasonable
479*7c478bd9Sstevel@tonic-gate */
480*7c478bd9Sstevel@tonic-gate if ((ioflags = link->flags & FORIO) == 0)
481*7c478bd9Sstevel@tonic-gate ioflags = FORIO;
482*7c478bd9Sstevel@tonic-gate
483*7c478bd9Sstevel@tonic-gate /*
484*7c478bd9Sstevel@tonic-gate * Open each resource participating in the association.
485*7c478bd9Sstevel@tonic-gate */
486*7c478bd9Sstevel@tonic-gate lfd = open(link->used->id, O_EXCL|O_RDWR|O_NONBLOCK|O_NOCTTY);
487*7c478bd9Sstevel@tonic-gate if (lfd == -1) {
488*7c478bd9Sstevel@tonic-gate if (errno == EBUSY) {
489*7c478bd9Sstevel@tonic-gate rcm_log_message(RCM_WARNING, _("TTYMUX: device %s is "
490*7c478bd9Sstevel@tonic-gate " busy - " " cannot connect to %s\n"),
491*7c478bd9Sstevel@tonic-gate link->used->id, link->user->id);
492*7c478bd9Sstevel@tonic-gate } else {
493*7c478bd9Sstevel@tonic-gate rcm_log_message(RCM_WARNING,
494*7c478bd9Sstevel@tonic-gate _("TTYMUX: open error %d for device %s\n"),
495*7c478bd9Sstevel@tonic-gate errno, link->used->id);
496*7c478bd9Sstevel@tonic-gate }
497*7c478bd9Sstevel@tonic-gate return (errno);
498*7c478bd9Sstevel@tonic-gate }
499*7c478bd9Sstevel@tonic-gate /*
500*7c478bd9Sstevel@tonic-gate * Note: Issuing the I_PLINK and TTYMUX_ASSOC request on the 'using'
501*7c478bd9Sstevel@tonic-gate * resource is more generic:
502*7c478bd9Sstevel@tonic-gate * muxfd = open(link->user->id, oflags);
503*7c478bd9Sstevel@tonic-gate * However using the ctl (MUXCTLLINK) node means that any current opens
504*7c478bd9Sstevel@tonic-gate * on the 'using' resource are uneffected.
505*7c478bd9Sstevel@tonic-gate */
506*7c478bd9Sstevel@tonic-gate
507*7c478bd9Sstevel@tonic-gate /*
508*7c478bd9Sstevel@tonic-gate * Figure out if the 'used' resource is already associated with
509*7c478bd9Sstevel@tonic-gate * some resource - if so tell the caller to try again later.
510*7c478bd9Sstevel@tonic-gate * More generally if any user or kernel thread has the resource
511*7c478bd9Sstevel@tonic-gate * open then the association should not be made.
512*7c478bd9Sstevel@tonic-gate * The ttymux driver makes this check (but it should be done here).
513*7c478bd9Sstevel@tonic-gate */
514*7c478bd9Sstevel@tonic-gate as.ttymux_linkid = 0;
515*7c478bd9Sstevel@tonic-gate as.ttymux_ldev = link->used->dev;
516*7c478bd9Sstevel@tonic-gate
517*7c478bd9Sstevel@tonic-gate if (istrioctl(muxfd, TTYMUX_GETLINK,
518*7c478bd9Sstevel@tonic-gate (void *)&as, sizeof (as), NULL) == 0) {
519*7c478bd9Sstevel@tonic-gate
520*7c478bd9Sstevel@tonic-gate _msg(7, ("TTYMUX: %ld:%ld (%d) (udev %ld:%ld) already linked\n",
521*7c478bd9Sstevel@tonic-gate major(as.ttymux_ldev), minor(as.ttymux_ldev),
522*7c478bd9Sstevel@tonic-gate as.ttymux_linkid, major(as.ttymux_udev),
523*7c478bd9Sstevel@tonic-gate minor(as.ttymux_udev)));
524*7c478bd9Sstevel@tonic-gate link->linkid = as.ttymux_linkid;
525*7c478bd9Sstevel@tonic-gate if (as.ttymux_udev != NODEV) {
526*7c478bd9Sstevel@tonic-gate (void) close(lfd);
527*7c478bd9Sstevel@tonic-gate return (EAGAIN);
528*7c478bd9Sstevel@tonic-gate }
529*7c478bd9Sstevel@tonic-gate }
530*7c478bd9Sstevel@tonic-gate
531*7c478bd9Sstevel@tonic-gate /*
532*7c478bd9Sstevel@tonic-gate * Now link and associate the used resource under the using resource.
533*7c478bd9Sstevel@tonic-gate */
534*7c478bd9Sstevel@tonic-gate as.ttymux_udev = link->user->dev;
535*7c478bd9Sstevel@tonic-gate as.ttymux_ldev = link->used->dev;
536*7c478bd9Sstevel@tonic-gate as.ttymux_tag = 0ul;
537*7c478bd9Sstevel@tonic-gate as.ttymux_ioflag = ioflags;
538*7c478bd9Sstevel@tonic-gate
539*7c478bd9Sstevel@tonic-gate _msg(6, ("TTYMUX: connecting %ld:%ld to %ld:%ld\n",
540*7c478bd9Sstevel@tonic-gate major(as.ttymux_ldev), minor(as.ttymux_ldev),
541*7c478bd9Sstevel@tonic-gate major(as.ttymux_udev), minor(as.ttymux_udev)));
542*7c478bd9Sstevel@tonic-gate
543*7c478bd9Sstevel@tonic-gate if (as.ttymux_udev == cn_dev) {
544*7c478bd9Sstevel@tonic-gate struct termios tc;
545*7c478bd9Sstevel@tonic-gate
546*7c478bd9Sstevel@tonic-gate if (ioctl(lfd, TCGETS, &tc) != -1) {
547*7c478bd9Sstevel@tonic-gate tc.c_cflag |= CREAD;
548*7c478bd9Sstevel@tonic-gate if (ioctl(lfd, TCSETSW, &tc) == -1) {
549*7c478bd9Sstevel@tonic-gate rcm_log_message(RCM_WARNING,
550*7c478bd9Sstevel@tonic-gate _("TTYMUX: error %d whilst enabling the "
551*7c478bd9Sstevel@tonic-gate "receiver on device %d:%d\n"),
552*7c478bd9Sstevel@tonic-gate errno, major(as.ttymux_ldev),
553*7c478bd9Sstevel@tonic-gate minor(as.ttymux_ldev));
554*7c478bd9Sstevel@tonic-gate }
555*7c478bd9Sstevel@tonic-gate }
556*7c478bd9Sstevel@tonic-gate }
557*7c478bd9Sstevel@tonic-gate
558*7c478bd9Sstevel@tonic-gate if (as.ttymux_linkid <= 0 && (as.ttymux_linkid =
559*7c478bd9Sstevel@tonic-gate plink(muxfd, lfd)) <= 0) {
560*7c478bd9Sstevel@tonic-gate rcm_log_message(RCM_WARNING,
561*7c478bd9Sstevel@tonic-gate _("TTYMUX: Link error %d for device %s\n"),
562*7c478bd9Sstevel@tonic-gate errno, link->used->id);
563*7c478bd9Sstevel@tonic-gate rv = errno;
564*7c478bd9Sstevel@tonic-gate goto out;
565*7c478bd9Sstevel@tonic-gate }
566*7c478bd9Sstevel@tonic-gate link->linkid = as.ttymux_linkid;
567*7c478bd9Sstevel@tonic-gate
568*7c478bd9Sstevel@tonic-gate _msg(6, ("TTYMUX: associating\n"));
569*7c478bd9Sstevel@tonic-gate if (istrioctl(muxfd, TTYMUX_ASSOC, (void *)&as, sizeof (as), 0) != 0) {
570*7c478bd9Sstevel@tonic-gate rv = errno;
571*7c478bd9Sstevel@tonic-gate goto out;
572*7c478bd9Sstevel@tonic-gate }
573*7c478bd9Sstevel@tonic-gate _msg(6, ("TTYMUX: Succesfully connected %ld:%ld to %ld:%ld\n",
574*7c478bd9Sstevel@tonic-gate major(as.ttymux_ldev), minor(as.ttymux_ldev),
575*7c478bd9Sstevel@tonic-gate major(as.ttymux_udev), minor(as.ttymux_udev)));
576*7c478bd9Sstevel@tonic-gate link->state = CONNECTED;
577*7c478bd9Sstevel@tonic-gate (void) close(lfd);
578*7c478bd9Sstevel@tonic-gate return (0);
579*7c478bd9Sstevel@tonic-gate out:
580*7c478bd9Sstevel@tonic-gate rcm_log_message(RCM_WARNING,
581*7c478bd9Sstevel@tonic-gate _("TTYMUX: Error [%d] connecting %d:%d to %d:%d\n"),
582*7c478bd9Sstevel@tonic-gate rv, major(as.ttymux_ldev), minor(as.ttymux_ldev),
583*7c478bd9Sstevel@tonic-gate major(as.ttymux_udev), minor(as.ttymux_udev));
584*7c478bd9Sstevel@tonic-gate
585*7c478bd9Sstevel@tonic-gate (void) close(lfd);
586*7c478bd9Sstevel@tonic-gate if (as.ttymux_linkid > 0) {
587*7c478bd9Sstevel@tonic-gate /*
588*7c478bd9Sstevel@tonic-gate * There was an error so unwind the I_PLINK step
589*7c478bd9Sstevel@tonic-gate */
590*7c478bd9Sstevel@tonic-gate if (punlink(muxfd, as.ttymux_linkid) != 0)
591*7c478bd9Sstevel@tonic-gate rcm_log_message(RCM_WARNING,
592*7c478bd9Sstevel@tonic-gate _("TTYMUX: Unlink error %d (%s).\n"),
593*7c478bd9Sstevel@tonic-gate errno, link->used->id);
594*7c478bd9Sstevel@tonic-gate }
595*7c478bd9Sstevel@tonic-gate return (rv);
596*7c478bd9Sstevel@tonic-gate }
597*7c478bd9Sstevel@tonic-gate
598*7c478bd9Sstevel@tonic-gate /*
599*7c478bd9Sstevel@tonic-gate * Disconnect a pair of resources by destroying the dependency association.
600*7c478bd9Sstevel@tonic-gate * Only works for devices that support the TTYMUX ioctls.
601*7c478bd9Sstevel@tonic-gate */
602*7c478bd9Sstevel@tonic-gate static int
mux_disconnect(link_t * link)603*7c478bd9Sstevel@tonic-gate mux_disconnect(link_t *link)
604*7c478bd9Sstevel@tonic-gate {
605*7c478bd9Sstevel@tonic-gate int rv;
606*7c478bd9Sstevel@tonic-gate ttymux_assoc_t as;
607*7c478bd9Sstevel@tonic-gate
608*7c478bd9Sstevel@tonic-gate _msg(6, ("TTYMUX: mux_disconnect %s<->%s (%ld:%ld<->%ld:%ld)\n",
609*7c478bd9Sstevel@tonic-gate link->user->id, link->used->id,
610*7c478bd9Sstevel@tonic-gate major(link->user->dev), minor(link->user->dev),
611*7c478bd9Sstevel@tonic-gate major(link->used->dev), minor(link->used->dev)));
612*7c478bd9Sstevel@tonic-gate
613*7c478bd9Sstevel@tonic-gate as.ttymux_ldev = link->used->dev;
614*7c478bd9Sstevel@tonic-gate
615*7c478bd9Sstevel@tonic-gate if (istrioctl(muxfd, TTYMUX_GETLINK,
616*7c478bd9Sstevel@tonic-gate (void *)&as, sizeof (as), NULL) != 0) {
617*7c478bd9Sstevel@tonic-gate
618*7c478bd9Sstevel@tonic-gate _msg(1, ("TTYMUX: %ld:%ld not linked [err %d]\n",
619*7c478bd9Sstevel@tonic-gate major(link->used->dev), minor(link->used->dev), errno));
620*7c478bd9Sstevel@tonic-gate return (0);
621*7c478bd9Sstevel@tonic-gate
622*7c478bd9Sstevel@tonic-gate /*
623*7c478bd9Sstevel@tonic-gate * Do not disassociate console resources - simply
624*7c478bd9Sstevel@tonic-gate * unlink them so that they remain persistent.
625*7c478bd9Sstevel@tonic-gate */
626*7c478bd9Sstevel@tonic-gate } else if (as.ttymux_udev != cn_dev &&
627*7c478bd9Sstevel@tonic-gate istrioctl(muxfd, TTYMUX_DISASSOC, (void *)&as,
628*7c478bd9Sstevel@tonic-gate sizeof (as), 0) == -1) {
629*7c478bd9Sstevel@tonic-gate
630*7c478bd9Sstevel@tonic-gate rv = errno;
631*7c478bd9Sstevel@tonic-gate rcm_log_message(RCM_WARNING,
632*7c478bd9Sstevel@tonic-gate _("TTYMUX: Dissassociate error %d for %s\n"),
633*7c478bd9Sstevel@tonic-gate rv, link->used->id);
634*7c478bd9Sstevel@tonic-gate
635*7c478bd9Sstevel@tonic-gate } else if (punlink(muxfd, as.ttymux_linkid) != 0) {
636*7c478bd9Sstevel@tonic-gate rv = errno;
637*7c478bd9Sstevel@tonic-gate rcm_log_message(RCM_WARNING,
638*7c478bd9Sstevel@tonic-gate _("TTYMUX: Error %d unlinking %d:%d\n"),
639*7c478bd9Sstevel@tonic-gate errno, major(link->used->dev), minor(link->used->dev));
640*7c478bd9Sstevel@tonic-gate } else {
641*7c478bd9Sstevel@tonic-gate _msg(6, ("TTYMUX: %s<->%s disconnected.\n",
642*7c478bd9Sstevel@tonic-gate link->user->id, link->used->id));
643*7c478bd9Sstevel@tonic-gate
644*7c478bd9Sstevel@tonic-gate link->state = DISCONNECTED;
645*7c478bd9Sstevel@tonic-gate link->linkid = 0;
646*7c478bd9Sstevel@tonic-gate rv = 0;
647*7c478bd9Sstevel@tonic-gate }
648*7c478bd9Sstevel@tonic-gate return (rv);
649*7c478bd9Sstevel@tonic-gate }
650*7c478bd9Sstevel@tonic-gate
651*7c478bd9Sstevel@tonic-gate /* PESISTENCY */
652*7c478bd9Sstevel@tonic-gate
653*7c478bd9Sstevel@tonic-gate /*
654*7c478bd9Sstevel@tonic-gate * Given a special device file system path return the /devices path
655*7c478bd9Sstevel@tonic-gate * and/or the device number (dev_t) of the device.
656*7c478bd9Sstevel@tonic-gate */
657*7c478bd9Sstevel@tonic-gate static int
get_devpath(char * dev,char ** cname,dev_t * devt)658*7c478bd9Sstevel@tonic-gate get_devpath(char *dev, char **cname, dev_t *devt)
659*7c478bd9Sstevel@tonic-gate {
660*7c478bd9Sstevel@tonic-gate struct stat sb;
661*7c478bd9Sstevel@tonic-gate
662*7c478bd9Sstevel@tonic-gate if (cname != NULL)
663*7c478bd9Sstevel@tonic-gate *cname = NULL;
664*7c478bd9Sstevel@tonic-gate
665*7c478bd9Sstevel@tonic-gate if (devt != NULL)
666*7c478bd9Sstevel@tonic-gate *devt = NODEV;
667*7c478bd9Sstevel@tonic-gate
668*7c478bd9Sstevel@tonic-gate if (lstat(dev, &sb) < 0) {
669*7c478bd9Sstevel@tonic-gate return (errno);
670*7c478bd9Sstevel@tonic-gate } else if ((sb.st_mode & S_IFMT) == S_IFLNK) {
671*7c478bd9Sstevel@tonic-gate int lsz;
672*7c478bd9Sstevel@tonic-gate char linkbuf[PATH_MAX+1];
673*7c478bd9Sstevel@tonic-gate
674*7c478bd9Sstevel@tonic-gate if (stat(dev, &sb) < 0)
675*7c478bd9Sstevel@tonic-gate return (errno);
676*7c478bd9Sstevel@tonic-gate
677*7c478bd9Sstevel@tonic-gate lsz = readlink(dev, linkbuf, PATH_MAX);
678*7c478bd9Sstevel@tonic-gate
679*7c478bd9Sstevel@tonic-gate if (lsz <= 0)
680*7c478bd9Sstevel@tonic-gate return (ENODEV);
681*7c478bd9Sstevel@tonic-gate linkbuf[lsz] = '\0';
682*7c478bd9Sstevel@tonic-gate dev = strstr(linkbuf, "/devices");
683*7c478bd9Sstevel@tonic-gate if (dev == NULL)
684*7c478bd9Sstevel@tonic-gate return (ENODEV);
685*7c478bd9Sstevel@tonic-gate }
686*7c478bd9Sstevel@tonic-gate
687*7c478bd9Sstevel@tonic-gate if (cname != NULL)
688*7c478bd9Sstevel@tonic-gate *cname = strdup(dev);
689*7c478bd9Sstevel@tonic-gate
690*7c478bd9Sstevel@tonic-gate if (devt != NULL)
691*7c478bd9Sstevel@tonic-gate *devt = sb.st_rdev;
692*7c478bd9Sstevel@tonic-gate
693*7c478bd9Sstevel@tonic-gate return (0);
694*7c478bd9Sstevel@tonic-gate }
695*7c478bd9Sstevel@tonic-gate
696*7c478bd9Sstevel@tonic-gate /*
697*7c478bd9Sstevel@tonic-gate * See routine locate_node
698*7c478bd9Sstevel@tonic-gate */
699*7c478bd9Sstevel@tonic-gate static int
locate_dev(di_node_t node,di_minor_t minor,void * arg)700*7c478bd9Sstevel@tonic-gate locate_dev(di_node_t node, di_minor_t minor, void *arg)
701*7c478bd9Sstevel@tonic-gate {
702*7c478bd9Sstevel@tonic-gate char *devfspath;
703*7c478bd9Sstevel@tonic-gate char resource[PATH_MAX];
704*7c478bd9Sstevel@tonic-gate rsrc_t *rsrc;
705*7c478bd9Sstevel@tonic-gate
706*7c478bd9Sstevel@tonic-gate if (di_minor_devt(minor) != (dev_t)arg)
707*7c478bd9Sstevel@tonic-gate return (DI_WALK_CONTINUE);
708*7c478bd9Sstevel@tonic-gate
709*7c478bd9Sstevel@tonic-gate if ((devfspath = di_devfs_path(node)) == NULL)
710*7c478bd9Sstevel@tonic-gate return (DI_WALK_TERMINATE);
711*7c478bd9Sstevel@tonic-gate
712*7c478bd9Sstevel@tonic-gate if (snprintf(resource, sizeof (resource), "/devices%s:%s",
713*7c478bd9Sstevel@tonic-gate devfspath, di_minor_name(minor)) > sizeof (resource)) {
714*7c478bd9Sstevel@tonic-gate di_devfs_path_free(devfspath);
715*7c478bd9Sstevel@tonic-gate return (DI_WALK_TERMINATE);
716*7c478bd9Sstevel@tonic-gate }
717*7c478bd9Sstevel@tonic-gate
718*7c478bd9Sstevel@tonic-gate di_devfs_path_free(devfspath);
719*7c478bd9Sstevel@tonic-gate
720*7c478bd9Sstevel@tonic-gate rsrc = cache_lookup(resource);
721*7c478bd9Sstevel@tonic-gate if (rsrc == NULL &&
722*7c478bd9Sstevel@tonic-gate (rsrc = cache_create(resource, di_minor_devt(minor))) == NULL)
723*7c478bd9Sstevel@tonic-gate return (DI_WALK_TERMINATE);
724*7c478bd9Sstevel@tonic-gate
725*7c478bd9Sstevel@tonic-gate rsrc->dev = di_minor_devt(minor);
726*7c478bd9Sstevel@tonic-gate rsrc->flags |= PRESENT;
727*7c478bd9Sstevel@tonic-gate rsrc->flags &= ~UNKNOWN;
728*7c478bd9Sstevel@tonic-gate return (DI_WALK_TERMINATE);
729*7c478bd9Sstevel@tonic-gate }
730*7c478bd9Sstevel@tonic-gate
731*7c478bd9Sstevel@tonic-gate /*
732*7c478bd9Sstevel@tonic-gate * Find a devinfo node that matches the device argument (dev).
733*7c478bd9Sstevel@tonic-gate * This is an expensive search of the whole device tree!
734*7c478bd9Sstevel@tonic-gate */
735*7c478bd9Sstevel@tonic-gate static rsrc_t *
locate_node(dev_t dev,di_node_t * root)736*7c478bd9Sstevel@tonic-gate locate_node(dev_t dev, di_node_t *root)
737*7c478bd9Sstevel@tonic-gate {
738*7c478bd9Sstevel@tonic-gate rsrc_t *rsrc;
739*7c478bd9Sstevel@tonic-gate
740*7c478bd9Sstevel@tonic-gate assert(root != NULL);
741*7c478bd9Sstevel@tonic-gate
742*7c478bd9Sstevel@tonic-gate if ((rsrc = cache_lookup_bydevt(dev)) != NULL)
743*7c478bd9Sstevel@tonic-gate return (rsrc);
744*7c478bd9Sstevel@tonic-gate
745*7c478bd9Sstevel@tonic-gate (void) di_walk_minor(*root, NULL, 0, (void*)dev, locate_dev);
746*7c478bd9Sstevel@tonic-gate
747*7c478bd9Sstevel@tonic-gate return (cache_lookup_bydevt(dev));
748*7c478bd9Sstevel@tonic-gate }
749*7c478bd9Sstevel@tonic-gate
750*7c478bd9Sstevel@tonic-gate /*
751*7c478bd9Sstevel@tonic-gate * Search for any existing dependency relationships managed by this
752*7c478bd9Sstevel@tonic-gate * RCM module.
753*7c478bd9Sstevel@tonic-gate */
754*7c478bd9Sstevel@tonic-gate static int
probe_dependencies()755*7c478bd9Sstevel@tonic-gate probe_dependencies()
756*7c478bd9Sstevel@tonic-gate {
757*7c478bd9Sstevel@tonic-gate ttymux_assocs_t links;
758*7c478bd9Sstevel@tonic-gate ttymux_assoc_t *asp;
759*7c478bd9Sstevel@tonic-gate int cnt, n;
760*7c478bd9Sstevel@tonic-gate rsrc_t *ruser;
761*7c478bd9Sstevel@tonic-gate rsrc_t *used;
762*7c478bd9Sstevel@tonic-gate link_t *link;
763*7c478bd9Sstevel@tonic-gate di_node_t root;
764*7c478bd9Sstevel@tonic-gate
765*7c478bd9Sstevel@tonic-gate cnt = istrioctl(muxfd, TTYMUX_LIST, (void *)0, 0, 0);
766*7c478bd9Sstevel@tonic-gate
767*7c478bd9Sstevel@tonic-gate _msg(8, ("TTYMUX: Probed %d links [%d]\n", cnt, errno));
768*7c478bd9Sstevel@tonic-gate
769*7c478bd9Sstevel@tonic-gate if (cnt <= 0)
770*7c478bd9Sstevel@tonic-gate return (0);
771*7c478bd9Sstevel@tonic-gate
772*7c478bd9Sstevel@tonic-gate if ((links.ttymux_assocs = calloc(cnt, sizeof (ttymux_assoc_t))) == 0)
773*7c478bd9Sstevel@tonic-gate return (EAGAIN);
774*7c478bd9Sstevel@tonic-gate
775*7c478bd9Sstevel@tonic-gate links.ttymux_nlinks = cnt;
776*7c478bd9Sstevel@tonic-gate
777*7c478bd9Sstevel@tonic-gate n = istrioctl(muxfd, TTYMUX_LIST, (void *)&links, sizeof (links), 0);
778*7c478bd9Sstevel@tonic-gate
779*7c478bd9Sstevel@tonic-gate if (n == -1) {
780*7c478bd9Sstevel@tonic-gate _msg(2, ("TTYMUX: Probe error %s\n", strerror(errno)));
781*7c478bd9Sstevel@tonic-gate free(links.ttymux_assocs);
782*7c478bd9Sstevel@tonic-gate return (0);
783*7c478bd9Sstevel@tonic-gate }
784*7c478bd9Sstevel@tonic-gate
785*7c478bd9Sstevel@tonic-gate asp = (ttymux_assoc_t *)links.ttymux_assocs;
786*7c478bd9Sstevel@tonic-gate
787*7c478bd9Sstevel@tonic-gate if ((root = di_init("/", DINFOSUBTREE|DINFOMINOR)) == DI_NODE_NIL)
788*7c478bd9Sstevel@tonic-gate return (errno);
789*7c478bd9Sstevel@tonic-gate
790*7c478bd9Sstevel@tonic-gate (void) mutex_lock(&cache_lock);
791*7c478bd9Sstevel@tonic-gate for (; cnt--; asp++) {
792*7c478bd9Sstevel@tonic-gate _msg(7, ("TTYMUX: Probed: %ld %ld %ld:%ld <-> %ld:%ld\n",
793*7c478bd9Sstevel@tonic-gate asp->ttymux_udev, asp->ttymux_ldev,
794*7c478bd9Sstevel@tonic-gate major(asp->ttymux_udev), minor(asp->ttymux_udev),
795*7c478bd9Sstevel@tonic-gate major(asp->ttymux_ldev), minor(asp->ttymux_ldev)));
796*7c478bd9Sstevel@tonic-gate /*
797*7c478bd9Sstevel@tonic-gate * The TTYMUX_LIST ioctl can return links relating
798*7c478bd9Sstevel@tonic-gate * to potential devices. Such devices are identified
799*7c478bd9Sstevel@tonic-gate * in the path field.
800*7c478bd9Sstevel@tonic-gate */
801*7c478bd9Sstevel@tonic-gate if (asp->ttymux_ldev == NODEV) {
802*7c478bd9Sstevel@tonic-gate char buf[PATH_MAX];
803*7c478bd9Sstevel@tonic-gate
804*7c478bd9Sstevel@tonic-gate if (asp->ttymux_path == NULL ||
805*7c478bd9Sstevel@tonic-gate *asp->ttymux_path != '/')
806*7c478bd9Sstevel@tonic-gate continue;
807*7c478bd9Sstevel@tonic-gate
808*7c478bd9Sstevel@tonic-gate if (snprintf(buf, sizeof (buf), "/devices%s",
809*7c478bd9Sstevel@tonic-gate asp->ttymux_path) > sizeof (buf))
810*7c478bd9Sstevel@tonic-gate continue;
811*7c478bd9Sstevel@tonic-gate
812*7c478bd9Sstevel@tonic-gate used = cache_get(buf);
813*7c478bd9Sstevel@tonic-gate } else {
814*7c478bd9Sstevel@tonic-gate used = locate_node(asp->ttymux_ldev, &root);
815*7c478bd9Sstevel@tonic-gate }
816*7c478bd9Sstevel@tonic-gate if ((ruser = locate_node(asp->ttymux_udev, &root)) == NULL) {
817*7c478bd9Sstevel@tonic-gate _msg(7, ("TTYMUX: Probe: %ld:%ld not present\n",
818*7c478bd9Sstevel@tonic-gate major(asp->ttymux_udev), minor(asp->ttymux_udev)));
819*7c478bd9Sstevel@tonic-gate continue;
820*7c478bd9Sstevel@tonic-gate }
821*7c478bd9Sstevel@tonic-gate if (used == NULL) {
822*7c478bd9Sstevel@tonic-gate _msg(7, ("TTYMUX: Probe: %ld:%ld not present\n",
823*7c478bd9Sstevel@tonic-gate major(asp->ttymux_ldev), minor(asp->ttymux_ldev)));
824*7c478bd9Sstevel@tonic-gate continue;
825*7c478bd9Sstevel@tonic-gate }
826*7c478bd9Sstevel@tonic-gate _msg(6, ("TTYMUX: Probe: Restore %s <-> %s (id %d)\n",
827*7c478bd9Sstevel@tonic-gate ruser->id, used->id, asp->ttymux_linkid));
828*7c478bd9Sstevel@tonic-gate
829*7c478bd9Sstevel@tonic-gate link = add_dependency(ruser, used);
830*7c478bd9Sstevel@tonic-gate
831*7c478bd9Sstevel@tonic-gate if (link != NULL) {
832*7c478bd9Sstevel@tonic-gate link->flags = (uint_t)asp->ttymux_ioflag;
833*7c478bd9Sstevel@tonic-gate link->linkid = asp->ttymux_linkid;
834*7c478bd9Sstevel@tonic-gate link->state = CONNECTED;
835*7c478bd9Sstevel@tonic-gate link->connect = mux_connect;
836*7c478bd9Sstevel@tonic-gate link->disconnect = mux_disconnect;
837*7c478bd9Sstevel@tonic-gate }
838*7c478bd9Sstevel@tonic-gate }
839*7c478bd9Sstevel@tonic-gate di_fini(root);
840*7c478bd9Sstevel@tonic-gate (void) mutex_unlock(&cache_lock);
841*7c478bd9Sstevel@tonic-gate free(links.ttymux_assocs);
842*7c478bd9Sstevel@tonic-gate return (0);
843*7c478bd9Sstevel@tonic-gate }
844*7c478bd9Sstevel@tonic-gate
845*7c478bd9Sstevel@tonic-gate /*
846*7c478bd9Sstevel@tonic-gate * A resource has become available. Re-establish any associations involving
847*7c478bd9Sstevel@tonic-gate * the resource.
848*7c478bd9Sstevel@tonic-gate */
849*7c478bd9Sstevel@tonic-gate static int
rsrc_available(rsrc_t * rsrc)850*7c478bd9Sstevel@tonic-gate rsrc_available(rsrc_t *rsrc)
851*7c478bd9Sstevel@tonic-gate {
852*7c478bd9Sstevel@tonic-gate link_t *link;
853*7c478bd9Sstevel@tonic-gate rsrc_t *rs;
854*7c478bd9Sstevel@tonic-gate
855*7c478bd9Sstevel@tonic-gate if (rsrc->dev == NODEV) {
856*7c478bd9Sstevel@tonic-gate /*
857*7c478bd9Sstevel@tonic-gate * Now that the resource is present obtain its device number.
858*7c478bd9Sstevel@tonic-gate * For this to work the node must be present in the /devices
859*7c478bd9Sstevel@tonic-gate * tree (see devfsadm(1M) or drvconfig(1M)).
860*7c478bd9Sstevel@tonic-gate * We do not use libdevinfo because the node must be present
861*7c478bd9Sstevel@tonic-gate * under /devices for the connect step below to work
862*7c478bd9Sstevel@tonic-gate * (the node needs to be opened).
863*7c478bd9Sstevel@tonic-gate */
864*7c478bd9Sstevel@tonic-gate (void) get_devpath(rsrc->id, NULL, &rsrc->dev);
865*7c478bd9Sstevel@tonic-gate if (rsrc->dev == NODEV) {
866*7c478bd9Sstevel@tonic-gate _msg(4,
867*7c478bd9Sstevel@tonic-gate ("Device node %s does not exist\n", rsrc->id));
868*7c478bd9Sstevel@tonic-gate /*
869*7c478bd9Sstevel@tonic-gate * What does RCM do with failed online notifications.
870*7c478bd9Sstevel@tonic-gate */
871*7c478bd9Sstevel@tonic-gate return (RCM_FAILURE);
872*7c478bd9Sstevel@tonic-gate }
873*7c478bd9Sstevel@tonic-gate }
874*7c478bd9Sstevel@tonic-gate for (rs = cache_head.next; rs != &cache_tail; rs = rs->next) {
875*7c478bd9Sstevel@tonic-gate for (link = rs->dependencies;
876*7c478bd9Sstevel@tonic-gate link != NULL;
877*7c478bd9Sstevel@tonic-gate link = link->next) {
878*7c478bd9Sstevel@tonic-gate if (link->user == rsrc || link->used == rsrc) {
879*7c478bd9Sstevel@tonic-gate _msg(6, ("TTYMUX: re-connect\n"));
880*7c478bd9Sstevel@tonic-gate (void) link->connect(link);
881*7c478bd9Sstevel@tonic-gate }
882*7c478bd9Sstevel@tonic-gate }
883*7c478bd9Sstevel@tonic-gate }
884*7c478bd9Sstevel@tonic-gate return (RCM_SUCCESS);
885*7c478bd9Sstevel@tonic-gate }
886*7c478bd9Sstevel@tonic-gate
887*7c478bd9Sstevel@tonic-gate /*
888*7c478bd9Sstevel@tonic-gate * A resource is going away. Tear down any associations involving
889*7c478bd9Sstevel@tonic-gate * the resource.
890*7c478bd9Sstevel@tonic-gate */
891*7c478bd9Sstevel@tonic-gate static int
rsrc_unavailable(rsrc_t * rsrc)892*7c478bd9Sstevel@tonic-gate rsrc_unavailable(rsrc_t *rsrc)
893*7c478bd9Sstevel@tonic-gate {
894*7c478bd9Sstevel@tonic-gate link_t *link;
895*7c478bd9Sstevel@tonic-gate rsrc_t *rs;
896*7c478bd9Sstevel@tonic-gate
897*7c478bd9Sstevel@tonic-gate for (rs = cache_head.next; rs != &cache_tail; rs = rs->next) {
898*7c478bd9Sstevel@tonic-gate for (link = rs->dependencies;
899*7c478bd9Sstevel@tonic-gate link != NULL;
900*7c478bd9Sstevel@tonic-gate link = link->next) {
901*7c478bd9Sstevel@tonic-gate if (link->user == rsrc || link->used == rsrc) {
902*7c478bd9Sstevel@tonic-gate _msg(6, ("TTYMUX: unavailable %s %s\n",
903*7c478bd9Sstevel@tonic-gate link->user->id, link->used->id));
904*7c478bd9Sstevel@tonic-gate (void) link->disconnect(link);
905*7c478bd9Sstevel@tonic-gate }
906*7c478bd9Sstevel@tonic-gate }
907*7c478bd9Sstevel@tonic-gate }
908*7c478bd9Sstevel@tonic-gate
909*7c478bd9Sstevel@tonic-gate return (RCM_SUCCESS);
910*7c478bd9Sstevel@tonic-gate }
911*7c478bd9Sstevel@tonic-gate
912*7c478bd9Sstevel@tonic-gate /*
913*7c478bd9Sstevel@tonic-gate * Find any resources that are using a given resource (identified by
914*7c478bd9Sstevel@tonic-gate * the rsrc argument). The search begins after the resource identified
915*7c478bd9Sstevel@tonic-gate * by the next argument. If next is NULL start at the first resource
916*7c478bd9Sstevel@tonic-gate * in this RCM modules resource list. If the redundancy argument is
917*7c478bd9Sstevel@tonic-gate * greater than zero then a resource which uses rsrc will only be
918*7c478bd9Sstevel@tonic-gate * returned if it is associated with >= redundancy dependents.
919*7c478bd9Sstevel@tonic-gate *
920*7c478bd9Sstevel@tonic-gate * Thus, provided that the caller keeps the list locked he can iterate
921*7c478bd9Sstevel@tonic-gate * through all the resources in the cache that depend upon rsrc.
922*7c478bd9Sstevel@tonic-gate */
923*7c478bd9Sstevel@tonic-gate static rsrc_t *
get_next_user(rsrc_t * next,rsrc_t * rsrc,int redundancy)924*7c478bd9Sstevel@tonic-gate get_next_user(rsrc_t *next, rsrc_t *rsrc, int redundancy)
925*7c478bd9Sstevel@tonic-gate {
926*7c478bd9Sstevel@tonic-gate rsrc_t *src;
927*7c478bd9Sstevel@tonic-gate link_t *link;
928*7c478bd9Sstevel@tonic-gate int cnt = 0;
929*7c478bd9Sstevel@tonic-gate boolean_t inuse;
930*7c478bd9Sstevel@tonic-gate
931*7c478bd9Sstevel@tonic-gate src = (next != NULL) ? next->next : cache_head.next;
932*7c478bd9Sstevel@tonic-gate
933*7c478bd9Sstevel@tonic-gate while (src != &cache_tail) {
934*7c478bd9Sstevel@tonic-gate inuse = B_FALSE;
935*7c478bd9Sstevel@tonic-gate
936*7c478bd9Sstevel@tonic-gate for (link = src->dependencies, cnt = 0;
937*7c478bd9Sstevel@tonic-gate link != NULL;
938*7c478bd9Sstevel@tonic-gate link = link->next) {
939*7c478bd9Sstevel@tonic-gate
940*7c478bd9Sstevel@tonic-gate if (link->state == CONNECTED)
941*7c478bd9Sstevel@tonic-gate cnt++;
942*7c478bd9Sstevel@tonic-gate
943*7c478bd9Sstevel@tonic-gate if (link->used == rsrc)
944*7c478bd9Sstevel@tonic-gate inuse = B_TRUE;
945*7c478bd9Sstevel@tonic-gate }
946*7c478bd9Sstevel@tonic-gate if (inuse == B_TRUE &&
947*7c478bd9Sstevel@tonic-gate (redundancy <= 0 || cnt == redundancy)) {
948*7c478bd9Sstevel@tonic-gate return (src);
949*7c478bd9Sstevel@tonic-gate }
950*7c478bd9Sstevel@tonic-gate
951*7c478bd9Sstevel@tonic-gate src = src->next;
952*7c478bd9Sstevel@tonic-gate }
953*7c478bd9Sstevel@tonic-gate
954*7c478bd9Sstevel@tonic-gate _msg(8, ("TTYMUX: count_users(%s) res %d.\n", rsrc->id, cnt));
955*7c478bd9Sstevel@tonic-gate return (NULL);
956*7c478bd9Sstevel@tonic-gate }
957*7c478bd9Sstevel@tonic-gate
958*7c478bd9Sstevel@tonic-gate /*
959*7c478bd9Sstevel@tonic-gate * Common handler for RCM notifications.
960*7c478bd9Sstevel@tonic-gate */
961*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
962*7c478bd9Sstevel@tonic-gate static int
rsrc_change_common(rcm_handle_t * hd,int op,const char * rsrcid,uint_t flag,char ** reason,rcm_info_t ** dependent_reason,void * arg)963*7c478bd9Sstevel@tonic-gate rsrc_change_common(rcm_handle_t *hd, int op, const char *rsrcid, uint_t flag,
964*7c478bd9Sstevel@tonic-gate char **reason, rcm_info_t **dependent_reason, void *arg)
965*7c478bd9Sstevel@tonic-gate {
966*7c478bd9Sstevel@tonic-gate rsrc_t *rsrc, *user;
967*7c478bd9Sstevel@tonic-gate int rv, len;
968*7c478bd9Sstevel@tonic-gate char *tmp = NULL;
969*7c478bd9Sstevel@tonic-gate
970*7c478bd9Sstevel@tonic-gate (void) mutex_lock(&cache_lock);
971*7c478bd9Sstevel@tonic-gate rsrc = cache_lookup(rsrcid);
972*7c478bd9Sstevel@tonic-gate if (rsrc == NULL) {
973*7c478bd9Sstevel@tonic-gate /* shouldn't happen because rsrc has been registered */
974*7c478bd9Sstevel@tonic-gate (void) mutex_unlock(&cache_lock);
975*7c478bd9Sstevel@tonic-gate return (RCM_SUCCESS);
976*7c478bd9Sstevel@tonic-gate }
977*7c478bd9Sstevel@tonic-gate if ((muxfd = open_file(muxctl, oflags)) == -1) {
978*7c478bd9Sstevel@tonic-gate rcm_log_message(RCM_ERROR, _("TTYMUX: %s unavailable: %s\n"),
979*7c478bd9Sstevel@tonic-gate muxctl, strerror(errno));
980*7c478bd9Sstevel@tonic-gate (void) mutex_unlock(&cache_lock);
981*7c478bd9Sstevel@tonic-gate return (RCM_SUCCESS);
982*7c478bd9Sstevel@tonic-gate }
983*7c478bd9Sstevel@tonic-gate switch (op) {
984*7c478bd9Sstevel@tonic-gate
985*7c478bd9Sstevel@tonic-gate case TTYMUX_SUSPEND:
986*7c478bd9Sstevel@tonic-gate rv = RCM_FAILURE;
987*7c478bd9Sstevel@tonic-gate _msg(4, ("TTYMUX: SUSPEND %s operation refused.\n",
988*7c478bd9Sstevel@tonic-gate rsrc->id));
989*7c478bd9Sstevel@tonic-gate if ((*reason = strdup(TTYMUX_INVALID_ERR)) == NULL) {
990*7c478bd9Sstevel@tonic-gate rcm_log_message(RCM_ERROR, TTYMUX_MEMORY_ERR);
991*7c478bd9Sstevel@tonic-gate }
992*7c478bd9Sstevel@tonic-gate break;
993*7c478bd9Sstevel@tonic-gate
994*7c478bd9Sstevel@tonic-gate case TTYMUX_REMOVE:
995*7c478bd9Sstevel@tonic-gate rsrc->flags |= UNKNOWN;
996*7c478bd9Sstevel@tonic-gate rsrc->flags &= ~(PRESENT | REGISTERED);
997*7c478bd9Sstevel@tonic-gate rv = RCM_SUCCESS;
998*7c478bd9Sstevel@tonic-gate break;
999*7c478bd9Sstevel@tonic-gate
1000*7c478bd9Sstevel@tonic-gate case TTYMUX_OFFLINE:
1001*7c478bd9Sstevel@tonic-gate user = get_next_user(NULL, rsrc, 1);
1002*7c478bd9Sstevel@tonic-gate if (flag & RCM_QUERY) {
1003*7c478bd9Sstevel@tonic-gate rv = ((flag & RCM_FORCE) || (user == NULL)) ?
1004*7c478bd9Sstevel@tonic-gate RCM_SUCCESS : RCM_FAILURE;
1005*7c478bd9Sstevel@tonic-gate if (rv == RCM_FAILURE) {
1006*7c478bd9Sstevel@tonic-gate tmp = TTYMUX_OFFLINE_ERR;
1007*7c478bd9Sstevel@tonic-gate assert(tmp != NULL);
1008*7c478bd9Sstevel@tonic-gate len = strlen(tmp) + strlen(user->id) + 2;
1009*7c478bd9Sstevel@tonic-gate if ((*reason = (char *)malloc(len)) != NULL) {
1010*7c478bd9Sstevel@tonic-gate (void) snprintf(*reason, len,
1011*7c478bd9Sstevel@tonic-gate "%s %s", tmp, user->id);
1012*7c478bd9Sstevel@tonic-gate } else {
1013*7c478bd9Sstevel@tonic-gate rcm_log_message(RCM_ERROR, TTYMUX_MEMORY_ERR);
1014*7c478bd9Sstevel@tonic-gate }
1015*7c478bd9Sstevel@tonic-gate }
1016*7c478bd9Sstevel@tonic-gate
1017*7c478bd9Sstevel@tonic-gate } else if (flag & RCM_FORCE) {
1018*7c478bd9Sstevel@tonic-gate rv = rsrc_unavailable(rsrc);
1019*7c478bd9Sstevel@tonic-gate
1020*7c478bd9Sstevel@tonic-gate if (rv == RCM_FAILURE) {
1021*7c478bd9Sstevel@tonic-gate if ((*reason = strdup(TTYMUX_OFFLINE_FAIL)) ==
1022*7c478bd9Sstevel@tonic-gate NULL) {
1023*7c478bd9Sstevel@tonic-gate rcm_log_message(RCM_ERROR,
1024*7c478bd9Sstevel@tonic-gate TTYMUX_MEMORY_ERR);
1025*7c478bd9Sstevel@tonic-gate }
1026*7c478bd9Sstevel@tonic-gate }
1027*7c478bd9Sstevel@tonic-gate
1028*7c478bd9Sstevel@tonic-gate } else if (user != NULL) {
1029*7c478bd9Sstevel@tonic-gate rv = RCM_FAILURE;
1030*7c478bd9Sstevel@tonic-gate tmp = TTYMUX_OFFLINE_ERR;
1031*7c478bd9Sstevel@tonic-gate assert(tmp != NULL);
1032*7c478bd9Sstevel@tonic-gate len = strlen(tmp) + strlen(user->id) + 2;
1033*7c478bd9Sstevel@tonic-gate if ((*reason = (char *)malloc(len)) != NULL) {
1034*7c478bd9Sstevel@tonic-gate (void) snprintf(*reason, len,
1035*7c478bd9Sstevel@tonic-gate "%s %s", tmp, user->id);
1036*7c478bd9Sstevel@tonic-gate } else {
1037*7c478bd9Sstevel@tonic-gate rcm_log_message(RCM_ERROR, TTYMUX_MEMORY_ERR);
1038*7c478bd9Sstevel@tonic-gate }
1039*7c478bd9Sstevel@tonic-gate
1040*7c478bd9Sstevel@tonic-gate } else {
1041*7c478bd9Sstevel@tonic-gate rv = rsrc_unavailable(rsrc);
1042*7c478bd9Sstevel@tonic-gate if (rv == RCM_FAILURE) {
1043*7c478bd9Sstevel@tonic-gate if ((*reason = strdup(TTYMUX_OFFLINE_FAIL)) ==
1044*7c478bd9Sstevel@tonic-gate NULL) {
1045*7c478bd9Sstevel@tonic-gate rcm_log_message(RCM_ERROR,
1046*7c478bd9Sstevel@tonic-gate TTYMUX_MEMORY_ERR);
1047*7c478bd9Sstevel@tonic-gate }
1048*7c478bd9Sstevel@tonic-gate }
1049*7c478bd9Sstevel@tonic-gate }
1050*7c478bd9Sstevel@tonic-gate
1051*7c478bd9Sstevel@tonic-gate if (rv == RCM_FAILURE) {
1052*7c478bd9Sstevel@tonic-gate _msg(4, ("TTYMUX: OFFLINE %s operation refused.\n",
1053*7c478bd9Sstevel@tonic-gate rsrc->id));
1054*7c478bd9Sstevel@tonic-gate
1055*7c478bd9Sstevel@tonic-gate } else {
1056*7c478bd9Sstevel@tonic-gate _msg(4, ("TTYMUX: OFFLINE %s res %d.\n", rsrc->id, rv));
1057*7c478bd9Sstevel@tonic-gate }
1058*7c478bd9Sstevel@tonic-gate break;
1059*7c478bd9Sstevel@tonic-gate
1060*7c478bd9Sstevel@tonic-gate case TTYMUX_RESUME:
1061*7c478bd9Sstevel@tonic-gate rv = RCM_FAILURE;
1062*7c478bd9Sstevel@tonic-gate _msg(4, ("TTYMUX: RESUME %s operation refused.\n",
1063*7c478bd9Sstevel@tonic-gate rsrc->id));
1064*7c478bd9Sstevel@tonic-gate if ((*reason = strdup(TTYMUX_INVALID_ERR)) == NULL) {
1065*7c478bd9Sstevel@tonic-gate rcm_log_message(RCM_ERROR, TTYMUX_MEMORY_ERR);
1066*7c478bd9Sstevel@tonic-gate }
1067*7c478bd9Sstevel@tonic-gate break;
1068*7c478bd9Sstevel@tonic-gate
1069*7c478bd9Sstevel@tonic-gate case TTYMUX_ONLINE:
1070*7c478bd9Sstevel@tonic-gate _msg(4, ("TTYMUX: ONLINE %s res %d.\n", rsrc->id, rv));
1071*7c478bd9Sstevel@tonic-gate rv = rsrc_available(rsrc);
1072*7c478bd9Sstevel@tonic-gate if (rv == RCM_FAILURE) {
1073*7c478bd9Sstevel@tonic-gate if ((*reason = strdup(TTYMUX_ONLINE_ERR)) == NULL) {
1074*7c478bd9Sstevel@tonic-gate rcm_log_message(RCM_ERROR, TTYMUX_MEMORY_ERR);
1075*7c478bd9Sstevel@tonic-gate }
1076*7c478bd9Sstevel@tonic-gate }
1077*7c478bd9Sstevel@tonic-gate break;
1078*7c478bd9Sstevel@tonic-gate default:
1079*7c478bd9Sstevel@tonic-gate rv = RCM_FAILURE;
1080*7c478bd9Sstevel@tonic-gate if ((*reason = strdup(TTYMUX_UNKNOWN_ERR)) == NULL) {
1081*7c478bd9Sstevel@tonic-gate rcm_log_message(RCM_ERROR, TTYMUX_MEMORY_ERR);
1082*7c478bd9Sstevel@tonic-gate }
1083*7c478bd9Sstevel@tonic-gate }
1084*7c478bd9Sstevel@tonic-gate
1085*7c478bd9Sstevel@tonic-gate (void) close(muxfd);
1086*7c478bd9Sstevel@tonic-gate (void) mutex_unlock(&cache_lock);
1087*7c478bd9Sstevel@tonic-gate return (rv);
1088*7c478bd9Sstevel@tonic-gate }
1089*7c478bd9Sstevel@tonic-gate
1090*7c478bd9Sstevel@tonic-gate static boolean_t
find_mux_nodes(char * drv)1091*7c478bd9Sstevel@tonic-gate find_mux_nodes(char *drv)
1092*7c478bd9Sstevel@tonic-gate {
1093*7c478bd9Sstevel@tonic-gate di_node_t root, node;
1094*7c478bd9Sstevel@tonic-gate di_minor_t dim;
1095*7c478bd9Sstevel@tonic-gate char *devfspath;
1096*7c478bd9Sstevel@tonic-gate char muxctlname[] = "ctl";
1097*7c478bd9Sstevel@tonic-gate char muxconname[] = "con";
1098*7c478bd9Sstevel@tonic-gate int nminors = 0;
1099*7c478bd9Sstevel@tonic-gate
1100*7c478bd9Sstevel@tonic-gate (void) strcpy(muxctl, MUXCTLLINK);
1101*7c478bd9Sstevel@tonic-gate (void) strcpy(muxcon, MUXCONLINK);
1102*7c478bd9Sstevel@tonic-gate cn_rsrc = NULL;
1103*7c478bd9Sstevel@tonic-gate
1104*7c478bd9Sstevel@tonic-gate if ((root = di_init("/", DINFOCPYALL)) == DI_NODE_NIL) {
1105*7c478bd9Sstevel@tonic-gate rcm_log_message(RCM_WARNING, _("di_init error\n"));
1106*7c478bd9Sstevel@tonic-gate return (B_FALSE);
1107*7c478bd9Sstevel@tonic-gate }
1108*7c478bd9Sstevel@tonic-gate
1109*7c478bd9Sstevel@tonic-gate node = di_drv_first_node(drv, root);
1110*7c478bd9Sstevel@tonic-gate if (node == DI_NODE_NIL) {
1111*7c478bd9Sstevel@tonic-gate _msg(4, ("no node for %s\n", drv));
1112*7c478bd9Sstevel@tonic-gate di_fini(root);
1113*7c478bd9Sstevel@tonic-gate return (B_FALSE);
1114*7c478bd9Sstevel@tonic-gate }
1115*7c478bd9Sstevel@tonic-gate /*
1116*7c478bd9Sstevel@tonic-gate * If the device is not a prom node do not continue.
1117*7c478bd9Sstevel@tonic-gate */
1118*7c478bd9Sstevel@tonic-gate if (di_nodeid(node) != DI_PROM_NODEID) {
1119*7c478bd9Sstevel@tonic-gate di_fini(root);
1120*7c478bd9Sstevel@tonic-gate return (B_FALSE);
1121*7c478bd9Sstevel@tonic-gate }
1122*7c478bd9Sstevel@tonic-gate if ((devfspath = di_devfs_path(node)) == NULL) {
1123*7c478bd9Sstevel@tonic-gate di_fini(root);
1124*7c478bd9Sstevel@tonic-gate return (B_FALSE);
1125*7c478bd9Sstevel@tonic-gate }
1126*7c478bd9Sstevel@tonic-gate
1127*7c478bd9Sstevel@tonic-gate /*
1128*7c478bd9Sstevel@tonic-gate * Loop through all the minor nodes the driver (drv) looking
1129*7c478bd9Sstevel@tonic-gate * for the ctl node (this is the device on which
1130*7c478bd9Sstevel@tonic-gate * to issue ioctls).
1131*7c478bd9Sstevel@tonic-gate */
1132*7c478bd9Sstevel@tonic-gate dim = DI_MINOR_NIL;
1133*7c478bd9Sstevel@tonic-gate while ((dim = di_minor_next(node, dim)) != DI_MINOR_NIL) {
1134*7c478bd9Sstevel@tonic-gate
1135*7c478bd9Sstevel@tonic-gate _msg(7, ("MUXNODES: minor %s\n", di_minor_name(dim)));
1136*7c478bd9Sstevel@tonic-gate
1137*7c478bd9Sstevel@tonic-gate if (strcmp(di_minor_name(dim), muxctlname) == 0) {
1138*7c478bd9Sstevel@tonic-gate if (snprintf(muxctl, sizeof (muxctl),
1139*7c478bd9Sstevel@tonic-gate "/devices%s:%s", devfspath,
1140*7c478bd9Sstevel@tonic-gate di_minor_name(dim)) > sizeof (muxctl)) {
1141*7c478bd9Sstevel@tonic-gate _msg(1, ("muxctl:snprintf error\n"));
1142*7c478bd9Sstevel@tonic-gate }
1143*7c478bd9Sstevel@tonic-gate if (++nminors == 2)
1144*7c478bd9Sstevel@tonic-gate break;
1145*7c478bd9Sstevel@tonic-gate } else if (strcmp(di_minor_name(dim), muxconname) == 0) {
1146*7c478bd9Sstevel@tonic-gate if (snprintf(muxcon, sizeof (muxcon),
1147*7c478bd9Sstevel@tonic-gate "/devices%s:%s", devfspath,
1148*7c478bd9Sstevel@tonic-gate di_minor_name(dim)) > sizeof (muxcon)) {
1149*7c478bd9Sstevel@tonic-gate _msg(1, ("muxcon:snprintf error\n"));
1150*7c478bd9Sstevel@tonic-gate }
1151*7c478bd9Sstevel@tonic-gate if (++nminors == 2)
1152*7c478bd9Sstevel@tonic-gate break;
1153*7c478bd9Sstevel@tonic-gate }
1154*7c478bd9Sstevel@tonic-gate }
1155*7c478bd9Sstevel@tonic-gate
1156*7c478bd9Sstevel@tonic-gate di_devfs_path_free(devfspath);
1157*7c478bd9Sstevel@tonic-gate di_fini(root);
1158*7c478bd9Sstevel@tonic-gate
1159*7c478bd9Sstevel@tonic-gate if ((muxfd = open_file(muxctl, oflags)) != -1) {
1160*7c478bd9Sstevel@tonic-gate
1161*7c478bd9Sstevel@tonic-gate if (istrioctl(muxfd, TTYMUX_CONSDEV, (void *)&cn_dev,
1162*7c478bd9Sstevel@tonic-gate sizeof (cn_dev), 0) != 0) {
1163*7c478bd9Sstevel@tonic-gate cn_dev = NODEV;
1164*7c478bd9Sstevel@tonic-gate } else {
1165*7c478bd9Sstevel@tonic-gate _msg(8, ("MUXNODES: found sys console: %ld:%ld\n",
1166*7c478bd9Sstevel@tonic-gate major(cn_dev), minor(cn_dev)));
1167*7c478bd9Sstevel@tonic-gate
1168*7c478bd9Sstevel@tonic-gate cn_rsrc = cache_create(muxcon, cn_dev);
1169*7c478bd9Sstevel@tonic-gate if (cn_rsrc != NULL) {
1170*7c478bd9Sstevel@tonic-gate cn_rsrc->flags |= PRESENT;
1171*7c478bd9Sstevel@tonic-gate cn_rsrc->flags &= ~UNKNOWN;
1172*7c478bd9Sstevel@tonic-gate }
1173*7c478bd9Sstevel@tonic-gate }
1174*7c478bd9Sstevel@tonic-gate (void) close(muxfd);
1175*7c478bd9Sstevel@tonic-gate
1176*7c478bd9Sstevel@tonic-gate if (cn_dev != NODEV)
1177*7c478bd9Sstevel@tonic-gate return (B_TRUE);
1178*7c478bd9Sstevel@tonic-gate } else {
1179*7c478bd9Sstevel@tonic-gate _msg(1, ("TTYMUX: %s unavailable: %s\n",
1180*7c478bd9Sstevel@tonic-gate muxctl, strerror(errno)));
1181*7c478bd9Sstevel@tonic-gate }
1182*7c478bd9Sstevel@tonic-gate
1183*7c478bd9Sstevel@tonic-gate return (B_FALSE);
1184*7c478bd9Sstevel@tonic-gate }
1185*7c478bd9Sstevel@tonic-gate
1186*7c478bd9Sstevel@tonic-gate /*
1187*7c478bd9Sstevel@tonic-gate * Update registrations, and return the ops structure.
1188*7c478bd9Sstevel@tonic-gate */
1189*7c478bd9Sstevel@tonic-gate struct rcm_mod_ops *
rcm_mod_init()1190*7c478bd9Sstevel@tonic-gate rcm_mod_init()
1191*7c478bd9Sstevel@tonic-gate {
1192*7c478bd9Sstevel@tonic-gate _msg(4, ("TTYMUX: mod_init:\n"));
1193*7c478bd9Sstevel@tonic-gate cache_head.next = &cache_tail;
1194*7c478bd9Sstevel@tonic-gate cache_head.prev = NULL;
1195*7c478bd9Sstevel@tonic-gate cache_tail.prev = &cache_head;
1196*7c478bd9Sstevel@tonic-gate cache_tail.next = NULL;
1197*7c478bd9Sstevel@tonic-gate (void) mutex_init(&cache_lock, NULL, NULL);
1198*7c478bd9Sstevel@tonic-gate
1199*7c478bd9Sstevel@tonic-gate /*
1200*7c478bd9Sstevel@tonic-gate * Find the multiplexer ctl and con nodes
1201*7c478bd9Sstevel@tonic-gate */
1202*7c478bd9Sstevel@tonic-gate register_rsrcs = find_mux_nodes(TTYMUX_DRVNAME);
1203*7c478bd9Sstevel@tonic-gate
1204*7c478bd9Sstevel@tonic-gate return (&tty_ops);
1205*7c478bd9Sstevel@tonic-gate }
1206*7c478bd9Sstevel@tonic-gate
1207*7c478bd9Sstevel@tonic-gate /*
1208*7c478bd9Sstevel@tonic-gate * Save state and release resources.
1209*7c478bd9Sstevel@tonic-gate */
1210*7c478bd9Sstevel@tonic-gate int
rcm_mod_fini()1211*7c478bd9Sstevel@tonic-gate rcm_mod_fini()
1212*7c478bd9Sstevel@tonic-gate {
1213*7c478bd9Sstevel@tonic-gate rsrc_t *rsrc;
1214*7c478bd9Sstevel@tonic-gate link_t *link, *nlink;
1215*7c478bd9Sstevel@tonic-gate
1216*7c478bd9Sstevel@tonic-gate _msg(7, ("TTYMUX: freeing cache.\n"));
1217*7c478bd9Sstevel@tonic-gate (void) mutex_lock(&cache_lock);
1218*7c478bd9Sstevel@tonic-gate rsrc = cache_head.next;
1219*7c478bd9Sstevel@tonic-gate while (rsrc != &cache_tail) {
1220*7c478bd9Sstevel@tonic-gate cache_remove(rsrc);
1221*7c478bd9Sstevel@tonic-gate
1222*7c478bd9Sstevel@tonic-gate for (link = rsrc->dependencies; link != NULL; ) {
1223*7c478bd9Sstevel@tonic-gate nlink = link->next;
1224*7c478bd9Sstevel@tonic-gate free(link);
1225*7c478bd9Sstevel@tonic-gate link = nlink;
1226*7c478bd9Sstevel@tonic-gate }
1227*7c478bd9Sstevel@tonic-gate
1228*7c478bd9Sstevel@tonic-gate free_node(rsrc);
1229*7c478bd9Sstevel@tonic-gate rsrc = cache_head.next;
1230*7c478bd9Sstevel@tonic-gate }
1231*7c478bd9Sstevel@tonic-gate (void) mutex_unlock(&cache_lock);
1232*7c478bd9Sstevel@tonic-gate
1233*7c478bd9Sstevel@tonic-gate (void) mutex_destroy(&cache_lock);
1234*7c478bd9Sstevel@tonic-gate return (RCM_SUCCESS);
1235*7c478bd9Sstevel@tonic-gate }
1236*7c478bd9Sstevel@tonic-gate
1237*7c478bd9Sstevel@tonic-gate /*
1238*7c478bd9Sstevel@tonic-gate * Return a string describing this module.
1239*7c478bd9Sstevel@tonic-gate */
1240*7c478bd9Sstevel@tonic-gate const char *
rcm_mod_info()1241*7c478bd9Sstevel@tonic-gate rcm_mod_info()
1242*7c478bd9Sstevel@tonic-gate {
1243*7c478bd9Sstevel@tonic-gate return ("Serial mux device module 1.1");
1244*7c478bd9Sstevel@tonic-gate }
1245*7c478bd9Sstevel@tonic-gate
1246*7c478bd9Sstevel@tonic-gate /*
1247*7c478bd9Sstevel@tonic-gate * RCM Notification Handlers
1248*7c478bd9Sstevel@tonic-gate */
1249*7c478bd9Sstevel@tonic-gate
1250*7c478bd9Sstevel@tonic-gate static int
tty_register(rcm_handle_t * hd)1251*7c478bd9Sstevel@tonic-gate tty_register(rcm_handle_t *hd)
1252*7c478bd9Sstevel@tonic-gate {
1253*7c478bd9Sstevel@tonic-gate rsrc_t *rsrc;
1254*7c478bd9Sstevel@tonic-gate link_t *link;
1255*7c478bd9Sstevel@tonic-gate int rv;
1256*7c478bd9Sstevel@tonic-gate
1257*7c478bd9Sstevel@tonic-gate if (register_rsrcs == B_FALSE)
1258*7c478bd9Sstevel@tonic-gate return (RCM_SUCCESS);
1259*7c478bd9Sstevel@tonic-gate
1260*7c478bd9Sstevel@tonic-gate if ((muxfd = open_file(muxctl, oflags)) == -1) {
1261*7c478bd9Sstevel@tonic-gate rcm_log_message(RCM_ERROR, _("TTYMUX: %s unavailable: %s\n"),
1262*7c478bd9Sstevel@tonic-gate muxctl, strerror(errno));
1263*7c478bd9Sstevel@tonic-gate return (RCM_SUCCESS);
1264*7c478bd9Sstevel@tonic-gate }
1265*7c478bd9Sstevel@tonic-gate /*
1266*7c478bd9Sstevel@tonic-gate * Search for any new dependencies since the last notification or
1267*7c478bd9Sstevel@tonic-gate * since module was initialisated.
1268*7c478bd9Sstevel@tonic-gate */
1269*7c478bd9Sstevel@tonic-gate (void) probe_dependencies();
1270*7c478bd9Sstevel@tonic-gate
1271*7c478bd9Sstevel@tonic-gate /*
1272*7c478bd9Sstevel@tonic-gate * Search the whole cache looking for any unregistered used resources
1273*7c478bd9Sstevel@tonic-gate * and register them. Note that the 'using resource' (a ttymux device
1274*7c478bd9Sstevel@tonic-gate * node) is not subject to DR operations so there is no need to
1275*7c478bd9Sstevel@tonic-gate * register them with the RCM framework.
1276*7c478bd9Sstevel@tonic-gate */
1277*7c478bd9Sstevel@tonic-gate (void) mutex_lock(&cache_lock);
1278*7c478bd9Sstevel@tonic-gate for (rsrc = cache_head.next; rsrc != &cache_tail; rsrc = rsrc->next) {
1279*7c478bd9Sstevel@tonic-gate _msg(6, ("TTYMUX: REGISTER rsrc %s flags %d\n",
1280*7c478bd9Sstevel@tonic-gate rsrc->id, rsrc->flags));
1281*7c478bd9Sstevel@tonic-gate
1282*7c478bd9Sstevel@tonic-gate if (rsrc->dependencies != NULL &&
1283*7c478bd9Sstevel@tonic-gate (rsrc->flags & REGISTERED) == 0) {
1284*7c478bd9Sstevel@tonic-gate _msg(6, ("TTYMUX: Registering rsrc %s\n", rsrc->id));
1285*7c478bd9Sstevel@tonic-gate rv = rcm_register_interest(hd, rsrc->id, 0, NULL);
1286*7c478bd9Sstevel@tonic-gate if (rv == RCM_SUCCESS)
1287*7c478bd9Sstevel@tonic-gate rsrc->flags |= REGISTERED;
1288*7c478bd9Sstevel@tonic-gate }
1289*7c478bd9Sstevel@tonic-gate
1290*7c478bd9Sstevel@tonic-gate for (link = rsrc->dependencies; link != NULL;
1291*7c478bd9Sstevel@tonic-gate link = link->next) {
1292*7c478bd9Sstevel@tonic-gate if ((link->used->flags & REGISTERED) != 0)
1293*7c478bd9Sstevel@tonic-gate continue;
1294*7c478bd9Sstevel@tonic-gate
1295*7c478bd9Sstevel@tonic-gate _msg(6, ("TTYMUX: Registering rsrc %s\n",
1296*7c478bd9Sstevel@tonic-gate link->used->id));
1297*7c478bd9Sstevel@tonic-gate rv = rcm_register_interest(hd, link->used->id,
1298*7c478bd9Sstevel@tonic-gate 0, NULL);
1299*7c478bd9Sstevel@tonic-gate if (rv != RCM_SUCCESS)
1300*7c478bd9Sstevel@tonic-gate rcm_log_message(RCM_WARNING,
1301*7c478bd9Sstevel@tonic-gate _("TTYMUX: err %d registering %s\n"),
1302*7c478bd9Sstevel@tonic-gate rv, link->used->id);
1303*7c478bd9Sstevel@tonic-gate else
1304*7c478bd9Sstevel@tonic-gate link->used->flags |= REGISTERED;
1305*7c478bd9Sstevel@tonic-gate }
1306*7c478bd9Sstevel@tonic-gate }
1307*7c478bd9Sstevel@tonic-gate
1308*7c478bd9Sstevel@tonic-gate (void) mutex_unlock(&cache_lock);
1309*7c478bd9Sstevel@tonic-gate (void) close(muxfd);
1310*7c478bd9Sstevel@tonic-gate return (RCM_SUCCESS);
1311*7c478bd9Sstevel@tonic-gate }
1312*7c478bd9Sstevel@tonic-gate
1313*7c478bd9Sstevel@tonic-gate /*
1314*7c478bd9Sstevel@tonic-gate * Unregister all registrations.
1315*7c478bd9Sstevel@tonic-gate */
1316*7c478bd9Sstevel@tonic-gate static int
tty_unregister(rcm_handle_t * hd)1317*7c478bd9Sstevel@tonic-gate tty_unregister(rcm_handle_t *hd)
1318*7c478bd9Sstevel@tonic-gate {
1319*7c478bd9Sstevel@tonic-gate rsrc_t *rsrc;
1320*7c478bd9Sstevel@tonic-gate
1321*7c478bd9Sstevel@tonic-gate (void) mutex_lock(&cache_lock);
1322*7c478bd9Sstevel@tonic-gate /*
1323*7c478bd9Sstevel@tonic-gate * Search every resource in the cache and if it has been registered
1324*7c478bd9Sstevel@tonic-gate * then unregister it from the RCM framework.
1325*7c478bd9Sstevel@tonic-gate */
1326*7c478bd9Sstevel@tonic-gate for (rsrc = cache_head.next; rsrc != &cache_tail; rsrc = rsrc->next) {
1327*7c478bd9Sstevel@tonic-gate if ((rsrc->flags & REGISTERED) == 0)
1328*7c478bd9Sstevel@tonic-gate continue;
1329*7c478bd9Sstevel@tonic-gate
1330*7c478bd9Sstevel@tonic-gate if (rcm_unregister_interest(hd, rsrc->id, 0) != RCM_SUCCESS)
1331*7c478bd9Sstevel@tonic-gate rcm_log_message(RCM_WARNING,
1332*7c478bd9Sstevel@tonic-gate _("TTYMUX: Failed to unregister %s\n"), rsrc->id);
1333*7c478bd9Sstevel@tonic-gate else
1334*7c478bd9Sstevel@tonic-gate rsrc->flags &= ~REGISTERED;
1335*7c478bd9Sstevel@tonic-gate }
1336*7c478bd9Sstevel@tonic-gate (void) mutex_unlock(&cache_lock);
1337*7c478bd9Sstevel@tonic-gate return (RCM_SUCCESS);
1338*7c478bd9Sstevel@tonic-gate }
1339*7c478bd9Sstevel@tonic-gate
1340*7c478bd9Sstevel@tonic-gate /*
1341*7c478bd9Sstevel@tonic-gate * Report resource usage information.
1342*7c478bd9Sstevel@tonic-gate */
1343*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
1344*7c478bd9Sstevel@tonic-gate static int
tty_getinfo(rcm_handle_t * hd,char * rsrcid,id_t id,uint_t flag,char ** info,char ** errstr,nvlist_t * proplist,rcm_info_t ** depend_info)1345*7c478bd9Sstevel@tonic-gate tty_getinfo(rcm_handle_t *hd, char *rsrcid, id_t id, uint_t flag, char **info,
1346*7c478bd9Sstevel@tonic-gate char **errstr, nvlist_t *proplist, rcm_info_t **depend_info)
1347*7c478bd9Sstevel@tonic-gate {
1348*7c478bd9Sstevel@tonic-gate rsrc_t *rsrc, *user;
1349*7c478bd9Sstevel@tonic-gate char *ru;
1350*7c478bd9Sstevel@tonic-gate size_t sz;
1351*7c478bd9Sstevel@tonic-gate
1352*7c478bd9Sstevel@tonic-gate (void) mutex_lock(&cache_lock);
1353*7c478bd9Sstevel@tonic-gate rsrc = cache_lookup(rsrcid);
1354*7c478bd9Sstevel@tonic-gate
1355*7c478bd9Sstevel@tonic-gate if (rsrc == NULL) {
1356*7c478bd9Sstevel@tonic-gate (void) mutex_unlock(&cache_lock);
1357*7c478bd9Sstevel@tonic-gate *errstr = strdup(gettext("Unmanaged resource"));
1358*7c478bd9Sstevel@tonic-gate return (RCM_FAILURE);
1359*7c478bd9Sstevel@tonic-gate }
1360*7c478bd9Sstevel@tonic-gate
1361*7c478bd9Sstevel@tonic-gate ru = strdup(gettext("Resource Users"));
1362*7c478bd9Sstevel@tonic-gate user = NULL;
1363*7c478bd9Sstevel@tonic-gate while ((user = get_next_user(user, rsrc, -1)) != NULL) {
1364*7c478bd9Sstevel@tonic-gate *info = ru;
1365*7c478bd9Sstevel@tonic-gate sz = strlen(*info) + strlen(user->id) + 2;
1366*7c478bd9Sstevel@tonic-gate ru = malloc(sz);
1367*7c478bd9Sstevel@tonic-gate if (ru == NULL) {
1368*7c478bd9Sstevel@tonic-gate free(*info);
1369*7c478bd9Sstevel@tonic-gate *info = NULL;
1370*7c478bd9Sstevel@tonic-gate break;
1371*7c478bd9Sstevel@tonic-gate }
1372*7c478bd9Sstevel@tonic-gate if (snprintf(ru, sz, ": %s%s", *info, user->id) > sz) {
1373*7c478bd9Sstevel@tonic-gate _msg(4, ("tty_getinfo: snprintf error.\n"));
1374*7c478bd9Sstevel@tonic-gate }
1375*7c478bd9Sstevel@tonic-gate
1376*7c478bd9Sstevel@tonic-gate free(*info);
1377*7c478bd9Sstevel@tonic-gate }
1378*7c478bd9Sstevel@tonic-gate *info = ru;
1379*7c478bd9Sstevel@tonic-gate
1380*7c478bd9Sstevel@tonic-gate if (*info == NULL) {
1381*7c478bd9Sstevel@tonic-gate (void) mutex_unlock(&cache_lock);
1382*7c478bd9Sstevel@tonic-gate *errstr = strdup(gettext("Short of memory resources"));
1383*7c478bd9Sstevel@tonic-gate return (RCM_FAILURE);
1384*7c478bd9Sstevel@tonic-gate }
1385*7c478bd9Sstevel@tonic-gate
1386*7c478bd9Sstevel@tonic-gate (void) mutex_unlock(&cache_lock);
1387*7c478bd9Sstevel@tonic-gate return (RCM_SUCCESS);
1388*7c478bd9Sstevel@tonic-gate }
1389*7c478bd9Sstevel@tonic-gate
1390*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
1391*7c478bd9Sstevel@tonic-gate static int
tty_offline(rcm_handle_t * hd,char * rsrc,id_t id,uint_t flags,char ** reason,rcm_info_t ** dependent_reason)1392*7c478bd9Sstevel@tonic-gate tty_offline(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
1393*7c478bd9Sstevel@tonic-gate char **reason, rcm_info_t **dependent_reason)
1394*7c478bd9Sstevel@tonic-gate {
1395*7c478bd9Sstevel@tonic-gate return (rsrc_change_common(hd, TTYMUX_OFFLINE, rsrc, flags,
1396*7c478bd9Sstevel@tonic-gate reason, dependent_reason, NULL));
1397*7c478bd9Sstevel@tonic-gate }
1398*7c478bd9Sstevel@tonic-gate
1399*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
1400*7c478bd9Sstevel@tonic-gate static int
tty_remove(rcm_handle_t * hd,char * rsrc,id_t id,uint_t flags,char ** reason,rcm_info_t ** dependent_reason)1401*7c478bd9Sstevel@tonic-gate tty_remove(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
1402*7c478bd9Sstevel@tonic-gate char **reason, rcm_info_t **dependent_reason)
1403*7c478bd9Sstevel@tonic-gate {
1404*7c478bd9Sstevel@tonic-gate return (rsrc_change_common(hd, TTYMUX_REMOVE, rsrc, flags,
1405*7c478bd9Sstevel@tonic-gate reason, dependent_reason, NULL));
1406*7c478bd9Sstevel@tonic-gate }
1407*7c478bd9Sstevel@tonic-gate
1408*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
1409*7c478bd9Sstevel@tonic-gate static int
tty_suspend(rcm_handle_t * hd,char * rsrc,id_t id,timespec_t * interval,uint_t flag,char ** reason,rcm_info_t ** dependent_reason)1410*7c478bd9Sstevel@tonic-gate tty_suspend(rcm_handle_t *hd, char *rsrc, id_t id, timespec_t *interval,
1411*7c478bd9Sstevel@tonic-gate uint_t flag, char **reason, rcm_info_t **dependent_reason)
1412*7c478bd9Sstevel@tonic-gate {
1413*7c478bd9Sstevel@tonic-gate return (rsrc_change_common(hd, TTYMUX_SUSPEND, rsrc, flag,
1414*7c478bd9Sstevel@tonic-gate reason, dependent_reason, (void *)interval));
1415*7c478bd9Sstevel@tonic-gate }
1416*7c478bd9Sstevel@tonic-gate
1417*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
1418*7c478bd9Sstevel@tonic-gate static int
tty_online(rcm_handle_t * hd,char * rsrc,id_t id,uint_t flags,char ** reason,rcm_info_t ** dependent_reason)1419*7c478bd9Sstevel@tonic-gate tty_online(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
1420*7c478bd9Sstevel@tonic-gate char **reason, rcm_info_t **dependent_reason)
1421*7c478bd9Sstevel@tonic-gate {
1422*7c478bd9Sstevel@tonic-gate return (rsrc_change_common(hd, TTYMUX_ONLINE, rsrc, flags,
1423*7c478bd9Sstevel@tonic-gate reason, dependent_reason, NULL));
1424*7c478bd9Sstevel@tonic-gate }
1425*7c478bd9Sstevel@tonic-gate
1426*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
1427*7c478bd9Sstevel@tonic-gate static int
tty_resume(rcm_handle_t * hd,char * rsrc,id_t id,uint_t flags,char ** reason,rcm_info_t ** dependent_reason)1428*7c478bd9Sstevel@tonic-gate tty_resume(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
1429*7c478bd9Sstevel@tonic-gate char **reason, rcm_info_t **dependent_reason)
1430*7c478bd9Sstevel@tonic-gate {
1431*7c478bd9Sstevel@tonic-gate return (rsrc_change_common(hd, TTYMUX_RESUME, rsrc, flags,
1432*7c478bd9Sstevel@tonic-gate reason, dependent_reason, NULL));
1433*7c478bd9Sstevel@tonic-gate }
1434