1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #include <sys/dada/dada.h>
28 #include <sys/vtrace.h>
29 
30 #define	A_TO_TRAN(ap)	((ap)->a_hba_tran)
31 #define	P_TO_TRAN(pkt)	((pkt)->pkt_address.a_hba_tran)
32 #define	P_TO_ADDR(pkt)	(&((pkt)->pkt_address))
33 
34 /*
35  * Callback id
36  */
37 uintptr_t	dcd_callback_id = 0L;
38 
39 /* For i_ddi_mem_alloc() in dcd_alloc_consistent_buf() */
40 static ddi_dma_attr_t standard_dma_attr = {
41 	DMA_ATTR_V0,	/* version number */
42 	0x0,		/* lowest usable address */
43 	0xFFFFFFFFull,	/* high DMA address range */
44 	0xFFFFFFFFull,	/* DMA counter register */
45 	1,		/* DMA address alignment */
46 	1,		/* DMA burstsizes */
47 	1,		/* min effective DMA size */
48 	0xFFFFFFFFull,	/* max DMA xfer size */
49 	0xFFFFFFFFull,	/* segment boundary */
50 	1,		/* s/g list length */
51 	512,		/* granularity of device */
52 	0,		/* DMA transfer flags */
53 };
54 
55 struct buf *
dcd_alloc_consistent_buf(struct dcd_address * ap,struct buf * in_bp,size_t datalen,uint_t bflags,int (* callback)(caddr_t),caddr_t callback_arg)56 dcd_alloc_consistent_buf(struct dcd_address *ap,
57     struct buf *in_bp, size_t datalen, uint_t bflags,
58     int (*callback)(caddr_t), caddr_t callback_arg)
59 {
60 
61 	dev_info_t	*pdip;
62 	struct	buf	*bp;
63 	int		kmflag;
64 	size_t		rlen;
65 
66 
67 	if (!in_bp) {
68 		kmflag = (callback == SLEEP_FUNC) ? KM_SLEEP: KM_NOSLEEP;
69 		if ((bp = getrbuf(kmflag)) == NULL) {
70 			goto no_resource;
71 		}
72 	} else
73 		bp = in_bp;
74 
75 	bp->b_un.b_addr = 0;
76 	if (datalen) {
77 		pdip = (A_TO_TRAN(ap))->tran_hba_dip;
78 		if (i_ddi_mem_alloc(pdip, &standard_dma_attr, datalen, 0,
79 		    0, NULL, &bp->b_un.b_addr, &rlen, NULL) != DDI_SUCCESS) {
80 			if (!in_bp)
81 				freerbuf(bp);
82 			goto no_resource;
83 		}
84 		bp->b_flags |= bflags;
85 	}
86 	bp->b_bcount = datalen;
87 	bp->b_resid = 0;
88 
89 	return (bp);
90 
91 no_resource:
92 	if (callback != NULL_FUNC && callback != SLEEP_FUNC) {
93 		ddi_set_callback(callback, callback_arg, &dcd_callback_id);
94 	}
95 
96 	return (NULL);
97 }
98 
99 
100 void
dcd_free_consistent_buf(struct buf * bp)101 dcd_free_consistent_buf(struct buf *bp)
102 {
103 
104 	if (!bp)
105 		return;
106 
107 	if (bp->b_un.b_addr)
108 		i_ddi_mem_free((caddr_t)bp->b_un.b_addr, NULL);
109 	freerbuf(bp);
110 	if (dcd_callback_id != 0L) {
111 		ddi_run_callback(&dcd_callback_id);
112 	}
113 
114 }
115 
116 struct dcd_pkt *
dcd_init_pkt(struct dcd_address * ap,struct dcd_pkt * in_pktp,struct buf * bp,int cmdlen,int statuslen,int pplen,int flags,int (* callback)(caddr_t),caddr_t callback_arg)117 dcd_init_pkt(struct dcd_address *ap, struct dcd_pkt *in_pktp,
118     struct buf *bp, int cmdlen, int statuslen, int pplen,
119     int flags, int (*callback)(caddr_t), caddr_t callback_arg)
120 {
121 	struct dcd_pkt *pktp;
122 	dcd_hba_tran_t	*tranp = ap->a_hba_tran;
123 	int		(*func)(caddr_t);
124 
125 #if defined(__x86)
126 	if (flags & PKT_CONSISTENT_OLD) {
127 		flags &= ~PKT_CONSISTENT_OLD;
128 		flags |= PKT_CONSISTENT;
129 	}
130 #endif	/* __x86 */
131 
132 	func = (callback == SLEEP_FUNC) ? SLEEP_FUNC : NULL_FUNC;
133 
134 	pktp = (*tranp->tran_init_pkt)(ap, in_pktp, bp, cmdlen,
135 	    statuslen, pplen, flags, func, NULL);
136 
137 	if (pktp == NULL) {
138 		if (callback != NULL_FUNC && callback != SLEEP_FUNC) {
139 			ddi_set_callback(callback, callback_arg,
140 			    &dcd_callback_id);
141 		}
142 	}
143 
144 	return (pktp);
145 }
146 
147 void
dcd_destroy_pkt(struct dcd_pkt * pkt)148 dcd_destroy_pkt(struct dcd_pkt *pkt)
149 {
150 
151 	struct dcd_address *ap = P_TO_ADDR(pkt);
152 
153 	(*A_TO_TRAN(ap)->tran_destroy_pkt)(ap, pkt);
154 
155 	if (dcd_callback_id != 0L) {
156 		ddi_run_callback(&dcd_callback_id);
157 	}
158 
159 }
160 
161 struct dcd_pkt *
dcd_resalloc(struct dcd_address * ap,int cmdlen,int statuslen,ataopaque_t dmatoken,int (* callback)())162 dcd_resalloc(struct dcd_address *ap, int cmdlen, int statuslen,
163     ataopaque_t dmatoken, int (*callback)())
164 {
165 
166 	register struct dcd_pkt *pkt;
167 	register dcd_hba_tran_t	*tranp = ap->a_hba_tran;
168 	register int		(*func)(caddr_t);
169 
170 
171 	func = (callback == SLEEP_FUNC) ? SLEEP_FUNC: NULL_FUNC;
172 	pkt = (*tranp->tran_init_pkt) (ap, NULL, (struct buf *)dmatoken,
173 	    cmdlen, statuslen, 0, 0, func, NULL);
174 
175 	if (pkt == NULL) {
176 		if (callback != NULL_FUNC && callback != SLEEP_FUNC) {
177 			ddi_set_callback(callback, NULL, &dcd_callback_id);
178 		}
179 	}
180 	return (pkt);
181 }
182 
183 
184 struct dcd_pkt *
dcd_pktalloc(struct dcd_address * ap,int cmdlen,int statuslen,int (* callback)())185 dcd_pktalloc(struct dcd_address *ap, int cmdlen, int statuslen,
186     int (*callback)())
187 {
188 
189 	struct dcd_pkt		*pkt;
190 	struct dcd_hba_tran	*tran = ap->a_hba_tran;
191 	register int		(*func)(caddr_t);
192 
193 
194 	func = (callback == SLEEP_FUNC) ? SLEEP_FUNC: NULL_FUNC;
195 
196 	pkt = (*tran->tran_init_pkt) (ap, NULL, NULL, cmdlen, statuslen,
197 	    0, 0, func, NULL);
198 	if (pkt == NULL) {
199 		if (callback != NULL_FUNC && callback != SLEEP_FUNC) {
200 			ddi_set_callback(callback, NULL, &dcd_callback_id);
201 		}
202 	}
203 	return (pkt);
204 }
205 
206 
207 struct dcd_pkt *
dcd_dmaget(struct dcd_pkt * pkt,ataopaque_t dmatoken,int (* callback)())208 dcd_dmaget(struct dcd_pkt *pkt, ataopaque_t dmatoken, int (*callback)())
209 {
210 
211 	struct dcd_pkt *new_pkt;
212 	register	int	(*func)(caddr_t);
213 
214 	func = (callback == SLEEP_FUNC) ? SLEEP_FUNC : NULL_FUNC;
215 
216 	new_pkt = (*P_TO_TRAN(pkt)->tran_init_pkt) (&pkt->pkt_address,
217 	    pkt, (struct buf *)dmatoken, 0, 0, 0, 0, func, NULL);
218 
219 	ASSERT(new_pkt == pkt || new_pkt == NULL);
220 	if (new_pkt == NULL) {
221 		if (callback != NULL_FUNC && callback != SLEEP_FUNC) {
222 			ddi_set_callback(callback, NULL, &dcd_callback_id);
223 		}
224 	}
225 
226 	return (pkt);
227 }
228 
229 
230 /*
231  * Generic Resource Allocation Routines
232  */
233 
234 void
dcd_dmafree(struct dcd_pkt * pkt)235 dcd_dmafree(struct dcd_pkt *pkt)
236 {
237 
238 	register struct dcd_address *ap = P_TO_ADDR(pkt);
239 
240 	(*A_TO_TRAN(ap)->tran_dmafree)(ap, pkt);
241 
242 	if (dcd_callback_id != 0L) {
243 		ddi_run_callback(&dcd_callback_id);
244 	}
245 
246 }
247 
248 void
dcd_sync_pkt(struct dcd_pkt * pkt)249 dcd_sync_pkt(struct dcd_pkt *pkt)
250 {
251 	register struct dcd_address *ap = P_TO_ADDR(pkt);
252 
253 	(*A_TO_TRAN(ap)->tran_sync_pkt) (ap, pkt);
254 }
255 
256 void
dcd_resfree(struct dcd_pkt * pkt)257 dcd_resfree(struct dcd_pkt *pkt)
258 {
259 
260 	register struct dcd_address *ap = P_TO_ADDR(pkt);
261 
262 	(*A_TO_TRAN(ap)->tran_destroy_pkt)(ap, pkt);
263 
264 	if (dcd_callback_id != 0L) {
265 		ddi_run_callback(&dcd_callback_id);
266 	}
267 }
268