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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2004 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 42 struct buf * 43 dcd_alloc_consistent_buf(struct dcd_address *ap, 44 struct buf *in_bp, size_t datalen, uint_t bflags, 45 int (*callback)(caddr_t), caddr_t callback_arg) 46 { 47 48 dev_info_t *pdip; 49 struct buf *bp; 50 int kmflag; 51 52 53 if (!in_bp) { 54 kmflag = (callback == SLEEP_FUNC) ? KM_SLEEP: KM_NOSLEEP; 55 if ((bp = getrbuf(kmflag)) == NULL) { 56 goto no_resource; 57 } 58 } else 59 bp = in_bp; 60 61 bp->b_un.b_addr = 0; 62 if (datalen) { 63 pdip = (A_TO_TRAN(ap))->tran_hba_dip; 64 65 if (ddi_iopb_alloc(pdip, (ddi_dma_lim_t *)0, datalen, 66 &bp->b_un.b_addr)) { 67 if (!in_bp) 68 freerbuf(bp); 69 goto no_resource; 70 } 71 bp->b_flags |= bflags; 72 } 73 bp->b_bcount = datalen; 74 bp->b_resid = 0; 75 76 return (bp); 77 78 no_resource: 79 if (callback != NULL_FUNC && callback != SLEEP_FUNC) { 80 ddi_set_callback(callback, callback_arg, &dcd_callback_id); 81 } 82 83 return (NULL); 84 } 85 86 87 void 88 dcd_free_consistent_buf(struct buf *bp) 89 { 90 91 if (!bp) 92 return; 93 94 if (bp->b_un.b_addr) 95 ddi_iopb_free((caddr_t)bp->b_un.b_addr); 96 freerbuf(bp); 97 if (dcd_callback_id != 0L) { 98 ddi_run_callback(&dcd_callback_id); 99 } 100 101 } 102 103 struct dcd_pkt * 104 dcd_init_pkt(struct dcd_address *ap, struct dcd_pkt *in_pktp, 105 struct buf *bp, int cmdlen, int statuslen, int pplen, 106 int flags, int (*callback)(caddr_t), caddr_t callback_arg) 107 { 108 struct dcd_pkt *pktp; 109 dcd_hba_tran_t *tranp = ap->a_hba_tran; 110 int (*func)(caddr_t); 111 112 #if defined(__i386) || defined(__amd64) 113 if (flags & PKT_CONSISTENT_OLD) { 114 flags &= ~PKT_CONSISTENT_OLD; 115 flags |= PKT_CONSISTENT; 116 } 117 #endif /* __i386 || __amd64 */ 118 119 func = (callback == SLEEP_FUNC) ? SLEEP_FUNC : NULL_FUNC; 120 121 pktp = (*tranp->tran_init_pkt)(ap, in_pktp, bp, cmdlen, 122 statuslen, pplen, flags, func, NULL); 123 124 if (pktp == NULL) { 125 if (callback != NULL_FUNC && callback != SLEEP_FUNC) { 126 ddi_set_callback(callback, callback_arg, 127 &dcd_callback_id); 128 } 129 } 130 131 return (pktp); 132 } 133 134 void 135 dcd_destroy_pkt(struct dcd_pkt *pkt) 136 { 137 138 struct dcd_address *ap = P_TO_ADDR(pkt); 139 140 (*A_TO_TRAN(ap)->tran_destroy_pkt)(ap, pkt); 141 142 if (dcd_callback_id != 0L) { 143 ddi_run_callback(&dcd_callback_id); 144 } 145 146 } 147 148 struct dcd_pkt * 149 dcd_resalloc(struct dcd_address *ap, int cmdlen, int statuslen, 150 ataopaque_t dmatoken, int (*callback)()) 151 { 152 153 register struct dcd_pkt *pkt; 154 register dcd_hba_tran_t *tranp = ap->a_hba_tran; 155 register int (*func)(caddr_t); 156 157 158 func = (callback == SLEEP_FUNC) ? SLEEP_FUNC: NULL_FUNC; 159 pkt = (*tranp->tran_init_pkt) (ap, NULL, (struct buf *)dmatoken, 160 cmdlen, statuslen, 0, 0, func, NULL); 161 162 if (pkt == NULL) { 163 if (callback != NULL_FUNC && callback != SLEEP_FUNC) { 164 ddi_set_callback(callback, NULL, &dcd_callback_id); 165 } 166 } 167 return (pkt); 168 } 169 170 171 struct dcd_pkt * 172 dcd_pktalloc(struct dcd_address *ap, int cmdlen, int statuslen, 173 int (*callback)()) 174 { 175 176 struct dcd_pkt *pkt; 177 struct dcd_hba_tran *tran = ap->a_hba_tran; 178 register int (*func)(caddr_t); 179 180 181 func = (callback == SLEEP_FUNC) ? SLEEP_FUNC: NULL_FUNC; 182 183 pkt = (*tran->tran_init_pkt) (ap, NULL, NULL, cmdlen, statuslen, 184 0, 0, func, NULL); 185 if (pkt == NULL) { 186 if (callback != NULL_FUNC && callback != SLEEP_FUNC) { 187 ddi_set_callback(callback, NULL, &dcd_callback_id); 188 } 189 } 190 return (pkt); 191 } 192 193 194 struct dcd_pkt * 195 dcd_dmaget(struct dcd_pkt *pkt, ataopaque_t dmatoken, int (*callback)()) 196 { 197 198 struct dcd_pkt *new_pkt; 199 register int (*func)(caddr_t); 200 201 func = (callback == SLEEP_FUNC) ? SLEEP_FUNC : NULL_FUNC; 202 203 new_pkt = (*P_TO_TRAN(pkt)->tran_init_pkt) (&pkt->pkt_address, 204 pkt, (struct buf *)dmatoken, 0, 0, 0, 0, func, NULL); 205 206 ASSERT(new_pkt == pkt || new_pkt == NULL); 207 if (new_pkt == NULL) { 208 if (callback != NULL_FUNC && callback != SLEEP_FUNC) { 209 ddi_set_callback(callback, NULL, &dcd_callback_id); 210 } 211 } 212 213 return (pkt); 214 } 215 216 217 /* 218 * Generic Resource Allocation Routines 219 */ 220 221 void 222 dcd_dmafree(struct dcd_pkt *pkt) 223 { 224 225 register struct dcd_address *ap = P_TO_ADDR(pkt); 226 227 (*A_TO_TRAN(ap)->tran_dmafree)(ap, pkt); 228 229 if (dcd_callback_id != 0L) { 230 ddi_run_callback(&dcd_callback_id); 231 } 232 233 } 234 235 void 236 dcd_sync_pkt(struct dcd_pkt *pkt) 237 { 238 register struct dcd_address *ap = P_TO_ADDR(pkt); 239 240 (*A_TO_TRAN(ap)->tran_sync_pkt) (ap, pkt); 241 } 242 243 void 244 dcd_resfree(struct dcd_pkt *pkt) 245 { 246 247 register struct dcd_address *ap = P_TO_ADDR(pkt); 248 249 (*A_TO_TRAN(ap)->tran_destroy_pkt)(ap, pkt); 250 251 if (dcd_callback_id != 0L) { 252 ddi_run_callback(&dcd_callback_id); 253 } 254 } 255