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