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 2005 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 void scsi_free_cache_pkt(struct scsi_address *, struct scsi_pkt *); 128 129 struct scsi_pkt * 130 scsi_init_cache_pkt(struct scsi_address *ap, struct scsi_pkt *in_pktp, 131 struct buf *bp, int cmdlen, int statuslen, int pplen, 132 int flags, int (*callback)(caddr_t), caddr_t callback_arg) 133 { 134 struct scsi_pkt_cache_wrapper *pktw; 135 scsi_hba_tran_t *tranp = ap->a_hba_tran; 136 int (*func)(caddr_t); 137 138 func = (callback == SLEEP_FUNC) ? SLEEP_FUNC : NULL_FUNC; 139 140 if (in_pktp == NULL) { 141 int kf; 142 143 if (callback == SLEEP_FUNC) 144 kf = KM_SLEEP; 145 else 146 kf = KM_NOSLEEP; 147 pktw = kmem_cache_alloc(tranp->tran_pkt_cache_ptr, 148 kf); 149 if (pktw == NULL) 150 goto fail1; 151 152 pktw->pcw_kmflags = 0; 153 in_pktp = &(pktw->pcw_pkt); 154 /* 155 * target driver initializes pkt_comp, pkt_flags, 156 * and pkt_time 157 */ 158 in_pktp->pkt_address = *ap; 159 in_pktp->pkt_resid = 0; 160 in_pktp->pkt_state = 0; 161 in_pktp->pkt_statistics = 0; 162 in_pktp->pkt_reason = 0; 163 164 in_pktp->pkt_cdblen = cmdlen; 165 if ((tranp->tran_hba_flags & SCSI_HBA_TRAN_CDB) && 166 (cmdlen > DEFAULT_CDBLEN)) { 167 pktw->pcw_kmflags |= NEED_EXT_CDB; 168 in_pktp->pkt_cdbp = kmem_zalloc(cmdlen, kf); 169 if (in_pktp->pkt_cdbp == NULL) 170 goto fail2; 171 } 172 in_pktp->pkt_tgtlen = pplen; 173 if (pplen > DEFAULT_PRIVLEN) { 174 pktw->pcw_kmflags |= NEED_EXT_TGT; 175 in_pktp->pkt_private = kmem_zalloc(pplen, kf); 176 if (in_pktp->pkt_private == NULL) 177 goto fail3; 178 } 179 in_pktp->pkt_scblen = statuslen; 180 if ((tranp->tran_hba_flags & SCSI_HBA_TRAN_SCB) && 181 (statuslen > DEFAULT_SCBLEN)) { 182 pktw->pcw_kmflags |= NEED_EXT_SCB; 183 in_pktp->pkt_scbp = kmem_zalloc(statuslen, kf); 184 if (in_pktp->pkt_scbp == NULL) 185 goto fail4; 186 } 187 if ((*tranp->tran_setup_pkt) (in_pktp, 188 func, NULL) == -1) { 189 goto fail5; 190 } 191 } 192 if (bp && bp->b_bcount) { 193 if ((*tranp->tran_setup_bp) (in_pktp, bp, 194 flags, func, NULL) == -1) { 195 scsi_free_cache_pkt(ap, in_pktp); 196 in_pktp = NULL; 197 } 198 } 199 return (in_pktp); 200 201 fail5: 202 if (pktw->pcw_kmflags & NEED_EXT_SCB) { 203 kmem_free(in_pktp->pkt_scbp, statuslen); 204 in_pktp->pkt_scbp = (opaque_t)((char *)in_pktp + 205 tranp->tran_hba_len + DEFAULT_PRIVLEN + 206 sizeof (struct scsi_pkt)); 207 if ((A_TO_TRAN(ap))->tran_hba_flags & SCSI_HBA_TRAN_CDB) 208 in_pktp->pkt_scbp = (opaque_t)((in_pktp->pkt_scbp) + 209 DEFAULT_CDBLEN); 210 in_pktp->pkt_scblen = 0; 211 } 212 fail4: 213 if (pktw->pcw_kmflags & NEED_EXT_TGT) { 214 kmem_free(in_pktp->pkt_private, pplen); 215 in_pktp->pkt_tgtlen = 0; 216 in_pktp->pkt_private = NULL; 217 } 218 fail3: 219 if (pktw->pcw_kmflags & NEED_EXT_CDB) { 220 kmem_free(in_pktp->pkt_cdbp, cmdlen); 221 in_pktp->pkt_cdbp = (opaque_t)((char *)in_pktp + 222 tranp->tran_hba_len + 223 sizeof (struct scsi_pkt)); 224 in_pktp->pkt_cdblen = 0; 225 } 226 pktw->pcw_kmflags &= 227 ~(NEED_EXT_CDB|NEED_EXT_TGT|NEED_EXT_SCB); 228 fail2: 229 kmem_cache_free(tranp->tran_pkt_cache_ptr, pktw); 230 fail1: 231 if (callback != NULL_FUNC && callback != SLEEP_FUNC) { 232 ddi_set_callback(callback, callback_arg, 233 &scsi_callback_id); 234 } 235 236 return (NULL); 237 } 238 239 void 240 scsi_free_cache_pkt(struct scsi_address *ap, struct scsi_pkt *pktp) 241 { 242 struct scsi_pkt_cache_wrapper *pktw; 243 244 (*A_TO_TRAN(ap)->tran_teardown_pkt)(pktp); 245 pktw = (struct scsi_pkt_cache_wrapper *)pktp; 246 247 /* 248 * if we allocated memory for anything that wouldn't fit, free 249 * the memory and restore the pointers 250 */ 251 if (pktw->pcw_kmflags & NEED_EXT_SCB) { 252 kmem_free(pktp->pkt_scbp, pktp->pkt_scblen); 253 pktp->pkt_scbp = (opaque_t)((char *)pktp + 254 (A_TO_TRAN(ap))->tran_hba_len + 255 DEFAULT_PRIVLEN + sizeof (struct scsi_pkt_cache_wrapper)); 256 if ((A_TO_TRAN(ap))->tran_hba_flags & SCSI_HBA_TRAN_CDB) 257 pktp->pkt_scbp = (opaque_t)((pktp->pkt_scbp) + 258 DEFAULT_CDBLEN); 259 pktp->pkt_scblen = 0; 260 } 261 if (pktw->pcw_kmflags & NEED_EXT_TGT) { 262 kmem_free(pktp->pkt_private, pktp->pkt_tgtlen); 263 pktp->pkt_tgtlen = 0; 264 pktp->pkt_private = NULL; 265 } 266 if (pktw->pcw_kmflags & NEED_EXT_CDB) { 267 kmem_free(pktp->pkt_cdbp, pktp->pkt_cdblen); 268 pktp->pkt_cdbp = (opaque_t)((char *)pktp + 269 (A_TO_TRAN(ap))->tran_hba_len + 270 sizeof (struct scsi_pkt_cache_wrapper)); 271 pktp->pkt_cdblen = 0; 272 } 273 pktw->pcw_kmflags &= 274 ~(NEED_EXT_CDB|NEED_EXT_TGT|NEED_EXT_SCB); 275 ASSERT(pktw->pcw_kmflags == 0); 276 kmem_cache_free(A_TO_TRAN(ap)->tran_pkt_cache_ptr, pktw); 277 278 if (scsi_callback_id != 0) { 279 ddi_run_callback(&scsi_callback_id); 280 } 281 282 } 283 284 struct scsi_pkt * 285 scsi_init_pkt(struct scsi_address *ap, struct scsi_pkt *in_pktp, 286 struct buf *bp, int cmdlen, int statuslen, int pplen, 287 int flags, int (*callback)(caddr_t), caddr_t callback_arg) 288 { 289 struct scsi_pkt *pktp; 290 scsi_hba_tran_t *tranp = ap->a_hba_tran; 291 int (*func)(caddr_t); 292 293 TRACE_5(TR_FAC_SCSI_RES, TR_SCSI_INIT_PKT_START, 294 "scsi_init_pkt_start: addr %p in_pktp %p cmdlen %d statuslen %d pplen %d", 295 ap, in_pktp, cmdlen, statuslen, pplen); 296 297 #if defined(__i386) || defined(__amd64) 298 if (flags & PKT_CONSISTENT_OLD) { 299 flags &= ~PKT_CONSISTENT_OLD; 300 flags |= PKT_CONSISTENT; 301 } 302 #endif 303 304 func = (callback == SLEEP_FUNC) ? SLEEP_FUNC : NULL_FUNC; 305 306 pktp = (*tranp->tran_init_pkt) (ap, in_pktp, bp, cmdlen, 307 statuslen, pplen, flags, func, NULL); 308 if (pktp == NULL) { 309 if (callback != NULL_FUNC && callback != SLEEP_FUNC) { 310 ddi_set_callback(callback, callback_arg, 311 &scsi_callback_id); 312 } 313 } 314 315 TRACE_1(TR_FAC_SCSI_RES, TR_SCSI_INIT_PKT_END, 316 "scsi_init_pkt_end: pktp %p", pktp); 317 return (pktp); 318 } 319 320 void 321 scsi_destroy_pkt(struct scsi_pkt *pkt) 322 { 323 struct scsi_address *ap = P_TO_ADDR(pkt); 324 325 TRACE_1(TR_FAC_SCSI_RES, TR_SCSI_DESTROY_PKT_START, 326 "scsi_destroy_pkt_start: pkt %p", pkt); 327 328 (*A_TO_TRAN(ap)->tran_destroy_pkt)(ap, pkt); 329 330 if (scsi_callback_id != 0) { 331 ddi_run_callback(&scsi_callback_id); 332 } 333 334 TRACE_0(TR_FAC_SCSI_RES, TR_SCSI_DESTROY_PKT_END, 335 "scsi_destroy_pkt_end"); 336 } 337 338 339 /* 340 * Generic Resource Allocation Routines 341 */ 342 343 struct scsi_pkt * 344 scsi_resalloc(struct scsi_address *ap, int cmdlen, int statuslen, 345 opaque_t dmatoken, int (*callback)()) 346 { 347 register struct scsi_pkt *pkt; 348 register scsi_hba_tran_t *tranp = ap->a_hba_tran; 349 register int (*func)(caddr_t); 350 351 func = (callback == SLEEP_FUNC) ? SLEEP_FUNC : NULL_FUNC; 352 353 pkt = (*tranp->tran_init_pkt) (ap, NULL, (struct buf *)dmatoken, 354 cmdlen, statuslen, 0, 0, func, NULL); 355 if (pkt == NULL) { 356 if (callback != NULL_FUNC && callback != SLEEP_FUNC) { 357 ddi_set_callback(callback, NULL, &scsi_callback_id); 358 } 359 } 360 361 return (pkt); 362 } 363 364 struct scsi_pkt * 365 scsi_pktalloc(struct scsi_address *ap, int cmdlen, int statuslen, 366 int (*callback)()) 367 { 368 struct scsi_pkt *pkt; 369 struct scsi_hba_tran *tran = ap->a_hba_tran; 370 register int (*func)(caddr_t); 371 372 func = (callback == SLEEP_FUNC) ? SLEEP_FUNC : NULL_FUNC; 373 374 pkt = (*tran->tran_init_pkt) (ap, NULL, NULL, cmdlen, 375 statuslen, 0, 0, func, NULL); 376 if (pkt == NULL) { 377 if (callback != NULL_FUNC && callback != SLEEP_FUNC) { 378 ddi_set_callback(callback, NULL, &scsi_callback_id); 379 } 380 } 381 382 return (pkt); 383 } 384 385 struct scsi_pkt * 386 scsi_dmaget(struct scsi_pkt *pkt, opaque_t dmatoken, int (*callback)()) 387 { 388 struct scsi_pkt *new_pkt; 389 register int (*func)(caddr_t); 390 391 func = (callback == SLEEP_FUNC) ? SLEEP_FUNC : NULL_FUNC; 392 393 new_pkt = (*P_TO_TRAN(pkt)->tran_init_pkt) (&pkt->pkt_address, 394 pkt, (struct buf *)dmatoken, 395 0, 0, 0, 0, func, NULL); 396 ASSERT(new_pkt == pkt || new_pkt == NULL); 397 if (new_pkt == NULL) { 398 if (callback != NULL_FUNC && callback != SLEEP_FUNC) { 399 ddi_set_callback(callback, NULL, &scsi_callback_id); 400 } 401 } 402 403 return (new_pkt); 404 } 405 406 407 /* 408 * Generic Resource Deallocation Routines 409 */ 410 411 void 412 scsi_dmafree(struct scsi_pkt *pkt) 413 { 414 register struct scsi_address *ap = P_TO_ADDR(pkt); 415 (*A_TO_TRAN(ap)->tran_dmafree)(ap, pkt); 416 417 if (scsi_callback_id != 0) { 418 ddi_run_callback(&scsi_callback_id); 419 } 420 } 421 422 void 423 scsi_sync_pkt(struct scsi_pkt *pkt) 424 { 425 register struct scsi_address *ap = P_TO_ADDR(pkt); 426 (*A_TO_TRAN(ap)->tran_sync_pkt)(ap, pkt); 427 } 428 429 void 430 scsi_resfree(struct scsi_pkt *pkt) 431 { 432 register struct scsi_address *ap = P_TO_ADDR(pkt); 433 (*A_TO_TRAN(ap)->tran_destroy_pkt)(ap, pkt); 434 435 if (scsi_callback_id != 0) { 436 ddi_run_callback(&scsi_callback_id); 437 } 438 } 439