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 2009 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  */
  26 
  27 #include <sys/scsi/scsi.h>
  28 #include <sys/vtrace.h>
  29 
  30 
  31 #define A_TO_TRAN(ap)   ((ap)->a_hba_tran)
  32 #define P_TO_TRAN(pkt)  ((pkt)->pkt_address.a_hba_tran)
  33 #define P_TO_ADDR(pkt)  (&((pkt)->pkt_address))
  34 
  35 /*
  36  * Callback id
  37  */
  38 uintptr_t scsi_callback_id = 0;
  39 
  40 extern ddi_dma_attr_t scsi_alloc_attr;
  41 
  42 struct buf *
  43 scsi_alloc_consistent_buf(struct scsi_address *ap,
  44     struct buf *in_bp, size_t datalen, uint_t bflags,
  45     int (*callback)(caddr_t), caddr_t callback_arg)
  46 {
  47         dev_info_t      *pdip;
  48         struct          buf *bp;
  49         int             kmflag;
  50         size_t          rlen;
  51 
  52         TRACE_0(TR_FAC_SCSI_RES, TR_SCSI_ALLOC_CONSISTENT_BUF_START,
  53             "scsi_alloc_consistent_buf_start");
  54 
  55         if (!in_bp) {
  56                 kmflag = (callback == SLEEP_FUNC) ? KM_SLEEP : KM_NOSLEEP;
  57                 if ((bp = getrbuf(kmflag)) == NULL) {
  58                         goto no_resource;
  59                 }
  60         } else {
  61                 bp = in_bp;
  62 
  63                 /* we are establishing a new buffer memory association */
  64                 bp->b_flags &= ~(B_PAGEIO | B_PHYS | B_REMAPPED | B_SHADOW);
  65                 bp->b_proc = NULL;
  66                 bp->b_pages = NULL;
  67                 bp->b_shadow = NULL;
  68         }
  69 
  70         /* limit bits that can be set by bflags argument */
  71         ASSERT(!(bflags & ~(B_READ | B_WRITE)));
  72         bflags &= (B_READ | B_WRITE);
  73         bp->b_un.b_addr = 0;
  74 
  75         if (datalen) {
  76                 pdip = (A_TO_TRAN(ap))->tran_hba_dip;
  77 
  78                 /*
  79                  * use i_ddi_mem_alloc() for now until we have an interface to
  80                  * allocate memory for DMA which doesn't require a DMA handle.
  81                  * ddi_iopb_alloc() is obsolete and we want more flexibility in
  82                  * controlling the DMA address constraints.
  83                  */
  84                 while (i_ddi_mem_alloc(pdip, &scsi_alloc_attr, datalen,
  85                     ((callback == SLEEP_FUNC) ? 1 : 0), 0, NULL,
  86                     &bp->b_un.b_addr, &rlen, NULL) != DDI_SUCCESS) {
  87                         if (callback == SLEEP_FUNC) {
  88                                 delay(drv_usectohz(10000));
  89                         } else {
  90                                 if (!in_bp)
  91                                         freerbuf(bp);
  92                                 goto no_resource;
  93                         }
  94                 }
  95                 bp->b_flags |= bflags;
  96         }
  97         bp->b_bcount = datalen;
  98         bp->b_resid = 0;
  99 
 100         TRACE_0(TR_FAC_SCSI_RES, TR_SCSI_ALLOC_CONSISTENT_BUF_END,
 101             "scsi_alloc_consistent_buf_end");
 102         return (bp);
 103 
 104 no_resource:
 105 
 106         if (callback != NULL_FUNC && callback != SLEEP_FUNC) {
 107                 ddi_set_callback(callback, callback_arg,
 108                     &scsi_callback_id);
 109         }
 110         TRACE_0(TR_FAC_SCSI_RES,
 111             TR_SCSI_ALLOC_CONSISTENT_BUF_RETURN1_END,
 112             "scsi_alloc_consistent_buf_end (return1)");
 113         return (NULL);
 114 }
 115 
 116 void
 117 scsi_free_consistent_buf(struct buf *bp)
 118 {
 119         TRACE_0(TR_FAC_SCSI_RES, TR_SCSI_FREE_CONSISTENT_BUF_START,
 120             "scsi_free_consistent_buf_start");
 121         if (!bp)
 122                 return;
 123         if (bp->b_un.b_addr)
 124                 i_ddi_mem_free((caddr_t)bp->b_un.b_addr, NULL);
 125         freerbuf(bp);
 126         if (scsi_callback_id != 0) {
 127                 ddi_run_callback(&scsi_callback_id);
 128         }
 129         TRACE_0(TR_FAC_SCSI_RES, TR_SCSI_FREE_CONSISTENT_BUF_END,
 130             "scsi_free_consistent_buf_end");
 131 }
 132 
 133 void
 134 scsi_dmafree_attr(struct scsi_pkt *pktp)
 135 {
 136         struct scsi_pkt_cache_wrapper *pktw =
 137             (struct scsi_pkt_cache_wrapper *)pktp;
 138 
 139         if (pktw->pcw_flags & PCW_BOUND) {
 140                 if (ddi_dma_unbind_handle(pktp->pkt_handle) !=
 141                     DDI_SUCCESS)
 142                         cmn_err(CE_WARN, "scsi_dmafree_attr: "
 143                             "unbind handle failed");
 144                 pktw->pcw_flags &= ~PCW_BOUND;
 145         }
 146         pktp->pkt_numcookies = 0;
 147         pktw->pcw_totalwin = 0;
 148 }
 149 
 150 struct buf *
 151 scsi_pkt2bp(struct scsi_pkt *pkt)
 152 {
 153         return (((struct scsi_pkt_cache_wrapper *)pkt)->pcw_bp);
 154 }
 155 
 156 int
 157 scsi_dma_buf_bind_attr(struct scsi_pkt_cache_wrapper *pktw,
 158                         struct buf      *bp,
 159                         int              dma_flags,
 160                         int             (*callback)(),
 161                         caddr_t          arg)
 162 {
 163         struct scsi_pkt *pktp = &(pktw->pcw_pkt);
 164         int      status;
 165 
 166         /*
 167          * First time, need to establish the handle.
 168          */
 169 
 170         ASSERT(pktp->pkt_numcookies == 0);
 171         ASSERT(pktw->pcw_totalwin == 0);
 172 
 173         status = ddi_dma_buf_bind_handle(pktp->pkt_handle, bp, dma_flags,
 174             callback, arg, &pktw->pcw_cookie,
 175             &pktp->pkt_numcookies);
 176 
 177         switch (status) {
 178         case DDI_DMA_MAPPED:
 179                 pktw->pcw_totalwin = 1;
 180                 break;
 181 
 182         case DDI_DMA_PARTIAL_MAP:
 183                 /* enable first call to ddi_dma_getwin */
 184                 if (ddi_dma_numwin(pktp->pkt_handle,
 185                     &pktw->pcw_totalwin) != DDI_SUCCESS) {
 186                         bp->b_error = 0;
 187                         return (0);
 188                 }
 189                 break;
 190 
 191         case DDI_DMA_NORESOURCES:
 192                 bp->b_error = 0;
 193                 return (0);
 194 
 195         case DDI_DMA_TOOBIG:
 196                 bioerror(bp, EINVAL);
 197                 return (0);
 198 
 199         case DDI_DMA_NOMAPPING:
 200         case DDI_DMA_INUSE:
 201         default:
 202                 bioerror(bp, EFAULT);
 203                 return (0);
 204         }
 205 
 206         /* initialize the loop controls for scsi_dmaget_attr() */
 207         pktw->pcw_curwin = 0;
 208         pktw->pcw_total_xfer = 0;
 209         pktp->pkt_dma_flags = dma_flags;
 210         return (1);
 211 }
 212 
 213 #if defined(_DMA_USES_PHYSADDR)
 214 int
 215 scsi_dmaget_attr(struct scsi_pkt_cache_wrapper *pktw)
 216 {
 217         struct scsi_pkt *pktp = &(pktw->pcw_pkt);
 218 
 219         int             status;
 220         int             num_segs = 0;
 221         ddi_dma_impl_t  *hp = (ddi_dma_impl_t *)pktp->pkt_handle;
 222         ddi_dma_cookie_t *cp;
 223 
 224         if (pktw->pcw_curwin != 0) {
 225                 ddi_dma_cookie_t        cookie;
 226 
 227                 /*
 228                  * start the next window, and get its first cookie
 229                  */
 230                 status = ddi_dma_getwin(pktp->pkt_handle,
 231                     pktw->pcw_curwin, &pktp->pkt_dma_offset,
 232                     &pktp->pkt_dma_len, &cookie,
 233                     &pktp->pkt_numcookies);
 234                 if (status != DDI_SUCCESS)
 235                         return (0);
 236         }
 237 
 238         /*
 239          * start the Scatter/Gather loop
 240          */
 241         cp = hp->dmai_cookie - 1;
 242         pktp->pkt_dma_len = 0;
 243         for (;;) {
 244 
 245                 /* take care of the loop-bookkeeping */
 246                 pktp->pkt_dma_len += cp->dmac_size;
 247                 num_segs++;
 248                 /*
 249                  * if this was the last cookie in the current window
 250                  * set the loop controls start the next window and
 251                  * exit so the HBA can do this partial transfer
 252                  */
 253                 if (num_segs >= pktp->pkt_numcookies) {
 254                         pktw->pcw_curwin++;
 255                         break;
 256                 }
 257 
 258                 cp++;
 259         }
 260         pktw->pcw_total_xfer += pktp->pkt_dma_len;
 261         pktp->pkt_cookies = hp->dmai_cookie - 1;
 262         hp->dmai_cookie = cp;
 263 
 264         return (1);
 265 }
 266 #endif
 267 
 268 void scsi_free_cache_pkt(struct scsi_address *, struct scsi_pkt *);
 269 
 270 struct scsi_pkt *
 271 scsi_init_cache_pkt(struct scsi_address *ap, struct scsi_pkt *in_pktp,
 272     struct buf *bp, int cmdlen, int statuslen, int pplen,
 273     int flags, int (*callback)(caddr_t), caddr_t callback_arg)
 274 {
 275         struct scsi_pkt_cache_wrapper *pktw;
 276         scsi_hba_tran_t *tranp = ap->a_hba_tran;
 277         int             (*func)(caddr_t);
 278 
 279         func = (callback == SLEEP_FUNC) ? SLEEP_FUNC : NULL_FUNC;
 280 
 281         if (in_pktp == NULL) {
 282                 int kf;
 283 
 284                 if (callback == SLEEP_FUNC)
 285                         kf = KM_SLEEP;
 286                 else
 287                         kf = KM_NOSLEEP;
 288                 /*
 289                  * By using kmem_cache_alloc(), the layout of the
 290                  * scsi_pkt, scsi_pkt_cache_wrapper, hba private data,
 291                  * cdb, tgt driver private data, and status block is
 292                  * as below.
 293                  *
 294                  * This is a piece of contiguous memory starting from
 295                  * the first structure field scsi_pkt in the struct
 296                  * scsi_pkt_cache_wrapper, followed by the hba private
 297                  * data, pkt_cdbp, the tgt driver private data and
 298                  * pkt_scbp.
 299                  *
 300                  * |----------------------------|--------------------->
 301                  * |    struct scsi_pkt         |       struct
 302                  * |    ......                  |scsi_pkt_cache_wrapper
 303                  * |    pcw_flags               |
 304                  * |----------------------------|<---------------------
 305                  * |    hba private data        |tranp->tran_hba_len
 306                  * |----------------------------|
 307                  * |    pkt_cdbp                |DEFAULT_CDBLEN
 308                  * |----------------------------|
 309                  * |    tgt private data        |DEFAULT_PRIVLEN
 310                  * |----------------------------|
 311                  * |    pkt_scbp                |DEFAULT_SCBLEN
 312                  * |----------------------------|
 313                  *
 314                  * If the actual data length of the cdb, or the tgt
 315                  * driver private data, or the status block is bigger
 316                  * than the default data length, kmem_alloc() will be
 317                  * called to get extra space.
 318                  */
 319                 pktw = kmem_cache_alloc(tranp->tran_pkt_cache_ptr,
 320                     kf);
 321                 if (pktw == NULL)
 322                         goto fail1;
 323 
 324                 pktw->pcw_flags = 0;
 325                 in_pktp = &(pktw->pcw_pkt);
 326                 in_pktp->pkt_address = *ap;
 327 
 328                 /*
 329                  * target drivers should initialize pkt_comp and
 330                  * pkt_time, but sometimes they don't so initialize
 331                  * them here to be safe.
 332                  */
 333                 in_pktp->pkt_flags = 0;
 334                 in_pktp->pkt_time = 0;
 335                 in_pktp->pkt_resid = 0;
 336                 in_pktp->pkt_state = 0;
 337                 in_pktp->pkt_statistics = 0;
 338                 in_pktp->pkt_reason = 0;
 339                 in_pktp->pkt_dma_offset = 0;
 340                 in_pktp->pkt_dma_len = 0;
 341                 in_pktp->pkt_dma_flags = 0;
 342                 in_pktp->pkt_path_instance = 0;
 343                 ASSERT(in_pktp->pkt_numcookies == 0);
 344                 pktw->pcw_curwin = 0;
 345                 pktw->pcw_totalwin = 0;
 346                 pktw->pcw_total_xfer = 0;
 347 
 348                 in_pktp->pkt_cdblen = cmdlen;
 349                 if ((tranp->tran_hba_flags & SCSI_HBA_TRAN_CDB) &&
 350                     (cmdlen > DEFAULT_CDBLEN)) {
 351                         pktw->pcw_flags |= PCW_NEED_EXT_CDB;
 352                         in_pktp->pkt_cdbp = kmem_alloc(cmdlen, kf);
 353                         if (in_pktp->pkt_cdbp == NULL)
 354                                 goto fail2;
 355                 }
 356                 in_pktp->pkt_tgtlen = pplen;
 357                 if (pplen > DEFAULT_PRIVLEN) {
 358                         pktw->pcw_flags |= PCW_NEED_EXT_TGT;
 359                         in_pktp->pkt_private = kmem_alloc(pplen, kf);
 360                         if (in_pktp->pkt_private == NULL)
 361                                 goto fail3;
 362                 }
 363                 in_pktp->pkt_scblen = statuslen;
 364                 if ((tranp->tran_hba_flags & SCSI_HBA_TRAN_SCB) &&
 365                     (statuslen > DEFAULT_SCBLEN)) {
 366                         pktw->pcw_flags |= PCW_NEED_EXT_SCB;
 367                         in_pktp->pkt_scbp = kmem_alloc(statuslen, kf);
 368                         if (in_pktp->pkt_scbp == NULL)
 369                                 goto fail4;
 370                 }
 371                 if ((*tranp->tran_setup_pkt) (in_pktp,
 372                     func, NULL) == -1) {
 373                                 goto fail5;
 374                 }
 375                 if (cmdlen)
 376                         bzero((void *)in_pktp->pkt_cdbp, cmdlen);
 377                 if (pplen)
 378                         bzero((void *)in_pktp->pkt_private, pplen);
 379                 if (statuslen)
 380                         bzero((void *)in_pktp->pkt_scbp, statuslen);
 381         } else
 382                 pktw = (struct scsi_pkt_cache_wrapper *)in_pktp;
 383 
 384         if (bp && bp->b_bcount) {
 385 
 386                 int dma_flags = 0;
 387 
 388                 /*
 389                  * we need to transfer data, so we alloc dma resources
 390                  * for this packet
 391                  */
 392                 /*CONSTCOND*/
 393                 ASSERT(SLEEP_FUNC == DDI_DMA_SLEEP);
 394                 /*CONSTCOND*/
 395                 ASSERT(NULL_FUNC == DDI_DMA_DONTWAIT);
 396 
 397 #if defined(_DMA_USES_PHYSADDR)
 398                 /*
 399                  * with an IOMMU we map everything, so we don't
 400                  * need to bother with this
 401                  */
 402                 if (tranp->tran_dma_attr.dma_attr_granular !=
 403                     pktw->pcw_granular) {
 404 
 405                         ddi_dma_free_handle(&in_pktp->pkt_handle);
 406                         if (ddi_dma_alloc_handle(tranp->tran_hba_dip,
 407                             &tranp->tran_dma_attr,
 408                             func, NULL,
 409                             &in_pktp->pkt_handle) != DDI_SUCCESS) {
 410 
 411                                 in_pktp->pkt_handle = NULL;
 412                                 return (NULL);
 413                         }
 414                         pktw->pcw_granular =
 415                             tranp->tran_dma_attr.dma_attr_granular;
 416                 }
 417 #endif
 418 
 419                 if (in_pktp->pkt_numcookies == 0) {
 420                         pktw->pcw_bp = bp;
 421                         /*
 422                          * set dma flags; the "read" case must be first
 423                          * since B_WRITE isn't always be set for writes.
 424                          */
 425                         if (bp->b_flags & B_READ) {
 426                                 dma_flags |= DDI_DMA_READ;
 427                         } else {
 428                                 dma_flags |= DDI_DMA_WRITE;
 429                         }
 430                         if (flags & PKT_CONSISTENT)
 431                                 dma_flags |= DDI_DMA_CONSISTENT;
 432                         if (flags & PKT_DMA_PARTIAL)
 433                                 dma_flags |= DDI_DMA_PARTIAL;
 434 
 435 #if defined(__sparc)
 436                         /*
 437                          * workaround for byte hole issue on psycho and
 438                          * schizo pre 2.1
 439                          */
 440                         if ((bp->b_flags & B_READ) && ((bp->b_flags &
 441                             (B_PAGEIO|B_REMAPPED)) != B_PAGEIO) &&
 442                             (((uintptr_t)bp->b_un.b_addr & 0x7) ||
 443                             ((uintptr_t)bp->b_bcount & 0x7))) {
 444                                 dma_flags |= DDI_DMA_CONSISTENT;
 445                         }
 446 #endif
 447                         if (!scsi_dma_buf_bind_attr(pktw, bp,
 448                             dma_flags, callback, callback_arg)) {
 449                                 return (NULL);
 450                         } else {
 451                                 pktw->pcw_flags |= PCW_BOUND;
 452                         }
 453                 }
 454 
 455 #if defined(_DMA_USES_PHYSADDR)
 456                 if (!scsi_dmaget_attr(pktw)) {
 457                         scsi_dmafree_attr(in_pktp);
 458                         goto fail5;
 459                 }
 460 #else
 461                 in_pktp->pkt_cookies = &pktw->pcw_cookie;
 462                 in_pktp->pkt_dma_len = pktw->pcw_cookie.dmac_size;
 463                 pktw->pcw_total_xfer += in_pktp->pkt_dma_len;
 464 #endif
 465                 ASSERT(in_pktp->pkt_numcookies <=
 466                     tranp->tran_dma_attr.dma_attr_sgllen);
 467                 ASSERT(pktw->pcw_total_xfer <= bp->b_bcount);
 468                 in_pktp->pkt_resid = bp->b_bcount -
 469                     pktw->pcw_total_xfer;
 470 
 471                 ASSERT((in_pktp->pkt_resid % pktw->pcw_granular) ==
 472                     0);
 473         } else {
 474                 /* !bp or no b_bcount */
 475                 in_pktp->pkt_resid = 0;
 476         }
 477         return (in_pktp);
 478 
 479 fail5:
 480         if (pktw->pcw_flags & PCW_NEED_EXT_SCB) {
 481                 kmem_free(in_pktp->pkt_scbp, statuslen);
 482                 in_pktp->pkt_scbp = (opaque_t)((char *)in_pktp +
 483                     tranp->tran_hba_len + DEFAULT_PRIVLEN +
 484                     sizeof (struct scsi_pkt_cache_wrapper));
 485                 if ((A_TO_TRAN(ap))->tran_hba_flags & SCSI_HBA_TRAN_CDB)
 486                         in_pktp->pkt_scbp = (opaque_t)((in_pktp->pkt_scbp) +
 487                             DEFAULT_CDBLEN);
 488                 in_pktp->pkt_scblen = 0;
 489         }
 490 fail4:
 491         if (pktw->pcw_flags & PCW_NEED_EXT_TGT) {
 492                 kmem_free(in_pktp->pkt_private, pplen);
 493                 in_pktp->pkt_tgtlen = 0;
 494                 in_pktp->pkt_private = NULL;
 495         }
 496 fail3:
 497         if (pktw->pcw_flags & PCW_NEED_EXT_CDB) {
 498                 kmem_free(in_pktp->pkt_cdbp, cmdlen);
 499                 in_pktp->pkt_cdbp = (opaque_t)((char *)in_pktp +
 500                     tranp->tran_hba_len +
 501                     sizeof (struct scsi_pkt_cache_wrapper));
 502                 in_pktp->pkt_cdblen = 0;
 503         }
 504         pktw->pcw_flags &=
 505             ~(PCW_NEED_EXT_CDB|PCW_NEED_EXT_TGT|PCW_NEED_EXT_SCB);
 506 fail2:
 507         kmem_cache_free(tranp->tran_pkt_cache_ptr, pktw);
 508 fail1:
 509         if (callback != NULL_FUNC && callback != SLEEP_FUNC) {
 510                 ddi_set_callback(callback, callback_arg,
 511                     &scsi_callback_id);
 512         }
 513 
 514         return (NULL);
 515 }
 516 
 517 void
 518 scsi_free_cache_pkt(struct scsi_address *ap, struct scsi_pkt *pktp)
 519 {
 520         struct scsi_pkt_cache_wrapper *pktw;
 521 
 522         (*A_TO_TRAN(ap)->tran_teardown_pkt)(pktp);
 523         pktw = (struct scsi_pkt_cache_wrapper *)pktp;
 524         if (pktw->pcw_flags & PCW_BOUND)
 525                 scsi_dmafree_attr(pktp);
 526 
 527         /*
 528          * if we allocated memory for anything that wouldn't fit, free
 529          * the memory and restore the pointers
 530          */
 531         if (pktw->pcw_flags & PCW_NEED_EXT_SCB) {
 532                 kmem_free(pktp->pkt_scbp, pktp->pkt_scblen);
 533                 pktp->pkt_scbp = (opaque_t)((char *)pktp +
 534                     (A_TO_TRAN(ap))->tran_hba_len +
 535                     DEFAULT_PRIVLEN + sizeof (struct scsi_pkt_cache_wrapper));
 536                 if ((A_TO_TRAN(ap))->tran_hba_flags & SCSI_HBA_TRAN_CDB)
 537                         pktp->pkt_scbp = (opaque_t)((pktp->pkt_scbp) +
 538                             DEFAULT_CDBLEN);
 539                 pktp->pkt_scblen = 0;
 540         }
 541         if (pktw->pcw_flags & PCW_NEED_EXT_TGT) {
 542                 kmem_free(pktp->pkt_private, pktp->pkt_tgtlen);
 543                 pktp->pkt_tgtlen = 0;
 544                 pktp->pkt_private = NULL;
 545         }
 546         if (pktw->pcw_flags & PCW_NEED_EXT_CDB) {
 547                 kmem_free(pktp->pkt_cdbp, pktp->pkt_cdblen);
 548                 pktp->pkt_cdbp = (opaque_t)((char *)pktp +
 549                     (A_TO_TRAN(ap))->tran_hba_len +
 550                     sizeof (struct scsi_pkt_cache_wrapper));
 551                 pktp->pkt_cdblen = 0;
 552         }
 553         pktw->pcw_flags &=
 554             ~(PCW_NEED_EXT_CDB|PCW_NEED_EXT_TGT|PCW_NEED_EXT_SCB);
 555         kmem_cache_free(A_TO_TRAN(ap)->tran_pkt_cache_ptr, pktw);
 556 
 557         if (scsi_callback_id != 0) {
 558                 ddi_run_callback(&scsi_callback_id);
 559         }
 560 
 561 }
 562 
 563 
 564 struct scsi_pkt *
 565 scsi_init_pkt(struct scsi_address *ap, struct scsi_pkt *in_pktp,
 566     struct buf *bp, int cmdlen, int statuslen, int pplen,
 567     int flags, int (*callback)(caddr_t), caddr_t callback_arg)
 568 {
 569         struct scsi_pkt *pktp;
 570         scsi_hba_tran_t *tranp = ap->a_hba_tran;
 571         int             (*func)(caddr_t);
 572 
 573         TRACE_5(TR_FAC_SCSI_RES, TR_SCSI_INIT_PKT_START,
 574 "scsi_init_pkt_start: addr %p in_pktp %p cmdlen %d statuslen %d pplen %d",
 575             ap, in_pktp, cmdlen, statuslen, pplen);
 576 
 577 #if defined(__i386) || defined(__amd64)
 578         if (flags & PKT_CONSISTENT_OLD) {
 579                 flags &= ~PKT_CONSISTENT_OLD;
 580                 flags |= PKT_CONSISTENT;
 581         }
 582 #endif
 583 
 584         func = (callback == SLEEP_FUNC) ? SLEEP_FUNC : NULL_FUNC;
 585 
 586         pktp = (*tranp->tran_init_pkt) (ap, in_pktp, bp, cmdlen,
 587             statuslen, pplen, flags, func, NULL);
 588         if (pktp == NULL) {
 589                 if (callback != NULL_FUNC && callback != SLEEP_FUNC) {
 590                         ddi_set_callback(callback, callback_arg,
 591                             &scsi_callback_id);
 592                 }
 593         }
 594 
 595         TRACE_1(TR_FAC_SCSI_RES, TR_SCSI_INIT_PKT_END,
 596             "scsi_init_pkt_end: pktp %p", pktp);
 597         return (pktp);
 598 }
 599 
 600 void
 601 scsi_destroy_pkt(struct scsi_pkt *pkt)
 602 {
 603         struct scsi_address     *ap = P_TO_ADDR(pkt);
 604 
 605         TRACE_1(TR_FAC_SCSI_RES, TR_SCSI_DESTROY_PKT_START,
 606             "scsi_destroy_pkt_start: pkt %p", pkt);
 607 
 608         (*A_TO_TRAN(ap)->tran_destroy_pkt)(ap, pkt);
 609 
 610         if (scsi_callback_id != 0) {
 611                 ddi_run_callback(&scsi_callback_id);
 612         }
 613 
 614         TRACE_0(TR_FAC_SCSI_RES, TR_SCSI_DESTROY_PKT_END,
 615             "scsi_destroy_pkt_end");
 616 }
 617 
 618 
 619 /*
 620  *      Generic Resource Allocation Routines
 621  */
 622 
 623 struct scsi_pkt *
 624 scsi_resalloc(struct scsi_address *ap, int cmdlen, int statuslen,
 625     opaque_t dmatoken, int (*callback)())
 626 {
 627         register struct scsi_pkt *pkt;
 628         register scsi_hba_tran_t *tranp = ap->a_hba_tran;
 629         register int                    (*func)(caddr_t);
 630 
 631         func = (callback == SLEEP_FUNC) ? SLEEP_FUNC : NULL_FUNC;
 632 
 633         pkt = (*tranp->tran_init_pkt) (ap, NULL, (struct buf *)dmatoken,
 634             cmdlen, statuslen, 0, 0, func, NULL);
 635         if (pkt == NULL) {
 636                 if (callback != NULL_FUNC && callback != SLEEP_FUNC) {
 637                         ddi_set_callback(callback, NULL, &scsi_callback_id);
 638                 }
 639         }
 640 
 641         return (pkt);
 642 }
 643 
 644 struct scsi_pkt *
 645 scsi_pktalloc(struct scsi_address *ap, int cmdlen, int statuslen,
 646     int (*callback)())
 647 {
 648         struct scsi_pkt         *pkt;
 649         struct scsi_hba_tran    *tran = ap->a_hba_tran;
 650         register int                    (*func)(caddr_t);
 651 
 652         func = (callback == SLEEP_FUNC) ? SLEEP_FUNC : NULL_FUNC;
 653 
 654         pkt = (*tran->tran_init_pkt) (ap, NULL, NULL, cmdlen,
 655             statuslen, 0, 0, func, NULL);
 656         if (pkt == NULL) {
 657                 if (callback != NULL_FUNC && callback != SLEEP_FUNC) {
 658                         ddi_set_callback(callback, NULL, &scsi_callback_id);
 659                 }
 660         }
 661 
 662         return (pkt);
 663 }
 664 
 665 struct scsi_pkt *
 666 scsi_dmaget(struct scsi_pkt *pkt, opaque_t dmatoken, int (*callback)())
 667 {
 668         struct scsi_pkt         *new_pkt;
 669         register int            (*func)(caddr_t);
 670 
 671         func = (callback == SLEEP_FUNC) ? SLEEP_FUNC : NULL_FUNC;
 672 
 673         new_pkt = (*P_TO_TRAN(pkt)->tran_init_pkt) (&pkt->pkt_address,
 674             pkt, (struct buf *)dmatoken,
 675             0, 0, 0, 0, func, NULL);
 676         ASSERT(new_pkt == pkt || new_pkt == NULL);
 677         if (new_pkt == NULL) {
 678                 if (callback != NULL_FUNC && callback != SLEEP_FUNC) {
 679                         ddi_set_callback(callback, NULL, &scsi_callback_id);
 680                 }
 681         }
 682 
 683         return (new_pkt);
 684 }
 685 
 686 
 687 /*
 688  *      Generic Resource Deallocation Routines
 689  */
 690 
 691 void
 692 scsi_dmafree(struct scsi_pkt *pkt)
 693 {
 694         register struct scsi_address    *ap = P_TO_ADDR(pkt);
 695 
 696         (*A_TO_TRAN(ap)->tran_dmafree)(ap, pkt);
 697 
 698         if (scsi_callback_id != 0) {
 699                 ddi_run_callback(&scsi_callback_id);
 700         }
 701 }
 702 
 703 /*ARGSUSED*/
 704 void
 705 scsi_cache_dmafree(struct scsi_address *ap, struct scsi_pkt *pkt)
 706 {
 707         ASSERT(pkt->pkt_numcookies == 0 ||
 708             ((struct scsi_pkt_cache_wrapper *)pkt)->pcw_flags & PCW_BOUND);
 709         ASSERT(pkt->pkt_handle != NULL);
 710         scsi_dmafree_attr(pkt);
 711 
 712         if (scsi_callback_id != 0) {
 713                 ddi_run_callback(&scsi_callback_id);
 714         }
 715 }
 716 
 717 void
 718 scsi_sync_pkt(struct scsi_pkt *pkt)
 719 {
 720         register struct scsi_address    *ap = P_TO_ADDR(pkt);
 721 
 722         if (pkt->pkt_state & STATE_XFERRED_DATA)
 723                 (*A_TO_TRAN(ap)->tran_sync_pkt)(ap, pkt);
 724 }
 725 
 726 /*ARGSUSED*/
 727 void
 728 scsi_sync_cache_pkt(struct scsi_address *ap, struct scsi_pkt *pkt)
 729 {
 730         if (pkt->pkt_handle &&
 731             (pkt->pkt_dma_flags & (DDI_DMA_WRITE | DDI_DMA_READ))) {
 732                 (void) ddi_dma_sync(pkt->pkt_handle,
 733                     pkt->pkt_dma_offset, pkt->pkt_dma_len,
 734                     (pkt->pkt_dma_flags & DDI_DMA_WRITE) ?
 735                     DDI_DMA_SYNC_FORDEV : DDI_DMA_SYNC_FORCPU);
 736         }
 737 }
 738 
 739 void
 740 scsi_resfree(struct scsi_pkt *pkt)
 741 {
 742         register struct scsi_address    *ap = P_TO_ADDR(pkt);
 743         (*A_TO_TRAN(ap)->tran_destroy_pkt)(ap, pkt);
 744 
 745         if (scsi_callback_id != 0) {
 746                 ddi_run_callback(&scsi_callback_id);
 747         }
 748 }