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