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 *
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)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
dcd_free_consistent_buf(struct buf * bp)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 *
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)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
dcd_destroy_pkt(struct dcd_pkt * pkt)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 *
dcd_resalloc(struct dcd_address * ap,int cmdlen,int statuslen,ataopaque_t dmatoken,int (* callback)())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 *
dcd_pktalloc(struct dcd_address * ap,int cmdlen,int statuslen,int (* callback)())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 *
dcd_dmaget(struct dcd_pkt * pkt,ataopaque_t dmatoken,int (* callback)())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
dcd_dmafree(struct dcd_pkt * pkt)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
dcd_sync_pkt(struct dcd_pkt * pkt)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
dcd_resfree(struct dcd_pkt * pkt)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