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