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 * 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 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 * 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 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 * 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 * 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 * 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 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 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 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