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 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <sys/dada/dada.h>
30 #include <sys/vtrace.h>
31 
32 #define	A_TO_TRAN(ap)	((ap)->a_hba_tran)
33 #define	P_TO_TRAN(pkt)	((pkt)->pkt_address.a_hba_tran)
34 #define	P_TO_ADDR(pkt)	(&((pkt)->pkt_address))
35 
36 /*
37  * Callback id
38  */
39 uintptr_t	dcd_callback_id = 0L;
40 
41 /* For i_ddi_mem_alloc() in dcd_alloc_consistent_buf() */
42 static ddi_dma_attr_t standard_dma_attr = {
43 	DMA_ATTR_V0,	/* version number */
44 	0x0,		/* lowest usable address */
45 	0xFFFFFFFFull,	/* high DMA address range */
46 	0xFFFFFFFFull,	/* DMA counter register */
47 	1,		/* DMA address alignment */
48 	1,		/* DMA burstsizes */
49 	1,		/* min effective DMA size */
50 	0xFFFFFFFFull,	/* max DMA xfer size */
51 	0xFFFFFFFFull,	/* segment boundary */
52 	1,		/* s/g list length */
53 	512,		/* granularity of device */
54 	0,		/* DMA transfer flags */
55 };
56 
57 struct buf *
58 dcd_alloc_consistent_buf(struct dcd_address *ap,
59 	struct buf *in_bp, size_t datalen, uint_t bflags,
60 	int (*callback)(caddr_t), caddr_t callback_arg)
61 {
62 
63 	dev_info_t	*pdip;
64 	struct	buf 	*bp;
65 	int		kmflag;
66 	size_t		rlen;
67 
68 
69 	if (!in_bp) {
70 		kmflag = (callback == SLEEP_FUNC) ? KM_SLEEP: KM_NOSLEEP;
71 		if ((bp = getrbuf(kmflag)) == NULL) {
72 			goto no_resource;
73 		}
74 	} else
75 		bp = in_bp;
76 
77 	bp->b_un.b_addr = 0;
78 	if (datalen) {
79 		pdip = (A_TO_TRAN(ap))->tran_hba_dip;
80 		if (i_ddi_mem_alloc(pdip, &standard_dma_attr, datalen, 0,
81 		    0, NULL, &bp->b_un.b_addr, &rlen, NULL) != DDI_SUCCESS) {
82 			if (!in_bp)
83 				freerbuf(bp);
84 			goto no_resource;
85 		}
86 		bp->b_flags |= bflags;
87 	}
88 	bp->b_bcount = datalen;
89 	bp->b_resid = 0;
90 
91 	return (bp);
92 
93 no_resource:
94 	if (callback != NULL_FUNC && callback != SLEEP_FUNC) {
95 		ddi_set_callback(callback, callback_arg, &dcd_callback_id);
96 	}
97 
98 	return (NULL);
99 }
100 
101 
102 void
103 dcd_free_consistent_buf(struct buf *bp)
104 {
105 
106 	if (!bp)
107 		return;
108 
109 	if (bp->b_un.b_addr)
110 		i_ddi_mem_free((caddr_t)bp->b_un.b_addr, NULL);
111 	freerbuf(bp);
112 	if (dcd_callback_id != 0L) {
113 		ddi_run_callback(&dcd_callback_id);
114 	}
115 
116 }
117 
118 struct dcd_pkt *
119 dcd_init_pkt(struct dcd_address *ap, struct dcd_pkt *in_pktp,
120 	struct buf *bp, int cmdlen, int statuslen, int pplen,
121 	int flags, int (*callback)(caddr_t), caddr_t callback_arg)
122 {
123 	struct dcd_pkt *pktp;
124 	dcd_hba_tran_t	*tranp = ap->a_hba_tran;
125 	int		(*func)(caddr_t);
126 
127 #if defined(__i386) || defined(__amd64)
128 	if (flags & PKT_CONSISTENT_OLD) {
129 		flags &= ~PKT_CONSISTENT_OLD;
130 		flags |= PKT_CONSISTENT;
131 	}
132 #endif	/* __i386 || __amd64 */
133 
134 	func = (callback == SLEEP_FUNC) ? SLEEP_FUNC : NULL_FUNC;
135 
136 	pktp = (*tranp->tran_init_pkt)(ap, in_pktp, bp, cmdlen,
137 		statuslen, pplen, flags, func, NULL);
138 
139 	if (pktp == NULL) {
140 		if (callback != NULL_FUNC && callback != SLEEP_FUNC) {
141 			ddi_set_callback(callback, callback_arg,
142 				&dcd_callback_id);
143 		}
144 	}
145 
146 	return (pktp);
147 }
148 
149 void
150 dcd_destroy_pkt(struct dcd_pkt *pkt)
151 {
152 
153 	struct dcd_address *ap = P_TO_ADDR(pkt);
154 
155 	(*A_TO_TRAN(ap)->tran_destroy_pkt)(ap, pkt);
156 
157 	if (dcd_callback_id != 0L) {
158 		ddi_run_callback(&dcd_callback_id);
159 	}
160 
161 }
162 
163 struct dcd_pkt *
164 dcd_resalloc(struct dcd_address *ap, int cmdlen, int statuslen,
165 	ataopaque_t dmatoken, int (*callback)())
166 {
167 
168 	register struct dcd_pkt *pkt;
169 	register dcd_hba_tran_t	*tranp = ap->a_hba_tran;
170 	register int		(*func)(caddr_t);
171 
172 
173 	func = (callback == SLEEP_FUNC) ? SLEEP_FUNC: NULL_FUNC;
174 	pkt = (*tranp->tran_init_pkt) (ap, NULL, (struct buf *)dmatoken,
175 		cmdlen, statuslen, 0, 0, func, NULL);
176 
177 	if (pkt == NULL) {
178 		if (callback != NULL_FUNC && callback != SLEEP_FUNC) {
179 			ddi_set_callback(callback, NULL, &dcd_callback_id);
180 		}
181 	}
182 	return (pkt);
183 }
184 
185 
186 struct dcd_pkt *
187 dcd_pktalloc(struct dcd_address *ap, int cmdlen, int statuslen,
188 	int (*callback)())
189 {
190 
191 	struct dcd_pkt 	*pkt;
192 	struct dcd_hba_tran	*tran = ap->a_hba_tran;
193 	register int 		(*func)(caddr_t);
194 
195 
196 	func = (callback == SLEEP_FUNC) ? SLEEP_FUNC: NULL_FUNC;
197 
198 	pkt = (*tran->tran_init_pkt) (ap, NULL, NULL, cmdlen, statuslen,
199 		0, 0, func, NULL);
200 	if (pkt == NULL) {
201 		if (callback != NULL_FUNC && callback != SLEEP_FUNC) {
202 			ddi_set_callback(callback, NULL, &dcd_callback_id);
203 		}
204 	}
205 	return (pkt);
206 }
207 
208 
209 struct dcd_pkt *
210 dcd_dmaget(struct dcd_pkt *pkt, ataopaque_t dmatoken, int (*callback)())
211 {
212 
213 	struct dcd_pkt *new_pkt;
214 	register	int	(*func)(caddr_t);
215 
216 	func = (callback == SLEEP_FUNC) ? SLEEP_FUNC : NULL_FUNC;
217 
218 	new_pkt = (*P_TO_TRAN(pkt)->tran_init_pkt) (&pkt->pkt_address,
219 		pkt, (struct buf *)dmatoken, 0, 0, 0, 0, func, NULL);
220 
221 	ASSERT(new_pkt == pkt || new_pkt == NULL);
222 	if (new_pkt == NULL) {
223 		if (callback != NULL_FUNC && callback != SLEEP_FUNC) {
224 			ddi_set_callback(callback, NULL, &dcd_callback_id);
225 		}
226 	}
227 
228 	return (pkt);
229 }
230 
231 
232 /*
233  * Generic Resource Allocation Routines
234  */
235 
236 void
237 dcd_dmafree(struct dcd_pkt *pkt)
238 {
239 
240 	register struct dcd_address *ap = P_TO_ADDR(pkt);
241 
242 	(*A_TO_TRAN(ap)->tran_dmafree)(ap, pkt);
243 
244 	if (dcd_callback_id != 0L) {
245 		ddi_run_callback(&dcd_callback_id);
246 	}
247 
248 }
249 
250 void
251 dcd_sync_pkt(struct dcd_pkt *pkt)
252 {
253 	register struct dcd_address *ap = P_TO_ADDR(pkt);
254 
255 	(*A_TO_TRAN(ap)->tran_sync_pkt) (ap, pkt);
256 }
257 
258 void
259 dcd_resfree(struct dcd_pkt *pkt)
260 {
261 
262 	register struct dcd_address *ap = P_TO_ADDR(pkt);
263 
264 	(*A_TO_TRAN(ap)->tran_destroy_pkt)(ap, pkt);
265 
266 	if (dcd_callback_id != 0L) {
267 		ddi_run_callback(&dcd_callback_id);
268 	}
269 }
270