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 2008 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_name_to_major(ddi_get_name(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 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; 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 tout = ddi_get_lbolt() + drv_usectohz(DM2S_MB_TOUT); 739 ret = cv_timedwait_sig(&dm2sp->ms_wait, 740 &dm2sp->ms_lock, tout); 741 if (ret == 0) { 742 /* if interrupted, return immediately. */ 743 DPRINTF(DBG_MBOX, 744 ("dm2s_mbox_init: interrupted\n")); 745 return (EINTR); 746 } 747 } 748 } 749 750 /* 751 * Obtain the max size of a single message. 752 * NOTE: There is no mechanism to update the 753 * upperlayers dynamically, so we expect this 754 * size to be atleast the default MTU size. 755 */ 756 ret = scf_mb_ctrl(dm2sp->ms_target, dm2sp->ms_key, 757 SCF_MBOP_MAXMSGSIZE, &dm2sp->ms_mtu); 758 759 if ((ret == 0) && (dm2sp->ms_mtu < DM2S_DEF_MTU)) { 760 cmn_err(CE_WARN, "Max message size expected >= %d " 761 "but found %d\n", DM2S_DEF_MTU, dm2sp->ms_mtu); 762 ret = EIO; 763 } 764 765 if (ret != 0) { 766 dm2sp->ms_state &= ~DM2S_MB_INITED; 767 (void) scf_mb_fini(dm2sp->ms_target, dm2sp->ms_key); 768 } 769 DPRINTF(DBG_MBOX, ("dm2s_mbox_init: mb_init ret=%d\n", ret)); 770 return (ret); 771 } 772 773 /* 774 * dm2s_mbox_fini - Mailbox de-initialization. 775 */ 776 static void 777 dm2s_mbox_fini(dm2s_t *dm2sp) 778 { 779 int ret; 780 781 ASSERT(dm2sp != NULL); 782 if (dm2sp->ms_state & DM2S_MB_INITED) { 783 DPRINTF(DBG_MBOX, ("dm2s_mbox_fini: calling mb_fini\n")); 784 ret = scf_mb_fini(dm2sp->ms_target, dm2sp->ms_key); 785 if (ret != 0) { 786 cmn_err(CE_WARN, 787 "Failed to close the Mailbox error =%d", ret); 788 } 789 DPRINTF(DBG_MBOX, ("dm2s_mbox_fini: mb_fini ret=%d\n", ret)); 790 dm2sp->ms_state &= ~(DM2S_MB_INITED |DM2S_MB_CONN | 791 DM2S_MB_DISC); 792 } 793 } 794 795 /* 796 * dm2s_event_handler - Mailbox event handler. 797 */ 798 void 799 dm2s_event_handler(scf_event_t event, void *arg) 800 { 801 dm2s_t *dm2sp = (dm2s_t *)arg; 802 queue_t *rq; 803 804 ASSERT(dm2sp != NULL); 805 mutex_enter(&dm2sp->ms_lock); 806 if (!(dm2sp->ms_state & DM2S_MB_INITED)) { 807 /* 808 * Ignore all events if the state flag indicates that the 809 * mailbox not initialized, this may happen during the close. 810 */ 811 mutex_exit(&dm2sp->ms_lock); 812 DPRINTF(DBG_MBOX, 813 ("Event(0x%X) received - Mailbox not inited\n", event)); 814 return; 815 } 816 switch (event) { 817 case SCF_MB_CONN_OK: 818 /* 819 * Now the mailbox is ready to use, lets wake up 820 * any one waiting for this event. 821 */ 822 dm2sp->ms_state |= DM2S_MB_CONN; 823 cv_broadcast(&dm2sp->ms_wait); 824 DPRINTF(DBG_MBOX, ("Event received = CONN_OK\n")); 825 break; 826 827 case SCF_MB_MSG_DATA: 828 if (!DM2S_MBOX_READY(dm2sp)) { 829 DPRINTF(DBG_MBOX, 830 ("Event(MSG_DATA) received - Mailbox not READY\n")); 831 break; 832 } 833 /* 834 * A message is available in the mailbox. 835 * Lets enable the read service procedure 836 * to receive this message. 837 */ 838 if (dm2sp->ms_rq != NULL) { 839 qenable(dm2sp->ms_rq); 840 } 841 DPRINTF(DBG_MBOX, ("Event received = MSG_DATA\n")); 842 break; 843 844 case SCF_MB_SPACE: 845 if (!DM2S_MBOX_READY(dm2sp)) { 846 DPRINTF(DBG_MBOX, 847 ("Event(MB_SPACE) received - Mailbox not READY\n")); 848 break; 849 } 850 851 /* 852 * Now the mailbox is ready to transmit, lets 853 * schedule the write service procedure. 854 */ 855 if (dm2sp->ms_wq != NULL) { 856 qenable(dm2sp->ms_wq); 857 } 858 DPRINTF(DBG_MBOX, ("Event received = MB_SPACE\n")); 859 break; 860 case SCF_MB_DISC_ERROR: 861 dm2sp->ms_state |= DM2S_MB_DISC; 862 if (dm2sp->ms_state & DM2S_MB_CONN) { 863 /* 864 * If it was previously connected, 865 * then send a hangup message. 866 */ 867 rq = dm2sp->ms_rq; 868 if (rq != NULL) { 869 mutex_exit(&dm2sp->ms_lock); 870 /* 871 * Send a hangup message to indicate 872 * disconnect event. 873 */ 874 (void) putctl(rq, M_HANGUP); 875 DTRACE_PROBE1(dm2s_hangup, dm2s_t, dm2sp); 876 mutex_enter(&dm2sp->ms_lock); 877 } 878 } else { 879 /* 880 * Signal if the open is waiting for a 881 * connection. 882 */ 883 cv_broadcast(&dm2sp->ms_wait); 884 } 885 DPRINTF(DBG_MBOX, ("Event received = DISC_ERROR\n")); 886 break; 887 default: 888 cmn_err(CE_WARN, "Unexpected event received\n"); 889 break; 890 } 891 mutex_exit(&dm2sp->ms_lock); 892 } 893 894 /* 895 * dm2s_start - Start transmission function. 896 * 897 * Send all queued messages. If the mailbox is busy, then 898 * start a timeout as a polling mechanism. The timeout is useful 899 * to not rely entirely on the SCF_MB_SPACE event. 900 */ 901 void 902 dm2s_start(queue_t *wq, dm2s_t *dm2sp) 903 { 904 mblk_t *mp; 905 int ret; 906 907 DPRINTF(DBG_DRV, ("dm2s_start: called\n")); 908 ASSERT(dm2sp != NULL); 909 ASSERT(MUTEX_HELD(&dm2sp->ms_lock)); 910 911 while ((mp = getq(wq)) != NULL) { 912 switch (mp->b_datap->db_type) { 913 914 case M_DATA: 915 ret = dm2s_transmit(wq, mp, dm2sp->ms_target, 916 dm2sp->ms_key); 917 if (ret == EBUSY || ret == ENOSPC || ret == EAGAIN) { 918 DPRINTF(DBG_MBOX, 919 ("dm2s_start: recoverable err=%d\n", ret)); 920 /* 921 * Start a timeout to retry again. 922 */ 923 if (dm2sp->ms_wq_timeoutid == 0) { 924 DTRACE_PROBE1(dm2s_wqtimeout__start, 925 dm2s_t, dm2sp); 926 dm2sp->ms_wq_timeoutid = qtimeout(wq, 927 dm2s_wq_timeout, (void *)dm2sp, 928 dm2s_timeout_val(ret)); 929 } 930 return; 931 } else if (ret != 0) { 932 mutex_exit(&dm2sp->ms_lock); 933 /* 934 * An error occurred with the transmission, 935 * flush pending messages and initiate a 936 * hangup. 937 */ 938 flushq(wq, FLUSHDATA); 939 (void) putnextctl(RD(wq), M_HANGUP); 940 DTRACE_PROBE1(dm2s_hangup, dm2s_t, dm2sp); 941 DPRINTF(DBG_WARN, 942 ("dm2s_start: hangup transmit err=%d\n", 943 ret)); 944 mutex_enter(&dm2sp->ms_lock); 945 } 946 break; 947 default: 948 /* 949 * At this point, we don't expect any other messages. 950 */ 951 freemsg(mp); 952 break; 953 } 954 } 955 } 956 957 /* 958 * dm2s_receive - Read all messages from the mailbox. 959 * 960 * This function is called from the read service procedure, to 961 * receive the messages awaiting in the mailbox. 962 */ 963 void 964 dm2s_receive(dm2s_t *dm2sp) 965 { 966 queue_t *rq = dm2sp->ms_rq; 967 mblk_t *mp; 968 int ret; 969 uint32_t len; 970 971 DPRINTF(DBG_DRV, ("dm2s_receive: called\n")); 972 ASSERT(dm2sp != NULL); 973 ASSERT(MUTEX_HELD(&dm2sp->ms_lock)); 974 if (rq == NULL) { 975 return; 976 } 977 /* 978 * As the number of messages in the mailbox are pretty limited, 979 * it is safe to process all messages in one loop. 980 */ 981 while (DM2S_MBOX_READY(dm2sp) && ((ret = scf_mb_canget(dm2sp->ms_target, 982 dm2sp->ms_key, &len)) == 0)) { 983 DPRINTF(DBG_MBOX, ("dm2s_receive: mb_canget len=%d\n", len)); 984 if (len == 0) { 985 break; 986 } 987 mp = allocb(len, BPRI_MED); 988 if (mp == NULL) { 989 DPRINTF(DBG_WARN, ("dm2s_receive: allocb failed\n")); 990 /* 991 * Start a bufcall so that we can retry again 992 * when memory becomes available. 993 */ 994 dm2sp->ms_rbufcid = qbufcall(rq, len, BPRI_MED, 995 dm2s_bufcall_rcv, dm2sp); 996 if (dm2sp->ms_rbufcid == 0) { 997 DPRINTF(DBG_WARN, 998 ("dm2s_receive: qbufcall failed\n")); 999 /* 1000 * if bufcall fails, start a timeout to 1001 * initiate a re-try after some time. 1002 */ 1003 DTRACE_PROBE1(dm2s_rqtimeout__start, 1004 dm2s_t, dm2sp); 1005 dm2sp->ms_rq_timeoutid = qtimeout(rq, 1006 dm2s_rq_timeout, (void *)dm2sp, 1007 drv_usectohz(DM2S_SM_TOUT)); 1008 } 1009 break; 1010 } 1011 1012 /* 1013 * Only a single scatter/gather element is enough here. 1014 */ 1015 dm2sp->ms_sg_rcv.msc_dptr = (caddr_t)mp->b_wptr; 1016 dm2sp->ms_sg_rcv.msc_len = len; 1017 DPRINTF(DBG_MBOX, ("dm2s_receive: calling getmsg\n")); 1018 ret = scf_mb_getmsg(dm2sp->ms_target, dm2sp->ms_key, len, 1, 1019 &dm2sp->ms_sg_rcv, 0); 1020 DPRINTF(DBG_MBOX, ("dm2s_receive: getmsg ret=%d\n", ret)); 1021 if (ret != 0) { 1022 freemsg(mp); 1023 break; 1024 } 1025 DMPBYTES("dm2s: Getmsg: ", len, 1, &dm2sp->ms_sg_rcv); 1026 mp->b_wptr += len; 1027 /* 1028 * Queue the messages in the rq, so that the service 1029 * procedure handles sending the messages up the stream. 1030 */ 1031 putq(rq, mp); 1032 } 1033 1034 if ((!DM2S_MBOX_READY(dm2sp)) || (ret != ENOMSG && ret != EMSGSIZE)) { 1035 /* 1036 * Some thing went wrong, flush pending messages 1037 * and initiate a hangup. 1038 * Note: flushing the wq initiates a faster close. 1039 */ 1040 mutex_exit(&dm2sp->ms_lock); 1041 flushq(WR(rq), FLUSHDATA); 1042 (void) putnextctl(rq, M_HANGUP); 1043 DTRACE_PROBE1(dm2s_hangup, dm2s_t, dm2sp); 1044 mutex_enter(&dm2sp->ms_lock); 1045 DPRINTF(DBG_WARN, ("dm2s_receive: encountered unknown " 1046 "condition - hangup ret=%d\n", ret)); 1047 } 1048 } 1049 1050 /* 1051 * dm2s_transmit - Transmit a message. 1052 */ 1053 int 1054 dm2s_transmit(queue_t *wq, mblk_t *mp, target_id_t target, mkey_t key) 1055 { 1056 dm2s_t *dm2sp = (dm2s_t *)wq->q_ptr; 1057 int ret; 1058 uint32_t len; 1059 uint32_t numsg; 1060 1061 DPRINTF(DBG_DRV, ("dm2s_transmit: called\n")); 1062 ASSERT(dm2sp != NULL); 1063 ASSERT(MUTEX_HELD(&dm2sp->ms_lock)); 1064 /* 1065 * Free the message if the mailbox is not in the connected state. 1066 */ 1067 if (!DM2S_MBOX_READY(dm2sp)) { 1068 DPRINTF(DBG_MBOX, ("dm2s_transmit: mailbox not ready yet\n")); 1069 freemsg(mp); 1070 return (EIO); 1071 } 1072 1073 len = msgdsize(mp); 1074 if (len > dm2sp->ms_mtu) { 1075 /* 1076 * Size is too big to send, free the message. 1077 */ 1078 DPRINTF(DBG_MBOX, ("dm2s_transmit: message too large\n")); 1079 DTRACE_PROBE2(dm2s_msg_too_big, dm2s_t, dm2sp, uint32_t, len); 1080 freemsg(mp); 1081 return (0); 1082 } 1083 1084 if ((ret = dm2s_prep_scatgath(mp, &numsg, dm2sp->ms_sg_tx, 1085 DM2S_MAX_SG)) != 0) { 1086 DPRINTF(DBG_MBOX, ("dm2s_transmit: prep_scatgath failed\n")); 1087 putbq(wq, mp); 1088 return (EAGAIN); 1089 } 1090 DPRINTF(DBG_MBOX, ("dm2s_transmit: calling mb_putmsg numsg=%d len=%d\n", 1091 numsg, len)); 1092 ret = scf_mb_putmsg(target, key, len, numsg, dm2sp->ms_sg_tx, 0); 1093 if (ret == EBUSY || ret == ENOSPC) { 1094 DPRINTF(DBG_MBOX, 1095 ("dm2s_transmit: mailbox busy ret=%d\n", ret)); 1096 if (++dm2sp->ms_retries >= DM2S_MAX_RETRIES) { 1097 /* 1098 * If maximum retries are reached, then free the 1099 * message. 1100 */ 1101 DPRINTF(DBG_MBOX, 1102 ("dm2s_transmit: freeing msg after max retries\n")); 1103 DTRACE_PROBE2(dm2s_retry_fail, dm2s_t, dm2sp, int, ret); 1104 freemsg(mp); 1105 dm2sp->ms_retries = 0; 1106 return (0); 1107 } 1108 DTRACE_PROBE2(dm2s_mb_busy, dm2s_t, dm2sp, int, ret); 1109 /* 1110 * Queue it back, so that we can retry again. 1111 */ 1112 putbq(wq, mp); 1113 return (ret); 1114 } 1115 DMPBYTES("dm2s: Putmsg: ", len, numsg, dm2sp->ms_sg_tx); 1116 dm2sp->ms_retries = 0; 1117 freemsg(mp); 1118 DPRINTF(DBG_DRV, ("dm2s_transmit: ret=%d\n", ret)); 1119 return (ret); 1120 } 1121 1122 /* 1123 * dm2s_bufcall_rcv - Bufcall callaback routine. 1124 * 1125 * It simply enables read side queue so that the service procedure 1126 * can retry receive operation. 1127 */ 1128 void 1129 dm2s_bufcall_rcv(void *arg) 1130 { 1131 dm2s_t *dm2sp = (dm2s_t *)arg; 1132 1133 DPRINTF(DBG_DRV, ("dm2s_bufcall_rcv: called\n")); 1134 mutex_enter(&dm2sp->ms_lock); 1135 dm2sp->ms_rbufcid = 0; 1136 if (dm2sp->ms_rq != NULL) { 1137 qenable(dm2sp->ms_rq); 1138 } 1139 mutex_exit(&dm2sp->ms_lock); 1140 } 1141 1142 /* 1143 * dm2s_rq_timeout - Timeout callback for the read side. 1144 * 1145 * It simply enables read side queue so that the service procedure 1146 * can retry the receive operation. 1147 */ 1148 void 1149 dm2s_rq_timeout(void *arg) 1150 { 1151 dm2s_t *dm2sp = (dm2s_t *)arg; 1152 1153 DPRINTF(DBG_DRV, ("dm2s_rq_timeout: called\n")); 1154 mutex_enter(&dm2sp->ms_lock); 1155 dm2sp->ms_rq_timeoutid = 0; 1156 if (dm2sp->ms_rq != NULL) { 1157 qenable(dm2sp->ms_rq); 1158 } 1159 mutex_exit(&dm2sp->ms_lock); 1160 } 1161 1162 /* 1163 * dm2s_wq_timeout - Timeout callback for the write. 1164 * 1165 * It simply enables write side queue so that the service procedure 1166 * can retry the transmission operation. 1167 */ 1168 void 1169 dm2s_wq_timeout(void *arg) 1170 { 1171 dm2s_t *dm2sp = (dm2s_t *)arg; 1172 1173 DPRINTF(DBG_DRV, ("dm2s_wq_timeout: called\n")); 1174 mutex_enter(&dm2sp->ms_lock); 1175 dm2sp->ms_wq_timeoutid = 0; 1176 if (dm2sp->ms_wq != NULL) { 1177 qenable(dm2sp->ms_wq); 1178 } 1179 mutex_exit(&dm2sp->ms_lock); 1180 } 1181 1182 /* 1183 * dm2s_prep_scatgath - Prepare scatter/gather elements for transmission 1184 * of a streams message. 1185 */ 1186 static int 1187 dm2s_prep_scatgath(mblk_t *mp, uint32_t *numsg, mscat_gath_t *sgp, int maxsg) 1188 { 1189 uint32_t num = 0; 1190 mblk_t *tmp = mp; 1191 1192 while ((tmp != NULL) && (num < maxsg)) { 1193 sgp[num].msc_dptr = (caddr_t)tmp->b_rptr; 1194 sgp[num].msc_len = MBLKL(tmp); 1195 tmp = tmp->b_cont; 1196 num++; 1197 } 1198 1199 if (tmp != NULL) { 1200 /* 1201 * Number of scatter/gather elements available are not 1202 * enough, so lets pullup the msg. 1203 */ 1204 if (pullupmsg(mp, -1) != 1) { 1205 return (EAGAIN); 1206 } 1207 sgp[0].msc_dptr = (caddr_t)mp->b_rptr; 1208 sgp[0].msc_len = MBLKL(mp); 1209 num = 1; 1210 } 1211 *numsg = num; 1212 return (0); 1213 } 1214 1215 /* 1216 * dm2s_timeout_val -- Return appropriate timeout value. 1217 * 1218 * A small timeout value is returned for EBUSY and EAGAIN cases. This is 1219 * because the condition is expected to be recovered sooner. 1220 * 1221 * A larger timeout value is returned for ENOSPC case, as the condition 1222 * depends on the peer to release buffer space. 1223 * NOTE: there will also be an event(SCF_MB_SPACE) but a timeout is 1224 * used for reliability purposes. 1225 */ 1226 static clock_t 1227 dm2s_timeout_val(int error) 1228 { 1229 clock_t tval; 1230 1231 ASSERT(error == EBUSY || error == ENOSPC || error == EAGAIN); 1232 1233 if (error == EBUSY || error == EAGAIN) { 1234 tval = DM2S_SM_TOUT; 1235 } else { 1236 tval = DM2S_LG_TOUT; 1237 } 1238 return (drv_usectohz(tval)); 1239 } 1240 1241 #ifdef DEBUG 1242 1243 static void 1244 dm2s_dump_bytes(char *str, uint32_t total_len, 1245 uint32_t num_sg, mscat_gath_t *sgp) 1246 { 1247 int i, j; 1248 int nsg; 1249 int len, tlen = 0; 1250 mscat_gath_t *tp; 1251 uint8_t *datap; 1252 #define BYTES_PER_LINE 20 1253 char bytestr[BYTES_PER_LINE * 3 + 1]; 1254 uint32_t digest = 0; 1255 1256 if (!(dm2s_debug & DBG_MESG)) 1257 return; 1258 ASSERT(num_sg != 0); 1259 1260 for (nsg = 0; (nsg < num_sg) && (tlen < total_len); nsg++) { 1261 tp = &sgp[nsg]; 1262 datap = (uint8_t *)tp->msc_dptr; 1263 len = tp->msc_len; 1264 for (i = 0; i < len; i++) { 1265 digest += datap[i]; 1266 } 1267 tlen += len; 1268 } 1269 sprintf(bytestr, "%s Packet: Size=%d Digest=%d\n", 1270 str, total_len, digest); 1271 DTRACE_PROBE1(dm2s_dump_digest, unsigned char *, bytestr); 1272 1273 tlen = 0; 1274 for (nsg = 0; (nsg < num_sg) && (tlen < total_len); nsg++) { 1275 tp = &sgp[nsg]; 1276 datap = (uint8_t *)tp->msc_dptr; 1277 len = tp->msc_len; 1278 for (i = 0; i < len; ) { 1279 for (j = 0; (j < BYTES_PER_LINE) && 1280 (i < len); j++, i++) { 1281 sprintf(&bytestr[j * 3], "%02X ", 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