1*25cf1a30Sjl /* 2*25cf1a30Sjl * CDDL HEADER START 3*25cf1a30Sjl * 4*25cf1a30Sjl * The contents of this file are subject to the terms of the 5*25cf1a30Sjl * Common Development and Distribution License (the "License"). 6*25cf1a30Sjl * You may not use this file except in compliance with the License. 7*25cf1a30Sjl * 8*25cf1a30Sjl * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*25cf1a30Sjl * or http://www.opensolaris.org/os/licensing. 10*25cf1a30Sjl * See the License for the specific language governing permissions 11*25cf1a30Sjl * and limitations under the License. 12*25cf1a30Sjl * 13*25cf1a30Sjl * When distributing Covered Code, include this CDDL HEADER in each 14*25cf1a30Sjl * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*25cf1a30Sjl * If applicable, add the following below this CDDL HEADER, with the 16*25cf1a30Sjl * fields enclosed by brackets "[]" replaced with your own identifying 17*25cf1a30Sjl * information: Portions Copyright [yyyy] [name of copyright owner] 18*25cf1a30Sjl * 19*25cf1a30Sjl * CDDL HEADER END 20*25cf1a30Sjl */ 21*25cf1a30Sjl /* 22*25cf1a30Sjl * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23*25cf1a30Sjl * Use is subject to license terms. 24*25cf1a30Sjl */ 25*25cf1a30Sjl 26*25cf1a30Sjl #pragma ident "%Z%%M% %I% %E% SMI" 27*25cf1a30Sjl 28*25cf1a30Sjl /* 29*25cf1a30Sjl * DM2S - Domain side Mailbox to synchronous serial device driver. 30*25cf1a30Sjl * 31*25cf1a30Sjl * Description: 32*25cf1a30Sjl * ----------- 33*25cf1a30Sjl * It is a streams driver which simulates a sync serial device on 34*25cf1a30Sjl * top of a mailbox type of communication. That is, it sends/receives 35*25cf1a30Sjl * frames as mailbox messages. The mailbox communication is provided 36*25cf1a30Sjl * by another driver, which exports the mailbox interfaces. 37*25cf1a30Sjl * 38*25cf1a30Sjl * Synchronization: 39*25cf1a30Sjl * --------------- 40*25cf1a30Sjl * This driver uses streams perimeters to simplify the synchronization. 41*25cf1a30Sjl * An inner perimeter D_MTPERMOD which protects the entire module, 42*25cf1a30Sjl * that is only one thread exists inside the perimeter, is used. As 43*25cf1a30Sjl * this driver supports only one instance and is not a high-performance 44*25cf1a30Sjl * driver, D_MTPERMOD is highly suitable. 45*25cf1a30Sjl * 46*25cf1a30Sjl * All transmission and reception of frames is done inside the service 47*25cf1a30Sjl * procedures so that all streams related operations are protected 48*25cf1a30Sjl * by the perimeters. 49*25cf1a30Sjl * 50*25cf1a30Sjl * The mailbox event handler is the only asynchronous callback which 51*25cf1a30Sjl * needs to be protected outside of the streams perimeters. This is 52*25cf1a30Sjl * done using the module private lock('ms_lock'); 53*25cf1a30Sjl * 54*25cf1a30Sjl */ 55*25cf1a30Sjl 56*25cf1a30Sjl #include <sys/types.h> 57*25cf1a30Sjl #include <sys/param.h> 58*25cf1a30Sjl #include <sys/stream.h> 59*25cf1a30Sjl #include <sys/cred.h> 60*25cf1a30Sjl #include <sys/systm.h> 61*25cf1a30Sjl #include <sys/sunddi.h> 62*25cf1a30Sjl #include <sys/ddi.h> 63*25cf1a30Sjl #include <sys/conf.h> 64*25cf1a30Sjl #include <sys/modctl.h> 65*25cf1a30Sjl #include <sys/mkdev.h> 66*25cf1a30Sjl #include <sys/errno.h> 67*25cf1a30Sjl #include <sys/debug.h> 68*25cf1a30Sjl #include <sys/kbio.h> 69*25cf1a30Sjl #include <sys/kmem.h> 70*25cf1a30Sjl #include <sys/consdev.h> 71*25cf1a30Sjl #include <sys/file.h> 72*25cf1a30Sjl #include <sys/stropts.h> 73*25cf1a30Sjl #include <sys/strsun.h> 74*25cf1a30Sjl #include <sys/dlpi.h> 75*25cf1a30Sjl #include <sys/stat.h> 76*25cf1a30Sjl #include <sys/ser_sync.h> 77*25cf1a30Sjl #include <sys/sysmacros.h> 78*25cf1a30Sjl #include <sys/note.h> 79*25cf1a30Sjl #include <sys/sdt.h> 80*25cf1a30Sjl 81*25cf1a30Sjl #include <sys/scfd/scfdscpif.h> 82*25cf1a30Sjl #include <sys/dm2s.h> 83*25cf1a30Sjl 84*25cf1a30Sjl 85*25cf1a30Sjl #define DM2S_MODNAME "dm2s" /* Module name */ 86*25cf1a30Sjl #define DM2S_TARGET_ID 0 /* Target ID of the peer */ 87*25cf1a30Sjl #define DM2S_ID_NUM 0x4D53 /* 'M''S' */ 88*25cf1a30Sjl #define DM2S_DEF_MTU 1504 /* Def. MTU size + PPP bytes */ 89*25cf1a30Sjl #define DM2S_MAXPSZ DM2S_DEF_MTU /* Set it to the default MTU */ 90*25cf1a30Sjl #define DM2S_LOWAT (4 * 1024) /* Low water mark */ 91*25cf1a30Sjl #define DM2S_HIWAT (12 * 1024) /* High water mark */ 92*25cf1a30Sjl #define DM2S_SM_TOUT 5000 /* Small timeout (5msec) */ 93*25cf1a30Sjl #define DM2S_LG_TOUT 50000 /* Large timeout (50msec) */ 94*25cf1a30Sjl #define DM2S_MB_TOUT 10000000 /* Mailbox timeout (10sec) */ 95*25cf1a30Sjl 96*25cf1a30Sjl /* 97*25cf1a30Sjl * Global variables 98*25cf1a30Sjl */ 99*25cf1a30Sjl void *dm2s_softstate = NULL; /* Softstate pointer */ 100*25cf1a30Sjl 101*25cf1a30Sjl 102*25cf1a30Sjl /* 103*25cf1a30Sjl * Prototypes for the module related functions. 104*25cf1a30Sjl */ 105*25cf1a30Sjl int dm2s_attach(dev_info_t *dip, ddi_attach_cmd_t cmd); 106*25cf1a30Sjl int dm2s_detach(dev_info_t *dip, ddi_detach_cmd_t cmd); 107*25cf1a30Sjl int dm2s_info(dev_info_t *dip, ddi_info_cmd_t infocmd, 108*25cf1a30Sjl void *arg, void **result); 109*25cf1a30Sjl 110*25cf1a30Sjl /* 111*25cf1a30Sjl * Prototypes for the streams related functions. 112*25cf1a30Sjl */ 113*25cf1a30Sjl int dm2s_open(queue_t *rq, dev_t *dev, int flag, int sflag, cred_t *cr); 114*25cf1a30Sjl int dm2s_close(queue_t *rq, int flag, cred_t *cred); 115*25cf1a30Sjl int dm2s_wput(queue_t *wq, mblk_t *mp); 116*25cf1a30Sjl int dm2s_rsrv(queue_t *rq); 117*25cf1a30Sjl int dm2s_wsrv(queue_t *wq); 118*25cf1a30Sjl 119*25cf1a30Sjl /* 120*25cf1a30Sjl * Prototypes for the internal functions. 121*25cf1a30Sjl */ 122*25cf1a30Sjl void dm2s_start(queue_t *wq, dm2s_t *dm2sp); 123*25cf1a30Sjl void dm2s_event_handler(scf_event_t event, void *arg); 124*25cf1a30Sjl int dm2s_transmit(queue_t *wq, mblk_t *mp, target_id_t target, mkey_t key); 125*25cf1a30Sjl void dm2s_receive(dm2s_t *dm2sp); 126*25cf1a30Sjl void dm2s_wq_timeout(void *arg); 127*25cf1a30Sjl void dm2s_rq_timeout(void *arg); 128*25cf1a30Sjl void dm2s_bufcall_rcv(void *arg); 129*25cf1a30Sjl static clock_t dm2s_timeout_val(int error); 130*25cf1a30Sjl static void dm2s_cleanup(dm2s_t *dm2sp); 131*25cf1a30Sjl static int dm2s_mbox_init(dm2s_t *dm2sp); 132*25cf1a30Sjl static void dm2s_mbox_fini(dm2s_t *dm2sp); 133*25cf1a30Sjl static int dm2s_prep_scatgath(mblk_t *mp, uint32_t *numsg, 134*25cf1a30Sjl mscat_gath_t *sgp, int maxsg); 135*25cf1a30Sjl 136*25cf1a30Sjl #ifdef DEBUG 137*25cf1a30Sjl uint32_t dm2s_debug = DBG_WARN; 138*25cf1a30Sjl #endif /* DEBUG */ 139*25cf1a30Sjl 140*25cf1a30Sjl 141*25cf1a30Sjl /* 142*25cf1a30Sjl * Streams and module related structures. 143*25cf1a30Sjl */ 144*25cf1a30Sjl struct module_info dm2s_module_info = { 145*25cf1a30Sjl DM2S_ID_NUM, /* module ID number */ 146*25cf1a30Sjl DM2S_MODNAME, /* module name. */ 147*25cf1a30Sjl 0, /* Minimum packet size (none) */ 148*25cf1a30Sjl DM2S_MAXPSZ, /* Maximum packet size (none) */ 149*25cf1a30Sjl DM2S_HIWAT, /* queue high water mark */ 150*25cf1a30Sjl DM2S_LOWAT /* queue low water mark */ 151*25cf1a30Sjl }; 152*25cf1a30Sjl 153*25cf1a30Sjl struct qinit dm2s_rinit = { 154*25cf1a30Sjl putq, /* qi_putp */ 155*25cf1a30Sjl dm2s_rsrv, /* qi_srvp */ 156*25cf1a30Sjl dm2s_open, /* qi_qopen */ 157*25cf1a30Sjl dm2s_close, /* qi_qlcose */ 158*25cf1a30Sjl NULL, /* qi_qadmin */ 159*25cf1a30Sjl &dm2s_module_info, /* qi_minfo */ 160*25cf1a30Sjl NULL /* qi_mstat */ 161*25cf1a30Sjl }; 162*25cf1a30Sjl 163*25cf1a30Sjl struct qinit dm2s_winit = { 164*25cf1a30Sjl dm2s_wput, /* qi_putp */ 165*25cf1a30Sjl dm2s_wsrv, /* qi_srvp */ 166*25cf1a30Sjl NULL, /* qi_qopen */ 167*25cf1a30Sjl NULL, /* qi_qlcose */ 168*25cf1a30Sjl NULL, /* qi_qadmin */ 169*25cf1a30Sjl &dm2s_module_info, /* qi_minfo */ 170*25cf1a30Sjl NULL /* qi_mstat */ 171*25cf1a30Sjl }; 172*25cf1a30Sjl 173*25cf1a30Sjl 174*25cf1a30Sjl struct streamtab dm2s_streamtab = { 175*25cf1a30Sjl &dm2s_rinit, 176*25cf1a30Sjl &dm2s_winit, 177*25cf1a30Sjl NULL, 178*25cf1a30Sjl NULL 179*25cf1a30Sjl }; 180*25cf1a30Sjl 181*25cf1a30Sjl DDI_DEFINE_STREAM_OPS(dm2s_ops, nulldev, nulldev, dm2s_attach, \ 182*25cf1a30Sjl dm2s_detach, nodev, dm2s_info, D_NEW | D_MP | D_MTPERMOD, \ 183*25cf1a30Sjl &dm2s_streamtab); 184*25cf1a30Sjl 185*25cf1a30Sjl 186*25cf1a30Sjl struct modldrv modldrv = { 187*25cf1a30Sjl &mod_driverops, 188*25cf1a30Sjl "OPL Mbox to Serial Driver %I%", 189*25cf1a30Sjl &dm2s_ops 190*25cf1a30Sjl }; 191*25cf1a30Sjl 192*25cf1a30Sjl struct modlinkage modlinkage = { 193*25cf1a30Sjl MODREV_1, 194*25cf1a30Sjl &modldrv, 195*25cf1a30Sjl NULL 196*25cf1a30Sjl }; 197*25cf1a30Sjl 198*25cf1a30Sjl 199*25cf1a30Sjl /* 200*25cf1a30Sjl * _init - Module's init routine. 201*25cf1a30Sjl */ 202*25cf1a30Sjl int 203*25cf1a30Sjl _init(void) 204*25cf1a30Sjl { 205*25cf1a30Sjl int ret; 206*25cf1a30Sjl 207*25cf1a30Sjl if (ddi_soft_state_init(&dm2s_softstate, sizeof (dm2s_t), 1) != 0) { 208*25cf1a30Sjl cmn_err(CE_WARN, "softstate initialization failed\n"); 209*25cf1a30Sjl return (DDI_FAILURE); 210*25cf1a30Sjl } 211*25cf1a30Sjl if ((ret = mod_install(&modlinkage)) != 0) { 212*25cf1a30Sjl cmn_err(CE_WARN, "mod_install failed, error = %d", ret); 213*25cf1a30Sjl ddi_soft_state_fini(&dm2s_softstate); 214*25cf1a30Sjl } 215*25cf1a30Sjl return (ret); 216*25cf1a30Sjl } 217*25cf1a30Sjl 218*25cf1a30Sjl /* 219*25cf1a30Sjl * _fini - Module's fini routine. 220*25cf1a30Sjl */ 221*25cf1a30Sjl int 222*25cf1a30Sjl _fini(void) 223*25cf1a30Sjl { 224*25cf1a30Sjl int ret; 225*25cf1a30Sjl 226*25cf1a30Sjl if ((ret = mod_remove(&modlinkage)) != 0) { 227*25cf1a30Sjl return (ret); 228*25cf1a30Sjl } 229*25cf1a30Sjl ddi_soft_state_fini(&dm2s_softstate); 230*25cf1a30Sjl return (ret); 231*25cf1a30Sjl } 232*25cf1a30Sjl 233*25cf1a30Sjl /* 234*25cf1a30Sjl * _info - Module's info routine. 235*25cf1a30Sjl */ 236*25cf1a30Sjl int 237*25cf1a30Sjl _info(struct modinfo *modinfop) 238*25cf1a30Sjl { 239*25cf1a30Sjl return (mod_info(&modlinkage, modinfop)); 240*25cf1a30Sjl } 241*25cf1a30Sjl 242*25cf1a30Sjl /* 243*25cf1a30Sjl * dm2s_attach - Module's attach routine. 244*25cf1a30Sjl */ 245*25cf1a30Sjl int 246*25cf1a30Sjl dm2s_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 247*25cf1a30Sjl { 248*25cf1a30Sjl int instance; 249*25cf1a30Sjl dm2s_t *dm2sp; 250*25cf1a30Sjl char name[20]; 251*25cf1a30Sjl 252*25cf1a30Sjl 253*25cf1a30Sjl instance = ddi_get_instance(dip); 254*25cf1a30Sjl 255*25cf1a30Sjl /* Only one instance is supported. */ 256*25cf1a30Sjl if (instance != 0) { 257*25cf1a30Sjl cmn_err(CE_WARN, "only one instance is supported"); 258*25cf1a30Sjl return (DDI_FAILURE); 259*25cf1a30Sjl } 260*25cf1a30Sjl 261*25cf1a30Sjl if (cmd != DDI_ATTACH) { 262*25cf1a30Sjl return (DDI_FAILURE); 263*25cf1a30Sjl } 264*25cf1a30Sjl if (ddi_soft_state_zalloc(dm2s_softstate, instance) != DDI_SUCCESS) { 265*25cf1a30Sjl cmn_err(CE_WARN, "softstate allocation failure"); 266*25cf1a30Sjl return (DDI_FAILURE); 267*25cf1a30Sjl } 268*25cf1a30Sjl dm2sp = (dm2s_t *)ddi_get_soft_state(dm2s_softstate, instance); 269*25cf1a30Sjl if (dm2sp == NULL) { 270*25cf1a30Sjl ddi_soft_state_free(dm2s_softstate, instance); 271*25cf1a30Sjl cmn_err(CE_WARN, "softstate allocation failure."); 272*25cf1a30Sjl return (DDI_FAILURE); 273*25cf1a30Sjl } 274*25cf1a30Sjl dm2sp->ms_dip = dip; 275*25cf1a30Sjl dm2sp->ms_major = ddi_name_to_major(ddi_get_name(dip)); 276*25cf1a30Sjl dm2sp->ms_ppa = instance; 277*25cf1a30Sjl 278*25cf1a30Sjl /* 279*25cf1a30Sjl * Get an interrupt block cookie corresponding to the 280*25cf1a30Sjl * interrupt priority of the event handler. 281*25cf1a30Sjl * Assert that the event priority is not re-defined to 282*25cf1a30Sjl * some higher priority. 283*25cf1a30Sjl */ 284*25cf1a30Sjl /* LINTED */ 285*25cf1a30Sjl ASSERT(SCF_EVENT_PRI == DDI_SOFTINT_LOW); 286*25cf1a30Sjl if (ddi_get_soft_iblock_cookie(dip, SCF_EVENT_PRI, 287*25cf1a30Sjl &dm2sp->ms_ibcookie) != DDI_SUCCESS) { 288*25cf1a30Sjl cmn_err(CE_WARN, "ddi_get_soft_iblock_cookie failed."); 289*25cf1a30Sjl goto error; 290*25cf1a30Sjl } 291*25cf1a30Sjl mutex_init(&dm2sp->ms_lock, NULL, MUTEX_DRIVER, 292*25cf1a30Sjl (void *)dm2sp->ms_ibcookie); 293*25cf1a30Sjl 294*25cf1a30Sjl dm2sp->ms_clean |= DM2S_CLEAN_LOCK; 295*25cf1a30Sjl cv_init(&dm2sp->ms_wait, NULL, CV_DRIVER, NULL); 296*25cf1a30Sjl dm2sp->ms_clean |= DM2S_CLEAN_CV; 297*25cf1a30Sjl 298*25cf1a30Sjl (void) sprintf(name, "%s%d", DM2S_MODNAME, instance); 299*25cf1a30Sjl if (ddi_create_minor_node(dip, name, S_IFCHR, instance, 300*25cf1a30Sjl DDI_PSEUDO, NULL) == DDI_FAILURE) { 301*25cf1a30Sjl ddi_remove_minor_node(dip, NULL); 302*25cf1a30Sjl cmn_err(CE_WARN, "Device node creation failed."); 303*25cf1a30Sjl goto error; 304*25cf1a30Sjl } 305*25cf1a30Sjl 306*25cf1a30Sjl dm2sp->ms_clean |= DM2S_CLEAN_NODE; 307*25cf1a30Sjl ddi_set_driver_private(dip, (caddr_t)dm2sp); 308*25cf1a30Sjl ddi_report_dev(dip); 309*25cf1a30Sjl return (DDI_SUCCESS); 310*25cf1a30Sjl error: 311*25cf1a30Sjl dm2s_cleanup(dm2sp); 312*25cf1a30Sjl return (DDI_FAILURE); 313*25cf1a30Sjl } 314*25cf1a30Sjl 315*25cf1a30Sjl /* 316*25cf1a30Sjl * dm2s_info - Module's info routine. 317*25cf1a30Sjl */ 318*25cf1a30Sjl /*ARGSUSED*/ 319*25cf1a30Sjl int 320*25cf1a30Sjl dm2s_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 321*25cf1a30Sjl { 322*25cf1a30Sjl dm2s_t *dm2sp; 323*25cf1a30Sjl minor_t minor; 324*25cf1a30Sjl int ret = DDI_FAILURE; 325*25cf1a30Sjl 326*25cf1a30Sjl switch (infocmd) { 327*25cf1a30Sjl case DDI_INFO_DEVT2DEVINFO: 328*25cf1a30Sjl minor = getminor((dev_t)arg); 329*25cf1a30Sjl dm2sp = (dm2s_t *)ddi_get_soft_state(dm2s_softstate, minor); 330*25cf1a30Sjl if (dm2sp == NULL) { 331*25cf1a30Sjl *result = NULL; 332*25cf1a30Sjl } else { 333*25cf1a30Sjl *result = dm2sp->ms_dip; 334*25cf1a30Sjl ret = DDI_SUCCESS; 335*25cf1a30Sjl } 336*25cf1a30Sjl break; 337*25cf1a30Sjl 338*25cf1a30Sjl case DDI_INFO_DEVT2INSTANCE: 339*25cf1a30Sjl minor = getminor((dev_t)arg); 340*25cf1a30Sjl *result = (void *)(uintptr_t)minor; 341*25cf1a30Sjl ret = DDI_SUCCESS; 342*25cf1a30Sjl break; 343*25cf1a30Sjl 344*25cf1a30Sjl default: 345*25cf1a30Sjl break; 346*25cf1a30Sjl } 347*25cf1a30Sjl return (ret); 348*25cf1a30Sjl } 349*25cf1a30Sjl 350*25cf1a30Sjl /* 351*25cf1a30Sjl * dm2s_detach - Module's detach routine. 352*25cf1a30Sjl */ 353*25cf1a30Sjl int 354*25cf1a30Sjl dm2s_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 355*25cf1a30Sjl { 356*25cf1a30Sjl int instance; 357*25cf1a30Sjl dm2s_t *dm2sp; 358*25cf1a30Sjl 359*25cf1a30Sjl if (cmd != DDI_DETACH) { 360*25cf1a30Sjl return (DDI_FAILURE); 361*25cf1a30Sjl } 362*25cf1a30Sjl 363*25cf1a30Sjl instance = ddi_get_instance(dip); 364*25cf1a30Sjl dm2sp = (dm2s_t *)ddi_get_soft_state(dm2s_softstate, instance); 365*25cf1a30Sjl if (dm2sp == NULL) { 366*25cf1a30Sjl return (DDI_FAILURE); 367*25cf1a30Sjl } 368*25cf1a30Sjl 369*25cf1a30Sjl mutex_enter(&dm2sp->ms_lock); 370*25cf1a30Sjl 371*25cf1a30Sjl /* Check if the mailbox is still in use. */ 372*25cf1a30Sjl if (dm2sp->ms_state & DM2S_MB_INITED) { 373*25cf1a30Sjl mutex_exit(&dm2sp->ms_lock); 374*25cf1a30Sjl cmn_err(CE_WARN, "Mailbox in use: Detach failed"); 375*25cf1a30Sjl return (DDI_FAILURE); 376*25cf1a30Sjl } 377*25cf1a30Sjl mutex_exit(&dm2sp->ms_lock); 378*25cf1a30Sjl dm2s_cleanup(dm2sp); 379*25cf1a30Sjl return (DDI_SUCCESS); 380*25cf1a30Sjl } 381*25cf1a30Sjl 382*25cf1a30Sjl /* 383*25cf1a30Sjl * dm2s_open - Device open routine. 384*25cf1a30Sjl * 385*25cf1a30Sjl * Only one open supported. Clone open is not supported. 386*25cf1a30Sjl */ 387*25cf1a30Sjl /* ARGSUSED */ 388*25cf1a30Sjl int 389*25cf1a30Sjl dm2s_open(queue_t *rq, dev_t *dev, int flag, int sflag, cred_t *cr) 390*25cf1a30Sjl { 391*25cf1a30Sjl dm2s_t *dm2sp; 392*25cf1a30Sjl int instance = getminor(*dev); 393*25cf1a30Sjl int ret = 0; 394*25cf1a30Sjl 395*25cf1a30Sjl DPRINTF(DBG_DRV, ("dm2s_open: called\n")); 396*25cf1a30Sjl if (sflag == CLONEOPEN) { 397*25cf1a30Sjl /* Clone open not supported */ 398*25cf1a30Sjl DPRINTF(DBG_WARN, ("dm2s_open: clone open not supported\n")); 399*25cf1a30Sjl return (ENOTSUP); 400*25cf1a30Sjl } 401*25cf1a30Sjl 402*25cf1a30Sjl if (rq->q_ptr != NULL) { 403*25cf1a30Sjl DPRINTF(DBG_WARN, ("dm2s_open: already opened\n")); 404*25cf1a30Sjl return (EBUSY); 405*25cf1a30Sjl } 406*25cf1a30Sjl 407*25cf1a30Sjl if ((dm2sp = ddi_get_soft_state(dm2s_softstate, instance)) == NULL) { 408*25cf1a30Sjl DPRINTF(DBG_WARN, ("dm2s_open: instance not found\n")); 409*25cf1a30Sjl return (ENODEV); 410*25cf1a30Sjl } 411*25cf1a30Sjl 412*25cf1a30Sjl mutex_enter(&dm2sp->ms_lock); 413*25cf1a30Sjl if (dm2sp->ms_state & DM2S_OPENED) { 414*25cf1a30Sjl /* Only one open supported */ 415*25cf1a30Sjl mutex_exit(&dm2sp->ms_lock); 416*25cf1a30Sjl DPRINTF(DBG_WARN, ("dm2s_open: already opened\n")); 417*25cf1a30Sjl return (EBUSY); 418*25cf1a30Sjl } 419*25cf1a30Sjl 420*25cf1a30Sjl dm2sp->ms_state |= DM2S_OPENED; 421*25cf1a30Sjl /* Initialize the mailbox. */ 422*25cf1a30Sjl if ((ret = dm2s_mbox_init(dm2sp)) != 0) { 423*25cf1a30Sjl dm2sp->ms_state = 0; 424*25cf1a30Sjl mutex_exit(&dm2sp->ms_lock); 425*25cf1a30Sjl return (ret); 426*25cf1a30Sjl } 427*25cf1a30Sjl rq->q_ptr = WR(rq)->q_ptr = (void *)dm2sp; 428*25cf1a30Sjl dm2sp->ms_rq = rq; 429*25cf1a30Sjl dm2sp->ms_wq = WR(rq); 430*25cf1a30Sjl mutex_exit(&dm2sp->ms_lock); 431*25cf1a30Sjl 432*25cf1a30Sjl if (ret == 0) { 433*25cf1a30Sjl qprocson(rq); /* now schedule our queue */ 434*25cf1a30Sjl } 435*25cf1a30Sjl DPRINTF(DBG_DRV, ("dm2s_open: ret=%d\n", ret)); 436*25cf1a30Sjl return (ret); 437*25cf1a30Sjl } 438*25cf1a30Sjl 439*25cf1a30Sjl /* 440*25cf1a30Sjl * dm2s_close - Device close routine. 441*25cf1a30Sjl */ 442*25cf1a30Sjl /* ARGSUSED */ 443*25cf1a30Sjl int 444*25cf1a30Sjl dm2s_close(queue_t *rq, int flag, cred_t *cred) 445*25cf1a30Sjl { 446*25cf1a30Sjl dm2s_t *dm2sp = (dm2s_t *)rq->q_ptr; 447*25cf1a30Sjl 448*25cf1a30Sjl DPRINTF(DBG_DRV, ("dm2s_close: called\n")); 449*25cf1a30Sjl if (dm2sp == NULL) { 450*25cf1a30Sjl /* Already closed once */ 451*25cf1a30Sjl return (ENODEV); 452*25cf1a30Sjl } 453*25cf1a30Sjl 454*25cf1a30Sjl /* Close the lower layer first */ 455*25cf1a30Sjl mutex_enter(&dm2sp->ms_lock); 456*25cf1a30Sjl (void) scf_mb_flush(dm2sp->ms_target, dm2sp->ms_key, MB_FLUSH_ALL); 457*25cf1a30Sjl dm2s_mbox_fini(dm2sp); 458*25cf1a30Sjl mutex_exit(&dm2sp->ms_lock); 459*25cf1a30Sjl 460*25cf1a30Sjl /* 461*25cf1a30Sjl * Now we can assume that no asynchronous callbacks exist. 462*25cf1a30Sjl * Poison the stream head so that we can't be pushed again. 463*25cf1a30Sjl */ 464*25cf1a30Sjl (void) putnextctl(rq, M_HANGUP); 465*25cf1a30Sjl qprocsoff(rq); 466*25cf1a30Sjl if (dm2sp->ms_rbufcid != 0) { 467*25cf1a30Sjl qunbufcall(rq, dm2sp->ms_rbufcid); 468*25cf1a30Sjl dm2sp->ms_rbufcid = 0; 469*25cf1a30Sjl } 470*25cf1a30Sjl if (dm2sp->ms_rq_timeoutid != 0) { 471*25cf1a30Sjl DTRACE_PROBE1(dm2s_rqtimeout__cancel, dm2s_t, dm2sp); 472*25cf1a30Sjl (void) quntimeout(dm2sp->ms_rq, dm2sp->ms_rq_timeoutid); 473*25cf1a30Sjl dm2sp->ms_rq_timeoutid = 0; 474*25cf1a30Sjl } 475*25cf1a30Sjl if (dm2sp->ms_wq_timeoutid != 0) { 476*25cf1a30Sjl DTRACE_PROBE1(dm2s_wqtimeout__cancel, dm2s_t, dm2sp); 477*25cf1a30Sjl (void) quntimeout(dm2sp->ms_wq, dm2sp->ms_wq_timeoutid); 478*25cf1a30Sjl dm2sp->ms_wq_timeoutid = 0; 479*25cf1a30Sjl } 480*25cf1a30Sjl /* 481*25cf1a30Sjl * Now we can really mark it closed. 482*25cf1a30Sjl */ 483*25cf1a30Sjl mutex_enter(&dm2sp->ms_lock); 484*25cf1a30Sjl dm2sp->ms_rq = dm2sp->ms_wq = NULL; 485*25cf1a30Sjl dm2sp->ms_state &= ~DM2S_OPENED; 486*25cf1a30Sjl mutex_exit(&dm2sp->ms_lock); 487*25cf1a30Sjl 488*25cf1a30Sjl rq->q_ptr = WR(rq)->q_ptr = NULL; 489*25cf1a30Sjl (void) qassociate(rq, -1); 490*25cf1a30Sjl DPRINTF(DBG_DRV, ("dm2s_close: successfully closed\n")); 491*25cf1a30Sjl return (0); 492*25cf1a30Sjl } 493*25cf1a30Sjl 494*25cf1a30Sjl /* 495*25cf1a30Sjl * dm2s_rsrv - Streams read side service procedure. 496*25cf1a30Sjl * 497*25cf1a30Sjl * All messages are received in the service procedure 498*25cf1a30Sjl * only. This is done to simplify the streams synchronization. 499*25cf1a30Sjl */ 500*25cf1a30Sjl int 501*25cf1a30Sjl dm2s_rsrv(queue_t *rq) 502*25cf1a30Sjl { 503*25cf1a30Sjl mblk_t *mp; 504*25cf1a30Sjl dm2s_t *dm2sp = (dm2s_t *)rq->q_ptr; 505*25cf1a30Sjl 506*25cf1a30Sjl DPRINTF(DBG_DRV, ("dm2s_rsrv: called\n")); 507*25cf1a30Sjl ASSERT(dm2sp != NULL); 508*25cf1a30Sjl mutex_enter(&dm2sp->ms_lock); 509*25cf1a30Sjl 510*25cf1a30Sjl /* Receive if there are any messages waiting in the mailbox. */ 511*25cf1a30Sjl dm2s_receive(dm2sp); 512*25cf1a30Sjl mutex_exit(&dm2sp->ms_lock); 513*25cf1a30Sjl 514*25cf1a30Sjl /* Send the received messages up the stream. */ 515*25cf1a30Sjl while ((mp = getq(rq)) != NULL) { 516*25cf1a30Sjl if (canputnext(rq)) { 517*25cf1a30Sjl putnext(rq, mp); 518*25cf1a30Sjl } else { 519*25cf1a30Sjl putbq(rq, mp); 520*25cf1a30Sjl break; 521*25cf1a30Sjl } 522*25cf1a30Sjl } 523*25cf1a30Sjl DPRINTF(DBG_DRV, ("dm2s_rsrv: return\n")); 524*25cf1a30Sjl return (0); 525*25cf1a30Sjl } 526*25cf1a30Sjl 527*25cf1a30Sjl /* 528*25cf1a30Sjl * dm2s_wsrv - Streams write side service procedure. 529*25cf1a30Sjl * 530*25cf1a30Sjl * All messages are transmitted in the service procedure 531*25cf1a30Sjl * only. This is done to simplify the streams synchronization. 532*25cf1a30Sjl */ 533*25cf1a30Sjl int 534*25cf1a30Sjl dm2s_wsrv(queue_t *wq) 535*25cf1a30Sjl { 536*25cf1a30Sjl dm2s_t *dm2sp = (dm2s_t *)wq->q_ptr; 537*25cf1a30Sjl 538*25cf1a30Sjl DPRINTF(DBG_DRV, ("dm2s_wsrv: called\n")); 539*25cf1a30Sjl ASSERT(dm2sp != NULL); 540*25cf1a30Sjl /* Lets cancel any timeouts waiting to be scheduled. */ 541*25cf1a30Sjl if (dm2sp->ms_wq_timeoutid != 0) { 542*25cf1a30Sjl DTRACE_PROBE1(dm2s_wqtimeout__cancel, dm2s_t, dm2sp); 543*25cf1a30Sjl (void) quntimeout(dm2sp->ms_wq, dm2sp->ms_wq_timeoutid); 544*25cf1a30Sjl dm2sp->ms_wq_timeoutid = 0; 545*25cf1a30Sjl } 546*25cf1a30Sjl mutex_enter(&dm2sp->ms_lock); 547*25cf1a30Sjl dm2s_start(wq, dm2sp); 548*25cf1a30Sjl mutex_exit(&dm2sp->ms_lock); 549*25cf1a30Sjl DPRINTF(DBG_DRV, ("dm2s_wsrv: return\n")); 550*25cf1a30Sjl return (0); 551*25cf1a30Sjl } 552*25cf1a30Sjl 553*25cf1a30Sjl /* 554*25cf1a30Sjl * dm2s_wput - Streams write side put routine. 555*25cf1a30Sjl * 556*25cf1a30Sjl * All M_DATA messages are queued so that they are transmitted in 557*25cf1a30Sjl * the service procedure. This is done to simplify the streams 558*25cf1a30Sjl * synchronization. Other messages are handled appropriately. 559*25cf1a30Sjl */ 560*25cf1a30Sjl int 561*25cf1a30Sjl dm2s_wput(queue_t *wq, mblk_t *mp) 562*25cf1a30Sjl { 563*25cf1a30Sjl dm2s_t *dm2sp = (dm2s_t *)wq->q_ptr; 564*25cf1a30Sjl 565*25cf1a30Sjl DPRINTF(DBG_DRV, ("dm2s_wput: called\n")); 566*25cf1a30Sjl if (dm2sp == NULL) { 567*25cf1a30Sjl return (ENODEV); /* Can't happen. */ 568*25cf1a30Sjl } 569*25cf1a30Sjl 570*25cf1a30Sjl switch (mp->b_datap->db_type) { 571*25cf1a30Sjl case (M_DATA): 572*25cf1a30Sjl DPRINTF(DBG_DRV, ("dm2s_wput: M_DATA message\n")); 573*25cf1a30Sjl while (mp->b_wptr == mp->b_rptr) { 574*25cf1a30Sjl mblk_t *mp1; 575*25cf1a30Sjl 576*25cf1a30Sjl mp1 = unlinkb(mp); 577*25cf1a30Sjl freemsg(mp); 578*25cf1a30Sjl mp = mp1; 579*25cf1a30Sjl if (mp == NULL) { 580*25cf1a30Sjl return (0); 581*25cf1a30Sjl } 582*25cf1a30Sjl } 583*25cf1a30Sjl 584*25cf1a30Sjl /* 585*25cf1a30Sjl * Simply queue the message and handle it in the service 586*25cf1a30Sjl * procedure. 587*25cf1a30Sjl */ 588*25cf1a30Sjl (void) putq(wq, mp); 589*25cf1a30Sjl qenable(wq); 590*25cf1a30Sjl return (0); 591*25cf1a30Sjl 592*25cf1a30Sjl case (M_PROTO): 593*25cf1a30Sjl DPRINTF(DBG_DRV, ("dm2s_wput: M_PROTO message\n")); 594*25cf1a30Sjl /* We don't expect this */ 595*25cf1a30Sjl mp->b_datap->db_type = M_ERROR; 596*25cf1a30Sjl mp->b_rptr = mp->b_wptr = mp->b_datap->db_base; 597*25cf1a30Sjl *mp->b_wptr++ = EPROTO; 598*25cf1a30Sjl qreply(wq, mp); 599*25cf1a30Sjl return (EINVAL); 600*25cf1a30Sjl 601*25cf1a30Sjl case (M_IOCTL): 602*25cf1a30Sjl DPRINTF(DBG_DRV, ("dm2s_wput: M_IOCTL message\n")); 603*25cf1a30Sjl if (MBLKL(mp) < sizeof (struct iocblk)) { 604*25cf1a30Sjl freemsg(mp); 605*25cf1a30Sjl return (0); 606*25cf1a30Sjl } 607*25cf1a30Sjl /* 608*25cf1a30Sjl * No ioctls required to be supported by this driver, so 609*25cf1a30Sjl * return EINVAL for all ioctls. 610*25cf1a30Sjl */ 611*25cf1a30Sjl miocnak(wq, mp, 0, EINVAL); 612*25cf1a30Sjl break; 613*25cf1a30Sjl 614*25cf1a30Sjl case (M_CTL): 615*25cf1a30Sjl DPRINTF(DBG_DRV, ("dm2s_wput: M_CTL message\n")); 616*25cf1a30Sjl /* 617*25cf1a30Sjl * No M_CTL messages need to supported by this driver, 618*25cf1a30Sjl * so simply ignore them. 619*25cf1a30Sjl */ 620*25cf1a30Sjl freemsg(mp); 621*25cf1a30Sjl break; 622*25cf1a30Sjl 623*25cf1a30Sjl case (M_FLUSH): 624*25cf1a30Sjl DPRINTF(DBG_DRV, ( 625*25cf1a30Sjl "dm2s_wput: M_FLUSH message 0x%X\n", *mp->b_rptr)); 626*25cf1a30Sjl if (*mp->b_rptr & FLUSHW) { /* Flush write-side */ 627*25cf1a30Sjl (void) scf_mb_flush(dm2sp->ms_target, dm2sp->ms_key, 628*25cf1a30Sjl MB_FLUSH_SEND); 629*25cf1a30Sjl flushq(wq, FLUSHDATA); 630*25cf1a30Sjl *mp->b_rptr &= ~FLUSHW; 631*25cf1a30Sjl } 632*25cf1a30Sjl if (*mp->b_rptr & FLUSHR) { 633*25cf1a30Sjl (void) scf_mb_flush(dm2sp->ms_target, dm2sp->ms_key, 634*25cf1a30Sjl MB_FLUSH_RECEIVE); 635*25cf1a30Sjl flushq(RD(wq), FLUSHDATA); 636*25cf1a30Sjl qreply(wq, mp); 637*25cf1a30Sjl } else { 638*25cf1a30Sjl freemsg(mp); 639*25cf1a30Sjl } 640*25cf1a30Sjl break; 641*25cf1a30Sjl 642*25cf1a30Sjl default: 643*25cf1a30Sjl DPRINTF(DBG_DRV, ("dm2s_wput: UNKNOWN message\n")); 644*25cf1a30Sjl freemsg(mp); 645*25cf1a30Sjl 646*25cf1a30Sjl } 647*25cf1a30Sjl return (0); 648*25cf1a30Sjl } 649*25cf1a30Sjl 650*25cf1a30Sjl /* 651*25cf1a30Sjl * dm2s_cleanup - Cleanup routine. 652*25cf1a30Sjl */ 653*25cf1a30Sjl static void 654*25cf1a30Sjl dm2s_cleanup(dm2s_t *dm2sp) 655*25cf1a30Sjl { 656*25cf1a30Sjl char name[20]; 657*25cf1a30Sjl 658*25cf1a30Sjl DPRINTF(DBG_DRV, ("dm2s_cleanup: called\n")); 659*25cf1a30Sjl ASSERT(dm2sp != NULL); 660*25cf1a30Sjl if (dm2sp->ms_clean & DM2S_CLEAN_NODE) { 661*25cf1a30Sjl (void) sprintf(name, "%s%d", DM2S_MODNAME, dm2sp->ms_ppa); 662*25cf1a30Sjl ddi_remove_minor_node(dm2sp->ms_dip, name); 663*25cf1a30Sjl } 664*25cf1a30Sjl if (dm2sp->ms_clean & DM2S_CLEAN_LOCK) 665*25cf1a30Sjl mutex_destroy(&dm2sp->ms_lock); 666*25cf1a30Sjl if (dm2sp->ms_clean & DM2S_CLEAN_CV) 667*25cf1a30Sjl cv_destroy(&dm2sp->ms_wait); 668*25cf1a30Sjl ddi_set_driver_private(dm2sp->ms_dip, NULL); 669*25cf1a30Sjl ddi_soft_state_free(dm2s_softstate, dm2sp->ms_ppa); 670*25cf1a30Sjl } 671*25cf1a30Sjl 672*25cf1a30Sjl /* 673*25cf1a30Sjl * dm2s_mbox_init - Mailbox specific initialization. 674*25cf1a30Sjl */ 675*25cf1a30Sjl static int 676*25cf1a30Sjl dm2s_mbox_init(dm2s_t *dm2sp) 677*25cf1a30Sjl { 678*25cf1a30Sjl int ret; 679*25cf1a30Sjl clock_t tout; 680*25cf1a30Sjl 681*25cf1a30Sjl ASSERT(MUTEX_HELD(&dm2sp->ms_lock)); 682*25cf1a30Sjl dm2sp->ms_target = DM2S_TARGET_ID; 683*25cf1a30Sjl dm2sp->ms_key = DSCP_KEY; 684*25cf1a30Sjl dm2sp->ms_state &= ~DM2S_MB_INITED; 685*25cf1a30Sjl 686*25cf1a30Sjl /* Iterate until mailbox gets connected */ 687*25cf1a30Sjl while (!(dm2sp->ms_state & DM2S_MB_CONN)) { 688*25cf1a30Sjl DPRINTF(DBG_MBOX, ("dm2s_mbox_init: calling mb_init\n")); 689*25cf1a30Sjl ret = scf_mb_init(dm2sp->ms_target, dm2sp->ms_key, 690*25cf1a30Sjl dm2s_event_handler, (void *)dm2sp); 691*25cf1a30Sjl DPRINTF(DBG_MBOX, ("dm2s_mbox_init: mb_init ret=%d\n", ret)); 692*25cf1a30Sjl 693*25cf1a30Sjl if (ret == 0) { 694*25cf1a30Sjl dm2sp->ms_state |= DM2S_MB_INITED; 695*25cf1a30Sjl 696*25cf1a30Sjl /* Block until the mailbox is ready to communicate. */ 697*25cf1a30Sjl while (!(dm2sp->ms_state & 698*25cf1a30Sjl (DM2S_MB_CONN | DM2S_MB_DISC))) { 699*25cf1a30Sjl 700*25cf1a30Sjl if (cv_wait_sig(&dm2sp->ms_wait, 701*25cf1a30Sjl &dm2sp->ms_lock) <= 0) { 702*25cf1a30Sjl /* interrupted */ 703*25cf1a30Sjl ret = EINTR; 704*25cf1a30Sjl break; 705*25cf1a30Sjl } 706*25cf1a30Sjl } 707*25cf1a30Sjl } 708*25cf1a30Sjl 709*25cf1a30Sjl if (ret != 0) { 710*25cf1a30Sjl 711*25cf1a30Sjl DPRINTF(DBG_MBOX, 712*25cf1a30Sjl ("dm2s_mbox_init: failed/interrupted\n")); 713*25cf1a30Sjl DTRACE_PROBE1(dm2s_mbox_fail, int, ret); 714*25cf1a30Sjl dm2sp->ms_state &= ~DM2S_MB_INITED; 715*25cf1a30Sjl (void) scf_mb_fini(dm2sp->ms_target, dm2sp->ms_key); 716*25cf1a30Sjl 717*25cf1a30Sjl /* if interrupted, return immediately. */ 718*25cf1a30Sjl if (ret == EINTR) 719*25cf1a30Sjl return (ret); 720*25cf1a30Sjl 721*25cf1a30Sjl } 722*25cf1a30Sjl 723*25cf1a30Sjl if ((ret != 0) || (dm2sp->ms_state & DM2S_MB_DISC)) { 724*25cf1a30Sjl 725*25cf1a30Sjl DPRINTF(DBG_WARN, 726*25cf1a30Sjl ("dm2s_mbox_init: mbox DISC_ERROR\n")); 727*25cf1a30Sjl DTRACE_PROBE1(dm2s_mbox_fail, int, DM2S_MB_DISC); 728*25cf1a30Sjl dm2sp->ms_state &= ~DM2S_MB_INITED; 729*25cf1a30Sjl (void) scf_mb_fini(dm2sp->ms_target, dm2sp->ms_key); 730*25cf1a30Sjl 731*25cf1a30Sjl /* 732*25cf1a30Sjl * If there was failure, then wait for 733*25cf1a30Sjl * DM2S_MB_TOUT secs and retry again. 734*25cf1a30Sjl */ 735*25cf1a30Sjl 736*25cf1a30Sjl DPRINTF(DBG_MBOX, ("dm2s_mbox_init: waiting...\n")); 737*25cf1a30Sjl tout = ddi_get_lbolt() + drv_usectohz(DM2S_MB_TOUT); 738*25cf1a30Sjl ret = cv_timedwait_sig(&dm2sp->ms_wait, 739*25cf1a30Sjl &dm2sp->ms_lock, tout); 740*25cf1a30Sjl if (ret == 0) { 741*25cf1a30Sjl /* if interrupted, return immediately. */ 742*25cf1a30Sjl DPRINTF(DBG_MBOX, 743*25cf1a30Sjl ("dm2s_mbox_init: interrupted\n")); 744*25cf1a30Sjl return (EINTR); 745*25cf1a30Sjl } 746*25cf1a30Sjl } 747*25cf1a30Sjl } 748*25cf1a30Sjl 749*25cf1a30Sjl /* 750*25cf1a30Sjl * Obtain the max size of a single message. 751*25cf1a30Sjl * NOTE: There is no mechanism to update the 752*25cf1a30Sjl * upperlayers dynamically, so we expect this 753*25cf1a30Sjl * size to be atleast the default MTU size. 754*25cf1a30Sjl */ 755*25cf1a30Sjl ret = scf_mb_ctrl(dm2sp->ms_target, dm2sp->ms_key, 756*25cf1a30Sjl SCF_MBOP_MAXMSGSIZE, &dm2sp->ms_mtu); 757*25cf1a30Sjl 758*25cf1a30Sjl if ((ret == 0) && (dm2sp->ms_mtu < DM2S_DEF_MTU)) { 759*25cf1a30Sjl cmn_err(CE_WARN, "Max message size expected >= %d " 760*25cf1a30Sjl "but found %d\n", DM2S_DEF_MTU, dm2sp->ms_mtu); 761*25cf1a30Sjl ret = EIO; 762*25cf1a30Sjl } 763*25cf1a30Sjl 764*25cf1a30Sjl if (ret != 0) { 765*25cf1a30Sjl dm2sp->ms_state &= ~DM2S_MB_INITED; 766*25cf1a30Sjl (void) scf_mb_fini(dm2sp->ms_target, dm2sp->ms_key); 767*25cf1a30Sjl } 768*25cf1a30Sjl DPRINTF(DBG_MBOX, ("dm2s_mbox_init: mb_init ret=%d\n", ret)); 769*25cf1a30Sjl return (ret); 770*25cf1a30Sjl } 771*25cf1a30Sjl 772*25cf1a30Sjl /* 773*25cf1a30Sjl * dm2s_mbox_fini - Mailbox de-initialization. 774*25cf1a30Sjl */ 775*25cf1a30Sjl static void 776*25cf1a30Sjl dm2s_mbox_fini(dm2s_t *dm2sp) 777*25cf1a30Sjl { 778*25cf1a30Sjl int ret; 779*25cf1a30Sjl 780*25cf1a30Sjl ASSERT(dm2sp != NULL); 781*25cf1a30Sjl if (dm2sp->ms_state & DM2S_MB_INITED) { 782*25cf1a30Sjl DPRINTF(DBG_MBOX, ("dm2s_mbox_fini: calling mb_fini\n")); 783*25cf1a30Sjl ret = scf_mb_fini(dm2sp->ms_target, dm2sp->ms_key); 784*25cf1a30Sjl if (ret != 0) { 785*25cf1a30Sjl cmn_err(CE_WARN, 786*25cf1a30Sjl "Failed to close the Mailbox error =%d", ret); 787*25cf1a30Sjl } 788*25cf1a30Sjl DPRINTF(DBG_MBOX, ("dm2s_mbox_fini: mb_fini ret=%d\n", ret)); 789*25cf1a30Sjl dm2sp->ms_state &= ~(DM2S_MB_INITED |DM2S_MB_CONN | 790*25cf1a30Sjl DM2S_MB_DISC); 791*25cf1a30Sjl } 792*25cf1a30Sjl } 793*25cf1a30Sjl 794*25cf1a30Sjl /* 795*25cf1a30Sjl * dm2s_event_handler - Mailbox event handler. 796*25cf1a30Sjl */ 797*25cf1a30Sjl void 798*25cf1a30Sjl dm2s_event_handler(scf_event_t event, void *arg) 799*25cf1a30Sjl { 800*25cf1a30Sjl dm2s_t *dm2sp = (dm2s_t *)arg; 801*25cf1a30Sjl queue_t *rq; 802*25cf1a30Sjl 803*25cf1a30Sjl ASSERT(dm2sp != NULL); 804*25cf1a30Sjl mutex_enter(&dm2sp->ms_lock); 805*25cf1a30Sjl if (!(dm2sp->ms_state & DM2S_MB_INITED)) { 806*25cf1a30Sjl /* 807*25cf1a30Sjl * Ignore all events if the state flag indicates that the 808*25cf1a30Sjl * mailbox not initialized, this may happen during the close. 809*25cf1a30Sjl */ 810*25cf1a30Sjl mutex_exit(&dm2sp->ms_lock); 811*25cf1a30Sjl DPRINTF(DBG_MBOX, 812*25cf1a30Sjl ("Event(0x%X) received - Mailbox not inited\n", event)); 813*25cf1a30Sjl return; 814*25cf1a30Sjl } 815*25cf1a30Sjl switch (event) { 816*25cf1a30Sjl case SCF_MB_CONN_OK: 817*25cf1a30Sjl /* 818*25cf1a30Sjl * Now the mailbox is ready to use, lets wake up 819*25cf1a30Sjl * any one waiting for this event. 820*25cf1a30Sjl */ 821*25cf1a30Sjl dm2sp->ms_state |= DM2S_MB_CONN; 822*25cf1a30Sjl cv_broadcast(&dm2sp->ms_wait); 823*25cf1a30Sjl DPRINTF(DBG_MBOX, ("Event received = CONN_OK\n")); 824*25cf1a30Sjl break; 825*25cf1a30Sjl 826*25cf1a30Sjl case SCF_MB_MSG_DATA: 827*25cf1a30Sjl if (!DM2S_MBOX_READY(dm2sp)) { 828*25cf1a30Sjl DPRINTF(DBG_MBOX, 829*25cf1a30Sjl ("Event(MSG_DATA) received - Mailbox not READY\n")); 830*25cf1a30Sjl break; 831*25cf1a30Sjl } 832*25cf1a30Sjl /* 833*25cf1a30Sjl * A message is available in the mailbox. 834*25cf1a30Sjl * Lets enable the read service procedure 835*25cf1a30Sjl * to receive this message. 836*25cf1a30Sjl */ 837*25cf1a30Sjl if (dm2sp->ms_rq != NULL) { 838*25cf1a30Sjl qenable(dm2sp->ms_rq); 839*25cf1a30Sjl } 840*25cf1a30Sjl DPRINTF(DBG_MBOX, ("Event received = MSG_DATA\n")); 841*25cf1a30Sjl break; 842*25cf1a30Sjl 843*25cf1a30Sjl case SCF_MB_SPACE: 844*25cf1a30Sjl if (!DM2S_MBOX_READY(dm2sp)) { 845*25cf1a30Sjl DPRINTF(DBG_MBOX, 846*25cf1a30Sjl ("Event(MB_SPACE) received - Mailbox not READY\n")); 847*25cf1a30Sjl break; 848*25cf1a30Sjl } 849*25cf1a30Sjl 850*25cf1a30Sjl /* 851*25cf1a30Sjl * Now the mailbox is ready to transmit, lets 852*25cf1a30Sjl * schedule the write service procedure. 853*25cf1a30Sjl */ 854*25cf1a30Sjl if (dm2sp->ms_wq != NULL) { 855*25cf1a30Sjl qenable(dm2sp->ms_wq); 856*25cf1a30Sjl } 857*25cf1a30Sjl DPRINTF(DBG_MBOX, ("Event received = MB_SPACE\n")); 858*25cf1a30Sjl break; 859*25cf1a30Sjl case SCF_MB_DISC_ERROR: 860*25cf1a30Sjl dm2sp->ms_state |= DM2S_MB_DISC; 861*25cf1a30Sjl if (dm2sp->ms_state & DM2S_MB_CONN) { 862*25cf1a30Sjl /* 863*25cf1a30Sjl * If it was previously connected, 864*25cf1a30Sjl * then send a hangup message. 865*25cf1a30Sjl */ 866*25cf1a30Sjl rq = dm2sp->ms_rq; 867*25cf1a30Sjl if (rq != NULL) { 868*25cf1a30Sjl mutex_exit(&dm2sp->ms_lock); 869*25cf1a30Sjl /* 870*25cf1a30Sjl * Send a hangup message to indicate 871*25cf1a30Sjl * disconnect event. 872*25cf1a30Sjl */ 873*25cf1a30Sjl (void) putctl(rq, M_HANGUP); 874*25cf1a30Sjl DTRACE_PROBE1(dm2s_hangup, dm2s_t, dm2sp); 875*25cf1a30Sjl mutex_enter(&dm2sp->ms_lock); 876*25cf1a30Sjl } 877*25cf1a30Sjl } else { 878*25cf1a30Sjl /* 879*25cf1a30Sjl * Signal if the open is waiting for a 880*25cf1a30Sjl * connection. 881*25cf1a30Sjl */ 882*25cf1a30Sjl cv_broadcast(&dm2sp->ms_wait); 883*25cf1a30Sjl } 884*25cf1a30Sjl DPRINTF(DBG_MBOX, ("Event received = DISC_ERROR\n")); 885*25cf1a30Sjl break; 886*25cf1a30Sjl default: 887*25cf1a30Sjl cmn_err(CE_WARN, "Unexpected event received\n"); 888*25cf1a30Sjl break; 889*25cf1a30Sjl } 890*25cf1a30Sjl mutex_exit(&dm2sp->ms_lock); 891*25cf1a30Sjl } 892*25cf1a30Sjl 893*25cf1a30Sjl /* 894*25cf1a30Sjl * dm2s_start - Start transmission function. 895*25cf1a30Sjl * 896*25cf1a30Sjl * Send all queued messages. If the mailbox is busy, then 897*25cf1a30Sjl * start a timeout as a polling mechanism. The timeout is useful 898*25cf1a30Sjl * to not rely entirely on the SCF_MB_SPACE event. 899*25cf1a30Sjl */ 900*25cf1a30Sjl void 901*25cf1a30Sjl dm2s_start(queue_t *wq, dm2s_t *dm2sp) 902*25cf1a30Sjl { 903*25cf1a30Sjl mblk_t *mp; 904*25cf1a30Sjl int ret; 905*25cf1a30Sjl 906*25cf1a30Sjl DPRINTF(DBG_DRV, ("dm2s_start: called\n")); 907*25cf1a30Sjl ASSERT(dm2sp != NULL); 908*25cf1a30Sjl ASSERT(MUTEX_HELD(&dm2sp->ms_lock)); 909*25cf1a30Sjl 910*25cf1a30Sjl while ((mp = getq(wq)) != NULL) { 911*25cf1a30Sjl switch (mp->b_datap->db_type) { 912*25cf1a30Sjl 913*25cf1a30Sjl case M_DATA: 914*25cf1a30Sjl ret = dm2s_transmit(wq, mp, dm2sp->ms_target, 915*25cf1a30Sjl dm2sp->ms_key); 916*25cf1a30Sjl if (ret == EBUSY || ret == ENOSPC || ret == EAGAIN) { 917*25cf1a30Sjl DPRINTF(DBG_MBOX, 918*25cf1a30Sjl ("dm2s_start: recoverable err=%d\n", ret)); 919*25cf1a30Sjl /* 920*25cf1a30Sjl * Start a timeout to retry again. 921*25cf1a30Sjl */ 922*25cf1a30Sjl if (dm2sp->ms_wq_timeoutid == 0) { 923*25cf1a30Sjl DTRACE_PROBE1(dm2s_wqtimeout__start, 924*25cf1a30Sjl dm2s_t, dm2sp); 925*25cf1a30Sjl dm2sp->ms_wq_timeoutid = qtimeout(wq, 926*25cf1a30Sjl dm2s_wq_timeout, (void *)dm2sp, 927*25cf1a30Sjl dm2s_timeout_val(ret)); 928*25cf1a30Sjl } 929*25cf1a30Sjl return; 930*25cf1a30Sjl } else if (ret != 0) { 931*25cf1a30Sjl mutex_exit(&dm2sp->ms_lock); 932*25cf1a30Sjl /* 933*25cf1a30Sjl * An error occurred with the transmission, 934*25cf1a30Sjl * flush pending messages and initiate a 935*25cf1a30Sjl * hangup. 936*25cf1a30Sjl */ 937*25cf1a30Sjl flushq(wq, FLUSHDATA); 938*25cf1a30Sjl (void) putnextctl(RD(wq), M_HANGUP); 939*25cf1a30Sjl DTRACE_PROBE1(dm2s_hangup, dm2s_t, dm2sp); 940*25cf1a30Sjl DPRINTF(DBG_WARN, 941*25cf1a30Sjl ("dm2s_start: hangup transmit err=%d\n", 942*25cf1a30Sjl ret)); 943*25cf1a30Sjl mutex_enter(&dm2sp->ms_lock); 944*25cf1a30Sjl } 945*25cf1a30Sjl break; 946*25cf1a30Sjl default: 947*25cf1a30Sjl /* 948*25cf1a30Sjl * At this point, we don't expect any other messages. 949*25cf1a30Sjl */ 950*25cf1a30Sjl freemsg(mp); 951*25cf1a30Sjl break; 952*25cf1a30Sjl } 953*25cf1a30Sjl } 954*25cf1a30Sjl } 955*25cf1a30Sjl 956*25cf1a30Sjl /* 957*25cf1a30Sjl * dm2s_receive - Read all messages from the mailbox. 958*25cf1a30Sjl * 959*25cf1a30Sjl * This function is called from the read service procedure, to 960*25cf1a30Sjl * receive the messages awaiting in the mailbox. 961*25cf1a30Sjl */ 962*25cf1a30Sjl void 963*25cf1a30Sjl dm2s_receive(dm2s_t *dm2sp) 964*25cf1a30Sjl { 965*25cf1a30Sjl queue_t *rq = dm2sp->ms_rq; 966*25cf1a30Sjl mblk_t *mp; 967*25cf1a30Sjl int ret; 968*25cf1a30Sjl uint32_t len; 969*25cf1a30Sjl 970*25cf1a30Sjl DPRINTF(DBG_DRV, ("dm2s_receive: called\n")); 971*25cf1a30Sjl ASSERT(dm2sp != NULL); 972*25cf1a30Sjl ASSERT(MUTEX_HELD(&dm2sp->ms_lock)); 973*25cf1a30Sjl if (rq == NULL) { 974*25cf1a30Sjl return; 975*25cf1a30Sjl } 976*25cf1a30Sjl /* 977*25cf1a30Sjl * As the number of messages in the mailbox are pretty limited, 978*25cf1a30Sjl * it is safe to process all messages in one loop. 979*25cf1a30Sjl */ 980*25cf1a30Sjl while (DM2S_MBOX_READY(dm2sp) && ((ret = scf_mb_canget(dm2sp->ms_target, 981*25cf1a30Sjl dm2sp->ms_key, &len)) == 0)) { 982*25cf1a30Sjl DPRINTF(DBG_MBOX, ("dm2s_receive: mb_canget len=%d\n", len)); 983*25cf1a30Sjl if (len == 0) { 984*25cf1a30Sjl break; 985*25cf1a30Sjl } 986*25cf1a30Sjl mp = allocb(len, BPRI_MED); 987*25cf1a30Sjl if (mp == NULL) { 988*25cf1a30Sjl DPRINTF(DBG_WARN, ("dm2s_receive: allocb failed\n")); 989*25cf1a30Sjl /* 990*25cf1a30Sjl * Start a bufcall so that we can retry again 991*25cf1a30Sjl * when memory becomes available. 992*25cf1a30Sjl */ 993*25cf1a30Sjl dm2sp->ms_rbufcid = qbufcall(rq, len, BPRI_MED, 994*25cf1a30Sjl dm2s_bufcall_rcv, dm2sp); 995*25cf1a30Sjl if (dm2sp->ms_rbufcid == 0) { 996*25cf1a30Sjl DPRINTF(DBG_WARN, 997*25cf1a30Sjl ("dm2s_receive: qbufcall failed\n")); 998*25cf1a30Sjl /* 999*25cf1a30Sjl * if bufcall fails, start a timeout to 1000*25cf1a30Sjl * initiate a re-try after some time. 1001*25cf1a30Sjl */ 1002*25cf1a30Sjl DTRACE_PROBE1(dm2s_rqtimeout__start, 1003*25cf1a30Sjl dm2s_t, dm2sp); 1004*25cf1a30Sjl dm2sp->ms_rq_timeoutid = qtimeout(rq, 1005*25cf1a30Sjl dm2s_rq_timeout, (void *)dm2sp, 1006*25cf1a30Sjl drv_usectohz(DM2S_SM_TOUT)); 1007*25cf1a30Sjl } 1008*25cf1a30Sjl break; 1009*25cf1a30Sjl } 1010*25cf1a30Sjl 1011*25cf1a30Sjl /* 1012*25cf1a30Sjl * Only a single scatter/gather element is enough here. 1013*25cf1a30Sjl */ 1014*25cf1a30Sjl dm2sp->ms_sg_rcv.msc_dptr = (caddr_t)mp->b_wptr; 1015*25cf1a30Sjl dm2sp->ms_sg_rcv.msc_len = len; 1016*25cf1a30Sjl DPRINTF(DBG_MBOX, ("dm2s_receive: calling getmsg\n")); 1017*25cf1a30Sjl ret = scf_mb_getmsg(dm2sp->ms_target, dm2sp->ms_key, len, 1, 1018*25cf1a30Sjl &dm2sp->ms_sg_rcv, 0); 1019*25cf1a30Sjl DPRINTF(DBG_MBOX, ("dm2s_receive: getmsg ret=%d\n", ret)); 1020*25cf1a30Sjl if (ret != 0) { 1021*25cf1a30Sjl freemsg(mp); 1022*25cf1a30Sjl break; 1023*25cf1a30Sjl } 1024*25cf1a30Sjl DMPBYTES("dm2s: Getmsg: ", len, 1, &dm2sp->ms_sg_rcv); 1025*25cf1a30Sjl mp->b_wptr += len; 1026*25cf1a30Sjl /* 1027*25cf1a30Sjl * Queue the messages in the rq, so that the service 1028*25cf1a30Sjl * procedure handles sending the messages up the stream. 1029*25cf1a30Sjl */ 1030*25cf1a30Sjl putq(rq, mp); 1031*25cf1a30Sjl } 1032*25cf1a30Sjl 1033*25cf1a30Sjl if ((!DM2S_MBOX_READY(dm2sp)) || (ret != ENOMSG && ret != EMSGSIZE)) { 1034*25cf1a30Sjl /* 1035*25cf1a30Sjl * Some thing went wrong, flush pending messages 1036*25cf1a30Sjl * and initiate a hangup. 1037*25cf1a30Sjl * Note: flushing the wq initiates a faster close. 1038*25cf1a30Sjl */ 1039*25cf1a30Sjl mutex_exit(&dm2sp->ms_lock); 1040*25cf1a30Sjl flushq(WR(rq), FLUSHDATA); 1041*25cf1a30Sjl (void) putnextctl(rq, M_HANGUP); 1042*25cf1a30Sjl DTRACE_PROBE1(dm2s_hangup, dm2s_t, dm2sp); 1043*25cf1a30Sjl mutex_enter(&dm2sp->ms_lock); 1044*25cf1a30Sjl DPRINTF(DBG_WARN, ("dm2s_receive: encountered unknown " 1045*25cf1a30Sjl "condition - hangup ret=%d\n", ret)); 1046*25cf1a30Sjl } 1047*25cf1a30Sjl } 1048*25cf1a30Sjl 1049*25cf1a30Sjl /* 1050*25cf1a30Sjl * dm2s_transmit - Transmit a message. 1051*25cf1a30Sjl */ 1052*25cf1a30Sjl int 1053*25cf1a30Sjl dm2s_transmit(queue_t *wq, mblk_t *mp, target_id_t target, mkey_t key) 1054*25cf1a30Sjl { 1055*25cf1a30Sjl dm2s_t *dm2sp = (dm2s_t *)wq->q_ptr; 1056*25cf1a30Sjl int ret; 1057*25cf1a30Sjl uint32_t len; 1058*25cf1a30Sjl uint32_t numsg; 1059*25cf1a30Sjl 1060*25cf1a30Sjl DPRINTF(DBG_DRV, ("dm2s_transmit: called\n")); 1061*25cf1a30Sjl ASSERT(dm2sp != NULL); 1062*25cf1a30Sjl ASSERT(MUTEX_HELD(&dm2sp->ms_lock)); 1063*25cf1a30Sjl /* 1064*25cf1a30Sjl * Free the message if the mailbox is not in the connected state. 1065*25cf1a30Sjl */ 1066*25cf1a30Sjl if (!DM2S_MBOX_READY(dm2sp)) { 1067*25cf1a30Sjl DPRINTF(DBG_MBOX, ("dm2s_transmit: mailbox not ready yet\n")); 1068*25cf1a30Sjl freemsg(mp); 1069*25cf1a30Sjl return (EIO); 1070*25cf1a30Sjl } 1071*25cf1a30Sjl 1072*25cf1a30Sjl len = msgdsize(mp); 1073*25cf1a30Sjl if (len > dm2sp->ms_mtu) { 1074*25cf1a30Sjl /* 1075*25cf1a30Sjl * Size is too big to send, free the message. 1076*25cf1a30Sjl */ 1077*25cf1a30Sjl DPRINTF(DBG_MBOX, ("dm2s_transmit: message too large\n")); 1078*25cf1a30Sjl DTRACE_PROBE2(dm2s_msg_too_big, dm2s_t, dm2sp, uint32_t, len); 1079*25cf1a30Sjl freemsg(mp); 1080*25cf1a30Sjl return (0); 1081*25cf1a30Sjl } 1082*25cf1a30Sjl 1083*25cf1a30Sjl if ((ret = dm2s_prep_scatgath(mp, &numsg, dm2sp->ms_sg_tx, 1084*25cf1a30Sjl DM2S_MAX_SG)) != 0) { 1085*25cf1a30Sjl DPRINTF(DBG_MBOX, ("dm2s_transmit: prep_scatgath failed\n")); 1086*25cf1a30Sjl putbq(wq, mp); 1087*25cf1a30Sjl return (EAGAIN); 1088*25cf1a30Sjl } 1089*25cf1a30Sjl DPRINTF(DBG_MBOX, ("dm2s_transmit: calling mb_putmsg numsg=%d len=%d\n", 1090*25cf1a30Sjl numsg, len)); 1091*25cf1a30Sjl ret = scf_mb_putmsg(target, key, len, numsg, dm2sp->ms_sg_tx, 0); 1092*25cf1a30Sjl if (ret == EBUSY || ret == ENOSPC) { 1093*25cf1a30Sjl DPRINTF(DBG_MBOX, 1094*25cf1a30Sjl ("dm2s_transmit: mailbox busy ret=%d\n", ret)); 1095*25cf1a30Sjl if (++dm2sp->ms_retries >= DM2S_MAX_RETRIES) { 1096*25cf1a30Sjl /* 1097*25cf1a30Sjl * If maximum retries are reached, then free the 1098*25cf1a30Sjl * message. 1099*25cf1a30Sjl */ 1100*25cf1a30Sjl DPRINTF(DBG_MBOX, 1101*25cf1a30Sjl ("dm2s_transmit: freeing msg after max retries\n")); 1102*25cf1a30Sjl DTRACE_PROBE2(dm2s_retry_fail, dm2s_t, dm2sp, int, ret); 1103*25cf1a30Sjl freemsg(mp); 1104*25cf1a30Sjl dm2sp->ms_retries = 0; 1105*25cf1a30Sjl return (0); 1106*25cf1a30Sjl } 1107*25cf1a30Sjl DTRACE_PROBE2(dm2s_mb_busy, dm2s_t, dm2sp, int, ret); 1108*25cf1a30Sjl /* 1109*25cf1a30Sjl * Queue it back, so that we can retry again. 1110*25cf1a30Sjl */ 1111*25cf1a30Sjl putbq(wq, mp); 1112*25cf1a30Sjl return (ret); 1113*25cf1a30Sjl } 1114*25cf1a30Sjl DMPBYTES("dm2s: Putmsg: ", len, numsg, dm2sp->ms_sg_tx); 1115*25cf1a30Sjl dm2sp->ms_retries = 0; 1116*25cf1a30Sjl freemsg(mp); 1117*25cf1a30Sjl DPRINTF(DBG_DRV, ("dm2s_transmit: ret=%d\n", ret)); 1118*25cf1a30Sjl return (ret); 1119*25cf1a30Sjl } 1120*25cf1a30Sjl 1121*25cf1a30Sjl /* 1122*25cf1a30Sjl * dm2s_bufcall_rcv - Bufcall callaback routine. 1123*25cf1a30Sjl * 1124*25cf1a30Sjl * It simply enables read side queue so that the service procedure 1125*25cf1a30Sjl * can retry receive operation. 1126*25cf1a30Sjl */ 1127*25cf1a30Sjl void 1128*25cf1a30Sjl dm2s_bufcall_rcv(void *arg) 1129*25cf1a30Sjl { 1130*25cf1a30Sjl dm2s_t *dm2sp = (dm2s_t *)arg; 1131*25cf1a30Sjl 1132*25cf1a30Sjl DPRINTF(DBG_DRV, ("dm2s_bufcall_rcv: called\n")); 1133*25cf1a30Sjl mutex_enter(&dm2sp->ms_lock); 1134*25cf1a30Sjl dm2sp->ms_rbufcid = 0; 1135*25cf1a30Sjl if (dm2sp->ms_rq != NULL) { 1136*25cf1a30Sjl qenable(dm2sp->ms_rq); 1137*25cf1a30Sjl } 1138*25cf1a30Sjl mutex_exit(&dm2sp->ms_lock); 1139*25cf1a30Sjl } 1140*25cf1a30Sjl 1141*25cf1a30Sjl /* 1142*25cf1a30Sjl * dm2s_rq_timeout - Timeout callback for the read side. 1143*25cf1a30Sjl * 1144*25cf1a30Sjl * It simply enables read side queue so that the service procedure 1145*25cf1a30Sjl * can retry the receive operation. 1146*25cf1a30Sjl */ 1147*25cf1a30Sjl void 1148*25cf1a30Sjl dm2s_rq_timeout(void *arg) 1149*25cf1a30Sjl { 1150*25cf1a30Sjl dm2s_t *dm2sp = (dm2s_t *)arg; 1151*25cf1a30Sjl 1152*25cf1a30Sjl DPRINTF(DBG_DRV, ("dm2s_rq_timeout: called\n")); 1153*25cf1a30Sjl mutex_enter(&dm2sp->ms_lock); 1154*25cf1a30Sjl dm2sp->ms_rq_timeoutid = 0; 1155*25cf1a30Sjl if (dm2sp->ms_rq != NULL) { 1156*25cf1a30Sjl qenable(dm2sp->ms_rq); 1157*25cf1a30Sjl } 1158*25cf1a30Sjl mutex_exit(&dm2sp->ms_lock); 1159*25cf1a30Sjl } 1160*25cf1a30Sjl 1161*25cf1a30Sjl /* 1162*25cf1a30Sjl * dm2s_wq_timeout - Timeout callback for the write. 1163*25cf1a30Sjl * 1164*25cf1a30Sjl * It simply enables write side queue so that the service procedure 1165*25cf1a30Sjl * can retry the transmission operation. 1166*25cf1a30Sjl */ 1167*25cf1a30Sjl void 1168*25cf1a30Sjl dm2s_wq_timeout(void *arg) 1169*25cf1a30Sjl { 1170*25cf1a30Sjl dm2s_t *dm2sp = (dm2s_t *)arg; 1171*25cf1a30Sjl 1172*25cf1a30Sjl DPRINTF(DBG_DRV, ("dm2s_wq_timeout: called\n")); 1173*25cf1a30Sjl mutex_enter(&dm2sp->ms_lock); 1174*25cf1a30Sjl dm2sp->ms_wq_timeoutid = 0; 1175*25cf1a30Sjl if (dm2sp->ms_wq != NULL) { 1176*25cf1a30Sjl qenable(dm2sp->ms_wq); 1177*25cf1a30Sjl } 1178*25cf1a30Sjl mutex_exit(&dm2sp->ms_lock); 1179*25cf1a30Sjl } 1180*25cf1a30Sjl 1181*25cf1a30Sjl /* 1182*25cf1a30Sjl * dm2s_prep_scatgath - Prepare scatter/gather elements for transmission 1183*25cf1a30Sjl * of a streams message. 1184*25cf1a30Sjl */ 1185*25cf1a30Sjl static int 1186*25cf1a30Sjl dm2s_prep_scatgath(mblk_t *mp, uint32_t *numsg, mscat_gath_t *sgp, int maxsg) 1187*25cf1a30Sjl { 1188*25cf1a30Sjl uint32_t num = 0; 1189*25cf1a30Sjl mblk_t *tmp = mp; 1190*25cf1a30Sjl 1191*25cf1a30Sjl while ((tmp != NULL) && (num < maxsg)) { 1192*25cf1a30Sjl sgp[num].msc_dptr = (caddr_t)tmp->b_rptr; 1193*25cf1a30Sjl sgp[num].msc_len = MBLKL(tmp); 1194*25cf1a30Sjl tmp = tmp->b_cont; 1195*25cf1a30Sjl num++; 1196*25cf1a30Sjl } 1197*25cf1a30Sjl 1198*25cf1a30Sjl if (tmp != NULL) { 1199*25cf1a30Sjl /* 1200*25cf1a30Sjl * Number of scatter/gather elements available are not 1201*25cf1a30Sjl * enough, so lets pullup the msg. 1202*25cf1a30Sjl */ 1203*25cf1a30Sjl if (pullupmsg(mp, -1) != 1) { 1204*25cf1a30Sjl return (EAGAIN); 1205*25cf1a30Sjl } 1206*25cf1a30Sjl sgp[0].msc_dptr = (caddr_t)mp->b_rptr; 1207*25cf1a30Sjl sgp[0].msc_len = MBLKL(mp); 1208*25cf1a30Sjl num = 1; 1209*25cf1a30Sjl } 1210*25cf1a30Sjl *numsg = num; 1211*25cf1a30Sjl return (0); 1212*25cf1a30Sjl } 1213*25cf1a30Sjl 1214*25cf1a30Sjl /* 1215*25cf1a30Sjl * dm2s_timeout_val -- Return appropriate timeout value. 1216*25cf1a30Sjl * 1217*25cf1a30Sjl * A small timeout value is returned for EBUSY and EAGAIN cases. This is 1218*25cf1a30Sjl * because the condition is expected to be recovered sooner. 1219*25cf1a30Sjl * 1220*25cf1a30Sjl * A larger timeout value is returned for ENOSPC case, as the condition 1221*25cf1a30Sjl * depends on the peer to release buffer space. 1222*25cf1a30Sjl * NOTE: there will also be an event(SCF_MB_SPACE) but a timeout is 1223*25cf1a30Sjl * used for reliability purposes. 1224*25cf1a30Sjl */ 1225*25cf1a30Sjl static clock_t 1226*25cf1a30Sjl dm2s_timeout_val(int error) 1227*25cf1a30Sjl { 1228*25cf1a30Sjl clock_t tval; 1229*25cf1a30Sjl 1230*25cf1a30Sjl ASSERT(error == EBUSY || error == ENOSPC || error == EAGAIN); 1231*25cf1a30Sjl 1232*25cf1a30Sjl if (error == EBUSY || error == EAGAIN) { 1233*25cf1a30Sjl tval = DM2S_SM_TOUT; 1234*25cf1a30Sjl } else { 1235*25cf1a30Sjl tval = DM2S_LG_TOUT; 1236*25cf1a30Sjl } 1237*25cf1a30Sjl return (drv_usectohz(tval)); 1238*25cf1a30Sjl } 1239*25cf1a30Sjl 1240*25cf1a30Sjl #ifdef DEBUG 1241*25cf1a30Sjl 1242*25cf1a30Sjl static void 1243*25cf1a30Sjl dm2s_dump_bytes(char *str, uint32_t total_len, 1244*25cf1a30Sjl uint32_t num_sg, mscat_gath_t *sgp) 1245*25cf1a30Sjl { 1246*25cf1a30Sjl int i, j; 1247*25cf1a30Sjl int nsg; 1248*25cf1a30Sjl int len, tlen = 0; 1249*25cf1a30Sjl mscat_gath_t *tp; 1250*25cf1a30Sjl uint8_t *datap; 1251*25cf1a30Sjl #define BYTES_PER_LINE 20 1252*25cf1a30Sjl char bytestr[BYTES_PER_LINE * 3 + 1]; 1253*25cf1a30Sjl uint32_t digest = 0; 1254*25cf1a30Sjl 1255*25cf1a30Sjl if (!(dm2s_debug & DBG_MESG)) 1256*25cf1a30Sjl return; 1257*25cf1a30Sjl ASSERT(num_sg != 0); 1258*25cf1a30Sjl 1259*25cf1a30Sjl for (nsg = 0; (nsg < num_sg) && (tlen < total_len); nsg++) { 1260*25cf1a30Sjl tp = &sgp[nsg]; 1261*25cf1a30Sjl datap = (uint8_t *)tp->msc_dptr; 1262*25cf1a30Sjl len = tp->msc_len; 1263*25cf1a30Sjl for (i = 0; i < len; i++) { 1264*25cf1a30Sjl digest += datap[i]; 1265*25cf1a30Sjl } 1266*25cf1a30Sjl tlen += len; 1267*25cf1a30Sjl } 1268*25cf1a30Sjl sprintf(bytestr, "%s Packet: Size=%d Digest=%d\n", 1269*25cf1a30Sjl str, total_len, digest); 1270*25cf1a30Sjl DTRACE_PROBE1(dm2s_dump_digest, unsigned char *, bytestr); 1271*25cf1a30Sjl 1272*25cf1a30Sjl for (nsg = 0; (nsg < num_sg) && (tlen < total_len); nsg++) { 1273*25cf1a30Sjl tp = &sgp[nsg]; 1274*25cf1a30Sjl datap = (uint8_t *)tp->msc_dptr; 1275*25cf1a30Sjl len = tp->msc_len; 1276*25cf1a30Sjl for (i = 0; i < len; ) { 1277*25cf1a30Sjl for (j = 0; (j < BYTES_PER_LINE) && 1278*25cf1a30Sjl (i < len); j++, i++) { 1279*25cf1a30Sjl sprintf(&bytestr[j * 3], "%02X ", datap[i]); 1280*25cf1a30Sjl digest += datap[i]; 1281*25cf1a30Sjl } 1282*25cf1a30Sjl if (j != 0) { 1283*25cf1a30Sjl DTRACE_PROBE1(dm2s_dump, unsigned char *, 1284*25cf1a30Sjl bytestr); 1285*25cf1a30Sjl } 1286*25cf1a30Sjl } 1287*25cf1a30Sjl tlen += i; 1288*25cf1a30Sjl } 1289*25cf1a30Sjl } 1290*25cf1a30Sjl 1291*25cf1a30Sjl #endif /* DEBUG */ 1292