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