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 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 (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 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 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 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 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 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 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 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 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 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 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 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 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 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