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 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 27 /* 28 * DM2S - Domain side Mailbox to synchronous serial device driver. 29 * 30 * Description: 31 * ----------- 32 * It is a streams driver which simulates a sync serial device on 33 * top of a mailbox type of communication. That is, it sends/receives 34 * frames as mailbox messages. The mailbox communication is provided 35 * by another driver, which exports the mailbox interfaces. 36 * 37 * Synchronization: 38 * --------------- 39 * This driver uses streams perimeters to simplify the synchronization. 40 * An inner perimeter D_MTPERMOD which protects the entire module, 41 * that is only one thread exists inside the perimeter, is used. As 42 * this driver supports only one instance and is not a high-performance 43 * driver, D_MTPERMOD is highly suitable. 44 * 45 * All transmission and reception of frames is done inside the service 46 * procedures so that all streams related operations are protected 47 * by the perimeters. 48 * 49 * The mailbox event handler is the only asynchronous callback which 50 * needs to be protected outside of the streams perimeters. This is 51 * done using the module private lock('ms_lock'); 52 * 53 */ 54 55 #include <sys/types.h> 56 #include <sys/param.h> 57 #include <sys/stream.h> 58 #include <sys/cred.h> 59 #include <sys/systm.h> 60 #include <sys/sunddi.h> 61 #include <sys/ddi.h> 62 #include <sys/conf.h> 63 #include <sys/modctl.h> 64 #include <sys/mkdev.h> 65 #include <sys/errno.h> 66 #include <sys/debug.h> 67 #include <sys/kbio.h> 68 #include <sys/kmem.h> 69 #include <sys/consdev.h> 70 #include <sys/file.h> 71 #include <sys/stropts.h> 72 #include <sys/strsun.h> 73 #include <sys/dlpi.h> 74 #include <sys/stat.h> 75 #include <sys/ser_sync.h> 76 #include <sys/sysmacros.h> 77 #include <sys/note.h> 78 #include <sys/sdt.h> 79 80 #include <sys/scfd/scfdscpif.h> 81 #include <sys/dm2s.h> 82 83 84 #define DM2S_MODNAME "dm2s" /* Module name */ 85 #define DM2S_TARGET_ID 0 /* Target ID of the peer */ 86 #define DM2S_ID_NUM 0x4D53 /* 'M''S' */ 87 #define DM2S_DEF_MTU 1504 /* Def. MTU size + PPP bytes */ 88 #define DM2S_MAXPSZ DM2S_DEF_MTU /* Set it to the default MTU */ 89 #define DM2S_LOWAT (4 * 1024) /* Low water mark */ 90 #define DM2S_HIWAT (12 * 1024) /* High water mark */ 91 #define DM2S_SM_TOUT 5000 /* Small timeout (5msec) */ 92 #define DM2S_LG_TOUT 50000 /* Large timeout (50msec) */ 93 #define DM2S_MB_TOUT 10000000 /* Mailbox timeout (10sec) */ 94 95 /* 96 * Global variables 97 */ 98 void *dm2s_softstate = NULL; /* Softstate pointer */ 99 100 101 /* 102 * Prototypes for the module related functions. 103 */ 104 int dm2s_attach(dev_info_t *dip, ddi_attach_cmd_t cmd); 105 int dm2s_detach(dev_info_t *dip, ddi_detach_cmd_t cmd); 106 int dm2s_info(dev_info_t *dip, ddi_info_cmd_t infocmd, 107 void *arg, void **result); 108 109 /* 110 * Prototypes for the streams related functions. 111 */ 112 int dm2s_open(queue_t *rq, dev_t *dev, int flag, int sflag, cred_t *cr); 113 int dm2s_close(queue_t *rq, int flag, cred_t *cred); 114 int dm2s_wput(queue_t *wq, mblk_t *mp); 115 int dm2s_rsrv(queue_t *rq); 116 int dm2s_wsrv(queue_t *wq); 117 118 /* 119 * Prototypes for the internal functions. 120 */ 121 void dm2s_start(queue_t *wq, dm2s_t *dm2sp); 122 void dm2s_event_handler(scf_event_t event, void *arg); 123 int dm2s_transmit(queue_t *wq, mblk_t *mp, target_id_t target, mkey_t key); 124 void dm2s_receive(dm2s_t *dm2sp); 125 void dm2s_wq_timeout(void *arg); 126 void dm2s_rq_timeout(void *arg); 127 void dm2s_bufcall_rcv(void *arg); 128 static clock_t dm2s_timeout_val(int error); 129 static void dm2s_cleanup(dm2s_t *dm2sp); 130 static int dm2s_mbox_init(dm2s_t *dm2sp); 131 static void dm2s_mbox_fini(dm2s_t *dm2sp); 132 static int dm2s_prep_scatgath(mblk_t *mp, uint32_t *numsg, 133 mscat_gath_t *sgp, int maxsg); 134 135 #ifdef DEBUG 136 uint32_t dm2s_debug = DBG_WARN; 137 #endif /* DEBUG */ 138 139 140 /* 141 * Streams and module related structures. 142 */ 143 struct module_info dm2s_module_info = { 144 DM2S_ID_NUM, /* module ID number */ 145 DM2S_MODNAME, /* module name. */ 146 0, /* Minimum packet size (none) */ 147 DM2S_MAXPSZ, /* Maximum packet size (none) */ 148 DM2S_HIWAT, /* queue high water mark */ 149 DM2S_LOWAT /* queue low water mark */ 150 }; 151 152 struct qinit dm2s_rinit = { 153 putq, /* qi_putp */ 154 dm2s_rsrv, /* qi_srvp */ 155 dm2s_open, /* qi_qopen */ 156 dm2s_close, /* qi_qlcose */ 157 NULL, /* qi_qadmin */ 158 &dm2s_module_info, /* qi_minfo */ 159 NULL /* qi_mstat */ 160 }; 161 162 struct qinit dm2s_winit = { 163 dm2s_wput, /* qi_putp */ 164 dm2s_wsrv, /* qi_srvp */ 165 NULL, /* qi_qopen */ 166 NULL, /* qi_qlcose */ 167 NULL, /* qi_qadmin */ 168 &dm2s_module_info, /* qi_minfo */ 169 NULL /* qi_mstat */ 170 }; 171 172 173 struct streamtab dm2s_streamtab = { 174 &dm2s_rinit, 175 &dm2s_winit, 176 NULL, 177 NULL 178 }; 179 180 DDI_DEFINE_STREAM_OPS(dm2s_ops, nulldev, nulldev, dm2s_attach, \ 181 dm2s_detach, nodev, dm2s_info, D_NEW | D_MP | D_MTPERMOD, \ 182 &dm2s_streamtab, ddi_quiesce_not_supported); 183 184 185 struct modldrv modldrv = { 186 &mod_driverops, 187 "OPL Mbox to Serial Driver", 188 &dm2s_ops 189 }; 190 191 struct modlinkage modlinkage = { 192 MODREV_1, 193 &modldrv, 194 NULL 195 }; 196 197 198 /* 199 * _init - Module's init routine. 200 */ 201 int 202 _init(void) 203 { 204 int ret; 205 206 if (ddi_soft_state_init(&dm2s_softstate, sizeof (dm2s_t), 1) != 0) { 207 cmn_err(CE_WARN, "softstate initialization failed\n"); 208 return (DDI_FAILURE); 209 } 210 if ((ret = mod_install(&modlinkage)) != 0) { 211 cmn_err(CE_WARN, "mod_install failed, error = %d", ret); 212 ddi_soft_state_fini(&dm2s_softstate); 213 } 214 return (ret); 215 } 216 217 /* 218 * _fini - Module's fini routine. 219 */ 220 int 221 _fini(void) 222 { 223 int ret; 224 225 if ((ret = mod_remove(&modlinkage)) != 0) { 226 return (ret); 227 } 228 ddi_soft_state_fini(&dm2s_softstate); 229 return (ret); 230 } 231 232 /* 233 * _info - Module's info routine. 234 */ 235 int 236 _info(struct modinfo *modinfop) 237 { 238 return (mod_info(&modlinkage, modinfop)); 239 } 240 241 /* 242 * dm2s_attach - Module's attach routine. 243 */ 244 int 245 dm2s_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 246 { 247 int instance; 248 dm2s_t *dm2sp; 249 char name[20]; 250 251 252 instance = ddi_get_instance(dip); 253 254 /* Only one instance is supported. */ 255 if (instance != 0) { 256 cmn_err(CE_WARN, "only one instance is supported"); 257 return (DDI_FAILURE); 258 } 259 260 if (cmd != DDI_ATTACH) { 261 return (DDI_FAILURE); 262 } 263 if (ddi_soft_state_zalloc(dm2s_softstate, instance) != DDI_SUCCESS) { 264 cmn_err(CE_WARN, "softstate allocation failure"); 265 return (DDI_FAILURE); 266 } 267 dm2sp = (dm2s_t *)ddi_get_soft_state(dm2s_softstate, instance); 268 if (dm2sp == NULL) { 269 ddi_soft_state_free(dm2s_softstate, instance); 270 cmn_err(CE_WARN, "softstate allocation failure."); 271 return (DDI_FAILURE); 272 } 273 dm2sp->ms_dip = dip; 274 dm2sp->ms_major = ddi_driver_major(dip); 275 dm2sp->ms_ppa = instance; 276 277 /* 278 * Get an interrupt block cookie corresponding to the 279 * interrupt priority of the event handler. 280 * Assert that the event priority is not re-defined to 281 * some higher priority. 282 */ 283 /* LINTED */ 284 ASSERT(SCF_EVENT_PRI == DDI_SOFTINT_LOW); 285 if (ddi_get_soft_iblock_cookie(dip, SCF_EVENT_PRI, 286 &dm2sp->ms_ibcookie) != DDI_SUCCESS) { 287 cmn_err(CE_WARN, "ddi_get_soft_iblock_cookie failed."); 288 goto error; 289 } 290 mutex_init(&dm2sp->ms_lock, NULL, MUTEX_DRIVER, 291 (void *)dm2sp->ms_ibcookie); 292 293 dm2sp->ms_clean |= DM2S_CLEAN_LOCK; 294 cv_init(&dm2sp->ms_wait, NULL, CV_DRIVER, NULL); 295 dm2sp->ms_clean |= DM2S_CLEAN_CV; 296 297 (void) sprintf(name, "%s%d", DM2S_MODNAME, instance); 298 if (ddi_create_minor_node(dip, name, S_IFCHR, instance, 299 DDI_PSEUDO, NULL) == DDI_FAILURE) { 300 ddi_remove_minor_node(dip, NULL); 301 cmn_err(CE_WARN, "Device node creation failed."); 302 goto error; 303 } 304 305 dm2sp->ms_clean |= DM2S_CLEAN_NODE; 306 ddi_set_driver_private(dip, (caddr_t)dm2sp); 307 ddi_report_dev(dip); 308 return (DDI_SUCCESS); 309 error: 310 dm2s_cleanup(dm2sp); 311 return (DDI_FAILURE); 312 } 313 314 /* 315 * dm2s_info - Module's info routine. 316 */ 317 /*ARGSUSED*/ 318 int 319 dm2s_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 320 { 321 dm2s_t *dm2sp; 322 minor_t minor; 323 int ret = DDI_FAILURE; 324 325 switch (infocmd) { 326 case DDI_INFO_DEVT2DEVINFO: 327 minor = getminor((dev_t)arg); 328 dm2sp = (dm2s_t *)ddi_get_soft_state(dm2s_softstate, minor); 329 if (dm2sp == NULL) { 330 *result = NULL; 331 } else { 332 *result = dm2sp->ms_dip; 333 ret = DDI_SUCCESS; 334 } 335 break; 336 337 case DDI_INFO_DEVT2INSTANCE: 338 minor = getminor((dev_t)arg); 339 *result = (void *)(uintptr_t)minor; 340 ret = DDI_SUCCESS; 341 break; 342 343 default: 344 break; 345 } 346 return (ret); 347 } 348 349 /* 350 * dm2s_detach - Module's detach routine. 351 */ 352 int 353 dm2s_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 354 { 355 int instance; 356 dm2s_t *dm2sp; 357 358 if (cmd != DDI_DETACH) { 359 return (DDI_FAILURE); 360 } 361 362 instance = ddi_get_instance(dip); 363 dm2sp = (dm2s_t *)ddi_get_soft_state(dm2s_softstate, instance); 364 if (dm2sp == NULL) { 365 return (DDI_FAILURE); 366 } 367 368 mutex_enter(&dm2sp->ms_lock); 369 370 /* Check if the mailbox is still in use. */ 371 if (dm2sp->ms_state & DM2S_MB_INITED) { 372 mutex_exit(&dm2sp->ms_lock); 373 cmn_err(CE_WARN, "Mailbox in use: Detach failed"); 374 return (DDI_FAILURE); 375 } 376 mutex_exit(&dm2sp->ms_lock); 377 dm2s_cleanup(dm2sp); 378 return (DDI_SUCCESS); 379 } 380 381 /* 382 * dm2s_open - Device open routine. 383 * 384 * Only one open supported. Clone open is not supported. 385 */ 386 /* ARGSUSED */ 387 int 388 dm2s_open(queue_t *rq, dev_t *dev, int flag, int sflag, cred_t *cr) 389 { 390 dm2s_t *dm2sp; 391 int instance = getminor(*dev); 392 int ret = 0; 393 394 DPRINTF(DBG_DRV, ("dm2s_open: called\n")); 395 if (sflag == CLONEOPEN) { 396 /* Clone open not supported */ 397 DPRINTF(DBG_WARN, ("dm2s_open: clone open not supported\n")); 398 return (ENOTSUP); 399 } 400 401 if (rq->q_ptr != NULL) { 402 DPRINTF(DBG_WARN, ("dm2s_open: already opened\n")); 403 return (EBUSY); 404 } 405 406 if ((dm2sp = ddi_get_soft_state(dm2s_softstate, instance)) == NULL) { 407 DPRINTF(DBG_WARN, ("dm2s_open: instance not found\n")); 408 return (ENODEV); 409 } 410 411 mutex_enter(&dm2sp->ms_lock); 412 if (dm2sp->ms_state & DM2S_OPENED) { 413 /* Only one open supported */ 414 mutex_exit(&dm2sp->ms_lock); 415 DPRINTF(DBG_WARN, ("dm2s_open: already opened\n")); 416 return (EBUSY); 417 } 418 419 dm2sp->ms_state |= DM2S_OPENED; 420 /* Initialize the mailbox. */ 421 if ((ret = dm2s_mbox_init(dm2sp)) != 0) { 422 dm2sp->ms_state = 0; 423 mutex_exit(&dm2sp->ms_lock); 424 return (ret); 425 } 426 rq->q_ptr = WR(rq)->q_ptr = (void *)dm2sp; 427 dm2sp->ms_rq = rq; 428 dm2sp->ms_wq = WR(rq); 429 mutex_exit(&dm2sp->ms_lock); 430 431 if (ret == 0) { 432 qprocson(rq); /* now schedule our queue */ 433 } 434 DPRINTF(DBG_DRV, ("dm2s_open: ret=%d\n", ret)); 435 return (ret); 436 } 437 438 /* 439 * dm2s_close - Device close routine. 440 */ 441 /* ARGSUSED */ 442 int 443 dm2s_close(queue_t *rq, int flag, cred_t *cred) 444 { 445 dm2s_t *dm2sp = (dm2s_t *)rq->q_ptr; 446 447 DPRINTF(DBG_DRV, ("dm2s_close: called\n")); 448 if (dm2sp == NULL) { 449 /* Already closed once */ 450 return (ENODEV); 451 } 452 453 /* Close the lower layer first */ 454 mutex_enter(&dm2sp->ms_lock); 455 (void) scf_mb_flush(dm2sp->ms_target, dm2sp->ms_key, MB_FLUSH_ALL); 456 dm2s_mbox_fini(dm2sp); 457 mutex_exit(&dm2sp->ms_lock); 458 459 /* 460 * Now we can assume that no asynchronous callbacks exist. 461 * Poison the stream head so that we can't be pushed again. 462 */ 463 (void) putnextctl(rq, M_HANGUP); 464 qprocsoff(rq); 465 if (dm2sp->ms_rbufcid != 0) { 466 qunbufcall(rq, dm2sp->ms_rbufcid); 467 dm2sp->ms_rbufcid = 0; 468 } 469 if (dm2sp->ms_rq_timeoutid != 0) { 470 DTRACE_PROBE1(dm2s_rqtimeout__cancel, dm2s_t, dm2sp); 471 (void) quntimeout(dm2sp->ms_rq, dm2sp->ms_rq_timeoutid); 472 dm2sp->ms_rq_timeoutid = 0; 473 } 474 if (dm2sp->ms_wq_timeoutid != 0) { 475 DTRACE_PROBE1(dm2s_wqtimeout__cancel, dm2s_t, dm2sp); 476 (void) quntimeout(dm2sp->ms_wq, dm2sp->ms_wq_timeoutid); 477 dm2sp->ms_wq_timeoutid = 0; 478 } 479 /* 480 * Now we can really mark it closed. 481 */ 482 mutex_enter(&dm2sp->ms_lock); 483 dm2sp->ms_rq = dm2sp->ms_wq = NULL; 484 dm2sp->ms_state &= ~DM2S_OPENED; 485 mutex_exit(&dm2sp->ms_lock); 486 487 rq->q_ptr = WR(rq)->q_ptr = NULL; 488 (void) qassociate(rq, -1); 489 DPRINTF(DBG_DRV, ("dm2s_close: successfully closed\n")); 490 return (0); 491 } 492 493 /* 494 * dm2s_rsrv - Streams read side service procedure. 495 * 496 * All messages are received in the service procedure 497 * only. This is done to simplify the streams synchronization. 498 */ 499 int 500 dm2s_rsrv(queue_t *rq) 501 { 502 mblk_t *mp; 503 dm2s_t *dm2sp = (dm2s_t *)rq->q_ptr; 504 505 DPRINTF(DBG_DRV, ("dm2s_rsrv: called\n")); 506 ASSERT(dm2sp != NULL); 507 mutex_enter(&dm2sp->ms_lock); 508 509 /* Receive if there are any messages waiting in the mailbox. */ 510 dm2s_receive(dm2sp); 511 mutex_exit(&dm2sp->ms_lock); 512 513 /* Send the received messages up the stream. */ 514 while ((mp = getq(rq)) != NULL) { 515 if (canputnext(rq)) { 516 putnext(rq, mp); 517 } else { 518 (void) putbq(rq, mp); 519 break; 520 } 521 } 522 DPRINTF(DBG_DRV, ("dm2s_rsrv: return\n")); 523 return (0); 524 } 525 526 /* 527 * dm2s_wsrv - Streams write side service procedure. 528 * 529 * All messages are transmitted in the service procedure 530 * only. This is done to simplify the streams synchronization. 531 */ 532 int 533 dm2s_wsrv(queue_t *wq) 534 { 535 dm2s_t *dm2sp = (dm2s_t *)wq->q_ptr; 536 537 DPRINTF(DBG_DRV, ("dm2s_wsrv: called\n")); 538 ASSERT(dm2sp != NULL); 539 /* Lets cancel any timeouts waiting to be scheduled. */ 540 if (dm2sp->ms_wq_timeoutid != 0) { 541 DTRACE_PROBE1(dm2s_wqtimeout__cancel, dm2s_t, dm2sp); 542 (void) quntimeout(dm2sp->ms_wq, dm2sp->ms_wq_timeoutid); 543 dm2sp->ms_wq_timeoutid = 0; 544 } 545 mutex_enter(&dm2sp->ms_lock); 546 dm2s_start(wq, dm2sp); 547 mutex_exit(&dm2sp->ms_lock); 548 DPRINTF(DBG_DRV, ("dm2s_wsrv: return\n")); 549 return (0); 550 } 551 552 /* 553 * dm2s_wput - Streams write side put routine. 554 * 555 * All M_DATA messages are queued so that they are transmitted in 556 * the service procedure. This is done to simplify the streams 557 * synchronization. Other messages are handled appropriately. 558 */ 559 int 560 dm2s_wput(queue_t *wq, mblk_t *mp) 561 { 562 dm2s_t *dm2sp = (dm2s_t *)wq->q_ptr; 563 564 DPRINTF(DBG_DRV, ("dm2s_wput: called\n")); 565 if (dm2sp == NULL) { 566 return (ENODEV); /* Can't happen. */ 567 } 568 569 switch (mp->b_datap->db_type) { 570 case (M_DATA): 571 DPRINTF(DBG_DRV, ("dm2s_wput: M_DATA message\n")); 572 while (mp->b_wptr == mp->b_rptr) { 573 mblk_t *mp1; 574 575 mp1 = unlinkb(mp); 576 freemsg(mp); 577 mp = mp1; 578 if (mp == NULL) { 579 return (0); 580 } 581 } 582 583 /* 584 * Simply queue the message and handle it in the service 585 * procedure. 586 */ 587 (void) putq(wq, mp); 588 qenable(wq); 589 return (0); 590 591 case (M_PROTO): 592 DPRINTF(DBG_DRV, ("dm2s_wput: M_PROTO message\n")); 593 /* We don't expect this */ 594 mp->b_datap->db_type = M_ERROR; 595 mp->b_rptr = mp->b_wptr = mp->b_datap->db_base; 596 *mp->b_wptr++ = EPROTO; 597 qreply(wq, mp); 598 return (EINVAL); 599 600 case (M_IOCTL): 601 DPRINTF(DBG_DRV, ("dm2s_wput: M_IOCTL message\n")); 602 if (MBLKL(mp) < sizeof (struct iocblk)) { 603 freemsg(mp); 604 return (0); 605 } 606 /* 607 * No ioctls required to be supported by this driver, so 608 * return EINVAL for all ioctls. 609 */ 610 miocnak(wq, mp, 0, EINVAL); 611 break; 612 613 case (M_CTL): 614 DPRINTF(DBG_DRV, ("dm2s_wput: M_CTL message\n")); 615 /* 616 * No M_CTL messages need to supported by this driver, 617 * so simply ignore them. 618 */ 619 freemsg(mp); 620 break; 621 622 case (M_FLUSH): 623 DPRINTF(DBG_DRV, ( 624 "dm2s_wput: M_FLUSH message 0x%X\n", *mp->b_rptr)); 625 if (*mp->b_rptr & FLUSHW) { /* Flush write-side */ 626 (void) scf_mb_flush(dm2sp->ms_target, dm2sp->ms_key, 627 MB_FLUSH_SEND); 628 flushq(wq, FLUSHDATA); 629 *mp->b_rptr &= ~FLUSHW; 630 } 631 if (*mp->b_rptr & FLUSHR) { 632 (void) scf_mb_flush(dm2sp->ms_target, dm2sp->ms_key, 633 MB_FLUSH_RECEIVE); 634 flushq(RD(wq), FLUSHDATA); 635 qreply(wq, mp); 636 } else { 637 freemsg(mp); 638 } 639 break; 640 641 default: 642 DPRINTF(DBG_DRV, ("dm2s_wput: UNKNOWN message\n")); 643 freemsg(mp); 644 645 } 646 return (0); 647 } 648 649 /* 650 * dm2s_cleanup - Cleanup routine. 651 */ 652 static void 653 dm2s_cleanup(dm2s_t *dm2sp) 654 { 655 char name[20]; 656 657 DPRINTF(DBG_DRV, ("dm2s_cleanup: called\n")); 658 ASSERT(dm2sp != NULL); 659 if (dm2sp->ms_clean & DM2S_CLEAN_NODE) { 660 (void) sprintf(name, "%s%d", DM2S_MODNAME, dm2sp->ms_ppa); 661 ddi_remove_minor_node(dm2sp->ms_dip, name); 662 } 663 if (dm2sp->ms_clean & DM2S_CLEAN_LOCK) 664 mutex_destroy(&dm2sp->ms_lock); 665 if (dm2sp->ms_clean & DM2S_CLEAN_CV) 666 cv_destroy(&dm2sp->ms_wait); 667 ddi_set_driver_private(dm2sp->ms_dip, NULL); 668 ddi_soft_state_free(dm2s_softstate, dm2sp->ms_ppa); 669 } 670 671 /* 672 * dm2s_mbox_init - Mailbox specific initialization. 673 */ 674 static int 675 dm2s_mbox_init(dm2s_t *dm2sp) 676 { 677 int ret; 678 clock_t tout = drv_usectohz(DM2S_MB_TOUT); 679 680 ASSERT(MUTEX_HELD(&dm2sp->ms_lock)); 681 dm2sp->ms_target = DM2S_TARGET_ID; 682 dm2sp->ms_key = DSCP_KEY; 683 dm2sp->ms_state &= ~DM2S_MB_INITED; 684 685 /* Iterate until mailbox gets connected */ 686 while (!(dm2sp->ms_state & DM2S_MB_CONN)) { 687 DPRINTF(DBG_MBOX, ("dm2s_mbox_init: calling mb_init\n")); 688 ret = scf_mb_init(dm2sp->ms_target, dm2sp->ms_key, 689 dm2s_event_handler, (void *)dm2sp); 690 DPRINTF(DBG_MBOX, ("dm2s_mbox_init: mb_init ret=%d\n", ret)); 691 692 if (ret != 0) { 693 DPRINTF(DBG_MBOX, 694 ("dm2s_mbox_init: failed ret =%d\n", ret)); 695 DTRACE_PROBE1(dm2s_mbox_fail, int, ret); 696 } else { 697 dm2sp->ms_state |= DM2S_MB_INITED; 698 699 /* Block until the mailbox is ready to communicate. */ 700 while (!(dm2sp->ms_state & 701 (DM2S_MB_CONN | DM2S_MB_DISC))) { 702 703 if (cv_wait_sig(&dm2sp->ms_wait, 704 &dm2sp->ms_lock) <= 0) { 705 /* interrupted */ 706 ret = EINTR; 707 break; 708 } 709 } 710 } 711 712 if ((ret != 0) || (dm2sp->ms_state & DM2S_MB_DISC)) { 713 714 if (dm2sp->ms_state & DM2S_MB_INITED) { 715 (void) scf_mb_fini(dm2sp->ms_target, 716 dm2sp->ms_key); 717 } 718 if (dm2sp->ms_state & DM2S_MB_DISC) { 719 DPRINTF(DBG_WARN, 720 ("dm2s_mbox_init: mbox DISC_ERROR\n")); 721 DTRACE_PROBE1(dm2s_mbox_fail, 722 int, DM2S_MB_DISC); 723 } 724 725 dm2sp->ms_state &= ~(DM2S_MB_INITED | DM2S_MB_DISC | 726 DM2S_MB_CONN); 727 728 if (ret == EINTR) { 729 return (ret); 730 } 731 732 /* 733 * If there was failure, then wait for 734 * DM2S_MB_TOUT secs and retry again. 735 */ 736 737 DPRINTF(DBG_MBOX, ("dm2s_mbox_init: waiting...\n")); 738 ret = cv_reltimedwait_sig(&dm2sp->ms_wait, 739 &dm2sp->ms_lock, tout, TR_CLOCK_TICK); 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 (void) 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 (void) 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 (void) 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 (void) 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 tlen = 0; 1273 for (nsg = 0; (nsg < num_sg) && (tlen < total_len); nsg++) { 1274 tp = &sgp[nsg]; 1275 datap = (uint8_t *)tp->msc_dptr; 1276 len = tp->msc_len; 1277 for (i = 0; i < len; ) { 1278 for (j = 0; (j < BYTES_PER_LINE) && 1279 (i < len); j++, i++) { 1280 (void) sprintf(&bytestr[j * 3], "%02X ", 1281 datap[i]); 1282 digest += datap[i]; 1283 } 1284 if (j != 0) { 1285 DTRACE_PROBE1(dm2s_dump, unsigned char *, 1286 bytestr); 1287 } 1288 } 1289 tlen += i; 1290 } 1291 } 1292 1293 #endif /* DEBUG */ 1294