From 2e0fef85e098f6794956b8b80b111179fbb4cbb7 Mon Sep 17 00:00:00 2001 From: James Smart Date: Sun, 17 Jun 2007 19:56:36 -0500 Subject: [SCSI] lpfc: NPIV: split ports The driver is reorganized to separate the handling of the adapter from the handling of the FC port. Adapter handling includes submissions of command requests, receiving responses, and managing adapter resources. The FC port includes the discovery engine, login handling, and the mapping of a Scsi_Host on the "port". Although not a large functional change, as it touches core structures and functions, resulting in a large text delta. Signed-off-by: James Smart Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc_mem.c | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) (limited to 'drivers/scsi/lpfc/lpfc_mem.c') diff --git a/drivers/scsi/lpfc/lpfc_mem.c b/drivers/scsi/lpfc/lpfc_mem.c index ec3bbbd..3aa1dff 100644 --- a/drivers/scsi/lpfc/lpfc_mem.c +++ b/drivers/scsi/lpfc/lpfc_mem.c @@ -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 * @@ -38,6 +38,8 @@ #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) { @@ -84,6 +86,7 @@ lpfc_mem_alloc(struct lpfc_hba * phba) 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 +94,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 +111,7 @@ lpfc_mem_free(struct lpfc_hba * phba) struct lpfc_dmabuf *mp; int i; + spin_lock_irq(&phba->hbalock); list_for_each_entry_safe(mbox, next_mbox, &psli->mboxq, list) { mp = (struct lpfc_dmabuf *) (mbox->context1); if (mp) { @@ -117,6 +123,7 @@ lpfc_mem_free(struct lpfc_hba * phba) } psli->sli_flag &= ~LPFC_SLI_MBOX_ACTIVE; + spin_unlock_irq(&phba->hbalock); if (psli->mbox_active) { mbox = psli->mbox_active; mp = (struct lpfc_dmabuf *) (mbox->context1); @@ -132,12 +139,18 @@ 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); + 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); + 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 +161,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); + 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 +190,14 @@ 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; +} -- cgit v1.1 From ed957684294618602b48f1950b0c9bbcb036583f Mon Sep 17 00:00:00 2001 From: James Smart Date: Sun, 17 Jun 2007 19:56:37 -0500 Subject: [SCSI] lpfc: NPIV: add SLI-3 interface NPIV support is only available via new adapter interface extensions, termed SLI-3. This interface changes some of the basic behaviors such as command and response ring element sizes and data structures, as well as a change in buffer posting. Note: the new firmware extensions are found only on our mid-range and enterprise 4Gig adapters - so NPIV support is available only on these newer adapters. The latest firmware can be downloaded from the Emulex support page. Signed-off-by: James Smart Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc_mem.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) (limited to 'drivers/scsi/lpfc/lpfc_mem.c') diff --git a/drivers/scsi/lpfc/lpfc_mem.c b/drivers/scsi/lpfc/lpfc_mem.c index 3aa1dff..435dc2e 100644 --- a/drivers/scsi/lpfc/lpfc_mem.c +++ b/drivers/scsi/lpfc/lpfc_mem.c @@ -82,8 +82,16 @@ 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; + return 0; + 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; @@ -111,6 +119,8 @@ lpfc_mem_free(struct lpfc_hba * phba) struct lpfc_dmabuf *mp; int i; + lpfc_sli_hbqbuf_free_all(phba); + spin_lock_irq(&phba->hbalock); list_for_each_entry_safe(mbox, next_mbox, &psli->mboxq, list) { mp = (struct lpfc_dmabuf *) (mbox->context1); @@ -140,12 +150,14 @@ lpfc_mem_free(struct lpfc_hba * phba) 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); + phba->lpfc_hbq_pool = NULL; phba->nlp_mem_pool = NULL; phba->mbox_mem_pool = NULL; phba->lpfc_scsi_dma_buf_pool = NULL; @@ -201,3 +213,20 @@ lpfc_mbuf_free(struct lpfc_hba * phba, void *virt, dma_addr_t dma) spin_unlock_irqrestore(&phba->hbalock, iflags); return; } + + +void * +lpfc_hbq_alloc(struct lpfc_hba *phba, int mem_flags, dma_addr_t *handle) +{ + void *ret; + ret = pci_pool_alloc(phba->lpfc_hbq_pool, GFP_ATOMIC, handle); + return ret; +} + +void +lpfc_hbq_free(struct lpfc_hba *phba, void *virt, dma_addr_t dma) +{ + pci_pool_free(phba->lpfc_hbq_pool, virt, dma); + return; +} + -- cgit v1.1 From 92d7f7b0cde3ad2260e7462b40867b57efd49851 Mon Sep 17 00:00:00 2001 From: James Smart Date: Sun, 17 Jun 2007 19:56:38 -0500 Subject: [SCSI] lpfc: NPIV: add NPIV support on top of SLI-3 NPIV support is added to the driver. It utilizes the interfaces of the fc transport for the creation and deletion of vports. Within the driver, a new Scsi_Host is created for each NPIV instance, and is paired with a new instance of a FC port. This allows N FC Port elements to share a single Adapter. Signed-off-by: James Smart Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc_mem.c | 46 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 41 insertions(+), 5 deletions(-) (limited to 'drivers/scsi/lpfc/lpfc_mem.c') diff --git a/drivers/scsi/lpfc/lpfc_mem.c b/drivers/scsi/lpfc/lpfc_mem.c index 435dc2e..6598e89 100644 --- a/drivers/scsi/lpfc/lpfc_mem.c +++ b/drivers/scsi/lpfc/lpfc_mem.c @@ -44,6 +44,7 @@ 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", @@ -87,8 +88,15 @@ lpfc_mem_alloc(struct lpfc_hba * phba) if (!phba->lpfc_hbq_pool) goto fail_free_nlp_mem_pool; + longs = (phba->max_vpi + 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); fail_free_nlp_mem_pool: mempool_destroy(phba->nlp_mem_pool); phba->nlp_mem_pool = NULL; @@ -119,9 +127,9 @@ lpfc_mem_free(struct lpfc_hba * phba) struct lpfc_dmabuf *mp; int i; + kfree(phba->vpi_bmask); lpfc_sli_hbqbuf_free_all(phba); - spin_lock_irq(&phba->hbalock); list_for_each_entry_safe(mbox, next_mbox, &psli->mboxq, list) { mp = (struct lpfc_dmabuf *) (mbox->context1); if (mp) { @@ -131,9 +139,17 @@ 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; - spin_unlock_irq(&phba->hbalock); if (psli->mbox_active) { mbox = psli->mbox_active; mp = (struct lpfc_dmabuf *) (mbox->context1); @@ -163,7 +179,7 @@ lpfc_mem_free(struct lpfc_hba * phba) phba->lpfc_scsi_dma_buf_pool = NULL; phba->lpfc_mbuf_pool = NULL; - /* Free the iocb lookup array */ + /* Free the iocb lookup array */ kfree(psli->iocbq_lookup); psli->iocbq_lookup = NULL; @@ -179,7 +195,7 @@ lpfc_mbuf_alloc(struct lpfc_hba *phba, int mem_flags, dma_addr_t *handle) ret = pci_pool_alloc(phba->lpfc_mbuf_pool, GFP_KERNEL, handle); spin_lock_irqsave(&phba->hbalock, iflags); - if (!ret && ( mem_flags & MEM_PRI) && pool->current_count) { + 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; @@ -214,7 +230,6 @@ lpfc_mbuf_free(struct lpfc_hba * phba, void *virt, dma_addr_t dma) return; } - void * lpfc_hbq_alloc(struct lpfc_hba *phba, int mem_flags, dma_addr_t *handle) { @@ -230,3 +245,24 @@ lpfc_hbq_free(struct lpfc_hba *phba, void *virt, dma_addr_t dma) return; } +void +lpfc_in_buf_free(struct lpfc_hba *phba, struct lpfc_dmabuf *mp) +{ + struct hbq_dmabuf *hbq_entry; + + if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) { + hbq_entry = container_of(mp, struct hbq_dmabuf, dbuf); + if (hbq_entry->tag == -1) { + lpfc_hbq_free(phba, hbq_entry->dbuf.virt, + hbq_entry->dbuf.phys); + kfree(hbq_entry); + } else { + lpfc_sli_free_hbq(phba, hbq_entry); + } + } else { + lpfc_mbuf_free(phba, mp->virt, mp->phys); + kfree(mp); + } + return; +} + -- cgit v1.1 From 858c9f6c19c6f9bf86cbbc64ce0d17c61d6131b8 Mon Sep 17 00:00:00 2001 From: James Smart Date: Sun, 17 Jun 2007 19:56:39 -0500 Subject: [SCSI] lpfc: bug fixes Following the NPIV support, the following changes have been accumulated in the testing and qualification of the driver: - Fix affinity of ELS ring to slow/deferred event processing - Fix Ring attention masks - Defer dev_loss_tmo timeout handling to worker thread - Consolidate link down error classification for better error checking - Remove unused/deprecated nlp_initiator_tmr timer - Fix for async scan - move adapter init code back into pci_probe_one context. Fix async scan interfaces. - Expand validation of ability to create vports - Extract VPI resource cnt from firmware - Tuning of Login/Reject policies to better deal with overwhelmned targets - Misc ELS and discovery fixes - Export the npiv_enable attribute to sysfs - Mailbox handling fix - Add debugfs support - A few other small misc fixes: - wrong return values, double-frees, bad locking - Added adapter failure heartbeat Signed-off-by: James Smart Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc_mem.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/scsi/lpfc/lpfc_mem.c') diff --git a/drivers/scsi/lpfc/lpfc_mem.c b/drivers/scsi/lpfc/lpfc_mem.c index 6598e89..3594c46 100644 --- a/drivers/scsi/lpfc/lpfc_mem.c +++ b/drivers/scsi/lpfc/lpfc_mem.c @@ -88,7 +88,8 @@ lpfc_mem_alloc(struct lpfc_hba * phba) if (!phba->lpfc_hbq_pool) goto fail_free_nlp_mem_pool; - longs = (phba->max_vpi + BITS_PER_LONG - 1) / BITS_PER_LONG; + /* 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; -- cgit v1.1