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