1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 /* 29 * DM2S - Domain side Mailbox to synchronous serial device driver. 30 * 31 * Description: 32 * ----------- 33 * It is a streams driver which simulates a sync serial device on 34 * top of a mailbox type of communication. That is, it sends/receives 35 * frames as mailbox messages. The mailbox communication is provided 36 * by another driver, which exports the mailbox interfaces. 37 * 38 * Synchronization: 39 * --------------- 40 * This driver uses streams perimeters to simplify the synchronization. 41 * An inner perimeter D_MTPERMOD which protects the entire module, 42 * that is only one thread exists inside the perimeter, is used. As 43 * this driver supports only one instance and is not a high-performance 44 * driver, D_MTPERMOD is highly suitable. 45 * 46 * All transmission and reception of frames is done inside the service 47 * procedures so that all streams related operations are protected 48 * by the perimeters. 49 * 50 * The mailbox event handler is the only asynchronous callback which 51 * needs to be protected outside of the streams perimeters. This is 52 * done using the module private lock('ms_lock'); 53 * 54 */ 55 56 #include <sys/types.h> 57 #include <sys/param.h> 58 #include <sys/stream.h> 59 #include <sys/cred.h> 60 #include <sys/systm.h> 61 #include <sys/sunddi.h> 62 #include <sys/ddi.h> 63 #include <sys/conf.h> 64 #include <sys/modctl.h> 65 #include <sys/mkdev.h> 66 #include <sys/errno.h> 67 #include <sys/debug.h> 68 #include <sys/kbio.h> 69 #include <sys/kmem.h> 70 #include <sys/consdev.h> 71 #include <sys/file.h> 72 #include <sys/stropts.h> 73 #include <sys/strsun.h> 74 #include <sys/dlpi.h> 75 #include <sys/stat.h> 76 #include <sys/ser_sync.h> 77 #include <sys/sysmacros.h> 78 #include <sys/note.h> 79 #include <sys/sdt.h> 80 81 #include <sys/scfd/scfdscpif.h> 82 #include <sys/dm2s.h> 83 84 85 #define DM2S_MODNAME "dm2s" /* Module name */ 86 #define DM2S_TARGET_ID 0 /* Target ID of the peer */ 87 #define DM2S_ID_NUM 0x4D53 /* 'M''S' */ 88 #define DM2S_DEF_MTU 1504 /* Def. MTU size + PPP bytes */ 89 #define DM2S_MAXPSZ DM2S_DEF_MTU /* Set it to the default MTU */ 90 #define DM2S_LOWAT (4 * 1024) /* Low water mark */ 91 #define DM2S_HIWAT (12 * 1024) /* High water mark */ 92 #define DM2S_SM_TOUT 5000 /* Small timeout (5msec) */ 93 #define DM2S_LG_TOUT 50000 /* Large timeout (50msec) */ 94 #define DM2S_MB_TOUT 10000000 /* Mailbox timeout (10sec) */ 95 96 /* 97 * Global variables 98 */ 99 void *dm2s_softstate = NULL; /* Softstate pointer */ 100 101 102 /* 103 * Prototypes for the module related functions. 104 */ 105 int dm2s_attach(dev_info_t *dip, ddi_attach_cmd_t cmd); 106 int dm2s_detach(dev_info_t *dip, ddi_detach_cmd_t cmd); 107 int dm2s_info(dev_info_t *dip, ddi_info_cmd_t infocmd, 108 void *arg, void **result); 109 110 /* 111 * Prototypes for the streams related functions. 112 */ 113 int dm2s_open(queue_t *rq, dev_t *dev, int flag, int sflag, cred_t *cr); 114 int dm2s_close(queue_t *rq, int flag, cred_t *cred); 115 int dm2s_wput(queue_t *wq, mblk_t *mp); 116 int dm2s_rsrv(queue_t *rq); 117 int dm2s_wsrv(queue_t *wq); 118 119 /* 120 * Prototypes for the internal functions. 121 */ 122 void dm2s_start(queue_t *wq, dm2s_t *dm2sp); 123 void dm2s_event_handler(scf_event_t event, void *arg); 124 int dm2s_transmit(queue_t *wq, mblk_t *mp, target_id_t target, mkey_t key); 125 void dm2s_receive(dm2s_t *dm2sp); 126 void dm2s_wq_timeout(void *arg); 127 void dm2s_rq_timeout(void *arg); 128 void dm2s_bufcall_rcv(void *arg); 129 static clock_t dm2s_timeout_val(int error); 130 static void dm2s_cleanup(dm2s_t *dm2sp); 131 static int dm2s_mbox_init(dm2s_t *dm2sp); 132 static void dm2s_mbox_fini(dm2s_t *dm2sp); 133 static int dm2s_prep_scatgath(mblk_t *mp, uint32_t *numsg, 134 mscat_gath_t *sgp, int maxsg); 135 136 #ifdef DEBUG 137 uint32_t dm2s_debug = DBG_WARN; 138 #endif /* DEBUG */ 139 140 141 /* 142 * Streams and module related structures. 143 */ 144 struct module_info dm2s_module_info = { 145 DM2S_ID_NUM, /* module ID number */ 146 DM2S_MODNAME, /* module name. */ 147 0, /* Minimum packet size (none) */ 148 DM2S_MAXPSZ, /* Maximum packet size (none) */ 149 DM2S_HIWAT, /* queue high water mark */ 150 DM2S_LOWAT /* queue low water mark */ 151 }; 152 153 struct qinit dm2s_rinit = { 154 putq, /* qi_putp */ 155 dm2s_rsrv, /* qi_srvp */ 156 dm2s_open, /* qi_qopen */ 157 dm2s_close, /* qi_qlcose */ 158 NULL, /* qi_qadmin */ 159 &dm2s_module_info, /* qi_minfo */ 160 NULL /* qi_mstat */ 161 }; 162 163 struct qinit dm2s_winit = { 164 dm2s_wput, /* qi_putp */ 165 dm2s_wsrv, /* qi_srvp */ 166 NULL, /* qi_qopen */ 167 NULL, /* qi_qlcose */ 168 NULL, /* qi_qadmin */ 169 &dm2s_module_info, /* qi_minfo */ 170 NULL /* qi_mstat */ 171 }; 172 173 174 struct streamtab dm2s_streamtab = { 175 &dm2s_rinit, 176 &dm2s_winit, 177 NULL, 178 NULL 179 }; 180 181 DDI_DEFINE_STREAM_OPS(dm2s_ops, nulldev, nulldev, dm2s_attach, \ 182 dm2s_detach, nodev, dm2s_info, D_NEW | D_MP | D_MTPERMOD, \ 183 &dm2s_streamtab); 184 185 186 struct modldrv modldrv = { 187 &mod_driverops, 188 "OPL Mbox to Serial Driver %I%", 189 &dm2s_ops 190 }; 191 192 struct modlinkage modlinkage = { 193 MODREV_1, 194 &modldrv, 195 NULL 196 }; 197 198 199 /* 200 * _init - Module's init routine. 201 */ 202 int 203 _init(void) 204 { 205 int ret; 206 207 if (ddi_soft_state_init(&dm2s_softstate, sizeof (dm2s_t), 1) != 0) { 208 cmn_err(CE_WARN, "softstate initialization failed\n"); 209 return (DDI_FAILURE); 210 } 211 if ((ret = mod_install(&modlinkage)) != 0) { 212 cmn_err(CE_WARN, "mod_install failed, error = %d", ret); 213 ddi_soft_state_fini(&dm2s_softstate); 214 } 215 return (ret); 216 } 217 218 /* 219 * _fini - Module's fini routine. 220 */ 221 int 222 _fini(void) 223 { 224 int ret; 225 226 if ((ret = mod_remove(&modlinkage)) != 0) { 227 return (ret); 228 } 229 ddi_soft_state_fini(&dm2s_softstate); 230 return (ret); 231 } 232 233 /* 234 * _info - Module's info routine. 235 */ 236 int 237 _info(struct modinfo *modinfop) 238 { 239 return (mod_info(&modlinkage, modinfop)); 240 } 241 242 /* 243 * dm2s_attach - Module's attach routine. 244 */ 245 int 246 dm2s_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 247 { 248 int instance; 249 dm2s_t *dm2sp; 250 char name[20]; 251 252 253 instance = ddi_get_instance(dip); 254 255 /* Only one instance is supported. */ 256 if (instance != 0) { 257 cmn_err(CE_WARN, "only one instance is supported"); 258 return (DDI_FAILURE); 259 } 260 261 if (cmd != DDI_ATTACH) { 262 return (DDI_FAILURE); 263 } 264 if (ddi_soft_state_zalloc(dm2s_softstate, instance) != DDI_SUCCESS) { 265 cmn_err(CE_WARN, "softstate allocation failure"); 266 return (DDI_FAILURE); 267 } 268 dm2sp = (dm2s_t *)ddi_get_soft_state(dm2s_softstate, instance); 269 if (dm2sp == NULL) { 270 ddi_soft_state_free(dm2s_softstate, instance); 271 cmn_err(CE_WARN, "softstate allocation failure."); 272 return (DDI_FAILURE); 273 } 274 dm2sp->ms_dip = dip; 275 dm2sp->ms_major = ddi_name_to_major(ddi_get_name(dip)); 276 dm2sp->ms_ppa = instance; 277 278 /* 279 * Get an interrupt block cookie corresponding to the 280 * interrupt priority of the event handler. 281 * Assert that the event priority is not re-defined to 282 * some higher priority. 283 */ 284 /* LINTED */ 285 ASSERT(SCF_EVENT_PRI == DDI_SOFTINT_LOW); 286 if (ddi_get_soft_iblock_cookie(dip, SCF_EVENT_PRI, 287 &dm2sp->ms_ibcookie) != DDI_SUCCESS) { 288 cmn_err(CE_WARN, "ddi_get_soft_iblock_cookie failed."); 289 goto error; 290 } 291 mutex_init(&dm2sp->ms_lock, NULL, MUTEX_DRIVER, 292 (void *)dm2sp->ms_ibcookie); 293 294 dm2sp->ms_clean |= DM2S_CLEAN_LOCK; 295 cv_init(&dm2sp->ms_wait, NULL, CV_DRIVER, NULL); 296 dm2sp->ms_clean |= DM2S_CLEAN_CV; 297 298 (void) sprintf(name, "%s%d", DM2S_MODNAME, instance); 299 if (ddi_create_minor_node(dip, name, S_IFCHR, instance, 300 DDI_PSEUDO, NULL) == DDI_FAILURE) { 301 ddi_remove_minor_node(dip, NULL); 302 cmn_err(CE_WARN, "Device node creation failed."); 303 goto error; 304 } 305 306 dm2sp->ms_clean |= DM2S_CLEAN_NODE; 307 ddi_set_driver_private(dip, (caddr_t)dm2sp); 308 ddi_report_dev(dip); 309 return (DDI_SUCCESS); 310 error: 311 dm2s_cleanup(dm2sp); 312 return (DDI_FAILURE); 313 } 314 315 /* 316 * dm2s_info - Module's info routine. 317 */ 318 /*ARGSUSED*/ 319 int 320 dm2s_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 321 { 322 dm2s_t *dm2sp; 323 minor_t minor; 324 int ret = DDI_FAILURE; 325 326 switch (infocmd) { 327 case DDI_INFO_DEVT2DEVINFO: 328 minor = getminor((dev_t)arg); 329 dm2sp = (dm2s_t *)ddi_get_soft_state(dm2s_softstate, minor); 330 if (dm2sp == NULL) { 331 *result = NULL; 332 } else { 333 *result = dm2sp->ms_dip; 334 ret = DDI_SUCCESS; 335 } 336 break; 337 338 case DDI_INFO_DEVT2INSTANCE: 339 minor = getminor((dev_t)arg); 340 *result = (void *)(uintptr_t)minor; 341 ret = DDI_SUCCESS; 342 break; 343 344 default: 345 break; 346 } 347 return (ret); 348 } 349 350 /* 351 * dm2s_detach - Module's detach routine. 352 */ 353 int 354 dm2s_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 355 { 356 int instance; 357 dm2s_t *dm2sp; 358 359 if (cmd != DDI_DETACH) { 360 return (DDI_FAILURE); 361 } 362 363 instance = ddi_get_instance(dip); 364 dm2sp = (dm2s_t *)ddi_get_soft_state(dm2s_softstate, instance); 365 if (dm2sp == NULL) { 366 return (DDI_FAILURE); 367 } 368 369 mutex_enter(&dm2sp->ms_lock); 370 371 /* Check if the mailbox is still in use. */ 372 if (dm2sp->ms_state & DM2S_MB_INITED) { 373 mutex_exit(&dm2sp->ms_lock); 374 cmn_err(CE_WARN, "Mailbox in use: Detach failed"); 375 return (DDI_FAILURE); 376 } 377 mutex_exit(&dm2sp->ms_lock); 378 dm2s_cleanup(dm2sp); 379 return (DDI_SUCCESS); 380 } 381 382 /* 383 * dm2s_open - Device open routine. 384 * 385 * Only one open supported. Clone open is not supported. 386 */ 387 /* ARGSUSED */ 388 int 389 dm2s_open(queue_t *rq, dev_t *dev, int flag, int sflag, cred_t *cr) 390 { 391 dm2s_t *dm2sp; 392 int instance = getminor(*dev); 393 int ret = 0; 394 395 DPRINTF(DBG_DRV, ("dm2s_open: called\n")); 396 if (sflag == CLONEOPEN) { 397 /* Clone open not supported */ 398 DPRINTF(DBG_WARN, ("dm2s_open: clone open not supported\n")); 399 return (ENOTSUP); 400 } 401 402 if (rq->q_ptr != NULL) { 403 DPRINTF(DBG_WARN, ("dm2s_open: already opened\n")); 404 return (EBUSY); 405 } 406 407 if ((dm2sp = ddi_get_soft_state(dm2s_softstate, instance)) == NULL) { 408 DPRINTF(DBG_WARN, ("dm2s_open: instance not found\n")); 409 return (ENODEV); 410 } 411 412 mutex_enter(&dm2sp->ms_lock); 413 if (dm2sp->ms_state & DM2S_OPENED) { 414 /* Only one open supported */ 415 mutex_exit(&dm2sp->ms_lock); 416 DPRINTF(DBG_WARN, ("dm2s_open: already opened\n")); 417 return (EBUSY); 418 } 419 420 dm2sp->ms_state |= DM2S_OPENED; 421 /* Initialize the mailbox. */ 422 if ((ret = dm2s_mbox_init(dm2sp)) != 0) { 423 dm2sp->ms_state = 0; 424 mutex_exit(&dm2sp->ms_lock); 425 return (ret); 426 } 427 rq->q_ptr = WR(rq)->q_ptr = (void *)dm2sp; 428 dm2sp->ms_rq = rq; 429 dm2sp->ms_wq = WR(rq); 430 mutex_exit(&dm2sp->ms_lock); 431 432 if (ret == 0) { 433 qprocson(rq); /* now schedule our queue */ 434 } 435 DPRINTF(DBG_DRV, ("dm2s_open: ret=%d\n", ret)); 436 return (ret); 437 } 438 439 /* 440 * dm2s_close - Device close routine. 441 */ 442 /* ARGSUSED */ 443 int 444 dm2s_close(queue_t *rq, int flag, cred_t *cred) 445 { 446 dm2s_t *dm2sp = (dm2s_t *)rq->q_ptr; 447 448 DPRINTF(DBG_DRV, ("dm2s_close: called\n")); 449 if (dm2sp == NULL) { 450 /* Already closed once */ 451 return (ENODEV); 452 } 453 454 /* Close the lower layer first */ 455 mutex_enter(&dm2sp->ms_lock); 456 (void) scf_mb_flush(dm2sp->ms_target, dm2sp->ms_key, MB_FLUSH_ALL); 457 dm2s_mbox_fini(dm2sp); 458 mutex_exit(&dm2sp->ms_lock); 459 460 /* 461 * Now we can assume that no asynchronous callbacks exist. 462 * Poison the stream head so that we can't be pushed again. 463 */ 464 (void) putnextctl(rq, M_HANGUP); 465 qprocsoff(rq); 466 if (dm2sp->ms_rbufcid != 0) { 467 qunbufcall(rq, dm2sp->ms_rbufcid); 468 dm2sp->ms_rbufcid = 0; 469 } 470 if (dm2sp->ms_rq_timeoutid != 0) { 471 DTRACE_PROBE1(dm2s_rqtimeout__cancel, dm2s_t, dm2sp); 472 (void) quntimeout(dm2sp->ms_rq, dm2sp->ms_rq_timeoutid); 473 dm2sp->ms_rq_timeoutid = 0; 474 } 475 if (dm2sp->ms_wq_timeoutid != 0) { 476 DTRACE_PROBE1(dm2s_wqtimeout__cancel, dm2s_t, dm2sp); 477 (void) quntimeout(dm2sp->ms_wq, dm2sp->ms_wq_timeoutid); 478 dm2sp->ms_wq_timeoutid = 0; 479 } 480 /* 481 * Now we can really mark it closed. 482 */ 483 mutex_enter(&dm2sp->ms_lock); 484 dm2sp->ms_rq = dm2sp->ms_wq = NULL; 485 dm2sp->ms_state &= ~DM2S_OPENED; 486 mutex_exit(&dm2sp->ms_lock); 487 488 rq->q_ptr = WR(rq)->q_ptr = NULL; 489 (void) qassociate(rq, -1); 490 DPRINTF(DBG_DRV, ("dm2s_close: successfully closed\n")); 491 return (0); 492 } 493 494 /* 495 * dm2s_rsrv - Streams read side service procedure. 496 * 497 * All messages are received in the service procedure 498 * only. This is done to simplify the streams synchronization. 499 */ 500 int 501 dm2s_rsrv(queue_t *rq) 502 { 503 mblk_t *mp; 504 dm2s_t *dm2sp = (dm2s_t *)rq->q_ptr; 505 506 DPRINTF(DBG_DRV, ("dm2s_rsrv: called\n")); 507 ASSERT(dm2sp != NULL); 508 mutex_enter(&dm2sp->ms_lock); 509 510 /* Receive if there are any messages waiting in the mailbox. */ 511 dm2s_receive(dm2sp); 512 mutex_exit(&dm2sp->ms_lock); 513 514 /* Send the received messages up the stream. */ 515 while ((mp = getq(rq)) != NULL) { 516 if (canputnext(rq)) { 517 putnext(rq, mp); 518 } else { 519 putbq(rq, mp); 520 break; 521 } 522 } 523 DPRINTF(DBG_DRV, ("dm2s_rsrv: return\n")); 524 return (0); 525 } 526 527 /* 528 * dm2s_wsrv - Streams write side service procedure. 529 * 530 * All messages are transmitted in the service procedure 531 * only. This is done to simplify the streams synchronization. 532 */ 533 int 534 dm2s_wsrv(queue_t *wq) 535 { 536 dm2s_t *dm2sp = (dm2s_t *)wq->q_ptr; 537 538 DPRINTF(DBG_DRV, ("dm2s_wsrv: called\n")); 539 ASSERT(dm2sp != NULL); 540 /* Lets cancel any timeouts waiting to be scheduled. */ 541 if (dm2sp->ms_wq_timeoutid != 0) { 542 DTRACE_PROBE1(dm2s_wqtimeout__cancel, dm2s_t, dm2sp); 543 (void) quntimeout(dm2sp->ms_wq, dm2sp->ms_wq_timeoutid); 544 dm2sp->ms_wq_timeoutid = 0; 545 } 546 mutex_enter(&dm2sp->ms_lock); 547 dm2s_start(wq, dm2sp); 548 mutex_exit(&dm2sp->ms_lock); 549 DPRINTF(DBG_DRV, ("dm2s_wsrv: return\n")); 550 return (0); 551 } 552 553 /* 554 * dm2s_wput - Streams write side put routine. 555 * 556 * All M_DATA messages are queued so that they are transmitted in 557 * the service procedure. This is done to simplify the streams 558 * synchronization. Other messages are handled appropriately. 559 */ 560 int 561 dm2s_wput(queue_t *wq, mblk_t *mp) 562 { 563 dm2s_t *dm2sp = (dm2s_t *)wq->q_ptr; 564 565 DPRINTF(DBG_DRV, ("dm2s_wput: called\n")); 566 if (dm2sp == NULL) { 567 return (ENODEV); /* Can't happen. */ 568 } 569 570 switch (mp->b_datap->db_type) { 571 case (M_DATA): 572 DPRINTF(DBG_DRV, ("dm2s_wput: M_DATA message\n")); 573 while (mp->b_wptr == mp->b_rptr) { 574 mblk_t *mp1; 575 576 mp1 = unlinkb(mp); 577 freemsg(mp); 578 mp = mp1; 579 if (mp == NULL) { 580 return (0); 581 } 582 } 583 584 /* 585 * Simply queue the message and handle it in the service 586 * procedure. 587 */ 588 (void) putq(wq, mp); 589 qenable(wq); 590 return (0); 591 592 case (M_PROTO): 593 DPRINTF(DBG_DRV, ("dm2s_wput: M_PROTO message\n")); 594 /* We don't expect this */ 595 mp->b_datap->db_type = M_ERROR; 596 mp->b_rptr = mp->b_wptr = mp->b_datap->db_base; 597 *mp->b_wptr++ = EPROTO; 598 qreply(wq, mp); 599 return (EINVAL); 600 601 case (M_IOCTL): 602 DPRINTF(DBG_DRV, ("dm2s_wput: M_IOCTL message\n")); 603 if (MBLKL(mp) < sizeof (struct iocblk)) { 604 freemsg(mp); 605 return (0); 606 } 607 /* 608 * No ioctls required to be supported by this driver, so 609 * return EINVAL for all ioctls. 610 */ 611 miocnak(wq, mp, 0, EINVAL); 612 break; 613 614 case (M_CTL): 615 DPRINTF(DBG_DRV, ("dm2s_wput: M_CTL message\n")); 616 /* 617 * No M_CTL messages need to supported by this driver, 618 * so simply ignore them. 619 */ 620 freemsg(mp); 621 break; 622 623 case (M_FLUSH): 624 DPRINTF(DBG_DRV, ( 625 "dm2s_wput: M_FLUSH message 0x%X\n", *mp->b_rptr)); 626 if (*mp->b_rptr & FLUSHW) { /* Flush write-side */ 627 (void) scf_mb_flush(dm2sp->ms_target, dm2sp->ms_key, 628 MB_FLUSH_SEND); 629 flushq(wq, FLUSHDATA); 630 *mp->b_rptr &= ~FLUSHW; 631 } 632 if (*mp->b_rptr & FLUSHR) { 633 (void) scf_mb_flush(dm2sp->ms_target, dm2sp->ms_key, 634 MB_FLUSH_RECEIVE); 635 flushq(RD(wq), FLUSHDATA); 636 qreply(wq, mp); 637 } else { 638 freemsg(mp); 639 } 640 break; 641 642 default: 643 DPRINTF(DBG_DRV, ("dm2s_wput: UNKNOWN message\n")); 644 freemsg(mp); 645 646 } 647 return (0); 648 } 649 650 /* 651 * dm2s_cleanup - Cleanup routine. 652 */ 653 static void 654 dm2s_cleanup(dm2s_t *dm2sp) 655 { 656 char name[20]; 657 658 DPRINTF(DBG_DRV, ("dm2s_cleanup: called\n")); 659 ASSERT(dm2sp != NULL); 660 if (dm2sp->ms_clean & DM2S_CLEAN_NODE) { 661 (void) sprintf(name, "%s%d", DM2S_MODNAME, dm2sp->ms_ppa); 662 ddi_remove_minor_node(dm2sp->ms_dip, name); 663 } 664 if (dm2sp->ms_clean & DM2S_CLEAN_LOCK) 665 mutex_destroy(&dm2sp->ms_lock); 666 if (dm2sp->ms_clean & DM2S_CLEAN_CV) 667 cv_destroy(&dm2sp->ms_wait); 668 ddi_set_driver_private(dm2sp->ms_dip, NULL); 669 ddi_soft_state_free(dm2s_softstate, dm2sp->ms_ppa); 670 } 671 672 /* 673 * dm2s_mbox_init - Mailbox specific initialization. 674 */ 675 static int 676 dm2s_mbox_init(dm2s_t *dm2sp) 677 { 678 int ret; 679 clock_t tout; 680 681 ASSERT(MUTEX_HELD(&dm2sp->ms_lock)); 682 dm2sp->ms_target = DM2S_TARGET_ID; 683 dm2sp->ms_key = DSCP_KEY; 684 dm2sp->ms_state &= ~DM2S_MB_INITED; 685 686 /* Iterate until mailbox gets connected */ 687 while (!(dm2sp->ms_state & DM2S_MB_CONN)) { 688 DPRINTF(DBG_MBOX, ("dm2s_mbox_init: calling mb_init\n")); 689 ret = scf_mb_init(dm2sp->ms_target, dm2sp->ms_key, 690 dm2s_event_handler, (void *)dm2sp); 691 DPRINTF(DBG_MBOX, ("dm2s_mbox_init: mb_init ret=%d\n", ret)); 692 693 if (ret == 0) { 694 dm2sp->ms_state |= DM2S_MB_INITED; 695 696 /* Block until the mailbox is ready to communicate. */ 697 while (!(dm2sp->ms_state & 698 (DM2S_MB_CONN | DM2S_MB_DISC))) { 699 700 if (cv_wait_sig(&dm2sp->ms_wait, 701 &dm2sp->ms_lock) <= 0) { 702 /* interrupted */ 703 ret = EINTR; 704 break; 705 } 706 } 707 } 708 709 if (ret != 0) { 710 711 DPRINTF(DBG_MBOX, 712 ("dm2s_mbox_init: failed/interrupted\n")); 713 DTRACE_PROBE1(dm2s_mbox_fail, int, ret); 714 dm2sp->ms_state &= ~DM2S_MB_INITED; 715 (void) scf_mb_fini(dm2sp->ms_target, dm2sp->ms_key); 716 717 /* if interrupted, return immediately. */ 718 if (ret == EINTR) 719 return (ret); 720 721 } 722 723 if ((ret != 0) || (dm2sp->ms_state & DM2S_MB_DISC)) { 724 725 DPRINTF(DBG_WARN, 726 ("dm2s_mbox_init: mbox DISC_ERROR\n")); 727 DTRACE_PROBE1(dm2s_mbox_fail, int, DM2S_MB_DISC); 728 dm2sp->ms_state &= ~DM2S_MB_INITED; 729 (void) scf_mb_fini(dm2sp->ms_target, dm2sp->ms_key); 730 731 /* 732 * If there was failure, then wait for 733 * DM2S_MB_TOUT secs and retry again. 734 */ 735 736 DPRINTF(DBG_MBOX, ("dm2s_mbox_init: waiting...\n")); 737 tout = ddi_get_lbolt() + drv_usectohz(DM2S_MB_TOUT); 738 ret = cv_timedwait_sig(&dm2sp->ms_wait, 739 &dm2sp->ms_lock, tout); 740 if (ret == 0) { 741 /* if interrupted, return immediately. */ 742 DPRINTF(DBG_MBOX, 743 ("dm2s_mbox_init: interrupted\n")); 744 return (EINTR); 745 } 746 } 747 } 748 749 /* 750 * Obtain the max size of a single message. 751 * NOTE: There is no mechanism to update the 752 * upperlayers dynamically, so we expect this 753 * size to be atleast the default MTU size. 754 */ 755 ret = scf_mb_ctrl(dm2sp->ms_target, dm2sp->ms_key, 756 SCF_MBOP_MAXMSGSIZE, &dm2sp->ms_mtu); 757 758 if ((ret == 0) && (dm2sp->ms_mtu < DM2S_DEF_MTU)) { 759 cmn_err(CE_WARN, "Max message size expected >= %d " 760 "but found %d\n", DM2S_DEF_MTU, dm2sp->ms_mtu); 761 ret = EIO; 762 } 763 764 if (ret != 0) { 765 dm2sp->ms_state &= ~DM2S_MB_INITED; 766 (void) scf_mb_fini(dm2sp->ms_target, dm2sp->ms_key); 767 } 768 DPRINTF(DBG_MBOX, ("dm2s_mbox_init: mb_init ret=%d\n", ret)); 769 return (ret); 770 } 771 772 /* 773 * dm2s_mbox_fini - Mailbox de-initialization. 774 */ 775 static void 776 dm2s_mbox_fini(dm2s_t *dm2sp) 777 { 778 int ret; 779 780 ASSERT(dm2sp != NULL); 781 if (dm2sp->ms_state & DM2S_MB_INITED) { 782 DPRINTF(DBG_MBOX, ("dm2s_mbox_fini: calling mb_fini\n")); 783 ret = scf_mb_fini(dm2sp->ms_target, dm2sp->ms_key); 784 if (ret != 0) { 785 cmn_err(CE_WARN, 786 "Failed to close the Mailbox error =%d", ret); 787 } 788 DPRINTF(DBG_MBOX, ("dm2s_mbox_fini: mb_fini ret=%d\n", ret)); 789 dm2sp->ms_state &= ~(DM2S_MB_INITED |DM2S_MB_CONN | 790 DM2S_MB_DISC); 791 } 792 } 793 794 /* 795 * dm2s_event_handler - Mailbox event handler. 796 */ 797 void 798 dm2s_event_handler(scf_event_t event, void *arg) 799 { 800 dm2s_t *dm2sp = (dm2s_t *)arg; 801 queue_t *rq; 802 803 ASSERT(dm2sp != NULL); 804 mutex_enter(&dm2sp->ms_lock); 805 if (!(dm2sp->ms_state & DM2S_MB_INITED)) { 806 /* 807 * Ignore all events if the state flag indicates that the 808 * mailbox not initialized, this may happen during the close. 809 */ 810 mutex_exit(&dm2sp->ms_lock); 811 DPRINTF(DBG_MBOX, 812 ("Event(0x%X) received - Mailbox not inited\n", event)); 813 return; 814 } 815 switch (event) { 816 case SCF_MB_CONN_OK: 817 /* 818 * Now the mailbox is ready to use, lets wake up 819 * any one waiting for this event. 820 */ 821 dm2sp->ms_state |= DM2S_MB_CONN; 822 cv_broadcast(&dm2sp->ms_wait); 823 DPRINTF(DBG_MBOX, ("Event received = CONN_OK\n")); 824 break; 825 826 case SCF_MB_MSG_DATA: 827 if (!DM2S_MBOX_READY(dm2sp)) { 828 DPRINTF(DBG_MBOX, 829 ("Event(MSG_DATA) received - Mailbox not READY\n")); 830 break; 831 } 832 /* 833 * A message is available in the mailbox. 834 * Lets enable the read service procedure 835 * to receive this message. 836 */ 837 if (dm2sp->ms_rq != NULL) { 838 qenable(dm2sp->ms_rq); 839 } 840 DPRINTF(DBG_MBOX, ("Event received = MSG_DATA\n")); 841 break; 842 843 case SCF_MB_SPACE: 844 if (!DM2S_MBOX_READY(dm2sp)) { 845 DPRINTF(DBG_MBOX, 846 ("Event(MB_SPACE) received - Mailbox not READY\n")); 847 break; 848 } 849 850 /* 851 * Now the mailbox is ready to transmit, lets 852 * schedule the write service procedure. 853 */ 854 if (dm2sp->ms_wq != NULL) { 855 qenable(dm2sp->ms_wq); 856 } 857 DPRINTF(DBG_MBOX, ("Event received = MB_SPACE\n")); 858 break; 859 case SCF_MB_DISC_ERROR: 860 dm2sp->ms_state |= DM2S_MB_DISC; 861 if (dm2sp->ms_state & DM2S_MB_CONN) { 862 /* 863 * If it was previously connected, 864 * then send a hangup message. 865 */ 866 rq = dm2sp->ms_rq; 867 if (rq != NULL) { 868 mutex_exit(&dm2sp->ms_lock); 869 /* 870 * Send a hangup message to indicate 871 * disconnect event. 872 */ 873 (void) putctl(rq, M_HANGUP); 874 DTRACE_PROBE1(dm2s_hangup, dm2s_t, dm2sp); 875 mutex_enter(&dm2sp->ms_lock); 876 } 877 } else { 878 /* 879 * Signal if the open is waiting for a 880 * connection. 881 */ 882 cv_broadcast(&dm2sp->ms_wait); 883 } 884 DPRINTF(DBG_MBOX, ("Event received = DISC_ERROR\n")); 885 break; 886 default: 887 cmn_err(CE_WARN, "Unexpected event received\n"); 888 break; 889 } 890 mutex_exit(&dm2sp->ms_lock); 891 } 892 893 /* 894 * dm2s_start - Start transmission function. 895 * 896 * Send all queued messages. If the mailbox is busy, then 897 * start a timeout as a polling mechanism. The timeout is useful 898 * to not rely entirely on the SCF_MB_SPACE event. 899 */ 900 void 901 dm2s_start(queue_t *wq, dm2s_t *dm2sp) 902 { 903 mblk_t *mp; 904 int ret; 905 906 DPRINTF(DBG_DRV, ("dm2s_start: called\n")); 907 ASSERT(dm2sp != NULL); 908 ASSERT(MUTEX_HELD(&dm2sp->ms_lock)); 909 910 while ((mp = getq(wq)) != NULL) { 911 switch (mp->b_datap->db_type) { 912 913 case M_DATA: 914 ret = dm2s_transmit(wq, mp, dm2sp->ms_target, 915 dm2sp->ms_key); 916 if (ret == EBUSY || ret == ENOSPC || ret == EAGAIN) { 917 DPRINTF(DBG_MBOX, 918 ("dm2s_start: recoverable err=%d\n", ret)); 919 /* 920 * Start a timeout to retry again. 921 */ 922 if (dm2sp->ms_wq_timeoutid == 0) { 923 DTRACE_PROBE1(dm2s_wqtimeout__start, 924 dm2s_t, dm2sp); 925 dm2sp->ms_wq_timeoutid = qtimeout(wq, 926 dm2s_wq_timeout, (void *)dm2sp, 927 dm2s_timeout_val(ret)); 928 } 929 return; 930 } else if (ret != 0) { 931 mutex_exit(&dm2sp->ms_lock); 932 /* 933 * An error occurred with the transmission, 934 * flush pending messages and initiate a 935 * hangup. 936 */ 937 flushq(wq, FLUSHDATA); 938 (void) putnextctl(RD(wq), M_HANGUP); 939 DTRACE_PROBE1(dm2s_hangup, dm2s_t, dm2sp); 940 DPRINTF(DBG_WARN, 941 ("dm2s_start: hangup transmit err=%d\n", 942 ret)); 943 mutex_enter(&dm2sp->ms_lock); 944 } 945 break; 946 default: 947 /* 948 * At this point, we don't expect any other messages. 949 */ 950 freemsg(mp); 951 break; 952 } 953 } 954 } 955 956 /* 957 * dm2s_receive - Read all messages from the mailbox. 958 * 959 * This function is called from the read service procedure, to 960 * receive the messages awaiting in the mailbox. 961 */ 962 void 963 dm2s_receive(dm2s_t *dm2sp) 964 { 965 queue_t *rq = dm2sp->ms_rq; 966 mblk_t *mp; 967 int ret; 968 uint32_t len; 969 970 DPRINTF(DBG_DRV, ("dm2s_receive: called\n")); 971 ASSERT(dm2sp != NULL); 972 ASSERT(MUTEX_HELD(&dm2sp->ms_lock)); 973 if (rq == NULL) { 974 return; 975 } 976 /* 977 * As the number of messages in the mailbox are pretty limited, 978 * it is safe to process all messages in one loop. 979 */ 980 while (DM2S_MBOX_READY(dm2sp) && ((ret = scf_mb_canget(dm2sp->ms_target, 981 dm2sp->ms_key, &len)) == 0)) { 982 DPRINTF(DBG_MBOX, ("dm2s_receive: mb_canget len=%d\n", len)); 983 if (len == 0) { 984 break; 985 } 986 mp = allocb(len, BPRI_MED); 987 if (mp == NULL) { 988 DPRINTF(DBG_WARN, ("dm2s_receive: allocb failed\n")); 989 /* 990 * Start a bufcall so that we can retry again 991 * when memory becomes available. 992 */ 993 dm2sp->ms_rbufcid = qbufcall(rq, len, BPRI_MED, 994 dm2s_bufcall_rcv, dm2sp); 995 if (dm2sp->ms_rbufcid == 0) { 996 DPRINTF(DBG_WARN, 997 ("dm2s_receive: qbufcall failed\n")); 998 /* 999 * if bufcall fails, start a timeout to 1000 * initiate a re-try after some time. 1001 */ 1002 DTRACE_PROBE1(dm2s_rqtimeout__start, 1003 dm2s_t, dm2sp); 1004 dm2sp->ms_rq_timeoutid = qtimeout(rq, 1005 dm2s_rq_timeout, (void *)dm2sp, 1006 drv_usectohz(DM2S_SM_TOUT)); 1007 } 1008 break; 1009 } 1010 1011 /* 1012 * Only a single scatter/gather element is enough here. 1013 */ 1014 dm2sp->ms_sg_rcv.msc_dptr = (caddr_t)mp->b_wptr; 1015 dm2sp->ms_sg_rcv.msc_len = len; 1016 DPRINTF(DBG_MBOX, ("dm2s_receive: calling getmsg\n")); 1017 ret = scf_mb_getmsg(dm2sp->ms_target, dm2sp->ms_key, len, 1, 1018 &dm2sp->ms_sg_rcv, 0); 1019 DPRINTF(DBG_MBOX, ("dm2s_receive: getmsg ret=%d\n", ret)); 1020 if (ret != 0) { 1021 freemsg(mp); 1022 break; 1023 } 1024 DMPBYTES("dm2s: Getmsg: ", len, 1, &dm2sp->ms_sg_rcv); 1025 mp->b_wptr += len; 1026 /* 1027 * Queue the messages in the rq, so that the service 1028 * procedure handles sending the messages up the stream. 1029 */ 1030 putq(rq, mp); 1031 } 1032 1033 if ((!DM2S_MBOX_READY(dm2sp)) || (ret != ENOMSG && ret != EMSGSIZE)) { 1034 /* 1035 * Some thing went wrong, flush pending messages 1036 * and initiate a hangup. 1037 * Note: flushing the wq initiates a faster close. 1038 */ 1039 mutex_exit(&dm2sp->ms_lock); 1040 flushq(WR(rq), FLUSHDATA); 1041 (void) putnextctl(rq, M_HANGUP); 1042 DTRACE_PROBE1(dm2s_hangup, dm2s_t, dm2sp); 1043 mutex_enter(&dm2sp->ms_lock); 1044 DPRINTF(DBG_WARN, ("dm2s_receive: encountered unknown " 1045 "condition - hangup ret=%d\n", ret)); 1046 } 1047 } 1048 1049 /* 1050 * dm2s_transmit - Transmit a message. 1051 */ 1052 int 1053 dm2s_transmit(queue_t *wq, mblk_t *mp, target_id_t target, mkey_t key) 1054 { 1055 dm2s_t *dm2sp = (dm2s_t *)wq->q_ptr; 1056 int ret; 1057 uint32_t len; 1058 uint32_t numsg; 1059 1060 DPRINTF(DBG_DRV, ("dm2s_transmit: called\n")); 1061 ASSERT(dm2sp != NULL); 1062 ASSERT(MUTEX_HELD(&dm2sp->ms_lock)); 1063 /* 1064 * Free the message if the mailbox is not in the connected state. 1065 */ 1066 if (!DM2S_MBOX_READY(dm2sp)) { 1067 DPRINTF(DBG_MBOX, ("dm2s_transmit: mailbox not ready yet\n")); 1068 freemsg(mp); 1069 return (EIO); 1070 } 1071 1072 len = msgdsize(mp); 1073 if (len > dm2sp->ms_mtu) { 1074 /* 1075 * Size is too big to send, free the message. 1076 */ 1077 DPRINTF(DBG_MBOX, ("dm2s_transmit: message too large\n")); 1078 DTRACE_PROBE2(dm2s_msg_too_big, dm2s_t, dm2sp, uint32_t, len); 1079 freemsg(mp); 1080 return (0); 1081 } 1082 1083 if ((ret = dm2s_prep_scatgath(mp, &numsg, dm2sp->ms_sg_tx, 1084 DM2S_MAX_SG)) != 0) { 1085 DPRINTF(DBG_MBOX, ("dm2s_transmit: prep_scatgath failed\n")); 1086 putbq(wq, mp); 1087 return (EAGAIN); 1088 } 1089 DPRINTF(DBG_MBOX, ("dm2s_transmit: calling mb_putmsg numsg=%d len=%d\n", 1090 numsg, len)); 1091 ret = scf_mb_putmsg(target, key, len, numsg, dm2sp->ms_sg_tx, 0); 1092 if (ret == EBUSY || ret == ENOSPC) { 1093 DPRINTF(DBG_MBOX, 1094 ("dm2s_transmit: mailbox busy ret=%d\n", ret)); 1095 if (++dm2sp->ms_retries >= DM2S_MAX_RETRIES) { 1096 /* 1097 * If maximum retries are reached, then free the 1098 * message. 1099 */ 1100 DPRINTF(DBG_MBOX, 1101 ("dm2s_transmit: freeing msg after max retries\n")); 1102 DTRACE_PROBE2(dm2s_retry_fail, dm2s_t, dm2sp, int, ret); 1103 freemsg(mp); 1104 dm2sp->ms_retries = 0; 1105 return (0); 1106 } 1107 DTRACE_PROBE2(dm2s_mb_busy, dm2s_t, dm2sp, int, ret); 1108 /* 1109 * Queue it back, so that we can retry again. 1110 */ 1111 putbq(wq, mp); 1112 return (ret); 1113 } 1114 DMPBYTES("dm2s: Putmsg: ", len, numsg, dm2sp->ms_sg_tx); 1115 dm2sp->ms_retries = 0; 1116 freemsg(mp); 1117 DPRINTF(DBG_DRV, ("dm2s_transmit: ret=%d\n", ret)); 1118 return (ret); 1119 } 1120 1121 /* 1122 * dm2s_bufcall_rcv - Bufcall callaback routine. 1123 * 1124 * It simply enables read side queue so that the service procedure 1125 * can retry receive operation. 1126 */ 1127 void 1128 dm2s_bufcall_rcv(void *arg) 1129 { 1130 dm2s_t *dm2sp = (dm2s_t *)arg; 1131 1132 DPRINTF(DBG_DRV, ("dm2s_bufcall_rcv: called\n")); 1133 mutex_enter(&dm2sp->ms_lock); 1134 dm2sp->ms_rbufcid = 0; 1135 if (dm2sp->ms_rq != NULL) { 1136 qenable(dm2sp->ms_rq); 1137 } 1138 mutex_exit(&dm2sp->ms_lock); 1139 } 1140 1141 /* 1142 * dm2s_rq_timeout - Timeout callback for the read side. 1143 * 1144 * It simply enables read side queue so that the service procedure 1145 * can retry the receive operation. 1146 */ 1147 void 1148 dm2s_rq_timeout(void *arg) 1149 { 1150 dm2s_t *dm2sp = (dm2s_t *)arg; 1151 1152 DPRINTF(DBG_DRV, ("dm2s_rq_timeout: called\n")); 1153 mutex_enter(&dm2sp->ms_lock); 1154 dm2sp->ms_rq_timeoutid = 0; 1155 if (dm2sp->ms_rq != NULL) { 1156 qenable(dm2sp->ms_rq); 1157 } 1158 mutex_exit(&dm2sp->ms_lock); 1159 } 1160 1161 /* 1162 * dm2s_wq_timeout - Timeout callback for the write. 1163 * 1164 * It simply enables write side queue so that the service procedure 1165 * can retry the transmission operation. 1166 */ 1167 void 1168 dm2s_wq_timeout(void *arg) 1169 { 1170 dm2s_t *dm2sp = (dm2s_t *)arg; 1171 1172 DPRINTF(DBG_DRV, ("dm2s_wq_timeout: called\n")); 1173 mutex_enter(&dm2sp->ms_lock); 1174 dm2sp->ms_wq_timeoutid = 0; 1175 if (dm2sp->ms_wq != NULL) { 1176 qenable(dm2sp->ms_wq); 1177 } 1178 mutex_exit(&dm2sp->ms_lock); 1179 } 1180 1181 /* 1182 * dm2s_prep_scatgath - Prepare scatter/gather elements for transmission 1183 * of a streams message. 1184 */ 1185 static int 1186 dm2s_prep_scatgath(mblk_t *mp, uint32_t *numsg, mscat_gath_t *sgp, int maxsg) 1187 { 1188 uint32_t num = 0; 1189 mblk_t *tmp = mp; 1190 1191 while ((tmp != NULL) && (num < maxsg)) { 1192 sgp[num].msc_dptr = (caddr_t)tmp->b_rptr; 1193 sgp[num].msc_len = MBLKL(tmp); 1194 tmp = tmp->b_cont; 1195 num++; 1196 } 1197 1198 if (tmp != NULL) { 1199 /* 1200 * Number of scatter/gather elements available are not 1201 * enough, so lets pullup the msg. 1202 */ 1203 if (pullupmsg(mp, -1) != 1) { 1204 return (EAGAIN); 1205 } 1206 sgp[0].msc_dptr = (caddr_t)mp->b_rptr; 1207 sgp[0].msc_len = MBLKL(mp); 1208 num = 1; 1209 } 1210 *numsg = num; 1211 return (0); 1212 } 1213 1214 /* 1215 * dm2s_timeout_val -- Return appropriate timeout value. 1216 * 1217 * A small timeout value is returned for EBUSY and EAGAIN cases. This is 1218 * because the condition is expected to be recovered sooner. 1219 * 1220 * A larger timeout value is returned for ENOSPC case, as the condition 1221 * depends on the peer to release buffer space. 1222 * NOTE: there will also be an event(SCF_MB_SPACE) but a timeout is 1223 * used for reliability purposes. 1224 */ 1225 static clock_t 1226 dm2s_timeout_val(int error) 1227 { 1228 clock_t tval; 1229 1230 ASSERT(error == EBUSY || error == ENOSPC || error == EAGAIN); 1231 1232 if (error == EBUSY || error == EAGAIN) { 1233 tval = DM2S_SM_TOUT; 1234 } else { 1235 tval = DM2S_LG_TOUT; 1236 } 1237 return (drv_usectohz(tval)); 1238 } 1239 1240 #ifdef DEBUG 1241 1242 static void 1243 dm2s_dump_bytes(char *str, uint32_t total_len, 1244 uint32_t num_sg, mscat_gath_t *sgp) 1245 { 1246 int i, j; 1247 int nsg; 1248 int len, tlen = 0; 1249 mscat_gath_t *tp; 1250 uint8_t *datap; 1251 #define BYTES_PER_LINE 20 1252 char bytestr[BYTES_PER_LINE * 3 + 1]; 1253 uint32_t digest = 0; 1254 1255 if (!(dm2s_debug & DBG_MESG)) 1256 return; 1257 ASSERT(num_sg != 0); 1258 1259 for (nsg = 0; (nsg < num_sg) && (tlen < total_len); nsg++) { 1260 tp = &sgp[nsg]; 1261 datap = (uint8_t *)tp->msc_dptr; 1262 len = tp->msc_len; 1263 for (i = 0; i < len; i++) { 1264 digest += datap[i]; 1265 } 1266 tlen += len; 1267 } 1268 sprintf(bytestr, "%s Packet: Size=%d Digest=%d\n", 1269 str, total_len, digest); 1270 DTRACE_PROBE1(dm2s_dump_digest, unsigned char *, bytestr); 1271 1272 for (nsg = 0; (nsg < num_sg) && (tlen < total_len); nsg++) { 1273 tp = &sgp[nsg]; 1274 datap = (uint8_t *)tp->msc_dptr; 1275 len = tp->msc_len; 1276 for (i = 0; i < len; ) { 1277 for (j = 0; (j < BYTES_PER_LINE) && 1278 (i < len); j++, i++) { 1279 sprintf(&bytestr[j * 3], "%02X ", datap[i]); 1280 digest += datap[i]; 1281 } 1282 if (j != 0) { 1283 DTRACE_PROBE1(dm2s_dump, unsigned char *, 1284 bytestr); 1285 } 1286 } 1287 tlen += i; 1288 } 1289 } 1290 1291 #endif /* DEBUG */ 1292