2005-04-17 16:05:31 -05:00
/*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
2005-06-25 10:34:39 -04:00
* Fibre Channel Host Bus Adapters . *
2008-08-24 21:49:00 -04:00
* Copyright ( C ) 2004 - 2008 Emulex . All rights reserved . *
2005-06-25 10:34:39 -04:00
* EMULEX and SLI are trademarks of Emulex . *
2005-04-17 16:05:31 -05:00
* www . emulex . com *
2005-06-25 10:34:39 -04:00
* Portions Copyright ( C ) 2004 - 2005 Christoph Hellwig *
2005-04-17 16:05:31 -05:00
* *
* This program is free software ; you can redistribute it and / or *
2005-06-25 10:34:39 -04:00
* modify it under the terms of version 2 of the GNU General *
* Public License as published by the Free Software Foundation . *
* This program is distributed in the hope that it will be useful . *
* ALL EXPRESS OR IMPLIED CONDITIONS , REPRESENTATIONS AND *
* WARRANTIES , INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY , *
* FITNESS FOR A PARTICULAR PURPOSE , OR NON - INFRINGEMENT , ARE *
* DISCLAIMED , EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD *
* TO BE LEGALLY INVALID . See the GNU General Public License for *
* more details , a copy of which can be found in the file COPYING *
* included with this package . *
2005-04-17 16:05:31 -05:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# include <linux/mempool.h>
# include <linux/pci.h>
# include <linux/interrupt.h>
2005-08-10 15:03:01 -04:00
# include <scsi/scsi_device.h>
# include <scsi/scsi_transport_fc.h>
2005-08-10 15:03:09 -04:00
# include <scsi/scsi.h>
2005-04-17 16:05:31 -05:00
# include "lpfc_hw.h"
# include "lpfc_sli.h"
2008-09-07 11:52:10 -04:00
# include "lpfc_nl.h"
2005-04-17 16:05:31 -05:00
# include "lpfc_disc.h"
# include "lpfc_scsi.h"
# include "lpfc.h"
# include "lpfc_crtn.h"
# 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 */
2007-06-17 19:56:36 -05:00
2008-08-24 21:49:00 -04:00
/**
* lpfc_mem_alloc : create and allocate all PCI and memory pools
* @ phba : HBA to allocate pools for
*
* Description : Creates and allocates PCI pools lpfc_scsi_dma_buf_pool ,
* lpfc_mbuf_pool , lpfc_hbq_pool . Creates and allocates kmalloc - backed mempools
* for LPFC_MBOXQ_t and lpfc_nodelist . Also allocates the VPI bitmask .
*
* Notes : Not interrupt - safe . Must be called with no locks held . If any
* allocation fails , frees all successfully allocated memory before returning .
*
* Returns :
* 0 on success
* - ENOMEM on failure ( if any memory allocations fail )
* */
2005-04-17 16:05:31 -05:00
int
lpfc_mem_alloc ( struct lpfc_hba * phba )
{
struct lpfc_dma_pool * pool = & phba - > lpfc_mbuf_safety_pool ;
2007-06-17 19:56:38 -05:00
int longs ;
2005-04-17 16:05:31 -05:00
int i ;
phba - > lpfc_scsi_dma_buf_pool = pci_pool_create ( " lpfc_scsi_dma_buf_pool " ,
phba - > pcidev , phba - > cfg_sg_dma_buf_size , 8 , 0 ) ;
if ( ! phba - > lpfc_scsi_dma_buf_pool )
goto fail ;
phba - > lpfc_mbuf_pool = pci_pool_create ( " lpfc_mbuf_pool " , phba - > pcidev ,
LPFC_BPL_SIZE , 8 , 0 ) ;
if ( ! phba - > lpfc_mbuf_pool )
goto fail_free_dma_buf_pool ;
pool - > elements = kmalloc ( sizeof ( struct lpfc_dmabuf ) *
LPFC_MBUF_POOL_SIZE , GFP_KERNEL ) ;
2007-01-02 01:07:32 +01:00
if ( ! pool - > elements )
goto fail_free_lpfc_mbuf_pool ;
2005-04-17 16:05:31 -05:00
pool - > max_count = 0 ;
pool - > current_count = 0 ;
for ( i = 0 ; i < LPFC_MBUF_POOL_SIZE ; i + + ) {
pool - > elements [ i ] . virt = pci_pool_alloc ( phba - > lpfc_mbuf_pool ,
GFP_KERNEL , & pool - > elements [ i ] . phys ) ;
if ( ! pool - > elements [ i ] . virt )
goto fail_free_mbuf_pool ;
pool - > max_count + + ;
pool - > current_count + + ;
}
2006-03-26 01:37:47 -08:00
phba - > mbox_mem_pool = mempool_create_kmalloc_pool ( LPFC_MEM_POOL_SIZE ,
sizeof ( LPFC_MBOXQ_t ) ) ;
2005-04-17 16:05:31 -05:00
if ( ! phba - > mbox_mem_pool )
goto fail_free_mbuf_pool ;
2006-03-26 01:37:47 -08:00
phba - > nlp_mem_pool = mempool_create_kmalloc_pool ( LPFC_MEM_POOL_SIZE ,
sizeof ( struct lpfc_nodelist ) ) ;
2005-04-17 16:05:31 -05:00
if ( ! phba - > nlp_mem_pool )
goto fail_free_mbox_pool ;
2007-06-17 19:56:37 -05:00
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 ;
2007-06-17 19:56:39 -05:00
/* 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 ;
2007-06-17 19:56:38 -05:00
phba - > vpi_bmask = kzalloc ( longs * sizeof ( unsigned long ) , GFP_KERNEL ) ;
if ( ! phba - > vpi_bmask )
goto fail_free_hbq_pool ;
2005-04-17 16:05:31 -05:00
return 0 ;
2007-06-17 19:56:38 -05:00
fail_free_hbq_pool :
lpfc_sli_hbqbuf_free_all ( phba ) ;
2008-01-11 01:52:54 -05:00
pci_pool_destroy ( phba - > lpfc_hbq_pool ) ;
2007-06-17 19:56:37 -05:00
fail_free_nlp_mem_pool :
mempool_destroy ( phba - > nlp_mem_pool ) ;
phba - > nlp_mem_pool = NULL ;
2005-04-17 16:05:31 -05:00
fail_free_mbox_pool :
mempool_destroy ( phba - > mbox_mem_pool ) ;
2007-06-17 19:56:36 -05:00
phba - > mbox_mem_pool = NULL ;
2005-04-17 16:05:31 -05:00
fail_free_mbuf_pool :
2007-01-02 01:07:32 +01:00
while ( i - - )
2005-04-17 16:05:31 -05:00
pci_pool_free ( phba - > lpfc_mbuf_pool , pool - > elements [ i ] . virt ,
pool - > elements [ i ] . phys ) ;
kfree ( pool - > elements ) ;
2007-01-02 01:07:32 +01:00
fail_free_lpfc_mbuf_pool :
2005-04-17 16:05:31 -05:00
pci_pool_destroy ( phba - > lpfc_mbuf_pool ) ;
2007-06-17 19:56:36 -05:00
phba - > lpfc_mbuf_pool = NULL ;
2005-04-17 16:05:31 -05:00
fail_free_dma_buf_pool :
pci_pool_destroy ( phba - > lpfc_scsi_dma_buf_pool ) ;
2007-06-17 19:56:36 -05:00
phba - > lpfc_scsi_dma_buf_pool = NULL ;
2005-04-17 16:05:31 -05:00
fail :
return - ENOMEM ;
}
2008-08-24 21:49:00 -04:00
/**
* lpfc_mem_free : Frees all PCI and memory allocated by lpfc_mem_alloc
* @ phba : HBA to free memory for
*
* Description : Frees PCI pools lpfc_scsi_dma_buf_pool , lpfc_mbuf_pool ,
* lpfc_hbq_pool . Frees kmalloc - backed mempools for LPFC_MBOXQ_t and
* lpfc_nodelist . Also frees the VPI bitmask .
*
* Returns : None
* */
2005-04-17 16:05:31 -05:00
void
lpfc_mem_free ( struct lpfc_hba * phba )
{
struct lpfc_sli * psli = & phba - > sli ;
struct lpfc_dma_pool * pool = & phba - > lpfc_mbuf_safety_pool ;
LPFC_MBOXQ_t * mbox , * next_mbox ;
struct lpfc_dmabuf * mp ;
int i ;
2007-06-17 19:56:38 -05:00
kfree ( phba - > vpi_bmask ) ;
2007-06-17 19:56:37 -05:00
lpfc_sli_hbqbuf_free_all ( phba ) ;
2005-04-17 16:05:31 -05:00
list_for_each_entry_safe ( mbox , next_mbox , & psli - > mboxq , 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 ) ;
}
2007-06-17 19:56:38 -05:00
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 ) ;
}
2005-04-17 16:05:31 -05:00
psli - > sli_flag & = ~ LPFC_SLI_MBOX_ACTIVE ;
if ( psli - > mbox_active ) {
mbox = psli - > mbox_active ;
mp = ( struct lpfc_dmabuf * ) ( mbox - > context1 ) ;
if ( mp ) {
lpfc_mbuf_free ( phba , mp - > virt , mp - > phys ) ;
kfree ( mp ) ;
}
mempool_free ( mbox , phba - > mbox_mem_pool ) ;
psli - > mbox_active = NULL ;
}
for ( i = 0 ; i < pool - > current_count ; i + + )
pci_pool_free ( phba - > lpfc_mbuf_pool , pool - > elements [ i ] . virt ,
pool - > elements [ i ] . phys ) ;
kfree ( pool - > elements ) ;
2007-06-17 19:56:36 -05:00
2007-06-17 19:56:37 -05:00
pci_pool_destroy ( phba - > lpfc_hbq_pool ) ;
2005-04-17 16:05:31 -05:00
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 ) ;
2006-07-06 15:49:34 -04:00
2007-06-17 19:56:37 -05:00
phba - > lpfc_hbq_pool = NULL ;
2007-06-17 19:56:36 -05:00
phba - > nlp_mem_pool = NULL ;
phba - > mbox_mem_pool = NULL ;
phba - > lpfc_scsi_dma_buf_pool = NULL ;
phba - > lpfc_mbuf_pool = NULL ;
2008-08-24 21:49:00 -04:00
/* Free the iocb lookup array */
2006-07-06 15:49:34 -04:00
kfree ( psli - > iocbq_lookup ) ;
psli - > iocbq_lookup = NULL ;
2005-04-17 16:05:31 -05:00
}
2008-08-24 21:49:00 -04:00
/**
* lpfc_mbuf_alloc : Allocate an mbuf from the lpfc_mbuf_pool PCI pool
* @ phba : HBA which owns the pool to allocate from
* @ mem_flags : indicates if this is a priority ( MEM_PRI ) allocation
* @ handle : used to return the DMA - mapped address of the mbuf
*
* Description : Allocates a DMA - mapped buffer from the lpfc_mbuf_pool PCI pool .
* Allocates from generic pci_pool_alloc function first and if that fails and
* mem_flags has MEM_PRI set ( the only defined flag ) , returns an mbuf from the
* HBA ' s pool .
*
* Notes : Not interrupt - safe . Must be called with no locks held . Takes
* phba - > hbalock .
*
* Returns :
* pointer to the allocated mbuf on success
* NULL on failure
* */
2005-04-17 16:05:31 -05:00
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 ;
2007-06-17 19:56:36 -05:00
unsigned long iflags ;
2005-04-17 16:05:31 -05:00
void * ret ;
ret = pci_pool_alloc ( phba - > lpfc_mbuf_pool , GFP_KERNEL , handle ) ;
2007-06-17 19:56:36 -05:00
spin_lock_irqsave ( & phba - > hbalock , iflags ) ;
2007-06-17 19:56:38 -05:00
if ( ! ret & & ( mem_flags & MEM_PRI ) & & pool - > current_count ) {
2005-04-17 16:05:31 -05:00
pool - > current_count - - ;
ret = pool - > elements [ pool - > current_count ] . virt ;
* handle = pool - > elements [ pool - > current_count ] . phys ;
}
2007-06-17 19:56:36 -05:00
spin_unlock_irqrestore ( & phba - > hbalock , iflags ) ;
2005-04-17 16:05:31 -05:00
return ret ;
}
2008-08-24 21:49:00 -04:00
/**
* __lpfc_mem_free : Free an mbuf from the lpfc_mbuf_pool PCI pool ( locked )
* @ phba : HBA which owns the pool to return to
* @ virt : mbuf to free
* @ dma : the DMA - mapped address of the lpfc_mbuf_pool to be freed
*
* Description : Returns an mbuf lpfc_mbuf_pool to the lpfc_mbuf_safety_pool if
* it is below its max_count , frees the mbuf otherwise .
*
* Notes : Must be called with phba - > hbalock held to synchronize access to
* lpfc_mbuf_safety_pool .
*
* Returns : None
* */
2005-04-17 16:05:31 -05:00
void
2007-06-17 19:56:36 -05:00
__lpfc_mbuf_free ( struct lpfc_hba * phba , void * virt , dma_addr_t dma )
2005-04-17 16:05:31 -05:00
{
struct lpfc_dma_pool * pool = & phba - > lpfc_mbuf_safety_pool ;
if ( pool - > current_count < pool - > max_count ) {
pool - > elements [ pool - > current_count ] . virt = virt ;
pool - > elements [ pool - > current_count ] . phys = dma ;
pool - > current_count + + ;
} else {
pci_pool_free ( phba - > lpfc_mbuf_pool , virt , dma ) ;
}
return ;
}
2007-06-17 19:56:36 -05:00
2008-08-24 21:49:00 -04:00
/**
* lpfc_mem_free : Free an mbuf from the lpfc_mbuf_pool PCI pool ( unlocked )
* @ phba : HBA which owns the pool to return to
* @ virt : mbuf to free
* @ dma : the DMA - mapped address of the lpfc_mbuf_pool to be freed
*
* Description : Returns an mbuf lpfc_mbuf_pool to the lpfc_mbuf_safety_pool if
* it is below its max_count , frees the mbuf otherwise .
*
* Notes : Takes phba - > hbalock . Can be called with or without other locks held .
*
* Returns : None
* */
2007-06-17 19:56:36 -05:00
void
2008-08-24 21:49:00 -04:00
2007-06-17 19:56:36 -05:00
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 ;
}
2007-06-17 19:56:37 -05:00
2008-08-24 21:49:00 -04:00
/**
* lpfc_els_hbq_alloc : Allocate an HBQ buffer
* @ phba : HBA to allocate HBQ buffer for
*
* Description : Allocates a DMA - mapped HBQ buffer from the lpfc_hbq_pool PCI
* pool along a non - DMA - mapped container for it .
*
* Notes : Not interrupt - safe . Must be called with no locks held .
*
* Returns :
* pointer to HBQ on success
* NULL on failure
* */
2007-08-02 11:10:31 -04:00
struct hbq_dmabuf *
lpfc_els_hbq_alloc ( struct lpfc_hba * phba )
2007-06-17 19:56:37 -05:00
{
2007-08-02 11:10:31 -04:00
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 ;
2007-06-17 19:56:37 -05:00
}
2008-08-24 21:49:00 -04:00
/**
* lpfc_mem_hbq_free : Frees an HBQ buffer allocated with lpfc_els_hbq_alloc
* @ phba : HBA buffer was allocated for
* @ hbqbp : HBQ container returned by lpfc_els_hbq_alloc
*
* Description : Frees both the container and the DMA - mapped buffer returned by
* lpfc_els_hbq_alloc .
*
* Notes : Can be called with or without locks held .
*
* Returns : None
* */
2007-06-17 19:56:37 -05:00
void
2007-08-02 11:10:31 -04:00
lpfc_els_hbq_free ( struct lpfc_hba * phba , struct hbq_dmabuf * hbqbp )
2007-06-17 19:56:37 -05:00
{
2007-08-02 11:10:31 -04:00
pci_pool_free ( phba - > lpfc_hbq_pool , hbqbp - > dbuf . virt , hbqbp - > dbuf . phys ) ;
kfree ( hbqbp ) ;
2007-06-17 19:56:37 -05:00
return ;
}
2008-08-24 21:49:00 -04:00
/**
* lpfc_in_buf_free : Free a DMA buffer
* @ phba : HBA buffer is associated with
* @ mp : Buffer to free
*
* Description : Frees the given DMA buffer in the appropriate way given if the
* HBA is running in SLI3 mode with HBQs enabled .
*
* Notes : Takes phba - > hbalock . Can be called with or without other locks held .
*
* Returns : None
* */
2007-06-17 19:56:38 -05:00
void
lpfc_in_buf_free ( struct lpfc_hba * phba , struct lpfc_dmabuf * mp )
{
struct hbq_dmabuf * hbq_entry ;
2008-02-08 18:50:25 -05:00
unsigned long flags ;
2007-06-17 19:56:38 -05:00
2008-02-08 18:50:14 -05:00
if ( ! mp )
return ;
2007-06-17 19:56:38 -05:00
if ( phba - > sli3_options & LPFC_SLI3_HBQ_ENABLED ) {
2008-02-08 18:50:25 -05:00
/* 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 ;
}
2007-06-17 19:56:38 -05:00
hbq_entry = container_of ( mp , struct hbq_dmabuf , dbuf ) ;
2008-02-08 18:50:25 -05:00
list_del ( & hbq_entry - > dbuf . list ) ;
2007-06-17 19:56:38 -05:00
if ( hbq_entry - > tag = = - 1 ) {
2007-08-02 11:10:31 -04:00
( phba - > hbqs [ LPFC_ELS_HBQ ] . hbq_free_buffer )
( phba , hbq_entry ) ;
2007-06-17 19:56:38 -05:00
} else {
lpfc_sli_free_hbq ( phba , hbq_entry ) ;
}
2008-02-08 18:50:25 -05:00
spin_unlock_irqrestore ( & phba - > hbalock , flags ) ;
2007-06-17 19:56:38 -05:00
} else {
lpfc_mbuf_free ( phba , mp - > virt , mp - > phys ) ;
kfree ( mp ) ;
}
return ;
}