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 QLogic Corporation.  All rights reserved.
  24  * Use is subject to license terms.
  25  */
  26 
  27 /*
  28  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
  29  */
  30 
  31 #include <sys/conf.h>
  32 #include <sys/ddi.h>
  33 #include <sys/sunddi.h>
  34 #include <sys/modctl.h>
  35 
  36 #include <sys/stmf_defines.h>
  37 #include <sys/fct_defines.h>
  38 #include <sys/stmf.h>
  39 #include <sys/portif.h>
  40 #include <sys/fct.h>
  41 
  42 #include "qlt.h"
  43 #include "qlt_dma.h"
  44 
  45 /*
  46  *  Local Function Prototypes.
  47  */
  48 static void
  49 qlt_dma_free_handles(qlt_state_t *qlt, qlt_dma_handle_t *first_handle);
  50 
  51 #define BUF_COUNT_2K            2048
  52 #define BUF_COUNT_8K            512
  53 #define BUF_COUNT_64K           256
  54 #define BUF_COUNT_128K          1024
  55 #define BUF_COUNT_256K          8
  56 
  57 #define QLT_DMEM_MAX_BUF_SIZE   (4 * 65536)
  58 #define QLT_DMEM_NBUCKETS       5
  59 static qlt_dmem_bucket_t bucket2K       = { 2048, BUF_COUNT_2K },
  60                         bucket8K        = { 8192, BUF_COUNT_8K },
  61                         bucket64K       = { 65536, BUF_COUNT_64K },
  62                         bucket128k      = { (2 * 65536), BUF_COUNT_128K },
  63                         bucket256k      = { (4 * 65536), BUF_COUNT_256K };
  64 
  65 static qlt_dmem_bucket_t *dmem_buckets[] = { &bucket2K, &bucket8K,
  66                         &bucket64K, &bucket128k, &bucket256k, NULL };
  67 static ddi_device_acc_attr_t acc;
  68 static ddi_dma_attr_t qlt_scsi_dma_attr = {
  69         DMA_ATTR_V0,            /* dma_attr_version */
  70         0,                      /* low DMA address range */
  71         0xffffffffffffffff,     /* high DMA address range */
  72         0xffffffff,             /* DMA counter register */
  73         8192,                   /* DMA address alignment */
  74         0xff,                   /* DMA burstsizes */
  75         1,                      /* min effective DMA size */
  76         0xffffffff,             /* max DMA xfer size */
  77         0xffffffff,             /* segment boundary */
  78         1,                      /* s/g list length */
  79         1,                      /* granularity of device */
  80         0                       /* DMA transfer flags */
  81 };
  82 
  83 fct_status_t
  84 qlt_dmem_init(qlt_state_t *qlt)
  85 {
  86         qlt_dmem_bucket_t       *p;
  87         qlt_dmem_bctl_t         *bctl, *bc;
  88         qlt_dmem_bctl_t         *prev;
  89         int                     ndx, i;
  90         uint32_t                total_mem;
  91         uint8_t                 *addr;
  92         uint8_t                 *host_addr;
  93         uint64_t                dev_addr;
  94         ddi_dma_cookie_t        cookie;
  95         uint32_t                ncookie;
  96         uint32_t                bsize;
  97         size_t                  len;
  98 
  99         if (qlt->qlt_bucketcnt[0] != 0) {
 100                 bucket2K.dmem_nbufs = qlt->qlt_bucketcnt[0];
 101         }
 102         if (qlt->qlt_bucketcnt[1] != 0) {
 103                 bucket8K.dmem_nbufs = qlt->qlt_bucketcnt[1];
 104         }
 105         if (qlt->qlt_bucketcnt[2] != 0) {
 106                 bucket64K.dmem_nbufs = qlt->qlt_bucketcnt[2];
 107         }
 108         if (qlt->qlt_bucketcnt[3] != 0) {
 109                 bucket128k.dmem_nbufs = qlt->qlt_bucketcnt[3];
 110         }
 111         if (qlt->qlt_bucketcnt[4] != 0) {
 112                 bucket256k.dmem_nbufs = qlt->qlt_bucketcnt[4];
 113         }
 114 
 115         bsize = sizeof (dmem_buckets);
 116         ndx = (int)(bsize / sizeof (void *));
 117         /*
 118          * The reason it is ndx - 1 everywhere is becasue the last bucket
 119          * pointer is NULL.
 120          */
 121         qlt->dmem_buckets = (qlt_dmem_bucket_t **)kmem_zalloc(bsize +
 122             ((ndx - 1) * (int)sizeof (qlt_dmem_bucket_t)), KM_SLEEP);
 123         for (i = 0; i < (ndx - 1); i++) {
 124                 qlt->dmem_buckets[i] = (qlt_dmem_bucket_t *)
 125                     ((uint8_t *)qlt->dmem_buckets + bsize +
 126                     (i * (int)sizeof (qlt_dmem_bucket_t)));
 127                 bcopy(dmem_buckets[i], qlt->dmem_buckets[i],
 128                     sizeof (qlt_dmem_bucket_t));
 129         }
 130         bzero(&acc, sizeof (acc));
 131         acc.devacc_attr_version = DDI_DEVICE_ATTR_V0;
 132         acc.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC;
 133         acc.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
 134         for (ndx = 0; (p = qlt->dmem_buckets[ndx]) != NULL; ndx++) {
 135                 bctl = (qlt_dmem_bctl_t *)kmem_zalloc(p->dmem_nbufs *
 136                     sizeof (qlt_dmem_bctl_t), KM_NOSLEEP);
 137                 if (bctl == NULL) {
 138                         EL(qlt, "bctl==NULL\n");
 139                         goto alloc_bctl_failed;
 140                 }
 141                 p->dmem_bctls_mem = bctl;
 142                 mutex_init(&p->dmem_lock, NULL, MUTEX_DRIVER, NULL);
 143                 if ((i = ddi_dma_alloc_handle(qlt->dip, &qlt_scsi_dma_attr,
 144                     DDI_DMA_SLEEP, 0, &p->dmem_dma_handle)) != DDI_SUCCESS) {
 145                         EL(qlt, "ddi_dma_alloc_handle status=%xh\n", i);
 146                         goto alloc_handle_failed;
 147                 }
 148 
 149                 total_mem = p->dmem_buf_size * p->dmem_nbufs;
 150 
 151                 if ((i = ddi_dma_mem_alloc(p->dmem_dma_handle, total_mem, &acc,
 152                     DDI_DMA_STREAMING, DDI_DMA_DONTWAIT, 0, (caddr_t *)&addr,
 153                     &len, &p->dmem_acc_handle)) != DDI_SUCCESS) {
 154                         EL(qlt, "ddi_dma_mem_alloc status=%xh\n", i);
 155                         goto mem_alloc_failed;
 156                 }
 157 
 158                 if ((i = ddi_dma_addr_bind_handle(p->dmem_dma_handle, NULL,
 159                     (caddr_t)addr, total_mem, DDI_DMA_RDWR | DDI_DMA_STREAMING,
 160                     DDI_DMA_DONTWAIT, 0, &cookie, &ncookie)) != DDI_SUCCESS) {
 161                         EL(qlt, "ddi_dma_addr_bind_handle status=%xh\n", i);
 162                         goto addr_bind_handle_failed;
 163                 }
 164                 if (ncookie != 1) {
 165                         EL(qlt, "ncookie=%d\n", ncookie);
 166                         goto dmem_init_failed;
 167                 }
 168 
 169                 p->dmem_host_addr = host_addr = addr;
 170                 p->dmem_dev_addr = dev_addr = (uint64_t)cookie.dmac_laddress;
 171                 bsize = p->dmem_buf_size;
 172                 p->dmem_bctl_free_list = bctl;
 173                 p->dmem_nbufs_free = p->dmem_nbufs;
 174                 for (i = 0; i < p->dmem_nbufs; i++) {
 175                         stmf_data_buf_t *db;
 176                         prev = bctl;
 177                         bctl->bctl_bucket = p;
 178                         bctl->bctl_buf = db = stmf_alloc(STMF_STRUCT_DATA_BUF,
 179                             0, 0);
 180                         db->db_port_private = bctl;
 181                         db->db_sglist[0].seg_addr = host_addr;
 182                         bctl->bctl_dev_addr = dev_addr;
 183                         db->db_sglist[0].seg_length = db->db_buf_size = bsize;
 184                         db->db_sglist_length = 1;
 185                         host_addr += bsize;
 186                         dev_addr += bsize;
 187                         bctl++;
 188                         prev->bctl_next = bctl;
 189                 }
 190                 prev->bctl_next = NULL;
 191         }
 192 
 193         return (QLT_SUCCESS);
 194 
 195 dmem_failure_loop:;
 196         bc = bctl;
 197         while (bc) {
 198                 stmf_free(bc->bctl_buf);
 199                 bc = bc->bctl_next;
 200         }
 201 dmem_init_failed:;
 202         (void) ddi_dma_unbind_handle(p->dmem_dma_handle);
 203 addr_bind_handle_failed:;
 204         ddi_dma_mem_free(&p->dmem_acc_handle);
 205 mem_alloc_failed:;
 206         ddi_dma_free_handle(&p->dmem_dma_handle);
 207 alloc_handle_failed:;
 208         kmem_free(p->dmem_bctls_mem, p->dmem_nbufs * sizeof (qlt_dmem_bctl_t));
 209         mutex_destroy(&p->dmem_lock);
 210 alloc_bctl_failed:;
 211         if (--ndx >= 0) {
 212                 p = qlt->dmem_buckets[ndx];
 213                 bctl = p->dmem_bctl_free_list;
 214                 goto dmem_failure_loop;
 215         }
 216         kmem_free(qlt->dmem_buckets, sizeof (dmem_buckets) +
 217             ((sizeof (dmem_buckets)/sizeof (void *))
 218             *sizeof (qlt_dmem_bucket_t)));
 219         qlt->dmem_buckets = NULL;
 220 
 221         return (QLT_FAILURE);
 222 }
 223 
 224 void
 225 qlt_dma_handle_pool_init(qlt_state_t *qlt)
 226 {
 227         qlt_dma_handle_pool_t *pool;
 228 
 229         pool = kmem_zalloc(sizeof (*pool), KM_SLEEP);
 230         mutex_init(&pool->pool_lock, NULL, MUTEX_DRIVER, NULL);
 231         qlt->qlt_dma_handle_pool = pool;
 232 }
 233 
 234 void
 235 qlt_dma_handle_pool_fini(qlt_state_t *qlt)
 236 {
 237         qlt_dma_handle_pool_t   *pool;
 238         qlt_dma_handle_t        *handle, *next_handle;
 239 
 240         pool = qlt->qlt_dma_handle_pool;
 241         mutex_enter(&pool->pool_lock);
 242         /*
 243          * XXX Need to wait for free == total elements
 244          * XXX Not sure how other driver shutdown stuff is done.
 245          */
 246         ASSERT(pool->num_free == pool->num_total);
 247         if (pool->num_free != pool->num_total)
 248                 cmn_err(CE_WARN,
 249                     "num_free %d != num_total %d\n",
 250                     pool->num_free, pool->num_total);
 251         handle = pool->free_list;
 252         while (handle) {
 253                 next_handle = handle->next;
 254                 kmem_free(handle, sizeof (*handle));
 255                 handle = next_handle;
 256         }
 257         qlt->qlt_dma_handle_pool = NULL;
 258         mutex_destroy(&pool->pool_lock);
 259         kmem_free(pool, sizeof (*pool));
 260 }
 261 
 262 void
 263 qlt_dmem_fini(qlt_state_t *qlt)
 264 {
 265         qlt_dmem_bucket_t *p;
 266         qlt_dmem_bctl_t *bctl;
 267         int ndx;
 268 
 269         for (ndx = 0; (p = qlt->dmem_buckets[ndx]) != NULL; ndx++) {
 270                 bctl = p->dmem_bctl_free_list;
 271                 while (bctl) {
 272                         stmf_free(bctl->bctl_buf);
 273                         bctl = bctl->bctl_next;
 274                 }
 275                 bctl = p->dmem_bctl_free_list;
 276                 (void) ddi_dma_unbind_handle(p->dmem_dma_handle);
 277                 ddi_dma_mem_free(&p->dmem_acc_handle);
 278                 ddi_dma_free_handle(&p->dmem_dma_handle);
 279                 kmem_free(p->dmem_bctls_mem,
 280                     p->dmem_nbufs * sizeof (qlt_dmem_bctl_t));
 281                 mutex_destroy(&p->dmem_lock);
 282         }
 283         kmem_free(qlt->dmem_buckets, sizeof (dmem_buckets) +
 284             (((sizeof (dmem_buckets)/sizeof (void *))-1)*
 285             sizeof (qlt_dmem_bucket_t)));
 286         qlt->dmem_buckets = NULL;
 287 }
 288 
 289 stmf_data_buf_t *
 290 qlt_dmem_alloc(fct_local_port_t *port, uint32_t size, uint32_t *pminsize,
 291     uint32_t flags)
 292 {
 293         return (qlt_i_dmem_alloc((qlt_state_t *)
 294             port->port_fca_private, size, pminsize,
 295             flags));
 296 }
 297 
 298 /* ARGSUSED */
 299 stmf_data_buf_t *
 300 qlt_i_dmem_alloc(qlt_state_t *qlt, uint32_t size, uint32_t *pminsize,
 301     uint32_t flags)
 302 {
 303         qlt_dmem_bucket_t       *p;
 304         qlt_dmem_bctl_t         *bctl;
 305         int                     i;
 306         uint32_t                size_possible = 0;
 307 
 308         if (size > QLT_DMEM_MAX_BUF_SIZE) {
 309                 goto qlt_try_partial_alloc;
 310         }
 311 
 312         /* 1st try to do a full allocation */
 313         for (i = 0; (p = qlt->dmem_buckets[i]) != NULL; i++) {
 314                 if (p->dmem_buf_size >= size) {
 315                         if (p->dmem_nbufs_free) {
 316                                 mutex_enter(&p->dmem_lock);
 317                                 bctl = p->dmem_bctl_free_list;
 318                                 if (bctl == NULL) {
 319                                         mutex_exit(&p->dmem_lock);
 320                                         continue;
 321                                 }
 322                                 p->dmem_bctl_free_list =
 323                                     bctl->bctl_next;
 324                                 p->dmem_nbufs_free--;
 325                                 qlt->qlt_bufref[i]++;
 326                                 mutex_exit(&p->dmem_lock);
 327                                 bctl->bctl_buf->db_data_size = size;
 328                                 return (bctl->bctl_buf);
 329                         } else {
 330                                 qlt->qlt_bumpbucket++;
 331                         }
 332                 }
 333         }
 334 
 335 qlt_try_partial_alloc:
 336 
 337         qlt->qlt_pmintry++;
 338 
 339         /* Now go from high to low */
 340         for (i = QLT_DMEM_NBUCKETS - 1; i >= 0; i--) {
 341                 p = qlt->dmem_buckets[i];
 342                 if (p->dmem_nbufs_free == 0)
 343                         continue;
 344                 if (!size_possible) {
 345                         size_possible = p->dmem_buf_size;
 346                 }
 347                 if (*pminsize > p->dmem_buf_size) {
 348                         /* At this point we know the request is failing. */
 349                         if (size_possible) {
 350                                 /*
 351                                  * This caller is asking too much. We already
 352                                  * know what we can give, so get out.
 353                                  */
 354                                 break;
 355                         } else {
 356                                 /*
 357                                  * Lets continue to find out and tell what
 358                                  * we can give.
 359                                  */
 360                                 continue;
 361                         }
 362                 }
 363                 mutex_enter(&p->dmem_lock);
 364                 if (*pminsize <= p->dmem_buf_size) {
 365                         bctl = p->dmem_bctl_free_list;
 366                         if (bctl == NULL) {
 367                                 /* Someone took it. */
 368                                 size_possible = 0;
 369                                 mutex_exit(&p->dmem_lock);
 370                                 continue;
 371                         }
 372                         p->dmem_bctl_free_list = bctl->bctl_next;
 373                         p->dmem_nbufs_free--;
 374                         mutex_exit(&p->dmem_lock);
 375                         bctl->bctl_buf->db_data_size = p->dmem_buf_size;
 376                         qlt->qlt_pmin_ok++;
 377                         return (bctl->bctl_buf);
 378                 }
 379         }
 380 
 381         *pminsize = size_possible;
 382 
 383         return (NULL);
 384 }
 385 
 386 /* ARGSUSED */
 387 void
 388 qlt_i_dmem_free(qlt_state_t *qlt, stmf_data_buf_t *dbuf)
 389 {
 390         qlt_dmem_free(0, dbuf);
 391 }
 392 
 393 /* ARGSUSED */
 394 void
 395 qlt_dmem_free(fct_dbuf_store_t *fds, stmf_data_buf_t *dbuf)
 396 {
 397         qlt_dmem_bctl_t         *bctl;
 398         qlt_dmem_bucket_t       *p;
 399 
 400         ASSERT((dbuf->db_flags & DB_LU_DATA_BUF) == 0);
 401 
 402         bctl = (qlt_dmem_bctl_t *)dbuf->db_port_private;
 403         p = bctl->bctl_bucket;
 404         mutex_enter(&p->dmem_lock);
 405         bctl->bctl_next = p->dmem_bctl_free_list;
 406         p->dmem_bctl_free_list = bctl;
 407         p->dmem_nbufs_free++;
 408         mutex_exit(&p->dmem_lock);
 409 }
 410 
 411 void
 412 qlt_dmem_dma_sync(stmf_data_buf_t *dbuf, uint_t sync_type)
 413 {
 414         qlt_dmem_bctl_t         *bctl;
 415         qlt_dma_sgl_t           *qsgl;
 416         qlt_dmem_bucket_t       *p;
 417         qlt_dma_handle_t        *th;
 418         int                     rv;
 419 
 420         if (dbuf->db_flags & DB_LU_DATA_BUF) {
 421                 /*
 422                  * go through ddi handle list
 423                  */
 424                 qsgl = (qlt_dma_sgl_t *)dbuf->db_port_private;
 425                 th = qsgl->handle_list;
 426                 while (th) {
 427                         rv = ddi_dma_sync(th->dma_handle,
 428                             0, 0, sync_type);
 429                         if (rv != DDI_SUCCESS) {
 430                                 cmn_err(CE_WARN, "ddi_dma_sync FAILED\n");
 431                         }
 432                         th = th->next;
 433                 }
 434         } else {
 435                 bctl = (qlt_dmem_bctl_t *)dbuf->db_port_private;
 436                 p = bctl->bctl_bucket;
 437                 (void) ddi_dma_sync(p->dmem_dma_handle, (off_t)
 438                     (bctl->bctl_dev_addr - p->dmem_dev_addr),
 439                     dbuf->db_data_size, sync_type);
 440         }
 441 }
 442 
 443 /*
 444  * A very lite version of ddi_dma_addr_bind_handle()
 445  */
 446 uint64_t
 447 qlt_ddi_vtop(caddr_t vaddr)
 448 {
 449         uint64_t offset, paddr;
 450         pfn_t pfn;
 451 
 452         pfn = hat_getpfnum(kas.a_hat, vaddr);
 453         ASSERT(pfn != PFN_INVALID && pfn != PFN_SUSPENDED);
 454         offset = ((uintptr_t)vaddr) & MMU_PAGEOFFSET;
 455         paddr = mmu_ptob(pfn);
 456         return (paddr+offset);
 457 }
 458 
 459 static ddi_dma_attr_t   qlt_sgl_dma_attr = {
 460         DMA_ATTR_V0,            /* dma_attr_version */
 461         0,                              /* low DMA address range */
 462         0xffffffffffffffff,             /* high DMA address range */
 463         0xffffffff,                     /* DMA counter register */
 464         64,                             /* DMA address alignment */
 465         0xff,                   /* DMA burstsizes */
 466         1,                              /* min effective DMA size */
 467         0xffffffff,                     /* max DMA xfer size */
 468         0xffffffff,                     /* segment boundary */
 469         QLT_DMA_SG_LIST_LENGTH, /* s/g list length */
 470         1,                              /* granularity of device */
 471         0                               /* DMA transfer flags */
 472 };
 473 
 474 /*
 475  * Allocate a qlt_dma_handle container and fill it with a ddi_dma_handle
 476  */
 477 static qlt_dma_handle_t *
 478 qlt_dma_alloc_handle(qlt_state_t *qlt)
 479 {
 480         ddi_dma_handle_t ddi_handle;
 481         qlt_dma_handle_t *qlt_handle;
 482         int rv;
 483 
 484         rv = ddi_dma_alloc_handle(qlt->dip, &qlt_sgl_dma_attr,
 485             DDI_DMA_SLEEP, 0, &ddi_handle);
 486         if (rv != DDI_SUCCESS) {
 487                 EL(qlt, "ddi_dma_alloc_handle status=%xh\n", rv);
 488                 return (NULL);
 489         }
 490         qlt_handle = kmem_zalloc(sizeof (qlt_dma_handle_t), KM_SLEEP);
 491         qlt_handle->dma_handle = ddi_handle;
 492         return (qlt_handle);
 493 }
 494 
 495 /*
 496  * Allocate a list of qlt_dma_handle containers from the free list
 497  */
 498 static qlt_dma_handle_t *
 499 qlt_dma_alloc_handle_list(qlt_state_t *qlt, int handle_count)
 500 {
 501         qlt_dma_handle_pool_t   *pool;
 502         qlt_dma_handle_t        *tmp_handle, *first_handle, *last_handle;
 503         int i;
 504 
 505         /*
 506          * Make sure the free list can satisfy the request.
 507          * Once the free list is primed, it should satisfy most requests.
 508          * XXX Should there be a limit on pool size?
 509          */
 510         pool = qlt->qlt_dma_handle_pool;
 511         mutex_enter(&pool->pool_lock);
 512         while (handle_count > pool->num_free) {
 513                 mutex_exit(&pool->pool_lock);
 514                 if ((tmp_handle = qlt_dma_alloc_handle(qlt)) == NULL)
 515                         return (NULL);
 516                 mutex_enter(&pool->pool_lock);
 517                 tmp_handle->next = pool->free_list;
 518                 pool->free_list = tmp_handle;
 519                 pool->num_free++;
 520                 pool->num_total++;
 521         }
 522 
 523         /*
 524          * The free list lock is held and the list is large enough to
 525          * satisfy this request. Run down the freelist and snip off
 526          * the number of elements needed for this request.
 527          */
 528         first_handle = pool->free_list;
 529         tmp_handle = first_handle;
 530         for (i = 0; i < handle_count; i++) {
 531                 last_handle = tmp_handle;
 532                 tmp_handle = tmp_handle->next;
 533         }
 534         pool->free_list = tmp_handle;
 535         pool->num_free -= handle_count;
 536         mutex_exit(&pool->pool_lock);
 537         last_handle->next = NULL;    /* sanity */
 538         return (first_handle);
 539 }
 540 
 541 /*
 542  * Return a list of qlt_dma_handle containers to the free list.
 543  */
 544 static void
 545 qlt_dma_free_handles(qlt_state_t *qlt, qlt_dma_handle_t *first_handle)
 546 {
 547         qlt_dma_handle_pool_t *pool;
 548         qlt_dma_handle_t *tmp_handle, *last_handle;
 549         int rv, handle_count;
 550 
 551         /*
 552          * Traverse the list and unbind the handles
 553          */
 554         ASSERT(first_handle);
 555         tmp_handle = first_handle;
 556         handle_count = 0;
 557         while (tmp_handle != NULL) {
 558                 last_handle = tmp_handle;
 559                 /*
 560                  * If the handle is bound, unbind the handle so it can be
 561                  * reused. It may not be bound if there was a bind failure.
 562                  */
 563                 if (tmp_handle->num_cookies != 0) {
 564                         rv = ddi_dma_unbind_handle(tmp_handle->dma_handle);
 565                         ASSERT(rv == DDI_SUCCESS);
 566                         tmp_handle->num_cookies = 0;
 567                         tmp_handle->num_cookies_fetched = 0;
 568                 }
 569                 tmp_handle = tmp_handle->next;
 570                 handle_count++;
 571         }
 572         /*
 573          * Insert this list into the free list
 574          */
 575         pool = qlt->qlt_dma_handle_pool;
 576         mutex_enter(&pool->pool_lock);
 577         last_handle->next = pool->free_list;
 578         pool->free_list = first_handle;
 579         pool->num_free += handle_count;
 580         mutex_exit(&pool->pool_lock);
 581 }
 582 
 583 /*
 584  * cookies produced by mapping this dbuf
 585  */
 586 uint16_t
 587 qlt_get_cookie_count(stmf_data_buf_t *dbuf)
 588 {
 589         qlt_dma_sgl_t *qsgl = dbuf->db_port_private;
 590 
 591         ASSERT(dbuf->db_flags & DB_LU_DATA_BUF);
 592         return (qsgl->cookie_count);
 593 }
 594 
 595 ddi_dma_cookie_t
 596 *qlt_get_cookie_array(stmf_data_buf_t *dbuf)
 597 {
 598         qlt_dma_sgl_t *qsgl = dbuf->db_port_private;
 599 
 600         ASSERT(dbuf->db_flags & DB_LU_DATA_BUF);
 601 
 602         if (qsgl->cookie_prefetched)
 603                 return (&qsgl->cookie[0]);
 604         else
 605                 return (NULL);
 606 }
 607 
 608 /*
 609  * Wrapper around ddi_dma_nextcookie that hides the ddi_dma_handle usage.
 610  */
 611 void
 612 qlt_ddi_dma_nextcookie(stmf_data_buf_t *dbuf, ddi_dma_cookie_t *cookiep)
 613 {
 614         qlt_dma_sgl_t *qsgl = dbuf->db_port_private;
 615 
 616         ASSERT(dbuf->db_flags & DB_LU_DATA_BUF);
 617 
 618         if (qsgl->cookie_prefetched) {
 619                 ASSERT(qsgl->cookie_next_fetch < qsgl->cookie_count);
 620                 *cookiep = qsgl->cookie[qsgl->cookie_next_fetch++];
 621         } else {
 622                 qlt_dma_handle_t *fetch;
 623                 qlt_dma_handle_t *FETCH_DONE = (qlt_dma_handle_t *)0xbad;
 624 
 625                 ASSERT(qsgl->handle_list != NULL);
 626                 ASSERT(qsgl->handle_next_fetch != FETCH_DONE);
 627 
 628                 fetch = qsgl->handle_next_fetch;
 629                 if (fetch->num_cookies_fetched == 0) {
 630                         *cookiep = fetch->first_cookie;
 631                 } else {
 632                         ddi_dma_nextcookie(fetch->dma_handle, cookiep);
 633                 }
 634                 if (++fetch->num_cookies_fetched == fetch->num_cookies) {
 635                         if (fetch->next == NULL)
 636                                 qsgl->handle_next_fetch = FETCH_DONE;
 637                         else
 638                                 qsgl->handle_next_fetch = fetch->next;
 639                 }
 640         }
 641 }
 642 
 643 /*
 644  * Set this flag to fetch the DDI dma cookies from the handles here and
 645  * store them in the port private area of the dbuf. This will allow
 646  * faster access to the cookies in qlt_xfer_scsi_data() at the expense of
 647  * an extra copy. If the qlt->req_lock is hot, this may help.
 648  */
 649 int qlt_sgl_prefetch = 0;
 650 
 651 /*ARGSUSED*/
 652 stmf_status_t
 653 qlt_dma_setup_dbuf(fct_local_port_t *port, stmf_data_buf_t *dbuf,
 654     uint32_t flags)
 655 {
 656         qlt_state_t             *qlt = port->port_fca_private;
 657         qlt_dma_sgl_t           *qsgl;
 658         struct stmf_sglist_ent  *sglp;
 659         qlt_dma_handle_t        *handle_list, *th;
 660         int                     i, rv;
 661         ddi_dma_cookie_t        *cookie_p;
 662         int                     cookie_count, numbufs;
 663         int                     prefetch;
 664         size_t                  qsize;
 665 
 666         /*
 667          * psuedo code:
 668          * get dma handle list from cache - one per sglist entry
 669          * foreach sglist entry
 670          *      bind dma handle to sglist vaddr
 671          * allocate space for DMA state to store in db_port_private
 672          * fill in port private object
 673          * if prefetching
 674          *      move all dma cookies into db_port_private
 675          */
 676         dbuf->db_port_private = NULL;
 677         numbufs = dbuf->db_sglist_length;
 678         handle_list = qlt_dma_alloc_handle_list(qlt, numbufs);
 679         if (handle_list == NULL) {
 680                 EL(qlt, "handle_list==NULL\n");
 681                 return (STMF_FAILURE);
 682         }
 683         /*
 684          * Loop through sglist and bind each entry to a handle
 685          */
 686         th = handle_list;
 687         sglp = &dbuf->db_sglist[0];
 688         cookie_count = 0;
 689         for (i = 0; i < numbufs; i++, sglp++) {
 690 
 691                 /*
 692                  * Bind this sgl entry to a DDI dma handle
 693                  */
 694                 if ((rv = ddi_dma_addr_bind_handle(
 695                     th->dma_handle,
 696                     NULL,
 697                     (caddr_t)(sglp->seg_addr),
 698                     (size_t)sglp->seg_length,
 699                     DDI_DMA_RDWR | DDI_DMA_STREAMING,
 700                     DDI_DMA_DONTWAIT,
 701                     NULL,
 702                     &th->first_cookie,
 703                     &th->num_cookies)) != DDI_DMA_MAPPED) {
 704                         cmn_err(CE_NOTE, "ddi_dma_addr_bind_handle %d", rv);
 705                         qlt_dma_free_handles(qlt, handle_list);
 706                         return (STMF_FAILURE);
 707                 }
 708 
 709                 /*
 710                  * Add to total cookie count
 711                  */
 712                 cookie_count += th->num_cookies;
 713                 if (cookie_count > QLT_DMA_SG_LIST_LENGTH) {
 714                         /*
 715                          * Request exceeds HBA limit
 716                          */
 717                         qlt_dma_free_handles(qlt, handle_list);
 718                         return (STMF_FAILURE);
 719                 }
 720                 /* move to next ddi_dma_handle */
 721                 th = th->next;
 722         }
 723 
 724         /*
 725          * Allocate our port private object for DMA mapping state.
 726          */
 727         prefetch =  qlt_sgl_prefetch;
 728         qsize = sizeof (qlt_dma_sgl_t);
 729         if (prefetch) {
 730                 /* one extra ddi_dma_cookie allocated for alignment padding */
 731                 qsize += cookie_count * sizeof (ddi_dma_cookie_t);
 732         }
 733         qsgl = kmem_alloc(qsize, KM_SLEEP);
 734         /*
 735          * Fill in the sgl
 736          */
 737         dbuf->db_port_private = qsgl;
 738         qsgl->qsize = qsize;
 739         qsgl->handle_count = dbuf->db_sglist_length;
 740         qsgl->cookie_prefetched = prefetch;
 741         qsgl->cookie_count = cookie_count;
 742         qsgl->cookie_next_fetch = 0;
 743         qsgl->handle_list = handle_list;
 744         qsgl->handle_next_fetch = handle_list;
 745         if (prefetch) {
 746                 /*
 747                  * traverse handle list and move cookies to db_port_private
 748                  */
 749                 th = handle_list;
 750                 cookie_p = &qsgl->cookie[0];
 751                 for (i = 0; i < numbufs; i++) {
 752                         uint_t cc = th->num_cookies;
 753 
 754                         *cookie_p++ = th->first_cookie;
 755                         while (--cc > 0) {
 756                                 ddi_dma_nextcookie(th->dma_handle, cookie_p++);
 757                         }
 758                         th->num_cookies_fetched = th->num_cookies;
 759                         th = th->next;
 760                 }
 761         }
 762 
 763         return (STMF_SUCCESS);
 764 }
 765 
 766 void
 767 qlt_dma_teardown_dbuf(fct_dbuf_store_t *fds, stmf_data_buf_t *dbuf)
 768 {
 769         qlt_state_t             *qlt = fds->fds_fca_private;
 770         qlt_dma_sgl_t           *qsgl = dbuf->db_port_private;
 771 
 772         ASSERT(qlt);
 773         ASSERT(qsgl);
 774         ASSERT(dbuf->db_flags & DB_LU_DATA_BUF);
 775 
 776         /*
 777          * unbind and free the dma handles
 778          */
 779         if (qsgl->handle_list) {
 780                 /* go through ddi handle list */
 781                 qlt_dma_free_handles(qlt, qsgl->handle_list);
 782         }
 783         kmem_free(qsgl, qsgl->qsize);
 784 }
 785 
 786 uint8_t
 787 qlt_get_iocb_count(uint32_t cookie_count)
 788 {
 789         uint32_t        cnt, cont_segs;
 790         uint8_t         iocb_count;
 791 
 792         iocb_count = 1;
 793         cnt = CMD7_2400_DATA_SEGMENTS;
 794         cont_segs = CONT_A64_DATA_SEGMENTS;
 795 
 796         if (cookie_count > cnt) {
 797                 cnt = cookie_count - cnt;
 798                 iocb_count = (uint8_t)(iocb_count + cnt / cont_segs);
 799                 if (cnt % cont_segs) {
 800                         iocb_count++;
 801                 }
 802         }
 803         return (iocb_count);
 804 }