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