xref: /onnv-gate/usr/src/uts/common/io/ib/clients/rds/rdsddi.c (revision 11042:2d6e217af1b4)
13302Sagiri /*
23302Sagiri  * CDDL HEADER START
33302Sagiri  *
43302Sagiri  * The contents of this file are subject to the terms of the
53302Sagiri  * Common Development and Distribution License (the "License").
63302Sagiri  * You may not use this file except in compliance with the License.
73302Sagiri  *
83302Sagiri  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
93302Sagiri  * or http://www.opensolaris.org/os/licensing.
103302Sagiri  * See the License for the specific language governing permissions
113302Sagiri  * and limitations under the License.
123302Sagiri  *
133302Sagiri  * When distributing Covered Code, include this CDDL HEADER in each
143302Sagiri  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
153302Sagiri  * If applicable, add the following below this CDDL HEADER, with the
163302Sagiri  * fields enclosed by brackets "[]" replaced with your own identifying
173302Sagiri  * information: Portions Copyright [yyyy] [name of copyright owner]
183302Sagiri  *
193302Sagiri  * CDDL HEADER END
203302Sagiri  */
213302Sagiri /*
228778SErik.Nordmark@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
233302Sagiri  * Use is subject to license terms.
243302Sagiri  */
253302Sagiri 
263302Sagiri #include <sys/types.h>
273302Sagiri #include <sys/conf.h>
283302Sagiri #include <sys/modctl.h>
293302Sagiri #include <sys/stat.h>
303302Sagiri #include <sys/stream.h>
313302Sagiri #include <sys/strsun.h>
323302Sagiri #include <sys/ddi.h>
333302Sagiri #include <sys/sunddi.h>
343302Sagiri #include <sys/priv_names.h>
353302Sagiri #include <inet/common.h>
363302Sagiri 
373302Sagiri #define	_SUN_TPI_VERSION 2
383302Sagiri #include <sys/tihdr.h>
393302Sagiri #include <sys/timod.h>
403302Sagiri #include <sys/tiuser.h>
413302Sagiri #include <sys/suntpi.h>
423302Sagiri #include <inet/common.h>
433302Sagiri #include <inet/ip.h>
443302Sagiri #include <inet/mi.h>
458348SEric.Yu@Sun.COM #include <inet/proto_set.h>
463302Sagiri #include <sys/ib/clients/rds/rds.h>
473302Sagiri #include <sys/policy.h>
483302Sagiri #include <inet/ipclassifier.h>
493302Sagiri #include <sys/ib/clients/rds/rds_kstat.h>
503302Sagiri #include "sys/random.h"
513302Sagiri #include <sys/ib/clients/rds/rds_transport.h>
523302Sagiri #include <sys/ib/ibtl/ibti.h>
533302Sagiri 
543302Sagiri 
553302Sagiri #define	RDS_NAME	"rds"
563302Sagiri #define	RDS_STRTAB	rdsinfo
577656SSherry.Moore@Sun.COM #define	RDS_DEVDESC	"RDS STREAMS driver"
583302Sagiri #define	RDS_DEVMINOR	0
593302Sagiri #define	RDS_DEVMTFLAGS D_MP | D_SYNCSTR
603302Sagiri #define	RDS_DEFAULT_PRIV_MODE	0666
613302Sagiri 
623302Sagiri #define	rds_smallest_port	1
633302Sagiri #define	rds_largest_port	65535
643302Sagiri 
653302Sagiri #define	RDS_RECV_HIWATER	(56 * 1024)
663302Sagiri #define	RDS_RECV_LOWATER	128
673302Sagiri #define	RDS_XMIT_HIWATER	(56 * 1024)
683302Sagiri #define	RDS_XMIT_LOWATER	1024
693302Sagiri 
703302Sagiri #define	RDS_DPRINTF2	0 &&
713302Sagiri #define	LABEL	"RDS"
723302Sagiri 
733302Sagiri typedef struct rdsahdr_s {
743302Sagiri 	in_port_t	uha_src_port;	/* Source port */
753302Sagiri 	in_port_t	uha_dst_port;	/* Destination port */
763302Sagiri } rdsha_t;
773302Sagiri 
783302Sagiri #define	RDSH_SIZE	4
793302Sagiri 
803302Sagiri int rds_recv_hiwat = RDS_RECV_HIWATER;
813302Sagiri int rds_recv_lowat = RDS_RECV_LOWATER;
823302Sagiri int rds_xmit_hiwat = RDS_XMIT_HIWATER;
833302Sagiri int rds_xmit_lowat = RDS_XMIT_LOWATER;
843302Sagiri 
853302Sagiri int rdsdebug;
863302Sagiri 
873302Sagiri static dev_info_t *rds_dev_info;
883302Sagiri 
893302Sagiri /* Hint not protected by any lock */
903302Sagiri static	in_port_t	rds_next_port_to_try;
913302Sagiri 
923302Sagiri ldi_ident_t rds_li;
933302Sagiri static int loopmax = rds_largest_port - rds_smallest_port + 1;
943302Sagiri 
953302Sagiri /* global configuration variables */
963302Sagiri uint_t  UserBufferSize;
973302Sagiri uint_t  rds_rx_pkts_pending_hwm;
983302Sagiri 
993302Sagiri extern void rds_ioctl(queue_t *, mblk_t *);
1003302Sagiri extern void rds_ioctl_copyin_done(queue_t *q, mblk_t *mp);
1013302Sagiri 
1023302Sagiri int rds_open_transport_driver();
1033302Sagiri int rds_close_transport_driver();
1043302Sagiri 
1053302Sagiri #define	RDS_CURRENT_PORT_QUOTA()					\
1063302Sagiri 	(rds_rx_pkts_pending_hwm/RDS_GET_NPORT())
1073302Sagiri 
1083302Sagiri krwlock_t	rds_transport_lock;
1093302Sagiri ldi_handle_t	rds_transport_handle = NULL;
1103302Sagiri rds_transport_ops_t *rds_transport_ops = NULL;
1113302Sagiri 
1123302Sagiri static int
rds_attach(dev_info_t * devi,ddi_attach_cmd_t cmd)1133302Sagiri rds_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
1143302Sagiri {
1153302Sagiri 	int	ret;
1163302Sagiri 
1173302Sagiri 	if (cmd != DDI_ATTACH)
1183302Sagiri 		return (DDI_FAILURE);
1193302Sagiri 
1203302Sagiri 	rds_dev_info = devi;
1213302Sagiri 
1223302Sagiri 	ret = ddi_create_minor_node(devi, RDS_NAME, S_IFCHR,
1233302Sagiri 	    RDS_DEVMINOR, DDI_PSEUDO, 0);
1243302Sagiri 	if (ret != DDI_SUCCESS) {
1253302Sagiri 		return (ret);
1263302Sagiri 	}
1273302Sagiri 
1283302Sagiri 	return (DDI_SUCCESS);
1293302Sagiri }
1303302Sagiri 
1313302Sagiri static int
rds_detach(dev_info_t * devi,ddi_detach_cmd_t cmd)1323302Sagiri rds_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
1333302Sagiri {
1343302Sagiri 	if (cmd != DDI_DETACH)
1353302Sagiri 		return (DDI_FAILURE);
1363302Sagiri 
1373302Sagiri 	ASSERT(devi == rds_dev_info);
1383302Sagiri 
1393302Sagiri 	ddi_remove_minor_node(devi, NULL);
1403302Sagiri 
1413302Sagiri 	return (DDI_SUCCESS);
1423302Sagiri }
1433302Sagiri 
1443302Sagiri /* ARGSUSED */
1453302Sagiri static int
rds_info(dev_info_t * dip,ddi_info_cmd_t cmd,void * arg,void ** result)1463302Sagiri rds_info(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
1473302Sagiri {
1483302Sagiri 	int error = DDI_FAILURE;
1493302Sagiri 
1503302Sagiri 	switch (cmd) {
1513302Sagiri 	case DDI_INFO_DEVT2DEVINFO:
1523302Sagiri 		if (rds_dev_info != NULL) {
1533302Sagiri 			*result = (void *)rds_dev_info;
1543302Sagiri 			error = DDI_SUCCESS;
1553302Sagiri 		}
1563302Sagiri 		break;
1573302Sagiri 
1583302Sagiri 	case DDI_INFO_DEVT2INSTANCE:
1593302Sagiri 		*result = NULL;
1603302Sagiri 		error = DDI_SUCCESS;
1613302Sagiri 		break;
1623302Sagiri 
1633302Sagiri 	default:
1643302Sagiri 		break;
1653302Sagiri 	}
1663302Sagiri 
1673302Sagiri 	return (error);
1683302Sagiri }
1693302Sagiri 
1703302Sagiri 
1713302Sagiri /*ARGSUSED*/
1723302Sagiri static int
rds_open(queue_t * q,dev_t * devp,int flag,int sflag,cred_t * credp)1733302Sagiri rds_open(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *credp)
1743302Sagiri {
1753302Sagiri 	rds_t	*rds;
1763302Sagiri 	int	ret;
1773302Sagiri 
1783302Sagiri 	if (is_system_labeled()) {
1793302Sagiri 		/*
1803302Sagiri 		 * RDS socket is not supported on labeled systems
1813302Sagiri 		 */
1823302Sagiri 		return (ESOCKTNOSUPPORT);
1833302Sagiri 	}
1843302Sagiri 
1853302Sagiri 	/* Open the transport driver if IB HW is present */
1863302Sagiri 	rw_enter(&rds_transport_lock, RW_READER);
1873302Sagiri 	if (rds_transport_handle == NULL) {
1883302Sagiri 		rw_exit(&rds_transport_lock);
1893302Sagiri 		ret = rds_open_transport_driver();
1903302Sagiri 		rw_enter(&rds_transport_lock, RW_READER);
1913302Sagiri 
1923302Sagiri 		if (ret != 0) {
1933302Sagiri 			/* Transport driver failed to load */
1943302Sagiri 			rw_exit(&rds_transport_lock);
1953302Sagiri 			return (ret);
1963302Sagiri 		}
1973302Sagiri 	}
1983302Sagiri 	rw_exit(&rds_transport_lock);
1993302Sagiri 
2003302Sagiri 	if (sflag == MODOPEN) {
2013302Sagiri 		return (EINVAL);
2023302Sagiri 	}
2033302Sagiri 
2043302Sagiri 	/* Reopen not supported */
2053302Sagiri 	if (q->q_ptr != NULL) {
2063302Sagiri 		dprint(2, ("%s: Reopen is not supported: %p", LABEL, q->q_ptr));
2073302Sagiri 		return (0);
2083302Sagiri 	}
2093302Sagiri 
2103302Sagiri 	rds = rds_create(q, credp);
2113302Sagiri 	if (rds == NULL) {
2123302Sagiri 		dprint(2, ("%s: rds_create failed", LABEL));
2133302Sagiri 		return (0);
2143302Sagiri 	}
2153302Sagiri 
2163302Sagiri 	q->q_ptr = WR(q)->q_ptr = rds;
2173302Sagiri 	rds->rds_state = TS_UNBND;
2183302Sagiri 	rds->rds_family = AF_INET_OFFLOAD;
2193302Sagiri 
2203302Sagiri 	q->q_hiwat = rds_recv_hiwat;
2213302Sagiri 	q->q_lowat = rds_recv_lowat;
2223302Sagiri 
2233302Sagiri 	qprocson(q);
2243302Sagiri 
2253302Sagiri 	WR(q)->q_hiwat = rds_xmit_hiwat;
2263302Sagiri 	WR(q)->q_lowat = rds_xmit_lowat;
2273302Sagiri 
2283302Sagiri 	/* Set the Stream head watermarks */
2298348SEric.Yu@Sun.COM 	(void) proto_set_rx_hiwat(q, NULL, rds_recv_hiwat);
2308348SEric.Yu@Sun.COM 	(void) proto_set_rx_lowat(q, NULL, rds_recv_lowat);
2313302Sagiri 
2323302Sagiri 	return (0);
2333302Sagiri }
2343302Sagiri 
2353302Sagiri static int
rds_close(queue_t * q)2363302Sagiri rds_close(queue_t *q)
2373302Sagiri {
2383302Sagiri 	rds_t *rdsp = (rds_t *)q->q_ptr;
2393302Sagiri 
2403302Sagiri 	qprocsoff(q);
2413302Sagiri 
2423302Sagiri 	/*
2433302Sagiri 	 * NPORT should be decremented only if this socket was previously
2443302Sagiri 	 * bound to an RDS port.
2453302Sagiri 	 */
2463302Sagiri 	if (rdsp->rds_state >= TS_IDLE) {
2473302Sagiri 		RDS_DECR_NPORT();
2483302Sagiri 		RDS_SET_PORT_QUOTA(RDS_CURRENT_PORT_QUOTA());
2493302Sagiri 		rds_transport_ops->
2503302Sagiri 		    rds_transport_resume_port(ntohs(rdsp->rds_port));
2513302Sagiri 	}
2523302Sagiri 
2533302Sagiri 	/* close the transport driver if this is the last socket */
2543302Sagiri 	if (RDS_GET_NPORT() == 1) {
2553302Sagiri 		(void) rds_close_transport_driver();
2563302Sagiri 	}
2573302Sagiri 
2583302Sagiri 	/*
2593302Sagiri 	 * We set the flags without holding a lock as this is
2603302Sagiri 	 * just a hint for the fanout lookup to skip this rds.
2613302Sagiri 	 * We dont free the struct until it's out of the hash and
2623302Sagiri 	 * the ref count goes down.
2633302Sagiri 	 */
2643302Sagiri 	rdsp->rds_flags |= RDS_CLOSING;
2653302Sagiri 	rds_bind_hash_remove(rdsp, B_FALSE);
2663302Sagiri 	mutex_enter(&rdsp->rds_lock);
2673302Sagiri 	ASSERT(rdsp->rds_refcnt > 0);
2683302Sagiri 	if (rdsp->rds_refcnt != 1) {
2693302Sagiri 		cv_wait(&rdsp->rds_refcv, &rdsp->rds_lock);
2703302Sagiri 	}
2713302Sagiri 	mutex_exit(&rdsp->rds_lock);
2723302Sagiri 	RDS_DEC_REF_CNT(rdsp);
2733302Sagiri 	RD(q)->q_ptr = NULL;
2743302Sagiri 	WR(q)->q_ptr = NULL;
2753302Sagiri 	return (0);
2763302Sagiri }
2773302Sagiri 
2783302Sagiri /*
2793302Sagiri  * Add a new message to the socket
2803302Sagiri  */
2813302Sagiri int
rds_deliver_new_msg(mblk_t * mp,ipaddr_t local_addr,ipaddr_t rem_addr,in_port_t local_port,in_port_t rem_port,zoneid_t zoneid)2823302Sagiri rds_deliver_new_msg(mblk_t *mp, ipaddr_t local_addr, ipaddr_t rem_addr,
2833302Sagiri     in_port_t local_port, in_port_t rem_port, zoneid_t zoneid)
2843302Sagiri {
2853302Sagiri 	rds_t *rds;
2863302Sagiri 	struct  T_unitdata_ind  *tudi;
2873302Sagiri 	int	udi_size;	/* Size of T_unitdata_ind */
2883302Sagiri 	mblk_t *mp1;
2893302Sagiri 	sin_t	*sin;
2903302Sagiri 	int error = 0;
2913302Sagiri 
2923302Sagiri 	local_port = htons(local_port);
2933302Sagiri 	rem_port = htons(rem_port);
2943302Sagiri 
2953302Sagiri 	ASSERT(mp->b_datap->db_type == M_DATA);
2963302Sagiri 	rds = rds_fanout(local_addr, rem_addr, local_port, rem_port, zoneid);
2973302Sagiri 	if (rds == NULL) {
2983302Sagiri 		dprint(2, ("%s: rds_fanout failed: (0x%x 0x%x %d %d)", LABEL,
2993302Sagiri 		    local_addr, rem_addr, ntohs(local_port), ntohs(rem_port)));
3003302Sagiri 		freemsg(mp);
3013302Sagiri 		return (error);
3023302Sagiri 	}
3033302Sagiri 
3043302Sagiri 	udi_size = sizeof (struct T_unitdata_ind) + sizeof (sin_t);
3053302Sagiri 
3063302Sagiri 	/* Allocate a message block for the T_UNITDATA_IND structure. */
3073302Sagiri 	mp1 = allocb(udi_size, BPRI_MED);
3083302Sagiri 	if (mp1 == NULL) {
3093302Sagiri 		dprint(2, ("%s: allocb failed", LABEL));
3103302Sagiri 		freemsg(mp);
3113302Sagiri 		return (ENOMEM);
3123302Sagiri 	}
3133302Sagiri 
3143302Sagiri 	mp1->b_cont = mp;
3153302Sagiri 	mp = mp1;
3163302Sagiri 	mp->b_datap->db_type = M_PROTO;
3173302Sagiri 	tudi = (struct T_unitdata_ind *)(uintptr_t)mp->b_rptr;
3183302Sagiri 	mp->b_wptr = (uchar_t *)tudi + udi_size;
3193302Sagiri 	tudi->PRIM_type = T_UNITDATA_IND;
3203302Sagiri 	tudi->SRC_length = sizeof (sin_t);
3213302Sagiri 	tudi->SRC_offset = sizeof (struct T_unitdata_ind);
3223302Sagiri 	tudi->OPT_offset = sizeof (struct T_unitdata_ind) + sizeof (sin_t);
3233302Sagiri 	udi_size -= (sizeof (struct T_unitdata_ind) + sizeof (sin_t));
3243302Sagiri 	tudi->OPT_length = udi_size;
3253302Sagiri 	sin = (sin_t *)&tudi[1];
3263302Sagiri 	sin->sin_addr.s_addr = rem_addr;
3273302Sagiri 	sin->sin_port = ntohs(rem_port);
3283302Sagiri 	sin->sin_family = rds->rds_family;
3293302Sagiri 	*(uint32_t *)(uintptr_t)&sin->sin_zero[0] = 0;
3303302Sagiri 	*(uint32_t *)(uintptr_t)&sin->sin_zero[4] = 0;
3313302Sagiri 
3323302Sagiri 	putnext(rds->rds_ulpd, mp);
3333302Sagiri 
3343302Sagiri 	/* check port quota */
3353302Sagiri 	if (RDS_GET_RXPKTS_PEND() > rds_rx_pkts_pending_hwm) {
3363302Sagiri 		ulong_t current_port_quota = RDS_GET_PORT_QUOTA();
3373302Sagiri 		if (rds->rds_port_quota > current_port_quota) {
3383302Sagiri 			/* this may result in stalling the port */
3393302Sagiri 			rds->rds_port_quota = current_port_quota;
3408348SEric.Yu@Sun.COM 			(void) proto_set_rx_hiwat(rds->rds_ulpd, NULL,
3413302Sagiri 			    rds->rds_port_quota * UserBufferSize);
3423302Sagiri 			RDS_INCR_PORT_QUOTA_ADJUSTED();
3433302Sagiri 		}
3443302Sagiri 	}
3453302Sagiri 
3463302Sagiri 	/*
3473302Sagiri 	 * canputnext() check is done after putnext as the protocol does
3483302Sagiri 	 * not allow dropping any received packet.
3493302Sagiri 	 */
3503302Sagiri 	if (!canputnext(rds->rds_ulpd)) {
3513302Sagiri 		error = ENOSPC;
3523302Sagiri 	}
3533302Sagiri 
3543302Sagiri 	RDS_DEC_REF_CNT(rds);
3553302Sagiri 	return (error);
3563302Sagiri }
3573302Sagiri 
3583302Sagiri 
3593302Sagiri /* Default structure copied into T_INFO_ACK messages */
3603302Sagiri static struct T_info_ack rds_g_t_info_ack_ipv4 = {
3613302Sagiri 	T_INFO_ACK,
3623302Sagiri 	65535,	/* TSDU_size. Excl. headers */
3633302Sagiri 	T_INVALID,	/* ETSU_size.  rds does not support expedited data. */
3643302Sagiri 	T_INVALID,	/* CDATA_size. rds does not support connect data. */
3653302Sagiri 	T_INVALID,	/* DDATA_size. rds does not support disconnect data. */
3663302Sagiri 	sizeof (sin_t),	/* ADDR_size. */
3673302Sagiri 	0,		/* OPT_size - not initialized here */
3683302Sagiri 	65535,		/* TIDU_size.  Excl. headers */
3693302Sagiri 	T_CLTS,		/* SERV_type.  rds supports connection-less. */
3703302Sagiri 	TS_UNBND,	/* CURRENT_state.  This is set from rds_state. */
3713302Sagiri 	(XPG4_1|SENDZERO) /* PROVIDER_flag */
3723302Sagiri };
3733302Sagiri 
3743302Sagiri static in_port_t
rds_update_next_port(in_port_t port)3753302Sagiri rds_update_next_port(in_port_t port)
3763302Sagiri {
3773302Sagiri 	(void) random_get_pseudo_bytes((uint8_t *)&port, sizeof (in_port_t));
3783302Sagiri 	if (port < rds_smallest_port)
3793302Sagiri 		port = rds_smallest_port;
3803302Sagiri 	return (port);
3813302Sagiri }
3823302Sagiri 
3833302Sagiri /* This routine creates a T_ERROR_ACK message and passes it upstream. */
3843302Sagiri static void
rds_err_ack(queue_t * q,mblk_t * mp,t_scalar_t t_error,int sys_error)3853302Sagiri rds_err_ack(queue_t *q, mblk_t *mp, t_scalar_t t_error, int sys_error)
3863302Sagiri {
3873302Sagiri 	if ((mp = mi_tpi_err_ack_alloc(mp, t_error, sys_error)) != NULL)
3883302Sagiri 		qreply(q, mp);
3893302Sagiri }
3903302Sagiri 
3913302Sagiri static void
rds_capability_req(queue_t * q,mblk_t * mp)3923302Sagiri rds_capability_req(queue_t *q, mblk_t *mp)
3933302Sagiri {
3943302Sagiri 	t_uscalar_t	cap_bits1;
3953302Sagiri 	struct T_capability_ack *tcap;
3963302Sagiri 
3973302Sagiri 	cap_bits1 =
3983302Sagiri 	    ((struct T_capability_req *)(uintptr_t)mp->b_rptr)->CAP_bits1;
3993302Sagiri 
4003302Sagiri 	mp = tpi_ack_alloc(mp, sizeof (struct T_capability_ack),
4013302Sagiri 	    mp->b_datap->db_type, T_CAPABILITY_ACK);
4023302Sagiri 	if (mp == NULL)
4033302Sagiri 		return;
4043302Sagiri 	tcap = (struct T_capability_ack *)(uintptr_t)mp->b_rptr;
4053302Sagiri 	tcap->CAP_bits1 = 0;
4063302Sagiri 
4073302Sagiri 	if (cap_bits1 & TC1_INFO) {
4083302Sagiri 		tcap->CAP_bits1 |= TC1_INFO;
4093302Sagiri 		*(&tcap->INFO_ack) = rds_g_t_info_ack_ipv4;
4103302Sagiri 	}
4113302Sagiri 
4123302Sagiri 	qreply(q, mp);
4133302Sagiri }
4143302Sagiri 
4153302Sagiri static void
rds_info_req(queue_t * q,mblk_t * omp)4163302Sagiri rds_info_req(queue_t *q, mblk_t *omp)
4173302Sagiri {
4183302Sagiri 	rds_t *rds = (rds_t *)q->q_ptr;
4193302Sagiri 	struct T_info_ack *tap;
4203302Sagiri 	mblk_t *mp;
4213302Sagiri 
4223302Sagiri 	/* Create a T_INFO_ACK message. */
4233302Sagiri 	mp = tpi_ack_alloc(omp, sizeof (struct T_info_ack), M_PCPROTO,
4243302Sagiri 	    T_INFO_ACK);
4253302Sagiri 	if (mp == NULL)
4263302Sagiri 		return;
4273302Sagiri 	tap = (struct T_info_ack *)(uintptr_t)mp->b_rptr;
4283302Sagiri 	*tap = rds_g_t_info_ack_ipv4;
4293302Sagiri 	tap->CURRENT_state = rds->rds_state;
4303302Sagiri 	tap->OPT_size = 128;
4313302Sagiri 	qreply(q, mp);
4323302Sagiri }
4333302Sagiri 
4343302Sagiri /*
4353302Sagiri  * NO locking protection here as sockfs will only send down
4363302Sagiri  * one bind operation at a time.
4373302Sagiri  */
4383302Sagiri static void
rds_bind(queue_t * q,mblk_t * mp)4393302Sagiri rds_bind(queue_t *q, mblk_t *mp)
4403302Sagiri {
4413302Sagiri 	sin_t		*sin;
4423302Sagiri 	rds_t *rds;
4433302Sagiri 	struct T_bind_req *tbr;
4443302Sagiri 	in_port_t	port;	/* Host byte order */
4453302Sagiri 	in_port_t	requested_port; /* Host byte order */
4463302Sagiri 	struct T_bind_ack *tba;
4473302Sagiri 	int		count;
4483302Sagiri 	rds_bf_t	*rdsbf;
4493302Sagiri 	in_port_t	lport;	/* Network byte order */
4503302Sagiri 
4513302Sagiri 	rds = (rds_t *)q->q_ptr;
4523302Sagiri 	if (((uintptr_t)mp->b_wptr - (uintptr_t)mp->b_rptr) < sizeof (*tbr)) {
4533302Sagiri 		rds_err_ack(q, mp, TPROTO, 0);
4543302Sagiri 		return;
4553302Sagiri 	}
4563302Sagiri 
4573302Sagiri 	/*
4583302Sagiri 	 * We don't allow multiple binds
4593302Sagiri 	 */
4603302Sagiri 	if (rds->rds_state != TS_UNBND) {
4613302Sagiri 		rds_err_ack(q, mp, TOUTSTATE, 0);
4623302Sagiri 		return;
4633302Sagiri 	}
4643302Sagiri 
4653302Sagiri 	tbr = (struct T_bind_req *)(uintptr_t)mp->b_rptr;
4663302Sagiri 	switch (tbr->ADDR_length) {
4673302Sagiri 	case sizeof (sin_t):    /* Complete IPv4 address */
4683302Sagiri 		sin = (sin_t *)(uintptr_t)mi_offset_param(mp, tbr->ADDR_offset,
4693302Sagiri 		    sizeof (sin_t));
4703302Sagiri 		if (sin == NULL || !OK_32PTR((char *)sin)) {
4713302Sagiri 			rds_err_ack(q, mp, TSYSERR, EINVAL);
4723302Sagiri 			return;
4733302Sagiri 		}
4743302Sagiri 		if (rds->rds_family != AF_INET_OFFLOAD ||
4753302Sagiri 		    sin->sin_family != AF_INET_OFFLOAD) {
4763302Sagiri 			rds_err_ack(q, mp, TSYSERR, EAFNOSUPPORT);
4773302Sagiri 			return;
4783302Sagiri 		}
4793302Sagiri 		if (sin->sin_addr.s_addr == INADDR_ANY) {
4803302Sagiri 			rds_err_ack(q, mp, TBADADDR, 0);
4813302Sagiri 			return;
4823302Sagiri 		}
4833302Sagiri 
4843302Sagiri 		/*
4853302Sagiri 		 * verify that the address is hosted on IB
4863302Sagiri 		 * only exception is the loopback address.
4873302Sagiri 		 */
4883302Sagiri 		if ((sin->sin_addr.s_addr != INADDR_LOOPBACK) &&
4893302Sagiri 		    !rds_verify_bind_address(sin->sin_addr.s_addr)) {
4903302Sagiri 			rds_err_ack(q, mp, TBADADDR, 0);
4913302Sagiri 			return;
4923302Sagiri 		}
4933302Sagiri 
4943302Sagiri 		port = ntohs(sin->sin_port);
4953302Sagiri 		break;
4963302Sagiri 	default:	/* Invalid request */
4973302Sagiri 		rds_err_ack(q, mp, TBADADDR, 0);
4983302Sagiri 		return;
4993302Sagiri 	}
5003302Sagiri 
5013302Sagiri 	requested_port = port;
5023302Sagiri 
5033302Sagiri 	/*
5043302Sagiri 	 * TPI only sends down T_BIND_REQ for AF_INET and AF_INET6
5053302Sagiri 	 * since RDS socket is of type AF_INET_OFFLOAD a O_T_BIND_REQ
5063302Sagiri 	 * will be sent down. Treat O_T_BIND_REQ as T_BIND_REQ
5073302Sagiri 	 */
5083302Sagiri 
5093302Sagiri 	if (requested_port == 0) {
5103302Sagiri 		/*
5113302Sagiri 		 * If the application passed in zero for the port number, it
5123302Sagiri 		 * doesn't care which port number we bind to. Get one in the
5133302Sagiri 		 * valid range.
5143302Sagiri 		 */
5153302Sagiri 		port = rds_update_next_port(rds_next_port_to_try);
5163302Sagiri 	}
5173302Sagiri 
5183302Sagiri 	ASSERT(port != 0);
5193302Sagiri 	count = 0;
5203302Sagiri 	for (;;) {
5213302Sagiri 		rds_t		*rds1;
5223302Sagiri 		ASSERT(sin->sin_addr.s_addr != INADDR_ANY);
5233302Sagiri 		/*
5243302Sagiri 		 * Walk through the list of rds streams bound to
5253302Sagiri 		 * requested port with the same IP address.
5263302Sagiri 		 */
5273302Sagiri 		lport = htons(port);
5283302Sagiri 		rdsbf = &rds_bind_fanout[RDS_BIND_HASH(lport)];
5293302Sagiri 		mutex_enter(&rdsbf->rds_bf_lock);
5303302Sagiri 		for (rds1 = rdsbf->rds_bf_rds; rds1 != NULL;
5313302Sagiri 		    rds1 = rds1->rds_bind_hash) {
5323302Sagiri 			if (lport != rds1->rds_port ||
5333302Sagiri 			    rds1->rds_src != sin->sin_addr.s_addr ||
5343302Sagiri 			    rds1->rds_zoneid != rds->rds_zoneid)
5353302Sagiri 
5363302Sagiri 				continue;
5373302Sagiri 			break;
5383302Sagiri 		}
5393302Sagiri 
5403302Sagiri 		if (rds1 == NULL) {
5413302Sagiri 			/*
5423302Sagiri 			 * No other stream has this IP address
5433302Sagiri 			 * and port number. We can use it.
5443302Sagiri 			 */
5453302Sagiri 			break;
5463302Sagiri 		}
5473302Sagiri 		mutex_exit(&rdsbf->rds_bf_lock);
5483302Sagiri 		if (requested_port != 0) {
5493302Sagiri 			/*
5503302Sagiri 			 * We get here only when requested port
5513302Sagiri 			 * is bound (and only first  of the for()
5523302Sagiri 			 * loop iteration).
5533302Sagiri 			 *
5543302Sagiri 			 * The semantics of this bind request
5553302Sagiri 			 * require it to fail so we return from
5563302Sagiri 			 * the routine (and exit the loop).
5573302Sagiri 			 *
5583302Sagiri 			 */
5593302Sagiri 			rds_err_ack(q, mp, TADDRBUSY, 0);
5603302Sagiri 			return;
5613302Sagiri 		}
5623302Sagiri 
5633302Sagiri 		port = rds_update_next_port(port + 1);
5643302Sagiri 
5653302Sagiri 		if (++count >= loopmax) {
5663302Sagiri 			/*
5673302Sagiri 			 * We've tried every possible port number and
5683302Sagiri 			 * there are none available, so send an error
5693302Sagiri 			 * to the user.
5703302Sagiri 			 */
5713302Sagiri 			rds_err_ack(q, mp, TNOADDR, 0);
5723302Sagiri 			return;
5733302Sagiri 		}
5743302Sagiri 	}
5753302Sagiri 
5763302Sagiri 	/*
5773302Sagiri 	 * Copy the source address into our rds structure.
5783302Sagiri 	 */
5793302Sagiri 	rds->rds_src = sin->sin_addr.s_addr;
5803302Sagiri 	rds->rds_port = lport;
5813302Sagiri 
5823302Sagiri 	/*
5833302Sagiri 	 * reset the next port if we choose the port
5843302Sagiri 	 */
5853302Sagiri 	if (requested_port == 0) {
5863302Sagiri 		rds_next_port_to_try = port + 1;
5873302Sagiri 	}
5883302Sagiri 
5893302Sagiri 	rds->rds_state = TS_IDLE;
5903302Sagiri 	rds_bind_hash_insert(rdsbf, rds);
5913302Sagiri 	mutex_exit(&rdsbf->rds_bf_lock);
5923302Sagiri 
5933302Sagiri 	/* Reset the message type in preparation for shipping it back. */
5943302Sagiri 	mp->b_datap->db_type = M_PCPROTO;
5953302Sagiri 	tba = (struct T_bind_ack *)(uintptr_t)mp->b_rptr;
5963302Sagiri 	tba->PRIM_type = T_BIND_ACK;
5973302Sagiri 
5983302Sagiri 	/* Increment the number of ports and set the port quota */
5993302Sagiri 	RDS_INCR_NPORT();
6003302Sagiri 	rds->rds_port_quota = RDS_CURRENT_PORT_QUOTA();
6013302Sagiri 	RDS_SET_PORT_QUOTA(rds->rds_port_quota);
6028348SEric.Yu@Sun.COM 	(void) proto_set_rx_hiwat(RD(q), NULL,
6038348SEric.Yu@Sun.COM 	    rds->rds_port_quota * UserBufferSize);
6043302Sagiri 
6053302Sagiri 	qreply(q, mp);
6063302Sagiri }
6073302Sagiri 
6083302Sagiri static void
rds_wput_other(queue_t * q,mblk_t * mp)6093302Sagiri rds_wput_other(queue_t *q, mblk_t *mp)
6103302Sagiri {
6113302Sagiri 	uchar_t *rptr = mp->b_rptr;
6123302Sagiri 	struct datab *db;
6133302Sagiri 	cred_t *cr;
6143302Sagiri 
6153302Sagiri 	db = mp->b_datap;
6163302Sagiri 	switch (db->db_type) {
6173302Sagiri 	case M_DATA:
6183302Sagiri 		/* Not connected */
6193302Sagiri 		freemsg(mp);
6203302Sagiri 		return;
6213302Sagiri 	case M_PROTO:
6223302Sagiri 	case M_PCPROTO:
6233302Sagiri 		if ((uintptr_t)mp->b_wptr - (uintptr_t)rptr <
6243302Sagiri 		    sizeof (t_scalar_t)) {
6253302Sagiri 			freemsg(mp);
6263302Sagiri 			return;
6273302Sagiri 		}
6283302Sagiri 		switch (((union T_primitives *)(uintptr_t)rptr)->type) {
6293302Sagiri 		case T_CAPABILITY_REQ:
6303302Sagiri 			rds_capability_req(q, mp);
6313302Sagiri 			return;
6323302Sagiri 
6333302Sagiri 		case T_INFO_REQ:
6343302Sagiri 			rds_info_req(q, mp);
6353302Sagiri 			return;
6363302Sagiri 		case O_T_BIND_REQ:
6373302Sagiri 		case T_BIND_REQ:
6383302Sagiri 			rds_bind(q, mp);
6393302Sagiri 			return;
6403302Sagiri 		case T_SVR4_OPTMGMT_REQ:
6413302Sagiri 		case T_OPTMGMT_REQ:
6428778SErik.Nordmark@Sun.COM 			/*
6438778SErik.Nordmark@Sun.COM 			 * All Solaris components should pass a db_credp
6448778SErik.Nordmark@Sun.COM 			 * for this TPI message, hence we ASSERT.
6458778SErik.Nordmark@Sun.COM 			 * But in case there is some other M_PROTO that looks
6468778SErik.Nordmark@Sun.COM 			 * like a TPI message sent by some other kernel
6478778SErik.Nordmark@Sun.COM 			 * component, we check and return an error.
6488778SErik.Nordmark@Sun.COM 			 */
6498778SErik.Nordmark@Sun.COM 			cr = msg_getcred(mp, NULL);
6508778SErik.Nordmark@Sun.COM 			ASSERT(cr != NULL);
6518778SErik.Nordmark@Sun.COM 			if (cr == NULL) {
6528778SErik.Nordmark@Sun.COM 				rds_err_ack(q, mp, TSYSERR, EINVAL);
6538778SErik.Nordmark@Sun.COM 				return;
6548778SErik.Nordmark@Sun.COM 			}
6558778SErik.Nordmark@Sun.COM 			if (((union T_primitives *)(uintptr_t)rptr)->type ==
6568778SErik.Nordmark@Sun.COM 			    T_SVR4_OPTMGMT_REQ) {
657*11042SErik.Nordmark@Sun.COM 				svr4_optcom_req(q, mp, cr, &rds_opt_obj);
6588778SErik.Nordmark@Sun.COM 			} else {
659*11042SErik.Nordmark@Sun.COM 				tpi_optcom_req(q, mp, cr, &rds_opt_obj);
6608778SErik.Nordmark@Sun.COM 			}
6613302Sagiri 			return;
6623302Sagiri 		case T_CONN_REQ:
6633302Sagiri 			/*
6643302Sagiri 			 * We should not receive T_CONN_REQ as sockfs only
6653302Sagiri 			 * sends down T_CONN_REQ if family == AF_INET/AF_INET6
6663302Sagiri 			 * and type == SOCK_DGRAM/SOCK_RAW. For all others
6673302Sagiri 			 * it simply calls soisconnected. see sotpi_connect()
6683302Sagiri 			 * for details.
6693302Sagiri 			 */
6703302Sagiri 		/* FALLTHRU */
6713302Sagiri 		default:
6723302Sagiri 			cmn_err(CE_PANIC, "type %d \n",
6733302Sagiri 			    ((union T_primitives *)(uintptr_t)rptr)->type);
6743302Sagiri 		}
6753302Sagiri 		break;
6763302Sagiri 	case M_FLUSH:
6773302Sagiri 		if (*rptr & FLUSHW)
6783302Sagiri 			flushq(q, FLUSHDATA);
6793302Sagiri 		break;
6803302Sagiri 	case M_IOCTL:
6813302Sagiri 		rds_ioctl(q, mp);
6823302Sagiri 		break;
6833302Sagiri 	case M_IOCDATA:
6843302Sagiri 		/* IOCTL continuation following copyin or copyout. */
6853302Sagiri 		if (mi_copy_state(q, mp, NULL) == -1) {
6863302Sagiri 			/*
6873302Sagiri 			 * The copy operation failed.  mi_copy_state already
6883302Sagiri 			 * cleaned up, so we're out of here.
6893302Sagiri 			 */
6903302Sagiri 			return;
6913302Sagiri 		}
6923302Sagiri 		/*
6933302Sagiri 		 * If we just completed a copy in, continue processing
6943302Sagiri 		 * in rds_ioctl_copyin_done. If it was a copy out, we call
6953302Sagiri 		 * mi_copyout again.  If there is nothing more to copy out,
6963302Sagiri 		 * it will complete the IOCTL.
6973302Sagiri 		 */
6983302Sagiri 
6993302Sagiri 		if (MI_COPY_DIRECTION(mp) == MI_COPY_IN)
7003302Sagiri 			rds_ioctl_copyin_done(q, mp);
7013302Sagiri 		else
7023302Sagiri 			mi_copyout(q, mp);
7033302Sagiri 		return;
7043302Sagiri 
7053302Sagiri 	default:
7063302Sagiri 		cmn_err(CE_PANIC, "types %d \n", db->db_type);
7073302Sagiri 	}
7083302Sagiri }
7093302Sagiri 
7103302Sagiri static int
rds_wput(queue_t * q,mblk_t * mp)7113302Sagiri rds_wput(queue_t *q, mblk_t *mp)
7123302Sagiri {
7133302Sagiri 	struct	datab	*db;
7143302Sagiri 	uchar_t	*rptr = mp->b_rptr;
7153302Sagiri 
7163302Sagiri 	db = mp->b_datap;
7173302Sagiri 	switch (db->db_type) {
7183302Sagiri 	case M_PROTO:
7193302Sagiri 	case M_PCPROTO:
7203302Sagiri 		ASSERT(((uintptr_t)mp->b_wptr - (uintptr_t)rptr) <=
7213302Sagiri 		    (uintptr_t)INT_MAX);
7223302Sagiri 		if ((uintptr_t)mp->b_wptr - (uintptr_t)rptr >=
7233302Sagiri 		    sizeof (struct T_unitdata_req)) {
7243302Sagiri 			if (((union T_primitives *)(uintptr_t)rptr)->type
7253302Sagiri 			    == T_UNITDATA_REQ) {
7263302Sagiri 				/*
7273302Sagiri 				 *  We should never come here for T_UNITDATA_REQ
7283302Sagiri 				 */
7293302Sagiri 				cmn_err(CE_PANIC, "rds_wput T_UNITDATA_REQ \n");
7303302Sagiri 			}
7313302Sagiri 		}
7323302Sagiri 		/* FALLTHRU */
7333302Sagiri 	default:
7343302Sagiri 		rds_wput_other(q, mp);
7353302Sagiri 		return (0);
7363302Sagiri 	}
7373302Sagiri }
7383302Sagiri 
7393302Sagiri static int
rds_wput_data(queue_t * q,mblk_t * mp,uio_t * uiop)7403302Sagiri rds_wput_data(queue_t *q, mblk_t *mp, uio_t *uiop)
7413302Sagiri {
7423302Sagiri 	uchar_t	*rptr = mp->b_rptr;
7433302Sagiri 	rds_t	*rds;
7443302Sagiri 	mblk_t	*mp1;
7453302Sagiri 	sin_t	*sin;
7463302Sagiri 	ipaddr_t dst;
7473302Sagiri 	uint16_t port;
7483302Sagiri 	int ret = 0;
7493302Sagiri 
7503302Sagiri #define	tudr	((struct T_unitdata_req *)(uintptr_t)rptr)
7513302Sagiri 
7523302Sagiri 	rds = (rds_t *)q->q_ptr;
7533302Sagiri 	/* Handle UNITDATA_REQ messages here */
7543302Sagiri 	if (rds->rds_state == TS_UNBND) {
7553302Sagiri 		/* If a port has not been bound to the stream, fail. */
7563302Sagiri 		dprint(2, ("%s: socket is not bound to a port", LABEL));
7573302Sagiri 		freemsg(mp);
7583302Sagiri 		return (EPROTO);
7593302Sagiri 	}
7603302Sagiri 
7613302Sagiri 	mp1 = mp->b_cont;
7623302Sagiri 	mp->b_cont = NULL;
7633302Sagiri 	if (mp1 == NULL) {
7643302Sagiri 		dprint(2, ("%s: No message to send", LABEL));
7653302Sagiri 		freemsg(mp);
7663302Sagiri 		return (EPROTO);
7673302Sagiri 	}
7683302Sagiri 
7693302Sagiri 	/*
7703302Sagiri 	 * No options allowed
7713302Sagiri 	 */
7723302Sagiri 	if (tudr->OPT_length != 0) {
7733302Sagiri 		ret = EINVAL;
7743302Sagiri 		goto done;
7753302Sagiri 	}
7763302Sagiri 
7773302Sagiri 	ASSERT(mp1->b_datap->db_ref == 1);
7783302Sagiri 
7793302Sagiri 	if ((rptr + tudr->DEST_offset + tudr->DEST_length) >
7803302Sagiri 	    mp->b_wptr) {
7813302Sagiri 		ret = EDESTADDRREQ;
7823302Sagiri 		goto done;
7833302Sagiri 	}
7843302Sagiri 
7853302Sagiri 	sin = (sin_t *)(uintptr_t)&rptr[tudr->DEST_offset];
7863302Sagiri 	if (!OK_32PTR((char *)sin) || tudr->DEST_length !=
7873302Sagiri 	    sizeof (sin_t) || sin->sin_family != AF_INET_OFFLOAD) {
7883302Sagiri 		ret = EDESTADDRREQ;
7893302Sagiri 		goto done;
7903302Sagiri 	}
7913302Sagiri 	/* Extract port and ipaddr */
7923302Sagiri 	port = sin->sin_port;
7933302Sagiri 	dst = sin->sin_addr.s_addr;
7943302Sagiri 
7953302Sagiri 	if (port == 0 || dst == INADDR_ANY) {
7963302Sagiri 		ret = EDESTADDRREQ;
7973302Sagiri 		goto done;
7983302Sagiri 	}
7993302Sagiri 
8003302Sagiri 	ASSERT(rds_transport_ops != NULL);
8013302Sagiri 	ret = rds_transport_ops->rds_transport_sendmsg(uiop, rds->rds_src, dst,
8023302Sagiri 	    ntohs(rds->rds_port), ntohs(port), rds->rds_zoneid);
8033302Sagiri 	if (ret != 0) {
8043302Sagiri 		if ((ret != ENOBUFS) && (ret != ENOMEM)) {
8053302Sagiri 			/* ENOMEM is actually EWOULDBLOCK */
8063302Sagiri 			dprint(2, ("%s: rds_sendmsg returned %d", LABEL, ret));
8073302Sagiri 			goto done;
8083302Sagiri 		}
8093302Sagiri 	}
8103302Sagiri done:
8113302Sagiri 	freemsg(mp1);
8123302Sagiri 	freemsg(mp);
8133302Sagiri 	return (ret);
8143302Sagiri }
8153302Sagiri 
8163302Sagiri /*
8173302Sagiri  * Make sure we dont return EINVAL and EWOULDBLOCK as it has
8183302Sagiri  * special meanings for the synchronous streams (rwnext()).
8193302Sagiri  * We should return ENOMEM which is changed to EWOULDBLOCK by kstrputmsg()
8203302Sagiri  */
8213302Sagiri static int
rds_wrw(queue_t * q,struiod_t * dp)8223302Sagiri rds_wrw(queue_t *q, struiod_t *dp)
8233302Sagiri {
8243302Sagiri 	mblk_t  *mp = dp->d_mp;
8253302Sagiri 	int error = 0;
8263302Sagiri 	struct  datab   *db;
8273302Sagiri 	uchar_t *rptr;
8283302Sagiri 
8293302Sagiri 	db = mp->b_datap;
8303302Sagiri 	rptr = mp->b_rptr;
8313302Sagiri 	switch (db->db_type) {
8323302Sagiri 	case M_PROTO:
8333302Sagiri 	case M_PCPROTO:
8343302Sagiri 		ASSERT(((uintptr_t)mp->b_wptr - (uintptr_t)rptr) <=
8353302Sagiri 		    (uintptr_t)INT_MAX);
8363302Sagiri 		if ((uintptr_t)mp->b_wptr - (uintptr_t)rptr >=
8373302Sagiri 		    sizeof (struct T_unitdata_req)) {
8383302Sagiri 			/* Detect valid T_UNITDATA_REQ here */
8393302Sagiri 			if (((union T_primitives *)(uintptr_t)rptr)->type
8403302Sagiri 			    == T_UNITDATA_REQ)
8413302Sagiri 			break;
8423302Sagiri 		}
8433302Sagiri 		/* FALLTHRU */
8443302Sagiri 	default:
8453302Sagiri 
8463302Sagiri 		if (isuioq(q) && (error = struioget(q, mp, dp, 0))) {
8473302Sagiri 		/*
8483302Sagiri 		 * Uio error of some sort, so just return the error.
8493302Sagiri 		 */
8503302Sagiri 			goto done;
8513302Sagiri 		}
8523302Sagiri 		dp->d_mp = 0;
8533302Sagiri 		rds_wput_other(q, mp);
8543302Sagiri 		return (0);
8553302Sagiri 	}
8563302Sagiri 
8573302Sagiri 	dp->d_mp = 0;
8583302Sagiri 	error = rds_wput_data(q, mp, &dp->d_uio);
8593302Sagiri done:
8603302Sagiri 	if (error == EWOULDBLOCK || error == EINVAL)
8613302Sagiri 		error = EIO;
8623302Sagiri 
8633302Sagiri 	return (error);
8643302Sagiri }
8653302Sagiri 
8663302Sagiri static void
rds_rsrv(queue_t * q)8673302Sagiri rds_rsrv(queue_t *q)
8683302Sagiri {
8693302Sagiri 	rds_t	*rds = (rds_t *)q->q_ptr;
8703302Sagiri 	ulong_t current_port_quota;
8713302Sagiri 
8723302Sagiri 	/* update the port quota to the current level */
8733302Sagiri 	current_port_quota = RDS_GET_PORT_QUOTA();
8743302Sagiri 	if (rds->rds_port_quota != current_port_quota) {
8753302Sagiri 		rds->rds_port_quota = current_port_quota;
8768348SEric.Yu@Sun.COM 		(void) proto_set_rx_hiwat(q, NULL,
8773302Sagiri 		    rds->rds_port_quota * UserBufferSize);
8783302Sagiri 	}
8793302Sagiri 
8803302Sagiri 	/* No more messages in the q, unstall the socket */
8813302Sagiri 	rds_transport_ops->rds_transport_resume_port(ntohs(rds->rds_port));
8823302Sagiri }
8833302Sagiri 
8843302Sagiri int
rds_close_transport_driver()8853302Sagiri rds_close_transport_driver()
8863302Sagiri {
8873302Sagiri 	ASSERT(rds_transport_ops != NULL);
8883302Sagiri 
8893302Sagiri 	rw_enter(&rds_transport_lock, RW_WRITER);
8903302Sagiri 	if (rds_transport_handle != NULL) {
8913302Sagiri 		rds_transport_ops->rds_transport_close_ib();
8923302Sagiri 		(void) ldi_close(rds_transport_handle, FNDELAY, kcred);
8933302Sagiri 		rds_transport_handle = NULL;
8943302Sagiri 	}
8953302Sagiri 	rw_exit(&rds_transport_lock);
8963302Sagiri 
8973302Sagiri 	return (0);
8983302Sagiri }
8993302Sagiri 
9003302Sagiri 
9013302Sagiri int
rds_open_transport_driver()9023302Sagiri rds_open_transport_driver()
9033302Sagiri {
9043302Sagiri 	int ret = 0;
9053302Sagiri 
9063302Sagiri 	rw_enter(&rds_transport_lock, RW_WRITER);
9073302Sagiri 	if (rds_transport_handle != NULL) {
9083302Sagiri 		/*
9093302Sagiri 		 * Someone beat us to it.
9103302Sagiri 		 */
9113302Sagiri 		goto done;
9123302Sagiri 	}
9133302Sagiri 
9143302Sagiri 	if (ibt_hw_is_present() == 0) {
9153302Sagiri 		ret = ENODEV;
9163302Sagiri 		goto done;
9173302Sagiri 	}
9183302Sagiri 
9193302Sagiri 	if (rds_li == NULL) {
9203302Sagiri 		ret = EPROTONOSUPPORT;
9213302Sagiri 		goto done;
9223302Sagiri 	}
9233302Sagiri 
9243302Sagiri 	ret = ldi_open_by_name("/devices/ib/rdsib@0:rdsib",
9253302Sagiri 	    FREAD | FWRITE, kcred, &rds_transport_handle, rds_li);
9263302Sagiri 	if (ret != 0) {
9273302Sagiri 		ret = EPROTONOSUPPORT;
9283302Sagiri 		rds_transport_handle = NULL;
9293302Sagiri 		goto done;
9303302Sagiri 	}
9313302Sagiri 
9323302Sagiri 	ret = rds_transport_ops->rds_transport_open_ib();
9333302Sagiri 	if (ret != 0) {
9343302Sagiri 		(void) ldi_close(rds_transport_handle, FNDELAY, kcred);
9353302Sagiri 		rds_transport_handle = NULL;
9363302Sagiri 	}
9373302Sagiri done:
9383302Sagiri 	rw_exit(&rds_transport_lock);
9393302Sagiri 	return (ret);
9403302Sagiri }
9413302Sagiri 
9423302Sagiri static struct module_info info = {
9433302Sagiri 	0, "rds", 1, INFPSZ, 65536, 1024
9443302Sagiri };
9453302Sagiri 
9463302Sagiri static struct qinit rinit = {
9473302Sagiri 	NULL, (pfi_t)rds_rsrv, rds_open, rds_close, NULL, &info
9483302Sagiri };
9493302Sagiri 
9503302Sagiri static struct qinit winit = {
9513302Sagiri 	(pfi_t)rds_wput, NULL, rds_open, rds_close, NULL, &info,
9523302Sagiri 	NULL, rds_wrw, NULL, STRUIOT_STANDARD
9533302Sagiri };
9543302Sagiri 
9553302Sagiri struct streamtab rdsinfo = {
9563302Sagiri 	&rinit, &winit, NULL, NULL
9573302Sagiri };
9583302Sagiri 
9593302Sagiri DDI_DEFINE_STREAM_OPS(rds_devops, nulldev, nulldev, rds_attach, rds_detach,
9607656SSherry.Moore@Sun.COM     nulldev, rds_info, RDS_DEVMTFLAGS, &RDS_STRTAB, ddi_quiesce_not_supported);
9613302Sagiri 
9623302Sagiri /*
9633302Sagiri  * Module linkage information for the kernel.
9643302Sagiri  */
9653302Sagiri static struct modldrv modldrv = {
9663302Sagiri 	&mod_driverops,
9673302Sagiri 	RDS_DEVDESC,
9683302Sagiri 	&rds_devops
9693302Sagiri };
9703302Sagiri 
9713302Sagiri static struct modlinkage modlinkage = {
9723302Sagiri 	MODREV_1,
9733302Sagiri 	&modldrv,
9743302Sagiri 	NULL
9753302Sagiri };
9763302Sagiri 
9773302Sagiri int
_init(void)9783302Sagiri _init(void)
9793302Sagiri {
9803302Sagiri 	int	ret;
9813302Sagiri 
9823302Sagiri 	rds_init();
9833302Sagiri 
9843302Sagiri 	ret = mod_install(&modlinkage);
9853302Sagiri 	if (ret != 0)
9863302Sagiri 		goto done;
9873302Sagiri 	ret = ldi_ident_from_mod(&modlinkage, &rds_li);
9883302Sagiri 	if (ret != 0)
9893302Sagiri 		rds_li = NULL;
9903302Sagiri done:
9913302Sagiri 	return (ret);
9923302Sagiri }
9933302Sagiri 
9943302Sagiri int
_fini(void)9953302Sagiri _fini(void)
9963302Sagiri {
9973302Sagiri 	int	ret;
9983302Sagiri 
9993302Sagiri 	ret = mod_remove(&modlinkage);
10003302Sagiri 	if (ret != 0) {
10013302Sagiri 		return (ret);
10023302Sagiri 	}
10033302Sagiri 
10043302Sagiri 	rds_fini();
10053302Sagiri 
10063302Sagiri 	ldi_ident_release(rds_li);
10073302Sagiri 	return (0);
10083302Sagiri }
10093302Sagiri 
10103302Sagiri int
_info(struct modinfo * modinfop)10113302Sagiri _info(struct modinfo *modinfop)
10123302Sagiri {
10133302Sagiri 	return (mod_info(&modlinkage, modinfop));
10143302Sagiri }
1015