xref: /titanic_52/usr/src/uts/common/io/softmac/softmac_capab.c (revision d62bc4badc1c1f1549c961cfb8b420e650e1272b)
1*d62bc4baSyz147064 /*
2*d62bc4baSyz147064  * CDDL HEADER START
3*d62bc4baSyz147064  *
4*d62bc4baSyz147064  * The contents of this file are subject to the terms of the
5*d62bc4baSyz147064  * Common Development and Distribution License (the "License").
6*d62bc4baSyz147064  * You may not use this file except in compliance with the License.
7*d62bc4baSyz147064  *
8*d62bc4baSyz147064  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*d62bc4baSyz147064  * or http://www.opensolaris.org/os/licensing.
10*d62bc4baSyz147064  * See the License for the specific language governing permissions
11*d62bc4baSyz147064  * and limitations under the License.
12*d62bc4baSyz147064  *
13*d62bc4baSyz147064  * When distributing Covered Code, include this CDDL HEADER in each
14*d62bc4baSyz147064  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*d62bc4baSyz147064  * If applicable, add the following below this CDDL HEADER, with the
16*d62bc4baSyz147064  * fields enclosed by brackets "[]" replaced with your own identifying
17*d62bc4baSyz147064  * information: Portions Copyright [yyyy] [name of copyright owner]
18*d62bc4baSyz147064  *
19*d62bc4baSyz147064  * CDDL HEADER END
20*d62bc4baSyz147064  */
21*d62bc4baSyz147064 /*
22*d62bc4baSyz147064  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23*d62bc4baSyz147064  * Use is subject to license terms.
24*d62bc4baSyz147064  */
25*d62bc4baSyz147064 
26*d62bc4baSyz147064 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27*d62bc4baSyz147064 
28*d62bc4baSyz147064 #include <sys/types.h>
29*d62bc4baSyz147064 #include <sys/mac.h>
30*d62bc4baSyz147064 #include <sys/softmac_impl.h>
31*d62bc4baSyz147064 
32*d62bc4baSyz147064 typedef struct softmac_capab_ops {
33*d62bc4baSyz147064 	int	(*sc_hcksum_ack)(void *, t_uscalar_t);
34*d62bc4baSyz147064 	int	(*sc_zcopy_ack)(void *, t_uscalar_t);
35*d62bc4baSyz147064 	int	(*sc_mdt_ack)(void *, dl_capab_mdt_t *);
36*d62bc4baSyz147064 } softmac_capab_ops_t;
37*d62bc4baSyz147064 
38*d62bc4baSyz147064 static int	dl_capab(ldi_handle_t, mblk_t **);
39*d62bc4baSyz147064 static int	softmac_fill_hcksum_ack(void *, t_uscalar_t);
40*d62bc4baSyz147064 static int	softmac_fill_zcopy_ack(void *, t_uscalar_t);
41*d62bc4baSyz147064 static int	softmac_fill_mdt_ack(void *, dl_capab_mdt_t *);
42*d62bc4baSyz147064 static int	softmac_adv_hcksum_ack(void *, t_uscalar_t);
43*d62bc4baSyz147064 static int	softmac_adv_zcopy_ack(void *, t_uscalar_t);
44*d62bc4baSyz147064 static int	softmac_adv_mdt_ack(void *, dl_capab_mdt_t *);
45*d62bc4baSyz147064 static int	softmac_enable_hcksum_ack(void *, t_uscalar_t);
46*d62bc4baSyz147064 static int	softmac_enable_mdt_ack(void *, dl_capab_mdt_t *);
47*d62bc4baSyz147064 static int	softmac_capab_send(softmac_lower_t *, boolean_t);
48*d62bc4baSyz147064 static int	i_capab_ack(mblk_t *, queue_t *, softmac_capab_ops_t *, void *);
49*d62bc4baSyz147064 static int	i_capab_id_ack(mblk_t *, dl_capability_sub_t *, queue_t *,
50*d62bc4baSyz147064     softmac_capab_ops_t *, void *);
51*d62bc4baSyz147064 static int	i_capab_sub_ack(mblk_t *, dl_capability_sub_t *, queue_t *,
52*d62bc4baSyz147064     softmac_capab_ops_t *, void *);
53*d62bc4baSyz147064 static int	i_capab_hcksum_ack(dl_capab_hcksum_t *, queue_t *,
54*d62bc4baSyz147064     softmac_capab_ops_t *, void *);
55*d62bc4baSyz147064 static int	i_capab_zcopy_ack(dl_capab_zerocopy_t *, queue_t *,
56*d62bc4baSyz147064     softmac_capab_ops_t *, void *);
57*d62bc4baSyz147064 static int	i_capab_mdt_ack(dl_capab_mdt_t *, queue_t *,
58*d62bc4baSyz147064     softmac_capab_ops_t *, void *);
59*d62bc4baSyz147064 static int	i_capab_hcksum_verify(dl_capab_hcksum_t *, queue_t *);
60*d62bc4baSyz147064 static int	i_capab_zcopy_verify(dl_capab_zerocopy_t *, queue_t *);
61*d62bc4baSyz147064 static int	i_capab_mdt_verify(dl_capab_mdt_t *, queue_t *);
62*d62bc4baSyz147064 
63*d62bc4baSyz147064 static softmac_capab_ops_t softmac_fill_capab_ops =
64*d62bc4baSyz147064 {
65*d62bc4baSyz147064 	softmac_fill_hcksum_ack,
66*d62bc4baSyz147064 	softmac_fill_zcopy_ack,
67*d62bc4baSyz147064 	softmac_fill_mdt_ack,
68*d62bc4baSyz147064 };
69*d62bc4baSyz147064 
70*d62bc4baSyz147064 static softmac_capab_ops_t softmac_adv_capab_ops =
71*d62bc4baSyz147064 {
72*d62bc4baSyz147064 	softmac_adv_hcksum_ack,
73*d62bc4baSyz147064 	softmac_adv_zcopy_ack,
74*d62bc4baSyz147064 	softmac_adv_mdt_ack
75*d62bc4baSyz147064 };
76*d62bc4baSyz147064 
77*d62bc4baSyz147064 static softmac_capab_ops_t softmac_enable_capab_ops =
78*d62bc4baSyz147064 {
79*d62bc4baSyz147064 	softmac_enable_hcksum_ack,
80*d62bc4baSyz147064 	NULL,
81*d62bc4baSyz147064 	softmac_enable_mdt_ack
82*d62bc4baSyz147064 };
83*d62bc4baSyz147064 
84*d62bc4baSyz147064 int
85*d62bc4baSyz147064 softmac_fill_capab(ldi_handle_t lh, softmac_t *softmac)
86*d62bc4baSyz147064 {
87*d62bc4baSyz147064 	mblk_t			*mp = NULL;
88*d62bc4baSyz147064 	union DL_primitives	*prim;
89*d62bc4baSyz147064 	int			err = 0;
90*d62bc4baSyz147064 
91*d62bc4baSyz147064 	if ((err = dl_capab(lh, &mp)) != 0)
92*d62bc4baSyz147064 		goto exit;
93*d62bc4baSyz147064 
94*d62bc4baSyz147064 	prim = (union DL_primitives *)mp->b_rptr;
95*d62bc4baSyz147064 	if (prim->dl_primitive == DL_ERROR_ACK) {
96*d62bc4baSyz147064 		err = -1;
97*d62bc4baSyz147064 		goto exit;
98*d62bc4baSyz147064 	}
99*d62bc4baSyz147064 
100*d62bc4baSyz147064 	err = i_capab_ack(mp, NULL, &softmac_fill_capab_ops, softmac);
101*d62bc4baSyz147064 
102*d62bc4baSyz147064 exit:
103*d62bc4baSyz147064 	freemsg(mp);
104*d62bc4baSyz147064 	return (err);
105*d62bc4baSyz147064 }
106*d62bc4baSyz147064 
107*d62bc4baSyz147064 static int
108*d62bc4baSyz147064 dl_capab(ldi_handle_t lh, mblk_t **mpp)
109*d62bc4baSyz147064 {
110*d62bc4baSyz147064 	dl_capability_req_t	*capb;
111*d62bc4baSyz147064 	union DL_primitives	*dl_prim;
112*d62bc4baSyz147064 	mblk_t			*mp;
113*d62bc4baSyz147064 	int			err;
114*d62bc4baSyz147064 
115*d62bc4baSyz147064 	if ((mp = allocb(sizeof (dl_capability_req_t), BPRI_MED)) == NULL)
116*d62bc4baSyz147064 		return (ENOMEM);
117*d62bc4baSyz147064 	mp->b_datap->db_type = M_PROTO;
118*d62bc4baSyz147064 
119*d62bc4baSyz147064 	capb = (dl_capability_req_t *)mp->b_wptr;
120*d62bc4baSyz147064 	mp->b_wptr += sizeof (dl_capability_req_t);
121*d62bc4baSyz147064 	bzero(mp->b_rptr, sizeof (dl_capability_req_t));
122*d62bc4baSyz147064 	capb->dl_primitive = DL_CAPABILITY_REQ;
123*d62bc4baSyz147064 
124*d62bc4baSyz147064 	(void) ldi_putmsg(lh, mp);
125*d62bc4baSyz147064 	if ((err = ldi_getmsg(lh, &mp, (timestruc_t *)NULL)) != 0)
126*d62bc4baSyz147064 		return (err);
127*d62bc4baSyz147064 
128*d62bc4baSyz147064 	dl_prim = (union DL_primitives *)mp->b_rptr;
129*d62bc4baSyz147064 	switch (dl_prim->dl_primitive) {
130*d62bc4baSyz147064 	case DL_CAPABILITY_ACK:
131*d62bc4baSyz147064 		if (MBLKL(mp) < DL_CAPABILITY_ACK_SIZE) {
132*d62bc4baSyz147064 			printf("dl_capability: DL_CAPABILITY_ACK "
133*d62bc4baSyz147064 			    "protocol err\n");
134*d62bc4baSyz147064 			break;
135*d62bc4baSyz147064 		}
136*d62bc4baSyz147064 		*mpp = mp;
137*d62bc4baSyz147064 		return (0);
138*d62bc4baSyz147064 
139*d62bc4baSyz147064 	case DL_ERROR_ACK:
140*d62bc4baSyz147064 		if (MBLKL(mp) < DL_ERROR_ACK_SIZE) {
141*d62bc4baSyz147064 			printf("dl_capability: DL_ERROR_ACK protocol err\n");
142*d62bc4baSyz147064 			break;
143*d62bc4baSyz147064 		}
144*d62bc4baSyz147064 		if (((dl_error_ack_t *)dl_prim)->dl_error_primitive !=
145*d62bc4baSyz147064 		    DL_CAPABILITY_REQ) {
146*d62bc4baSyz147064 			printf("dl_capability: DL_ERROR_ACK rtnd prim %u\n",
147*d62bc4baSyz147064 			    ((dl_error_ack_t *)dl_prim)->dl_error_primitive);
148*d62bc4baSyz147064 			break;
149*d62bc4baSyz147064 		}
150*d62bc4baSyz147064 
151*d62bc4baSyz147064 		*mpp = mp;
152*d62bc4baSyz147064 		return (0);
153*d62bc4baSyz147064 
154*d62bc4baSyz147064 	default:
155*d62bc4baSyz147064 		printf("dl_capability: bad ACK header %u\n",
156*d62bc4baSyz147064 		    dl_prim->dl_primitive);
157*d62bc4baSyz147064 		break;
158*d62bc4baSyz147064 	}
159*d62bc4baSyz147064 
160*d62bc4baSyz147064 	freemsg(mp);
161*d62bc4baSyz147064 	return (-1);
162*d62bc4baSyz147064 }
163*d62bc4baSyz147064 
164*d62bc4baSyz147064 static int
165*d62bc4baSyz147064 softmac_fill_hcksum_ack(void *arg, t_uscalar_t flags)
166*d62bc4baSyz147064 {
167*d62bc4baSyz147064 	softmac_t	*softmac = (softmac_t *)arg;
168*d62bc4baSyz147064 
169*d62bc4baSyz147064 	/*
170*d62bc4baSyz147064 	 * There are two types of acks we process here:
171*d62bc4baSyz147064 	 * 1. acks in reply to a (first form) generic capability req
172*d62bc4baSyz147064 	 *    (no ENABLE flag set)
173*d62bc4baSyz147064 	 * 2. acks in reply to a ENABLE capability req.
174*d62bc4baSyz147064 	 *    (ENABLE flag set)
175*d62bc4baSyz147064 	 * Only the first type should be expected here.
176*d62bc4baSyz147064 	 */
177*d62bc4baSyz147064 
178*d62bc4baSyz147064 	if (flags & HCKSUM_ENABLE) {
179*d62bc4baSyz147064 		cmn_err(CE_WARN, "softmac_fill_hcksum_ack: unexpected "
180*d62bc4baSyz147064 		    "HCKSUM_ENABLE flag in hardware checksum capability");
181*d62bc4baSyz147064 	} else if (flags & (HCKSUM_INET_PARTIAL | HCKSUM_INET_FULL_V4 |
182*d62bc4baSyz147064 	    HCKSUM_INET_FULL_V6 | HCKSUM_IPHDRCKSUM)) {
183*d62bc4baSyz147064 		softmac->smac_capab_flags |= MAC_CAPAB_HCKSUM;
184*d62bc4baSyz147064 		softmac->smac_hcksum_txflags = flags;
185*d62bc4baSyz147064 	}
186*d62bc4baSyz147064 	return (0);
187*d62bc4baSyz147064 }
188*d62bc4baSyz147064 
189*d62bc4baSyz147064 static int
190*d62bc4baSyz147064 softmac_fill_zcopy_ack(void *arg, t_uscalar_t flags)
191*d62bc4baSyz147064 {
192*d62bc4baSyz147064 	softmac_t	*softmac = (softmac_t *)arg;
193*d62bc4baSyz147064 
194*d62bc4baSyz147064 	ASSERT(flags == DL_CAPAB_VMSAFE_MEM);
195*d62bc4baSyz147064 	softmac->smac_capab_flags &= (~MAC_CAPAB_NO_ZCOPY);
196*d62bc4baSyz147064 	return (0);
197*d62bc4baSyz147064 }
198*d62bc4baSyz147064 
199*d62bc4baSyz147064 static int
200*d62bc4baSyz147064 softmac_fill_mdt_ack(void *arg, dl_capab_mdt_t *mdt)
201*d62bc4baSyz147064 {
202*d62bc4baSyz147064 	softmac_t *softmac = (softmac_t *)arg;
203*d62bc4baSyz147064 
204*d62bc4baSyz147064 	/*
205*d62bc4baSyz147064 	 * There are two types of acks we process here:
206*d62bc4baSyz147064 	 * 1. acks in reply to a (first form) generic capability req
207*d62bc4baSyz147064 	 *    (ENABLE flag might be set by some drivers)
208*d62bc4baSyz147064 	 * 2. acks in reply to a ENABLE capability req.
209*d62bc4baSyz147064 	 *    (ENABLE flag set)
210*d62bc4baSyz147064 	 */
211*d62bc4baSyz147064 
212*d62bc4baSyz147064 	ASSERT(mdt->mdt_version == MDT_VERSION_2);
213*d62bc4baSyz147064 	softmac->smac_mdt = B_TRUE;
214*d62bc4baSyz147064 	softmac->smac_mdt_capab.mdt_hdr_head = mdt->mdt_hdr_head;
215*d62bc4baSyz147064 	softmac->smac_mdt_capab.mdt_hdr_tail = mdt->mdt_hdr_tail;
216*d62bc4baSyz147064 	softmac->smac_mdt_capab.mdt_max_pld = mdt->mdt_max_pld;
217*d62bc4baSyz147064 	softmac->smac_mdt_capab.mdt_span_limit = mdt->mdt_span_limit;
218*d62bc4baSyz147064 	return (0);
219*d62bc4baSyz147064 }
220*d62bc4baSyz147064 
221*d62bc4baSyz147064 int
222*d62bc4baSyz147064 softmac_capab_enable(softmac_lower_t *slp)
223*d62bc4baSyz147064 {
224*d62bc4baSyz147064 	softmac_t	*softmac = slp->sl_softmac;
225*d62bc4baSyz147064 	int		err;
226*d62bc4baSyz147064 
227*d62bc4baSyz147064 	if (softmac->smac_no_capability_req)
228*d62bc4baSyz147064 		return (0);
229*d62bc4baSyz147064 
230*d62bc4baSyz147064 	/*
231*d62bc4baSyz147064 	 * Send DL_CAPABILITY_REQ to get capability advertisement.
232*d62bc4baSyz147064 	 */
233*d62bc4baSyz147064 	if ((err = softmac_capab_send(slp, B_FALSE)) != 0)
234*d62bc4baSyz147064 		return (err);
235*d62bc4baSyz147064 
236*d62bc4baSyz147064 	/*
237*d62bc4baSyz147064 	 * Send DL_CAPABILITY_REQ to enable specific capabilities.
238*d62bc4baSyz147064 	 */
239*d62bc4baSyz147064 	if ((err = softmac_capab_send(slp, B_TRUE)) != 0)
240*d62bc4baSyz147064 		return (err);
241*d62bc4baSyz147064 
242*d62bc4baSyz147064 	return (0);
243*d62bc4baSyz147064 }
244*d62bc4baSyz147064 
245*d62bc4baSyz147064 static int
246*d62bc4baSyz147064 softmac_capab_send(softmac_lower_t *slp, boolean_t enable)
247*d62bc4baSyz147064 {
248*d62bc4baSyz147064 	softmac_t		*softmac;
249*d62bc4baSyz147064 	dl_capability_req_t	*capb;
250*d62bc4baSyz147064 	dl_capability_sub_t	*subcapb;
251*d62bc4baSyz147064 	mblk_t			*reqmp, *ackmp;
252*d62bc4baSyz147064 	int			err;
253*d62bc4baSyz147064 	size_t			size = 0;
254*d62bc4baSyz147064 
255*d62bc4baSyz147064 	softmac = slp->sl_softmac;
256*d62bc4baSyz147064 
257*d62bc4baSyz147064 	if (enable) {
258*d62bc4baSyz147064 		/* No need to enable DL_CAPAB_ZEROCOPY */
259*d62bc4baSyz147064 		if (softmac->smac_capab_flags & MAC_CAPAB_HCKSUM)
260*d62bc4baSyz147064 			size += sizeof (dl_capability_sub_t) +
261*d62bc4baSyz147064 			    sizeof (dl_capab_hcksum_t);
262*d62bc4baSyz147064 
263*d62bc4baSyz147064 		if (softmac->smac_mdt) {
264*d62bc4baSyz147064 			if (!(softmac->smac_mdt_capab.mdt_flags &
265*d62bc4baSyz147064 			    DL_CAPAB_MDT_ENABLE)) {
266*d62bc4baSyz147064 				/*
267*d62bc4baSyz147064 				 * The MDT capability was not enabled for the
268*d62bc4baSyz147064 				 * first time, enable it now.
269*d62bc4baSyz147064 				 */
270*d62bc4baSyz147064 				size += sizeof (dl_capability_sub_t) +
271*d62bc4baSyz147064 				    sizeof (dl_capab_mdt_t);
272*d62bc4baSyz147064 			}
273*d62bc4baSyz147064 		}
274*d62bc4baSyz147064 
275*d62bc4baSyz147064 		if (size == 0)
276*d62bc4baSyz147064 			return (0);
277*d62bc4baSyz147064 	}
278*d62bc4baSyz147064 
279*d62bc4baSyz147064 	/*
280*d62bc4baSyz147064 	 * Create DL_CAPABILITY_REQ message and send it down
281*d62bc4baSyz147064 	 */
282*d62bc4baSyz147064 	reqmp = allocb(sizeof (dl_capability_req_t) + size, BPRI_MED);
283*d62bc4baSyz147064 	if (reqmp == NULL)
284*d62bc4baSyz147064 		return (ENOMEM);
285*d62bc4baSyz147064 
286*d62bc4baSyz147064 	bzero(reqmp->b_rptr, sizeof (dl_capability_req_t) + size);
287*d62bc4baSyz147064 
288*d62bc4baSyz147064 	DB_TYPE(reqmp) = M_PROTO;
289*d62bc4baSyz147064 	reqmp->b_wptr = reqmp->b_rptr + sizeof (dl_capability_req_t) + size;
290*d62bc4baSyz147064 
291*d62bc4baSyz147064 	capb = (dl_capability_req_t *)reqmp->b_rptr;
292*d62bc4baSyz147064 	capb->dl_primitive = DL_CAPABILITY_REQ;
293*d62bc4baSyz147064 
294*d62bc4baSyz147064 	if (!enable)
295*d62bc4baSyz147064 		goto output;
296*d62bc4baSyz147064 
297*d62bc4baSyz147064 	capb->dl_sub_offset = sizeof (dl_capability_req_t);
298*d62bc4baSyz147064 
299*d62bc4baSyz147064 	if (softmac->smac_capab_flags & MAC_CAPAB_HCKSUM) {
300*d62bc4baSyz147064 		dl_capab_hcksum_t *hck_subcapp;
301*d62bc4baSyz147064 
302*d62bc4baSyz147064 		size = sizeof (dl_capability_sub_t) +
303*d62bc4baSyz147064 		    sizeof (dl_capab_hcksum_t);
304*d62bc4baSyz147064 		capb->dl_sub_length += size;
305*d62bc4baSyz147064 
306*d62bc4baSyz147064 		subcapb = (dl_capability_sub_t *)(capb + 1);
307*d62bc4baSyz147064 		subcapb->dl_cap = DL_CAPAB_HCKSUM;
308*d62bc4baSyz147064 		subcapb->dl_length = sizeof (dl_capab_hcksum_t);
309*d62bc4baSyz147064 		hck_subcapp = (dl_capab_hcksum_t *)(subcapb + 1);
310*d62bc4baSyz147064 		hck_subcapp->hcksum_version = HCKSUM_VERSION_1;
311*d62bc4baSyz147064 		hck_subcapp->hcksum_txflags =
312*d62bc4baSyz147064 		    softmac->smac_hcksum_txflags | HCKSUM_ENABLE;
313*d62bc4baSyz147064 	}
314*d62bc4baSyz147064 
315*d62bc4baSyz147064 	if (softmac->smac_mdt) {
316*d62bc4baSyz147064 		if (!(softmac->smac_mdt_capab.mdt_flags &
317*d62bc4baSyz147064 		    DL_CAPAB_MDT_ENABLE)) {
318*d62bc4baSyz147064 			dl_capab_mdt_t *mdt_subcapp;
319*d62bc4baSyz147064 
320*d62bc4baSyz147064 			size = sizeof (dl_capability_sub_t) +
321*d62bc4baSyz147064 			    sizeof (dl_capab_mdt_t);
322*d62bc4baSyz147064 			capb->dl_sub_length += size;
323*d62bc4baSyz147064 
324*d62bc4baSyz147064 			subcapb = (dl_capability_sub_t *)
325*d62bc4baSyz147064 			    ((uint8_t *)(subcapb + 1) + subcapb->dl_length);
326*d62bc4baSyz147064 
327*d62bc4baSyz147064 			subcapb->dl_cap = DL_CAPAB_MDT;
328*d62bc4baSyz147064 			subcapb->dl_length = sizeof (dl_capab_mdt_t);
329*d62bc4baSyz147064 			mdt_subcapp = (dl_capab_mdt_t *)(subcapb + 1);
330*d62bc4baSyz147064 			mdt_subcapp->mdt_version = MDT_VERSION_2;
331*d62bc4baSyz147064 			mdt_subcapp->mdt_flags =
332*d62bc4baSyz147064 			    (softmac->smac_mdt_capab.mdt_flags |
333*d62bc4baSyz147064 			    DL_CAPAB_MDT_ENABLE);
334*d62bc4baSyz147064 			mdt_subcapp->mdt_hdr_head =
335*d62bc4baSyz147064 			    softmac->smac_mdt_capab.mdt_hdr_head;
336*d62bc4baSyz147064 			mdt_subcapp->mdt_hdr_tail =
337*d62bc4baSyz147064 			    softmac->smac_mdt_capab.mdt_hdr_tail;
338*d62bc4baSyz147064 			mdt_subcapp->mdt_max_pld =
339*d62bc4baSyz147064 			    softmac->smac_mdt_capab.mdt_max_pld;
340*d62bc4baSyz147064 			mdt_subcapp->mdt_span_limit =
341*d62bc4baSyz147064 			    softmac->smac_mdt_capab.mdt_span_limit;
342*d62bc4baSyz147064 		}
343*d62bc4baSyz147064 	}
344*d62bc4baSyz147064 
345*d62bc4baSyz147064 output:
346*d62bc4baSyz147064 	err = softmac_proto_tx(slp, reqmp, &ackmp);
347*d62bc4baSyz147064 	if (err == 0) {
348*d62bc4baSyz147064 		if (enable) {
349*d62bc4baSyz147064 			err = i_capab_ack(ackmp, NULL,
350*d62bc4baSyz147064 			    &softmac_enable_capab_ops, softmac);
351*d62bc4baSyz147064 		} else {
352*d62bc4baSyz147064 			err = i_capab_ack(ackmp, NULL,
353*d62bc4baSyz147064 			    &softmac_adv_capab_ops, softmac);
354*d62bc4baSyz147064 		}
355*d62bc4baSyz147064 	}
356*d62bc4baSyz147064 	freemsg(ackmp);
357*d62bc4baSyz147064 
358*d62bc4baSyz147064 	return (err);
359*d62bc4baSyz147064 }
360*d62bc4baSyz147064 
361*d62bc4baSyz147064 static int
362*d62bc4baSyz147064 softmac_adv_hcksum_ack(void *arg, t_uscalar_t flags)
363*d62bc4baSyz147064 {
364*d62bc4baSyz147064 	softmac_t	*softmac = (softmac_t *)arg;
365*d62bc4baSyz147064 
366*d62bc4baSyz147064 	/*
367*d62bc4baSyz147064 	 * There are two types of acks we process here:
368*d62bc4baSyz147064 	 * 1. acks in reply to a (first form) generic capability req
369*d62bc4baSyz147064 	 *    (no ENABLE flag set)
370*d62bc4baSyz147064 	 * 2. acks in reply to a ENABLE capability req.
371*d62bc4baSyz147064 	 *    (ENABLE flag set)
372*d62bc4baSyz147064 	 * Only the first type should be expected here.
373*d62bc4baSyz147064 	 */
374*d62bc4baSyz147064 
375*d62bc4baSyz147064 	if (flags & HCKSUM_ENABLE) {
376*d62bc4baSyz147064 		cmn_err(CE_WARN, "softmac_adv_hcksum_ack: unexpected "
377*d62bc4baSyz147064 		    "HCKSUM_ENABLE flag in hardware checksum capability");
378*d62bc4baSyz147064 		return (-1);
379*d62bc4baSyz147064 	} else if (flags & (HCKSUM_INET_PARTIAL | HCKSUM_INET_FULL_V4 |
380*d62bc4baSyz147064 	    HCKSUM_INET_FULL_V6 | HCKSUM_IPHDRCKSUM)) {
381*d62bc4baSyz147064 		/*
382*d62bc4baSyz147064 		 * The acknowledgement should be the same as we got when
383*d62bc4baSyz147064 		 * the softmac is created.
384*d62bc4baSyz147064 		 */
385*d62bc4baSyz147064 		if (!(softmac->smac_capab_flags & MAC_CAPAB_HCKSUM)) {
386*d62bc4baSyz147064 			ASSERT(B_FALSE);
387*d62bc4baSyz147064 			return (-1);
388*d62bc4baSyz147064 		}
389*d62bc4baSyz147064 		if (softmac->smac_hcksum_txflags != flags) {
390*d62bc4baSyz147064 			ASSERT(B_FALSE);
391*d62bc4baSyz147064 			return (-1);
392*d62bc4baSyz147064 		}
393*d62bc4baSyz147064 	}
394*d62bc4baSyz147064 
395*d62bc4baSyz147064 	return (0);
396*d62bc4baSyz147064 }
397*d62bc4baSyz147064 
398*d62bc4baSyz147064 static int
399*d62bc4baSyz147064 softmac_adv_zcopy_ack(void *arg, t_uscalar_t flags)
400*d62bc4baSyz147064 {
401*d62bc4baSyz147064 	softmac_t	*softmac = (softmac_t *)arg;
402*d62bc4baSyz147064 
403*d62bc4baSyz147064 	/*
404*d62bc4baSyz147064 	 * The acknowledgement should be the same as we got when
405*d62bc4baSyz147064 	 * the softmac is created.
406*d62bc4baSyz147064 	 */
407*d62bc4baSyz147064 	ASSERT(flags == DL_CAPAB_VMSAFE_MEM);
408*d62bc4baSyz147064 	if (softmac->smac_capab_flags & MAC_CAPAB_NO_ZCOPY) {
409*d62bc4baSyz147064 		ASSERT(B_FALSE);
410*d62bc4baSyz147064 		return (-1);
411*d62bc4baSyz147064 	}
412*d62bc4baSyz147064 
413*d62bc4baSyz147064 	return (0);
414*d62bc4baSyz147064 }
415*d62bc4baSyz147064 
416*d62bc4baSyz147064 static int
417*d62bc4baSyz147064 softmac_adv_mdt_ack(void *arg, dl_capab_mdt_t *mdt)
418*d62bc4baSyz147064 {
419*d62bc4baSyz147064 	softmac_t *softmac = (softmac_t *)arg;
420*d62bc4baSyz147064 
421*d62bc4baSyz147064 	/*
422*d62bc4baSyz147064 	 * The acknowledgement should be the same as we got when
423*d62bc4baSyz147064 	 * the softmac is created.
424*d62bc4baSyz147064 	 */
425*d62bc4baSyz147064 	if (!softmac->smac_mdt) {
426*d62bc4baSyz147064 		ASSERT(B_FALSE);
427*d62bc4baSyz147064 		return (-1);
428*d62bc4baSyz147064 	}
429*d62bc4baSyz147064 
430*d62bc4baSyz147064 	if ((softmac->smac_mdt_capab.mdt_hdr_head != mdt->mdt_hdr_head) ||
431*d62bc4baSyz147064 	    (softmac->smac_mdt_capab.mdt_hdr_tail != mdt->mdt_hdr_tail) ||
432*d62bc4baSyz147064 	    (softmac->smac_mdt_capab.mdt_max_pld != mdt->mdt_max_pld) ||
433*d62bc4baSyz147064 	    (softmac->smac_mdt_capab.mdt_span_limit != mdt->mdt_span_limit)) {
434*d62bc4baSyz147064 		ASSERT(B_FALSE);
435*d62bc4baSyz147064 		return (-1);
436*d62bc4baSyz147064 	}
437*d62bc4baSyz147064 	/*
438*d62bc4baSyz147064 	 * We need the mdt_flags field to know whether an additional
439*d62bc4baSyz147064 	 * DL_CAPAB_MDT_ENABLE is necessary.
440*d62bc4baSyz147064 	 */
441*d62bc4baSyz147064 	softmac->smac_mdt_capab.mdt_flags = mdt->mdt_flags;
442*d62bc4baSyz147064 	return (0);
443*d62bc4baSyz147064 }
444*d62bc4baSyz147064 
445*d62bc4baSyz147064 static int
446*d62bc4baSyz147064 softmac_enable_hcksum_ack(void *arg, t_uscalar_t flags)
447*d62bc4baSyz147064 {
448*d62bc4baSyz147064 	softmac_t	*softmac = (softmac_t *)arg;
449*d62bc4baSyz147064 
450*d62bc4baSyz147064 	/*
451*d62bc4baSyz147064 	 * There are two types of acks we process here:
452*d62bc4baSyz147064 	 * 1. acks in reply to a (first form) generic capability req
453*d62bc4baSyz147064 	 *    (no ENABLE flag set)
454*d62bc4baSyz147064 	 * 2. acks in reply to a ENABLE capability req.
455*d62bc4baSyz147064 	 *    (ENABLE flag set)
456*d62bc4baSyz147064 	 * Only the second type should be expected here.
457*d62bc4baSyz147064 	 */
458*d62bc4baSyz147064 
459*d62bc4baSyz147064 	if (flags & HCKSUM_ENABLE) {
460*d62bc4baSyz147064 		if ((flags & ~HCKSUM_ENABLE) != softmac->smac_hcksum_txflags) {
461*d62bc4baSyz147064 			cmn_err(CE_WARN, "softmac_enable_hcksum_ack: unexpected"
462*d62bc4baSyz147064 			    " hardware capability flag value 0x%x", flags);
463*d62bc4baSyz147064 			return (-1);
464*d62bc4baSyz147064 		}
465*d62bc4baSyz147064 	} else {
466*d62bc4baSyz147064 		cmn_err(CE_WARN, "softmac_enable_hcksum_ack: "
467*d62bc4baSyz147064 		    "hardware checksum flag HCKSUM_ENABLE is not set");
468*d62bc4baSyz147064 		return (-1);
469*d62bc4baSyz147064 	}
470*d62bc4baSyz147064 
471*d62bc4baSyz147064 	return (0);
472*d62bc4baSyz147064 }
473*d62bc4baSyz147064 
474*d62bc4baSyz147064 static int
475*d62bc4baSyz147064 softmac_enable_mdt_ack(void *arg, dl_capab_mdt_t *mdt)
476*d62bc4baSyz147064 {
477*d62bc4baSyz147064 	softmac_t	*softmac = (softmac_t *)arg;
478*d62bc4baSyz147064 
479*d62bc4baSyz147064 	/*
480*d62bc4baSyz147064 	 * There are two types of acks we process here:
481*d62bc4baSyz147064 	 * 1. acks in reply to a (first form) generic capability req
482*d62bc4baSyz147064 	 *    (no ENABLE flag set)
483*d62bc4baSyz147064 	 * 2. acks in reply to a ENABLE capability req.
484*d62bc4baSyz147064 	 *    (ENABLE flag set)
485*d62bc4baSyz147064 	 * Only the second type should be expected here.
486*d62bc4baSyz147064 	 */
487*d62bc4baSyz147064 
488*d62bc4baSyz147064 	if (mdt->mdt_flags & DL_CAPAB_MDT_ENABLE) {
489*d62bc4baSyz147064 		if ((softmac->smac_mdt_capab.mdt_hdr_head !=
490*d62bc4baSyz147064 		    mdt->mdt_hdr_head) ||
491*d62bc4baSyz147064 		    (softmac->smac_mdt_capab.mdt_hdr_tail !=
492*d62bc4baSyz147064 		    mdt->mdt_hdr_tail) ||
493*d62bc4baSyz147064 		    (softmac->smac_mdt_capab.mdt_max_pld !=
494*d62bc4baSyz147064 		    mdt->mdt_max_pld) ||
495*d62bc4baSyz147064 		    (softmac->smac_mdt_capab.mdt_span_limit !=
496*d62bc4baSyz147064 		    mdt->mdt_span_limit)) {
497*d62bc4baSyz147064 			cmn_err(CE_WARN, "softmac_enable_mdt_ack: "
498*d62bc4baSyz147064 			    "unexpected MDT capability value");
499*d62bc4baSyz147064 			return (-1);
500*d62bc4baSyz147064 		}
501*d62bc4baSyz147064 		softmac->smac_mdt_capab.mdt_flags = mdt->mdt_flags;
502*d62bc4baSyz147064 	} else {
503*d62bc4baSyz147064 		cmn_err(CE_WARN, "softmac_enable_mdt_ack: "
504*d62bc4baSyz147064 		    "MDT flag DL_CAPAB_MDT_ENABLE is not set");
505*d62bc4baSyz147064 		return (-1);
506*d62bc4baSyz147064 	}
507*d62bc4baSyz147064 
508*d62bc4baSyz147064 	return (0);
509*d62bc4baSyz147064 }
510*d62bc4baSyz147064 
511*d62bc4baSyz147064 static int
512*d62bc4baSyz147064 i_capab_ack(mblk_t *mp, queue_t *q, softmac_capab_ops_t *op, void *arg)
513*d62bc4baSyz147064 {
514*d62bc4baSyz147064 	union DL_primitives	*prim;
515*d62bc4baSyz147064 	dl_capability_ack_t	*cap;
516*d62bc4baSyz147064 	dl_capability_sub_t	*sub, *end;
517*d62bc4baSyz147064 	int			err = 0;
518*d62bc4baSyz147064 
519*d62bc4baSyz147064 	prim = (union DL_primitives *)mp->b_rptr;
520*d62bc4baSyz147064 	ASSERT(prim->dl_primitive == DL_CAPABILITY_ACK);
521*d62bc4baSyz147064 
522*d62bc4baSyz147064 	cap = (dl_capability_ack_t *)prim;
523*d62bc4baSyz147064 	if (cap->dl_sub_length == 0)
524*d62bc4baSyz147064 		goto exit;
525*d62bc4baSyz147064 
526*d62bc4baSyz147064 	/* Is dl_sub_length correct? */
527*d62bc4baSyz147064 	if ((sizeof (*cap) + cap->dl_sub_length) > MBLKL(mp)) {
528*d62bc4baSyz147064 		err = EINVAL;
529*d62bc4baSyz147064 		goto exit;
530*d62bc4baSyz147064 	}
531*d62bc4baSyz147064 
532*d62bc4baSyz147064 	sub = (dl_capability_sub_t *)((caddr_t)cap + cap->dl_sub_offset);
533*d62bc4baSyz147064 	end = (dl_capability_sub_t *)((caddr_t)cap + cap->dl_sub_length
534*d62bc4baSyz147064 	    - sizeof (*sub));
535*d62bc4baSyz147064 	for (; (sub <= end) && (err == 0); ) {
536*d62bc4baSyz147064 		switch (sub->dl_cap) {
537*d62bc4baSyz147064 		case DL_CAPAB_ID_WRAPPER:
538*d62bc4baSyz147064 			err = i_capab_id_ack(mp, sub, q, op, arg);
539*d62bc4baSyz147064 			break;
540*d62bc4baSyz147064 		default:
541*d62bc4baSyz147064 			err = i_capab_sub_ack(mp, sub, q, op, arg);
542*d62bc4baSyz147064 			break;
543*d62bc4baSyz147064 		}
544*d62bc4baSyz147064 		sub = (dl_capability_sub_t *)((caddr_t)sub + sizeof (*sub)
545*d62bc4baSyz147064 		    + sub->dl_length);
546*d62bc4baSyz147064 	}
547*d62bc4baSyz147064 
548*d62bc4baSyz147064 exit:
549*d62bc4baSyz147064 	return (err);
550*d62bc4baSyz147064 }
551*d62bc4baSyz147064 
552*d62bc4baSyz147064 static int
553*d62bc4baSyz147064 i_capab_id_ack(mblk_t *mp, dl_capability_sub_t *outers,
554*d62bc4baSyz147064     queue_t *q, softmac_capab_ops_t *op, void *arg)
555*d62bc4baSyz147064 {
556*d62bc4baSyz147064 	dl_capab_id_t		*capab_id;
557*d62bc4baSyz147064 	dl_capability_sub_t	*inners;
558*d62bc4baSyz147064 	caddr_t			capend;
559*d62bc4baSyz147064 	int			err = EINVAL;
560*d62bc4baSyz147064 
561*d62bc4baSyz147064 	ASSERT(outers->dl_cap == DL_CAPAB_ID_WRAPPER);
562*d62bc4baSyz147064 
563*d62bc4baSyz147064 	capend = (caddr_t)(outers + 1) + outers->dl_length;
564*d62bc4baSyz147064 	if (capend > (caddr_t)mp->b_wptr) {
565*d62bc4baSyz147064 		cmn_err(CE_WARN, "i_capab_id_ack: malformed "
566*d62bc4baSyz147064 		    "sub-capability too long");
567*d62bc4baSyz147064 		return (err);
568*d62bc4baSyz147064 	}
569*d62bc4baSyz147064 
570*d62bc4baSyz147064 	capab_id = (dl_capab_id_t *)(outers + 1);
571*d62bc4baSyz147064 
572*d62bc4baSyz147064 	if (outers->dl_length < sizeof (*capab_id) ||
573*d62bc4baSyz147064 	    (inners = &capab_id->id_subcap,
574*d62bc4baSyz147064 	    inners->dl_length > (outers->dl_length - sizeof (*inners)))) {
575*d62bc4baSyz147064 		cmn_err(CE_WARN, "i_capab_id_ack: malformed "
576*d62bc4baSyz147064 		    "encapsulated capab type %d too long",
577*d62bc4baSyz147064 		    inners->dl_cap);
578*d62bc4baSyz147064 		return (err);
579*d62bc4baSyz147064 	}
580*d62bc4baSyz147064 
581*d62bc4baSyz147064 	if ((q != NULL) && (!dlcapabcheckqid(&capab_id->id_mid, q))) {
582*d62bc4baSyz147064 		cmn_err(CE_WARN, "i_capab_id_ack: pass-thru module(s) "
583*d62bc4baSyz147064 		    "detected, discarding capab type %d", inners->dl_cap);
584*d62bc4baSyz147064 		return (err);
585*d62bc4baSyz147064 	}
586*d62bc4baSyz147064 
587*d62bc4baSyz147064 	/* Process the encapsulated sub-capability */
588*d62bc4baSyz147064 	return (i_capab_sub_ack(mp, inners, q, op, arg));
589*d62bc4baSyz147064 }
590*d62bc4baSyz147064 
591*d62bc4baSyz147064 static int
592*d62bc4baSyz147064 i_capab_sub_ack(mblk_t *mp, dl_capability_sub_t *sub, queue_t *q,
593*d62bc4baSyz147064     softmac_capab_ops_t *op, void *arg)
594*d62bc4baSyz147064 {
595*d62bc4baSyz147064 	caddr_t			capend;
596*d62bc4baSyz147064 	dl_capab_hcksum_t	*hcksum;
597*d62bc4baSyz147064 	dl_capab_zerocopy_t	*zcopy;
598*d62bc4baSyz147064 	dl_capab_mdt_t		*mdt;
599*d62bc4baSyz147064 	int			err = 0;
600*d62bc4baSyz147064 
601*d62bc4baSyz147064 	capend = (caddr_t)(sub + 1) + sub->dl_length;
602*d62bc4baSyz147064 	if (capend > (caddr_t)mp->b_wptr) {
603*d62bc4baSyz147064 		cmn_err(CE_WARN, "i_capab_sub_ack: "
604*d62bc4baSyz147064 		    "malformed sub-capability too long");
605*d62bc4baSyz147064 		return (EINVAL);
606*d62bc4baSyz147064 	}
607*d62bc4baSyz147064 
608*d62bc4baSyz147064 	switch (sub->dl_cap) {
609*d62bc4baSyz147064 	case DL_CAPAB_HCKSUM:
610*d62bc4baSyz147064 		hcksum = (dl_capab_hcksum_t *)(sub + 1);
611*d62bc4baSyz147064 		err = i_capab_hcksum_ack(hcksum, q, op, arg);
612*d62bc4baSyz147064 		break;
613*d62bc4baSyz147064 
614*d62bc4baSyz147064 	case DL_CAPAB_ZEROCOPY:
615*d62bc4baSyz147064 		zcopy = (dl_capab_zerocopy_t *)(sub + 1);
616*d62bc4baSyz147064 		err = i_capab_zcopy_ack(zcopy, q, op, arg);
617*d62bc4baSyz147064 		break;
618*d62bc4baSyz147064 
619*d62bc4baSyz147064 	case DL_CAPAB_MDT:
620*d62bc4baSyz147064 		mdt = (dl_capab_mdt_t *)(sub + 1);
621*d62bc4baSyz147064 		err = i_capab_mdt_ack(mdt, q, op, arg);
622*d62bc4baSyz147064 		break;
623*d62bc4baSyz147064 
624*d62bc4baSyz147064 	default:
625*d62bc4baSyz147064 		cmn_err(CE_WARN, "i_capab_sub_ack: unknown capab type %d",
626*d62bc4baSyz147064 		    sub->dl_cap);
627*d62bc4baSyz147064 		err = EINVAL;
628*d62bc4baSyz147064 	}
629*d62bc4baSyz147064 
630*d62bc4baSyz147064 	return (err);
631*d62bc4baSyz147064 }
632*d62bc4baSyz147064 
633*d62bc4baSyz147064 static int
634*d62bc4baSyz147064 i_capab_hcksum_ack(dl_capab_hcksum_t *hcksum, queue_t *q,
635*d62bc4baSyz147064     softmac_capab_ops_t *op, void *arg)
636*d62bc4baSyz147064 {
637*d62bc4baSyz147064 	t_uscalar_t		flags;
638*d62bc4baSyz147064 	int			err = 0;
639*d62bc4baSyz147064 
640*d62bc4baSyz147064 	if ((err = i_capab_hcksum_verify(hcksum, q)) != 0)
641*d62bc4baSyz147064 		return (err);
642*d62bc4baSyz147064 
643*d62bc4baSyz147064 	flags = hcksum->hcksum_txflags;
644*d62bc4baSyz147064 
645*d62bc4baSyz147064 	if (!(flags & (HCKSUM_INET_PARTIAL | HCKSUM_INET_FULL_V4 |
646*d62bc4baSyz147064 	    HCKSUM_INET_FULL_V6 | HCKSUM_IPHDRCKSUM | HCKSUM_ENABLE))) {
647*d62bc4baSyz147064 		cmn_err(CE_WARN, "i_capab_hcksum_ack: invalid "
648*d62bc4baSyz147064 		    "hardware checksum capability flags 0x%x", flags);
649*d62bc4baSyz147064 		return (EINVAL);
650*d62bc4baSyz147064 	}
651*d62bc4baSyz147064 
652*d62bc4baSyz147064 	if (op->sc_hcksum_ack)
653*d62bc4baSyz147064 		return (op->sc_hcksum_ack(arg, flags));
654*d62bc4baSyz147064 	else {
655*d62bc4baSyz147064 		cmn_err(CE_WARN, "i_capab_hcksum_ack: unexpected hardware "
656*d62bc4baSyz147064 		    "checksum acknowledgement");
657*d62bc4baSyz147064 		return (EINVAL);
658*d62bc4baSyz147064 	}
659*d62bc4baSyz147064 }
660*d62bc4baSyz147064 
661*d62bc4baSyz147064 static int
662*d62bc4baSyz147064 i_capab_zcopy_ack(dl_capab_zerocopy_t *zcopy, queue_t *q,
663*d62bc4baSyz147064     softmac_capab_ops_t *op, void *arg)
664*d62bc4baSyz147064 {
665*d62bc4baSyz147064 	t_uscalar_t		flags;
666*d62bc4baSyz147064 	int			err = 0;
667*d62bc4baSyz147064 
668*d62bc4baSyz147064 	if ((err = i_capab_zcopy_verify(zcopy, q)) != 0)
669*d62bc4baSyz147064 		return (err);
670*d62bc4baSyz147064 
671*d62bc4baSyz147064 	flags = zcopy->zerocopy_flags;
672*d62bc4baSyz147064 	if (!(flags & DL_CAPAB_VMSAFE_MEM)) {
673*d62bc4baSyz147064 		cmn_err(CE_WARN, "i_capab_zcopy_ack: invalid zcopy capability "
674*d62bc4baSyz147064 		    "flags 0x%x", flags);
675*d62bc4baSyz147064 		return (EINVAL);
676*d62bc4baSyz147064 	}
677*d62bc4baSyz147064 	if (op->sc_zcopy_ack)
678*d62bc4baSyz147064 		return (op->sc_zcopy_ack(arg, flags));
679*d62bc4baSyz147064 	else {
680*d62bc4baSyz147064 		cmn_err(CE_WARN, "i_capab_zcopy_ack: unexpected zcopy "
681*d62bc4baSyz147064 		    "acknowledgement");
682*d62bc4baSyz147064 		return (EINVAL);
683*d62bc4baSyz147064 	}
684*d62bc4baSyz147064 }
685*d62bc4baSyz147064 
686*d62bc4baSyz147064 static int
687*d62bc4baSyz147064 i_capab_mdt_ack(dl_capab_mdt_t *mdt, queue_t *q,
688*d62bc4baSyz147064     softmac_capab_ops_t *op, void *arg)
689*d62bc4baSyz147064 {
690*d62bc4baSyz147064 	int	err;
691*d62bc4baSyz147064 
692*d62bc4baSyz147064 	if ((err = i_capab_mdt_verify(mdt, q)) != 0)
693*d62bc4baSyz147064 		return (err);
694*d62bc4baSyz147064 
695*d62bc4baSyz147064 	if (op->sc_mdt_ack)
696*d62bc4baSyz147064 		return (op->sc_mdt_ack(arg, mdt));
697*d62bc4baSyz147064 	else {
698*d62bc4baSyz147064 		cmn_err(CE_WARN, "i_capab_mdt_ack: unexpected MDT "
699*d62bc4baSyz147064 		    "acknowledgement");
700*d62bc4baSyz147064 		return (EINVAL);
701*d62bc4baSyz147064 	}
702*d62bc4baSyz147064 }
703*d62bc4baSyz147064 
704*d62bc4baSyz147064 static int
705*d62bc4baSyz147064 i_capab_hcksum_verify(dl_capab_hcksum_t *hcksum, queue_t *q)
706*d62bc4baSyz147064 {
707*d62bc4baSyz147064 	if (hcksum->hcksum_version != HCKSUM_VERSION_1) {
708*d62bc4baSyz147064 		cmn_err(CE_WARN, "i_capab_hcksum_verify: "
709*d62bc4baSyz147064 		    "unsupported hardware checksum capability (version %d, "
710*d62bc4baSyz147064 		    "expected %d)", hcksum->hcksum_version, HCKSUM_VERSION_1);
711*d62bc4baSyz147064 		return (-1);
712*d62bc4baSyz147064 	}
713*d62bc4baSyz147064 
714*d62bc4baSyz147064 	if ((q != NULL) && !dlcapabcheckqid(&hcksum->hcksum_mid, q)) {
715*d62bc4baSyz147064 		cmn_err(CE_WARN, "i_capab_hcksum_verify: unexpected pass-thru "
716*d62bc4baSyz147064 		    "module detected; hardware checksum capability discarded");
717*d62bc4baSyz147064 		return (-1);
718*d62bc4baSyz147064 	}
719*d62bc4baSyz147064 	return (0);
720*d62bc4baSyz147064 }
721*d62bc4baSyz147064 
722*d62bc4baSyz147064 static int
723*d62bc4baSyz147064 i_capab_zcopy_verify(dl_capab_zerocopy_t *zcopy, queue_t *q)
724*d62bc4baSyz147064 {
725*d62bc4baSyz147064 	if (zcopy->zerocopy_version != ZEROCOPY_VERSION_1) {
726*d62bc4baSyz147064 		cmn_err(CE_WARN, "i_capab_zcopy_verify: unsupported zcopy "
727*d62bc4baSyz147064 		    "capability (version %d, expected %d)",
728*d62bc4baSyz147064 		    zcopy->zerocopy_version, ZEROCOPY_VERSION_1);
729*d62bc4baSyz147064 		return (-1);
730*d62bc4baSyz147064 	}
731*d62bc4baSyz147064 
732*d62bc4baSyz147064 	if ((q != NULL) && !dlcapabcheckqid(&zcopy->zerocopy_mid, q)) {
733*d62bc4baSyz147064 		cmn_err(CE_WARN, "i_capab_zcopy_verify: unexpected pass-thru "
734*d62bc4baSyz147064 		    "module detected; zcopy checksum capability discarded");
735*d62bc4baSyz147064 		return (-1);
736*d62bc4baSyz147064 	}
737*d62bc4baSyz147064 	return (0);
738*d62bc4baSyz147064 }
739*d62bc4baSyz147064 
740*d62bc4baSyz147064 static int
741*d62bc4baSyz147064 i_capab_mdt_verify(dl_capab_mdt_t *mdt, queue_t *q)
742*d62bc4baSyz147064 {
743*d62bc4baSyz147064 	if (mdt->mdt_version != MDT_VERSION_2) {
744*d62bc4baSyz147064 		cmn_err(CE_WARN, "i_capab_mdt_verify: unsupported MDT "
745*d62bc4baSyz147064 		    "capability (version %d, expected %d)",
746*d62bc4baSyz147064 		    mdt->mdt_version, MDT_VERSION_2);
747*d62bc4baSyz147064 		return (-1);
748*d62bc4baSyz147064 	}
749*d62bc4baSyz147064 
750*d62bc4baSyz147064 	if ((q != NULL) && !dlcapabcheckqid(&mdt->mdt_mid, q)) {
751*d62bc4baSyz147064 		cmn_err(CE_WARN, "i_capab_mdt_verify: unexpected pass-thru "
752*d62bc4baSyz147064 		    "module detected; MDT capability discarded");
753*d62bc4baSyz147064 		return (-1);
754*d62bc4baSyz147064 	}
755*d62bc4baSyz147064 	return (0);
756*d62bc4baSyz147064 }
757