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 /*
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27
28 /*
29 * MT STREAMS Virtual Console Device Driver
30 */
31
32 #include <sys/types.h>
33 #include <sys/open.h>
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/signal.h>
37 #include <sys/cred.h>
38 #include <sys/user.h>
39 #include <sys/proc.h>
40 #include <sys/disp.h>
41 #include <sys/vnode.h>
42 #include <sys/uio.h>
43 #include <sys/buf.h>
44 #include <sys/file.h>
45 #include <sys/kmem.h>
46 #include <sys/stat.h>
47 #include <sys/stream.h>
48 #include <sys/stropts.h>
49 #include <sys/strsubr.h>
50 #include <sys/strsun.h>
51 #include <sys/tty.h>
52 #include <sys/ptyvar.h>
53 #include <sys/poll.h>
54 #include <sys/debug.h>
55 #include <sys/conf.h>
56 #include <sys/ddi.h>
57 #include <sys/sunddi.h>
58 #include <sys/errno.h>
59 #include <sys/modctl.h>
60
61 #include <sys/sc_cvc.h>
62 #include <sys/sc_cvcio.h>
63 #include <sys/iosramio.h>
64
65 static int cvc_info(dev_info_t *, ddi_info_cmd_t, void *, void **);
66 static int cvc_attach(dev_info_t *, ddi_attach_cmd_t);
67 static int cvc_detach(dev_info_t *, ddi_detach_cmd_t);
68 static int cvc_open(register queue_t *, dev_t *, int, int, cred_t *);
69 static int cvc_close(queue_t *, int, cred_t *);
70 static int cvc_wput(queue_t *, mblk_t *);
71 static int cvc_wsrv(queue_t *);
72 static void cvc_ioctl(queue_t *, mblk_t *);
73 static void cvc_reioctl(void *);
74 static void cvc_input_daemon(void);
75 static void cvc_send_to_iosram(mblk_t **chainpp);
76 static void cvc_flush_queue(void *);
77 static void cvc_iosram_ops(uint8_t);
78 static void cvc_getstr(char *cp);
79 static void cvc_win_resize(int clear_flag);
80
81 #define ESUCCESS 0
82 #ifndef TRUE
83 #define TRUE 1
84 #define FALSE 0
85 #endif
86
87 /*
88 * Private copy of devinfo pointer; cvc_info uses it.
89 */
90 static dev_info_t *cvcdip;
91
92 /*
93 * This structure reflects the layout of data in CONI and CONO. If you are
94 * going to add fields that don't get written into those chunks, be sure to
95 * place them _after_ the buffer field.
96 */
97 typedef struct cvc_buf {
98 ushort_t count;
99 uchar_t buffer[MAX_XFER_COUTPUT];
100 } cvc_buf_t;
101
102 typedef struct cvc_s {
103 bufcall_id_t cvc_wbufcid;
104 tty_common_t cvc_tty;
105 } cvc_t;
106
107 cvc_t cvc_common_tty;
108
109 static struct module_info cvcm_info = {
110 1313, /* mi_idnum Bad luck number ;-) */
111 "cvc", /* mi_idname */
112 0, /* mi_minpsz */
113 INFPSZ, /* mi_maxpsz */
114 2048, /* mi_hiwat */
115 2048 /* mi_lowat */
116 };
117
118 static struct qinit cvcrinit = {
119 NULL, /* qi_putp */
120 NULL, /* qi_srvp */
121 cvc_open, /* qi_qopen */
122 cvc_close, /* qi_qclose */
123 NULL, /* qi_qadmin */
124 &cvcm_info, /* qi_minfo */
125 NULL /* qi_mstat */
126 };
127
128 static struct qinit cvcwinit = {
129 cvc_wput, /* qi_putp */
130 cvc_wsrv, /* qi_srvp */
131 cvc_open, /* qi_qopen */
132 cvc_close, /* qi_qclose */
133 NULL, /* qi_qadmin */
134 &cvcm_info, /* qi_minfo */
135 NULL /* qi_mstat */
136 };
137
138 struct streamtab cvcinfo = {
139 &cvcrinit, /* st_rdinit */
140 &cvcwinit, /* st_wrinit */
141 NULL, /* st_muxrinit */
142 NULL /* st_muxwrinit */
143 };
144
145 static krwlock_t cvclock; /* lock protecting everything here */
146 static queue_t *cvcinput_q; /* queue for console input */
147 static queue_t *cvcoutput_q; /* queue for console output */
148 static int cvc_instance = -1;
149 static int cvc_stopped = 0;
150 static int cvc_suspended = 0;
151
152 kthread_id_t cvc_input_daemon_thread; /* just to aid debugging */
153 static kmutex_t cvcmutex; /* protects input */
154 static kmutex_t cvc_iosram_input_mutex; /* protects IOSRAM inp buff */
155 static int input_ok = 0; /* true when stream is valid */
156
157 static int via_iosram = 0; /* toggle switch */
158 static timeout_id_t cvc_timeout_id = (timeout_id_t)-1;
159 static int input_daemon_started = 0;
160
161 /* debugging functions */
162 #ifdef DEBUG
163 uint32_t cvc_dbg_flags = 0x0;
164 static void cvc_dbg(uint32_t flag, char *fmt,
165 uintptr_t a1, uintptr_t a2, uintptr_t a3, uintptr_t a4, uintptr_t a5);
166 #endif
167
168 /*
169 * Module linkage information for the kernel.
170 */
171
172 DDI_DEFINE_STREAM_OPS(cvcops, nulldev, nulldev, cvc_attach, cvc_detach,
173 nodev, cvc_info, (D_NEW|D_MTPERQ|D_MP), &cvcinfo,
174 ddi_quiesce_not_supported);
175
176 extern int nodev(), nulldev();
177 extern struct mod_ops mod_driverops;
178
179 static struct modldrv modldrv = {
180 &mod_driverops, /* Type of module. This one is a pseudo driver */
181 "CVC driver 'cvc'",
182 &cvcops, /* driver ops */
183 };
184
185 static struct modlinkage modlinkage = {
186 MODREV_1,
187 &modldrv,
188 NULL
189 };
190
191 int
_init()192 _init()
193 {
194 int status;
195
196 status = mod_install(&modlinkage);
197 if (status == 0) {
198 mutex_init(&cvcmutex, NULL, MUTEX_DEFAULT, NULL);
199 }
200 return (status);
201 }
202
203 int
_fini()204 _fini()
205 {
206 return (EBUSY);
207 }
208
209 int
_info(struct modinfo * modinfop)210 _info(struct modinfo *modinfop)
211 {
212 return (mod_info(&modlinkage, modinfop));
213 }
214
215 /*
216 * DDI glue routines.
217 */
218
219 /* ARGSUSED */
220 static int
cvc_attach(dev_info_t * devi,ddi_attach_cmd_t cmd)221 cvc_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
222 {
223 static char been_here = 0;
224
225 if (cmd == DDI_RESUME) {
226 cvc_suspended = 0;
227 if (cvcinput_q != NULL) {
228 qenable(WR(cvcinput_q));
229 }
230 return (DDI_SUCCESS);
231 }
232
233 mutex_enter(&cvcmutex);
234 if (!been_here) {
235 been_here = 1;
236 mutex_init(&cvc_iosram_input_mutex, NULL, MUTEX_DEFAULT, NULL);
237 rw_init(&cvclock, NULL, RW_DRIVER, NULL);
238 cvc_instance = ddi_get_instance(devi);
239 } else {
240 #if defined(DEBUG)
241 cmn_err(CE_NOTE,
242 "cvc_attach: called multiple times!! (instance = %d)",
243 ddi_get_instance(devi));
244 #endif /* DEBUG */
245 mutex_exit(&cvcmutex);
246 return (DDI_SUCCESS);
247 }
248 mutex_exit(&cvcmutex);
249
250 if (ddi_create_minor_node(devi, "cvc", S_IFCHR,
251 0, NULL, NULL) == DDI_FAILURE) {
252 ddi_remove_minor_node(devi, NULL);
253 return (-1);
254 }
255 cvcdip = devi;
256 cvcinput_q = NULL;
257 cvcoutput_q = NULL;
258
259 CVC_DBG0(CVC_DBG_ATTACH, "Attached");
260
261 return (DDI_SUCCESS);
262 }
263
264 static int
cvc_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)265 cvc_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
266 {
267 if (cmd == DDI_SUSPEND) {
268 cvc_suspended = 1;
269 } else {
270 if (cmd != DDI_DETACH) {
271 return (DDI_FAILURE);
272 }
273 /*
274 * XXX this doesn't even begin to address the detach
275 * issues - it doesn't terminate the outstanding thread,
276 * it doesn't clean up mutexes, kill the timeout routine
277 * etc.
278 */
279 if (cvc_instance == ddi_get_instance(dip)) {
280 ddi_remove_minor_node(dip, NULL);
281 }
282 }
283
284 CVC_DBG0(CVC_DBG_DETACH, "Detached");
285
286 return (DDI_SUCCESS);
287 }
288
289 /* ARGSUSED */
290 static int
cvc_info(dev_info_t * dip,ddi_info_cmd_t infocmd,void * arg,void ** result)291 cvc_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
292 {
293 register int error;
294
295 switch (infocmd) {
296 case DDI_INFO_DEVT2DEVINFO:
297 if (cvcdip == NULL) {
298 error = DDI_FAILURE;
299 } else {
300 *result = (void *)cvcdip;
301 error = DDI_SUCCESS;
302 }
303 break;
304 case DDI_INFO_DEVT2INSTANCE:
305 *result = (void *)0;
306 error = DDI_SUCCESS;
307 break;
308 default:
309 error = DDI_FAILURE;
310 }
311 return (error);
312 }
313
314 /* ARGSUSED */
315 static int
cvc_open(register queue_t * q,dev_t * devp,int flag,int sflag,cred_t * crp)316 cvc_open(register queue_t *q, dev_t *devp, int flag, int sflag, cred_t *crp)
317 {
318 register int unit = getminor(*devp);
319 register int err = DDI_SUCCESS;
320 tty_common_t *tty;
321 cvc_t *cp;
322
323 if (unit != 0)
324 return (ENXIO);
325
326 if (q->q_ptr)
327 return (0);
328
329 cp = (cvc_t *)&cvc_common_tty;
330 bzero((caddr_t)cp, sizeof (cvc_t));
331 cp->cvc_wbufcid = 0;
332 tty = &cp->cvc_tty;
333 tty->t_readq = q;
334 tty->t_writeq = WR(q);
335 WR(q)->q_ptr = q->q_ptr = (caddr_t)cp;
336 cvcinput_q = RD(q); /* save for cvc_redir */
337 qprocson(q);
338 mutex_enter(&cvcmutex);
339 input_ok = 1;
340
341 /*
342 * Start the thread that handles input polling if it hasn't been started
343 * previously.
344 */
345 if (!input_daemon_started) {
346 input_daemon_started = 1;
347 mutex_exit(&cvcmutex);
348
349 cvc_input_daemon_thread = thread_create(NULL, 0,
350 cvc_input_daemon, NULL, 0, &p0, TS_RUN, minclsyspri);
351 CVC_DBG0(CVC_DBG_IOSRAM_RD, "Started input daemon");
352 } else {
353 mutex_exit(&cvcmutex);
354 }
355
356 /*
357 * Set the console window size.
358 */
359 mutex_enter(&cvc_iosram_input_mutex);
360 cvc_win_resize(FALSE);
361 mutex_exit(&cvc_iosram_input_mutex);
362
363 CVC_DBG0(CVC_DBG_OPEN, "Plumbed successfully");
364
365 return (err);
366 }
367
368 /* ARGSUSED */
369 static int
cvc_close(queue_t * q,int flag,cred_t * crp)370 cvc_close(queue_t *q, int flag, cred_t *crp)
371 {
372 register int err = DDI_SUCCESS;
373 register cvc_t *cp;
374
375 mutex_enter(&cvcmutex);
376 input_ok = 0;
377 mutex_exit(&cvcmutex);
378
379 cp = q->q_ptr;
380 if (cp->cvc_wbufcid != 0) {
381 unbufcall(cp->cvc_wbufcid);
382 }
383 ttycommon_close(&cp->cvc_tty);
384 WR(q)->q_ptr = q->q_ptr = NULL;
385 cvcinput_q = NULL;
386 bzero((caddr_t)cp, sizeof (cvc_t));
387 qprocsoff(q);
388
389 CVC_DBG0(CVC_DBG_CLOSE, "Un-plumbed successfully");
390
391 return (err);
392 }
393
394
395 /*
396 * cvc_wput()
397 * cn driver does a strwrite of console output data to rconsvp which has
398 * been set by consconfig. The data enters the cvc stream at the streamhead
399 * and flows thru ttycompat and ldterm which have been pushed on the
400 * stream. Console output data gets sent out either to cvcredir, if the
401 * network path is available and selected, or to IOSRAM otherwise. Data is
402 * sent to cvcredir via its read queue (cvcoutput_q, which gets set in
403 * cvc_register()). If the IOSRAM path is selected, or if previous mblks
404 * are currently queued up for processing, the new mblk will be queued
405 * and handled later on by cvc_wsrv.
406 */
407 static int
cvc_wput(queue_t * q,mblk_t * mp)408 cvc_wput(queue_t *q, mblk_t *mp)
409 {
410 int error = 0;
411
412 rw_enter(&cvclock, RW_READER);
413
414 CVC_DBG2(CVC_DBG_WPUT, "mp 0x%x db_type 0x%x",
415 mp, mp->b_datap->db_type);
416
417 switch (mp->b_datap->db_type) {
418
419 case M_IOCTL:
420 case M_CTL: {
421 struct iocblk *iocp = (struct iocblk *)mp->b_rptr;
422
423 switch (iocp->ioc_cmd) {
424 /*
425 * These ioctls are only supposed to be
426 * processed after everything else that is
427 * already queued awaiting processing, so throw
428 * them on the queue and let cvc_wsrv handle
429 * them.
430 */
431 case TCSETSW:
432 case TCSETSF:
433 case TCSETAW:
434 case TCSETAF:
435 case TCSBRK:
436 (void) putq(q, mp);
437 break;
438
439 default:
440 cvc_ioctl(q, mp);
441 }
442 break;
443 }
444
445 case M_FLUSH:
446 if (*mp->b_rptr & FLUSHW) {
447 /*
448 * Flush our write queue.
449 */
450 flushq(q, FLUSHDATA);
451 *mp->b_rptr &= ~FLUSHW;
452 }
453 if (*mp->b_rptr & FLUSHR) {
454 flushq(RD(q), FLUSHDATA);
455 qreply(q, mp);
456 } else
457 freemsg(mp);
458 break;
459
460 case M_STOP:
461 cvc_stopped = 1;
462 freemsg(mp);
463 break;
464
465 case M_START:
466 cvc_stopped = 0;
467 freemsg(mp);
468 qenable(q); /* Start up delayed messages */
469 break;
470
471 case M_READ:
472 /*
473 * ldterm handles this (VMIN/VTIME processing).
474 */
475 freemsg(mp);
476 break;
477
478 default:
479 cmn_err(CE_WARN, "cvc_wput: unexpected mblk type - mp ="
480 " 0x%p, type = 0x%x", (void *)mp,
481 mp->b_datap->db_type);
482 freemsg(mp);
483 break;
484
485 case M_DATA:
486 /*
487 * If there are other mblks queued up for transmission,
488 * or we're using IOSRAM either because cvcredir hasn't
489 * registered yet or because we were configured that
490 * way, or cvc has been stopped or suspended, place this
491 * mblk on the input queue for future processing.
492 * Otherwise, hand it off to cvcredir for transmission
493 * via the network.
494 */
495 if (q->q_first != NULL || cvcoutput_q == NULL ||
496 via_iosram || cvc_stopped == 1 ||
497 cvc_suspended == 1) {
498 (void) putq(q, mp);
499 } else {
500 /*
501 * XXX - should canputnext be called here?
502 * Starfire's cvc doesn't do that, and it
503 * appears to work anyway.
504 */
505 (void) putnext(cvcoutput_q, mp);
506 }
507 break;
508
509 }
510 rw_exit(&cvclock);
511 return (error);
512 }
513
514 /*
515 * cvc_wsrv()
516 * cvc_wsrv handles mblks that have been queued by cvc_wput either because
517 * the IOSRAM path was selected or the queue contained preceding mblks. To
518 * optimize processing (particularly if the IOSRAM path is selected), all
519 * mblks are pulled off of the queue and chained together. Then, if there
520 * are any mblks on the chain, they are either forwarded to cvcredir or
521 * sent for IOSRAM processing as appropriate given current circumstances.
522 * IOSRAM processing may not be able to handle all of the data in the
523 * chain, in which case the remaining data is placed back on the queue and
524 * a timeout routine is registered to reschedule cvc_wsrv in the future.
525 * Automatic scheduling of the queue is disabled (noenable(q)) while
526 * cvc_wsrv is running to avoid superfluous calls.
527 */
528 static int
cvc_wsrv(queue_t * q)529 cvc_wsrv(queue_t *q)
530 {
531 mblk_t *total_mp = NULL;
532 mblk_t *mp;
533
534 if (cvc_stopped == 1 || cvc_suspended == 1) {
535 return (0);
536 }
537
538 rw_enter(&cvclock, RW_READER);
539 noenable(q);
540
541 /*
542 * If there's already a timeout registered for scheduling this routine
543 * in the future, it's a safe bet that we don't want to run right now.
544 */
545 if (cvc_timeout_id != (timeout_id_t)-1) {
546 enableok(q);
547 rw_exit(&cvclock);
548 return (0);
549 }
550
551 /*
552 * Start by linking all of the queued M_DATA mblks into a single chain
553 * so we can flush as much as possible to IOSRAM (if we choose that
554 * route).
555 */
556 while ((mp = getq(q)) != NULL) {
557 /*
558 * Technically, certain IOCTLs are supposed to be processed only
559 * after all preceding data has completely "drained". In an
560 * attempt to support that, we delay processing of those IOCTLs
561 * until this point. It is still possible that an IOCTL will be
562 * processed before all preceding data is drained, for instance
563 * in the case where not all of the preceding data would fit
564 * into IOSRAM and we have to place it back on the queue.
565 * However, since none of these IOCTLs really appear to have any
566 * relevance for cvc, and we weren't supporting delayed
567 * processing at _all_ previously, this partial implementation
568 * should suffice. (Fully implementing the delayed IOCTL
569 * processing would be unjustifiably difficult given the nature
570 * of the underlying IOSRAM console protocol.)
571 */
572 if (mp->b_datap->db_type == M_IOCTL) {
573 cvc_ioctl(q, mp);
574 continue;
575 }
576
577 /*
578 * We know that only M_IOCTL and M_DATA blocks are placed on our
579 * queue. Since this block isn't an M_IOCTL, it must be M_DATA.
580 */
581 if (total_mp != NULL) {
582 linkb(total_mp, mp);
583 } else {
584 total_mp = mp;
585 }
586 }
587
588 /*
589 * Do we actually have anything to do?
590 */
591 if (total_mp == NULL) {
592 enableok(q);
593 rw_exit(&cvclock);
594 return (0);
595 }
596
597 /*
598 * Yes, we do, so send the data to either cvcredir or IOSRAM as
599 * appropriate. In the latter case, we might not be able to transmit
600 * everything right now, so re-queue the remainder.
601 */
602 if (cvcoutput_q != NULL && !via_iosram) {
603 CVC_DBG0(CVC_DBG_NETWORK_WR, "Sending to cvcredir.");
604 /*
605 * XXX - should canputnext be called here? Starfire's cvc
606 * doesn't do that, and it appears to work anyway.
607 */
608 (void) putnext(cvcoutput_q, total_mp);
609 } else {
610 CVC_DBG0(CVC_DBG_IOSRAM_WR, "Send to IOSRAM.");
611 cvc_send_to_iosram(&total_mp);
612 if (total_mp != NULL) {
613 (void) putbq(q, total_mp);
614 }
615 }
616
617 /*
618 * If there is still data queued at this point, make sure the queue
619 * gets scheduled again after an appropriate delay (which has been
620 * somewhat arbitrarily selected as half of the SC's input polling
621 * frequency).
622 */
623 enableok(q);
624 if (q->q_first != NULL) {
625 if (cvc_timeout_id == (timeout_id_t)-1) {
626 cvc_timeout_id = timeout(cvc_flush_queue,
627 NULL, drv_usectohz(CVC_IOSRAM_POLL_USECS / 2));
628 }
629 }
630 rw_exit(&cvclock);
631 return (0);
632 }
633
634
635 /*
636 * cvc_ioctl()
637 * handle normal console ioctls.
638 */
639 static void
cvc_ioctl(register queue_t * q,register mblk_t * mp)640 cvc_ioctl(register queue_t *q, register mblk_t *mp)
641 {
642 register cvc_t *cp = q->q_ptr;
643 int datasize;
644 int error = 0;
645
646 /*
647 * Let ttycommon_ioctl take the first shot at processing the ioctl. If
648 * it fails because it can't allocate memory, schedule processing of the
649 * ioctl later when a proper buffer is available. The mblk that
650 * couldn't be processed will have been stored in the tty structure by
651 * ttycommon_ioctl.
652 */
653 datasize = ttycommon_ioctl(&cp->cvc_tty, q, mp, &error);
654 if (datasize != 0) {
655 if (cp->cvc_wbufcid) {
656 unbufcall(cp->cvc_wbufcid);
657 }
658 cp->cvc_wbufcid = bufcall(datasize, BPRI_HI, cvc_reioctl, cp);
659 return;
660 }
661
662 /*
663 * ttycommon_ioctl didn't do anything, but there's nothing we really
664 * support either with the exception of TCSBRK, which is supported
665 * only to appear a bit more like a serial device for software that
666 * expects TCSBRK to work.
667 */
668 if (error != 0) {
669 struct iocblk *iocp = (struct iocblk *)mp->b_rptr;
670
671 if (iocp->ioc_cmd == TCSBRK) {
672 miocack(q, mp, 0, 0);
673 } else {
674 miocnak(q, mp, 0, EINVAL);
675 }
676 } else {
677 qreply(q, mp);
678 }
679 }
680
681
682 /*
683 * cvc_redir()
684 * called from cvcredir:cvcr_wput() to handle console input
685 * data. This routine puts the cvcredir write (downstream) data
686 * onto the cvc read (upstream) queues.
687 */
688 int
cvc_redir(mblk_t * mp)689 cvc_redir(mblk_t *mp)
690 {
691 register struct iocblk *iocp;
692 int rv = 1;
693
694 /*
695 * This function shouldn't be called if cvcredir hasn't registered yet.
696 */
697 if (cvcinput_q == NULL) {
698 /*
699 * Need to let caller know that it may be necessary for them to
700 * free the message buffer, so return 0.
701 */
702 CVC_DBG0(CVC_DBG_REDIR, "redirection not enabled");
703 cmn_err(CE_WARN, "cvc_redir: cvcinput_q NULL!");
704 return (0);
705 }
706
707 CVC_DBG1(CVC_DBG_REDIR, "type 0x%x", mp->b_datap->db_type);
708 if (mp->b_datap->db_type == M_DATA) {
709 /*
710 * XXX - should canputnext be called here? Starfire's cvc
711 * doesn't do that, and it appears to work anyway.
712 */
713 CVC_DBG1(CVC_DBG_NETWORK_RD, "Sending mp 0x%x", mp);
714 (void) putnext(cvcinput_q, mp);
715 } else if (mp->b_datap->db_type == M_IOCTL) {
716 /*
717 * The cvcredir driver filters out ioctl mblks we wouldn't
718 * understand, so we don't have to check for every conceivable
719 * ioc_cmd. However, additional ioctls may be supported (again)
720 * some day, so the code is structured to check the value even
721 * though there's only one that is currently supported.
722 */
723 iocp = (struct iocblk *)mp->b_rptr;
724 if (iocp->ioc_cmd == CVC_DISCONNECT) {
725 (void) putnextctl(cvcinput_q, M_HANGUP);
726 }
727 } else {
728 /*
729 * Since we don't know what this mblk is, we're not going to
730 * process it.
731 */
732 CVC_DBG1(CVC_DBG_REDIR, "unrecognized mblk type: %d",
733 mp->b_datap->db_type);
734 rv = 0;
735 }
736
737 return (rv);
738 }
739
740
741 /*
742 * cvc_register()
743 * called from cvcredir to register it's queues. cvc
744 * receives data from cn via the streamhead and sends it to cvcredir
745 * via pointers to cvcredir's queues.
746 */
747 int
cvc_register(queue_t * q)748 cvc_register(queue_t *q)
749 {
750 int error = -1;
751
752 if (cvcinput_q == NULL)
753 cmn_err(CE_WARN, "cvc_register: register w/ no console open!");
754 rw_enter(&cvclock, RW_WRITER);
755 if (cvcoutput_q == NULL) {
756 cvcoutput_q = RD(q); /* Make sure its the upstream q */
757 qprocson(cvcoutput_q); /* must be done within cvclock */
758 error = 0;
759 } else {
760 /*
761 * cmn_err will call us, so release lock.
762 */
763 rw_exit(&cvclock);
764 if (cvcoutput_q == q)
765 cmn_err(CE_WARN, "cvc_register: duplicate q!");
766 else
767 cmn_err(CE_WARN, "cvc_register: nondup q = 0x%p",
768 (void *)q);
769 return (error);
770 }
771 rw_exit(&cvclock);
772 return (error);
773 }
774
775
776 /*
777 * cvc_unregister()
778 * called from cvcredir to clear pointers to its queues.
779 * cvcredir no longer wants to send or receive data.
780 */
781 void
cvc_unregister(queue_t * q)782 cvc_unregister(queue_t *q)
783 {
784 rw_enter(&cvclock, RW_WRITER);
785 if (q == cvcoutput_q) {
786 qprocsoff(cvcoutput_q); /* must be done within cvclock */
787 cvcoutput_q = NULL;
788 } else {
789 rw_exit(&cvclock);
790 cmn_err(CE_WARN, "cvc_unregister: q = 0x%p not registered",
791 (void *)q);
792 return;
793 }
794 rw_exit(&cvclock);
795 }
796
797
798 /*
799 * cvc_reioctl()
800 * Retry an "ioctl", now that "bufcall" claims we may be able
801 * to allocate the buffer we need.
802 */
803 static void
cvc_reioctl(void * unit)804 cvc_reioctl(void *unit)
805 {
806 register queue_t *q;
807 register mblk_t *mp;
808 register cvc_t *cp = (cvc_t *)unit;
809
810 /*
811 * The bufcall is no longer pending.
812 */
813 if (!cp->cvc_wbufcid) {
814 return;
815 }
816 cp->cvc_wbufcid = 0;
817 if ((q = cp->cvc_tty.t_writeq) == NULL) {
818 return;
819 }
820 if ((mp = cp->cvc_tty.t_iocpending) != NULL) {
821 /* not pending any more */
822 cp->cvc_tty.t_iocpending = NULL;
823 cvc_ioctl(q, mp);
824 }
825 }
826
827
828 /*
829 * cvc_iosram_ops()
830 * Process commands sent to cvc from netcon_server via IOSRAM
831 */
832 static void
cvc_iosram_ops(uint8_t op)833 cvc_iosram_ops(uint8_t op)
834 {
835 int rval = ESUCCESS;
836 static uint8_t stale_op = 0;
837
838 ASSERT(MUTEX_HELD(&cvc_iosram_input_mutex));
839
840 CVC_DBG1(CVC_DBG_IOSRAM_CNTL, "cntl msg 0x%x", op);
841
842 /*
843 * If this is a repeated notice of a command that was previously
844 * processed but couldn't be cleared due to EAGAIN (tunnel switch in
845 * progress), just clear the data_valid flag and return.
846 */
847 if (op == stale_op) {
848 if (iosram_set_flag(IOSRAM_KEY_CONC, IOSRAM_DATA_INVALID,
849 IOSRAM_INT_NONE) == 0) {
850 stale_op = 0;
851 }
852 return;
853 }
854 stale_op = 0;
855
856 switch (op) {
857 case CVC_IOSRAM_BREAK: /* A console break (L1-A) */
858 abort_sequence_enter((char *)NULL);
859 break;
860
861 case CVC_IOSRAM_DISCONNECT: /* Break connection, hang up */
862 if (cvcinput_q)
863 (void) putnextctl(cvcinput_q, M_HANGUP);
864 break;
865
866 case CVC_IOSRAM_VIA_NET: /* console via network */
867 via_iosram = 0;
868 break;
869
870 case CVC_IOSRAM_VIA_IOSRAM: /* console via iosram */
871 via_iosram = 1;
872 /*
873 * Tell cvcd to close any network connection it has.
874 */
875 rw_enter(&cvclock, RW_READER);
876 if (cvcoutput_q != NULL) {
877 (void) putnextctl(cvcoutput_q, M_HANGUP);
878 }
879 rw_exit(&cvclock);
880 break;
881
882 case CVC_IOSRAM_WIN_RESIZE: /* console window size data */
883 /*
884 * In the case of window resizing, we don't want to
885 * record a stale_op value because we should always use
886 * the most recent winsize info, which could change
887 * between the time that we fail to clear the flag and
888 * the next time we try to process the command. So,
889 * we'll just let cvc_win_resize clear the data_valid
890 * flag itself (hence the TRUE parameter) and not worry
891 * about whether or not it succeeds.
892 */
893 cvc_win_resize(TRUE);
894 return;
895 /* NOTREACHED */
896
897 default:
898 cmn_err(CE_WARN, "cvc: unknown IOSRAM opcode %d", op);
899 break;
900 }
901
902 /*
903 * Clear CONC's data_valid flag to indicate that the chunk is available
904 * for further communications. If the flag can't be cleared due to an
905 * error, record the op value so we'll know to ignore it when we see it
906 * on the next poll.
907 */
908 rval = iosram_set_flag(IOSRAM_KEY_CONC, IOSRAM_DATA_INVALID,
909 IOSRAM_INT_NONE);
910 if (rval != 0) {
911 stale_op = op;
912 if (rval != EAGAIN) {
913 cmn_err(CE_WARN,
914 "cvc_iosram_ops: set flag for cntlbuf ret %d",
915 rval);
916 }
917 }
918 }
919
920
921 /*
922 * cvc_send_to_iosram()
923 * Flush as much data as possible to the CONO chunk. If successful, free
924 * any mblks that were completely transmitted, update the b_rptr field in
925 * the first remaining mblk if it was partially transmitted, and update the
926 * caller's pointer to the new head of the mblk chain. Since the software
927 * that will be pulling this data out of IOSRAM (dxs on the SC) is just
928 * polling at some frequency, we avoid attempts to flush data to IOSRAM any
929 * faster than a large divisor of that polling frequency.
930 *
931 * Note that "cvc_buf_t out" is only declared "static" to keep it from
932 * being allocated on the stack. Allocating 1K+ structures on the stack
933 * seems rather antisocial.
934 */
935 static void
cvc_send_to_iosram(mblk_t ** chainpp)936 cvc_send_to_iosram(mblk_t **chainpp)
937 {
938 int rval;
939 uint8_t dvalid;
940 uchar_t *cp;
941 mblk_t *mp;
942 mblk_t *last_empty_mp;
943 static clock_t last_flush = (clock_t)-1;
944 static cvc_buf_t out; /* see note above about static */
945
946 ASSERT(chainpp != NULL);
947
948 /*
949 * We _do_ have something to do, right?
950 */
951 if (*chainpp == NULL) {
952 return;
953 }
954
955 /*
956 * We can actually increase throughput by throttling back on attempts to
957 * flush data to IOSRAM, since trying to write every little bit of data
958 * as it shows up will actually generate more delays waiting for the SC
959 * to pick up each of those bits. Instead, we'll avoid attempting to
960 * write data to IOSRAM any faster than half of the polling frequency we
961 * expect the SC to be using.
962 */
963 if (ddi_get_lbolt() - last_flush <
964 drv_usectohz(CVC_IOSRAM_POLL_USECS / 2)) {
965 return;
966 }
967
968 /*
969 * If IOSRAM is inaccessible or the CONO chunk still holds data that
970 * hasn't been picked up by the SC, there's nothing we can do right now.
971 */
972 rval = iosram_get_flag(IOSRAM_KEY_CONO, &dvalid, NULL);
973 if ((rval != 0) || (dvalid == IOSRAM_DATA_VALID)) {
974 if ((rval != 0) && (rval != EAGAIN)) {
975 cmn_err(CE_WARN, "cvc_send_to_iosram: get_flag ret %d",
976 rval);
977 }
978 return;
979 }
980
981 /*
982 * Copy up to MAX_XFER_COUTPUT chars from the mblk chain into a buffer.
983 * Don't change any of the mblks just yet, since we can't be certain
984 * that we'll be successful in writing data to the CONO chunk.
985 */
986 out.count = 0;
987 mp = *chainpp;
988 cp = mp->b_rptr;
989 last_empty_mp = NULL;
990 while ((mp != NULL) && (out.count < MAX_XFER_COUTPUT)) {
991 /*
992 * Process as many of the characters in the current mblk as
993 * possible.
994 */
995 while ((cp != mp->b_wptr) && (out.count < MAX_XFER_COUTPUT)) {
996 out.buffer[out.count++] = *cp++;
997 }
998
999 /*
1000 * Did we process that entire mblk? If so, move on to the next
1001 * one. If not, we're done filling the buffer even if there's
1002 * space left, because apparently there wasn't room to process
1003 * the next character.
1004 */
1005 if (cp != mp->b_wptr) {
1006 break;
1007 }
1008
1009 /*
1010 * When this loop terminates, last_empty_mp will point to the
1011 * last mblk that was completely processed, mp will point to the
1012 * following mblk (or NULL if no more mblks exist), and cp will
1013 * point to the first untransmitted character in the mblk
1014 * pointed to by mp. We'll need this data to update the mblk
1015 * chain if all of the data is successfully transmitted.
1016 */
1017 last_empty_mp = mp;
1018 mp = mp->b_cont;
1019 cp = (mp != NULL) ? mp->b_rptr : NULL;
1020 }
1021
1022 /*
1023 * If we succeeded in preparing some data, try to transmit it through
1024 * IOSRAM. First write the count and the data, which can be done in a
1025 * single operation thanks to the buffer structure we use, then set the
1026 * data_valid flag if the first step succeeded.
1027 */
1028 if (out.count != 0) {
1029 rval = iosram_wr(IOSRAM_KEY_CONO, COUNT_OFFSET,
1030 CONSBUF_COUNT_SIZE + out.count, (caddr_t)&out);
1031 if ((rval != 0) && (rval != EAGAIN)) {
1032 cmn_err(CE_WARN, "cvc_putc: write ret %d", rval);
1033 }
1034
1035 /* if the data write succeeded, set the data_valid flag */
1036 if (rval == 0) {
1037 rval = iosram_set_flag(IOSRAM_KEY_CONO,
1038 IOSRAM_DATA_VALID, IOSRAM_INT_NONE);
1039 if ((rval != 0) && (rval != EAGAIN)) {
1040 cmn_err(CE_WARN,
1041 "cvc_putc: set flags for outbuf ret %d",
1042 rval);
1043 }
1044 }
1045
1046 /*
1047 * If we successfully transmitted any data, modify the caller's
1048 * mblk chain to remove the data that was transmitted, freeing
1049 * all mblks that were completely processed.
1050 */
1051 if (rval == 0) {
1052 last_flush = ddi_get_lbolt();
1053
1054 /*
1055 * If any data is left over, update the b_rptr field of
1056 * the first remaining mblk in case some of its data was
1057 * processed.
1058 */
1059 if (mp != NULL) {
1060 mp->b_rptr = cp;
1061 }
1062
1063 /*
1064 * If any mblks have been emptied, unlink them from the
1065 * residual chain, free them, and update the caller's
1066 * mblk pointer.
1067 */
1068 if (last_empty_mp != NULL) {
1069 last_empty_mp->b_cont = NULL;
1070 freemsg(*chainpp);
1071 *chainpp = mp;
1072 }
1073 }
1074 }
1075 }
1076
1077
1078 /*
1079 * cvc_flush_queue()
1080 * Tell the STREAMS subsystem to schedule cvc_wsrv to process the queue we
1081 * use to gather console output.
1082 */
1083 /* ARGSUSED */
1084 static void
cvc_flush_queue(void * notused)1085 cvc_flush_queue(void *notused)
1086 {
1087 rw_enter(&cvclock, RW_WRITER);
1088 if (cvcinput_q != NULL) {
1089 qenable(WR(cvcinput_q));
1090 }
1091
1092 cvc_timeout_id = (timeout_id_t)-1;
1093 rw_exit(&cvclock);
1094 }
1095
1096
1097 /*
1098 * cvc_getstr()
1099 * Poll IOSRAM for console input while available.
1100 */
1101 static void
cvc_getstr(char * cp)1102 cvc_getstr(char *cp)
1103 {
1104 short count;
1105 uint8_t command = 0;
1106 int rval = ESUCCESS;
1107 uint8_t dvalid = IOSRAM_DATA_INVALID;
1108 uint8_t intrpending = 0;
1109
1110 mutex_enter(&cvc_iosram_input_mutex);
1111 while (dvalid == IOSRAM_DATA_INVALID) {
1112 /*
1113 * Check the CONC data_valid flag to see if a control message is
1114 * available.
1115 */
1116 rval = iosram_get_flag(IOSRAM_KEY_CONC, &dvalid, &intrpending);
1117 if ((rval != 0) && (rval != EAGAIN)) {
1118 cmn_err(CE_WARN,
1119 "cvc_getstr: get flag for cntl ret %d", rval);
1120 }
1121
1122 /*
1123 * If a control message is available, try to read and process
1124 * it.
1125 */
1126 if ((dvalid == IOSRAM_DATA_VALID) && (rval == 0)) {
1127 /* read the control reg offset */
1128 rval = iosram_rd(IOSRAM_KEY_CONC,
1129 CVC_CTL_OFFSET(command), CVC_CTL_SIZE(command),
1130 (caddr_t)&command);
1131 if ((rval != 0) && (rval != EAGAIN)) {
1132 cmn_err(CE_WARN,
1133 "cvc_getstr: read for command ret %d",
1134 rval);
1135 }
1136
1137 /* process the cntl msg and clear the data_valid flag */
1138 if (rval == 0) {
1139 cvc_iosram_ops(command);
1140 }
1141 }
1142
1143 /*
1144 * Check the CONI data_valid flag to see if console input data
1145 * is available.
1146 */
1147 rval = iosram_get_flag(IOSRAM_KEY_CONI, &dvalid, &intrpending);
1148 if ((rval != 0) && (rval != EAGAIN)) {
1149 cmn_err(CE_WARN,
1150 "cvc_getstr: get flag for inbuf ret %d",
1151 rval);
1152 }
1153 if ((rval != 0) || (dvalid != IOSRAM_DATA_VALID)) {
1154 goto retry;
1155 }
1156
1157 /*
1158 * Try to read the count.
1159 */
1160 rval = iosram_rd(IOSRAM_KEY_CONI, COUNT_OFFSET,
1161 CONSBUF_COUNT_SIZE, (caddr_t)&count);
1162 if (rval != 0) {
1163 if (rval != EAGAIN) {
1164 cmn_err(CE_WARN,
1165 "cvc_getstr: read for count ret %d", rval);
1166 }
1167 goto retry;
1168 }
1169
1170 /*
1171 * If there is data to be read, try to read it.
1172 */
1173 if (count != 0) {
1174 rval = iosram_rd(IOSRAM_KEY_CONI, DATA_OFFSET, count,
1175 (caddr_t)cp);
1176 if (rval != 0) {
1177 if (rval != EAGAIN) {
1178 cmn_err(CE_WARN,
1179 "cvc_getstr: read for count ret %d",
1180 rval);
1181 }
1182 goto retry;
1183 }
1184 cp[count] = '\0';
1185 }
1186
1187 /*
1188 * Try to clear the data_valid flag to indicate that whatever
1189 * was in CONI was read successfully. If successful, and some
1190 * data was read, break out of the loop to return to the caller.
1191 */
1192 rval = iosram_set_flag(IOSRAM_KEY_CONI, IOSRAM_DATA_INVALID,
1193 IOSRAM_INT_NONE);
1194 if (rval != 0) {
1195 if (rval != EAGAIN) {
1196 cmn_err(CE_WARN,
1197 "cvc_getstr: set flag for inbuf ret %d",
1198 rval);
1199 }
1200 } else if (count != 0) {
1201 CVC_DBG1(CVC_DBG_IOSRAM_RD, "Read 0x%x", count);
1202 break;
1203 }
1204
1205 /*
1206 * Use a smaller delay between checks of IOSRAM for input
1207 * when cvcd/cvcredir are not running or "via_iosram" has
1208 * been set.
1209 * We don't go away completely when i/o is going through the
1210 * network via cvcd since a command may be sent via IOSRAM
1211 * to switch if the network is down or hung.
1212 */
1213 retry:
1214 if ((cvcoutput_q == NULL) || (via_iosram))
1215 delay(drv_usectohz(CVC_IOSRAM_POLL_USECS));
1216 else
1217 delay(drv_usectohz(CVC_IOSRAM_POLL_USECS * 10));
1218
1219 }
1220
1221 mutex_exit(&cvc_iosram_input_mutex);
1222 }
1223
1224
1225 /*
1226 * cvc_input_daemon()
1227 * this function runs as a separate kernel thread and polls IOSRAM for
1228 * input, and possibly put it on read stream for the console.
1229 * There are two poll rates (implemented in cvc_getstr):
1230 * 100 000 uS (10 Hz) - no cvcd communications || via_iosram
1231 * 1000 000 uS ( 1 Hz) - cvcd communications
1232 * This continues to run even if there are network console communications
1233 * in order to handle out-of-band signaling.
1234 */
1235 /* ARGSUSED */
1236 static void
cvc_input_daemon(void)1237 cvc_input_daemon(void)
1238 {
1239 char linebuf[MAX_XFER_CINPUT + 1];
1240 char *cp;
1241 mblk_t *mbp;
1242 int c;
1243 int dropped_read = 0;
1244
1245 for (;;) {
1246 cvc_getstr(linebuf);
1247
1248 mbp = allocb(strlen(linebuf), BPRI_MED);
1249 if (mbp == NULL) { /* drop it & go on if no buffer */
1250 if (!dropped_read) {
1251 cmn_err(CE_WARN, "cvc_input_daemon: "
1252 "dropping IOSRAM reads");
1253 }
1254 dropped_read++;
1255 continue;
1256 }
1257
1258 if (dropped_read) {
1259 cmn_err(CE_WARN,
1260 "cvc_input_daemon: dropped %d IOSRAM reads",
1261 dropped_read);
1262 dropped_read = 0;
1263 }
1264
1265 for (cp = linebuf; *cp != '\0'; cp++) {
1266 c = (int)*cp;
1267 if (c == '\r')
1268 c = '\n';
1269 c &= 0177;
1270 *mbp->b_wptr = (char)c;
1271 mbp->b_wptr++;
1272 }
1273 mutex_enter(&cvcmutex);
1274 if (input_ok) {
1275 if (cvcinput_q == NULL) {
1276 cmn_err(CE_WARN,
1277 "cvc_input_daemon: cvcinput_q is NULL!");
1278 } else {
1279 /*
1280 * XXX - should canputnext be called here?
1281 * Starfire's cvc doesn't do that, and it
1282 * appears to work anyway.
1283 */
1284 (void) putnext(cvcinput_q, mbp);
1285 }
1286 } else {
1287 freemsg(mbp);
1288 }
1289 mutex_exit(&cvcmutex);
1290 }
1291
1292 /* NOTREACHED */
1293 }
1294
1295 /*
1296 * cvc_win_resize()
1297 * cvc_win_resize will read winsize data from the CONC IOSRAM chunk and set
1298 * the console window size accordingly. If indicated by the caller, CONC's
1299 * data_valid flag will also be cleared. The flag isn't cleared in all
1300 * cases because we need to process winsize data at startup without waiting
1301 * for a command.
1302 */
1303 static void
cvc_win_resize(int clear_flag)1304 cvc_win_resize(int clear_flag)
1305 {
1306 int rval;
1307 uint16_t rows;
1308 uint16_t cols;
1309 uint16_t xpixels;
1310 uint16_t ypixels;
1311 tty_common_t *tty;
1312 cvc_t *cp;
1313 struct winsize ws;
1314
1315 /*
1316 * Start by reading the new window size out of the CONC chunk and, if
1317 * requested, clearing CONC's data_valid flag. If any of that fails,
1318 * return immediately. (Note that the rather bulky condition in the
1319 * two "if" statements takes advantage of C's short-circuit logic
1320 * evaluation)
1321 */
1322 if (((rval = iosram_rd(IOSRAM_KEY_CONC, CVC_CTL_OFFSET(winsize_rows),
1323 CVC_CTL_SIZE(winsize_rows), (caddr_t)&rows)) != 0) ||
1324 ((rval = iosram_rd(IOSRAM_KEY_CONC, CVC_CTL_OFFSET(winsize_cols),
1325 CVC_CTL_SIZE(winsize_cols), (caddr_t)&cols)) != 0) ||
1326 ((rval = iosram_rd(IOSRAM_KEY_CONC,
1327 CVC_CTL_OFFSET(winsize_xpixels), CVC_CTL_SIZE(winsize_xpixels),
1328 (caddr_t)&xpixels)) != 0) || ((rval = iosram_rd(IOSRAM_KEY_CONC,
1329 CVC_CTL_OFFSET(winsize_ypixels), CVC_CTL_SIZE(winsize_ypixels),
1330 (caddr_t)&ypixels)) != 0)) {
1331 if (rval != EAGAIN) {
1332 cmn_err(CE_WARN,
1333 "cvc_win_resize: read for ctlbuf ret %d", rval);
1334 }
1335 return;
1336 }
1337
1338 if (clear_flag && ((rval = iosram_set_flag(IOSRAM_KEY_CONC,
1339 IOSRAM_DATA_INVALID, IOSRAM_INT_NONE)) != 0)) {
1340 if (rval != EAGAIN) {
1341 cmn_err(CE_WARN,
1342 "cvc_win_resize: set_flag for ctlbuf ret %d", rval);
1343 }
1344 return;
1345 }
1346
1347 /*
1348 * Copy the parameters from IOSRAM to a winsize struct.
1349 */
1350 ws.ws_row = rows;
1351 ws.ws_col = cols;
1352 ws.ws_xpixel = xpixels;
1353 ws.ws_ypixel = ypixels;
1354
1355 /*
1356 * This code was taken from Starfire, and it appears to work correctly.
1357 * However, since the original developer felt it necessary to add the
1358 * following comment, it's probably worth preserving:
1359 *
1360 * XXX I hope this is safe...
1361 */
1362 cp = cvcinput_q->q_ptr;
1363 tty = &cp->cvc_tty;
1364 mutex_enter(&tty->t_excl);
1365 if (bcmp((caddr_t)&tty->t_size, (caddr_t)&ws,
1366 sizeof (struct winsize))) {
1367 tty->t_size = ws;
1368 mutex_exit(&tty->t_excl);
1369 (void) putnextctl1(cvcinput_q, M_PCSIG,
1370 SIGWINCH);
1371 } else {
1372 mutex_exit(&tty->t_excl);
1373 }
1374 }
1375
1376 #ifdef DEBUG
1377
1378 void
cvc_dbg(uint32_t flag,char * fmt,uintptr_t a1,uintptr_t a2,uintptr_t a3,uintptr_t a4,uintptr_t a5)1379 cvc_dbg(uint32_t flag, char *fmt,
1380 uintptr_t a1, uintptr_t a2, uintptr_t a3, uintptr_t a4, uintptr_t a5)
1381 {
1382 char *s = NULL;
1383 char buf[256];
1384
1385 if (cvc_dbg_flags && ((cvc_dbg_flags & flag) == flag)) {
1386 switch (flag) {
1387 case CVC_DBG_ATTACH:
1388 s = "attach";
1389 break;
1390 case CVC_DBG_DETACH:
1391 s = "detach";
1392 break;
1393 case CVC_DBG_OPEN:
1394 s = "open";
1395 break;
1396 case CVC_DBG_CLOSE:
1397 s = "close";
1398 break;
1399 case CVC_DBG_IOCTL:
1400 s = "ioctl";
1401 break;
1402 case CVC_DBG_REDIR:
1403 s = "redir";
1404 break;
1405 case CVC_DBG_WPUT:
1406 s = "wput";
1407 break;
1408 case CVC_DBG_WSRV:
1409 s = "wsrv";
1410 break;
1411 case CVC_DBG_IOSRAM_WR:
1412 s = "iosram_wr";
1413 break;
1414 case CVC_DBG_IOSRAM_RD:
1415 s = "iosram_rd";
1416 break;
1417 case CVC_DBG_NETWORK_WR:
1418 s = "network_wr";
1419 break;
1420 case CVC_DBG_NETWORK_RD:
1421 s = "network_rd";
1422 break;
1423 case CVC_DBG_IOSRAM_CNTL:
1424 s = "iosram_cntlmsg";
1425 break;
1426 default:
1427 s = "Unknown debug flag";
1428 break;
1429 }
1430
1431 (void) sprintf(buf, "!%s_%s(%d): %s", ddi_driver_name(cvcdip),
1432 s, cvc_instance, fmt);
1433 cmn_err(CE_NOTE, buf, a1, a2, a3, a4, a5);
1434 }
1435 }
1436
1437 #endif /* DEBUG */
1438