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/scsi/scsi.h> 30 #include <sys/vtrace.h> 31 32 33 #define A_TO_TRAN(ap) ((ap)->a_hba_tran) 34 #define P_TO_TRAN(pkt) ((pkt)->pkt_address.a_hba_tran) 35 #define P_TO_ADDR(pkt) (&((pkt)->pkt_address)) 36 37 /* 38 * Callback id 39 */ 40 uintptr_t scsi_callback_id = 0; 41 42 43 44 struct buf * 45 scsi_alloc_consistent_buf(struct scsi_address *ap, 46 struct buf *in_bp, size_t datalen, uint_t bflags, 47 int (*callback)(caddr_t), caddr_t callback_arg) 48 { 49 dev_info_t *pdip; 50 struct buf *bp; 51 int kmflag; 52 53 TRACE_0(TR_FAC_SCSI_RES, TR_SCSI_ALLOC_CONSISTENT_BUF_START, 54 "scsi_alloc_consistent_buf_start"); 55 56 if (!in_bp) { 57 kmflag = (callback == SLEEP_FUNC) ? KM_SLEEP : KM_NOSLEEP; 58 if ((bp = getrbuf(kmflag)) == NULL) { 59 goto no_resource; 60 } 61 } else { 62 bp = in_bp; 63 64 /* we are establishing a new buffer memory association */ 65 bp->b_flags &= ~(B_PAGEIO | B_PHYS | B_REMAPPED | B_SHADOW); 66 bp->b_proc = NULL; 67 bp->b_pages = NULL; 68 bp->b_shadow = NULL; 69 } 70 71 /* limit bits that can be set by bflags argument */ 72 ASSERT(!(bflags & ~(B_READ | B_WRITE))); 73 bflags &= (B_READ | B_WRITE); 74 bp->b_un.b_addr = 0; 75 76 if (datalen) { 77 pdip = (A_TO_TRAN(ap))->tran_hba_dip; 78 79 while (ddi_iopb_alloc(pdip, (ddi_dma_lim_t *)0, datalen, 80 &bp->b_un.b_addr)) { 81 if (callback == SLEEP_FUNC) { 82 delay(drv_usectohz(10000)); 83 } else { 84 if (!in_bp) 85 freerbuf(bp); 86 goto no_resource; 87 } 88 } 89 bp->b_flags |= bflags; 90 } 91 bp->b_bcount = datalen; 92 bp->b_resid = 0; 93 94 TRACE_0(TR_FAC_SCSI_RES, TR_SCSI_ALLOC_CONSISTENT_BUF_END, 95 "scsi_alloc_consistent_buf_end"); 96 return (bp); 97 98 no_resource: 99 100 if (callback != NULL_FUNC && callback != SLEEP_FUNC) { 101 ddi_set_callback(callback, callback_arg, 102 &scsi_callback_id); 103 } 104 TRACE_0(TR_FAC_SCSI_RES, 105 TR_SCSI_ALLOC_CONSISTENT_BUF_RETURN1_END, 106 "scsi_alloc_consistent_buf_end (return1)"); 107 return (NULL); 108 } 109 110 void 111 scsi_free_consistent_buf(struct buf *bp) 112 { 113 TRACE_0(TR_FAC_SCSI_RES, TR_SCSI_FREE_CONSISTENT_BUF_START, 114 "scsi_free_consistent_buf_start"); 115 if (!bp) 116 return; 117 if (bp->b_un.b_addr) 118 ddi_iopb_free((caddr_t)bp->b_un.b_addr); 119 freerbuf(bp); 120 if (scsi_callback_id != 0) { 121 ddi_run_callback(&scsi_callback_id); 122 } 123 TRACE_0(TR_FAC_SCSI_RES, TR_SCSI_FREE_CONSISTENT_BUF_END, 124 "scsi_free_consistent_buf_end"); 125 } 126 127 struct scsi_pkt * 128 scsi_init_pkt(struct scsi_address *ap, struct scsi_pkt *in_pktp, 129 struct buf *bp, int cmdlen, int statuslen, int pplen, 130 int flags, int (*callback)(caddr_t), caddr_t callback_arg) 131 { 132 struct scsi_pkt *pktp; 133 scsi_hba_tran_t *tranp = ap->a_hba_tran; 134 int (*func)(caddr_t); 135 136 TRACE_5(TR_FAC_SCSI_RES, TR_SCSI_INIT_PKT_START, 137 "scsi_init_pkt_start: addr %p in_pktp %p cmdlen %d statuslen %d pplen %d", 138 ap, in_pktp, cmdlen, statuslen, pplen); 139 140 #if defined(__i386) || defined(__amd64) 141 if (flags & PKT_CONSISTENT_OLD) { 142 flags &= ~PKT_CONSISTENT_OLD; 143 flags |= PKT_CONSISTENT; 144 } 145 #endif 146 147 func = (callback == SLEEP_FUNC) ? SLEEP_FUNC : NULL_FUNC; 148 149 pktp = (*tranp->tran_init_pkt) (ap, in_pktp, bp, cmdlen, 150 statuslen, pplen, flags, func, NULL); 151 if (pktp == NULL) { 152 if (callback != NULL_FUNC && callback != SLEEP_FUNC) { 153 ddi_set_callback(callback, callback_arg, 154 &scsi_callback_id); 155 } 156 } 157 158 TRACE_1(TR_FAC_SCSI_RES, TR_SCSI_INIT_PKT_END, 159 "scsi_init_pkt_end: pktp %p", pktp); 160 return (pktp); 161 } 162 163 void 164 scsi_destroy_pkt(struct scsi_pkt *pkt) 165 { 166 struct scsi_address *ap = P_TO_ADDR(pkt); 167 168 TRACE_1(TR_FAC_SCSI_RES, TR_SCSI_DESTROY_PKT_START, 169 "scsi_destroy_pkt_start: pkt %p", pkt); 170 171 (*A_TO_TRAN(ap)->tran_destroy_pkt)(ap, pkt); 172 173 if (scsi_callback_id != 0) { 174 ddi_run_callback(&scsi_callback_id); 175 } 176 177 TRACE_0(TR_FAC_SCSI_RES, TR_SCSI_DESTROY_PKT_END, 178 "scsi_destroy_pkt_end"); 179 } 180 181 182 /* 183 * Generic Resource Allocation Routines 184 */ 185 186 struct scsi_pkt * 187 scsi_resalloc(struct scsi_address *ap, int cmdlen, int statuslen, 188 opaque_t dmatoken, int (*callback)()) 189 { 190 register struct scsi_pkt *pkt; 191 register scsi_hba_tran_t *tranp = ap->a_hba_tran; 192 register int (*func)(caddr_t); 193 194 func = (callback == SLEEP_FUNC) ? SLEEP_FUNC : NULL_FUNC; 195 196 pkt = (*tranp->tran_init_pkt) (ap, NULL, (struct buf *)dmatoken, 197 cmdlen, statuslen, 0, 0, func, NULL); 198 if (pkt == NULL) { 199 if (callback != NULL_FUNC && callback != SLEEP_FUNC) { 200 ddi_set_callback(callback, NULL, &scsi_callback_id); 201 } 202 } 203 204 return (pkt); 205 } 206 207 struct scsi_pkt * 208 scsi_pktalloc(struct scsi_address *ap, int cmdlen, int statuslen, 209 int (*callback)()) 210 { 211 struct scsi_pkt *pkt; 212 struct scsi_hba_tran *tran = ap->a_hba_tran; 213 register int (*func)(caddr_t); 214 215 func = (callback == SLEEP_FUNC) ? SLEEP_FUNC : NULL_FUNC; 216 217 pkt = (*tran->tran_init_pkt) (ap, NULL, NULL, cmdlen, 218 statuslen, 0, 0, func, NULL); 219 if (pkt == NULL) { 220 if (callback != NULL_FUNC && callback != SLEEP_FUNC) { 221 ddi_set_callback(callback, NULL, &scsi_callback_id); 222 } 223 } 224 225 return (pkt); 226 } 227 228 struct scsi_pkt * 229 scsi_dmaget(struct scsi_pkt *pkt, opaque_t dmatoken, int (*callback)()) 230 { 231 struct scsi_pkt *new_pkt; 232 register int (*func)(caddr_t); 233 234 func = (callback == SLEEP_FUNC) ? SLEEP_FUNC : NULL_FUNC; 235 236 new_pkt = (*P_TO_TRAN(pkt)->tran_init_pkt) (&pkt->pkt_address, 237 pkt, (struct buf *)dmatoken, 238 0, 0, 0, 0, func, NULL); 239 ASSERT(new_pkt == pkt || new_pkt == NULL); 240 if (new_pkt == NULL) { 241 if (callback != NULL_FUNC && callback != SLEEP_FUNC) { 242 ddi_set_callback(callback, NULL, &scsi_callback_id); 243 } 244 } 245 246 return (new_pkt); 247 } 248 249 250 /* 251 * Generic Resource Deallocation Routines 252 */ 253 254 void 255 scsi_dmafree(struct scsi_pkt *pkt) 256 { 257 register struct scsi_address *ap = P_TO_ADDR(pkt); 258 (*A_TO_TRAN(ap)->tran_dmafree)(ap, pkt); 259 260 if (scsi_callback_id != 0) { 261 ddi_run_callback(&scsi_callback_id); 262 } 263 } 264 265 void 266 scsi_sync_pkt(struct scsi_pkt *pkt) 267 { 268 register struct scsi_address *ap = P_TO_ADDR(pkt); 269 (*A_TO_TRAN(ap)->tran_sync_pkt)(ap, pkt); 270 } 271 272 void 273 scsi_resfree(struct scsi_pkt *pkt) 274 { 275 register struct scsi_address *ap = P_TO_ADDR(pkt); 276 (*A_TO_TRAN(ap)->tran_destroy_pkt)(ap, pkt); 277 278 if (scsi_callback_id != 0) { 279 ddi_run_callback(&scsi_callback_id); 280 } 281 } 282