125cf1a30Sjl /* 225cf1a30Sjl * CDDL HEADER START 325cf1a30Sjl * 425cf1a30Sjl * The contents of this file are subject to the terms of the 525cf1a30Sjl * Common Development and Distribution License (the "License"). 625cf1a30Sjl * You may not use this file except in compliance with the License. 725cf1a30Sjl * 825cf1a30Sjl * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 925cf1a30Sjl * or http://www.opensolaris.org/os/licensing. 1025cf1a30Sjl * See the License for the specific language governing permissions 1125cf1a30Sjl * and limitations under the License. 1225cf1a30Sjl * 1325cf1a30Sjl * When distributing Covered Code, include this CDDL HEADER in each 1425cf1a30Sjl * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 1525cf1a30Sjl * If applicable, add the following below this CDDL HEADER, with the 1625cf1a30Sjl * fields enclosed by brackets "[]" replaced with your own identifying 1725cf1a30Sjl * information: Portions Copyright [yyyy] [name of copyright owner] 1825cf1a30Sjl * 1925cf1a30Sjl * CDDL HEADER END 2025cf1a30Sjl */ 2125cf1a30Sjl /* 2219397407SSherry Moore * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 2325cf1a30Sjl * Use is subject to license terms. 2425cf1a30Sjl */ 2525cf1a30Sjl 2625cf1a30Sjl 2725cf1a30Sjl /* 2825cf1a30Sjl * DM2S - Domain side Mailbox to synchronous serial device driver. 2925cf1a30Sjl * 3025cf1a30Sjl * Description: 3125cf1a30Sjl * ----------- 3225cf1a30Sjl * It is a streams driver which simulates a sync serial device on 3325cf1a30Sjl * top of a mailbox type of communication. That is, it sends/receives 3425cf1a30Sjl * frames as mailbox messages. The mailbox communication is provided 3525cf1a30Sjl * by another driver, which exports the mailbox interfaces. 3625cf1a30Sjl * 3725cf1a30Sjl * Synchronization: 3825cf1a30Sjl * --------------- 3925cf1a30Sjl * This driver uses streams perimeters to simplify the synchronization. 4025cf1a30Sjl * An inner perimeter D_MTPERMOD which protects the entire module, 4125cf1a30Sjl * that is only one thread exists inside the perimeter, is used. As 4225cf1a30Sjl * this driver supports only one instance and is not a high-performance 4325cf1a30Sjl * driver, D_MTPERMOD is highly suitable. 4425cf1a30Sjl * 4525cf1a30Sjl * All transmission and reception of frames is done inside the service 4625cf1a30Sjl * procedures so that all streams related operations are protected 4725cf1a30Sjl * by the perimeters. 4825cf1a30Sjl * 4925cf1a30Sjl * The mailbox event handler is the only asynchronous callback which 5025cf1a30Sjl * needs to be protected outside of the streams perimeters. This is 5125cf1a30Sjl * done using the module private lock('ms_lock'); 5225cf1a30Sjl * 5325cf1a30Sjl */ 5425cf1a30Sjl 5525cf1a30Sjl #include <sys/types.h> 5625cf1a30Sjl #include <sys/param.h> 5725cf1a30Sjl #include <sys/stream.h> 5825cf1a30Sjl #include <sys/cred.h> 5925cf1a30Sjl #include <sys/systm.h> 6025cf1a30Sjl #include <sys/sunddi.h> 6125cf1a30Sjl #include <sys/ddi.h> 6225cf1a30Sjl #include <sys/conf.h> 6325cf1a30Sjl #include <sys/modctl.h> 6425cf1a30Sjl #include <sys/mkdev.h> 6525cf1a30Sjl #include <sys/errno.h> 6625cf1a30Sjl #include <sys/debug.h> 6725cf1a30Sjl #include <sys/kbio.h> 6825cf1a30Sjl #include <sys/kmem.h> 6925cf1a30Sjl #include <sys/consdev.h> 7025cf1a30Sjl #include <sys/file.h> 7125cf1a30Sjl #include <sys/stropts.h> 7225cf1a30Sjl #include <sys/strsun.h> 7325cf1a30Sjl #include <sys/dlpi.h> 7425cf1a30Sjl #include <sys/stat.h> 7525cf1a30Sjl #include <sys/ser_sync.h> 7625cf1a30Sjl #include <sys/sysmacros.h> 7725cf1a30Sjl #include <sys/note.h> 7825cf1a30Sjl #include <sys/sdt.h> 7925cf1a30Sjl 8025cf1a30Sjl #include <sys/scfd/scfdscpif.h> 8125cf1a30Sjl #include <sys/dm2s.h> 8225cf1a30Sjl 8325cf1a30Sjl 8425cf1a30Sjl #define DM2S_MODNAME "dm2s" /* Module name */ 8525cf1a30Sjl #define DM2S_TARGET_ID 0 /* Target ID of the peer */ 8625cf1a30Sjl #define DM2S_ID_NUM 0x4D53 /* 'M''S' */ 8725cf1a30Sjl #define DM2S_DEF_MTU 1504 /* Def. MTU size + PPP bytes */ 8825cf1a30Sjl #define DM2S_MAXPSZ DM2S_DEF_MTU /* Set it to the default MTU */ 8925cf1a30Sjl #define DM2S_LOWAT (4 * 1024) /* Low water mark */ 9025cf1a30Sjl #define DM2S_HIWAT (12 * 1024) /* High water mark */ 9125cf1a30Sjl #define DM2S_SM_TOUT 5000 /* Small timeout (5msec) */ 9225cf1a30Sjl #define DM2S_LG_TOUT 50000 /* Large timeout (50msec) */ 9325cf1a30Sjl #define DM2S_MB_TOUT 10000000 /* Mailbox timeout (10sec) */ 9425cf1a30Sjl 9525cf1a30Sjl /* 9625cf1a30Sjl * Global variables 9725cf1a30Sjl */ 9825cf1a30Sjl void *dm2s_softstate = NULL; /* Softstate pointer */ 9925cf1a30Sjl 10025cf1a30Sjl 10125cf1a30Sjl /* 10225cf1a30Sjl * Prototypes for the module related functions. 10325cf1a30Sjl */ 10425cf1a30Sjl int dm2s_attach(dev_info_t *dip, ddi_attach_cmd_t cmd); 10525cf1a30Sjl int dm2s_detach(dev_info_t *dip, ddi_detach_cmd_t cmd); 10625cf1a30Sjl int dm2s_info(dev_info_t *dip, ddi_info_cmd_t infocmd, 10725cf1a30Sjl void *arg, void **result); 10825cf1a30Sjl 10925cf1a30Sjl /* 11025cf1a30Sjl * Prototypes for the streams related functions. 11125cf1a30Sjl */ 11225cf1a30Sjl int dm2s_open(queue_t *rq, dev_t *dev, int flag, int sflag, cred_t *cr); 11325cf1a30Sjl int dm2s_close(queue_t *rq, int flag, cred_t *cred); 11425cf1a30Sjl int dm2s_wput(queue_t *wq, mblk_t *mp); 11525cf1a30Sjl int dm2s_rsrv(queue_t *rq); 11625cf1a30Sjl int dm2s_wsrv(queue_t *wq); 11725cf1a30Sjl 11825cf1a30Sjl /* 11925cf1a30Sjl * Prototypes for the internal functions. 12025cf1a30Sjl */ 12125cf1a30Sjl void dm2s_start(queue_t *wq, dm2s_t *dm2sp); 12225cf1a30Sjl void dm2s_event_handler(scf_event_t event, void *arg); 12325cf1a30Sjl int dm2s_transmit(queue_t *wq, mblk_t *mp, target_id_t target, mkey_t key); 12425cf1a30Sjl void dm2s_receive(dm2s_t *dm2sp); 12525cf1a30Sjl void dm2s_wq_timeout(void *arg); 12625cf1a30Sjl void dm2s_rq_timeout(void *arg); 12725cf1a30Sjl void dm2s_bufcall_rcv(void *arg); 12825cf1a30Sjl static clock_t dm2s_timeout_val(int error); 12925cf1a30Sjl static void dm2s_cleanup(dm2s_t *dm2sp); 13025cf1a30Sjl static int dm2s_mbox_init(dm2s_t *dm2sp); 13125cf1a30Sjl static void dm2s_mbox_fini(dm2s_t *dm2sp); 13225cf1a30Sjl static int dm2s_prep_scatgath(mblk_t *mp, uint32_t *numsg, 13325cf1a30Sjl mscat_gath_t *sgp, int maxsg); 13425cf1a30Sjl 13525cf1a30Sjl #ifdef DEBUG 13625cf1a30Sjl uint32_t dm2s_debug = DBG_WARN; 13725cf1a30Sjl #endif /* DEBUG */ 13825cf1a30Sjl 13925cf1a30Sjl 14025cf1a30Sjl /* 14125cf1a30Sjl * Streams and module related structures. 14225cf1a30Sjl */ 14325cf1a30Sjl struct module_info dm2s_module_info = { 14425cf1a30Sjl DM2S_ID_NUM, /* module ID number */ 14525cf1a30Sjl DM2S_MODNAME, /* module name. */ 14625cf1a30Sjl 0, /* Minimum packet size (none) */ 14725cf1a30Sjl DM2S_MAXPSZ, /* Maximum packet size (none) */ 14825cf1a30Sjl DM2S_HIWAT, /* queue high water mark */ 14925cf1a30Sjl DM2S_LOWAT /* queue low water mark */ 15025cf1a30Sjl }; 15125cf1a30Sjl 15225cf1a30Sjl struct qinit dm2s_rinit = { 15325cf1a30Sjl putq, /* qi_putp */ 15425cf1a30Sjl dm2s_rsrv, /* qi_srvp */ 15525cf1a30Sjl dm2s_open, /* qi_qopen */ 15625cf1a30Sjl dm2s_close, /* qi_qlcose */ 15725cf1a30Sjl NULL, /* qi_qadmin */ 15825cf1a30Sjl &dm2s_module_info, /* qi_minfo */ 15925cf1a30Sjl NULL /* qi_mstat */ 16025cf1a30Sjl }; 16125cf1a30Sjl 16225cf1a30Sjl struct qinit dm2s_winit = { 16325cf1a30Sjl dm2s_wput, /* qi_putp */ 16425cf1a30Sjl dm2s_wsrv, /* qi_srvp */ 16525cf1a30Sjl NULL, /* qi_qopen */ 16625cf1a30Sjl NULL, /* qi_qlcose */ 16725cf1a30Sjl NULL, /* qi_qadmin */ 16825cf1a30Sjl &dm2s_module_info, /* qi_minfo */ 16925cf1a30Sjl NULL /* qi_mstat */ 17025cf1a30Sjl }; 17125cf1a30Sjl 17225cf1a30Sjl 17325cf1a30Sjl struct streamtab dm2s_streamtab = { 17425cf1a30Sjl &dm2s_rinit, 17525cf1a30Sjl &dm2s_winit, 17625cf1a30Sjl NULL, 17725cf1a30Sjl NULL 17825cf1a30Sjl }; 17925cf1a30Sjl 18025cf1a30Sjl DDI_DEFINE_STREAM_OPS(dm2s_ops, nulldev, nulldev, dm2s_attach, \ 18125cf1a30Sjl dm2s_detach, nodev, dm2s_info, D_NEW | D_MP | D_MTPERMOD, \ 18219397407SSherry Moore &dm2s_streamtab, ddi_quiesce_not_supported); 18325cf1a30Sjl 18425cf1a30Sjl 18525cf1a30Sjl struct modldrv modldrv = { 18625cf1a30Sjl &mod_driverops, 18719397407SSherry Moore "OPL Mbox to Serial Driver", 18825cf1a30Sjl &dm2s_ops 18925cf1a30Sjl }; 19025cf1a30Sjl 19125cf1a30Sjl struct modlinkage modlinkage = { 19225cf1a30Sjl MODREV_1, 19325cf1a30Sjl &modldrv, 19425cf1a30Sjl NULL 19525cf1a30Sjl }; 19625cf1a30Sjl 19725cf1a30Sjl 19825cf1a30Sjl /* 19925cf1a30Sjl * _init - Module's init routine. 20025cf1a30Sjl */ 20125cf1a30Sjl int 20225cf1a30Sjl _init(void) 20325cf1a30Sjl { 20425cf1a30Sjl int ret; 20525cf1a30Sjl 20625cf1a30Sjl if (ddi_soft_state_init(&dm2s_softstate, sizeof (dm2s_t), 1) != 0) { 20725cf1a30Sjl cmn_err(CE_WARN, "softstate initialization failed\n"); 20825cf1a30Sjl return (DDI_FAILURE); 20925cf1a30Sjl } 21025cf1a30Sjl if ((ret = mod_install(&modlinkage)) != 0) { 21125cf1a30Sjl cmn_err(CE_WARN, "mod_install failed, error = %d", ret); 21225cf1a30Sjl ddi_soft_state_fini(&dm2s_softstate); 21325cf1a30Sjl } 21425cf1a30Sjl return (ret); 21525cf1a30Sjl } 21625cf1a30Sjl 21725cf1a30Sjl /* 21825cf1a30Sjl * _fini - Module's fini routine. 21925cf1a30Sjl */ 22025cf1a30Sjl int 22125cf1a30Sjl _fini(void) 22225cf1a30Sjl { 22325cf1a30Sjl int ret; 22425cf1a30Sjl 22525cf1a30Sjl if ((ret = mod_remove(&modlinkage)) != 0) { 22625cf1a30Sjl return (ret); 22725cf1a30Sjl } 22825cf1a30Sjl ddi_soft_state_fini(&dm2s_softstate); 22925cf1a30Sjl return (ret); 23025cf1a30Sjl } 23125cf1a30Sjl 23225cf1a30Sjl /* 23325cf1a30Sjl * _info - Module's info routine. 23425cf1a30Sjl */ 23525cf1a30Sjl int 23625cf1a30Sjl _info(struct modinfo *modinfop) 23725cf1a30Sjl { 23825cf1a30Sjl return (mod_info(&modlinkage, modinfop)); 23925cf1a30Sjl } 24025cf1a30Sjl 24125cf1a30Sjl /* 24225cf1a30Sjl * dm2s_attach - Module's attach routine. 24325cf1a30Sjl */ 24425cf1a30Sjl int 24525cf1a30Sjl dm2s_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 24625cf1a30Sjl { 24725cf1a30Sjl int instance; 24825cf1a30Sjl dm2s_t *dm2sp; 24925cf1a30Sjl char name[20]; 25025cf1a30Sjl 25125cf1a30Sjl 25225cf1a30Sjl instance = ddi_get_instance(dip); 25325cf1a30Sjl 25425cf1a30Sjl /* Only one instance is supported. */ 25525cf1a30Sjl if (instance != 0) { 25625cf1a30Sjl cmn_err(CE_WARN, "only one instance is supported"); 25725cf1a30Sjl return (DDI_FAILURE); 25825cf1a30Sjl } 25925cf1a30Sjl 26025cf1a30Sjl if (cmd != DDI_ATTACH) { 26125cf1a30Sjl return (DDI_FAILURE); 26225cf1a30Sjl } 26325cf1a30Sjl if (ddi_soft_state_zalloc(dm2s_softstate, instance) != DDI_SUCCESS) { 26425cf1a30Sjl cmn_err(CE_WARN, "softstate allocation failure"); 26525cf1a30Sjl return (DDI_FAILURE); 26625cf1a30Sjl } 26725cf1a30Sjl dm2sp = (dm2s_t *)ddi_get_soft_state(dm2s_softstate, instance); 26825cf1a30Sjl if (dm2sp == NULL) { 26925cf1a30Sjl ddi_soft_state_free(dm2s_softstate, instance); 27025cf1a30Sjl cmn_err(CE_WARN, "softstate allocation failure."); 27125cf1a30Sjl return (DDI_FAILURE); 27225cf1a30Sjl } 27325cf1a30Sjl dm2sp->ms_dip = dip; 274*5c066ec2SJerry Gilliam dm2sp->ms_major = ddi_driver_major(dip); 27525cf1a30Sjl dm2sp->ms_ppa = instance; 27625cf1a30Sjl 27725cf1a30Sjl /* 27825cf1a30Sjl * Get an interrupt block cookie corresponding to the 27925cf1a30Sjl * interrupt priority of the event handler. 28025cf1a30Sjl * Assert that the event priority is not re-defined to 28125cf1a30Sjl * some higher priority. 28225cf1a30Sjl */ 28325cf1a30Sjl /* LINTED */ 28425cf1a30Sjl ASSERT(SCF_EVENT_PRI == DDI_SOFTINT_LOW); 28525cf1a30Sjl if (ddi_get_soft_iblock_cookie(dip, SCF_EVENT_PRI, 28625cf1a30Sjl &dm2sp->ms_ibcookie) != DDI_SUCCESS) { 28725cf1a30Sjl cmn_err(CE_WARN, "ddi_get_soft_iblock_cookie failed."); 28825cf1a30Sjl goto error; 28925cf1a30Sjl } 29025cf1a30Sjl mutex_init(&dm2sp->ms_lock, NULL, MUTEX_DRIVER, 29125cf1a30Sjl (void *)dm2sp->ms_ibcookie); 29225cf1a30Sjl 29325cf1a30Sjl dm2sp->ms_clean |= DM2S_CLEAN_LOCK; 29425cf1a30Sjl cv_init(&dm2sp->ms_wait, NULL, CV_DRIVER, NULL); 29525cf1a30Sjl dm2sp->ms_clean |= DM2S_CLEAN_CV; 29625cf1a30Sjl 29725cf1a30Sjl (void) sprintf(name, "%s%d", DM2S_MODNAME, instance); 29825cf1a30Sjl if (ddi_create_minor_node(dip, name, S_IFCHR, instance, 29925cf1a30Sjl DDI_PSEUDO, NULL) == DDI_FAILURE) { 30025cf1a30Sjl ddi_remove_minor_node(dip, NULL); 30125cf1a30Sjl cmn_err(CE_WARN, "Device node creation failed."); 30225cf1a30Sjl goto error; 30325cf1a30Sjl } 30425cf1a30Sjl 30525cf1a30Sjl dm2sp->ms_clean |= DM2S_CLEAN_NODE; 30625cf1a30Sjl ddi_set_driver_private(dip, (caddr_t)dm2sp); 30725cf1a30Sjl ddi_report_dev(dip); 30825cf1a30Sjl return (DDI_SUCCESS); 30925cf1a30Sjl error: 31025cf1a30Sjl dm2s_cleanup(dm2sp); 31125cf1a30Sjl return (DDI_FAILURE); 31225cf1a30Sjl } 31325cf1a30Sjl 31425cf1a30Sjl /* 31525cf1a30Sjl * dm2s_info - Module's info routine. 31625cf1a30Sjl */ 31725cf1a30Sjl /*ARGSUSED*/ 31825cf1a30Sjl int 31925cf1a30Sjl dm2s_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 32025cf1a30Sjl { 32125cf1a30Sjl dm2s_t *dm2sp; 32225cf1a30Sjl minor_t minor; 32325cf1a30Sjl int ret = DDI_FAILURE; 32425cf1a30Sjl 32525cf1a30Sjl switch (infocmd) { 32625cf1a30Sjl case DDI_INFO_DEVT2DEVINFO: 32725cf1a30Sjl minor = getminor((dev_t)arg); 32825cf1a30Sjl dm2sp = (dm2s_t *)ddi_get_soft_state(dm2s_softstate, minor); 32925cf1a30Sjl if (dm2sp == NULL) { 33025cf1a30Sjl *result = NULL; 33125cf1a30Sjl } else { 33225cf1a30Sjl *result = dm2sp->ms_dip; 33325cf1a30Sjl ret = DDI_SUCCESS; 33425cf1a30Sjl } 33525cf1a30Sjl break; 33625cf1a30Sjl 33725cf1a30Sjl case DDI_INFO_DEVT2INSTANCE: 33825cf1a30Sjl minor = getminor((dev_t)arg); 33925cf1a30Sjl *result = (void *)(uintptr_t)minor; 34025cf1a30Sjl ret = DDI_SUCCESS; 34125cf1a30Sjl break; 34225cf1a30Sjl 34325cf1a30Sjl default: 34425cf1a30Sjl break; 34525cf1a30Sjl } 34625cf1a30Sjl return (ret); 34725cf1a30Sjl } 34825cf1a30Sjl 34925cf1a30Sjl /* 35025cf1a30Sjl * dm2s_detach - Module's detach routine. 35125cf1a30Sjl */ 35225cf1a30Sjl int 35325cf1a30Sjl dm2s_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 35425cf1a30Sjl { 35525cf1a30Sjl int instance; 35625cf1a30Sjl dm2s_t *dm2sp; 35725cf1a30Sjl 35825cf1a30Sjl if (cmd != DDI_DETACH) { 35925cf1a30Sjl return (DDI_FAILURE); 36025cf1a30Sjl } 36125cf1a30Sjl 36225cf1a30Sjl instance = ddi_get_instance(dip); 36325cf1a30Sjl dm2sp = (dm2s_t *)ddi_get_soft_state(dm2s_softstate, instance); 36425cf1a30Sjl if (dm2sp == NULL) { 36525cf1a30Sjl return (DDI_FAILURE); 36625cf1a30Sjl } 36725cf1a30Sjl 36825cf1a30Sjl mutex_enter(&dm2sp->ms_lock); 36925cf1a30Sjl 37025cf1a30Sjl /* Check if the mailbox is still in use. */ 37125cf1a30Sjl if (dm2sp->ms_state & DM2S_MB_INITED) { 37225cf1a30Sjl mutex_exit(&dm2sp->ms_lock); 37325cf1a30Sjl cmn_err(CE_WARN, "Mailbox in use: Detach failed"); 37425cf1a30Sjl return (DDI_FAILURE); 37525cf1a30Sjl } 37625cf1a30Sjl mutex_exit(&dm2sp->ms_lock); 37725cf1a30Sjl dm2s_cleanup(dm2sp); 37825cf1a30Sjl return (DDI_SUCCESS); 37925cf1a30Sjl } 38025cf1a30Sjl 38125cf1a30Sjl /* 38225cf1a30Sjl * dm2s_open - Device open routine. 38325cf1a30Sjl * 38425cf1a30Sjl * Only one open supported. Clone open is not supported. 38525cf1a30Sjl */ 38625cf1a30Sjl /* ARGSUSED */ 38725cf1a30Sjl int 38825cf1a30Sjl dm2s_open(queue_t *rq, dev_t *dev, int flag, int sflag, cred_t *cr) 38925cf1a30Sjl { 39025cf1a30Sjl dm2s_t *dm2sp; 39125cf1a30Sjl int instance = getminor(*dev); 39225cf1a30Sjl int ret = 0; 39325cf1a30Sjl 39425cf1a30Sjl DPRINTF(DBG_DRV, ("dm2s_open: called\n")); 39525cf1a30Sjl if (sflag == CLONEOPEN) { 39625cf1a30Sjl /* Clone open not supported */ 39725cf1a30Sjl DPRINTF(DBG_WARN, ("dm2s_open: clone open not supported\n")); 39825cf1a30Sjl return (ENOTSUP); 39925cf1a30Sjl } 40025cf1a30Sjl 40125cf1a30Sjl if (rq->q_ptr != NULL) { 40225cf1a30Sjl DPRINTF(DBG_WARN, ("dm2s_open: already opened\n")); 40325cf1a30Sjl return (EBUSY); 40425cf1a30Sjl } 40525cf1a30Sjl 40625cf1a30Sjl if ((dm2sp = ddi_get_soft_state(dm2s_softstate, instance)) == NULL) { 40725cf1a30Sjl DPRINTF(DBG_WARN, ("dm2s_open: instance not found\n")); 40825cf1a30Sjl return (ENODEV); 40925cf1a30Sjl } 41025cf1a30Sjl 41125cf1a30Sjl mutex_enter(&dm2sp->ms_lock); 41225cf1a30Sjl if (dm2sp->ms_state & DM2S_OPENED) { 41325cf1a30Sjl /* Only one open supported */ 41425cf1a30Sjl mutex_exit(&dm2sp->ms_lock); 41525cf1a30Sjl DPRINTF(DBG_WARN, ("dm2s_open: already opened\n")); 41625cf1a30Sjl return (EBUSY); 41725cf1a30Sjl } 41825cf1a30Sjl 41925cf1a30Sjl dm2sp->ms_state |= DM2S_OPENED; 42025cf1a30Sjl /* Initialize the mailbox. */ 42125cf1a30Sjl if ((ret = dm2s_mbox_init(dm2sp)) != 0) { 42225cf1a30Sjl dm2sp->ms_state = 0; 42325cf1a30Sjl mutex_exit(&dm2sp->ms_lock); 42425cf1a30Sjl return (ret); 42525cf1a30Sjl } 42625cf1a30Sjl rq->q_ptr = WR(rq)->q_ptr = (void *)dm2sp; 42725cf1a30Sjl dm2sp->ms_rq = rq; 42825cf1a30Sjl dm2sp->ms_wq = WR(rq); 42925cf1a30Sjl mutex_exit(&dm2sp->ms_lock); 43025cf1a30Sjl 43125cf1a30Sjl if (ret == 0) { 43225cf1a30Sjl qprocson(rq); /* now schedule our queue */ 43325cf1a30Sjl } 43425cf1a30Sjl DPRINTF(DBG_DRV, ("dm2s_open: ret=%d\n", ret)); 43525cf1a30Sjl return (ret); 43625cf1a30Sjl } 43725cf1a30Sjl 43825cf1a30Sjl /* 43925cf1a30Sjl * dm2s_close - Device close routine. 44025cf1a30Sjl */ 44125cf1a30Sjl /* ARGSUSED */ 44225cf1a30Sjl int 44325cf1a30Sjl dm2s_close(queue_t *rq, int flag, cred_t *cred) 44425cf1a30Sjl { 44525cf1a30Sjl dm2s_t *dm2sp = (dm2s_t *)rq->q_ptr; 44625cf1a30Sjl 44725cf1a30Sjl DPRINTF(DBG_DRV, ("dm2s_close: called\n")); 44825cf1a30Sjl if (dm2sp == NULL) { 44925cf1a30Sjl /* Already closed once */ 45025cf1a30Sjl return (ENODEV); 45125cf1a30Sjl } 45225cf1a30Sjl 45325cf1a30Sjl /* Close the lower layer first */ 45425cf1a30Sjl mutex_enter(&dm2sp->ms_lock); 45525cf1a30Sjl (void) scf_mb_flush(dm2sp->ms_target, dm2sp->ms_key, MB_FLUSH_ALL); 45625cf1a30Sjl dm2s_mbox_fini(dm2sp); 45725cf1a30Sjl mutex_exit(&dm2sp->ms_lock); 45825cf1a30Sjl 45925cf1a30Sjl /* 46025cf1a30Sjl * Now we can assume that no asynchronous callbacks exist. 46125cf1a30Sjl * Poison the stream head so that we can't be pushed again. 46225cf1a30Sjl */ 46325cf1a30Sjl (void) putnextctl(rq, M_HANGUP); 46425cf1a30Sjl qprocsoff(rq); 46525cf1a30Sjl if (dm2sp->ms_rbufcid != 0) { 46625cf1a30Sjl qunbufcall(rq, dm2sp->ms_rbufcid); 46725cf1a30Sjl dm2sp->ms_rbufcid = 0; 46825cf1a30Sjl } 46925cf1a30Sjl if (dm2sp->ms_rq_timeoutid != 0) { 47025cf1a30Sjl DTRACE_PROBE1(dm2s_rqtimeout__cancel, dm2s_t, dm2sp); 47125cf1a30Sjl (void) quntimeout(dm2sp->ms_rq, dm2sp->ms_rq_timeoutid); 47225cf1a30Sjl dm2sp->ms_rq_timeoutid = 0; 47325cf1a30Sjl } 47425cf1a30Sjl if (dm2sp->ms_wq_timeoutid != 0) { 47525cf1a30Sjl DTRACE_PROBE1(dm2s_wqtimeout__cancel, dm2s_t, dm2sp); 47625cf1a30Sjl (void) quntimeout(dm2sp->ms_wq, dm2sp->ms_wq_timeoutid); 47725cf1a30Sjl dm2sp->ms_wq_timeoutid = 0; 47825cf1a30Sjl } 47925cf1a30Sjl /* 48025cf1a30Sjl * Now we can really mark it closed. 48125cf1a30Sjl */ 48225cf1a30Sjl mutex_enter(&dm2sp->ms_lock); 48325cf1a30Sjl dm2sp->ms_rq = dm2sp->ms_wq = NULL; 48425cf1a30Sjl dm2sp->ms_state &= ~DM2S_OPENED; 48525cf1a30Sjl mutex_exit(&dm2sp->ms_lock); 48625cf1a30Sjl 48725cf1a30Sjl rq->q_ptr = WR(rq)->q_ptr = NULL; 48825cf1a30Sjl (void) qassociate(rq, -1); 48925cf1a30Sjl DPRINTF(DBG_DRV, ("dm2s_close: successfully closed\n")); 49025cf1a30Sjl return (0); 49125cf1a30Sjl } 49225cf1a30Sjl 49325cf1a30Sjl /* 49425cf1a30Sjl * dm2s_rsrv - Streams read side service procedure. 49525cf1a30Sjl * 49625cf1a30Sjl * All messages are received in the service procedure 49725cf1a30Sjl * only. This is done to simplify the streams synchronization. 49825cf1a30Sjl */ 49925cf1a30Sjl int 50025cf1a30Sjl dm2s_rsrv(queue_t *rq) 50125cf1a30Sjl { 50225cf1a30Sjl mblk_t *mp; 50325cf1a30Sjl dm2s_t *dm2sp = (dm2s_t *)rq->q_ptr; 50425cf1a30Sjl 50525cf1a30Sjl DPRINTF(DBG_DRV, ("dm2s_rsrv: called\n")); 50625cf1a30Sjl ASSERT(dm2sp != NULL); 50725cf1a30Sjl mutex_enter(&dm2sp->ms_lock); 50825cf1a30Sjl 50925cf1a30Sjl /* Receive if there are any messages waiting in the mailbox. */ 51025cf1a30Sjl dm2s_receive(dm2sp); 51125cf1a30Sjl mutex_exit(&dm2sp->ms_lock); 51225cf1a30Sjl 51325cf1a30Sjl /* Send the received messages up the stream. */ 51425cf1a30Sjl while ((mp = getq(rq)) != NULL) { 51525cf1a30Sjl if (canputnext(rq)) { 51625cf1a30Sjl putnext(rq, mp); 51725cf1a30Sjl } else { 51825cf1a30Sjl putbq(rq, mp); 51925cf1a30Sjl break; 52025cf1a30Sjl } 52125cf1a30Sjl } 52225cf1a30Sjl DPRINTF(DBG_DRV, ("dm2s_rsrv: return\n")); 52325cf1a30Sjl return (0); 52425cf1a30Sjl } 52525cf1a30Sjl 52625cf1a30Sjl /* 52725cf1a30Sjl * dm2s_wsrv - Streams write side service procedure. 52825cf1a30Sjl * 52925cf1a30Sjl * All messages are transmitted in the service procedure 53025cf1a30Sjl * only. This is done to simplify the streams synchronization. 53125cf1a30Sjl */ 53225cf1a30Sjl int 53325cf1a30Sjl dm2s_wsrv(queue_t *wq) 53425cf1a30Sjl { 53525cf1a30Sjl dm2s_t *dm2sp = (dm2s_t *)wq->q_ptr; 53625cf1a30Sjl 53725cf1a30Sjl DPRINTF(DBG_DRV, ("dm2s_wsrv: called\n")); 53825cf1a30Sjl ASSERT(dm2sp != NULL); 53925cf1a30Sjl /* Lets cancel any timeouts waiting to be scheduled. */ 54025cf1a30Sjl if (dm2sp->ms_wq_timeoutid != 0) { 54125cf1a30Sjl DTRACE_PROBE1(dm2s_wqtimeout__cancel, dm2s_t, dm2sp); 54225cf1a30Sjl (void) quntimeout(dm2sp->ms_wq, dm2sp->ms_wq_timeoutid); 54325cf1a30Sjl dm2sp->ms_wq_timeoutid = 0; 54425cf1a30Sjl } 54525cf1a30Sjl mutex_enter(&dm2sp->ms_lock); 54625cf1a30Sjl dm2s_start(wq, dm2sp); 54725cf1a30Sjl mutex_exit(&dm2sp->ms_lock); 54825cf1a30Sjl DPRINTF(DBG_DRV, ("dm2s_wsrv: return\n")); 54925cf1a30Sjl return (0); 55025cf1a30Sjl } 55125cf1a30Sjl 55225cf1a30Sjl /* 55325cf1a30Sjl * dm2s_wput - Streams write side put routine. 55425cf1a30Sjl * 55525cf1a30Sjl * All M_DATA messages are queued so that they are transmitted in 55625cf1a30Sjl * the service procedure. This is done to simplify the streams 55725cf1a30Sjl * synchronization. Other messages are handled appropriately. 55825cf1a30Sjl */ 55925cf1a30Sjl int 56025cf1a30Sjl dm2s_wput(queue_t *wq, mblk_t *mp) 56125cf1a30Sjl { 56225cf1a30Sjl dm2s_t *dm2sp = (dm2s_t *)wq->q_ptr; 56325cf1a30Sjl 56425cf1a30Sjl DPRINTF(DBG_DRV, ("dm2s_wput: called\n")); 56525cf1a30Sjl if (dm2sp == NULL) { 56625cf1a30Sjl return (ENODEV); /* Can't happen. */ 56725cf1a30Sjl } 56825cf1a30Sjl 56925cf1a30Sjl switch (mp->b_datap->db_type) { 57025cf1a30Sjl case (M_DATA): 57125cf1a30Sjl DPRINTF(DBG_DRV, ("dm2s_wput: M_DATA message\n")); 57225cf1a30Sjl while (mp->b_wptr == mp->b_rptr) { 57325cf1a30Sjl mblk_t *mp1; 57425cf1a30Sjl 57525cf1a30Sjl mp1 = unlinkb(mp); 57625cf1a30Sjl freemsg(mp); 57725cf1a30Sjl mp = mp1; 57825cf1a30Sjl if (mp == NULL) { 57925cf1a30Sjl return (0); 58025cf1a30Sjl } 58125cf1a30Sjl } 58225cf1a30Sjl 58325cf1a30Sjl /* 58425cf1a30Sjl * Simply queue the message and handle it in the service 58525cf1a30Sjl * procedure. 58625cf1a30Sjl */ 58725cf1a30Sjl (void) putq(wq, mp); 58825cf1a30Sjl qenable(wq); 58925cf1a30Sjl return (0); 59025cf1a30Sjl 59125cf1a30Sjl case (M_PROTO): 59225cf1a30Sjl DPRINTF(DBG_DRV, ("dm2s_wput: M_PROTO message\n")); 59325cf1a30Sjl /* We don't expect this */ 59425cf1a30Sjl mp->b_datap->db_type = M_ERROR; 59525cf1a30Sjl mp->b_rptr = mp->b_wptr = mp->b_datap->db_base; 59625cf1a30Sjl *mp->b_wptr++ = EPROTO; 59725cf1a30Sjl qreply(wq, mp); 59825cf1a30Sjl return (EINVAL); 59925cf1a30Sjl 60025cf1a30Sjl case (M_IOCTL): 60125cf1a30Sjl DPRINTF(DBG_DRV, ("dm2s_wput: M_IOCTL message\n")); 60225cf1a30Sjl if (MBLKL(mp) < sizeof (struct iocblk)) { 60325cf1a30Sjl freemsg(mp); 60425cf1a30Sjl return (0); 60525cf1a30Sjl } 60625cf1a30Sjl /* 60725cf1a30Sjl * No ioctls required to be supported by this driver, so 60825cf1a30Sjl * return EINVAL for all ioctls. 60925cf1a30Sjl */ 61025cf1a30Sjl miocnak(wq, mp, 0, EINVAL); 61125cf1a30Sjl break; 61225cf1a30Sjl 61325cf1a30Sjl case (M_CTL): 61425cf1a30Sjl DPRINTF(DBG_DRV, ("dm2s_wput: M_CTL message\n")); 61525cf1a30Sjl /* 61625cf1a30Sjl * No M_CTL messages need to supported by this driver, 61725cf1a30Sjl * so simply ignore them. 61825cf1a30Sjl */ 61925cf1a30Sjl freemsg(mp); 62025cf1a30Sjl break; 62125cf1a30Sjl 62225cf1a30Sjl case (M_FLUSH): 62325cf1a30Sjl DPRINTF(DBG_DRV, ( 62425cf1a30Sjl "dm2s_wput: M_FLUSH message 0x%X\n", *mp->b_rptr)); 62525cf1a30Sjl if (*mp->b_rptr & FLUSHW) { /* Flush write-side */ 62625cf1a30Sjl (void) scf_mb_flush(dm2sp->ms_target, dm2sp->ms_key, 62725cf1a30Sjl MB_FLUSH_SEND); 62825cf1a30Sjl flushq(wq, FLUSHDATA); 62925cf1a30Sjl *mp->b_rptr &= ~FLUSHW; 63025cf1a30Sjl } 63125cf1a30Sjl if (*mp->b_rptr & FLUSHR) { 63225cf1a30Sjl (void) scf_mb_flush(dm2sp->ms_target, dm2sp->ms_key, 63325cf1a30Sjl MB_FLUSH_RECEIVE); 63425cf1a30Sjl flushq(RD(wq), FLUSHDATA); 63525cf1a30Sjl qreply(wq, mp); 63625cf1a30Sjl } else { 63725cf1a30Sjl freemsg(mp); 63825cf1a30Sjl } 63925cf1a30Sjl break; 64025cf1a30Sjl 64125cf1a30Sjl default: 64225cf1a30Sjl DPRINTF(DBG_DRV, ("dm2s_wput: UNKNOWN message\n")); 64325cf1a30Sjl freemsg(mp); 64425cf1a30Sjl 64525cf1a30Sjl } 64625cf1a30Sjl return (0); 64725cf1a30Sjl } 64825cf1a30Sjl 64925cf1a30Sjl /* 65025cf1a30Sjl * dm2s_cleanup - Cleanup routine. 65125cf1a30Sjl */ 65225cf1a30Sjl static void 65325cf1a30Sjl dm2s_cleanup(dm2s_t *dm2sp) 65425cf1a30Sjl { 65525cf1a30Sjl char name[20]; 65625cf1a30Sjl 65725cf1a30Sjl DPRINTF(DBG_DRV, ("dm2s_cleanup: called\n")); 65825cf1a30Sjl ASSERT(dm2sp != NULL); 65925cf1a30Sjl if (dm2sp->ms_clean & DM2S_CLEAN_NODE) { 66025cf1a30Sjl (void) sprintf(name, "%s%d", DM2S_MODNAME, dm2sp->ms_ppa); 66125cf1a30Sjl ddi_remove_minor_node(dm2sp->ms_dip, name); 66225cf1a30Sjl } 66325cf1a30Sjl if (dm2sp->ms_clean & DM2S_CLEAN_LOCK) 66425cf1a30Sjl mutex_destroy(&dm2sp->ms_lock); 66525cf1a30Sjl if (dm2sp->ms_clean & DM2S_CLEAN_CV) 66625cf1a30Sjl cv_destroy(&dm2sp->ms_wait); 66725cf1a30Sjl ddi_set_driver_private(dm2sp->ms_dip, NULL); 66825cf1a30Sjl ddi_soft_state_free(dm2s_softstate, dm2sp->ms_ppa); 66925cf1a30Sjl } 67025cf1a30Sjl 67125cf1a30Sjl /* 67225cf1a30Sjl * dm2s_mbox_init - Mailbox specific initialization. 67325cf1a30Sjl */ 67425cf1a30Sjl static int 67525cf1a30Sjl dm2s_mbox_init(dm2s_t *dm2sp) 67625cf1a30Sjl { 67725cf1a30Sjl int ret; 67825cf1a30Sjl clock_t tout; 67925cf1a30Sjl 68025cf1a30Sjl ASSERT(MUTEX_HELD(&dm2sp->ms_lock)); 68125cf1a30Sjl dm2sp->ms_target = DM2S_TARGET_ID; 68225cf1a30Sjl dm2sp->ms_key = DSCP_KEY; 68325cf1a30Sjl dm2sp->ms_state &= ~DM2S_MB_INITED; 68425cf1a30Sjl 68525cf1a30Sjl /* Iterate until mailbox gets connected */ 68625cf1a30Sjl while (!(dm2sp->ms_state & DM2S_MB_CONN)) { 68725cf1a30Sjl DPRINTF(DBG_MBOX, ("dm2s_mbox_init: calling mb_init\n")); 68825cf1a30Sjl ret = scf_mb_init(dm2sp->ms_target, dm2sp->ms_key, 68925cf1a30Sjl dm2s_event_handler, (void *)dm2sp); 69025cf1a30Sjl DPRINTF(DBG_MBOX, ("dm2s_mbox_init: mb_init ret=%d\n", ret)); 69125cf1a30Sjl 692030f3a8fSraghuram if (ret != 0) { 693030f3a8fSraghuram DPRINTF(DBG_MBOX, 694030f3a8fSraghuram ("dm2s_mbox_init: failed ret =%d\n", ret)); 695030f3a8fSraghuram DTRACE_PROBE1(dm2s_mbox_fail, int, ret); 696030f3a8fSraghuram } else { 69725cf1a30Sjl dm2sp->ms_state |= DM2S_MB_INITED; 69825cf1a30Sjl 69925cf1a30Sjl /* Block until the mailbox is ready to communicate. */ 70025cf1a30Sjl while (!(dm2sp->ms_state & 70125cf1a30Sjl (DM2S_MB_CONN | DM2S_MB_DISC))) { 70225cf1a30Sjl 70325cf1a30Sjl if (cv_wait_sig(&dm2sp->ms_wait, 70425cf1a30Sjl &dm2sp->ms_lock) <= 0) { 70525cf1a30Sjl /* interrupted */ 70625cf1a30Sjl ret = EINTR; 70725cf1a30Sjl break; 70825cf1a30Sjl } 70925cf1a30Sjl } 71025cf1a30Sjl } 71125cf1a30Sjl 712030f3a8fSraghuram if ((ret != 0) || (dm2sp->ms_state & DM2S_MB_DISC)) { 71325cf1a30Sjl 714030f3a8fSraghuram if (dm2sp->ms_state & DM2S_MB_INITED) { 715030f3a8fSraghuram (void) scf_mb_fini(dm2sp->ms_target, 716030f3a8fSraghuram dm2sp->ms_key); 717030f3a8fSraghuram } 718030f3a8fSraghuram if (dm2sp->ms_state & DM2S_MB_DISC) { 719030f3a8fSraghuram DPRINTF(DBG_WARN, 720030f3a8fSraghuram ("dm2s_mbox_init: mbox DISC_ERROR\n")); 721030f3a8fSraghuram DTRACE_PROBE1(dm2s_mbox_fail, 722030f3a8fSraghuram int, DM2S_MB_DISC); 723030f3a8fSraghuram } 72425cf1a30Sjl 725030f3a8fSraghuram dm2sp->ms_state &= ~(DM2S_MB_INITED | DM2S_MB_DISC | 726030f3a8fSraghuram DM2S_MB_CONN); 72725cf1a30Sjl 728030f3a8fSraghuram if (ret == EINTR) { 729030f3a8fSraghuram return (ret); 730030f3a8fSraghuram } 73125cf1a30Sjl 73225cf1a30Sjl /* 73325cf1a30Sjl * If there was failure, then wait for 73425cf1a30Sjl * DM2S_MB_TOUT secs and retry again. 73525cf1a30Sjl */ 73625cf1a30Sjl 73725cf1a30Sjl DPRINTF(DBG_MBOX, ("dm2s_mbox_init: waiting...\n")); 73825cf1a30Sjl tout = ddi_get_lbolt() + drv_usectohz(DM2S_MB_TOUT); 73925cf1a30Sjl ret = cv_timedwait_sig(&dm2sp->ms_wait, 74025cf1a30Sjl &dm2sp->ms_lock, tout); 74125cf1a30Sjl if (ret == 0) { 74225cf1a30Sjl /* if interrupted, return immediately. */ 74325cf1a30Sjl DPRINTF(DBG_MBOX, 74425cf1a30Sjl ("dm2s_mbox_init: interrupted\n")); 74525cf1a30Sjl return (EINTR); 74625cf1a30Sjl } 74725cf1a30Sjl } 74825cf1a30Sjl } 74925cf1a30Sjl 75025cf1a30Sjl /* 75125cf1a30Sjl * Obtain the max size of a single message. 75225cf1a30Sjl * NOTE: There is no mechanism to update the 75325cf1a30Sjl * upperlayers dynamically, so we expect this 75425cf1a30Sjl * size to be atleast the default MTU size. 75525cf1a30Sjl */ 75625cf1a30Sjl ret = scf_mb_ctrl(dm2sp->ms_target, dm2sp->ms_key, 75725cf1a30Sjl SCF_MBOP_MAXMSGSIZE, &dm2sp->ms_mtu); 75825cf1a30Sjl 75925cf1a30Sjl if ((ret == 0) && (dm2sp->ms_mtu < DM2S_DEF_MTU)) { 76025cf1a30Sjl cmn_err(CE_WARN, "Max message size expected >= %d " 76125cf1a30Sjl "but found %d\n", DM2S_DEF_MTU, dm2sp->ms_mtu); 76225cf1a30Sjl ret = EIO; 76325cf1a30Sjl } 76425cf1a30Sjl 76525cf1a30Sjl if (ret != 0) { 76625cf1a30Sjl dm2sp->ms_state &= ~DM2S_MB_INITED; 76725cf1a30Sjl (void) scf_mb_fini(dm2sp->ms_target, dm2sp->ms_key); 76825cf1a30Sjl } 76925cf1a30Sjl DPRINTF(DBG_MBOX, ("dm2s_mbox_init: mb_init ret=%d\n", ret)); 77025cf1a30Sjl return (ret); 77125cf1a30Sjl } 77225cf1a30Sjl 77325cf1a30Sjl /* 77425cf1a30Sjl * dm2s_mbox_fini - Mailbox de-initialization. 77525cf1a30Sjl */ 77625cf1a30Sjl static void 77725cf1a30Sjl dm2s_mbox_fini(dm2s_t *dm2sp) 77825cf1a30Sjl { 77925cf1a30Sjl int ret; 78025cf1a30Sjl 78125cf1a30Sjl ASSERT(dm2sp != NULL); 78225cf1a30Sjl if (dm2sp->ms_state & DM2S_MB_INITED) { 78325cf1a30Sjl DPRINTF(DBG_MBOX, ("dm2s_mbox_fini: calling mb_fini\n")); 78425cf1a30Sjl ret = scf_mb_fini(dm2sp->ms_target, dm2sp->ms_key); 78525cf1a30Sjl if (ret != 0) { 78625cf1a30Sjl cmn_err(CE_WARN, 78725cf1a30Sjl "Failed to close the Mailbox error =%d", ret); 78825cf1a30Sjl } 78925cf1a30Sjl DPRINTF(DBG_MBOX, ("dm2s_mbox_fini: mb_fini ret=%d\n", ret)); 79025cf1a30Sjl dm2sp->ms_state &= ~(DM2S_MB_INITED |DM2S_MB_CONN | 79125cf1a30Sjl DM2S_MB_DISC); 79225cf1a30Sjl } 79325cf1a30Sjl } 79425cf1a30Sjl 79525cf1a30Sjl /* 79625cf1a30Sjl * dm2s_event_handler - Mailbox event handler. 79725cf1a30Sjl */ 79825cf1a30Sjl void 79925cf1a30Sjl dm2s_event_handler(scf_event_t event, void *arg) 80025cf1a30Sjl { 80125cf1a30Sjl dm2s_t *dm2sp = (dm2s_t *)arg; 80225cf1a30Sjl queue_t *rq; 80325cf1a30Sjl 80425cf1a30Sjl ASSERT(dm2sp != NULL); 80525cf1a30Sjl mutex_enter(&dm2sp->ms_lock); 80625cf1a30Sjl if (!(dm2sp->ms_state & DM2S_MB_INITED)) { 80725cf1a30Sjl /* 80825cf1a30Sjl * Ignore all events if the state flag indicates that the 80925cf1a30Sjl * mailbox not initialized, this may happen during the close. 81025cf1a30Sjl */ 81125cf1a30Sjl mutex_exit(&dm2sp->ms_lock); 81225cf1a30Sjl DPRINTF(DBG_MBOX, 81325cf1a30Sjl ("Event(0x%X) received - Mailbox not inited\n", event)); 81425cf1a30Sjl return; 81525cf1a30Sjl } 81625cf1a30Sjl switch (event) { 81725cf1a30Sjl case SCF_MB_CONN_OK: 81825cf1a30Sjl /* 81925cf1a30Sjl * Now the mailbox is ready to use, lets wake up 82025cf1a30Sjl * any one waiting for this event. 82125cf1a30Sjl */ 82225cf1a30Sjl dm2sp->ms_state |= DM2S_MB_CONN; 82325cf1a30Sjl cv_broadcast(&dm2sp->ms_wait); 82425cf1a30Sjl DPRINTF(DBG_MBOX, ("Event received = CONN_OK\n")); 82525cf1a30Sjl break; 82625cf1a30Sjl 82725cf1a30Sjl case SCF_MB_MSG_DATA: 82825cf1a30Sjl if (!DM2S_MBOX_READY(dm2sp)) { 82925cf1a30Sjl DPRINTF(DBG_MBOX, 83025cf1a30Sjl ("Event(MSG_DATA) received - Mailbox not READY\n")); 83125cf1a30Sjl break; 83225cf1a30Sjl } 83325cf1a30Sjl /* 83425cf1a30Sjl * A message is available in the mailbox. 83525cf1a30Sjl * Lets enable the read service procedure 83625cf1a30Sjl * to receive this message. 83725cf1a30Sjl */ 83825cf1a30Sjl if (dm2sp->ms_rq != NULL) { 83925cf1a30Sjl qenable(dm2sp->ms_rq); 84025cf1a30Sjl } 84125cf1a30Sjl DPRINTF(DBG_MBOX, ("Event received = MSG_DATA\n")); 84225cf1a30Sjl break; 84325cf1a30Sjl 84425cf1a30Sjl case SCF_MB_SPACE: 84525cf1a30Sjl if (!DM2S_MBOX_READY(dm2sp)) { 84625cf1a30Sjl DPRINTF(DBG_MBOX, 84725cf1a30Sjl ("Event(MB_SPACE) received - Mailbox not READY\n")); 84825cf1a30Sjl break; 84925cf1a30Sjl } 85025cf1a30Sjl 85125cf1a30Sjl /* 85225cf1a30Sjl * Now the mailbox is ready to transmit, lets 85325cf1a30Sjl * schedule the write service procedure. 85425cf1a30Sjl */ 85525cf1a30Sjl if (dm2sp->ms_wq != NULL) { 85625cf1a30Sjl qenable(dm2sp->ms_wq); 85725cf1a30Sjl } 85825cf1a30Sjl DPRINTF(DBG_MBOX, ("Event received = MB_SPACE\n")); 85925cf1a30Sjl break; 86025cf1a30Sjl case SCF_MB_DISC_ERROR: 86125cf1a30Sjl dm2sp->ms_state |= DM2S_MB_DISC; 86225cf1a30Sjl if (dm2sp->ms_state & DM2S_MB_CONN) { 86325cf1a30Sjl /* 86425cf1a30Sjl * If it was previously connected, 86525cf1a30Sjl * then send a hangup message. 86625cf1a30Sjl */ 86725cf1a30Sjl rq = dm2sp->ms_rq; 86825cf1a30Sjl if (rq != NULL) { 86925cf1a30Sjl mutex_exit(&dm2sp->ms_lock); 87025cf1a30Sjl /* 87125cf1a30Sjl * Send a hangup message to indicate 87225cf1a30Sjl * disconnect event. 87325cf1a30Sjl */ 87425cf1a30Sjl (void) putctl(rq, M_HANGUP); 87525cf1a30Sjl DTRACE_PROBE1(dm2s_hangup, dm2s_t, dm2sp); 87625cf1a30Sjl mutex_enter(&dm2sp->ms_lock); 87725cf1a30Sjl } 87825cf1a30Sjl } else { 87925cf1a30Sjl /* 88025cf1a30Sjl * Signal if the open is waiting for a 88125cf1a30Sjl * connection. 88225cf1a30Sjl */ 88325cf1a30Sjl cv_broadcast(&dm2sp->ms_wait); 88425cf1a30Sjl } 88525cf1a30Sjl DPRINTF(DBG_MBOX, ("Event received = DISC_ERROR\n")); 88625cf1a30Sjl break; 88725cf1a30Sjl default: 88825cf1a30Sjl cmn_err(CE_WARN, "Unexpected event received\n"); 88925cf1a30Sjl break; 89025cf1a30Sjl } 89125cf1a30Sjl mutex_exit(&dm2sp->ms_lock); 89225cf1a30Sjl } 89325cf1a30Sjl 89425cf1a30Sjl /* 89525cf1a30Sjl * dm2s_start - Start transmission function. 89625cf1a30Sjl * 89725cf1a30Sjl * Send all queued messages. If the mailbox is busy, then 89825cf1a30Sjl * start a timeout as a polling mechanism. The timeout is useful 89925cf1a30Sjl * to not rely entirely on the SCF_MB_SPACE event. 90025cf1a30Sjl */ 90125cf1a30Sjl void 90225cf1a30Sjl dm2s_start(queue_t *wq, dm2s_t *dm2sp) 90325cf1a30Sjl { 90425cf1a30Sjl mblk_t *mp; 90525cf1a30Sjl int ret; 90625cf1a30Sjl 90725cf1a30Sjl DPRINTF(DBG_DRV, ("dm2s_start: called\n")); 90825cf1a30Sjl ASSERT(dm2sp != NULL); 90925cf1a30Sjl ASSERT(MUTEX_HELD(&dm2sp->ms_lock)); 91025cf1a30Sjl 91125cf1a30Sjl while ((mp = getq(wq)) != NULL) { 91225cf1a30Sjl switch (mp->b_datap->db_type) { 91325cf1a30Sjl 91425cf1a30Sjl case M_DATA: 91525cf1a30Sjl ret = dm2s_transmit(wq, mp, dm2sp->ms_target, 91625cf1a30Sjl dm2sp->ms_key); 91725cf1a30Sjl if (ret == EBUSY || ret == ENOSPC || ret == EAGAIN) { 91825cf1a30Sjl DPRINTF(DBG_MBOX, 91925cf1a30Sjl ("dm2s_start: recoverable err=%d\n", ret)); 92025cf1a30Sjl /* 92125cf1a30Sjl * Start a timeout to retry again. 92225cf1a30Sjl */ 92325cf1a30Sjl if (dm2sp->ms_wq_timeoutid == 0) { 92425cf1a30Sjl DTRACE_PROBE1(dm2s_wqtimeout__start, 92525cf1a30Sjl dm2s_t, dm2sp); 92625cf1a30Sjl dm2sp->ms_wq_timeoutid = qtimeout(wq, 92725cf1a30Sjl dm2s_wq_timeout, (void *)dm2sp, 92825cf1a30Sjl dm2s_timeout_val(ret)); 92925cf1a30Sjl } 93025cf1a30Sjl return; 93125cf1a30Sjl } else if (ret != 0) { 93225cf1a30Sjl mutex_exit(&dm2sp->ms_lock); 93325cf1a30Sjl /* 93425cf1a30Sjl * An error occurred with the transmission, 93525cf1a30Sjl * flush pending messages and initiate a 93625cf1a30Sjl * hangup. 93725cf1a30Sjl */ 93825cf1a30Sjl flushq(wq, FLUSHDATA); 93925cf1a30Sjl (void) putnextctl(RD(wq), M_HANGUP); 94025cf1a30Sjl DTRACE_PROBE1(dm2s_hangup, dm2s_t, dm2sp); 94125cf1a30Sjl DPRINTF(DBG_WARN, 94225cf1a30Sjl ("dm2s_start: hangup transmit err=%d\n", 94325cf1a30Sjl ret)); 94425cf1a30Sjl mutex_enter(&dm2sp->ms_lock); 94525cf1a30Sjl } 94625cf1a30Sjl break; 94725cf1a30Sjl default: 94825cf1a30Sjl /* 94925cf1a30Sjl * At this point, we don't expect any other messages. 95025cf1a30Sjl */ 95125cf1a30Sjl freemsg(mp); 95225cf1a30Sjl break; 95325cf1a30Sjl } 95425cf1a30Sjl } 95525cf1a30Sjl } 95625cf1a30Sjl 95725cf1a30Sjl /* 95825cf1a30Sjl * dm2s_receive - Read all messages from the mailbox. 95925cf1a30Sjl * 96025cf1a30Sjl * This function is called from the read service procedure, to 96125cf1a30Sjl * receive the messages awaiting in the mailbox. 96225cf1a30Sjl */ 96325cf1a30Sjl void 96425cf1a30Sjl dm2s_receive(dm2s_t *dm2sp) 96525cf1a30Sjl { 96625cf1a30Sjl queue_t *rq = dm2sp->ms_rq; 96725cf1a30Sjl mblk_t *mp; 96825cf1a30Sjl int ret; 96925cf1a30Sjl uint32_t len; 97025cf1a30Sjl 97125cf1a30Sjl DPRINTF(DBG_DRV, ("dm2s_receive: called\n")); 97225cf1a30Sjl ASSERT(dm2sp != NULL); 97325cf1a30Sjl ASSERT(MUTEX_HELD(&dm2sp->ms_lock)); 97425cf1a30Sjl if (rq == NULL) { 97525cf1a30Sjl return; 97625cf1a30Sjl } 97725cf1a30Sjl /* 97825cf1a30Sjl * As the number of messages in the mailbox are pretty limited, 97925cf1a30Sjl * it is safe to process all messages in one loop. 98025cf1a30Sjl */ 98125cf1a30Sjl while (DM2S_MBOX_READY(dm2sp) && ((ret = scf_mb_canget(dm2sp->ms_target, 98225cf1a30Sjl dm2sp->ms_key, &len)) == 0)) { 98325cf1a30Sjl DPRINTF(DBG_MBOX, ("dm2s_receive: mb_canget len=%d\n", len)); 98425cf1a30Sjl if (len == 0) { 98525cf1a30Sjl break; 98625cf1a30Sjl } 98725cf1a30Sjl mp = allocb(len, BPRI_MED); 98825cf1a30Sjl if (mp == NULL) { 98925cf1a30Sjl DPRINTF(DBG_WARN, ("dm2s_receive: allocb failed\n")); 99025cf1a30Sjl /* 99125cf1a30Sjl * Start a bufcall so that we can retry again 99225cf1a30Sjl * when memory becomes available. 99325cf1a30Sjl */ 99425cf1a30Sjl dm2sp->ms_rbufcid = qbufcall(rq, len, BPRI_MED, 99525cf1a30Sjl dm2s_bufcall_rcv, dm2sp); 99625cf1a30Sjl if (dm2sp->ms_rbufcid == 0) { 99725cf1a30Sjl DPRINTF(DBG_WARN, 99825cf1a30Sjl ("dm2s_receive: qbufcall failed\n")); 99925cf1a30Sjl /* 100025cf1a30Sjl * if bufcall fails, start a timeout to 100125cf1a30Sjl * initiate a re-try after some time. 100225cf1a30Sjl */ 100325cf1a30Sjl DTRACE_PROBE1(dm2s_rqtimeout__start, 100425cf1a30Sjl dm2s_t, dm2sp); 100525cf1a30Sjl dm2sp->ms_rq_timeoutid = qtimeout(rq, 100625cf1a30Sjl dm2s_rq_timeout, (void *)dm2sp, 100725cf1a30Sjl drv_usectohz(DM2S_SM_TOUT)); 100825cf1a30Sjl } 100925cf1a30Sjl break; 101025cf1a30Sjl } 101125cf1a30Sjl 101225cf1a30Sjl /* 101325cf1a30Sjl * Only a single scatter/gather element is enough here. 101425cf1a30Sjl */ 101525cf1a30Sjl dm2sp->ms_sg_rcv.msc_dptr = (caddr_t)mp->b_wptr; 101625cf1a30Sjl dm2sp->ms_sg_rcv.msc_len = len; 101725cf1a30Sjl DPRINTF(DBG_MBOX, ("dm2s_receive: calling getmsg\n")); 101825cf1a30Sjl ret = scf_mb_getmsg(dm2sp->ms_target, dm2sp->ms_key, len, 1, 101925cf1a30Sjl &dm2sp->ms_sg_rcv, 0); 102025cf1a30Sjl DPRINTF(DBG_MBOX, ("dm2s_receive: getmsg ret=%d\n", ret)); 102125cf1a30Sjl if (ret != 0) { 102225cf1a30Sjl freemsg(mp); 102325cf1a30Sjl break; 102425cf1a30Sjl } 102525cf1a30Sjl DMPBYTES("dm2s: Getmsg: ", len, 1, &dm2sp->ms_sg_rcv); 102625cf1a30Sjl mp->b_wptr += len; 102725cf1a30Sjl /* 102825cf1a30Sjl * Queue the messages in the rq, so that the service 102925cf1a30Sjl * procedure handles sending the messages up the stream. 103025cf1a30Sjl */ 103125cf1a30Sjl putq(rq, mp); 103225cf1a30Sjl } 103325cf1a30Sjl 103425cf1a30Sjl if ((!DM2S_MBOX_READY(dm2sp)) || (ret != ENOMSG && ret != EMSGSIZE)) { 103525cf1a30Sjl /* 103625cf1a30Sjl * Some thing went wrong, flush pending messages 103725cf1a30Sjl * and initiate a hangup. 103825cf1a30Sjl * Note: flushing the wq initiates a faster close. 103925cf1a30Sjl */ 104025cf1a30Sjl mutex_exit(&dm2sp->ms_lock); 104125cf1a30Sjl flushq(WR(rq), FLUSHDATA); 104225cf1a30Sjl (void) putnextctl(rq, M_HANGUP); 104325cf1a30Sjl DTRACE_PROBE1(dm2s_hangup, dm2s_t, dm2sp); 104425cf1a30Sjl mutex_enter(&dm2sp->ms_lock); 104525cf1a30Sjl DPRINTF(DBG_WARN, ("dm2s_receive: encountered unknown " 104625cf1a30Sjl "condition - hangup ret=%d\n", ret)); 104725cf1a30Sjl } 104825cf1a30Sjl } 104925cf1a30Sjl 105025cf1a30Sjl /* 105125cf1a30Sjl * dm2s_transmit - Transmit a message. 105225cf1a30Sjl */ 105325cf1a30Sjl int 105425cf1a30Sjl dm2s_transmit(queue_t *wq, mblk_t *mp, target_id_t target, mkey_t key) 105525cf1a30Sjl { 105625cf1a30Sjl dm2s_t *dm2sp = (dm2s_t *)wq->q_ptr; 105725cf1a30Sjl int ret; 105825cf1a30Sjl uint32_t len; 105925cf1a30Sjl uint32_t numsg; 106025cf1a30Sjl 106125cf1a30Sjl DPRINTF(DBG_DRV, ("dm2s_transmit: called\n")); 106225cf1a30Sjl ASSERT(dm2sp != NULL); 106325cf1a30Sjl ASSERT(MUTEX_HELD(&dm2sp->ms_lock)); 106425cf1a30Sjl /* 106525cf1a30Sjl * Free the message if the mailbox is not in the connected state. 106625cf1a30Sjl */ 106725cf1a30Sjl if (!DM2S_MBOX_READY(dm2sp)) { 106825cf1a30Sjl DPRINTF(DBG_MBOX, ("dm2s_transmit: mailbox not ready yet\n")); 106925cf1a30Sjl freemsg(mp); 107025cf1a30Sjl return (EIO); 107125cf1a30Sjl } 107225cf1a30Sjl 107325cf1a30Sjl len = msgdsize(mp); 107425cf1a30Sjl if (len > dm2sp->ms_mtu) { 107525cf1a30Sjl /* 107625cf1a30Sjl * Size is too big to send, free the message. 107725cf1a30Sjl */ 107825cf1a30Sjl DPRINTF(DBG_MBOX, ("dm2s_transmit: message too large\n")); 107925cf1a30Sjl DTRACE_PROBE2(dm2s_msg_too_big, dm2s_t, dm2sp, uint32_t, len); 108025cf1a30Sjl freemsg(mp); 108125cf1a30Sjl return (0); 108225cf1a30Sjl } 108325cf1a30Sjl 108425cf1a30Sjl if ((ret = dm2s_prep_scatgath(mp, &numsg, dm2sp->ms_sg_tx, 108525cf1a30Sjl DM2S_MAX_SG)) != 0) { 108625cf1a30Sjl DPRINTF(DBG_MBOX, ("dm2s_transmit: prep_scatgath failed\n")); 108725cf1a30Sjl putbq(wq, mp); 108825cf1a30Sjl return (EAGAIN); 108925cf1a30Sjl } 109025cf1a30Sjl DPRINTF(DBG_MBOX, ("dm2s_transmit: calling mb_putmsg numsg=%d len=%d\n", 109125cf1a30Sjl numsg, len)); 109225cf1a30Sjl ret = scf_mb_putmsg(target, key, len, numsg, dm2sp->ms_sg_tx, 0); 109325cf1a30Sjl if (ret == EBUSY || ret == ENOSPC) { 109425cf1a30Sjl DPRINTF(DBG_MBOX, 109525cf1a30Sjl ("dm2s_transmit: mailbox busy ret=%d\n", ret)); 109625cf1a30Sjl if (++dm2sp->ms_retries >= DM2S_MAX_RETRIES) { 109725cf1a30Sjl /* 109825cf1a30Sjl * If maximum retries are reached, then free the 109925cf1a30Sjl * message. 110025cf1a30Sjl */ 110125cf1a30Sjl DPRINTF(DBG_MBOX, 110225cf1a30Sjl ("dm2s_transmit: freeing msg after max retries\n")); 110325cf1a30Sjl DTRACE_PROBE2(dm2s_retry_fail, dm2s_t, dm2sp, int, ret); 110425cf1a30Sjl freemsg(mp); 110525cf1a30Sjl dm2sp->ms_retries = 0; 110625cf1a30Sjl return (0); 110725cf1a30Sjl } 110825cf1a30Sjl DTRACE_PROBE2(dm2s_mb_busy, dm2s_t, dm2sp, int, ret); 110925cf1a30Sjl /* 111025cf1a30Sjl * Queue it back, so that we can retry again. 111125cf1a30Sjl */ 111225cf1a30Sjl putbq(wq, mp); 111325cf1a30Sjl return (ret); 111425cf1a30Sjl } 111525cf1a30Sjl DMPBYTES("dm2s: Putmsg: ", len, numsg, dm2sp->ms_sg_tx); 111625cf1a30Sjl dm2sp->ms_retries = 0; 111725cf1a30Sjl freemsg(mp); 111825cf1a30Sjl DPRINTF(DBG_DRV, ("dm2s_transmit: ret=%d\n", ret)); 111925cf1a30Sjl return (ret); 112025cf1a30Sjl } 112125cf1a30Sjl 112225cf1a30Sjl /* 112325cf1a30Sjl * dm2s_bufcall_rcv - Bufcall callaback routine. 112425cf1a30Sjl * 112525cf1a30Sjl * It simply enables read side queue so that the service procedure 112625cf1a30Sjl * can retry receive operation. 112725cf1a30Sjl */ 112825cf1a30Sjl void 112925cf1a30Sjl dm2s_bufcall_rcv(void *arg) 113025cf1a30Sjl { 113125cf1a30Sjl dm2s_t *dm2sp = (dm2s_t *)arg; 113225cf1a30Sjl 113325cf1a30Sjl DPRINTF(DBG_DRV, ("dm2s_bufcall_rcv: called\n")); 113425cf1a30Sjl mutex_enter(&dm2sp->ms_lock); 113525cf1a30Sjl dm2sp->ms_rbufcid = 0; 113625cf1a30Sjl if (dm2sp->ms_rq != NULL) { 113725cf1a30Sjl qenable(dm2sp->ms_rq); 113825cf1a30Sjl } 113925cf1a30Sjl mutex_exit(&dm2sp->ms_lock); 114025cf1a30Sjl } 114125cf1a30Sjl 114225cf1a30Sjl /* 114325cf1a30Sjl * dm2s_rq_timeout - Timeout callback for the read side. 114425cf1a30Sjl * 114525cf1a30Sjl * It simply enables read side queue so that the service procedure 114625cf1a30Sjl * can retry the receive operation. 114725cf1a30Sjl */ 114825cf1a30Sjl void 114925cf1a30Sjl dm2s_rq_timeout(void *arg) 115025cf1a30Sjl { 115125cf1a30Sjl dm2s_t *dm2sp = (dm2s_t *)arg; 115225cf1a30Sjl 115325cf1a30Sjl DPRINTF(DBG_DRV, ("dm2s_rq_timeout: called\n")); 115425cf1a30Sjl mutex_enter(&dm2sp->ms_lock); 115525cf1a30Sjl dm2sp->ms_rq_timeoutid = 0; 115625cf1a30Sjl if (dm2sp->ms_rq != NULL) { 115725cf1a30Sjl qenable(dm2sp->ms_rq); 115825cf1a30Sjl } 115925cf1a30Sjl mutex_exit(&dm2sp->ms_lock); 116025cf1a30Sjl } 116125cf1a30Sjl 116225cf1a30Sjl /* 116325cf1a30Sjl * dm2s_wq_timeout - Timeout callback for the write. 116425cf1a30Sjl * 116525cf1a30Sjl * It simply enables write side queue so that the service procedure 116625cf1a30Sjl * can retry the transmission operation. 116725cf1a30Sjl */ 116825cf1a30Sjl void 116925cf1a30Sjl dm2s_wq_timeout(void *arg) 117025cf1a30Sjl { 117125cf1a30Sjl dm2s_t *dm2sp = (dm2s_t *)arg; 117225cf1a30Sjl 117325cf1a30Sjl DPRINTF(DBG_DRV, ("dm2s_wq_timeout: called\n")); 117425cf1a30Sjl mutex_enter(&dm2sp->ms_lock); 117525cf1a30Sjl dm2sp->ms_wq_timeoutid = 0; 117625cf1a30Sjl if (dm2sp->ms_wq != NULL) { 117725cf1a30Sjl qenable(dm2sp->ms_wq); 117825cf1a30Sjl } 117925cf1a30Sjl mutex_exit(&dm2sp->ms_lock); 118025cf1a30Sjl } 118125cf1a30Sjl 118225cf1a30Sjl /* 118325cf1a30Sjl * dm2s_prep_scatgath - Prepare scatter/gather elements for transmission 118425cf1a30Sjl * of a streams message. 118525cf1a30Sjl */ 118625cf1a30Sjl static int 118725cf1a30Sjl dm2s_prep_scatgath(mblk_t *mp, uint32_t *numsg, mscat_gath_t *sgp, int maxsg) 118825cf1a30Sjl { 118925cf1a30Sjl uint32_t num = 0; 119025cf1a30Sjl mblk_t *tmp = mp; 119125cf1a30Sjl 119225cf1a30Sjl while ((tmp != NULL) && (num < maxsg)) { 119325cf1a30Sjl sgp[num].msc_dptr = (caddr_t)tmp->b_rptr; 119425cf1a30Sjl sgp[num].msc_len = MBLKL(tmp); 119525cf1a30Sjl tmp = tmp->b_cont; 119625cf1a30Sjl num++; 119725cf1a30Sjl } 119825cf1a30Sjl 119925cf1a30Sjl if (tmp != NULL) { 120025cf1a30Sjl /* 120125cf1a30Sjl * Number of scatter/gather elements available are not 120225cf1a30Sjl * enough, so lets pullup the msg. 120325cf1a30Sjl */ 120425cf1a30Sjl if (pullupmsg(mp, -1) != 1) { 120525cf1a30Sjl return (EAGAIN); 120625cf1a30Sjl } 120725cf1a30Sjl sgp[0].msc_dptr = (caddr_t)mp->b_rptr; 120825cf1a30Sjl sgp[0].msc_len = MBLKL(mp); 120925cf1a30Sjl num = 1; 121025cf1a30Sjl } 121125cf1a30Sjl *numsg = num; 121225cf1a30Sjl return (0); 121325cf1a30Sjl } 121425cf1a30Sjl 121525cf1a30Sjl /* 121625cf1a30Sjl * dm2s_timeout_val -- Return appropriate timeout value. 121725cf1a30Sjl * 121825cf1a30Sjl * A small timeout value is returned for EBUSY and EAGAIN cases. This is 121925cf1a30Sjl * because the condition is expected to be recovered sooner. 122025cf1a30Sjl * 122125cf1a30Sjl * A larger timeout value is returned for ENOSPC case, as the condition 122225cf1a30Sjl * depends on the peer to release buffer space. 122325cf1a30Sjl * NOTE: there will also be an event(SCF_MB_SPACE) but a timeout is 122425cf1a30Sjl * used for reliability purposes. 122525cf1a30Sjl */ 122625cf1a30Sjl static clock_t 122725cf1a30Sjl dm2s_timeout_val(int error) 122825cf1a30Sjl { 122925cf1a30Sjl clock_t tval; 123025cf1a30Sjl 123125cf1a30Sjl ASSERT(error == EBUSY || error == ENOSPC || error == EAGAIN); 123225cf1a30Sjl 123325cf1a30Sjl if (error == EBUSY || error == EAGAIN) { 123425cf1a30Sjl tval = DM2S_SM_TOUT; 123525cf1a30Sjl } else { 123625cf1a30Sjl tval = DM2S_LG_TOUT; 123725cf1a30Sjl } 123825cf1a30Sjl return (drv_usectohz(tval)); 123925cf1a30Sjl } 124025cf1a30Sjl 124125cf1a30Sjl #ifdef DEBUG 124225cf1a30Sjl 124325cf1a30Sjl static void 124425cf1a30Sjl dm2s_dump_bytes(char *str, uint32_t total_len, 124525cf1a30Sjl uint32_t num_sg, mscat_gath_t *sgp) 124625cf1a30Sjl { 124725cf1a30Sjl int i, j; 124825cf1a30Sjl int nsg; 124925cf1a30Sjl int len, tlen = 0; 125025cf1a30Sjl mscat_gath_t *tp; 125125cf1a30Sjl uint8_t *datap; 125225cf1a30Sjl #define BYTES_PER_LINE 20 125325cf1a30Sjl char bytestr[BYTES_PER_LINE * 3 + 1]; 125425cf1a30Sjl uint32_t digest = 0; 125525cf1a30Sjl 125625cf1a30Sjl if (!(dm2s_debug & DBG_MESG)) 125725cf1a30Sjl return; 125825cf1a30Sjl ASSERT(num_sg != 0); 125925cf1a30Sjl 126025cf1a30Sjl for (nsg = 0; (nsg < num_sg) && (tlen < total_len); nsg++) { 126125cf1a30Sjl tp = &sgp[nsg]; 126225cf1a30Sjl datap = (uint8_t *)tp->msc_dptr; 126325cf1a30Sjl len = tp->msc_len; 126425cf1a30Sjl for (i = 0; i < len; i++) { 126525cf1a30Sjl digest += datap[i]; 126625cf1a30Sjl } 126725cf1a30Sjl tlen += len; 126825cf1a30Sjl } 126925cf1a30Sjl sprintf(bytestr, "%s Packet: Size=%d Digest=%d\n", 127019397407SSherry Moore str, total_len, digest); 127125cf1a30Sjl DTRACE_PROBE1(dm2s_dump_digest, unsigned char *, bytestr); 127225cf1a30Sjl 1273030f3a8fSraghuram tlen = 0; 127425cf1a30Sjl for (nsg = 0; (nsg < num_sg) && (tlen < total_len); nsg++) { 127525cf1a30Sjl tp = &sgp[nsg]; 127625cf1a30Sjl datap = (uint8_t *)tp->msc_dptr; 127725cf1a30Sjl len = tp->msc_len; 127825cf1a30Sjl for (i = 0; i < len; ) { 127925cf1a30Sjl for (j = 0; (j < BYTES_PER_LINE) && 128025cf1a30Sjl (i < len); j++, i++) { 128125cf1a30Sjl sprintf(&bytestr[j * 3], "%02X ", datap[i]); 128225cf1a30Sjl digest += datap[i]; 128325cf1a30Sjl } 128425cf1a30Sjl if (j != 0) { 128525cf1a30Sjl DTRACE_PROBE1(dm2s_dump, unsigned char *, 128625cf1a30Sjl bytestr); 128725cf1a30Sjl } 128825cf1a30Sjl } 128925cf1a30Sjl tlen += i; 129025cf1a30Sjl } 129125cf1a30Sjl } 129225cf1a30Sjl 129325cf1a30Sjl #endif /* DEBUG */ 1294