1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25 #pragma ident "%Z%%M% %I% %E% SMI"
26
27 /*
28 * Configuration and setup interface to vcc driver.
29 * At intialization time, vntsd opens vcc ctrl port and read initial
30 * configuratioa. It manages console groups, creates the listen thread,
31 * dynamically adds and removes virtual console within a group.
32 */
33
34
35 #include <syslog.h>
36 #include <stdio.h>
37 #include <sys/types.h>
38 #include <sys/ipc.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <unistd.h>
42 #include <sys/socket.h>
43 #include <sys/ipc.h>
44 #include <sys/shm.h>
45 #include <sys/sem.h>
46 #include <wait.h>
47 #include <time.h>
48 #include <synch.h>
49 #include <netinet/in.h>
50 #include <thread.h>
51 #include <signal.h>
52 #include "vntsd.h"
53
54 /* signal all clients that console has been deleted */
55 boolean_t
vntsd_notify_client_cons_del(vntsd_client_t * clientp)56 vntsd_notify_client_cons_del(vntsd_client_t *clientp)
57 {
58 (void) mutex_lock(&clientp->lock);
59 clientp->status |= VNTSD_CLIENT_CONS_DELETED;
60 (void) thr_kill(clientp->cons_tid, SIGUSR1);
61 (void) mutex_unlock(&clientp->lock);
62 return (B_FALSE);
63 }
64
65 /* free console structure */
66 static void
free_cons(vntsd_cons_t * consp)67 free_cons(vntsd_cons_t *consp)
68 {
69 assert(consp);
70 (void) mutex_destroy(&consp->lock);
71 (void) cond_destroy(&consp->cvp);
72 if (consp->vcc_fd != -1)
73 (void) close(consp->vcc_fd);
74 free(consp);
75 }
76
77 /* free group structure */
78 static void
free_group(vntsd_group_t * groupp)79 free_group(vntsd_group_t *groupp)
80 {
81 assert(groupp);
82 (void) mutex_destroy(&groupp->lock);
83 (void) cond_destroy(&groupp->cvp);
84 if (groupp->sockfd != -1)
85 (void) close(groupp->sockfd);
86 free(groupp);
87 }
88
89 /*
90 * all clients connected to a console must disconnect before
91 * removing a console.
92 */
93 static void
cleanup_cons(vntsd_cons_t * consp)94 cleanup_cons(vntsd_cons_t *consp)
95 {
96 vntsd_group_t *groupp;
97 timestruc_t to;
98
99 assert(consp);
100 D1(stderr, "t@%d vntsd_disconn_clients@%d\n", thr_self(),
101 consp->cons_no);
102
103 groupp = consp->group;
104 assert(groupp);
105
106
107 (void) mutex_lock(&consp->lock);
108
109 /* wait for all clients disconnect from the console */
110 while (consp->clientpq != NULL) {
111 consp->status |= VNTSD_CONS_SIG_WAIT;
112
113 /* signal client to disconnect the console */
114 (void) vntsd_que_walk(consp->clientpq,
115 (el_func_t)vntsd_notify_client_cons_del);
116
117 (void) thr_kill(consp->wr_tid, SIGUSR1);
118 to.tv_sec = VNTSD_CV_WAIT_DELTIME;
119 to.tv_nsec = 0;
120
121 /* wait for clients to disconnect */
122 (void) cond_reltimedwait(&consp->cvp, &consp->lock, &to);
123 }
124
125 /* reduce console count in the group */
126 (void) mutex_lock(&groupp->lock);
127 assert(groupp->num_cons > 0);
128 groupp->num_cons--;
129 (void) mutex_unlock(&groupp->lock);
130
131 (void) mutex_unlock(&consp->lock);
132
133 free_cons(consp);
134 }
135
136 /* search for a group whose console is being deleted */
137 static boolean_t
find_clean_cons_group(vntsd_group_t * groupp)138 find_clean_cons_group(vntsd_group_t *groupp)
139 {
140 if (groupp->status & VNTSD_GROUP_CLEAN_CONS) {
141 return (B_TRUE);
142 } else {
143 return (B_FALSE);
144 }
145 }
146
147 /* search for a console that is being deleted */
148 static boolean_t
find_clean_cons(vntsd_cons_t * consp)149 find_clean_cons(vntsd_cons_t *consp)
150 {
151 if (consp->status & VNTSD_CONS_DELETED) {
152 return (B_TRUE);
153 } else {
154 return (B_FALSE);
155 }
156 }
157
158 /* delete a console */
159 void
vntsd_delete_cons(vntsd_t * vntsdp)160 vntsd_delete_cons(vntsd_t *vntsdp)
161 {
162 vntsd_group_t *groupp;
163 vntsd_cons_t *consp;
164
165 for (; ; ) {
166 /* get the group contains deleted console */
167 (void) mutex_lock(&vntsdp->lock);
168 groupp = vntsd_que_walk(vntsdp->grouppq,
169 (el_func_t)find_clean_cons_group);
170 if (groupp == NULL) {
171 /* no more group has console deleted */
172 (void) mutex_unlock(&vntsdp->lock);
173 return;
174 }
175 (void) mutex_lock(&groupp->lock);
176 groupp->status &= ~VNTSD_GROUP_CLEAN_CONS;
177 (void) mutex_unlock(&groupp->lock);
178 (void) mutex_unlock(&vntsdp->lock);
179
180 for (; ; ) {
181 /* get the console to be deleted */
182 (void) mutex_lock(&groupp->lock);
183
184 /* clean up any deleted console in the group */
185 if (groupp->conspq != NULL) {
186 consp = vntsd_que_walk(groupp->conspq,
187 (el_func_t)find_clean_cons);
188 if (consp == NULL) {
189 /* no more cons to delete */
190 (void) mutex_unlock(&groupp->lock);
191 break;
192 }
193
194 /* remove console from the group */
195 (void) vntsd_que_rm(&groupp->conspq, consp);
196 (void) mutex_unlock(&groupp->lock);
197
198 /* clean up the console */
199 cleanup_cons(consp);
200 }
201
202 /* delete group? */
203 if (groupp->conspq == NULL) {
204 /* no more console in the group delete group */
205 assert(groupp->vntsd);
206
207 (void) mutex_lock(&groupp->vntsd->lock);
208 (void) vntsd_que_rm(&groupp->vntsd->grouppq,
209 groupp);
210 (void) mutex_unlock(&groupp->vntsd->lock);
211
212 /* clean up the group */
213 vntsd_clean_group(groupp);
214 break;
215 }
216 }
217 }
218 }
219
220 /* clean up a group */
221 void
vntsd_clean_group(vntsd_group_t * groupp)222 vntsd_clean_group(vntsd_group_t *groupp)
223 {
224
225 timestruc_t to;
226
227 D1(stderr, "t@%d clean_group() group=%s tcp=%lld\n", thr_self(),
228 groupp->group_name, groupp->tcp_port);
229
230 (void) mutex_lock(&groupp->lock);
231
232 /* prevent from reentry */
233 if (groupp->status & VNTSD_GROUP_IN_CLEANUP) {
234 (void) mutex_unlock(&groupp->lock);
235 return;
236 }
237 groupp->status |= VNTSD_GROUP_IN_CLEANUP;
238
239 /* mark group waiting for listen thread to exits */
240 groupp->status |= VNTSD_GROUP_SIG_WAIT;
241 (void) mutex_unlock(&groupp->lock);
242
243 vntsd_free_que(&groupp->conspq, (clean_func_t)cleanup_cons);
244
245 (void) mutex_lock(&groupp->lock);
246 /* walk through no cons client queue */
247 while (groupp->no_cons_clientpq != NULL) {
248 (void) vntsd_que_walk(groupp->no_cons_clientpq,
249 (el_func_t)vntsd_notify_client_cons_del);
250 to.tv_sec = VNTSD_CV_WAIT_DELTIME;
251 to.tv_nsec = 0;
252 (void) cond_reltimedwait(&groupp->cvp, &groupp->lock, &to);
253 }
254
255 /* waiting for listen thread to exit */
256 while (groupp->status & VNTSD_GROUP_SIG_WAIT) {
257 /* signal listen thread to exit */
258 (void) thr_kill(groupp->listen_tid, SIGUSR1);
259 to.tv_sec = VNTSD_CV_WAIT_DELTIME;
260 to.tv_nsec = 0;
261 /* wait listen thread to exit */
262 (void) cond_reltimedwait(&groupp->cvp, &groupp->lock, &to);
263 }
264
265 (void) mutex_unlock(&groupp->lock);
266 (void) thr_join(groupp->listen_tid, NULL, NULL);
267 /* free group */
268 free_group(groupp);
269 }
270
271 /* allocate and initialize console structure */
272 static vntsd_cons_t *
alloc_cons(vntsd_group_t * groupp,vcc_console_t * consolep)273 alloc_cons(vntsd_group_t *groupp, vcc_console_t *consolep)
274 {
275 vntsd_cons_t *consp;
276 int rv;
277
278 /* allocate console */
279 consp = (vntsd_cons_t *)malloc(sizeof (vntsd_cons_t));
280 if (consp == NULL) {
281 vntsd_log(VNTSD_ERR_NO_MEM, "alloc_cons");
282 return (NULL);
283 }
284
285 /* intialize console */
286 bzero(consp, sizeof (vntsd_cons_t));
287
288 (void) mutex_init(&consp->lock, USYNC_THREAD|LOCK_ERRORCHECK, NULL);
289 (void) cond_init(&consp->cvp, USYNC_THREAD, NULL);
290
291 consp->cons_no = consolep->cons_no;
292 (void) strlcpy(consp->domain_name, consolep->domain_name, MAXPATHLEN);
293 (void) strlcpy(consp->dev_name, consolep->dev_name, MAXPATHLEN);
294 consp->wr_tid = (thread_t)-1;
295 consp->vcc_fd = -1;
296
297 /* join the group */
298 (void) mutex_lock(&groupp->lock);
299
300 if ((rv = vntsd_que_append(&groupp->conspq, consp)) !=
301 VNTSD_SUCCESS) {
302 (void) mutex_unlock(&groupp->lock);
303 vntsd_log(rv, "alloc_cons");
304 free_cons(consp);
305 return (NULL);
306 }
307 groupp->num_cons++;
308 consp->group = groupp;
309
310 (void) mutex_unlock(&groupp->lock);
311
312 D1(stderr, "t@%d alloc_cons@%d %s %s\n", thr_self(),
313 consp->cons_no, consp->domain_name, consp->dev_name);
314
315 return (consp);
316 }
317
318 /* compare tcp with group->tcp */
319 static boolean_t
grp_by_tcp(vntsd_group_t * groupp,uint64_t * tcp_port)320 grp_by_tcp(vntsd_group_t *groupp, uint64_t *tcp_port)
321 {
322 assert(groupp);
323 assert(tcp_port);
324 return (groupp->tcp_port == *tcp_port);
325 }
326
327 /* allocate and initialize group */
328 static vntsd_group_t *
alloc_group(vntsd_t * vntsdp,char * group_name,uint64_t tcp_port)329 alloc_group(vntsd_t *vntsdp, char *group_name, uint64_t tcp_port)
330 {
331 vntsd_group_t *groupp;
332
333 /* allocate group */
334 groupp = (vntsd_group_t *)malloc(sizeof (vntsd_group_t));
335 if (groupp == NULL) {
336 vntsd_log(VNTSD_ERR_NO_MEM, "alloc_group");
337 return (NULL);
338 }
339
340 /* initialize group */
341 bzero(groupp, sizeof (vntsd_group_t));
342
343 (void) mutex_init(&groupp->lock, USYNC_THREAD|LOCK_ERRORCHECK, NULL);
344 (void) cond_init(&groupp->cvp, USYNC_THREAD, NULL);
345
346 if (group_name != NULL) {
347 (void) memcpy(groupp->group_name, group_name, MAXPATHLEN);
348 }
349
350 groupp->tcp_port = tcp_port;
351 groupp->listen_tid = (thread_t)-1;
352 groupp->sockfd = -1;
353 groupp->vntsd = vntsdp;
354
355 D1(stderr, "t@%d alloc_group@%lld:%s\n", thr_self(), groupp->tcp_port,
356 groupp->group_name);
357
358 return (groupp);
359 }
360
361 /* mark a deleted console */
362 boolean_t
vntsd_mark_deleted_cons(vntsd_cons_t * consp)363 vntsd_mark_deleted_cons(vntsd_cons_t *consp)
364 {
365 (void) mutex_lock(&consp->lock);
366 consp->status |= VNTSD_CONS_DELETED;
367 (void) mutex_unlock(&consp->lock);
368 return (B_FALSE);
369 }
370
371 /*
372 * Initialize a console, if console is associated with with a
373 * new group, intialize the group.
374 */
375 static int
alloc_cons_with_group(vntsd_t * vntsdp,vcc_console_t * consp,vntsd_group_t ** new_groupp)376 alloc_cons_with_group(vntsd_t *vntsdp, vcc_console_t *consp,
377 vntsd_group_t **new_groupp)
378 {
379 vntsd_group_t *groupp = NULL;
380 int rv;
381
382 *new_groupp = NULL;
383
384 /* match group by tcp port */
385
386
387 (void) mutex_lock(&vntsdp->lock);
388 groupp = vntsd_que_find(vntsdp->grouppq,
389 (compare_func_t)grp_by_tcp, (void *)&(consp->tcp_port));
390 if (groupp != NULL)
391 (void) mutex_lock(&groupp->lock);
392
393 (void) mutex_unlock(&vntsdp->lock);
394
395 if (groupp != NULL) {
396 /*
397 * group with same tcp port found.
398 * if there is no console in the group, the
399 * group should be removed and the tcp port can
400 * be used for tne new group.
401 * This is possible, when there is tight loop of
402 * creating/deleting domains. When a vcc port is
403 * removed, a read thread will have an I/O error because
404 * vcc has closed the port. The read thread then marks
405 * the console is removed and notify main thread to
406 * remove the console.
407 * Meanwhile, the same port and its group (with same
408 * tcp port and group name) is created. Vcc notify
409 * vntsd that new console is added.
410 * Main thread now have two events. If main thread polls
411 * out vcc notification first, it will find that there is
412 * a group has no console.
413 */
414
415 if (vntsd_chk_group_total_cons(groupp) == 0) {
416
417 /* all consoles in the group have been removed */
418 (void) vntsd_que_walk(groupp->conspq,
419 (el_func_t)vntsd_mark_deleted_cons);
420 groupp->status |= VNTSD_GROUP_CLEAN_CONS;
421 (void) mutex_unlock(&groupp->lock);
422 groupp = NULL;
423
424 } else if (strcmp(groupp->group_name, consp->group_name)) {
425 /* conflict group name */
426 vntsd_log(VNTSD_ERR_VCC_GRP_NAME,
427 "group name is different from existing group");
428 (void) mutex_unlock(&groupp->lock);
429 return (VNTSD_ERR_VCC_CTRL_DATA);
430
431 } else {
432 /* group already existed */
433 (void) mutex_unlock(&groupp->lock);
434 }
435
436 }
437
438 if (groupp == NULL) {
439 /* new group */
440 groupp = alloc_group(vntsdp, consp->group_name,
441 consp->tcp_port);
442 if (groupp == NULL) {
443 return (VNTSD_ERR_NO_MEM);
444 }
445
446 assert(groupp->conspq == NULL);
447 /* queue group to vntsdp */
448 (void) mutex_lock(&vntsdp->lock);
449 rv = vntsd_que_append(&vntsdp->grouppq, groupp);
450 (void) mutex_unlock(&vntsdp->lock);
451
452 if (rv != VNTSD_SUCCESS) {
453 return (rv);
454 }
455
456 *new_groupp = groupp;
457 }
458
459 /* intialize console */
460 if (alloc_cons(groupp, consp) == NULL) {
461 /* no memory */
462 if (new_groupp != NULL) {
463 /* clean up new group */
464 free_group(groupp);
465 }
466
467 return (VNTSD_ERR_NO_MEM);
468 }
469
470 return (VNTSD_SUCCESS);
471
472 }
473
474
475 /* create listen thread */
476 static boolean_t
create_listen_thread(vntsd_group_t * groupp)477 create_listen_thread(vntsd_group_t *groupp)
478 {
479
480 char err_msg[VNTSD_LINE_LEN];
481 int rv;
482
483 assert(groupp);
484
485 (void) mutex_lock(&groupp->lock);
486 assert(groupp->num_cons);
487
488 D1(stderr, "t@%d create_listen:%lld\n", thr_self(), groupp->tcp_port);
489
490 if ((rv = thr_create(NULL, 0, (thr_func_t)vntsd_listen_thread,
491 (void *)groupp, THR_DETACHED, &groupp->listen_tid))
492 != 0) {
493 (void) (void) snprintf(err_msg, sizeof (err_msg),
494 "Can not create listen thread for"
495 "group %s tcp %llx\n", groupp->group_name,
496 groupp->tcp_port);
497 vntsd_log(VNTSD_ERR_CREATE_LISTEN_THR, err_msg);
498
499 /* clean up group queue */
500 vntsd_free_que(&groupp->conspq, (clean_func_t)free_cons);
501 groupp->listen_tid = (thread_t)-1;
502 }
503
504 (void) mutex_unlock(&groupp->lock);
505
506 return (rv != 0);
507 }
508
509 /* find deleted console by console no */
510 static boolean_t
deleted_cons_by_consno(vntsd_cons_t * consp,int * cons_no)511 deleted_cons_by_consno(vntsd_cons_t *consp, int *cons_no)
512 {
513 vntsd_client_t *clientp;
514
515 assert(consp);
516
517 if (consp->cons_no != *cons_no)
518 return (B_FALSE);
519
520 /* has console marked as deleted? */
521 if ((consp->status & VNTSD_CONS_DELETED) == 0)
522 return (B_TRUE);
523
524 if (consp->clientpq == NULL)
525 /* there is no client for this console */
526 return (B_TRUE);
527
528 /* need to notify clients of console ? */
529 clientp = (vntsd_client_t *)consp->clientpq->handle;
530
531 if (clientp->status & VNTSD_CLIENT_CONS_DELETED)
532 /* clients of console have notified */
533 return (B_FALSE);
534
535 return (B_TRUE);
536 }
537
538 /* find group structure from console no */
539 static boolean_t
find_cons_group_by_cons_no(vntsd_group_t * groupp,uint_t * cons_no)540 find_cons_group_by_cons_no(vntsd_group_t *groupp, uint_t *cons_no)
541 {
542 vntsd_cons_t *consp;
543
544 consp = vntsd_que_find(groupp->conspq,
545 (compare_func_t)deleted_cons_by_consno, cons_no);
546 return (consp != NULL);
547
548 }
549
550 /* delete a console if the console exists in the vntsd */
551 static void
delete_cons_before_add(vntsd_t * vntsdp,uint_t cons_no)552 delete_cons_before_add(vntsd_t *vntsdp, uint_t cons_no)
553 {
554 vntsd_group_t *groupp;
555 vntsd_cons_t *consp;
556
557 /* group exists? */
558 (void) mutex_lock(&vntsdp->lock);
559 groupp = vntsd_que_find(vntsdp->grouppq,
560 (compare_func_t)find_cons_group_by_cons_no,
561 &cons_no);
562 (void) mutex_unlock(&vntsdp->lock);
563
564 if (groupp == NULL) {
565 /* no such group */
566 return;
567 }
568
569 /* group exists, if console exists? */
570 (void) mutex_lock(&groupp->lock);
571 consp = vntsd_que_find(groupp->conspq,
572 (compare_func_t)deleted_cons_by_consno, &cons_no);
573
574 if (consp == NULL) {
575 /* no such console */
576 (void) mutex_unlock(&groupp->lock);
577 return;
578 }
579
580 /* console exists - mark console for main thread to delete it */
581 (void) mutex_lock(&consp->lock);
582
583 if (consp->status & VNTSD_CONS_DELETED) {
584 /* already marked */
585 (void) mutex_unlock(&consp->lock);
586 (void) mutex_unlock(&groupp->lock);
587 return;
588 }
589
590 consp->status |= VNTSD_CONS_DELETED;
591 groupp->status |= VNTSD_GROUP_CLEAN_CONS;
592
593 (void) mutex_unlock(&consp->lock);
594 (void) mutex_unlock(&groupp->lock);
595
596 }
597
598 /* add a console */
599 static void
do_add_cons(vntsd_t * vntsdp,int cons_no)600 do_add_cons(vntsd_t *vntsdp, int cons_no)
601 {
602 vcc_console_t console;
603 vntsd_group_t *groupp;
604 int rv;
605 char err_msg[VNTSD_LINE_LEN];
606
607
608 (void) snprintf(err_msg, sizeof (err_msg),
609 "do_add_cons():Can not add console=%d", cons_no);
610
611 /* get console configuration from vcc */
612
613 if ((rv = vntsd_vcc_ioctl(VCC_CONS_INFO, cons_no, (void *)&console))
614 != VNTSD_SUCCESS) {
615 vntsd_log(rv, err_msg);
616 return;
617 }
618
619 /* clean up the console if console was deleted and added again */
620 delete_cons_before_add(vntsdp, console.cons_no);
621
622 /* initialize console */
623
624 if ((rv = alloc_cons_with_group(vntsdp, &console, &groupp)) !=
625 VNTSD_SUCCESS) {
626 /* no memory to add this new console */
627 vntsd_log(rv, err_msg);
628 return;
629 }
630
631 if (groupp != NULL) {
632 /* new group */
633 /* create listen thread for this console */
634 if (create_listen_thread(groupp)) {
635 vntsd_log(VNTSD_ERR_CREATE_LISTEN_THR, err_msg);
636 free_group(groupp);
637 }
638
639 }
640 }
641
642 /* daemon wake up */
643 void
vntsd_daemon_wakeup(vntsd_t * vntsdp)644 vntsd_daemon_wakeup(vntsd_t *vntsdp)
645 {
646
647 vcc_response_t inq_data;
648
649 /* reason to wake up */
650 if (vntsd_vcc_ioctl(VCC_INQUIRY, 0, (void *)&inq_data) !=
651 VNTSD_SUCCESS) {
652 vntsd_log(VNTSD_ERR_VCC_IOCTL, "vntsd_daemon_wakeup()");
653 return;
654 }
655
656 D1(stderr, "t@%d vntsd_daemon_wakup:msg %d port %x\n", thr_self(),
657 inq_data.reason, inq_data.cons_no);
658
659 switch (inq_data.reason) {
660
661 case VCC_CONS_ADDED:
662 do_add_cons(vntsdp, inq_data.cons_no);
663 break;
664
665 case VCC_CONS_MISS_ADDED:
666 /* an added port was deleted before vntsd can process it */
667 return;
668
669 default:
670 DERR(stderr, "t@%d daemon_wakeup:ioctl_unknown %d\n",
671 thr_self(), inq_data.reason);
672 vntsd_log(VNTSD_ERR_UNKNOWN_CMD, "from vcc\n");
673 break;
674 }
675 }
676
677 /* initial console configuration */
678 void
vntsd_get_config(vntsd_t * vntsdp)679 vntsd_get_config(vntsd_t *vntsdp)
680 {
681
682 int i;
683 int num_cons;
684 vcc_console_t *consp;
685 vntsd_group_t *groupp;
686
687 /* num of consoles */
688 num_cons = 0;
689
690 if (vntsd_vcc_ioctl(VCC_NUM_CONSOLE, 0, (void *)&num_cons) !=
691 VNTSD_SUCCESS) {
692 vntsd_log(VNTSD_ERR_VCC_IOCTL, "VCC_NUM_CONSOLE failed\n");
693 return;
694 }
695
696 D3(stderr, "get_config:num_cons=%d", num_cons);
697
698 if (num_cons == 0) {
699 return;
700 }
701
702 /* allocate memory for all consoles */
703 consp = malloc(num_cons*sizeof (vcc_console_t));
704
705 if (consp == NULL) {
706 vntsd_log(VNTSD_ERR_NO_MEM, "for console table.");
707 return;
708 }
709
710 /* get console table */
711 if (vntsd_vcc_ioctl(VCC_CONS_TBL, 0, (void *)consp) != VNTSD_SUCCESS) {
712 vntsd_log(VNTSD_ERR_VCC_IOCTL, " VCC_CONS_TBL "
713 "for console table\n");
714 return;
715 }
716
717 /* intialize groups and consoles */
718 for (i = 0; i < num_cons; i++) {
719 if (alloc_cons_with_group(vntsdp, &consp[i], &groupp)
720 != VNTSD_SUCCESS) {
721 vntsd_log(VNTSD_ERR_ADD_CONS_FAILED, "get_config");
722 }
723 }
724
725 /* create listen thread for each group */
726 (void) mutex_lock(&vntsdp->lock);
727
728 for (; ; ) {
729 groupp = vntsd_que_walk(vntsdp->grouppq,
730 (el_func_t)create_listen_thread);
731 if (groupp == NULL) {
732 break;
733 }
734 vntsd_log(VNTSD_ERR_CREATE_LISTEN_THR, "get config()");
735 }
736
737 (void) mutex_unlock(&vntsdp->lock);
738 }
739