]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/scsi/lpfc/lpfc_mem.c
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
[linux-2.6-omap-h63xx.git] / drivers / scsi / lpfc / lpfc_mem.c
index ec3bbbde6f7a397442eec29fbb477ca35a97f556..3c0cebc718002a3e65e0ea66443d39400e575f95 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2004-2005 Emulex.  All rights reserved.           *
+ * Copyright (C) 2004-2006 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * www.emulex.com                                                  *
  * Portions Copyright (C) 2004-2005 Christoph Hellwig              *
 #define LPFC_MBUF_POOL_SIZE     64      /* max elements in MBUF safety pool */
 #define LPFC_MEM_POOL_SIZE      64      /* max elem in non-DMA safety pool */
 
+
+
 int
 lpfc_mem_alloc(struct lpfc_hba * phba)
 {
        struct lpfc_dma_pool *pool = &phba->lpfc_mbuf_safety_pool;
+       int longs;
        int i;
 
        phba->lpfc_scsi_dma_buf_pool = pci_pool_create("lpfc_scsi_dma_buf_pool",
@@ -80,10 +83,28 @@ lpfc_mem_alloc(struct lpfc_hba * phba)
        if (!phba->nlp_mem_pool)
                goto fail_free_mbox_pool;
 
+       phba->lpfc_hbq_pool = pci_pool_create("lpfc_hbq_pool",phba->pcidev,
+                                             LPFC_BPL_SIZE, 8, 0);
+       if (!phba->lpfc_hbq_pool)
+               goto fail_free_nlp_mem_pool;
+
+       /* vpi zero is reserved for the physical port so add 1 to max */
+       longs = ((phba->max_vpi + 1) + BITS_PER_LONG - 1) / BITS_PER_LONG;
+       phba->vpi_bmask = kzalloc(longs * sizeof(unsigned long), GFP_KERNEL);
+       if (!phba->vpi_bmask)
+               goto fail_free_hbq_pool;
+
        return 0;
 
+ fail_free_hbq_pool:
+       lpfc_sli_hbqbuf_free_all(phba);
+       pci_pool_destroy(phba->lpfc_hbq_pool);
+ fail_free_nlp_mem_pool:
+       mempool_destroy(phba->nlp_mem_pool);
+       phba->nlp_mem_pool = NULL;
  fail_free_mbox_pool:
        mempool_destroy(phba->mbox_mem_pool);
+       phba->mbox_mem_pool = NULL;
  fail_free_mbuf_pool:
        while (i--)
                pci_pool_free(phba->lpfc_mbuf_pool, pool->elements[i].virt,
@@ -91,8 +112,10 @@ lpfc_mem_alloc(struct lpfc_hba * phba)
        kfree(pool->elements);
  fail_free_lpfc_mbuf_pool:
        pci_pool_destroy(phba->lpfc_mbuf_pool);
+       phba->lpfc_mbuf_pool = NULL;
  fail_free_dma_buf_pool:
        pci_pool_destroy(phba->lpfc_scsi_dma_buf_pool);
+       phba->lpfc_scsi_dma_buf_pool = NULL;
  fail:
        return -ENOMEM;
 }
@@ -106,6 +129,9 @@ lpfc_mem_free(struct lpfc_hba * phba)
        struct lpfc_dmabuf   *mp;
        int i;
 
+       kfree(phba->vpi_bmask);
+       lpfc_sli_hbqbuf_free_all(phba);
+
        list_for_each_entry_safe(mbox, next_mbox, &psli->mboxq, list) {
                mp = (struct lpfc_dmabuf *) (mbox->context1);
                if (mp) {
@@ -115,6 +141,15 @@ lpfc_mem_free(struct lpfc_hba * phba)
                list_del(&mbox->list);
                mempool_free(mbox, phba->mbox_mem_pool);
        }
+       list_for_each_entry_safe(mbox, next_mbox, &psli->mboxq_cmpl, list) {
+               mp = (struct lpfc_dmabuf *) (mbox->context1);
+               if (mp) {
+                       lpfc_mbuf_free(phba, mp->virt, mp->phys);
+                       kfree(mp);
+               }
+               list_del(&mbox->list);
+               mempool_free(mbox, phba->mbox_mem_pool);
+       }
 
        psli->sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;
        if (psli->mbox_active) {
@@ -132,13 +167,21 @@ lpfc_mem_free(struct lpfc_hba * phba)
                pci_pool_free(phba->lpfc_mbuf_pool, pool->elements[i].virt,
                                                 pool->elements[i].phys);
        kfree(pool->elements);
+
+       pci_pool_destroy(phba->lpfc_hbq_pool);
        mempool_destroy(phba->nlp_mem_pool);
        mempool_destroy(phba->mbox_mem_pool);
 
        pci_pool_destroy(phba->lpfc_scsi_dma_buf_pool);
        pci_pool_destroy(phba->lpfc_mbuf_pool);
 
-       /* Free the iocb lookup array */
+       phba->lpfc_hbq_pool = NULL;
+       phba->nlp_mem_pool = NULL;
+       phba->mbox_mem_pool = NULL;
+       phba->lpfc_scsi_dma_buf_pool = NULL;
+       phba->lpfc_mbuf_pool = NULL;
+
+                               /* Free the iocb lookup array */
        kfree(psli->iocbq_lookup);
        psli->iocbq_lookup = NULL;
 
@@ -148,20 +191,23 @@ void *
 lpfc_mbuf_alloc(struct lpfc_hba *phba, int mem_flags, dma_addr_t *handle)
 {
        struct lpfc_dma_pool *pool = &phba->lpfc_mbuf_safety_pool;
+       unsigned long iflags;
        void *ret;
 
        ret = pci_pool_alloc(phba->lpfc_mbuf_pool, GFP_KERNEL, handle);
 
-       if (!ret && ( mem_flags & MEM_PRI) && pool->current_count) {
+       spin_lock_irqsave(&phba->hbalock, iflags);
+       if (!ret && (mem_flags & MEM_PRI) && pool->current_count) {
                pool->current_count--;
                ret = pool->elements[pool->current_count].virt;
                *handle = pool->elements[pool->current_count].phys;
        }
+       spin_unlock_irqrestore(&phba->hbalock, iflags);
        return ret;
 }
 
 void
-lpfc_mbuf_free(struct lpfc_hba * phba, void *virt, dma_addr_t dma)
+__lpfc_mbuf_free(struct lpfc_hba * phba, void *virt, dma_addr_t dma)
 {
        struct lpfc_dma_pool *pool = &phba->lpfc_mbuf_safety_pool;
 
@@ -174,3 +220,74 @@ lpfc_mbuf_free(struct lpfc_hba * phba, void *virt, dma_addr_t dma)
        }
        return;
 }
+
+void
+lpfc_mbuf_free(struct lpfc_hba * phba, void *virt, dma_addr_t dma)
+{
+       unsigned long iflags;
+
+       spin_lock_irqsave(&phba->hbalock, iflags);
+       __lpfc_mbuf_free(phba, virt, dma);
+       spin_unlock_irqrestore(&phba->hbalock, iflags);
+       return;
+}
+
+struct hbq_dmabuf *
+lpfc_els_hbq_alloc(struct lpfc_hba *phba)
+{
+       struct hbq_dmabuf *hbqbp;
+
+       hbqbp = kmalloc(sizeof(struct hbq_dmabuf), GFP_KERNEL);
+       if (!hbqbp)
+               return NULL;
+
+       hbqbp->dbuf.virt = pci_pool_alloc(phba->lpfc_hbq_pool, GFP_KERNEL,
+                                         &hbqbp->dbuf.phys);
+       if (!hbqbp->dbuf.virt) {
+               kfree(hbqbp);
+               return NULL;
+       }
+       hbqbp->size = LPFC_BPL_SIZE;
+       return hbqbp;
+}
+
+void
+lpfc_els_hbq_free(struct lpfc_hba *phba, struct hbq_dmabuf *hbqbp)
+{
+       pci_pool_free(phba->lpfc_hbq_pool, hbqbp->dbuf.virt, hbqbp->dbuf.phys);
+       kfree(hbqbp);
+       return;
+}
+
+/* This is ONLY called for the LPFC_ELS_HBQ */
+void
+lpfc_in_buf_free(struct lpfc_hba *phba, struct lpfc_dmabuf *mp)
+{
+       struct hbq_dmabuf *hbq_entry;
+       unsigned long flags;
+
+       if (!mp)
+               return;
+
+       if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) {
+               /* Check whether HBQ is still in use */
+               spin_lock_irqsave(&phba->hbalock, flags);
+               if (!phba->hbq_in_use) {
+                       spin_unlock_irqrestore(&phba->hbalock, flags);
+                       return;
+               }
+               hbq_entry = container_of(mp, struct hbq_dmabuf, dbuf);
+               list_del(&hbq_entry->dbuf.list);
+               if (hbq_entry->tag == -1) {
+                       (phba->hbqs[LPFC_ELS_HBQ].hbq_free_buffer)
+                               (phba, hbq_entry);
+               } else {
+                       lpfc_sli_free_hbq(phba, hbq_entry);
+               }
+               spin_unlock_irqrestore(&phba->hbalock, flags);
+       } else {
+               lpfc_mbuf_free(phba, mp->virt, mp->phys);
+               kfree(mp);
+       }
+       return;
+}