2005-04-18 04:05:31 +07:00
|
|
|
/*******************************************************************
|
|
|
|
* This file is part of the Emulex Linux Device Driver for *
|
2005-06-25 21:34:39 +07:00
|
|
|
* Fibre Channel Host Bus Adapters. *
|
2019-01-29 02:14:41 +07:00
|
|
|
* Copyright (C) 2017-2019 Broadcom. All Rights Reserved. The term *
|
2018-06-26 22:24:31 +07:00
|
|
|
* “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. *
|
2016-04-01 04:12:34 +07:00
|
|
|
* Copyright (C) 2004-2016 Emulex. All rights reserved. *
|
2005-06-25 21:34:39 +07:00
|
|
|
* EMULEX and SLI are trademarks of Emulex. *
|
2017-02-13 04:52:39 +07:00
|
|
|
* www.broadcom.com *
|
2005-04-18 04:05:31 +07:00
|
|
|
* *
|
|
|
|
* This program is free software; you can redistribute it and/or *
|
2005-06-25 21:34:39 +07: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-18 04:05:31 +07:00
|
|
|
*******************************************************************/
|
|
|
|
|
|
|
|
/*
|
2008-01-11 13:52:54 +07:00
|
|
|
* Fibre Channel SCSI LAN Device Driver CT support: FC Generic Services FC-GS
|
2005-04-18 04:05:31 +07:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include <linux/blkdev.h>
|
|
|
|
#include <linux/pci.h>
|
|
|
|
#include <linux/interrupt.h>
|
include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit slab.h inclusion from percpu.h
percpu.h is included by sched.h and module.h and thus ends up being
included when building most .c files. percpu.h includes slab.h which
in turn includes gfp.h making everything defined by the two files
universally available and complicating inclusion dependencies.
percpu.h -> slab.h dependency is about to be removed. Prepare for
this change by updating users of gfp and slab facilities include those
headers directly instead of assuming availability. As this conversion
needs to touch large number of source files, the following script is
used as the basis of conversion.
http://userweb.kernel.org/~tj/misc/slabh-sweep.py
The script does the followings.
* Scan files for gfp and slab usages and update includes such that
only the necessary includes are there. ie. if only gfp is used,
gfp.h, if slab is used, slab.h.
* When the script inserts a new include, it looks at the include
blocks and try to put the new include such that its order conforms
to its surrounding. It's put in the include block which contains
core kernel includes, in the same order that the rest are ordered -
alphabetical, Christmas tree, rev-Xmas-tree or at the end if there
doesn't seem to be any matching order.
* If the script can't find a place to put a new include (mostly
because the file doesn't have fitting include block), it prints out
an error message indicating which .h file needs to be added to the
file.
The conversion was done in the following steps.
1. The initial automatic conversion of all .c files updated slightly
over 4000 files, deleting around 700 includes and adding ~480 gfp.h
and ~3000 slab.h inclusions. The script emitted errors for ~400
files.
2. Each error was manually checked. Some didn't need the inclusion,
some needed manual addition while adding it to implementation .h or
embedding .c file was more appropriate for others. This step added
inclusions to around 150 files.
3. The script was run again and the output was compared to the edits
from #2 to make sure no file was left behind.
4. Several build tests were done and a couple of problems were fixed.
e.g. lib/decompress_*.c used malloc/free() wrappers around slab
APIs requiring slab.h to be added manually.
5. The script was run on all .h files but without automatically
editing them as sprinkling gfp.h and slab.h inclusions around .h
files could easily lead to inclusion dependency hell. Most gfp.h
inclusion directives were ignored as stuff from gfp.h was usually
wildly available and often used in preprocessor macros. Each
slab.h inclusion directive was examined and added manually as
necessary.
6. percpu.h was updated not to include slab.h.
7. Build test were done on the following configurations and failures
were fixed. CONFIG_GCOV_KERNEL was turned off for all tests (as my
distributed build env didn't work with gcov compiles) and a few
more options had to be turned off depending on archs to make things
build (like ipr on powerpc/64 which failed due to missing writeq).
* x86 and x86_64 UP and SMP allmodconfig and a custom test config.
* powerpc and powerpc64 SMP allmodconfig
* sparc and sparc64 SMP allmodconfig
* ia64 SMP allmodconfig
* s390 SMP allmodconfig
* alpha SMP allmodconfig
* um on x86_64 SMP allmodconfig
8. percpu.h modifications were reverted so that it could be applied as
a separate patch and serve as bisection point.
Given the fact that I had only a couple of failures from tests on step
6, I'm fairly confident about the coverage of this conversion patch.
If there is a breakage, it's likely to be something in one of the arch
headers which should be easily discoverable easily on most builds of
the specific arch.
Signed-off-by: Tejun Heo <tj@kernel.org>
Guess-its-ok-by: Christoph Lameter <cl@linux-foundation.org>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Lee Schermerhorn <Lee.Schermerhorn@hp.com>
2010-03-24 15:04:11 +07:00
|
|
|
#include <linux/slab.h>
|
2005-04-18 04:05:31 +07:00
|
|
|
#include <linux/utsname.h>
|
|
|
|
|
2005-08-11 02:03:09 +07:00
|
|
|
#include <scsi/scsi.h>
|
2005-04-18 04:05:31 +07:00
|
|
|
#include <scsi/scsi_device.h>
|
|
|
|
#include <scsi/scsi_host.h>
|
2005-08-11 02:03:01 +07:00
|
|
|
#include <scsi/scsi_transport_fc.h>
|
2009-10-03 02:16:51 +07:00
|
|
|
#include <scsi/fc/fc_fs.h>
|
2005-04-18 04:05:31 +07:00
|
|
|
|
2009-05-23 01:51:39 +07:00
|
|
|
#include "lpfc_hw4.h"
|
2005-04-18 04:05:31 +07:00
|
|
|
#include "lpfc_hw.h"
|
|
|
|
#include "lpfc_sli.h"
|
2009-05-23 01:51:39 +07:00
|
|
|
#include "lpfc_sli4.h"
|
2008-09-07 22:52:10 +07:00
|
|
|
#include "lpfc_nl.h"
|
2005-04-18 04:05:31 +07:00
|
|
|
#include "lpfc_disc.h"
|
|
|
|
#include "lpfc.h"
|
2017-02-13 04:52:31 +07:00
|
|
|
#include "lpfc_scsi.h"
|
|
|
|
#include "lpfc_nvme.h"
|
2005-04-18 04:05:31 +07:00
|
|
|
#include "lpfc_logmsg.h"
|
|
|
|
#include "lpfc_crtn.h"
|
|
|
|
#include "lpfc_version.h"
|
2007-06-18 07:56:38 +07:00
|
|
|
#include "lpfc_vport.h"
|
2007-06-18 07:56:39 +07:00
|
|
|
#include "lpfc_debugfs.h"
|
2005-04-18 04:05:31 +07:00
|
|
|
|
2015-12-17 06:12:02 +07:00
|
|
|
/* FDMI Port Speed definitions - FC-GS-7 */
|
|
|
|
#define HBA_PORTSPEED_1GFC 0x00000001 /* 1G FC */
|
|
|
|
#define HBA_PORTSPEED_2GFC 0x00000002 /* 2G FC */
|
|
|
|
#define HBA_PORTSPEED_4GFC 0x00000008 /* 4G FC */
|
|
|
|
#define HBA_PORTSPEED_10GFC 0x00000004 /* 10G FC */
|
|
|
|
#define HBA_PORTSPEED_8GFC 0x00000010 /* 8G FC */
|
|
|
|
#define HBA_PORTSPEED_16GFC 0x00000020 /* 16G FC */
|
|
|
|
#define HBA_PORTSPEED_32GFC 0x00000040 /* 32G FC */
|
|
|
|
#define HBA_PORTSPEED_20GFC 0x00000080 /* 20G FC */
|
|
|
|
#define HBA_PORTSPEED_40GFC 0x00000100 /* 40G FC */
|
|
|
|
#define HBA_PORTSPEED_128GFC 0x00000200 /* 128G FC */
|
|
|
|
#define HBA_PORTSPEED_64GFC 0x00000400 /* 64G FC */
|
|
|
|
#define HBA_PORTSPEED_256GFC 0x00000800 /* 256G FC */
|
|
|
|
#define HBA_PORTSPEED_UNKNOWN 0x00008000 /* Unknown */
|
|
|
|
#define HBA_PORTSPEED_10GE 0x00010000 /* 10G E */
|
|
|
|
#define HBA_PORTSPEED_40GE 0x00020000 /* 40G E */
|
|
|
|
#define HBA_PORTSPEED_100GE 0x00040000 /* 100G E */
|
|
|
|
#define HBA_PORTSPEED_25GE 0x00080000 /* 25G E */
|
|
|
|
#define HBA_PORTSPEED_50GE 0x00100000 /* 50G E */
|
|
|
|
#define HBA_PORTSPEED_400GE 0x00200000 /* 400G E */
|
2005-04-18 04:05:31 +07:00
|
|
|
|
|
|
|
#define FOURBYTES 4
|
|
|
|
|
|
|
|
|
|
|
|
static char *lpfc_release_version = LPFC_DRIVER_VERSION;
|
|
|
|
|
2007-06-18 07:56:37 +07:00
|
|
|
static void
|
2008-01-11 13:53:18 +07:00
|
|
|
lpfc_ct_ignore_hbq_buffer(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq,
|
|
|
|
struct lpfc_dmabuf *mp, uint32_t size)
|
2007-06-18 07:56:37 +07:00
|
|
|
{
|
|
|
|
if (!mp) {
|
2008-01-11 13:53:18 +07:00
|
|
|
lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
|
2008-04-07 21:16:05 +07:00
|
|
|
"0146 Ignoring unsolicited CT No HBQ "
|
2008-01-11 13:53:18 +07:00
|
|
|
"status = x%x\n",
|
|
|
|
piocbq->iocb.ulpStatus);
|
2007-06-18 07:56:37 +07:00
|
|
|
}
|
2008-01-11 13:53:18 +07:00
|
|
|
lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
|
|
|
|
"0145 Ignoring unsolicted CT HBQ Size:%d "
|
|
|
|
"status = x%x\n",
|
|
|
|
size, piocbq->iocb.ulpStatus);
|
2007-06-18 07:56:37 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2008-01-11 13:53:18 +07:00
|
|
|
lpfc_ct_unsol_buffer(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq,
|
|
|
|
struct lpfc_dmabuf *mp, uint32_t size)
|
2007-06-18 07:56:37 +07:00
|
|
|
{
|
2008-01-11 13:53:18 +07:00
|
|
|
lpfc_ct_ignore_hbq_buffer(phba, piocbq, mp, size);
|
2007-06-18 07:56:37 +07:00
|
|
|
}
|
|
|
|
|
2005-04-18 04:05:31 +07:00
|
|
|
void
|
2007-06-18 07:56:36 +07:00
|
|
|
lpfc_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
|
|
|
|
struct lpfc_iocbq *piocbq)
|
2005-04-18 04:05:31 +07:00
|
|
|
{
|
2007-06-18 07:56:37 +07:00
|
|
|
struct lpfc_dmabuf *mp = NULL;
|
2005-04-18 04:05:31 +07:00
|
|
|
IOCB_t *icmd = &piocbq->iocb;
|
2007-06-18 07:56:37 +07:00
|
|
|
int i;
|
|
|
|
struct lpfc_iocbq *iocbq;
|
|
|
|
dma_addr_t paddr;
|
|
|
|
uint32_t size;
|
2008-01-11 13:53:18 +07:00
|
|
|
struct list_head head;
|
|
|
|
struct lpfc_dmabuf *bdeBuf;
|
2005-04-18 04:05:31 +07:00
|
|
|
|
2010-01-27 11:08:55 +07:00
|
|
|
if (lpfc_bsg_ct_unsol_event(phba, pring, piocbq) == 0)
|
|
|
|
return;
|
2009-07-19 21:01:32 +07:00
|
|
|
|
2007-06-18 07:56:38 +07:00
|
|
|
if (unlikely(icmd->ulpStatus == IOSTAT_NEED_BUFFER)) {
|
|
|
|
lpfc_sli_hbqbuf_add_hbqs(phba, LPFC_ELS_HBQ);
|
|
|
|
} else if ((icmd->ulpStatus == IOSTAT_LOCAL_REJECT) &&
|
2012-08-15 01:25:43 +07:00
|
|
|
((icmd->un.ulpWord[4] & IOERR_PARAM_MASK) ==
|
|
|
|
IOERR_RCV_BUFFER_WAITING)) {
|
2005-04-18 04:05:31 +07:00
|
|
|
/* Not enough posted buffers; Try posting more buffers */
|
|
|
|
phba->fc_stat.NoRcvBuf++;
|
2007-06-18 07:56:38 +07:00
|
|
|
if (!(phba->sli3_options & LPFC_SLI3_HBQ_ENABLED))
|
2008-06-15 09:52:59 +07:00
|
|
|
lpfc_post_buffer(phba, pring, 2);
|
2005-04-18 04:05:31 +07:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If there are no BDEs associated with this IOCB,
|
|
|
|
* there is nothing to do.
|
|
|
|
*/
|
|
|
|
if (icmd->ulpBdeCount == 0)
|
|
|
|
return;
|
|
|
|
|
2007-06-18 07:56:37 +07:00
|
|
|
if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) {
|
2008-01-11 13:53:18 +07:00
|
|
|
INIT_LIST_HEAD(&head);
|
|
|
|
list_add_tail(&head, &piocbq->list);
|
|
|
|
list_for_each_entry(iocbq, &head, list) {
|
2007-06-18 07:56:37 +07:00
|
|
|
icmd = &iocbq->iocb;
|
2008-01-11 13:53:18 +07:00
|
|
|
if (icmd->ulpBdeCount == 0)
|
2007-06-18 07:56:37 +07:00
|
|
|
continue;
|
2008-01-11 13:53:18 +07:00
|
|
|
bdeBuf = iocbq->context2;
|
|
|
|
iocbq->context2 = NULL;
|
2007-06-18 07:56:37 +07:00
|
|
|
size = icmd->un.cont64[0].tus.f.bdeSize;
|
2008-01-11 13:53:18 +07:00
|
|
|
lpfc_ct_unsol_buffer(phba, piocbq, bdeBuf, size);
|
|
|
|
lpfc_in_buf_free(phba, bdeBuf);
|
2007-06-18 07:56:37 +07:00
|
|
|
if (icmd->ulpBdeCount == 2) {
|
2008-01-11 13:53:18 +07:00
|
|
|
bdeBuf = iocbq->context3;
|
|
|
|
iocbq->context3 = NULL;
|
|
|
|
size = icmd->unsli3.rcvsli3.bde2.tus.f.bdeSize;
|
|
|
|
lpfc_ct_unsol_buffer(phba, piocbq, bdeBuf,
|
|
|
|
size);
|
|
|
|
lpfc_in_buf_free(phba, bdeBuf);
|
2007-06-18 07:56:37 +07:00
|
|
|
}
|
2005-04-18 04:05:31 +07:00
|
|
|
}
|
2008-01-11 13:53:18 +07:00
|
|
|
list_del(&head);
|
2007-06-18 07:56:37 +07:00
|
|
|
} else {
|
2008-08-25 08:50:00 +07:00
|
|
|
INIT_LIST_HEAD(&head);
|
|
|
|
list_add_tail(&head, &piocbq->list);
|
|
|
|
list_for_each_entry(iocbq, &head, list) {
|
2007-06-18 07:56:37 +07:00
|
|
|
icmd = &iocbq->iocb;
|
2008-01-11 13:53:18 +07:00
|
|
|
if (icmd->ulpBdeCount == 0)
|
2008-08-25 08:50:00 +07:00
|
|
|
lpfc_ct_unsol_buffer(phba, iocbq, NULL, 0);
|
2007-06-18 07:56:37 +07:00
|
|
|
for (i = 0; i < icmd->ulpBdeCount; i++) {
|
|
|
|
paddr = getPaddr(icmd->un.cont64[i].addrHigh,
|
|
|
|
icmd->un.cont64[i].addrLow);
|
|
|
|
mp = lpfc_sli_ringpostbuf_get(phba, pring,
|
|
|
|
paddr);
|
|
|
|
size = icmd->un.cont64[i].tus.f.bdeSize;
|
2008-08-25 08:50:00 +07:00
|
|
|
lpfc_ct_unsol_buffer(phba, iocbq, mp, size);
|
2007-06-18 07:56:38 +07:00
|
|
|
lpfc_in_buf_free(phba, mp);
|
2007-06-18 07:56:37 +07:00
|
|
|
}
|
2008-06-15 09:52:59 +07:00
|
|
|
lpfc_post_buffer(phba, pring, i);
|
2005-04-18 04:05:31 +07:00
|
|
|
}
|
2008-08-25 08:50:00 +07:00
|
|
|
list_del(&head);
|
2005-04-18 04:05:31 +07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-10-03 02:16:45 +07:00
|
|
|
/**
|
2013-01-04 03:43:37 +07:00
|
|
|
* lpfc_ct_handle_unsol_abort - ct upper level protocol abort handler
|
2009-10-03 02:16:45 +07:00
|
|
|
* @phba: Pointer to HBA context object.
|
2013-01-04 03:43:37 +07:00
|
|
|
* @dmabuf: pointer to a dmabuf that describes the FC sequence
|
2009-10-03 02:16:45 +07:00
|
|
|
*
|
2013-01-04 03:43:37 +07:00
|
|
|
* This function serves as the upper level protocol abort handler for CT
|
|
|
|
* protocol.
|
|
|
|
*
|
|
|
|
* Return 1 if abort has been handled, 0 otherwise.
|
2009-10-03 02:16:45 +07:00
|
|
|
**/
|
2013-01-04 03:43:37 +07:00
|
|
|
int
|
|
|
|
lpfc_ct_handle_unsol_abort(struct lpfc_hba *phba, struct hbq_dmabuf *dmabuf)
|
2009-10-03 02:16:45 +07:00
|
|
|
{
|
2013-01-04 03:43:37 +07:00
|
|
|
int handled;
|
2009-10-03 02:16:45 +07:00
|
|
|
|
2013-01-04 03:43:37 +07:00
|
|
|
/* CT upper level goes through BSG */
|
|
|
|
handled = lpfc_bsg_ct_unsol_abort(phba, dmabuf);
|
2009-10-03 02:16:45 +07:00
|
|
|
|
2013-01-04 03:43:37 +07:00
|
|
|
return handled;
|
2009-10-03 02:16:45 +07:00
|
|
|
}
|
|
|
|
|
2005-04-18 04:05:31 +07:00
|
|
|
static void
|
2007-06-18 07:56:36 +07:00
|
|
|
lpfc_free_ct_rsp(struct lpfc_hba *phba, struct lpfc_dmabuf *mlist)
|
2005-04-18 04:05:31 +07:00
|
|
|
{
|
|
|
|
struct lpfc_dmabuf *mlast, *next_mlast;
|
|
|
|
|
|
|
|
list_for_each_entry_safe(mlast, next_mlast, &mlist->list, list) {
|
|
|
|
lpfc_mbuf_free(phba, mlast->virt, mlast->phys);
|
|
|
|
list_del(&mlast->list);
|
|
|
|
kfree(mlast);
|
|
|
|
}
|
|
|
|
lpfc_mbuf_free(phba, mlist->virt, mlist->phys);
|
|
|
|
kfree(mlist);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct lpfc_dmabuf *
|
2007-06-18 07:56:36 +07:00
|
|
|
lpfc_alloc_ct_rsp(struct lpfc_hba *phba, int cmdcode, struct ulp_bde64 *bpl,
|
2005-04-18 04:05:31 +07:00
|
|
|
uint32_t size, int *entries)
|
|
|
|
{
|
|
|
|
struct lpfc_dmabuf *mlist = NULL;
|
|
|
|
struct lpfc_dmabuf *mp;
|
|
|
|
int cnt, i = 0;
|
|
|
|
|
2008-01-11 13:52:54 +07:00
|
|
|
/* We get chunks of FCELSSIZE */
|
2005-04-18 04:05:31 +07:00
|
|
|
cnt = size > FCELSSIZE ? FCELSSIZE: size;
|
|
|
|
|
|
|
|
while (size) {
|
|
|
|
/* Allocate buffer for rsp payload */
|
|
|
|
mp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
|
|
|
|
if (!mp) {
|
|
|
|
if (mlist)
|
|
|
|
lpfc_free_ct_rsp(phba, mlist);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
INIT_LIST_HEAD(&mp->list);
|
|
|
|
|
2007-06-18 07:56:38 +07:00
|
|
|
if (cmdcode == be16_to_cpu(SLI_CTNS_GID_FT) ||
|
|
|
|
cmdcode == be16_to_cpu(SLI_CTNS_GFF_ID))
|
2005-04-18 04:05:31 +07:00
|
|
|
mp->virt = lpfc_mbuf_alloc(phba, MEM_PRI, &(mp->phys));
|
|
|
|
else
|
|
|
|
mp->virt = lpfc_mbuf_alloc(phba, 0, &(mp->phys));
|
|
|
|
|
|
|
|
if (!mp->virt) {
|
|
|
|
kfree(mp);
|
2006-10-11 04:41:43 +07:00
|
|
|
if (mlist)
|
|
|
|
lpfc_free_ct_rsp(phba, mlist);
|
2005-04-18 04:05:31 +07:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Queue it to a linked list */
|
|
|
|
if (!mlist)
|
|
|
|
mlist = mp;
|
|
|
|
else
|
|
|
|
list_add_tail(&mp->list, &mlist->list);
|
|
|
|
|
2008-08-25 08:49:55 +07:00
|
|
|
bpl->tus.f.bdeFlags = BUFF_TYPE_BDE_64I;
|
2005-04-18 04:05:31 +07:00
|
|
|
/* build buffer ptr list for IOCB */
|
2007-06-18 07:56:38 +07:00
|
|
|
bpl->addrLow = le32_to_cpu(putPaddrLow(mp->phys) );
|
|
|
|
bpl->addrHigh = le32_to_cpu(putPaddrHigh(mp->phys) );
|
2005-04-18 04:05:31 +07:00
|
|
|
bpl->tus.f.bdeSize = (uint16_t) cnt;
|
|
|
|
bpl->tus.w = le32_to_cpu(bpl->tus.w);
|
|
|
|
bpl++;
|
|
|
|
|
|
|
|
i++;
|
|
|
|
size -= cnt;
|
|
|
|
}
|
|
|
|
|
|
|
|
*entries = i;
|
|
|
|
return mlist;
|
|
|
|
}
|
|
|
|
|
2007-06-18 07:56:39 +07:00
|
|
|
int
|
|
|
|
lpfc_ct_free_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *ctiocb)
|
|
|
|
{
|
|
|
|
struct lpfc_dmabuf *buf_ptr;
|
|
|
|
|
2007-08-02 22:10:31 +07:00
|
|
|
if (ctiocb->context_un.ndlp) {
|
|
|
|
lpfc_nlp_put(ctiocb->context_un.ndlp);
|
|
|
|
ctiocb->context_un.ndlp = NULL;
|
|
|
|
}
|
2007-06-18 07:56:39 +07:00
|
|
|
if (ctiocb->context1) {
|
|
|
|
buf_ptr = (struct lpfc_dmabuf *) ctiocb->context1;
|
|
|
|
lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys);
|
|
|
|
kfree(buf_ptr);
|
|
|
|
ctiocb->context1 = NULL;
|
|
|
|
}
|
|
|
|
if (ctiocb->context2) {
|
|
|
|
lpfc_free_ct_rsp(phba, (struct lpfc_dmabuf *) ctiocb->context2);
|
|
|
|
ctiocb->context2 = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ctiocb->context3) {
|
|
|
|
buf_ptr = (struct lpfc_dmabuf *) ctiocb->context3;
|
|
|
|
lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys);
|
|
|
|
kfree(buf_ptr);
|
2013-10-16 07:29:50 +07:00
|
|
|
ctiocb->context3 = NULL;
|
2007-06-18 07:56:39 +07:00
|
|
|
}
|
|
|
|
lpfc_sli_release_iocbq(phba, ctiocb);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-12-17 06:11:58 +07:00
|
|
|
/**
|
|
|
|
* lpfc_gen_req - Build and issue a GEN_REQUEST command to the SLI Layer
|
|
|
|
* @vport: pointer to a host virtual N_Port data structure.
|
|
|
|
* @bmp: Pointer to BPL for SLI command
|
|
|
|
* @inp: Pointer to data buffer for response data.
|
|
|
|
* @outp: Pointer to data buffer that hold the CT command.
|
|
|
|
* @cmpl: completion routine to call when command completes
|
|
|
|
* @ndlp: Destination NPort nodelist entry
|
|
|
|
*
|
|
|
|
* This function as the final part for issuing a CT command.
|
|
|
|
*/
|
2005-04-18 04:05:31 +07:00
|
|
|
static int
|
2007-06-18 07:56:36 +07:00
|
|
|
lpfc_gen_req(struct lpfc_vport *vport, struct lpfc_dmabuf *bmp,
|
2005-04-18 04:05:31 +07:00
|
|
|
struct lpfc_dmabuf *inp, struct lpfc_dmabuf *outp,
|
|
|
|
void (*cmpl) (struct lpfc_hba *, struct lpfc_iocbq *,
|
|
|
|
struct lpfc_iocbq *),
|
|
|
|
struct lpfc_nodelist *ndlp, uint32_t usr_flg, uint32_t num_entry,
|
2007-06-18 07:56:38 +07:00
|
|
|
uint32_t tmo, uint8_t retry)
|
2005-04-18 04:05:31 +07:00
|
|
|
{
|
2007-06-18 07:56:36 +07:00
|
|
|
struct lpfc_hba *phba = vport->phba;
|
2005-04-18 04:05:31 +07:00
|
|
|
IOCB_t *icmd;
|
2005-10-29 07:30:02 +07:00
|
|
|
struct lpfc_iocbq *geniocb;
|
2007-06-18 07:56:38 +07:00
|
|
|
int rc;
|
2005-04-18 04:05:31 +07:00
|
|
|
|
|
|
|
/* Allocate buffer for command iocb */
|
2005-10-29 07:30:02 +07:00
|
|
|
geniocb = lpfc_sli_get_iocbq(phba);
|
2005-04-18 04:05:31 +07:00
|
|
|
|
|
|
|
if (geniocb == NULL)
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
icmd = &geniocb->iocb;
|
|
|
|
icmd->un.genreq64.bdl.ulpIoTag32 = 0;
|
|
|
|
icmd->un.genreq64.bdl.addrHigh = putPaddrHigh(bmp->phys);
|
|
|
|
icmd->un.genreq64.bdl.addrLow = putPaddrLow(bmp->phys);
|
2008-08-25 08:49:55 +07:00
|
|
|
icmd->un.genreq64.bdl.bdeFlags = BUFF_TYPE_BLP_64;
|
2015-12-17 06:11:58 +07:00
|
|
|
icmd->un.genreq64.bdl.bdeSize = (num_entry * sizeof(struct ulp_bde64));
|
2005-04-18 04:05:31 +07:00
|
|
|
|
|
|
|
if (usr_flg)
|
|
|
|
geniocb->context3 = NULL;
|
|
|
|
else
|
|
|
|
geniocb->context3 = (uint8_t *) bmp;
|
|
|
|
|
|
|
|
/* Save for completion so we can release these resources */
|
|
|
|
geniocb->context1 = (uint8_t *) inp;
|
|
|
|
geniocb->context2 = (uint8_t *) outp;
|
2008-02-09 06:49:26 +07:00
|
|
|
geniocb->context_un.ndlp = lpfc_nlp_get(ndlp);
|
2005-04-18 04:05:31 +07:00
|
|
|
|
|
|
|
/* Fill in payload, bp points to frame payload */
|
|
|
|
icmd->ulpCommand = CMD_GEN_REQUEST64_CR;
|
|
|
|
|
|
|
|
/* Fill in rest of iocb */
|
|
|
|
icmd->un.genreq64.w5.hcsw.Fctl = (SI | LA);
|
|
|
|
icmd->un.genreq64.w5.hcsw.Dfctl = 0;
|
2009-10-03 02:16:51 +07:00
|
|
|
icmd->un.genreq64.w5.hcsw.Rctl = FC_RCTL_DD_UNSOL_CTL;
|
|
|
|
icmd->un.genreq64.w5.hcsw.Type = FC_TYPE_CT;
|
2005-04-18 04:05:31 +07:00
|
|
|
|
2006-03-01 07:25:23 +07:00
|
|
|
if (!tmo) {
|
|
|
|
/* FC spec states we need 3 * ratov for CT requests */
|
|
|
|
tmo = (3 * phba->fc_ratov);
|
|
|
|
}
|
2005-04-18 04:05:31 +07:00
|
|
|
icmd->ulpTimeout = tmo;
|
|
|
|
icmd->ulpBdeCount = 1;
|
|
|
|
icmd->ulpLe = 1;
|
|
|
|
icmd->ulpClass = CLASS3;
|
|
|
|
icmd->ulpContext = ndlp->nlp_rpi;
|
2011-05-24 22:44:12 +07:00
|
|
|
if (phba->sli_rev == LPFC_SLI_REV4)
|
|
|
|
icmd->ulpContext = phba->sli4_hba.rpi_ids[ndlp->nlp_rpi];
|
2005-04-18 04:05:31 +07:00
|
|
|
|
2007-06-18 07:56:38 +07:00
|
|
|
if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) {
|
|
|
|
/* For GEN_REQUEST64_CR, use the RPI */
|
|
|
|
icmd->ulpCt_h = 0;
|
|
|
|
icmd->ulpCt_l = 0;
|
|
|
|
}
|
|
|
|
|
2005-04-18 04:05:31 +07:00
|
|
|
/* Issue GEN REQ IOCB for NPORT <did> */
|
2007-08-02 22:10:09 +07:00
|
|
|
lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
|
|
|
|
"0119 Issue GEN REQ IOCB to NPORT x%x "
|
|
|
|
"Data: x%x x%x\n",
|
|
|
|
ndlp->nlp_DID, icmd->ulpIoTag,
|
|
|
|
vport->port_state);
|
2005-04-18 04:05:31 +07:00
|
|
|
geniocb->iocb_cmpl = cmpl;
|
|
|
|
geniocb->drvrTimeout = icmd->ulpTimeout + LPFC_DRVR_TIMEOUT;
|
2007-06-18 07:56:36 +07:00
|
|
|
geniocb->vport = vport;
|
2007-06-18 07:56:38 +07:00
|
|
|
geniocb->retry = retry;
|
[SCSI] lpfc 8.3.2 : Reorganization for SLI4
Preps the organization of the driver so that the bottom half, which
interacts with the hardware, can share common code sequences for
attachment, detachment, initialization, teardown, etc with new hardware.
For very common code sections, which become specific to the interface
type, the driver uses an indirect function call. The function is set at
initialization. For less common sections, such as initialization, the
driver looks at the interface type and calls the routines relative to
the interface.
Signed-off-by: James Smart <james.smart@emulex.com>
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
2009-05-23 01:50:54 +07:00
|
|
|
rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, geniocb, 0);
|
2007-06-18 07:56:38 +07:00
|
|
|
|
|
|
|
if (rc == IOCB_ERROR) {
|
2005-10-29 22:28:33 +07:00
|
|
|
lpfc_sli_release_iocbq(phba, geniocb);
|
2005-04-18 04:05:31 +07:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-12-17 06:11:58 +07:00
|
|
|
/**
|
|
|
|
* lpfc_ct_cmd - Build and issue a CT command
|
|
|
|
* @vport: pointer to a host virtual N_Port data structure.
|
|
|
|
* @inmp: Pointer to data buffer for response data.
|
|
|
|
* @bmp: Pointer to BPL for SLI command
|
|
|
|
* @ndlp: Destination NPort nodelist entry
|
|
|
|
* @cmpl: completion routine to call when command completes
|
|
|
|
*
|
|
|
|
* This function is called for issuing a CT command.
|
|
|
|
*/
|
2005-04-18 04:05:31 +07:00
|
|
|
static int
|
2007-06-18 07:56:36 +07:00
|
|
|
lpfc_ct_cmd(struct lpfc_vport *vport, struct lpfc_dmabuf *inmp,
|
2005-04-18 04:05:31 +07:00
|
|
|
struct lpfc_dmabuf *bmp, struct lpfc_nodelist *ndlp,
|
|
|
|
void (*cmpl) (struct lpfc_hba *, struct lpfc_iocbq *,
|
|
|
|
struct lpfc_iocbq *),
|
2007-06-18 07:56:38 +07:00
|
|
|
uint32_t rsp_size, uint8_t retry)
|
2005-04-18 04:05:31 +07:00
|
|
|
{
|
2007-06-18 07:56:36 +07:00
|
|
|
struct lpfc_hba *phba = vport->phba;
|
2005-04-18 04:05:31 +07:00
|
|
|
struct ulp_bde64 *bpl = (struct ulp_bde64 *) bmp->virt;
|
|
|
|
struct lpfc_dmabuf *outmp;
|
|
|
|
int cnt = 0, status;
|
|
|
|
int cmdcode = ((struct lpfc_sli_ct_request *) inmp->virt)->
|
|
|
|
CommandResponse.bits.CmdRsp;
|
|
|
|
|
|
|
|
bpl++; /* Skip past ct request */
|
|
|
|
|
|
|
|
/* Put buffer(s) for ct rsp in bpl */
|
|
|
|
outmp = lpfc_alloc_ct_rsp(phba, cmdcode, bpl, rsp_size, &cnt);
|
|
|
|
if (!outmp)
|
|
|
|
return -ENOMEM;
|
2009-10-03 02:16:51 +07:00
|
|
|
/*
|
|
|
|
* Form the CT IOCB. The total number of BDEs in this IOCB
|
|
|
|
* is the single command plus response count from
|
|
|
|
* lpfc_alloc_ct_rsp.
|
|
|
|
*/
|
|
|
|
cnt += 1;
|
2007-06-18 07:56:36 +07:00
|
|
|
status = lpfc_gen_req(vport, bmp, inmp, outmp, cmpl, ndlp, 0,
|
2009-10-03 02:16:51 +07:00
|
|
|
cnt, 0, retry);
|
2005-04-18 04:05:31 +07:00
|
|
|
if (status) {
|
|
|
|
lpfc_free_ct_rsp(phba, outmp);
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-08-02 22:09:51 +07:00
|
|
|
struct lpfc_vport *
|
2007-06-18 07:56:38 +07:00
|
|
|
lpfc_find_vport_by_did(struct lpfc_hba *phba, uint32_t did) {
|
|
|
|
struct lpfc_vport *vport_curr;
|
2007-08-02 22:09:51 +07:00
|
|
|
unsigned long flags;
|
2007-06-18 07:56:38 +07:00
|
|
|
|
2018-09-11 00:30:46 +07:00
|
|
|
spin_lock_irqsave(&phba->port_list_lock, flags);
|
2007-06-18 07:56:38 +07:00
|
|
|
list_for_each_entry(vport_curr, &phba->port_list, listentry) {
|
2007-08-02 22:09:51 +07:00
|
|
|
if ((vport_curr->fc_myDID) && (vport_curr->fc_myDID == did)) {
|
2018-09-11 00:30:46 +07:00
|
|
|
spin_unlock_irqrestore(&phba->port_list_lock, flags);
|
2007-06-18 07:56:38 +07:00
|
|
|
return vport_curr;
|
2007-08-02 22:09:51 +07:00
|
|
|
}
|
2007-06-18 07:56:38 +07:00
|
|
|
}
|
2018-09-11 00:30:46 +07:00
|
|
|
spin_unlock_irqrestore(&phba->port_list_lock, flags);
|
2007-06-18 07:56:38 +07:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2017-02-13 04:52:31 +07:00
|
|
|
static void
|
|
|
|
lpfc_prep_node_fc4type(struct lpfc_vport *vport, uint32_t Did, uint8_t fc4_type)
|
|
|
|
{
|
|
|
|
struct lpfc_nodelist *ndlp;
|
|
|
|
|
|
|
|
if ((vport->port_type != LPFC_NPIV_PORT) ||
|
scsi: lpfc: Fix loss of remote port after devloss due to lack of RPIs
In tests with remote ports contantly logging out/logging coupled with
occassional local link bounce, if a remote port is disocnnected for longer
than devloss_tmo and then subsequently reconnected, eventually the test
will fail to login with the remote port and remote port connectivity is
lost.
When devloss_tmo expires, the driver does not free the node struct until
the port or npiv instances is being deleted. The node is left allocated but
the state set to UNUSED. If the node was in the process of logging in when
the local link drop occurred, meaning the RPI was allocated for the node in
order to send the ELS, but not yet registered which comes after successful
login, the node is moved to the NPR state, and if devloss expires, to
UNUSED state. If the remote port comes back, the node associated with it
is restarted and this path happens to allocate a new RPI and overwrites the
prior RPI value. In the cases where the port was logged in and loggs out,
the path did release the RPI but did not set the node rpi value. In the
cases where the remote port never finished logging in, the path never did
the call to release the rpi. In this latter case, when the node is
subsequently restore, the new rpi allocation overwrites the rpi that was
not released, and the rpi is now leaked. Eventually the port will run out
of RPI resources to log into new remote ports.
Fix by following changes:
- When an rpi is released, do so under locks and ensure the node rpi value
is set to a non-allocated value (LPFC_RPI_ALLOC_ERROR). Note:
refactored to a small service routine to avoid indentation issues.
- When re-enabling a node, check the rpi value to determine if a new
allocation is necessary. If already set, use the prior rpi.
Enhanced logging to help in the future.
Signed-off-by: Dick Kennedy <dick.kennedy@broadcom.com>
Signed-off-by: James Smart <jsmart2021@gmail.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
2019-08-15 06:56:47 +07:00
|
|
|
(fc4_type == FC_TYPE_FCP) ||
|
2017-02-13 04:52:31 +07:00
|
|
|
!(vport->ct_flags & FC_CT_RFF_ID) || !vport->cfg_restrict_login) {
|
|
|
|
|
|
|
|
ndlp = lpfc_setup_disc_node(vport, Did);
|
|
|
|
|
|
|
|
if (ndlp && NLP_CHK_NODE_ACT(ndlp)) {
|
2017-02-13 04:52:33 +07:00
|
|
|
lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_CT,
|
|
|
|
"Parse GID_FTrsp: did:x%x flg:x%x x%x",
|
|
|
|
Did, ndlp->nlp_flag, vport->fc_flag);
|
|
|
|
|
2017-02-13 04:52:31 +07:00
|
|
|
/* By default, the driver expects to support FCP FC4 */
|
|
|
|
if (fc4_type == FC_TYPE_FCP)
|
|
|
|
ndlp->nlp_fc4_type |= NLP_FC4_FCP;
|
|
|
|
|
|
|
|
if (fc4_type == FC_TYPE_NVME)
|
|
|
|
ndlp->nlp_fc4_type |= NLP_FC4_NVME;
|
|
|
|
|
|
|
|
lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
|
|
|
|
"0238 Process x%06x NameServer Rsp "
|
2019-08-15 06:56:46 +07:00
|
|
|
"Data: x%x x%x x%x x%x x%x\n", Did,
|
2017-02-13 04:52:31 +07:00
|
|
|
ndlp->nlp_flag, ndlp->nlp_fc4_type,
|
2019-08-15 06:56:46 +07:00
|
|
|
ndlp->nlp_state, vport->fc_flag,
|
2017-02-13 04:52:31 +07:00
|
|
|
vport->fc_rscn_id_cnt);
|
2019-08-15 06:56:46 +07:00
|
|
|
|
|
|
|
/* if ndlp needs to be discovered and prior
|
|
|
|
* state of ndlp hit devloss, change state to
|
|
|
|
* allow rediscovery.
|
|
|
|
*/
|
|
|
|
if (ndlp->nlp_flag & NLP_NPR_2B_DISC &&
|
|
|
|
ndlp->nlp_state == NLP_STE_UNUSED_NODE) {
|
|
|
|
lpfc_nlp_set_state(vport, ndlp,
|
|
|
|
NLP_STE_NPR_NODE);
|
|
|
|
}
|
2017-02-13 04:52:33 +07:00
|
|
|
} else {
|
|
|
|
lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_CT,
|
|
|
|
"Skip1 GID_FTrsp: did:x%x flg:x%x cnt:%d",
|
|
|
|
Did, vport->fc_flag, vport->fc_rscn_id_cnt);
|
|
|
|
|
2017-02-13 04:52:31 +07:00
|
|
|
lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
|
|
|
|
"0239 Skip x%06x NameServer Rsp "
|
scsi: lpfc: Fix loss of remote port after devloss due to lack of RPIs
In tests with remote ports contantly logging out/logging coupled with
occassional local link bounce, if a remote port is disocnnected for longer
than devloss_tmo and then subsequently reconnected, eventually the test
will fail to login with the remote port and remote port connectivity is
lost.
When devloss_tmo expires, the driver does not free the node struct until
the port or npiv instances is being deleted. The node is left allocated but
the state set to UNUSED. If the node was in the process of logging in when
the local link drop occurred, meaning the RPI was allocated for the node in
order to send the ELS, but not yet registered which comes after successful
login, the node is moved to the NPR state, and if devloss expires, to
UNUSED state. If the remote port comes back, the node associated with it
is restarted and this path happens to allocate a new RPI and overwrites the
prior RPI value. In the cases where the port was logged in and loggs out,
the path did release the RPI but did not set the node rpi value. In the
cases where the remote port never finished logging in, the path never did
the call to release the rpi. In this latter case, when the node is
subsequently restore, the new rpi allocation overwrites the rpi that was
not released, and the rpi is now leaked. Eventually the port will run out
of RPI resources to log into new remote ports.
Fix by following changes:
- When an rpi is released, do so under locks and ensure the node rpi value
is set to a non-allocated value (LPFC_RPI_ALLOC_ERROR). Note:
refactored to a small service routine to avoid indentation issues.
- When re-enabling a node, check the rpi value to determine if a new
allocation is necessary. If already set, use the prior rpi.
Enhanced logging to help in the future.
Signed-off-by: Dick Kennedy <dick.kennedy@broadcom.com>
Signed-off-by: James Smart <jsmart2021@gmail.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
2019-08-15 06:56:47 +07:00
|
|
|
"Data: x%x x%x %p\n",
|
|
|
|
Did, vport->fc_flag,
|
|
|
|
vport->fc_rscn_id_cnt, ndlp);
|
2017-02-13 04:52:33 +07:00
|
|
|
}
|
2017-02-13 04:52:31 +07:00
|
|
|
} else {
|
|
|
|
if (!(vport->fc_flag & FC_RSCN_MODE) ||
|
|
|
|
lpfc_rscn_payload_check(vport, Did)) {
|
2017-02-13 04:52:33 +07:00
|
|
|
lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_CT,
|
|
|
|
"Query GID_FTrsp: did:x%x flg:x%x cnt:%d",
|
|
|
|
Did, vport->fc_flag, vport->fc_rscn_id_cnt);
|
|
|
|
|
2017-02-13 04:52:31 +07:00
|
|
|
/*
|
2017-06-02 11:07:08 +07:00
|
|
|
* This NPortID was previously a FCP/NVMe target,
|
2017-02-13 04:52:31 +07:00
|
|
|
* Don't even bother to send GFF_ID.
|
|
|
|
*/
|
|
|
|
ndlp = lpfc_findnode_did(vport, Did);
|
2017-06-02 11:07:08 +07:00
|
|
|
if (ndlp && NLP_CHK_NODE_ACT(ndlp) &&
|
|
|
|
(ndlp->nlp_type &
|
|
|
|
(NLP_FCP_TARGET | NLP_NVME_TARGET))) {
|
|
|
|
if (fc4_type == FC_TYPE_FCP)
|
|
|
|
ndlp->nlp_fc4_type |= NLP_FC4_FCP;
|
|
|
|
if (fc4_type == FC_TYPE_NVME)
|
|
|
|
ndlp->nlp_fc4_type |= NLP_FC4_NVME;
|
|
|
|
lpfc_setup_disc_node(vport, Did);
|
|
|
|
} else if (lpfc_ns_cmd(vport, SLI_CTNS_GFF_ID,
|
|
|
|
0, Did) == 0)
|
|
|
|
vport->num_disc_nodes++;
|
|
|
|
else
|
|
|
|
lpfc_setup_disc_node(vport, Did);
|
2017-02-13 04:52:33 +07:00
|
|
|
} else {
|
|
|
|
lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_CT,
|
|
|
|
"Skip2 GID_FTrsp: did:x%x flg:x%x cnt:%d",
|
|
|
|
Did, vport->fc_flag, vport->fc_rscn_id_cnt);
|
|
|
|
|
2017-02-13 04:52:31 +07:00
|
|
|
lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
|
|
|
|
"0245 Skip x%06x NameServer Rsp "
|
|
|
|
"Data: x%x x%x\n", Did,
|
|
|
|
vport->fc_flag,
|
|
|
|
vport->fc_rscn_id_cnt);
|
2017-02-13 04:52:33 +07:00
|
|
|
}
|
2017-02-13 04:52:31 +07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-04-22 06:05:03 +07:00
|
|
|
static void
|
|
|
|
lpfc_ns_rsp_audit_did(struct lpfc_vport *vport, uint32_t Did, uint8_t fc4_type)
|
|
|
|
{
|
|
|
|
struct lpfc_hba *phba = vport->phba;
|
|
|
|
struct lpfc_nodelist *ndlp = NULL;
|
|
|
|
struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
|
2018-12-14 06:17:56 +07:00
|
|
|
char *str;
|
2017-04-22 06:05:03 +07:00
|
|
|
|
2018-12-14 06:17:56 +07:00
|
|
|
if (phba->cfg_ns_query == LPFC_NS_QUERY_GID_FT)
|
|
|
|
str = "GID_FT";
|
|
|
|
else
|
|
|
|
str = "GID_PT";
|
|
|
|
lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
|
|
|
|
"6430 Process %s rsp for %08x type %x %s %s\n",
|
|
|
|
str, Did, fc4_type,
|
|
|
|
(fc4_type == FC_TYPE_FCP) ? "FCP" : " ",
|
|
|
|
(fc4_type == FC_TYPE_NVME) ? "NVME" : " ");
|
2017-04-22 06:05:03 +07:00
|
|
|
/*
|
|
|
|
* To conserve rpi's, filter out addresses for other
|
|
|
|
* vports on the same physical HBAs.
|
|
|
|
*/
|
|
|
|
if (Did != vport->fc_myDID &&
|
|
|
|
(!lpfc_find_vport_by_did(phba, Did) ||
|
|
|
|
vport->cfg_peer_port_login)) {
|
|
|
|
if (!phba->nvmet_support) {
|
|
|
|
/* FCPI/NVMEI path. Process Did */
|
|
|
|
lpfc_prep_node_fc4type(vport, Did, fc4_type);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
/* NVMET path. NVMET only cares about NVMEI nodes. */
|
|
|
|
list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) {
|
|
|
|
if (ndlp->nlp_type != NLP_NVME_INITIATOR ||
|
|
|
|
ndlp->nlp_state != NLP_STE_UNMAPPED_NODE)
|
|
|
|
continue;
|
|
|
|
spin_lock_irq(shost->host_lock);
|
|
|
|
if (ndlp->nlp_DID == Did)
|
|
|
|
ndlp->nlp_flag &= ~NLP_NVMET_RECOV;
|
|
|
|
else
|
|
|
|
ndlp->nlp_flag |= NLP_NVMET_RECOV;
|
|
|
|
spin_unlock_irq(shost->host_lock);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-04-18 04:05:31 +07:00
|
|
|
static int
|
2017-02-13 04:52:31 +07:00
|
|
|
lpfc_ns_rsp(struct lpfc_vport *vport, struct lpfc_dmabuf *mp, uint8_t fc4_type,
|
|
|
|
uint32_t Size)
|
2005-04-18 04:05:31 +07:00
|
|
|
{
|
|
|
|
struct lpfc_sli_ct_request *Response =
|
|
|
|
(struct lpfc_sli_ct_request *) mp->virt;
|
|
|
|
struct lpfc_dmabuf *mlast, *next_mp;
|
|
|
|
uint32_t *ctptr = (uint32_t *) & Response->un.gid.PortType;
|
2007-06-18 07:56:36 +07:00
|
|
|
uint32_t Did, CTentry;
|
2005-04-18 04:05:31 +07:00
|
|
|
int Cnt;
|
|
|
|
struct list_head head;
|
2017-04-22 06:05:03 +07:00
|
|
|
struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
|
|
|
|
struct lpfc_nodelist *ndlp = NULL;
|
2005-04-18 04:05:31 +07:00
|
|
|
|
2007-06-18 07:56:36 +07:00
|
|
|
lpfc_set_disctmo(vport);
|
2007-06-18 07:56:38 +07:00
|
|
|
vport->num_disc_nodes = 0;
|
2008-01-11 13:52:36 +07:00
|
|
|
vport->fc_ns_retry = 0;
|
2005-04-18 04:05:31 +07:00
|
|
|
|
|
|
|
|
|
|
|
list_add_tail(&head, &mp->list);
|
|
|
|
list_for_each_entry_safe(mp, next_mp, &head, list) {
|
|
|
|
mlast = mp;
|
|
|
|
|
2007-04-25 20:52:34 +07:00
|
|
|
Cnt = Size > FCELSSIZE ? FCELSSIZE : Size;
|
|
|
|
|
2005-04-18 04:05:31 +07:00
|
|
|
Size -= Cnt;
|
|
|
|
|
2007-04-25 20:51:30 +07:00
|
|
|
if (!ctptr) {
|
2005-04-18 04:05:31 +07:00
|
|
|
ctptr = (uint32_t *) mlast->virt;
|
2007-04-25 20:51:30 +07:00
|
|
|
} else
|
2005-04-18 04:05:31 +07:00
|
|
|
Cnt -= 16; /* subtract length of CT header */
|
|
|
|
|
|
|
|
/* Loop through entire NameServer list of DIDs */
|
2015-12-17 06:11:58 +07:00
|
|
|
while (Cnt >= sizeof(uint32_t)) {
|
2005-04-18 04:05:31 +07:00
|
|
|
/* Get next DID from NameServer List */
|
|
|
|
CTentry = *ctptr++;
|
|
|
|
Did = ((be32_to_cpu(CTentry)) & Mask_DID);
|
2017-04-22 06:05:03 +07:00
|
|
|
lpfc_ns_rsp_audit_did(vport, Did, fc4_type);
|
2015-04-08 02:07:19 +07:00
|
|
|
if (CTentry & (cpu_to_be32(SLI_CT_LAST_ENTRY)))
|
2005-04-18 04:05:31 +07:00
|
|
|
goto nsout1;
|
2017-02-13 04:52:31 +07:00
|
|
|
|
2015-12-17 06:11:58 +07:00
|
|
|
Cnt -= sizeof(uint32_t);
|
2005-04-18 04:05:31 +07:00
|
|
|
}
|
|
|
|
ctptr = NULL;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2017-04-22 06:05:03 +07:00
|
|
|
/* All GID_FT entries processed. If the driver is running in
|
|
|
|
* in target mode, put impacted nodes into recovery and drop
|
|
|
|
* the RPI to flush outstanding IO.
|
|
|
|
*/
|
|
|
|
if (vport->phba->nvmet_support) {
|
|
|
|
list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) {
|
|
|
|
if (!(ndlp->nlp_flag & NLP_NVMET_RECOV))
|
|
|
|
continue;
|
|
|
|
lpfc_disc_state_machine(vport, ndlp, NULL,
|
|
|
|
NLP_EVT_DEVICE_RECOVERY);
|
|
|
|
spin_lock_irq(shost->host_lock);
|
|
|
|
ndlp->nlp_flag &= ~NLP_NVMET_RECOV;
|
2017-05-04 04:22:16 +07:00
|
|
|
spin_unlock_irq(shost->host_lock);
|
2017-04-22 06:05:03 +07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-04-18 04:05:31 +07:00
|
|
|
nsout1:
|
|
|
|
list_del(&head);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2007-06-18 07:56:36 +07:00
|
|
|
lpfc_cmpl_ct_cmd_gid_ft(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
|
|
|
|
struct lpfc_iocbq *rspiocb)
|
2005-04-18 04:05:31 +07:00
|
|
|
{
|
2007-06-18 07:56:36 +07:00
|
|
|
struct lpfc_vport *vport = cmdiocb->vport;
|
2007-06-18 07:56:38 +07:00
|
|
|
struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
|
2005-04-18 04:05:31 +07:00
|
|
|
IOCB_t *irsp;
|
|
|
|
struct lpfc_dmabuf *outp;
|
2017-02-13 04:52:31 +07:00
|
|
|
struct lpfc_dmabuf *inp;
|
2005-04-18 04:05:31 +07:00
|
|
|
struct lpfc_sli_ct_request *CTrsp;
|
2017-02-13 04:52:31 +07:00
|
|
|
struct lpfc_sli_ct_request *CTreq;
|
2007-08-02 22:10:31 +07:00
|
|
|
struct lpfc_nodelist *ndlp;
|
2017-02-13 04:52:31 +07:00
|
|
|
int rc, type;
|
2005-04-18 04:05:31 +07:00
|
|
|
|
2007-08-02 22:10:31 +07:00
|
|
|
/* First save ndlp, before we overwrite it */
|
|
|
|
ndlp = cmdiocb->context_un.ndlp;
|
|
|
|
|
2005-04-18 04:05:31 +07:00
|
|
|
/* we pass cmdiocb to state machine which needs rspiocb as well */
|
|
|
|
cmdiocb->context_un.rsp_iocb = rspiocb;
|
2017-02-13 04:52:31 +07:00
|
|
|
inp = (struct lpfc_dmabuf *) cmdiocb->context1;
|
2005-04-18 04:05:31 +07:00
|
|
|
outp = (struct lpfc_dmabuf *) cmdiocb->context2;
|
2007-06-18 07:56:39 +07:00
|
|
|
irsp = &rspiocb->iocb;
|
|
|
|
|
|
|
|
lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_CT,
|
|
|
|
"GID_FT cmpl: status:x%x/x%x rtry:%d",
|
|
|
|
irsp->ulpStatus, irsp->un.ulpWord[4], vport->fc_ns_retry);
|
2005-04-18 04:05:31 +07:00
|
|
|
|
2007-06-18 07:56:38 +07:00
|
|
|
/* Don't bother processing response if vport is being torn down. */
|
2008-12-05 10:39:13 +07:00
|
|
|
if (vport->load_flag & FC_UNLOADING) {
|
|
|
|
if (vport->fc_flag & FC_RSCN_MODE)
|
|
|
|
lpfc_els_flush_rscn(vport);
|
2007-06-18 07:56:38 +07:00
|
|
|
goto out;
|
2008-12-05 10:39:13 +07:00
|
|
|
}
|
2007-06-18 07:56:38 +07:00
|
|
|
|
2008-04-07 21:15:56 +07:00
|
|
|
if (lpfc_els_chk_latt(vport)) {
|
2007-08-02 22:10:09 +07:00
|
|
|
lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
|
|
|
|
"0216 Link event during NS query\n");
|
2008-12-05 10:39:13 +07:00
|
|
|
if (vport->fc_flag & FC_RSCN_MODE)
|
|
|
|
lpfc_els_flush_rscn(vport);
|
2007-06-18 07:56:39 +07:00
|
|
|
lpfc_vport_set_state(vport, FC_VPORT_FAILED);
|
|
|
|
goto out;
|
|
|
|
}
|
2008-04-07 21:15:56 +07:00
|
|
|
if (lpfc_error_lost_link(irsp)) {
|
|
|
|
lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
|
|
|
|
"0226 NS query failed due to link event\n");
|
2008-12-05 10:39:13 +07:00
|
|
|
if (vport->fc_flag & FC_RSCN_MODE)
|
|
|
|
lpfc_els_flush_rscn(vport);
|
2008-04-07 21:15:56 +07:00
|
|
|
goto out;
|
|
|
|
}
|
2017-11-21 07:00:38 +07:00
|
|
|
|
|
|
|
spin_lock_irq(shost->host_lock);
|
|
|
|
if (vport->fc_flag & FC_RSCN_DEFERRED) {
|
|
|
|
vport->fc_flag &= ~FC_RSCN_DEFERRED;
|
|
|
|
spin_unlock_irq(shost->host_lock);
|
|
|
|
|
2018-04-10 04:24:29 +07:00
|
|
|
/* This is a GID_FT completing so the gidft_inp counter was
|
|
|
|
* incremented before the GID_FT was issued to the wire.
|
|
|
|
*/
|
|
|
|
vport->gidft_inp--;
|
|
|
|
|
2017-11-21 07:00:38 +07:00
|
|
|
/*
|
|
|
|
* Skip processing the NS response
|
|
|
|
* Re-issue the NS cmd
|
|
|
|
*/
|
|
|
|
lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
|
|
|
|
"0151 Process Deferred RSCN Data: x%x x%x\n",
|
|
|
|
vport->fc_flag, vport->fc_rscn_id_cnt);
|
|
|
|
lpfc_els_handle_rscn(vport);
|
|
|
|
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
spin_unlock_irq(shost->host_lock);
|
|
|
|
|
2007-06-18 07:56:39 +07:00
|
|
|
if (irsp->ulpStatus) {
|
2005-04-18 04:05:31 +07:00
|
|
|
/* Check for retry */
|
2007-06-18 07:56:36 +07:00
|
|
|
if (vport->fc_ns_retry < LPFC_MAX_NS_RETRY) {
|
2008-04-07 21:15:56 +07:00
|
|
|
if (irsp->ulpStatus != IOSTAT_LOCAL_REJECT ||
|
2012-11-01 01:45:21 +07:00
|
|
|
(irsp->un.ulpWord[4] & IOERR_PARAM_MASK) !=
|
2012-08-15 01:25:43 +07:00
|
|
|
IOERR_NO_RESOURCES)
|
2007-06-18 07:56:39 +07:00
|
|
|
vport->fc_ns_retry++;
|
2008-01-11 13:52:36 +07:00
|
|
|
|
2017-02-13 04:52:31 +07:00
|
|
|
type = lpfc_get_gidft_type(vport, cmdiocb);
|
|
|
|
if (type == 0)
|
|
|
|
goto out;
|
|
|
|
|
2008-04-07 21:15:56 +07:00
|
|
|
/* CT command is being retried */
|
2017-02-13 04:52:31 +07:00
|
|
|
vport->gidft_inp--;
|
2008-04-07 21:15:56 +07:00
|
|
|
rc = lpfc_ns_cmd(vport, SLI_CTNS_GID_FT,
|
2017-02-13 04:52:31 +07:00
|
|
|
vport->fc_ns_retry, type);
|
2008-04-07 21:15:56 +07:00
|
|
|
if (rc == 0)
|
|
|
|
goto out;
|
2007-06-18 07:56:38 +07:00
|
|
|
}
|
2008-12-05 10:39:13 +07:00
|
|
|
if (vport->fc_flag & FC_RSCN_MODE)
|
|
|
|
lpfc_els_flush_rscn(vport);
|
2007-06-18 07:56:38 +07:00
|
|
|
lpfc_vport_set_state(vport, FC_VPORT_FAILED);
|
2007-08-02 22:10:09 +07:00
|
|
|
lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
|
|
|
|
"0257 GID_FT Query error: 0x%x 0x%x\n",
|
|
|
|
irsp->ulpStatus, vport->fc_ns_retry);
|
2005-04-18 04:05:31 +07:00
|
|
|
} else {
|
|
|
|
/* Good status, continue checking */
|
2017-02-13 04:52:31 +07:00
|
|
|
CTreq = (struct lpfc_sli_ct_request *) inp->virt;
|
2005-04-18 04:05:31 +07:00
|
|
|
CTrsp = (struct lpfc_sli_ct_request *) outp->virt;
|
|
|
|
if (CTrsp->CommandResponse.bits.CmdRsp ==
|
2015-04-08 02:07:19 +07:00
|
|
|
cpu_to_be16(SLI_CT_RESPONSE_FS_ACC)) {
|
2007-08-02 22:10:09 +07:00
|
|
|
lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
|
2019-08-15 06:56:46 +07:00
|
|
|
"0208 NameServer Rsp Data: x%x x%x "
|
|
|
|
"sz x%x\n",
|
2017-02-13 04:52:31 +07:00
|
|
|
vport->fc_flag,
|
2019-08-15 06:56:46 +07:00
|
|
|
CTreq->un.gid.Fc4Type,
|
|
|
|
irsp->un.genreq64.bdl.bdeSize);
|
2017-02-13 04:52:31 +07:00
|
|
|
|
|
|
|
lpfc_ns_rsp(vport,
|
|
|
|
outp,
|
|
|
|
CTreq->un.gid.Fc4Type,
|
2005-04-18 04:05:31 +07:00
|
|
|
(uint32_t) (irsp->un.genreq64.bdl.bdeSize));
|
|
|
|
} else if (CTrsp->CommandResponse.bits.CmdRsp ==
|
|
|
|
be16_to_cpu(SLI_CT_RESPONSE_FS_RJT)) {
|
|
|
|
/* NameServer Rsp Error */
|
2007-08-02 22:09:43 +07:00
|
|
|
if ((CTrsp->ReasonCode == SLI_CT_UNABLE_TO_PERFORM_REQ)
|
|
|
|
&& (CTrsp->Explanation == SLI_CT_NO_FC4_TYPES)) {
|
2007-08-02 22:10:09 +07:00
|
|
|
lpfc_printf_vlog(vport, KERN_INFO,
|
|
|
|
LOG_DISCOVERY,
|
|
|
|
"0269 No NameServer Entries "
|
2007-08-02 22:09:43 +07:00
|
|
|
"Data: x%x x%x x%x x%x\n",
|
|
|
|
CTrsp->CommandResponse.bits.CmdRsp,
|
|
|
|
(uint32_t) CTrsp->ReasonCode,
|
|
|
|
(uint32_t) CTrsp->Explanation,
|
|
|
|
vport->fc_flag);
|
|
|
|
|
|
|
|
lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_CT,
|
|
|
|
"GID_FT no entry cmd:x%x rsn:x%x exp:x%x",
|
|
|
|
(uint32_t)CTrsp->CommandResponse.bits.CmdRsp,
|
|
|
|
(uint32_t) CTrsp->ReasonCode,
|
|
|
|
(uint32_t) CTrsp->Explanation);
|
2007-08-02 22:10:09 +07:00
|
|
|
} else {
|
|
|
|
lpfc_printf_vlog(vport, KERN_INFO,
|
|
|
|
LOG_DISCOVERY,
|
|
|
|
"0240 NameServer Rsp Error "
|
2005-04-18 04:05:31 +07:00
|
|
|
"Data: x%x x%x x%x x%x\n",
|
|
|
|
CTrsp->CommandResponse.bits.CmdRsp,
|
|
|
|
(uint32_t) CTrsp->ReasonCode,
|
|
|
|
(uint32_t) CTrsp->Explanation,
|
2007-06-18 07:56:36 +07:00
|
|
|
vport->fc_flag);
|
2007-06-18 07:56:39 +07:00
|
|
|
|
2007-08-02 22:09:43 +07:00
|
|
|
lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_CT,
|
2007-06-18 07:56:39 +07:00
|
|
|
"GID_FT rsp err1 cmd:x%x rsn:x%x exp:x%x",
|
|
|
|
(uint32_t)CTrsp->CommandResponse.bits.CmdRsp,
|
|
|
|
(uint32_t) CTrsp->ReasonCode,
|
|
|
|
(uint32_t) CTrsp->Explanation);
|
2007-08-02 22:09:43 +07:00
|
|
|
}
|
|
|
|
|
2007-06-18 07:56:39 +07:00
|
|
|
|
2005-04-18 04:05:31 +07:00
|
|
|
} else {
|
|
|
|
/* NameServer Rsp Error */
|
2007-08-02 22:10:09 +07:00
|
|
|
lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY,
|
|
|
|
"0241 NameServer Rsp Error "
|
2005-04-18 04:05:31 +07:00
|
|
|
"Data: x%x x%x x%x x%x\n",
|
|
|
|
CTrsp->CommandResponse.bits.CmdRsp,
|
|
|
|
(uint32_t) CTrsp->ReasonCode,
|
|
|
|
(uint32_t) CTrsp->Explanation,
|
2007-06-18 07:56:36 +07:00
|
|
|
vport->fc_flag);
|
2007-06-18 07:56:39 +07:00
|
|
|
|
|
|
|
lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_CT,
|
|
|
|
"GID_FT rsp err2 cmd:x%x rsn:x%x exp:x%x",
|
|
|
|
(uint32_t)CTrsp->CommandResponse.bits.CmdRsp,
|
|
|
|
(uint32_t) CTrsp->ReasonCode,
|
|
|
|
(uint32_t) CTrsp->Explanation);
|
2005-04-18 04:05:31 +07:00
|
|
|
}
|
2017-02-13 04:52:31 +07:00
|
|
|
vport->gidft_inp--;
|
2005-04-18 04:05:31 +07:00
|
|
|
}
|
2019-08-15 06:56:46 +07:00
|
|
|
|
|
|
|
lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
|
|
|
|
"4216 GID_FT cmpl inp %d disc %d\n",
|
|
|
|
vport->gidft_inp, vport->num_disc_nodes);
|
|
|
|
|
2005-04-18 04:05:31 +07:00
|
|
|
/* Link up / RSCN discovery */
|
2017-02-13 04:52:31 +07:00
|
|
|
if ((vport->num_disc_nodes == 0) &&
|
|
|
|
(vport->gidft_inp == 0)) {
|
2007-06-18 07:56:38 +07:00
|
|
|
/*
|
|
|
|
* The driver has cycled through all Nports in the RSCN payload.
|
|
|
|
* Complete the handling by cleaning up and marking the
|
|
|
|
* current driver state.
|
|
|
|
*/
|
|
|
|
if (vport->port_state >= LPFC_DISC_AUTH) {
|
|
|
|
if (vport->fc_flag & FC_RSCN_MODE) {
|
|
|
|
lpfc_els_flush_rscn(vport);
|
|
|
|
spin_lock_irq(shost->host_lock);
|
|
|
|
vport->fc_flag |= FC_RSCN_MODE; /* RSCN still */
|
|
|
|
spin_unlock_irq(shost->host_lock);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
lpfc_els_flush_rscn(vport);
|
|
|
|
}
|
|
|
|
|
|
|
|
lpfc_disc_start(vport);
|
|
|
|
}
|
|
|
|
out:
|
2007-08-02 22:10:31 +07:00
|
|
|
cmdiocb->context_un.ndlp = ndlp; /* Now restore ndlp for free */
|
2007-06-18 07:56:39 +07:00
|
|
|
lpfc_ct_free_iocb(phba, cmdiocb);
|
2007-06-18 07:56:38 +07:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-10-24 03:41:10 +07:00
|
|
|
static void
|
|
|
|
lpfc_cmpl_ct_cmd_gid_pt(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
|
|
|
|
struct lpfc_iocbq *rspiocb)
|
|
|
|
{
|
|
|
|
struct lpfc_vport *vport = cmdiocb->vport;
|
|
|
|
struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
|
|
|
|
IOCB_t *irsp;
|
|
|
|
struct lpfc_dmabuf *outp;
|
|
|
|
struct lpfc_dmabuf *inp;
|
|
|
|
struct lpfc_sli_ct_request *CTrsp;
|
|
|
|
struct lpfc_sli_ct_request *CTreq;
|
|
|
|
struct lpfc_nodelist *ndlp;
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
/* First save ndlp, before we overwrite it */
|
|
|
|
ndlp = cmdiocb->context_un.ndlp;
|
|
|
|
|
|
|
|
/* we pass cmdiocb to state machine which needs rspiocb as well */
|
|
|
|
cmdiocb->context_un.rsp_iocb = rspiocb;
|
|
|
|
inp = (struct lpfc_dmabuf *)cmdiocb->context1;
|
|
|
|
outp = (struct lpfc_dmabuf *)cmdiocb->context2;
|
|
|
|
irsp = &rspiocb->iocb;
|
|
|
|
|
|
|
|
lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_CT,
|
|
|
|
"GID_PT cmpl: status:x%x/x%x rtry:%d",
|
|
|
|
irsp->ulpStatus, irsp->un.ulpWord[4],
|
|
|
|
vport->fc_ns_retry);
|
|
|
|
|
|
|
|
/* Don't bother processing response if vport is being torn down. */
|
|
|
|
if (vport->load_flag & FC_UNLOADING) {
|
|
|
|
if (vport->fc_flag & FC_RSCN_MODE)
|
|
|
|
lpfc_els_flush_rscn(vport);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (lpfc_els_chk_latt(vport)) {
|
|
|
|
lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
|
|
|
|
"4108 Link event during NS query\n");
|
|
|
|
if (vport->fc_flag & FC_RSCN_MODE)
|
|
|
|
lpfc_els_flush_rscn(vport);
|
|
|
|
lpfc_vport_set_state(vport, FC_VPORT_FAILED);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
if (lpfc_error_lost_link(irsp)) {
|
|
|
|
lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
|
2019-03-13 06:30:30 +07:00
|
|
|
"4166 NS query failed due to link event\n");
|
2018-10-24 03:41:10 +07:00
|
|
|
if (vport->fc_flag & FC_RSCN_MODE)
|
|
|
|
lpfc_els_flush_rscn(vport);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
spin_lock_irq(shost->host_lock);
|
|
|
|
if (vport->fc_flag & FC_RSCN_DEFERRED) {
|
|
|
|
vport->fc_flag &= ~FC_RSCN_DEFERRED;
|
|
|
|
spin_unlock_irq(shost->host_lock);
|
|
|
|
|
|
|
|
/* This is a GID_PT completing so the gidft_inp counter was
|
|
|
|
* incremented before the GID_PT was issued to the wire.
|
|
|
|
*/
|
|
|
|
vport->gidft_inp--;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Skip processing the NS response
|
|
|
|
* Re-issue the NS cmd
|
|
|
|
*/
|
|
|
|
lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
|
2019-03-13 06:30:30 +07:00
|
|
|
"4167 Process Deferred RSCN Data: x%x x%x\n",
|
2018-10-24 03:41:10 +07:00
|
|
|
vport->fc_flag, vport->fc_rscn_id_cnt);
|
|
|
|
lpfc_els_handle_rscn(vport);
|
|
|
|
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
spin_unlock_irq(shost->host_lock);
|
|
|
|
|
|
|
|
if (irsp->ulpStatus) {
|
|
|
|
/* Check for retry */
|
|
|
|
if (vport->fc_ns_retry < LPFC_MAX_NS_RETRY) {
|
|
|
|
if (irsp->ulpStatus != IOSTAT_LOCAL_REJECT ||
|
|
|
|
(irsp->un.ulpWord[4] & IOERR_PARAM_MASK) !=
|
|
|
|
IOERR_NO_RESOURCES)
|
|
|
|
vport->fc_ns_retry++;
|
|
|
|
|
|
|
|
/* CT command is being retried */
|
|
|
|
vport->gidft_inp--;
|
|
|
|
rc = lpfc_ns_cmd(vport, SLI_CTNS_GID_PT,
|
|
|
|
vport->fc_ns_retry, GID_PT_N_PORT);
|
|
|
|
if (rc == 0)
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
if (vport->fc_flag & FC_RSCN_MODE)
|
|
|
|
lpfc_els_flush_rscn(vport);
|
|
|
|
lpfc_vport_set_state(vport, FC_VPORT_FAILED);
|
|
|
|
lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
|
|
|
|
"4103 GID_FT Query error: 0x%x 0x%x\n",
|
|
|
|
irsp->ulpStatus, vport->fc_ns_retry);
|
|
|
|
} else {
|
|
|
|
/* Good status, continue checking */
|
|
|
|
CTreq = (struct lpfc_sli_ct_request *)inp->virt;
|
|
|
|
CTrsp = (struct lpfc_sli_ct_request *)outp->virt;
|
|
|
|
if (CTrsp->CommandResponse.bits.CmdRsp ==
|
|
|
|
cpu_to_be16(SLI_CT_RESPONSE_FS_ACC)) {
|
|
|
|
lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
|
|
|
|
"4105 NameServer Rsp Data: x%x x%x\n",
|
|
|
|
vport->fc_flag,
|
|
|
|
CTreq->un.gid.Fc4Type);
|
|
|
|
|
|
|
|
lpfc_ns_rsp(vport,
|
|
|
|
outp,
|
|
|
|
CTreq->un.gid.Fc4Type,
|
|
|
|
(uint32_t)(irsp->un.genreq64.bdl.bdeSize));
|
|
|
|
} else if (CTrsp->CommandResponse.bits.CmdRsp ==
|
|
|
|
be16_to_cpu(SLI_CT_RESPONSE_FS_RJT)) {
|
|
|
|
/* NameServer Rsp Error */
|
|
|
|
if ((CTrsp->ReasonCode == SLI_CT_UNABLE_TO_PERFORM_REQ)
|
|
|
|
&& (CTrsp->Explanation == SLI_CT_NO_FC4_TYPES)) {
|
|
|
|
lpfc_printf_vlog(
|
|
|
|
vport, KERN_INFO, LOG_DISCOVERY,
|
|
|
|
"4106 No NameServer Entries "
|
|
|
|
"Data: x%x x%x x%x x%x\n",
|
|
|
|
CTrsp->CommandResponse.bits.CmdRsp,
|
|
|
|
(uint32_t)CTrsp->ReasonCode,
|
|
|
|
(uint32_t)CTrsp->Explanation,
|
|
|
|
vport->fc_flag);
|
|
|
|
|
|
|
|
lpfc_debugfs_disc_trc(
|
|
|
|
vport, LPFC_DISC_TRC_CT,
|
|
|
|
"GID_PT no entry cmd:x%x rsn:x%x exp:x%x",
|
|
|
|
(uint32_t)CTrsp->CommandResponse.bits.CmdRsp,
|
|
|
|
(uint32_t)CTrsp->ReasonCode,
|
|
|
|
(uint32_t)CTrsp->Explanation);
|
|
|
|
} else {
|
|
|
|
lpfc_printf_vlog(
|
|
|
|
vport, KERN_INFO, LOG_DISCOVERY,
|
|
|
|
"4107 NameServer Rsp Error "
|
|
|
|
"Data: x%x x%x x%x x%x\n",
|
|
|
|
CTrsp->CommandResponse.bits.CmdRsp,
|
|
|
|
(uint32_t)CTrsp->ReasonCode,
|
|
|
|
(uint32_t)CTrsp->Explanation,
|
|
|
|
vport->fc_flag);
|
|
|
|
|
|
|
|
lpfc_debugfs_disc_trc(
|
|
|
|
vport, LPFC_DISC_TRC_CT,
|
|
|
|
"GID_PT rsp err1 cmd:x%x rsn:x%x exp:x%x",
|
|
|
|
(uint32_t)CTrsp->CommandResponse.bits.CmdRsp,
|
|
|
|
(uint32_t)CTrsp->ReasonCode,
|
|
|
|
(uint32_t)CTrsp->Explanation);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/* NameServer Rsp Error */
|
|
|
|
lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY,
|
|
|
|
"4109 NameServer Rsp Error "
|
|
|
|
"Data: x%x x%x x%x x%x\n",
|
|
|
|
CTrsp->CommandResponse.bits.CmdRsp,
|
|
|
|
(uint32_t)CTrsp->ReasonCode,
|
|
|
|
(uint32_t)CTrsp->Explanation,
|
|
|
|
vport->fc_flag);
|
|
|
|
|
|
|
|
lpfc_debugfs_disc_trc(
|
|
|
|
vport, LPFC_DISC_TRC_CT,
|
|
|
|
"GID_PT rsp err2 cmd:x%x rsn:x%x exp:x%x",
|
|
|
|
(uint32_t)CTrsp->CommandResponse.bits.CmdRsp,
|
|
|
|
(uint32_t)CTrsp->ReasonCode,
|
|
|
|
(uint32_t)CTrsp->Explanation);
|
|
|
|
}
|
|
|
|
vport->gidft_inp--;
|
|
|
|
}
|
|
|
|
/* Link up / RSCN discovery */
|
|
|
|
if ((vport->num_disc_nodes == 0) &&
|
|
|
|
(vport->gidft_inp == 0)) {
|
|
|
|
/*
|
|
|
|
* The driver has cycled through all Nports in the RSCN payload.
|
|
|
|
* Complete the handling by cleaning up and marking the
|
|
|
|
* current driver state.
|
|
|
|
*/
|
|
|
|
if (vport->port_state >= LPFC_DISC_AUTH) {
|
|
|
|
if (vport->fc_flag & FC_RSCN_MODE) {
|
|
|
|
lpfc_els_flush_rscn(vport);
|
|
|
|
spin_lock_irq(shost->host_lock);
|
|
|
|
vport->fc_flag |= FC_RSCN_MODE; /* RSCN still */
|
|
|
|
spin_unlock_irq(shost->host_lock);
|
|
|
|
} else {
|
|
|
|
lpfc_els_flush_rscn(vport);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
lpfc_disc_start(vport);
|
|
|
|
}
|
|
|
|
out:
|
|
|
|
cmdiocb->context_un.ndlp = ndlp; /* Now restore ndlp for free */
|
|
|
|
lpfc_ct_free_iocb(phba, cmdiocb);
|
|
|
|
}
|
|
|
|
|
2007-08-02 22:10:37 +07:00
|
|
|
static void
|
2007-06-18 07:56:38 +07:00
|
|
|
lpfc_cmpl_ct_cmd_gff_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
|
|
|
|
struct lpfc_iocbq *rspiocb)
|
|
|
|
{
|
|
|
|
struct lpfc_vport *vport = cmdiocb->vport;
|
|
|
|
struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
|
|
|
|
IOCB_t *irsp = &rspiocb->iocb;
|
|
|
|
struct lpfc_dmabuf *inp = (struct lpfc_dmabuf *) cmdiocb->context1;
|
|
|
|
struct lpfc_dmabuf *outp = (struct lpfc_dmabuf *) cmdiocb->context2;
|
|
|
|
struct lpfc_sli_ct_request *CTrsp;
|
2008-01-11 13:52:36 +07:00
|
|
|
int did, rc, retry;
|
2007-06-18 07:56:38 +07:00
|
|
|
uint8_t fbits;
|
|
|
|
struct lpfc_nodelist *ndlp;
|
|
|
|
|
|
|
|
did = ((struct lpfc_sli_ct_request *) inp->virt)->un.gff.PortId;
|
|
|
|
did = be32_to_cpu(did);
|
|
|
|
|
2007-06-18 07:56:39 +07:00
|
|
|
lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_CT,
|
|
|
|
"GFF_ID cmpl: status:x%x/x%x did:x%x",
|
|
|
|
irsp->ulpStatus, irsp->un.ulpWord[4], did);
|
|
|
|
|
2007-06-18 07:56:38 +07:00
|
|
|
if (irsp->ulpStatus == IOSTAT_SUCCESS) {
|
|
|
|
/* Good status, continue checking */
|
|
|
|
CTrsp = (struct lpfc_sli_ct_request *) outp->virt;
|
|
|
|
fbits = CTrsp->un.gff_acc.fbits[FCP_TYPE_FEATURE_OFFSET];
|
|
|
|
|
2018-12-14 06:17:56 +07:00
|
|
|
lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
|
|
|
|
"6431 Process GFF_ID rsp for %08x "
|
|
|
|
"fbits %02x %s %s\n",
|
|
|
|
did, fbits,
|
|
|
|
(fbits & FC4_FEATURE_INIT) ? "Initiator" : " ",
|
|
|
|
(fbits & FC4_FEATURE_TARGET) ? "Target" : " ");
|
|
|
|
|
2007-06-18 07:56:38 +07:00
|
|
|
if (CTrsp->CommandResponse.bits.CmdRsp ==
|
|
|
|
be16_to_cpu(SLI_CT_RESPONSE_FS_ACC)) {
|
|
|
|
if ((fbits & FC4_FEATURE_INIT) &&
|
|
|
|
!(fbits & FC4_FEATURE_TARGET)) {
|
2007-08-02 22:10:09 +07:00
|
|
|
lpfc_printf_vlog(vport, KERN_INFO,
|
|
|
|
LOG_DISCOVERY,
|
|
|
|
"0270 Skip x%x GFF "
|
|
|
|
"NameServer Rsp Data: (init) "
|
|
|
|
"x%x x%x\n", did, fbits,
|
|
|
|
vport->fc_rscn_id_cnt);
|
2007-06-18 07:56:38 +07:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2007-06-18 07:56:39 +07:00
|
|
|
else {
|
2008-01-11 13:52:36 +07:00
|
|
|
/* Check for retry */
|
|
|
|
if (cmdiocb->retry < LPFC_MAX_NS_RETRY) {
|
|
|
|
retry = 1;
|
|
|
|
if (irsp->ulpStatus == IOSTAT_LOCAL_REJECT) {
|
2012-08-15 01:25:43 +07:00
|
|
|
switch ((irsp->un.ulpWord[4] &
|
|
|
|
IOERR_PARAM_MASK)) {
|
|
|
|
|
2008-01-11 13:52:36 +07:00
|
|
|
case IOERR_NO_RESOURCES:
|
|
|
|
/* We don't increment the retry
|
|
|
|
* count for this case.
|
|
|
|
*/
|
|
|
|
break;
|
|
|
|
case IOERR_LINK_DOWN:
|
|
|
|
case IOERR_SLI_ABORTED:
|
|
|
|
case IOERR_SLI_DOWN:
|
|
|
|
retry = 0;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
cmdiocb->retry++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
cmdiocb->retry++;
|
|
|
|
|
|
|
|
if (retry) {
|
|
|
|
/* CT command is being retried */
|
|
|
|
rc = lpfc_ns_cmd(vport, SLI_CTNS_GFF_ID,
|
|
|
|
cmdiocb->retry, did);
|
|
|
|
if (rc == 0) {
|
|
|
|
/* success */
|
|
|
|
lpfc_ct_free_iocb(phba, cmdiocb);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2007-08-02 22:10:09 +07:00
|
|
|
lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY,
|
|
|
|
"0267 NameServer GFF Rsp "
|
|
|
|
"x%x Error (%d %d) Data: x%x x%x\n",
|
|
|
|
did, irsp->ulpStatus, irsp->un.ulpWord[4],
|
2008-02-09 06:50:14 +07:00
|
|
|
vport->fc_flag, vport->fc_rscn_id_cnt);
|
2007-06-18 07:56:39 +07:00
|
|
|
}
|
|
|
|
|
2007-06-18 07:56:38 +07:00
|
|
|
/* This is a target port, unregistered port, or the GFF_ID failed */
|
|
|
|
ndlp = lpfc_setup_disc_node(vport, did);
|
2008-04-07 21:15:56 +07:00
|
|
|
if (ndlp && NLP_CHK_NODE_ACT(ndlp)) {
|
2007-08-02 22:10:09 +07:00
|
|
|
lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
|
|
|
|
"0242 Process x%x GFF "
|
|
|
|
"NameServer Rsp Data: x%x x%x x%x\n",
|
|
|
|
did, ndlp->nlp_flag, vport->fc_flag,
|
|
|
|
vport->fc_rscn_id_cnt);
|
2007-06-18 07:56:38 +07:00
|
|
|
} else {
|
2007-08-02 22:10:09 +07:00
|
|
|
lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
|
|
|
|
"0243 Skip x%x GFF "
|
|
|
|
"NameServer Rsp Data: x%x x%x\n", did,
|
|
|
|
vport->fc_flag, vport->fc_rscn_id_cnt);
|
2007-06-18 07:56:38 +07:00
|
|
|
}
|
2005-04-18 04:05:31 +07:00
|
|
|
out:
|
2007-06-18 07:56:38 +07:00
|
|
|
/* Link up / RSCN discovery */
|
|
|
|
if (vport->num_disc_nodes)
|
|
|
|
vport->num_disc_nodes--;
|
|
|
|
if (vport->num_disc_nodes == 0) {
|
|
|
|
/*
|
|
|
|
* The driver has cycled through all Nports in the RSCN payload.
|
|
|
|
* Complete the handling by cleaning up and marking the
|
|
|
|
* current driver state.
|
|
|
|
*/
|
|
|
|
if (vport->port_state >= LPFC_DISC_AUTH) {
|
|
|
|
if (vport->fc_flag & FC_RSCN_MODE) {
|
|
|
|
lpfc_els_flush_rscn(vport);
|
|
|
|
spin_lock_irq(shost->host_lock);
|
|
|
|
vport->fc_flag |= FC_RSCN_MODE; /* RSCN still */
|
|
|
|
spin_unlock_irq(shost->host_lock);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
lpfc_els_flush_rscn(vport);
|
|
|
|
}
|
|
|
|
lpfc_disc_start(vport);
|
|
|
|
}
|
2007-06-18 07:56:39 +07:00
|
|
|
lpfc_ct_free_iocb(phba, cmdiocb);
|
2005-04-18 04:05:31 +07:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-02-13 04:52:31 +07:00
|
|
|
static void
|
|
|
|
lpfc_cmpl_ct_cmd_gft_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
|
|
|
|
struct lpfc_iocbq *rspiocb)
|
|
|
|
{
|
|
|
|
struct lpfc_vport *vport = cmdiocb->vport;
|
|
|
|
IOCB_t *irsp = &rspiocb->iocb;
|
|
|
|
struct lpfc_dmabuf *inp = (struct lpfc_dmabuf *)cmdiocb->context1;
|
|
|
|
struct lpfc_dmabuf *outp = (struct lpfc_dmabuf *)cmdiocb->context2;
|
|
|
|
struct lpfc_sli_ct_request *CTrsp;
|
|
|
|
int did;
|
|
|
|
struct lpfc_nodelist *ndlp;
|
|
|
|
uint32_t fc4_data_0, fc4_data_1;
|
|
|
|
|
|
|
|
did = ((struct lpfc_sli_ct_request *)inp->virt)->un.gft.PortId;
|
|
|
|
did = be32_to_cpu(did);
|
|
|
|
|
2017-02-13 04:52:33 +07:00
|
|
|
lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_CT,
|
|
|
|
"GFT_ID cmpl: status:x%x/x%x did:x%x",
|
|
|
|
irsp->ulpStatus, irsp->un.ulpWord[4], did);
|
|
|
|
|
2017-02-13 04:52:31 +07:00
|
|
|
if (irsp->ulpStatus == IOSTAT_SUCCESS) {
|
|
|
|
/* Good status, continue checking */
|
|
|
|
CTrsp = (struct lpfc_sli_ct_request *)outp->virt;
|
|
|
|
fc4_data_0 = be32_to_cpu(CTrsp->un.gft_acc.fc4_types[0]);
|
|
|
|
fc4_data_1 = be32_to_cpu(CTrsp->un.gft_acc.fc4_types[1]);
|
2018-12-14 06:17:56 +07:00
|
|
|
|
2017-08-24 06:55:34 +07:00
|
|
|
lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
|
2018-12-14 06:17:56 +07:00
|
|
|
"6432 Process GFT_ID rsp for %08x "
|
|
|
|
"Data %08x %08x %s %s\n",
|
|
|
|
did, fc4_data_0, fc4_data_1,
|
|
|
|
(fc4_data_0 & LPFC_FC4_TYPE_BITMASK) ?
|
|
|
|
"FCP" : " ",
|
|
|
|
(fc4_data_1 & LPFC_FC4_TYPE_BITMASK) ?
|
|
|
|
"NVME" : " ");
|
2017-02-13 04:52:31 +07:00
|
|
|
|
|
|
|
ndlp = lpfc_findnode_did(vport, did);
|
|
|
|
if (ndlp) {
|
|
|
|
/* The bitmask value for FCP and NVME FCP types is
|
|
|
|
* the same because they are 32 bits distant from
|
|
|
|
* each other in word0 and word0.
|
|
|
|
*/
|
|
|
|
if (fc4_data_0 & LPFC_FC4_TYPE_BITMASK)
|
|
|
|
ndlp->nlp_fc4_type |= NLP_FC4_FCP;
|
|
|
|
if (fc4_data_1 & LPFC_FC4_TYPE_BITMASK)
|
|
|
|
ndlp->nlp_fc4_type |= NLP_FC4_NVME;
|
2017-08-24 06:55:34 +07:00
|
|
|
lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
|
2019-08-15 06:57:06 +07:00
|
|
|
"3064 Setting ndlp x%px, DID x%06x "
|
|
|
|
"with FC4 x%08x, Data: x%08x x%08x "
|
|
|
|
"%d\n",
|
2017-02-13 04:52:31 +07:00
|
|
|
ndlp, did, ndlp->nlp_fc4_type,
|
2019-08-15 06:56:37 +07:00
|
|
|
FC_TYPE_FCP, FC_TYPE_NVME,
|
|
|
|
ndlp->nlp_state);
|
2017-05-23 22:09:28 +07:00
|
|
|
|
2019-08-15 06:56:38 +07:00
|
|
|
if (ndlp->nlp_state == NLP_STE_REG_LOGIN_ISSUE &&
|
|
|
|
ndlp->nlp_fc4_type) {
|
2019-08-15 06:56:37 +07:00
|
|
|
ndlp->nlp_prev_state = NLP_STE_REG_LOGIN_ISSUE;
|
|
|
|
|
|
|
|
lpfc_nlp_set_state(vport, ndlp,
|
|
|
|
NLP_STE_PRLI_ISSUE);
|
|
|
|
lpfc_issue_els_prli(vport, ndlp, 0);
|
2019-08-15 06:56:38 +07:00
|
|
|
} else if (!ndlp->nlp_fc4_type) {
|
|
|
|
/* If fc4 type is still unknown, then LOGO */
|
|
|
|
lpfc_printf_vlog(vport, KERN_INFO,
|
|
|
|
LOG_DISCOVERY,
|
|
|
|
"6443 Sending LOGO ndlp x%px,"
|
|
|
|
"DID x%06x with fc4_type: "
|
|
|
|
"x%08x, state: %d\n",
|
|
|
|
ndlp, did, ndlp->nlp_fc4_type,
|
|
|
|
ndlp->nlp_state);
|
|
|
|
lpfc_issue_els_logo(vport, ndlp, 0);
|
|
|
|
ndlp->nlp_prev_state = NLP_STE_REG_LOGIN_ISSUE;
|
|
|
|
lpfc_nlp_set_state(vport, ndlp,
|
|
|
|
NLP_STE_NPR_NODE);
|
2019-08-15 06:56:37 +07:00
|
|
|
}
|
2017-02-13 04:52:31 +07:00
|
|
|
}
|
|
|
|
} else
|
|
|
|
lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY,
|
|
|
|
"3065 GFT_ID failed x%08x\n", irsp->ulpStatus);
|
|
|
|
|
|
|
|
lpfc_ct_free_iocb(phba, cmdiocb);
|
|
|
|
}
|
2007-06-18 07:56:38 +07:00
|
|
|
|
2005-04-18 04:05:31 +07:00
|
|
|
static void
|
2007-10-28 00:37:17 +07:00
|
|
|
lpfc_cmpl_ct(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
|
|
|
|
struct lpfc_iocbq *rspiocb)
|
2005-04-18 04:05:31 +07:00
|
|
|
{
|
2007-06-18 07:56:38 +07:00
|
|
|
struct lpfc_vport *vport = cmdiocb->vport;
|
2005-04-18 04:05:31 +07:00
|
|
|
struct lpfc_dmabuf *inp;
|
|
|
|
struct lpfc_dmabuf *outp;
|
|
|
|
IOCB_t *irsp;
|
|
|
|
struct lpfc_sli_ct_request *CTrsp;
|
2007-08-02 22:10:31 +07:00
|
|
|
struct lpfc_nodelist *ndlp;
|
2007-06-18 07:56:38 +07:00
|
|
|
int cmdcode, rc;
|
|
|
|
uint8_t retry;
|
2007-06-18 07:56:39 +07:00
|
|
|
uint32_t latt;
|
2005-04-18 04:05:31 +07:00
|
|
|
|
2007-08-02 22:10:31 +07:00
|
|
|
/* First save ndlp, before we overwrite it */
|
|
|
|
ndlp = cmdiocb->context_un.ndlp;
|
|
|
|
|
2005-04-18 04:05:31 +07:00
|
|
|
/* we pass cmdiocb to state machine which needs rspiocb as well */
|
|
|
|
cmdiocb->context_un.rsp_iocb = rspiocb;
|
|
|
|
|
|
|
|
inp = (struct lpfc_dmabuf *) cmdiocb->context1;
|
|
|
|
outp = (struct lpfc_dmabuf *) cmdiocb->context2;
|
|
|
|
irsp = &rspiocb->iocb;
|
|
|
|
|
2007-06-18 07:56:38 +07:00
|
|
|
cmdcode = be16_to_cpu(((struct lpfc_sli_ct_request *) inp->virt)->
|
|
|
|
CommandResponse.bits.CmdRsp);
|
2005-04-18 04:05:31 +07:00
|
|
|
CTrsp = (struct lpfc_sli_ct_request *) outp->virt;
|
|
|
|
|
2007-06-18 07:56:39 +07:00
|
|
|
latt = lpfc_els_chk_latt(vport);
|
|
|
|
|
|
|
|
/* RFT request completes status <ulpStatus> CmdRsp <CmdRsp> */
|
2007-08-02 22:10:09 +07:00
|
|
|
lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
|
2007-10-28 00:37:17 +07:00
|
|
|
"0209 CT Request completes, latt %d, "
|
2007-08-02 22:10:09 +07:00
|
|
|
"ulpStatus x%x CmdRsp x%x, Context x%x, Tag x%x\n",
|
|
|
|
latt, irsp->ulpStatus,
|
|
|
|
CTrsp->CommandResponse.bits.CmdRsp,
|
|
|
|
cmdiocb->iocb.ulpContext, cmdiocb->iocb.ulpIoTag);
|
2005-04-18 04:05:31 +07:00
|
|
|
|
2007-06-18 07:56:39 +07:00
|
|
|
lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_CT,
|
|
|
|
"CT cmd cmpl: status:x%x/x%x cmd:x%x",
|
|
|
|
irsp->ulpStatus, irsp->un.ulpWord[4], cmdcode);
|
|
|
|
|
2007-06-18 07:56:38 +07:00
|
|
|
if (irsp->ulpStatus) {
|
2007-08-02 22:10:09 +07:00
|
|
|
lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY,
|
2013-07-16 05:35:21 +07:00
|
|
|
"0268 NS cmd x%x Error (x%x x%x)\n",
|
2007-08-02 22:10:09 +07:00
|
|
|
cmdcode, irsp->ulpStatus, irsp->un.ulpWord[4]);
|
2007-06-18 07:56:39 +07:00
|
|
|
|
2007-06-18 07:56:38 +07:00
|
|
|
if ((irsp->ulpStatus == IOSTAT_LOCAL_REJECT) &&
|
2012-08-15 01:25:43 +07:00
|
|
|
(((irsp->un.ulpWord[4] & IOERR_PARAM_MASK) ==
|
|
|
|
IOERR_SLI_DOWN) ||
|
|
|
|
((irsp->un.ulpWord[4] & IOERR_PARAM_MASK) ==
|
|
|
|
IOERR_SLI_ABORTED)))
|
2007-06-18 07:56:38 +07:00
|
|
|
goto out;
|
|
|
|
|
|
|
|
retry = cmdiocb->retry;
|
|
|
|
if (retry >= LPFC_MAX_NS_RETRY)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
retry++;
|
2007-08-02 22:10:09 +07:00
|
|
|
lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
|
2008-08-25 08:50:00 +07:00
|
|
|
"0250 Retrying NS cmd %x\n", cmdcode);
|
2007-06-18 07:56:38 +07:00
|
|
|
rc = lpfc_ns_cmd(vport, cmdcode, retry, 0);
|
|
|
|
if (rc == 0)
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
out:
|
2007-08-02 22:10:31 +07:00
|
|
|
cmdiocb->context_un.ndlp = ndlp; /* Now restore ndlp for free */
|
2007-06-18 07:56:39 +07:00
|
|
|
lpfc_ct_free_iocb(phba, cmdiocb);
|
2005-04-18 04:05:31 +07:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2007-10-28 00:37:17 +07:00
|
|
|
static void
|
|
|
|
lpfc_cmpl_ct_cmd_rft_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
|
|
|
|
struct lpfc_iocbq *rspiocb)
|
|
|
|
{
|
|
|
|
IOCB_t *irsp = &rspiocb->iocb;
|
|
|
|
struct lpfc_vport *vport = cmdiocb->vport;
|
|
|
|
|
2007-10-28 00:37:33 +07:00
|
|
|
if (irsp->ulpStatus == IOSTAT_SUCCESS) {
|
|
|
|
struct lpfc_dmabuf *outp;
|
|
|
|
struct lpfc_sli_ct_request *CTrsp;
|
|
|
|
|
|
|
|
outp = (struct lpfc_dmabuf *) cmdiocb->context2;
|
|
|
|
CTrsp = (struct lpfc_sli_ct_request *) outp->virt;
|
|
|
|
if (CTrsp->CommandResponse.bits.CmdRsp ==
|
|
|
|
be16_to_cpu(SLI_CT_RESPONSE_FS_ACC))
|
|
|
|
vport->ct_flags |= FC_CT_RFT_ID;
|
|
|
|
}
|
2007-10-28 00:37:17 +07:00
|
|
|
lpfc_cmpl_ct(phba, cmdiocb, rspiocb);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2005-04-18 04:05:31 +07:00
|
|
|
static void
|
2007-06-18 07:56:36 +07:00
|
|
|
lpfc_cmpl_ct_cmd_rnn_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
|
|
|
|
struct lpfc_iocbq *rspiocb)
|
2005-04-18 04:05:31 +07:00
|
|
|
{
|
2007-10-28 00:37:17 +07:00
|
|
|
IOCB_t *irsp = &rspiocb->iocb;
|
|
|
|
struct lpfc_vport *vport = cmdiocb->vport;
|
|
|
|
|
2007-10-28 00:37:33 +07:00
|
|
|
if (irsp->ulpStatus == IOSTAT_SUCCESS) {
|
|
|
|
struct lpfc_dmabuf *outp;
|
|
|
|
struct lpfc_sli_ct_request *CTrsp;
|
|
|
|
|
|
|
|
outp = (struct lpfc_dmabuf *) cmdiocb->context2;
|
|
|
|
CTrsp = (struct lpfc_sli_ct_request *) outp->virt;
|
|
|
|
if (CTrsp->CommandResponse.bits.CmdRsp ==
|
|
|
|
be16_to_cpu(SLI_CT_RESPONSE_FS_ACC))
|
|
|
|
vport->ct_flags |= FC_CT_RNN_ID;
|
|
|
|
}
|
2007-10-28 00:37:17 +07:00
|
|
|
lpfc_cmpl_ct(phba, cmdiocb, rspiocb);
|
2005-04-18 04:05:31 +07:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2007-06-18 07:56:38 +07:00
|
|
|
static void
|
|
|
|
lpfc_cmpl_ct_cmd_rspn_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
|
|
|
|
struct lpfc_iocbq *rspiocb)
|
|
|
|
{
|
2007-10-28 00:37:17 +07:00
|
|
|
IOCB_t *irsp = &rspiocb->iocb;
|
|
|
|
struct lpfc_vport *vport = cmdiocb->vport;
|
|
|
|
|
2007-10-28 00:37:33 +07:00
|
|
|
if (irsp->ulpStatus == IOSTAT_SUCCESS) {
|
|
|
|
struct lpfc_dmabuf *outp;
|
|
|
|
struct lpfc_sli_ct_request *CTrsp;
|
|
|
|
|
|
|
|
outp = (struct lpfc_dmabuf *) cmdiocb->context2;
|
|
|
|
CTrsp = (struct lpfc_sli_ct_request *) outp->virt;
|
|
|
|
if (CTrsp->CommandResponse.bits.CmdRsp ==
|
|
|
|
be16_to_cpu(SLI_CT_RESPONSE_FS_ACC))
|
|
|
|
vport->ct_flags |= FC_CT_RSPN_ID;
|
|
|
|
}
|
2007-10-28 00:37:17 +07:00
|
|
|
lpfc_cmpl_ct(phba, cmdiocb, rspiocb);
|
2007-06-18 07:56:38 +07:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2005-04-18 04:05:31 +07:00
|
|
|
static void
|
2007-06-18 07:56:36 +07:00
|
|
|
lpfc_cmpl_ct_cmd_rsnn_nn(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
|
|
|
|
struct lpfc_iocbq *rspiocb)
|
2005-04-18 04:05:31 +07:00
|
|
|
{
|
2007-10-28 00:37:17 +07:00
|
|
|
IOCB_t *irsp = &rspiocb->iocb;
|
|
|
|
struct lpfc_vport *vport = cmdiocb->vport;
|
|
|
|
|
2007-10-28 00:37:33 +07:00
|
|
|
if (irsp->ulpStatus == IOSTAT_SUCCESS) {
|
|
|
|
struct lpfc_dmabuf *outp;
|
|
|
|
struct lpfc_sli_ct_request *CTrsp;
|
|
|
|
|
|
|
|
outp = (struct lpfc_dmabuf *) cmdiocb->context2;
|
|
|
|
CTrsp = (struct lpfc_sli_ct_request *) outp->virt;
|
|
|
|
if (CTrsp->CommandResponse.bits.CmdRsp ==
|
|
|
|
be16_to_cpu(SLI_CT_RESPONSE_FS_ACC))
|
|
|
|
vport->ct_flags |= FC_CT_RSNN_NN;
|
|
|
|
}
|
2007-10-28 00:37:17 +07:00
|
|
|
lpfc_cmpl_ct(phba, cmdiocb, rspiocb);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
lpfc_cmpl_ct_cmd_da_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
|
|
|
|
struct lpfc_iocbq *rspiocb)
|
|
|
|
{
|
|
|
|
struct lpfc_vport *vport = cmdiocb->vport;
|
|
|
|
|
|
|
|
/* even if it fails we will act as though it succeeded. */
|
|
|
|
vport->ct_flags = 0;
|
|
|
|
lpfc_cmpl_ct(phba, cmdiocb, rspiocb);
|
2005-04-18 04:05:31 +07:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2006-12-03 01:33:57 +07:00
|
|
|
static void
|
2007-06-18 07:56:38 +07:00
|
|
|
lpfc_cmpl_ct_cmd_rff_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
|
|
|
|
struct lpfc_iocbq *rspiocb)
|
2006-12-03 01:33:57 +07:00
|
|
|
{
|
2007-06-18 07:56:38 +07:00
|
|
|
IOCB_t *irsp = &rspiocb->iocb;
|
|
|
|
struct lpfc_vport *vport = cmdiocb->vport;
|
|
|
|
|
2007-10-28 00:37:33 +07:00
|
|
|
if (irsp->ulpStatus == IOSTAT_SUCCESS) {
|
|
|
|
struct lpfc_dmabuf *outp;
|
|
|
|
struct lpfc_sli_ct_request *CTrsp;
|
|
|
|
|
|
|
|
outp = (struct lpfc_dmabuf *) cmdiocb->context2;
|
|
|
|
CTrsp = (struct lpfc_sli_ct_request *) outp->virt;
|
|
|
|
if (CTrsp->CommandResponse.bits.CmdRsp ==
|
|
|
|
be16_to_cpu(SLI_CT_RESPONSE_FS_ACC))
|
|
|
|
vport->ct_flags |= FC_CT_RFF_ID;
|
|
|
|
}
|
2007-10-28 00:37:17 +07:00
|
|
|
lpfc_cmpl_ct(phba, cmdiocb, rspiocb);
|
2006-12-03 01:33:57 +07:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-02-13 04:52:31 +07:00
|
|
|
/*
|
|
|
|
* Although the symbolic port name is thought to be an integer
|
|
|
|
* as of January 18, 2016, leave it as a string until more of
|
|
|
|
* the record state becomes defined.
|
|
|
|
*/
|
2008-06-15 09:52:59 +07:00
|
|
|
int
|
2007-06-18 07:56:38 +07:00
|
|
|
lpfc_vport_symbolic_port_name(struct lpfc_vport *vport, char *symbol,
|
|
|
|
size_t size)
|
|
|
|
{
|
|
|
|
int n;
|
|
|
|
|
2017-02-13 04:52:31 +07:00
|
|
|
/*
|
|
|
|
* Use the lpfc board number as the Symbolic Port
|
|
|
|
* Name object. NPIV is not in play so this integer
|
|
|
|
* value is sufficient and unique per FC-ID.
|
|
|
|
*/
|
scsi: lpfc: change snprintf to scnprintf for possible overflow
Change snprintf to scnprintf. There are generally two cases where using
snprintf causes problems.
1) Uses of size += snprintf(buf, SIZE - size, fmt, ...)
In this case, if snprintf would have written more characters than what the
buffer size (SIZE) is, then size will end up larger than SIZE. In later
uses of snprintf, SIZE - size will result in a negative number, leading
to problems. Note that size might already be too large by using
size = snprintf before the code reaches a case of size += snprintf.
2) If size is ultimately used as a length parameter for a copy back to user
space, then it will potentially allow for a buffer overflow and information
disclosure when size is greater than SIZE. When the size is used to index
the buffer directly, we can have memory corruption. This also means when
size = snprintf... is used, it may also cause problems since size may become
large. Copying to userspace is mitigated by the HARDENED_USERCOPY kernel
configuration.
The solution to these issues is to use scnprintf which returns the number of
characters actually written to the buffer, so the size variable will never
exceed SIZE.
Signed-off-by: Silvio Cesare <silvio.cesare@gmail.com>
Signed-off-by: Willy Tarreau <w@1wt.eu>
Signed-off-by: James Smart <james.smart@broadcom.com>
Cc: Dick Kennedy <dick.kennedy@broadcom.com>
Cc: Dan Carpenter <dan.carpenter@oracle.com>
Cc: Kees Cook <keescook@chromium.org>
Cc: Will Deacon <will.deacon@arm.com>
Cc: Greg KH <greg@kroah.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
2019-03-21 23:44:32 +07:00
|
|
|
n = scnprintf(symbol, size, "%d", vport->phba->brd_no);
|
2007-06-18 07:56:38 +07:00
|
|
|
return n;
|
|
|
|
}
|
|
|
|
|
2017-02-13 04:52:31 +07:00
|
|
|
|
2007-06-18 07:56:38 +07:00
|
|
|
int
|
|
|
|
lpfc_vport_symbolic_node_name(struct lpfc_vport *vport, char *symbol,
|
|
|
|
size_t size)
|
2005-04-18 04:05:31 +07:00
|
|
|
{
|
2012-01-19 04:24:06 +07:00
|
|
|
char fwrev[FW_REV_STR_SIZE];
|
2007-06-18 07:56:38 +07:00
|
|
|
int n;
|
2005-04-18 04:05:31 +07:00
|
|
|
|
2007-06-18 07:56:38 +07:00
|
|
|
lpfc_decode_firmware_rev(vport->phba, fwrev, 0);
|
2005-04-18 04:05:31 +07:00
|
|
|
|
scsi: lpfc: change snprintf to scnprintf for possible overflow
Change snprintf to scnprintf. There are generally two cases where using
snprintf causes problems.
1) Uses of size += snprintf(buf, SIZE - size, fmt, ...)
In this case, if snprintf would have written more characters than what the
buffer size (SIZE) is, then size will end up larger than SIZE. In later
uses of snprintf, SIZE - size will result in a negative number, leading
to problems. Note that size might already be too large by using
size = snprintf before the code reaches a case of size += snprintf.
2) If size is ultimately used as a length parameter for a copy back to user
space, then it will potentially allow for a buffer overflow and information
disclosure when size is greater than SIZE. When the size is used to index
the buffer directly, we can have memory corruption. This also means when
size = snprintf... is used, it may also cause problems since size may become
large. Copying to userspace is mitigated by the HARDENED_USERCOPY kernel
configuration.
The solution to these issues is to use scnprintf which returns the number of
characters actually written to the buffer, so the size variable will never
exceed SIZE.
Signed-off-by: Silvio Cesare <silvio.cesare@gmail.com>
Signed-off-by: Willy Tarreau <w@1wt.eu>
Signed-off-by: James Smart <james.smart@broadcom.com>
Cc: Dick Kennedy <dick.kennedy@broadcom.com>
Cc: Dan Carpenter <dan.carpenter@oracle.com>
Cc: Kees Cook <keescook@chromium.org>
Cc: Will Deacon <will.deacon@arm.com>
Cc: Greg KH <greg@kroah.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
2019-03-21 23:44:32 +07:00
|
|
|
n = scnprintf(symbol, size, "Emulex %s", vport->phba->ModelName);
|
2015-04-08 02:07:18 +07:00
|
|
|
if (size < n)
|
|
|
|
return n;
|
|
|
|
|
scsi: lpfc: change snprintf to scnprintf for possible overflow
Change snprintf to scnprintf. There are generally two cases where using
snprintf causes problems.
1) Uses of size += snprintf(buf, SIZE - size, fmt, ...)
In this case, if snprintf would have written more characters than what the
buffer size (SIZE) is, then size will end up larger than SIZE. In later
uses of snprintf, SIZE - size will result in a negative number, leading
to problems. Note that size might already be too large by using
size = snprintf before the code reaches a case of size += snprintf.
2) If size is ultimately used as a length parameter for a copy back to user
space, then it will potentially allow for a buffer overflow and information
disclosure when size is greater than SIZE. When the size is used to index
the buffer directly, we can have memory corruption. This also means when
size = snprintf... is used, it may also cause problems since size may become
large. Copying to userspace is mitigated by the HARDENED_USERCOPY kernel
configuration.
The solution to these issues is to use scnprintf which returns the number of
characters actually written to the buffer, so the size variable will never
exceed SIZE.
Signed-off-by: Silvio Cesare <silvio.cesare@gmail.com>
Signed-off-by: Willy Tarreau <w@1wt.eu>
Signed-off-by: James Smart <james.smart@broadcom.com>
Cc: Dick Kennedy <dick.kennedy@broadcom.com>
Cc: Dan Carpenter <dan.carpenter@oracle.com>
Cc: Kees Cook <keescook@chromium.org>
Cc: Will Deacon <will.deacon@arm.com>
Cc: Greg KH <greg@kroah.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
2019-03-21 23:44:32 +07:00
|
|
|
n += scnprintf(symbol + n, size - n, " FV%s", fwrev);
|
2015-04-08 02:07:18 +07:00
|
|
|
if (size < n)
|
|
|
|
return n;
|
|
|
|
|
scsi: lpfc: change snprintf to scnprintf for possible overflow
Change snprintf to scnprintf. There are generally two cases where using
snprintf causes problems.
1) Uses of size += snprintf(buf, SIZE - size, fmt, ...)
In this case, if snprintf would have written more characters than what the
buffer size (SIZE) is, then size will end up larger than SIZE. In later
uses of snprintf, SIZE - size will result in a negative number, leading
to problems. Note that size might already be too large by using
size = snprintf before the code reaches a case of size += snprintf.
2) If size is ultimately used as a length parameter for a copy back to user
space, then it will potentially allow for a buffer overflow and information
disclosure when size is greater than SIZE. When the size is used to index
the buffer directly, we can have memory corruption. This also means when
size = snprintf... is used, it may also cause problems since size may become
large. Copying to userspace is mitigated by the HARDENED_USERCOPY kernel
configuration.
The solution to these issues is to use scnprintf which returns the number of
characters actually written to the buffer, so the size variable will never
exceed SIZE.
Signed-off-by: Silvio Cesare <silvio.cesare@gmail.com>
Signed-off-by: Willy Tarreau <w@1wt.eu>
Signed-off-by: James Smart <james.smart@broadcom.com>
Cc: Dick Kennedy <dick.kennedy@broadcom.com>
Cc: Dan Carpenter <dan.carpenter@oracle.com>
Cc: Kees Cook <keescook@chromium.org>
Cc: Will Deacon <will.deacon@arm.com>
Cc: Greg KH <greg@kroah.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
2019-03-21 23:44:32 +07:00
|
|
|
n += scnprintf(symbol + n, size - n, " DV%s.",
|
2017-02-13 04:52:31 +07:00
|
|
|
lpfc_release_version);
|
2015-04-08 02:07:18 +07:00
|
|
|
if (size < n)
|
|
|
|
return n;
|
|
|
|
|
scsi: lpfc: change snprintf to scnprintf for possible overflow
Change snprintf to scnprintf. There are generally two cases where using
snprintf causes problems.
1) Uses of size += snprintf(buf, SIZE - size, fmt, ...)
In this case, if snprintf would have written more characters than what the
buffer size (SIZE) is, then size will end up larger than SIZE. In later
uses of snprintf, SIZE - size will result in a negative number, leading
to problems. Note that size might already be too large by using
size = snprintf before the code reaches a case of size += snprintf.
2) If size is ultimately used as a length parameter for a copy back to user
space, then it will potentially allow for a buffer overflow and information
disclosure when size is greater than SIZE. When the size is used to index
the buffer directly, we can have memory corruption. This also means when
size = snprintf... is used, it may also cause problems since size may become
large. Copying to userspace is mitigated by the HARDENED_USERCOPY kernel
configuration.
The solution to these issues is to use scnprintf which returns the number of
characters actually written to the buffer, so the size variable will never
exceed SIZE.
Signed-off-by: Silvio Cesare <silvio.cesare@gmail.com>
Signed-off-by: Willy Tarreau <w@1wt.eu>
Signed-off-by: James Smart <james.smart@broadcom.com>
Cc: Dick Kennedy <dick.kennedy@broadcom.com>
Cc: Dan Carpenter <dan.carpenter@oracle.com>
Cc: Kees Cook <keescook@chromium.org>
Cc: Will Deacon <will.deacon@arm.com>
Cc: Greg KH <greg@kroah.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
2019-03-21 23:44:32 +07:00
|
|
|
n += scnprintf(symbol + n, size - n, " HN:%s.",
|
2017-02-13 04:52:31 +07:00
|
|
|
init_utsname()->nodename);
|
2015-04-08 02:07:18 +07:00
|
|
|
if (size < n)
|
|
|
|
return n;
|
|
|
|
|
2017-02-13 04:52:31 +07:00
|
|
|
/* Note :- OS name is "Linux" */
|
scsi: lpfc: change snprintf to scnprintf for possible overflow
Change snprintf to scnprintf. There are generally two cases where using
snprintf causes problems.
1) Uses of size += snprintf(buf, SIZE - size, fmt, ...)
In this case, if snprintf would have written more characters than what the
buffer size (SIZE) is, then size will end up larger than SIZE. In later
uses of snprintf, SIZE - size will result in a negative number, leading
to problems. Note that size might already be too large by using
size = snprintf before the code reaches a case of size += snprintf.
2) If size is ultimately used as a length parameter for a copy back to user
space, then it will potentially allow for a buffer overflow and information
disclosure when size is greater than SIZE. When the size is used to index
the buffer directly, we can have memory corruption. This also means when
size = snprintf... is used, it may also cause problems since size may become
large. Copying to userspace is mitigated by the HARDENED_USERCOPY kernel
configuration.
The solution to these issues is to use scnprintf which returns the number of
characters actually written to the buffer, so the size variable will never
exceed SIZE.
Signed-off-by: Silvio Cesare <silvio.cesare@gmail.com>
Signed-off-by: Willy Tarreau <w@1wt.eu>
Signed-off-by: James Smart <james.smart@broadcom.com>
Cc: Dick Kennedy <dick.kennedy@broadcom.com>
Cc: Dan Carpenter <dan.carpenter@oracle.com>
Cc: Kees Cook <keescook@chromium.org>
Cc: Will Deacon <will.deacon@arm.com>
Cc: Greg KH <greg@kroah.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
2019-03-21 23:44:32 +07:00
|
|
|
n += scnprintf(symbol + n, size - n, " OS:%s",
|
2017-02-13 04:52:31 +07:00
|
|
|
init_utsname()->sysname);
|
2007-06-18 07:56:38 +07:00
|
|
|
return n;
|
2005-04-18 04:05:31 +07:00
|
|
|
}
|
|
|
|
|
2015-04-08 02:07:19 +07:00
|
|
|
static uint32_t
|
|
|
|
lpfc_find_map_node(struct lpfc_vport *vport)
|
|
|
|
{
|
|
|
|
struct lpfc_nodelist *ndlp, *next_ndlp;
|
|
|
|
struct Scsi_Host *shost;
|
|
|
|
uint32_t cnt = 0;
|
|
|
|
|
|
|
|
shost = lpfc_shost_from_vport(vport);
|
|
|
|
spin_lock_irq(shost->host_lock);
|
|
|
|
list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) {
|
|
|
|
if (ndlp->nlp_type & NLP_FABRIC)
|
|
|
|
continue;
|
|
|
|
if ((ndlp->nlp_state == NLP_STE_MAPPED_NODE) ||
|
|
|
|
(ndlp->nlp_state == NLP_STE_UNMAPPED_NODE))
|
|
|
|
cnt++;
|
|
|
|
}
|
|
|
|
spin_unlock_irq(shost->host_lock);
|
|
|
|
return cnt;
|
|
|
|
}
|
|
|
|
|
2017-02-13 04:52:31 +07:00
|
|
|
/*
|
|
|
|
* This routine will return the FC4 Type associated with the CT
|
|
|
|
* GID_FT command.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
lpfc_get_gidft_type(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb)
|
|
|
|
{
|
|
|
|
struct lpfc_sli_ct_request *CtReq;
|
|
|
|
struct lpfc_dmabuf *mp;
|
|
|
|
uint32_t type;
|
|
|
|
|
|
|
|
mp = cmdiocb->context1;
|
|
|
|
if (mp == NULL)
|
|
|
|
return 0;
|
|
|
|
CtReq = (struct lpfc_sli_ct_request *)mp->virt;
|
|
|
|
type = (uint32_t)CtReq->un.gid.Fc4Type;
|
|
|
|
if ((type != SLI_CTPT_FCP) && (type != SLI_CTPT_NVME))
|
|
|
|
return 0;
|
|
|
|
return type;
|
|
|
|
}
|
|
|
|
|
2005-04-18 04:05:31 +07:00
|
|
|
/*
|
|
|
|
* lpfc_ns_cmd
|
|
|
|
* Description:
|
|
|
|
* Issue Cmd to NameServer
|
|
|
|
* SLI_CTNS_GID_FT
|
|
|
|
* LI_CTNS_RFT_ID
|
|
|
|
*/
|
|
|
|
int
|
2007-06-18 07:56:38 +07:00
|
|
|
lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode,
|
|
|
|
uint8_t retry, uint32_t context)
|
2005-04-18 04:05:31 +07:00
|
|
|
{
|
2007-06-18 07:56:38 +07:00
|
|
|
struct lpfc_nodelist * ndlp;
|
2007-06-18 07:56:36 +07:00
|
|
|
struct lpfc_hba *phba = vport->phba;
|
2005-04-18 04:05:31 +07:00
|
|
|
struct lpfc_dmabuf *mp, *bmp;
|
|
|
|
struct lpfc_sli_ct_request *CtReq;
|
|
|
|
struct ulp_bde64 *bpl;
|
|
|
|
void (*cmpl) (struct lpfc_hba *, struct lpfc_iocbq *,
|
|
|
|
struct lpfc_iocbq *) = NULL;
|
2018-12-14 06:17:56 +07:00
|
|
|
uint32_t *ptr;
|
2005-04-18 04:05:31 +07:00
|
|
|
uint32_t rsp_size = 1024;
|
2007-06-18 07:56:38 +07:00
|
|
|
size_t size;
|
2007-06-18 07:56:39 +07:00
|
|
|
int rc = 0;
|
2007-06-18 07:56:38 +07:00
|
|
|
|
|
|
|
ndlp = lpfc_findnode_did(vport, NameServer_DID);
|
2008-02-09 06:49:26 +07:00
|
|
|
if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)
|
|
|
|
|| ndlp->nlp_state != NLP_STE_UNMAPPED_NODE) {
|
2007-06-18 07:56:39 +07:00
|
|
|
rc=1;
|
|
|
|
goto ns_cmd_exit;
|
|
|
|
}
|
2005-04-18 04:05:31 +07:00
|
|
|
|
|
|
|
/* fill in BDEs for command */
|
|
|
|
/* Allocate buffer for command payload */
|
2015-12-17 06:11:58 +07:00
|
|
|
mp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
|
2007-06-18 07:56:39 +07:00
|
|
|
if (!mp) {
|
|
|
|
rc=2;
|
2005-04-18 04:05:31 +07:00
|
|
|
goto ns_cmd_exit;
|
2007-06-18 07:56:39 +07:00
|
|
|
}
|
2005-04-18 04:05:31 +07:00
|
|
|
|
|
|
|
INIT_LIST_HEAD(&mp->list);
|
|
|
|
mp->virt = lpfc_mbuf_alloc(phba, MEM_PRI, &(mp->phys));
|
2007-06-18 07:56:39 +07:00
|
|
|
if (!mp->virt) {
|
|
|
|
rc=3;
|
2005-04-18 04:05:31 +07:00
|
|
|
goto ns_cmd_free_mp;
|
2007-06-18 07:56:39 +07:00
|
|
|
}
|
2005-04-18 04:05:31 +07:00
|
|
|
|
|
|
|
/* Allocate buffer for Buffer ptr list */
|
2015-12-17 06:11:58 +07:00
|
|
|
bmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
|
2007-06-18 07:56:39 +07:00
|
|
|
if (!bmp) {
|
|
|
|
rc=4;
|
2005-04-18 04:05:31 +07:00
|
|
|
goto ns_cmd_free_mpvirt;
|
2007-06-18 07:56:39 +07:00
|
|
|
}
|
2005-04-18 04:05:31 +07:00
|
|
|
|
|
|
|
INIT_LIST_HEAD(&bmp->list);
|
|
|
|
bmp->virt = lpfc_mbuf_alloc(phba, MEM_PRI, &(bmp->phys));
|
2007-06-18 07:56:39 +07:00
|
|
|
if (!bmp->virt) {
|
|
|
|
rc=5;
|
2005-04-18 04:05:31 +07:00
|
|
|
goto ns_cmd_free_bmp;
|
2007-06-18 07:56:39 +07:00
|
|
|
}
|
2005-04-18 04:05:31 +07:00
|
|
|
|
|
|
|
/* NameServer Req */
|
2007-08-02 22:10:09 +07:00
|
|
|
lpfc_printf_vlog(vport, KERN_INFO ,LOG_DISCOVERY,
|
2017-02-13 04:52:31 +07:00
|
|
|
"0236 NameServer Req Data: x%x x%x x%x x%x\n",
|
|
|
|
cmdcode, vport->fc_flag, vport->fc_rscn_id_cnt,
|
|
|
|
context);
|
2005-04-18 04:05:31 +07:00
|
|
|
|
|
|
|
bpl = (struct ulp_bde64 *) bmp->virt;
|
|
|
|
memset(bpl, 0, sizeof(struct ulp_bde64));
|
2007-06-18 07:56:38 +07:00
|
|
|
bpl->addrHigh = le32_to_cpu(putPaddrHigh(mp->phys) );
|
|
|
|
bpl->addrLow = le32_to_cpu(putPaddrLow(mp->phys) );
|
2005-04-18 04:05:31 +07:00
|
|
|
bpl->tus.f.bdeFlags = 0;
|
|
|
|
if (cmdcode == SLI_CTNS_GID_FT)
|
|
|
|
bpl->tus.f.bdeSize = GID_REQUEST_SZ;
|
2018-10-24 03:41:10 +07:00
|
|
|
else if (cmdcode == SLI_CTNS_GID_PT)
|
|
|
|
bpl->tus.f.bdeSize = GID_REQUEST_SZ;
|
2007-06-18 07:56:38 +07:00
|
|
|
else if (cmdcode == SLI_CTNS_GFF_ID)
|
|
|
|
bpl->tus.f.bdeSize = GFF_REQUEST_SZ;
|
2017-02-13 04:52:31 +07:00
|
|
|
else if (cmdcode == SLI_CTNS_GFT_ID)
|
|
|
|
bpl->tus.f.bdeSize = GFT_REQUEST_SZ;
|
2005-04-18 04:05:31 +07:00
|
|
|
else if (cmdcode == SLI_CTNS_RFT_ID)
|
|
|
|
bpl->tus.f.bdeSize = RFT_REQUEST_SZ;
|
|
|
|
else if (cmdcode == SLI_CTNS_RNN_ID)
|
|
|
|
bpl->tus.f.bdeSize = RNN_REQUEST_SZ;
|
2007-06-18 07:56:38 +07:00
|
|
|
else if (cmdcode == SLI_CTNS_RSPN_ID)
|
|
|
|
bpl->tus.f.bdeSize = RSPN_REQUEST_SZ;
|
2005-04-18 04:05:31 +07:00
|
|
|
else if (cmdcode == SLI_CTNS_RSNN_NN)
|
|
|
|
bpl->tus.f.bdeSize = RSNN_REQUEST_SZ;
|
2007-10-28 00:37:17 +07:00
|
|
|
else if (cmdcode == SLI_CTNS_DA_ID)
|
|
|
|
bpl->tus.f.bdeSize = DA_ID_REQUEST_SZ;
|
2006-12-03 01:33:57 +07:00
|
|
|
else if (cmdcode == SLI_CTNS_RFF_ID)
|
|
|
|
bpl->tus.f.bdeSize = RFF_REQUEST_SZ;
|
2005-04-18 04:05:31 +07:00
|
|
|
else
|
|
|
|
bpl->tus.f.bdeSize = 0;
|
|
|
|
bpl->tus.w = le32_to_cpu(bpl->tus.w);
|
|
|
|
|
|
|
|
CtReq = (struct lpfc_sli_ct_request *) mp->virt;
|
2015-12-17 06:11:58 +07:00
|
|
|
memset(CtReq, 0, sizeof(struct lpfc_sli_ct_request));
|
2005-04-18 04:05:31 +07:00
|
|
|
CtReq->RevisionId.bits.Revision = SLI_CT_REVISION;
|
|
|
|
CtReq->RevisionId.bits.InId = 0;
|
|
|
|
CtReq->FsType = SLI_CT_DIRECTORY_SERVICE;
|
|
|
|
CtReq->FsSubType = SLI_CT_DIRECTORY_NAME_SERVER;
|
|
|
|
CtReq->CommandResponse.bits.Size = 0;
|
|
|
|
switch (cmdcode) {
|
|
|
|
case SLI_CTNS_GID_FT:
|
|
|
|
CtReq->CommandResponse.bits.CmdRsp =
|
2015-04-08 02:07:19 +07:00
|
|
|
cpu_to_be16(SLI_CTNS_GID_FT);
|
2017-02-13 04:52:31 +07:00
|
|
|
CtReq->un.gid.Fc4Type = context;
|
|
|
|
|
2007-06-18 07:56:38 +07:00
|
|
|
if (vport->port_state < LPFC_NS_QRY)
|
2007-06-18 07:56:36 +07:00
|
|
|
vport->port_state = LPFC_NS_QRY;
|
|
|
|
lpfc_set_disctmo(vport);
|
2005-04-18 04:05:31 +07:00
|
|
|
cmpl = lpfc_cmpl_ct_cmd_gid_ft;
|
|
|
|
rsp_size = FC_MAX_NS_RSP;
|
|
|
|
break;
|
|
|
|
|
2018-10-24 03:41:10 +07:00
|
|
|
case SLI_CTNS_GID_PT:
|
|
|
|
CtReq->CommandResponse.bits.CmdRsp =
|
|
|
|
cpu_to_be16(SLI_CTNS_GID_PT);
|
|
|
|
CtReq->un.gid.PortType = context;
|
|
|
|
|
|
|
|
if (vport->port_state < LPFC_NS_QRY)
|
|
|
|
vport->port_state = LPFC_NS_QRY;
|
|
|
|
lpfc_set_disctmo(vport);
|
|
|
|
cmpl = lpfc_cmpl_ct_cmd_gid_pt;
|
|
|
|
rsp_size = FC_MAX_NS_RSP;
|
|
|
|
break;
|
|
|
|
|
2007-06-18 07:56:38 +07:00
|
|
|
case SLI_CTNS_GFF_ID:
|
|
|
|
CtReq->CommandResponse.bits.CmdRsp =
|
2015-04-08 02:07:19 +07:00
|
|
|
cpu_to_be16(SLI_CTNS_GFF_ID);
|
2008-01-11 13:52:54 +07:00
|
|
|
CtReq->un.gff.PortId = cpu_to_be32(context);
|
2007-06-18 07:56:38 +07:00
|
|
|
cmpl = lpfc_cmpl_ct_cmd_gff_id;
|
|
|
|
break;
|
|
|
|
|
2017-02-13 04:52:31 +07:00
|
|
|
case SLI_CTNS_GFT_ID:
|
|
|
|
CtReq->CommandResponse.bits.CmdRsp =
|
|
|
|
cpu_to_be16(SLI_CTNS_GFT_ID);
|
|
|
|
CtReq->un.gft.PortId = cpu_to_be32(context);
|
|
|
|
cmpl = lpfc_cmpl_ct_cmd_gft_id;
|
|
|
|
break;
|
|
|
|
|
2005-04-18 04:05:31 +07:00
|
|
|
case SLI_CTNS_RFT_ID:
|
2007-10-28 00:37:17 +07:00
|
|
|
vport->ct_flags &= ~FC_CT_RFT_ID;
|
2005-04-18 04:05:31 +07:00
|
|
|
CtReq->CommandResponse.bits.CmdRsp =
|
2015-04-08 02:07:19 +07:00
|
|
|
cpu_to_be16(SLI_CTNS_RFT_ID);
|
2008-01-11 13:52:54 +07:00
|
|
|
CtReq->un.rft.PortId = cpu_to_be32(vport->fc_myDID);
|
2017-02-13 04:52:31 +07:00
|
|
|
|
|
|
|
/* Register FC4 FCP type if enabled. */
|
2019-01-29 02:14:38 +07:00
|
|
|
if (vport->cfg_enable_fc4_type == LPFC_ENABLE_BOTH ||
|
|
|
|
vport->cfg_enable_fc4_type == LPFC_ENABLE_FCP)
|
2017-02-13 04:52:31 +07:00
|
|
|
CtReq->un.rft.fcpReg = 1;
|
|
|
|
|
|
|
|
/* Register NVME type if enabled. Defined LE and swapped.
|
|
|
|
* rsvd[0] is used as word1 because of the hard-coded
|
|
|
|
* word0 usage in the ct_request data structure.
|
|
|
|
*/
|
2019-01-29 02:14:38 +07:00
|
|
|
if (vport->cfg_enable_fc4_type == LPFC_ENABLE_BOTH ||
|
|
|
|
vport->cfg_enable_fc4_type == LPFC_ENABLE_NVME)
|
2018-12-14 06:17:56 +07:00
|
|
|
CtReq->un.rft.rsvd[0] =
|
|
|
|
cpu_to_be32(LPFC_FC4_TYPE_BITMASK);
|
2017-02-13 04:52:31 +07:00
|
|
|
|
2018-12-14 06:17:56 +07:00
|
|
|
ptr = (uint32_t *)CtReq;
|
|
|
|
lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
|
|
|
|
"6433 Issue RFT (%s %s): %08x %08x %08x %08x "
|
|
|
|
"%08x %08x %08x %08x\n",
|
|
|
|
CtReq->un.rft.fcpReg ? "FCP" : " ",
|
|
|
|
CtReq->un.rft.rsvd[0] ? "NVME" : " ",
|
|
|
|
*ptr, *(ptr + 1), *(ptr + 2), *(ptr + 3),
|
|
|
|
*(ptr + 4), *(ptr + 5),
|
|
|
|
*(ptr + 6), *(ptr + 7));
|
2005-04-18 04:05:31 +07:00
|
|
|
cmpl = lpfc_cmpl_ct_cmd_rft_id;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SLI_CTNS_RNN_ID:
|
2007-10-28 00:37:17 +07:00
|
|
|
vport->ct_flags &= ~FC_CT_RNN_ID;
|
2005-04-18 04:05:31 +07:00
|
|
|
CtReq->CommandResponse.bits.CmdRsp =
|
2015-04-08 02:07:19 +07:00
|
|
|
cpu_to_be16(SLI_CTNS_RNN_ID);
|
2008-01-11 13:52:54 +07:00
|
|
|
CtReq->un.rnn.PortId = cpu_to_be32(vport->fc_myDID);
|
2007-06-18 07:56:36 +07:00
|
|
|
memcpy(CtReq->un.rnn.wwnn, &vport->fc_nodename,
|
2015-12-17 06:11:58 +07:00
|
|
|
sizeof(struct lpfc_name));
|
2005-04-18 04:05:31 +07:00
|
|
|
cmpl = lpfc_cmpl_ct_cmd_rnn_id;
|
|
|
|
break;
|
|
|
|
|
2007-06-18 07:56:38 +07:00
|
|
|
case SLI_CTNS_RSPN_ID:
|
2007-10-28 00:37:17 +07:00
|
|
|
vport->ct_flags &= ~FC_CT_RSPN_ID;
|
2007-06-18 07:56:38 +07:00
|
|
|
CtReq->CommandResponse.bits.CmdRsp =
|
2015-04-08 02:07:19 +07:00
|
|
|
cpu_to_be16(SLI_CTNS_RSPN_ID);
|
2008-01-11 13:52:54 +07:00
|
|
|
CtReq->un.rspn.PortId = cpu_to_be32(vport->fc_myDID);
|
2007-06-18 07:56:38 +07:00
|
|
|
size = sizeof(CtReq->un.rspn.symbname);
|
|
|
|
CtReq->un.rspn.len =
|
|
|
|
lpfc_vport_symbolic_port_name(vport,
|
|
|
|
CtReq->un.rspn.symbname, size);
|
|
|
|
cmpl = lpfc_cmpl_ct_cmd_rspn_id;
|
|
|
|
break;
|
2005-04-18 04:05:31 +07:00
|
|
|
case SLI_CTNS_RSNN_NN:
|
2007-10-28 00:37:17 +07:00
|
|
|
vport->ct_flags &= ~FC_CT_RSNN_NN;
|
2005-04-18 04:05:31 +07:00
|
|
|
CtReq->CommandResponse.bits.CmdRsp =
|
2015-04-08 02:07:19 +07:00
|
|
|
cpu_to_be16(SLI_CTNS_RSNN_NN);
|
2007-06-18 07:56:36 +07:00
|
|
|
memcpy(CtReq->un.rsnn.wwnn, &vport->fc_nodename,
|
2015-12-17 06:11:58 +07:00
|
|
|
sizeof(struct lpfc_name));
|
2007-06-18 07:56:38 +07:00
|
|
|
size = sizeof(CtReq->un.rsnn.symbname);
|
|
|
|
CtReq->un.rsnn.len =
|
|
|
|
lpfc_vport_symbolic_node_name(vport,
|
|
|
|
CtReq->un.rsnn.symbname, size);
|
2005-04-18 04:05:31 +07:00
|
|
|
cmpl = lpfc_cmpl_ct_cmd_rsnn_nn;
|
|
|
|
break;
|
2007-10-28 00:37:17 +07:00
|
|
|
case SLI_CTNS_DA_ID:
|
|
|
|
/* Implement DA_ID Nameserver request */
|
|
|
|
CtReq->CommandResponse.bits.CmdRsp =
|
2015-04-08 02:07:19 +07:00
|
|
|
cpu_to_be16(SLI_CTNS_DA_ID);
|
2008-01-11 13:52:54 +07:00
|
|
|
CtReq->un.da_id.port_id = cpu_to_be32(vport->fc_myDID);
|
2007-10-28 00:37:17 +07:00
|
|
|
cmpl = lpfc_cmpl_ct_cmd_da_id;
|
|
|
|
break;
|
2007-06-18 07:56:38 +07:00
|
|
|
case SLI_CTNS_RFF_ID:
|
2007-10-28 00:37:17 +07:00
|
|
|
vport->ct_flags &= ~FC_CT_RFF_ID;
|
2007-06-18 07:56:38 +07:00
|
|
|
CtReq->CommandResponse.bits.CmdRsp =
|
2015-04-08 02:07:19 +07:00
|
|
|
cpu_to_be16(SLI_CTNS_RFF_ID);
|
2009-08-19 01:18:35 +07:00
|
|
|
CtReq->un.rff.PortId = cpu_to_be32(vport->fc_myDID);
|
2007-06-18 07:56:38 +07:00
|
|
|
CtReq->un.rff.fbits = FC4_FEATURE_INIT;
|
2017-02-13 04:52:31 +07:00
|
|
|
|
|
|
|
/* The driver always supports FC_TYPE_FCP. However, the
|
|
|
|
* caller can specify NVME (type x28) as well. But only
|
|
|
|
* these that FC4 type is supported.
|
|
|
|
*/
|
2019-01-29 02:14:38 +07:00
|
|
|
if (((vport->cfg_enable_fc4_type == LPFC_ENABLE_BOTH) ||
|
|
|
|
(vport->cfg_enable_fc4_type == LPFC_ENABLE_NVME)) &&
|
2017-02-13 04:52:31 +07:00
|
|
|
(context == FC_TYPE_NVME)) {
|
2017-02-13 04:52:36 +07:00
|
|
|
if ((vport == phba->pport) && phba->nvmet_support) {
|
|
|
|
CtReq->un.rff.fbits = (FC4_FEATURE_TARGET |
|
|
|
|
FC4_FEATURE_NVME_DISC);
|
2017-02-13 04:52:37 +07:00
|
|
|
lpfc_nvmet_update_targetport(phba);
|
2017-02-13 04:52:36 +07:00
|
|
|
} else {
|
|
|
|
lpfc_nvme_update_localport(vport);
|
|
|
|
}
|
2017-02-13 04:52:31 +07:00
|
|
|
CtReq->un.rff.type_code = context;
|
|
|
|
|
2019-01-29 02:14:38 +07:00
|
|
|
} else if (((vport->cfg_enable_fc4_type == LPFC_ENABLE_BOTH) ||
|
|
|
|
(vport->cfg_enable_fc4_type == LPFC_ENABLE_FCP)) &&
|
2017-02-13 04:52:31 +07:00
|
|
|
(context == FC_TYPE_FCP))
|
|
|
|
CtReq->un.rff.type_code = context;
|
|
|
|
|
|
|
|
else
|
|
|
|
goto ns_cmd_free_bmpvirt;
|
|
|
|
|
2018-12-14 06:17:56 +07:00
|
|
|
ptr = (uint32_t *)CtReq;
|
|
|
|
lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
|
|
|
|
"6434 Issue RFF (%s): %08x %08x %08x %08x "
|
|
|
|
"%08x %08x %08x %08x\n",
|
|
|
|
(context == FC_TYPE_NVME) ? "NVME" : "FCP",
|
|
|
|
*ptr, *(ptr + 1), *(ptr + 2), *(ptr + 3),
|
|
|
|
*(ptr + 4), *(ptr + 5),
|
|
|
|
*(ptr + 6), *(ptr + 7));
|
2007-06-18 07:56:38 +07:00
|
|
|
cmpl = lpfc_cmpl_ct_cmd_rff_id;
|
|
|
|
break;
|
2005-04-18 04:05:31 +07:00
|
|
|
}
|
2008-02-09 06:49:26 +07:00
|
|
|
/* The lpfc_ct_cmd/lpfc_get_req shall increment ndlp reference count
|
|
|
|
* to hold ndlp reference for the corresponding callback function.
|
|
|
|
*/
|
2007-06-18 07:56:39 +07:00
|
|
|
if (!lpfc_ct_cmd(vport, mp, bmp, ndlp, cmpl, rsp_size, retry)) {
|
2005-04-18 04:05:31 +07:00
|
|
|
/* On success, The cmpl function will free the buffers */
|
2007-06-18 07:56:39 +07:00
|
|
|
lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_CT,
|
|
|
|
"Issue CT cmd: cmd:x%x did:x%x",
|
|
|
|
cmdcode, ndlp->nlp_DID, 0);
|
2005-04-18 04:05:31 +07:00
|
|
|
return 0;
|
2007-06-18 07:56:39 +07:00
|
|
|
}
|
|
|
|
rc=6;
|
2008-02-09 06:49:26 +07:00
|
|
|
|
|
|
|
/* Decrement ndlp reference count to release ndlp reference held
|
|
|
|
* for the failed command's callback function.
|
|
|
|
*/
|
2007-08-02 22:10:31 +07:00
|
|
|
lpfc_nlp_put(ndlp);
|
2008-02-09 06:49:26 +07:00
|
|
|
|
2017-02-13 04:52:31 +07:00
|
|
|
ns_cmd_free_bmpvirt:
|
2005-04-18 04:05:31 +07:00
|
|
|
lpfc_mbuf_free(phba, bmp->virt, bmp->phys);
|
|
|
|
ns_cmd_free_bmp:
|
|
|
|
kfree(bmp);
|
|
|
|
ns_cmd_free_mpvirt:
|
|
|
|
lpfc_mbuf_free(phba, mp->virt, mp->phys);
|
|
|
|
ns_cmd_free_mp:
|
|
|
|
kfree(mp);
|
|
|
|
ns_cmd_exit:
|
2007-08-02 22:10:09 +07:00
|
|
|
lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY,
|
|
|
|
"0266 Issue NameServer Req x%x err %d Data: x%x x%x\n",
|
|
|
|
cmdcode, rc, vport->fc_flag, vport->fc_rscn_id_cnt);
|
2005-04-18 04:05:31 +07:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2015-12-17 06:11:58 +07:00
|
|
|
/**
|
|
|
|
* lpfc_cmpl_ct_disc_fdmi - Handle a discovery FDMI completion
|
|
|
|
* @phba: Pointer to HBA context object.
|
|
|
|
* @cmdiocb: Pointer to the command IOCBQ.
|
|
|
|
* @rspiocb: Pointer to the response IOCBQ.
|
|
|
|
*
|
|
|
|
* This function to handle the completion of a driver initiated FDMI
|
|
|
|
* CT command issued during discovery.
|
|
|
|
*/
|
2005-04-18 04:05:31 +07:00
|
|
|
static void
|
2015-12-17 06:11:58 +07:00
|
|
|
lpfc_cmpl_ct_disc_fdmi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
|
|
|
|
struct lpfc_iocbq *rspiocb)
|
2005-04-18 04:05:31 +07:00
|
|
|
{
|
2015-12-17 06:11:58 +07:00
|
|
|
struct lpfc_vport *vport = cmdiocb->vport;
|
2005-04-18 04:05:31 +07:00
|
|
|
struct lpfc_dmabuf *inp = cmdiocb->context1;
|
|
|
|
struct lpfc_dmabuf *outp = cmdiocb->context2;
|
|
|
|
struct lpfc_sli_ct_request *CTcmd = inp->virt;
|
2015-12-17 06:11:58 +07:00
|
|
|
struct lpfc_sli_ct_request *CTrsp = outp->virt;
|
2005-04-18 04:05:31 +07:00
|
|
|
uint16_t fdmi_cmd = CTcmd->CommandResponse.bits.CmdRsp;
|
|
|
|
uint16_t fdmi_rsp = CTrsp->CommandResponse.bits.CmdRsp;
|
2007-06-18 07:56:39 +07:00
|
|
|
IOCB_t *irsp = &rspiocb->iocb;
|
2015-12-17 06:11:58 +07:00
|
|
|
struct lpfc_nodelist *ndlp;
|
|
|
|
uint32_t latt, cmd, err;
|
2007-06-18 07:56:39 +07:00
|
|
|
|
|
|
|
latt = lpfc_els_chk_latt(vport);
|
|
|
|
lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_CT,
|
|
|
|
"FDMI cmpl: status:x%x/x%x latt:%d",
|
|
|
|
irsp->ulpStatus, irsp->un.ulpWord[4], latt);
|
|
|
|
|
|
|
|
if (latt || irsp->ulpStatus) {
|
2015-12-17 06:11:58 +07:00
|
|
|
|
|
|
|
/* Look for a retryable error */
|
|
|
|
if (irsp->ulpStatus == IOSTAT_LOCAL_REJECT) {
|
|
|
|
switch ((irsp->un.ulpWord[4] & IOERR_PARAM_MASK)) {
|
|
|
|
case IOERR_SLI_ABORTED:
|
2019-09-22 10:58:59 +07:00
|
|
|
case IOERR_SLI_DOWN:
|
|
|
|
/* Driver aborted this IO. No retry as error
|
|
|
|
* is likely Offline->Online or some adapter
|
|
|
|
* error. Recovery will try again.
|
|
|
|
*/
|
|
|
|
break;
|
2015-12-17 06:11:58 +07:00
|
|
|
case IOERR_ABORT_IN_PROGRESS:
|
|
|
|
case IOERR_SEQUENCE_TIMEOUT:
|
|
|
|
case IOERR_ILLEGAL_FRAME:
|
|
|
|
case IOERR_NO_RESOURCES:
|
|
|
|
case IOERR_ILLEGAL_COMMAND:
|
|
|
|
cmdiocb->retry++;
|
|
|
|
if (cmdiocb->retry >= LPFC_FDMI_MAX_RETRY)
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* Retry the same FDMI command */
|
|
|
|
err = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING,
|
|
|
|
cmdiocb, 0);
|
|
|
|
if (err == IOCB_ERROR)
|
|
|
|
break;
|
|
|
|
return;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-08-02 22:10:09 +07:00
|
|
|
lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
|
|
|
|
"0229 FDMI cmd %04x failed, latt = %d "
|
|
|
|
"ulpStatus: x%x, rid x%x\n",
|
|
|
|
be16_to_cpu(fdmi_cmd), latt, irsp->ulpStatus,
|
|
|
|
irsp->un.ulpWord[4]);
|
2007-06-18 07:56:39 +07:00
|
|
|
}
|
2015-12-17 06:11:58 +07:00
|
|
|
lpfc_ct_free_iocb(phba, cmdiocb);
|
2005-04-18 04:05:31 +07:00
|
|
|
|
2007-06-18 07:56:36 +07:00
|
|
|
ndlp = lpfc_findnode_did(vport, FDMI_DID);
|
2008-02-09 06:49:26 +07:00
|
|
|
if (!ndlp || !NLP_CHK_NODE_ACT(ndlp))
|
2015-12-17 06:11:58 +07:00
|
|
|
return;
|
2008-02-09 06:49:26 +07:00
|
|
|
|
2015-12-17 06:11:58 +07:00
|
|
|
/* Check for a CT LS_RJT response */
|
|
|
|
cmd = be16_to_cpu(fdmi_cmd);
|
2015-04-08 02:07:19 +07:00
|
|
|
if (fdmi_rsp == cpu_to_be16(SLI_CT_RESPONSE_FS_RJT)) {
|
2005-04-18 04:05:31 +07:00
|
|
|
/* FDMI rsp failed */
|
2007-08-02 22:10:09 +07:00
|
|
|
lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
|
2015-12-17 06:11:58 +07:00
|
|
|
"0220 FDMI cmd failed FS_RJT Data: x%x", cmd);
|
|
|
|
|
|
|
|
/* Should we fallback to FDMI-2 / FDMI-1 ? */
|
|
|
|
switch (cmd) {
|
|
|
|
case SLI_MGMT_RHBA:
|
|
|
|
if (vport->fdmi_hba_mask == LPFC_FDMI2_HBA_ATTR) {
|
|
|
|
/* Fallback to FDMI-1 */
|
|
|
|
vport->fdmi_hba_mask = LPFC_FDMI1_HBA_ATTR;
|
|
|
|
vport->fdmi_port_mask = LPFC_FDMI1_PORT_ATTR;
|
|
|
|
/* Start over */
|
|
|
|
lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_DHBA, 0);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
|
|
|
|
case SLI_MGMT_RPRT:
|
|
|
|
if (vport->fdmi_port_mask == LPFC_FDMI2_PORT_ATTR) {
|
|
|
|
/* Fallback to FDMI-1 */
|
|
|
|
vport->fdmi_port_mask = LPFC_FDMI1_PORT_ATTR;
|
|
|
|
/* Start over */
|
|
|
|
lpfc_fdmi_cmd(vport, ndlp, cmd, 0);
|
|
|
|
}
|
|
|
|
if (vport->fdmi_port_mask == LPFC_FDMI2_SMART_ATTR) {
|
|
|
|
vport->fdmi_port_mask = LPFC_FDMI2_PORT_ATTR;
|
|
|
|
/* Retry the same command */
|
|
|
|
lpfc_fdmi_cmd(vport, ndlp, cmd, 0);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
|
|
|
|
case SLI_MGMT_RPA:
|
|
|
|
if (vport->fdmi_port_mask == LPFC_FDMI2_PORT_ATTR) {
|
|
|
|
/* Fallback to FDMI-1 */
|
|
|
|
vport->fdmi_hba_mask = LPFC_FDMI1_HBA_ATTR;
|
|
|
|
vport->fdmi_port_mask = LPFC_FDMI1_PORT_ATTR;
|
|
|
|
/* Start over */
|
|
|
|
lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_DHBA, 0);
|
|
|
|
}
|
|
|
|
if (vport->fdmi_port_mask == LPFC_FDMI2_SMART_ATTR) {
|
|
|
|
vport->fdmi_port_mask = LPFC_FDMI2_PORT_ATTR;
|
|
|
|
/* Retry the same command */
|
|
|
|
lpfc_fdmi_cmd(vport, ndlp, cmd, 0);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
2005-04-18 04:05:31 +07:00
|
|
|
}
|
|
|
|
|
2015-12-17 06:11:58 +07:00
|
|
|
/*
|
|
|
|
* On success, need to cycle thru FDMI registration for discovery
|
|
|
|
* DHBA -> DPRT -> RHBA -> RPA (physical port)
|
|
|
|
* DPRT -> RPRT (vports)
|
|
|
|
*/
|
|
|
|
switch (cmd) {
|
|
|
|
case SLI_MGMT_RHBA:
|
|
|
|
lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_RPA, 0);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SLI_MGMT_DHBA:
|
|
|
|
lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_DPRT, 0);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SLI_MGMT_DPRT:
|
|
|
|
if (vport->port_type == LPFC_PHYSICAL_PORT)
|
|
|
|
lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_RHBA, 0);
|
|
|
|
else
|
|
|
|
lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_RPRT, 0);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return;
|
2015-04-08 02:07:19 +07:00
|
|
|
}
|
|
|
|
|
2015-12-17 06:11:58 +07:00
|
|
|
|
|
|
|
/**
|
|
|
|
* lpfc_fdmi_num_disc_check - Check how many mapped NPorts we are connected to
|
|
|
|
* @vport: pointer to a host virtual N_Port data structure.
|
|
|
|
*
|
|
|
|
* Called from hbeat timeout routine to check if the number of discovered
|
|
|
|
* ports has changed. If so, re-register thar port Attribute.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
lpfc_fdmi_num_disc_check(struct lpfc_vport *vport)
|
2015-04-08 02:07:19 +07:00
|
|
|
{
|
2015-12-17 06:11:58 +07:00
|
|
|
struct lpfc_hba *phba = vport->phba;
|
2015-04-08 02:07:19 +07:00
|
|
|
struct lpfc_nodelist *ndlp;
|
2015-12-17 06:11:58 +07:00
|
|
|
uint16_t cnt;
|
2015-04-08 02:07:19 +07:00
|
|
|
|
2015-12-17 06:11:58 +07:00
|
|
|
if (!lpfc_is_link_up(phba))
|
|
|
|
return;
|
|
|
|
|
2016-07-07 02:36:12 +07:00
|
|
|
/* Must be connected to a Fabric */
|
|
|
|
if (!(vport->fc_flag & FC_FABRIC))
|
|
|
|
return;
|
|
|
|
|
2015-12-17 06:11:58 +07:00
|
|
|
if (!(vport->fdmi_port_mask & LPFC_FDMI_PORT_ATTR_num_disc))
|
|
|
|
return;
|
|
|
|
|
|
|
|
cnt = lpfc_find_map_node(vport);
|
|
|
|
if (cnt == vport->fdmi_num_disc)
|
|
|
|
return;
|
2015-04-08 02:07:19 +07:00
|
|
|
|
|
|
|
ndlp = lpfc_findnode_did(vport, FDMI_DID);
|
|
|
|
if (!ndlp || !NLP_CHK_NODE_ACT(ndlp))
|
|
|
|
return;
|
|
|
|
|
2015-12-17 06:11:58 +07:00
|
|
|
if (vport->port_type == LPFC_PHYSICAL_PORT) {
|
|
|
|
lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_RPA,
|
|
|
|
LPFC_FDMI_PORT_ATTR_num_disc);
|
|
|
|
} else {
|
|
|
|
lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_RPRT,
|
|
|
|
LPFC_FDMI_PORT_ATTR_num_disc);
|
|
|
|
}
|
|
|
|
}
|
2005-04-18 04:05:31 +07:00
|
|
|
|
2015-12-17 06:11:58 +07:00
|
|
|
/* Routines for all individual HBA attributes */
|
2016-09-25 12:44:55 +07:00
|
|
|
static int
|
2015-12-17 06:11:58 +07:00
|
|
|
lpfc_fdmi_hba_attr_wwnn(struct lpfc_vport *vport, struct lpfc_fdmi_attr_def *ad)
|
|
|
|
{
|
|
|
|
struct lpfc_fdmi_attr_entry *ae;
|
|
|
|
uint32_t size;
|
2005-04-18 04:05:31 +07:00
|
|
|
|
2015-12-17 06:11:58 +07:00
|
|
|
ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
|
|
|
|
memset(ae, 0, sizeof(struct lpfc_name));
|
|
|
|
|
|
|
|
memcpy(&ae->un.AttrWWN, &vport->fc_sparam.nodeName,
|
|
|
|
sizeof(struct lpfc_name));
|
|
|
|
size = FOURBYTES + sizeof(struct lpfc_name);
|
|
|
|
ad->AttrLen = cpu_to_be16(size);
|
|
|
|
ad->AttrType = cpu_to_be16(RHBA_NODENAME);
|
|
|
|
return size;
|
|
|
|
}
|
2016-09-25 12:44:55 +07:00
|
|
|
static int
|
2015-12-17 06:11:58 +07:00
|
|
|
lpfc_fdmi_hba_attr_manufacturer(struct lpfc_vport *vport,
|
|
|
|
struct lpfc_fdmi_attr_def *ad)
|
|
|
|
{
|
|
|
|
struct lpfc_fdmi_attr_entry *ae;
|
|
|
|
uint32_t len, size;
|
|
|
|
|
|
|
|
ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
|
|
|
|
memset(ae, 0, 256);
|
|
|
|
|
2019-03-13 06:30:20 +07:00
|
|
|
/* This string MUST be consistent with other FC platforms
|
|
|
|
* supported by Broadcom.
|
|
|
|
*/
|
2015-12-17 06:11:58 +07:00
|
|
|
strncpy(ae->un.AttrString,
|
2019-03-13 06:30:20 +07:00
|
|
|
"Emulex Corporation",
|
2015-12-17 06:11:58 +07:00
|
|
|
sizeof(ae->un.AttrString));
|
|
|
|
len = strnlen(ae->un.AttrString,
|
|
|
|
sizeof(ae->un.AttrString));
|
|
|
|
len += (len & 3) ? (4 - (len & 3)) : 4;
|
|
|
|
size = FOURBYTES + len;
|
|
|
|
ad->AttrLen = cpu_to_be16(size);
|
|
|
|
ad->AttrType = cpu_to_be16(RHBA_MANUFACTURER);
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
2016-09-25 12:44:55 +07:00
|
|
|
static int
|
2015-12-17 06:11:58 +07:00
|
|
|
lpfc_fdmi_hba_attr_sn(struct lpfc_vport *vport, struct lpfc_fdmi_attr_def *ad)
|
|
|
|
{
|
|
|
|
struct lpfc_hba *phba = vport->phba;
|
|
|
|
struct lpfc_fdmi_attr_entry *ae;
|
|
|
|
uint32_t len, size;
|
|
|
|
|
|
|
|
ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
|
|
|
|
memset(ae, 0, 256);
|
|
|
|
|
|
|
|
strncpy(ae->un.AttrString, phba->SerialNumber,
|
|
|
|
sizeof(ae->un.AttrString));
|
|
|
|
len = strnlen(ae->un.AttrString,
|
|
|
|
sizeof(ae->un.AttrString));
|
|
|
|
len += (len & 3) ? (4 - (len & 3)) : 4;
|
|
|
|
size = FOURBYTES + len;
|
|
|
|
ad->AttrLen = cpu_to_be16(size);
|
|
|
|
ad->AttrType = cpu_to_be16(RHBA_SERIAL_NUMBER);
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
2016-09-25 12:44:55 +07:00
|
|
|
static int
|
2015-12-17 06:11:58 +07:00
|
|
|
lpfc_fdmi_hba_attr_model(struct lpfc_vport *vport,
|
|
|
|
struct lpfc_fdmi_attr_def *ad)
|
|
|
|
{
|
|
|
|
struct lpfc_hba *phba = vport->phba;
|
|
|
|
struct lpfc_fdmi_attr_entry *ae;
|
|
|
|
uint32_t len, size;
|
|
|
|
|
|
|
|
ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
|
|
|
|
memset(ae, 0, 256);
|
|
|
|
|
|
|
|
strncpy(ae->un.AttrString, phba->ModelName,
|
|
|
|
sizeof(ae->un.AttrString));
|
|
|
|
len = strnlen(ae->un.AttrString, sizeof(ae->un.AttrString));
|
|
|
|
len += (len & 3) ? (4 - (len & 3)) : 4;
|
|
|
|
size = FOURBYTES + len;
|
|
|
|
ad->AttrLen = cpu_to_be16(size);
|
|
|
|
ad->AttrType = cpu_to_be16(RHBA_MODEL);
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
2016-09-25 12:44:55 +07:00
|
|
|
static int
|
2015-12-17 06:11:58 +07:00
|
|
|
lpfc_fdmi_hba_attr_description(struct lpfc_vport *vport,
|
|
|
|
struct lpfc_fdmi_attr_def *ad)
|
|
|
|
{
|
|
|
|
struct lpfc_hba *phba = vport->phba;
|
|
|
|
struct lpfc_fdmi_attr_entry *ae;
|
|
|
|
uint32_t len, size;
|
|
|
|
|
|
|
|
ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
|
|
|
|
memset(ae, 0, 256);
|
|
|
|
|
|
|
|
strncpy(ae->un.AttrString, phba->ModelDesc,
|
|
|
|
sizeof(ae->un.AttrString));
|
|
|
|
len = strnlen(ae->un.AttrString,
|
|
|
|
sizeof(ae->un.AttrString));
|
|
|
|
len += (len & 3) ? (4 - (len & 3)) : 4;
|
|
|
|
size = FOURBYTES + len;
|
|
|
|
ad->AttrLen = cpu_to_be16(size);
|
|
|
|
ad->AttrType = cpu_to_be16(RHBA_MODEL_DESCRIPTION);
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
2016-09-25 12:44:55 +07:00
|
|
|
static int
|
2015-12-17 06:11:58 +07:00
|
|
|
lpfc_fdmi_hba_attr_hdw_ver(struct lpfc_vport *vport,
|
|
|
|
struct lpfc_fdmi_attr_def *ad)
|
|
|
|
{
|
|
|
|
struct lpfc_hba *phba = vport->phba;
|
|
|
|
lpfc_vpd_t *vp = &phba->vpd;
|
|
|
|
struct lpfc_fdmi_attr_entry *ae;
|
|
|
|
uint32_t i, j, incr, size;
|
|
|
|
|
|
|
|
ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
|
|
|
|
memset(ae, 0, 256);
|
|
|
|
|
|
|
|
/* Convert JEDEC ID to ascii for hardware version */
|
|
|
|
incr = vp->rev.biuRev;
|
|
|
|
for (i = 0; i < 8; i++) {
|
|
|
|
j = (incr & 0xf);
|
|
|
|
if (j <= 9)
|
|
|
|
ae->un.AttrString[7 - i] =
|
|
|
|
(char)((uint8_t) 0x30 +
|
|
|
|
(uint8_t) j);
|
|
|
|
else
|
|
|
|
ae->un.AttrString[7 - i] =
|
|
|
|
(char)((uint8_t) 0x61 +
|
|
|
|
(uint8_t) (j - 10));
|
|
|
|
incr = (incr >> 4);
|
|
|
|
}
|
|
|
|
size = FOURBYTES + 8;
|
|
|
|
ad->AttrLen = cpu_to_be16(size);
|
|
|
|
ad->AttrType = cpu_to_be16(RHBA_HARDWARE_VERSION);
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
2016-09-25 12:44:55 +07:00
|
|
|
static int
|
2015-12-17 06:11:58 +07:00
|
|
|
lpfc_fdmi_hba_attr_drvr_ver(struct lpfc_vport *vport,
|
|
|
|
struct lpfc_fdmi_attr_def *ad)
|
|
|
|
{
|
|
|
|
struct lpfc_fdmi_attr_entry *ae;
|
|
|
|
uint32_t len, size;
|
|
|
|
|
|
|
|
ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
|
|
|
|
memset(ae, 0, 256);
|
|
|
|
|
|
|
|
strncpy(ae->un.AttrString, lpfc_release_version,
|
|
|
|
sizeof(ae->un.AttrString));
|
|
|
|
len = strnlen(ae->un.AttrString,
|
|
|
|
sizeof(ae->un.AttrString));
|
|
|
|
len += (len & 3) ? (4 - (len & 3)) : 4;
|
|
|
|
size = FOURBYTES + len;
|
|
|
|
ad->AttrLen = cpu_to_be16(size);
|
|
|
|
ad->AttrType = cpu_to_be16(RHBA_DRIVER_VERSION);
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
2016-09-25 12:44:55 +07:00
|
|
|
static int
|
2015-12-17 06:11:58 +07:00
|
|
|
lpfc_fdmi_hba_attr_rom_ver(struct lpfc_vport *vport,
|
|
|
|
struct lpfc_fdmi_attr_def *ad)
|
|
|
|
{
|
|
|
|
struct lpfc_hba *phba = vport->phba;
|
|
|
|
struct lpfc_fdmi_attr_entry *ae;
|
|
|
|
uint32_t len, size;
|
|
|
|
|
|
|
|
ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
|
|
|
|
memset(ae, 0, 256);
|
|
|
|
|
|
|
|
if (phba->sli_rev == LPFC_SLI_REV4)
|
|
|
|
lpfc_decode_firmware_rev(phba, ae->un.AttrString, 1);
|
|
|
|
else
|
|
|
|
strncpy(ae->un.AttrString, phba->OptionROMVersion,
|
|
|
|
sizeof(ae->un.AttrString));
|
|
|
|
len = strnlen(ae->un.AttrString,
|
|
|
|
sizeof(ae->un.AttrString));
|
|
|
|
len += (len & 3) ? (4 - (len & 3)) : 4;
|
|
|
|
size = FOURBYTES + len;
|
|
|
|
ad->AttrLen = cpu_to_be16(size);
|
|
|
|
ad->AttrType = cpu_to_be16(RHBA_OPTION_ROM_VERSION);
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
2016-09-25 12:44:55 +07:00
|
|
|
static int
|
2015-12-17 06:11:58 +07:00
|
|
|
lpfc_fdmi_hba_attr_fmw_ver(struct lpfc_vport *vport,
|
|
|
|
struct lpfc_fdmi_attr_def *ad)
|
|
|
|
{
|
|
|
|
struct lpfc_hba *phba = vport->phba;
|
|
|
|
struct lpfc_fdmi_attr_entry *ae;
|
|
|
|
uint32_t len, size;
|
|
|
|
|
|
|
|
ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
|
|
|
|
memset(ae, 0, 256);
|
|
|
|
|
|
|
|
lpfc_decode_firmware_rev(phba, ae->un.AttrString, 1);
|
|
|
|
len = strnlen(ae->un.AttrString,
|
|
|
|
sizeof(ae->un.AttrString));
|
|
|
|
len += (len & 3) ? (4 - (len & 3)) : 4;
|
|
|
|
size = FOURBYTES + len;
|
|
|
|
ad->AttrLen = cpu_to_be16(size);
|
|
|
|
ad->AttrType = cpu_to_be16(RHBA_FIRMWARE_VERSION);
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
2016-09-25 12:44:55 +07:00
|
|
|
static int
|
2015-12-17 06:11:58 +07:00
|
|
|
lpfc_fdmi_hba_attr_os_ver(struct lpfc_vport *vport,
|
|
|
|
struct lpfc_fdmi_attr_def *ad)
|
|
|
|
{
|
|
|
|
struct lpfc_fdmi_attr_entry *ae;
|
|
|
|
uint32_t len, size;
|
|
|
|
|
|
|
|
ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
|
|
|
|
memset(ae, 0, 256);
|
|
|
|
|
|
|
|
snprintf(ae->un.AttrString, sizeof(ae->un.AttrString), "%s %s %s",
|
|
|
|
init_utsname()->sysname,
|
|
|
|
init_utsname()->release,
|
|
|
|
init_utsname()->version);
|
|
|
|
|
|
|
|
len = strnlen(ae->un.AttrString, sizeof(ae->un.AttrString));
|
|
|
|
len += (len & 3) ? (4 - (len & 3)) : 4;
|
|
|
|
size = FOURBYTES + len;
|
|
|
|
ad->AttrLen = cpu_to_be16(size);
|
|
|
|
ad->AttrType = cpu_to_be16(RHBA_OS_NAME_VERSION);
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
2016-09-25 12:44:55 +07:00
|
|
|
static int
|
2015-12-17 06:11:58 +07:00
|
|
|
lpfc_fdmi_hba_attr_ct_len(struct lpfc_vport *vport,
|
|
|
|
struct lpfc_fdmi_attr_def *ad)
|
|
|
|
{
|
|
|
|
struct lpfc_fdmi_attr_entry *ae;
|
|
|
|
uint32_t size;
|
|
|
|
|
|
|
|
ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
|
|
|
|
|
|
|
|
ae->un.AttrInt = cpu_to_be32(LPFC_MAX_CT_SIZE);
|
|
|
|
size = FOURBYTES + sizeof(uint32_t);
|
|
|
|
ad->AttrLen = cpu_to_be16(size);
|
|
|
|
ad->AttrType = cpu_to_be16(RHBA_MAX_CT_PAYLOAD_LEN);
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
2016-09-25 12:44:55 +07:00
|
|
|
static int
|
2015-12-17 06:11:58 +07:00
|
|
|
lpfc_fdmi_hba_attr_symbolic_name(struct lpfc_vport *vport,
|
|
|
|
struct lpfc_fdmi_attr_def *ad)
|
|
|
|
{
|
|
|
|
struct lpfc_fdmi_attr_entry *ae;
|
|
|
|
uint32_t len, size;
|
|
|
|
|
|
|
|
ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
|
|
|
|
memset(ae, 0, 256);
|
|
|
|
|
|
|
|
len = lpfc_vport_symbolic_node_name(vport,
|
|
|
|
ae->un.AttrString, 256);
|
|
|
|
len += (len & 3) ? (4 - (len & 3)) : 4;
|
|
|
|
size = FOURBYTES + len;
|
|
|
|
ad->AttrLen = cpu_to_be16(size);
|
|
|
|
ad->AttrType = cpu_to_be16(RHBA_SYM_NODENAME);
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
2016-09-25 12:44:55 +07:00
|
|
|
static int
|
2015-12-17 06:11:58 +07:00
|
|
|
lpfc_fdmi_hba_attr_vendor_info(struct lpfc_vport *vport,
|
|
|
|
struct lpfc_fdmi_attr_def *ad)
|
|
|
|
{
|
|
|
|
struct lpfc_fdmi_attr_entry *ae;
|
|
|
|
uint32_t size;
|
|
|
|
|
|
|
|
ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
|
|
|
|
|
|
|
|
/* Nothing is defined for this currently */
|
|
|
|
ae->un.AttrInt = cpu_to_be32(0);
|
|
|
|
size = FOURBYTES + sizeof(uint32_t);
|
|
|
|
ad->AttrLen = cpu_to_be16(size);
|
|
|
|
ad->AttrType = cpu_to_be16(RHBA_VENDOR_INFO);
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
2016-09-25 12:44:55 +07:00
|
|
|
static int
|
2015-12-17 06:11:58 +07:00
|
|
|
lpfc_fdmi_hba_attr_num_ports(struct lpfc_vport *vport,
|
|
|
|
struct lpfc_fdmi_attr_def *ad)
|
|
|
|
{
|
|
|
|
struct lpfc_fdmi_attr_entry *ae;
|
|
|
|
uint32_t size;
|
|
|
|
|
|
|
|
ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
|
|
|
|
|
|
|
|
/* Each driver instance corresponds to a single port */
|
|
|
|
ae->un.AttrInt = cpu_to_be32(1);
|
|
|
|
size = FOURBYTES + sizeof(uint32_t);
|
|
|
|
ad->AttrLen = cpu_to_be16(size);
|
|
|
|
ad->AttrType = cpu_to_be16(RHBA_NUM_PORTS);
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
2016-09-25 12:44:55 +07:00
|
|
|
static int
|
2015-12-17 06:11:58 +07:00
|
|
|
lpfc_fdmi_hba_attr_fabric_wwnn(struct lpfc_vport *vport,
|
|
|
|
struct lpfc_fdmi_attr_def *ad)
|
|
|
|
{
|
|
|
|
struct lpfc_fdmi_attr_entry *ae;
|
|
|
|
uint32_t size;
|
|
|
|
|
|
|
|
ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
|
|
|
|
memset(ae, 0, sizeof(struct lpfc_name));
|
|
|
|
|
|
|
|
memcpy(&ae->un.AttrWWN, &vport->fabric_nodename,
|
|
|
|
sizeof(struct lpfc_name));
|
|
|
|
size = FOURBYTES + sizeof(struct lpfc_name);
|
|
|
|
ad->AttrLen = cpu_to_be16(size);
|
|
|
|
ad->AttrType = cpu_to_be16(RHBA_FABRIC_WWNN);
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
2016-09-25 12:44:55 +07:00
|
|
|
static int
|
2015-12-17 06:11:58 +07:00
|
|
|
lpfc_fdmi_hba_attr_bios_ver(struct lpfc_vport *vport,
|
|
|
|
struct lpfc_fdmi_attr_def *ad)
|
|
|
|
{
|
|
|
|
struct lpfc_hba *phba = vport->phba;
|
|
|
|
struct lpfc_fdmi_attr_entry *ae;
|
|
|
|
uint32_t len, size;
|
|
|
|
|
|
|
|
ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
|
|
|
|
memset(ae, 0, 256);
|
|
|
|
|
2019-03-13 06:30:23 +07:00
|
|
|
strlcat(ae->un.AttrString, phba->BIOSVersion,
|
|
|
|
sizeof(ae->un.AttrString));
|
2015-12-17 06:11:58 +07:00
|
|
|
len = strnlen(ae->un.AttrString,
|
|
|
|
sizeof(ae->un.AttrString));
|
|
|
|
len += (len & 3) ? (4 - (len & 3)) : 4;
|
|
|
|
size = FOURBYTES + len;
|
|
|
|
ad->AttrLen = cpu_to_be16(size);
|
|
|
|
ad->AttrType = cpu_to_be16(RHBA_BIOS_VERSION);
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
2016-09-25 12:44:55 +07:00
|
|
|
static int
|
2015-12-17 06:11:58 +07:00
|
|
|
lpfc_fdmi_hba_attr_bios_state(struct lpfc_vport *vport,
|
|
|
|
struct lpfc_fdmi_attr_def *ad)
|
|
|
|
{
|
|
|
|
struct lpfc_fdmi_attr_entry *ae;
|
|
|
|
uint32_t size;
|
|
|
|
|
|
|
|
ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
|
|
|
|
|
|
|
|
/* Driver doesn't have access to this information */
|
|
|
|
ae->un.AttrInt = cpu_to_be32(0);
|
|
|
|
size = FOURBYTES + sizeof(uint32_t);
|
|
|
|
ad->AttrLen = cpu_to_be16(size);
|
|
|
|
ad->AttrType = cpu_to_be16(RHBA_BIOS_STATE);
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
2016-09-25 12:44:55 +07:00
|
|
|
static int
|
2015-12-17 06:11:58 +07:00
|
|
|
lpfc_fdmi_hba_attr_vendor_id(struct lpfc_vport *vport,
|
|
|
|
struct lpfc_fdmi_attr_def *ad)
|
|
|
|
{
|
|
|
|
struct lpfc_fdmi_attr_entry *ae;
|
|
|
|
uint32_t len, size;
|
|
|
|
|
|
|
|
ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
|
|
|
|
memset(ae, 0, 256);
|
|
|
|
|
|
|
|
strncpy(ae->un.AttrString, "EMULEX",
|
|
|
|
sizeof(ae->un.AttrString));
|
|
|
|
len = strnlen(ae->un.AttrString,
|
|
|
|
sizeof(ae->un.AttrString));
|
|
|
|
len += (len & 3) ? (4 - (len & 3)) : 4;
|
|
|
|
size = FOURBYTES + len;
|
|
|
|
ad->AttrLen = cpu_to_be16(size);
|
|
|
|
ad->AttrType = cpu_to_be16(RHBA_VENDOR_ID);
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Routines for all individual PORT attributes */
|
2016-09-25 12:44:55 +07:00
|
|
|
static int
|
2015-12-17 06:11:58 +07:00
|
|
|
lpfc_fdmi_port_attr_fc4type(struct lpfc_vport *vport,
|
|
|
|
struct lpfc_fdmi_attr_def *ad)
|
|
|
|
{
|
2019-05-22 07:49:08 +07:00
|
|
|
struct lpfc_hba *phba = vport->phba;
|
2015-12-17 06:11:58 +07:00
|
|
|
struct lpfc_fdmi_attr_entry *ae;
|
|
|
|
uint32_t size;
|
|
|
|
|
|
|
|
ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
|
|
|
|
memset(ae, 0, 32);
|
|
|
|
|
2019-03-13 06:30:21 +07:00
|
|
|
ae->un.AttrTypes[3] = 0x02; /* Type 0x1 - ELS */
|
|
|
|
ae->un.AttrTypes[2] = 0x01; /* Type 0x8 - FCP */
|
|
|
|
ae->un.AttrTypes[7] = 0x01; /* Type 0x20 - CT */
|
2019-05-22 07:49:08 +07:00
|
|
|
|
|
|
|
/* Check to see if Firmware supports NVME and on physical port */
|
|
|
|
if ((phba->sli_rev == LPFC_SLI_REV4) && (vport == phba->pport) &&
|
|
|
|
phba->sli4_hba.pc_sli4_params.nvme)
|
|
|
|
ae->un.AttrTypes[6] = 0x01; /* Type 0x28 - NVME */
|
|
|
|
|
2015-12-17 06:11:58 +07:00
|
|
|
size = FOURBYTES + 32;
|
|
|
|
ad->AttrLen = cpu_to_be16(size);
|
|
|
|
ad->AttrType = cpu_to_be16(RPRT_SUPPORTED_FC4_TYPES);
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
2016-09-25 12:44:55 +07:00
|
|
|
static int
|
2015-12-17 06:11:58 +07:00
|
|
|
lpfc_fdmi_port_attr_support_speed(struct lpfc_vport *vport,
|
|
|
|
struct lpfc_fdmi_attr_def *ad)
|
|
|
|
{
|
|
|
|
struct lpfc_hba *phba = vport->phba;
|
|
|
|
struct lpfc_fdmi_attr_entry *ae;
|
|
|
|
uint32_t size;
|
|
|
|
|
|
|
|
ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
|
|
|
|
|
|
|
|
ae->un.AttrInt = 0;
|
2015-12-17 06:12:02 +07:00
|
|
|
if (!(phba->hba_flag & HBA_FCOE_MODE)) {
|
2018-10-24 03:41:11 +07:00
|
|
|
if (phba->lmt & LMT_128Gb)
|
|
|
|
ae->un.AttrInt |= HBA_PORTSPEED_128GFC;
|
2018-02-22 23:18:45 +07:00
|
|
|
if (phba->lmt & LMT_64Gb)
|
|
|
|
ae->un.AttrInt |= HBA_PORTSPEED_64GFC;
|
2015-12-17 06:12:02 +07:00
|
|
|
if (phba->lmt & LMT_32Gb)
|
|
|
|
ae->un.AttrInt |= HBA_PORTSPEED_32GFC;
|
|
|
|
if (phba->lmt & LMT_16Gb)
|
|
|
|
ae->un.AttrInt |= HBA_PORTSPEED_16GFC;
|
|
|
|
if (phba->lmt & LMT_10Gb)
|
|
|
|
ae->un.AttrInt |= HBA_PORTSPEED_10GFC;
|
|
|
|
if (phba->lmt & LMT_8Gb)
|
|
|
|
ae->un.AttrInt |= HBA_PORTSPEED_8GFC;
|
|
|
|
if (phba->lmt & LMT_4Gb)
|
|
|
|
ae->un.AttrInt |= HBA_PORTSPEED_4GFC;
|
|
|
|
if (phba->lmt & LMT_2Gb)
|
|
|
|
ae->un.AttrInt |= HBA_PORTSPEED_2GFC;
|
|
|
|
if (phba->lmt & LMT_1Gb)
|
|
|
|
ae->un.AttrInt |= HBA_PORTSPEED_1GFC;
|
|
|
|
} else {
|
|
|
|
/* FCoE links support only one speed */
|
|
|
|
switch (phba->fc_linkspeed) {
|
|
|
|
case LPFC_ASYNC_LINK_SPEED_10GBPS:
|
|
|
|
ae->un.AttrInt = HBA_PORTSPEED_10GE;
|
|
|
|
break;
|
|
|
|
case LPFC_ASYNC_LINK_SPEED_25GBPS:
|
|
|
|
ae->un.AttrInt = HBA_PORTSPEED_25GE;
|
|
|
|
break;
|
|
|
|
case LPFC_ASYNC_LINK_SPEED_40GBPS:
|
|
|
|
ae->un.AttrInt = HBA_PORTSPEED_40GE;
|
|
|
|
break;
|
|
|
|
case LPFC_ASYNC_LINK_SPEED_100GBPS:
|
|
|
|
ae->un.AttrInt = HBA_PORTSPEED_100GE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2015-12-17 06:11:58 +07:00
|
|
|
ae->un.AttrInt = cpu_to_be32(ae->un.AttrInt);
|
|
|
|
size = FOURBYTES + sizeof(uint32_t);
|
|
|
|
ad->AttrLen = cpu_to_be16(size);
|
|
|
|
ad->AttrType = cpu_to_be16(RPRT_SUPPORTED_SPEED);
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
2016-09-25 12:44:55 +07:00
|
|
|
static int
|
2015-12-17 06:11:58 +07:00
|
|
|
lpfc_fdmi_port_attr_speed(struct lpfc_vport *vport,
|
|
|
|
struct lpfc_fdmi_attr_def *ad)
|
|
|
|
{
|
|
|
|
struct lpfc_hba *phba = vport->phba;
|
|
|
|
struct lpfc_fdmi_attr_entry *ae;
|
|
|
|
uint32_t size;
|
|
|
|
|
|
|
|
ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
|
|
|
|
|
2015-12-17 06:12:02 +07:00
|
|
|
if (!(phba->hba_flag & HBA_FCOE_MODE)) {
|
|
|
|
switch (phba->fc_linkspeed) {
|
|
|
|
case LPFC_LINK_SPEED_1GHZ:
|
|
|
|
ae->un.AttrInt = HBA_PORTSPEED_1GFC;
|
|
|
|
break;
|
|
|
|
case LPFC_LINK_SPEED_2GHZ:
|
|
|
|
ae->un.AttrInt = HBA_PORTSPEED_2GFC;
|
|
|
|
break;
|
|
|
|
case LPFC_LINK_SPEED_4GHZ:
|
|
|
|
ae->un.AttrInt = HBA_PORTSPEED_4GFC;
|
|
|
|
break;
|
|
|
|
case LPFC_LINK_SPEED_8GHZ:
|
|
|
|
ae->un.AttrInt = HBA_PORTSPEED_8GFC;
|
|
|
|
break;
|
|
|
|
case LPFC_LINK_SPEED_10GHZ:
|
|
|
|
ae->un.AttrInt = HBA_PORTSPEED_10GFC;
|
|
|
|
break;
|
|
|
|
case LPFC_LINK_SPEED_16GHZ:
|
|
|
|
ae->un.AttrInt = HBA_PORTSPEED_16GFC;
|
|
|
|
break;
|
|
|
|
case LPFC_LINK_SPEED_32GHZ:
|
|
|
|
ae->un.AttrInt = HBA_PORTSPEED_32GFC;
|
|
|
|
break;
|
2018-02-22 23:18:45 +07:00
|
|
|
case LPFC_LINK_SPEED_64GHZ:
|
|
|
|
ae->un.AttrInt = HBA_PORTSPEED_64GFC;
|
|
|
|
break;
|
2018-10-24 03:41:11 +07:00
|
|
|
case LPFC_LINK_SPEED_128GHZ:
|
|
|
|
ae->un.AttrInt = HBA_PORTSPEED_128GFC;
|
|
|
|
break;
|
2015-12-17 06:12:02 +07:00
|
|
|
default:
|
|
|
|
ae->un.AttrInt = HBA_PORTSPEED_UNKNOWN;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
switch (phba->fc_linkspeed) {
|
|
|
|
case LPFC_ASYNC_LINK_SPEED_10GBPS:
|
|
|
|
ae->un.AttrInt = HBA_PORTSPEED_10GE;
|
|
|
|
break;
|
|
|
|
case LPFC_ASYNC_LINK_SPEED_25GBPS:
|
|
|
|
ae->un.AttrInt = HBA_PORTSPEED_25GE;
|
|
|
|
break;
|
|
|
|
case LPFC_ASYNC_LINK_SPEED_40GBPS:
|
|
|
|
ae->un.AttrInt = HBA_PORTSPEED_40GE;
|
|
|
|
break;
|
|
|
|
case LPFC_ASYNC_LINK_SPEED_100GBPS:
|
|
|
|
ae->un.AttrInt = HBA_PORTSPEED_100GE;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
ae->un.AttrInt = HBA_PORTSPEED_UNKNOWN;
|
|
|
|
break;
|
|
|
|
}
|
2005-04-18 04:05:31 +07:00
|
|
|
}
|
2015-12-17 06:12:02 +07:00
|
|
|
|
2015-12-17 06:11:58 +07:00
|
|
|
ae->un.AttrInt = cpu_to_be32(ae->un.AttrInt);
|
|
|
|
size = FOURBYTES + sizeof(uint32_t);
|
|
|
|
ad->AttrLen = cpu_to_be16(size);
|
|
|
|
ad->AttrType = cpu_to_be16(RPRT_PORT_SPEED);
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
2016-09-25 12:44:55 +07:00
|
|
|
static int
|
2015-12-17 06:11:58 +07:00
|
|
|
lpfc_fdmi_port_attr_max_frame(struct lpfc_vport *vport,
|
|
|
|
struct lpfc_fdmi_attr_def *ad)
|
|
|
|
{
|
|
|
|
struct serv_parm *hsp;
|
|
|
|
struct lpfc_fdmi_attr_entry *ae;
|
|
|
|
uint32_t size;
|
|
|
|
|
|
|
|
ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
|
|
|
|
|
|
|
|
hsp = (struct serv_parm *)&vport->fc_sparam;
|
2019-08-15 06:57:00 +07:00
|
|
|
ae->un.AttrInt = (((uint32_t) hsp->cmn.bbRcvSizeMsb & 0x0F) << 8) |
|
2015-12-17 06:11:58 +07:00
|
|
|
(uint32_t) hsp->cmn.bbRcvSizeLsb;
|
|
|
|
ae->un.AttrInt = cpu_to_be32(ae->un.AttrInt);
|
|
|
|
size = FOURBYTES + sizeof(uint32_t);
|
|
|
|
ad->AttrLen = cpu_to_be16(size);
|
|
|
|
ad->AttrType = cpu_to_be16(RPRT_MAX_FRAME_SIZE);
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
2016-09-25 12:44:55 +07:00
|
|
|
static int
|
2015-12-17 06:11:58 +07:00
|
|
|
lpfc_fdmi_port_attr_os_devname(struct lpfc_vport *vport,
|
|
|
|
struct lpfc_fdmi_attr_def *ad)
|
|
|
|
{
|
|
|
|
struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
|
|
|
|
struct lpfc_fdmi_attr_entry *ae;
|
|
|
|
uint32_t len, size;
|
|
|
|
|
|
|
|
ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
|
|
|
|
memset(ae, 0, 256);
|
|
|
|
|
|
|
|
snprintf(ae->un.AttrString, sizeof(ae->un.AttrString),
|
|
|
|
"/sys/class/scsi_host/host%d", shost->host_no);
|
|
|
|
len = strnlen((char *)ae->un.AttrString,
|
|
|
|
sizeof(ae->un.AttrString));
|
|
|
|
len += (len & 3) ? (4 - (len & 3)) : 4;
|
|
|
|
size = FOURBYTES + len;
|
|
|
|
ad->AttrLen = cpu_to_be16(size);
|
|
|
|
ad->AttrType = cpu_to_be16(RPRT_OS_DEVICE_NAME);
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
2016-09-25 12:44:55 +07:00
|
|
|
static int
|
2015-12-17 06:11:58 +07:00
|
|
|
lpfc_fdmi_port_attr_host_name(struct lpfc_vport *vport,
|
|
|
|
struct lpfc_fdmi_attr_def *ad)
|
|
|
|
{
|
|
|
|
struct lpfc_fdmi_attr_entry *ae;
|
|
|
|
uint32_t len, size;
|
|
|
|
|
|
|
|
ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
|
|
|
|
memset(ae, 0, 256);
|
|
|
|
|
|
|
|
snprintf(ae->un.AttrString, sizeof(ae->un.AttrString), "%s",
|
|
|
|
init_utsname()->nodename);
|
|
|
|
|
|
|
|
len = strnlen(ae->un.AttrString, sizeof(ae->un.AttrString));
|
|
|
|
len += (len & 3) ? (4 - (len & 3)) : 4;
|
|
|
|
size = FOURBYTES + len;
|
|
|
|
ad->AttrLen = cpu_to_be16(size);
|
|
|
|
ad->AttrType = cpu_to_be16(RPRT_HOST_NAME);
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
2016-09-25 12:44:55 +07:00
|
|
|
static int
|
2015-12-17 06:11:58 +07:00
|
|
|
lpfc_fdmi_port_attr_wwnn(struct lpfc_vport *vport,
|
|
|
|
struct lpfc_fdmi_attr_def *ad)
|
|
|
|
{
|
|
|
|
struct lpfc_fdmi_attr_entry *ae;
|
|
|
|
uint32_t size;
|
|
|
|
|
|
|
|
ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
|
|
|
|
memset(ae, 0, sizeof(struct lpfc_name));
|
|
|
|
|
|
|
|
memcpy(&ae->un.AttrWWN, &vport->fc_sparam.nodeName,
|
|
|
|
sizeof(struct lpfc_name));
|
|
|
|
size = FOURBYTES + sizeof(struct lpfc_name);
|
|
|
|
ad->AttrLen = cpu_to_be16(size);
|
|
|
|
ad->AttrType = cpu_to_be16(RPRT_NODENAME);
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
2016-09-25 12:44:55 +07:00
|
|
|
static int
|
2015-12-17 06:11:58 +07:00
|
|
|
lpfc_fdmi_port_attr_wwpn(struct lpfc_vport *vport,
|
|
|
|
struct lpfc_fdmi_attr_def *ad)
|
|
|
|
{
|
|
|
|
struct lpfc_fdmi_attr_entry *ae;
|
|
|
|
uint32_t size;
|
|
|
|
|
|
|
|
ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
|
|
|
|
memset(ae, 0, sizeof(struct lpfc_name));
|
|
|
|
|
|
|
|
memcpy(&ae->un.AttrWWN, &vport->fc_sparam.portName,
|
|
|
|
sizeof(struct lpfc_name));
|
|
|
|
size = FOURBYTES + sizeof(struct lpfc_name);
|
|
|
|
ad->AttrLen = cpu_to_be16(size);
|
|
|
|
ad->AttrType = cpu_to_be16(RPRT_PORTNAME);
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
2016-09-25 12:44:55 +07:00
|
|
|
static int
|
2015-12-17 06:11:58 +07:00
|
|
|
lpfc_fdmi_port_attr_symbolic_name(struct lpfc_vport *vport,
|
|
|
|
struct lpfc_fdmi_attr_def *ad)
|
|
|
|
{
|
|
|
|
struct lpfc_fdmi_attr_entry *ae;
|
|
|
|
uint32_t len, size;
|
|
|
|
|
|
|
|
ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
|
|
|
|
memset(ae, 0, 256);
|
|
|
|
|
|
|
|
len = lpfc_vport_symbolic_port_name(vport, ae->un.AttrString, 256);
|
|
|
|
len += (len & 3) ? (4 - (len & 3)) : 4;
|
|
|
|
size = FOURBYTES + len;
|
|
|
|
ad->AttrLen = cpu_to_be16(size);
|
|
|
|
ad->AttrType = cpu_to_be16(RPRT_SYM_PORTNAME);
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
2016-09-25 12:44:55 +07:00
|
|
|
static int
|
2015-12-17 06:11:58 +07:00
|
|
|
lpfc_fdmi_port_attr_port_type(struct lpfc_vport *vport,
|
|
|
|
struct lpfc_fdmi_attr_def *ad)
|
|
|
|
{
|
|
|
|
struct lpfc_hba *phba = vport->phba;
|
|
|
|
struct lpfc_fdmi_attr_entry *ae;
|
|
|
|
uint32_t size;
|
|
|
|
|
|
|
|
ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
|
|
|
|
if (phba->fc_topology == LPFC_TOPOLOGY_LOOP)
|
|
|
|
ae->un.AttrInt = cpu_to_be32(LPFC_FDMI_PORTTYPE_NLPORT);
|
|
|
|
else
|
|
|
|
ae->un.AttrInt = cpu_to_be32(LPFC_FDMI_PORTTYPE_NPORT);
|
|
|
|
size = FOURBYTES + sizeof(uint32_t);
|
|
|
|
ad->AttrLen = cpu_to_be16(size);
|
|
|
|
ad->AttrType = cpu_to_be16(RPRT_PORT_TYPE);
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
2016-09-25 12:44:55 +07:00
|
|
|
static int
|
2015-12-17 06:11:58 +07:00
|
|
|
lpfc_fdmi_port_attr_class(struct lpfc_vport *vport,
|
|
|
|
struct lpfc_fdmi_attr_def *ad)
|
|
|
|
{
|
|
|
|
struct lpfc_fdmi_attr_entry *ae;
|
|
|
|
uint32_t size;
|
|
|
|
|
|
|
|
ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
|
|
|
|
ae->un.AttrInt = cpu_to_be32(FC_COS_CLASS2 | FC_COS_CLASS3);
|
|
|
|
size = FOURBYTES + sizeof(uint32_t);
|
|
|
|
ad->AttrLen = cpu_to_be16(size);
|
|
|
|
ad->AttrType = cpu_to_be16(RPRT_SUPPORTED_CLASS);
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
2016-09-25 12:44:55 +07:00
|
|
|
static int
|
2015-12-17 06:11:58 +07:00
|
|
|
lpfc_fdmi_port_attr_fabric_wwpn(struct lpfc_vport *vport,
|
|
|
|
struct lpfc_fdmi_attr_def *ad)
|
|
|
|
{
|
|
|
|
struct lpfc_fdmi_attr_entry *ae;
|
|
|
|
uint32_t size;
|
|
|
|
|
|
|
|
ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
|
|
|
|
memset(ae, 0, sizeof(struct lpfc_name));
|
|
|
|
|
|
|
|
memcpy(&ae->un.AttrWWN, &vport->fabric_portname,
|
|
|
|
sizeof(struct lpfc_name));
|
|
|
|
size = FOURBYTES + sizeof(struct lpfc_name);
|
|
|
|
ad->AttrLen = cpu_to_be16(size);
|
|
|
|
ad->AttrType = cpu_to_be16(RPRT_FABRICNAME);
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
2016-09-25 12:44:55 +07:00
|
|
|
static int
|
2015-12-17 06:11:58 +07:00
|
|
|
lpfc_fdmi_port_attr_active_fc4type(struct lpfc_vport *vport,
|
|
|
|
struct lpfc_fdmi_attr_def *ad)
|
|
|
|
{
|
|
|
|
struct lpfc_fdmi_attr_entry *ae;
|
|
|
|
uint32_t size;
|
|
|
|
|
|
|
|
ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
|
|
|
|
memset(ae, 0, 32);
|
|
|
|
|
2019-03-13 06:30:21 +07:00
|
|
|
ae->un.AttrTypes[3] = 0x02; /* Type 0x1 - ELS */
|
|
|
|
ae->un.AttrTypes[2] = 0x01; /* Type 0x8 - FCP */
|
2019-05-22 07:49:08 +07:00
|
|
|
ae->un.AttrTypes[7] = 0x01; /* Type 0x20 - CT */
|
|
|
|
|
|
|
|
/* Check to see if NVME is configured or not */
|
2019-03-13 06:30:21 +07:00
|
|
|
if (vport->phba->cfg_enable_fc4_type & LPFC_ENABLE_NVME)
|
|
|
|
ae->un.AttrTypes[6] = 0x1; /* Type 0x28 - NVME */
|
2019-05-22 07:49:08 +07:00
|
|
|
|
2015-12-17 06:11:58 +07:00
|
|
|
size = FOURBYTES + 32;
|
|
|
|
ad->AttrLen = cpu_to_be16(size);
|
|
|
|
ad->AttrType = cpu_to_be16(RPRT_ACTIVE_FC4_TYPES);
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
2016-09-25 12:44:55 +07:00
|
|
|
static int
|
2015-12-17 06:11:58 +07:00
|
|
|
lpfc_fdmi_port_attr_port_state(struct lpfc_vport *vport,
|
|
|
|
struct lpfc_fdmi_attr_def *ad)
|
|
|
|
{
|
|
|
|
struct lpfc_fdmi_attr_entry *ae;
|
|
|
|
uint32_t size;
|
|
|
|
|
|
|
|
ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
|
|
|
|
/* Link Up - operational */
|
|
|
|
ae->un.AttrInt = cpu_to_be32(LPFC_FDMI_PORTSTATE_ONLINE);
|
|
|
|
size = FOURBYTES + sizeof(uint32_t);
|
|
|
|
ad->AttrLen = cpu_to_be16(size);
|
|
|
|
ad->AttrType = cpu_to_be16(RPRT_PORT_STATE);
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
2016-09-25 12:44:55 +07:00
|
|
|
static int
|
2015-12-17 06:11:58 +07:00
|
|
|
lpfc_fdmi_port_attr_num_disc(struct lpfc_vport *vport,
|
|
|
|
struct lpfc_fdmi_attr_def *ad)
|
|
|
|
{
|
|
|
|
struct lpfc_fdmi_attr_entry *ae;
|
|
|
|
uint32_t size;
|
|
|
|
|
|
|
|
ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
|
|
|
|
vport->fdmi_num_disc = lpfc_find_map_node(vport);
|
|
|
|
ae->un.AttrInt = cpu_to_be32(vport->fdmi_num_disc);
|
|
|
|
size = FOURBYTES + sizeof(uint32_t);
|
|
|
|
ad->AttrLen = cpu_to_be16(size);
|
|
|
|
ad->AttrType = cpu_to_be16(RPRT_DISC_PORT);
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
2016-09-25 12:44:55 +07:00
|
|
|
static int
|
2015-12-17 06:11:58 +07:00
|
|
|
lpfc_fdmi_port_attr_nportid(struct lpfc_vport *vport,
|
|
|
|
struct lpfc_fdmi_attr_def *ad)
|
|
|
|
{
|
|
|
|
struct lpfc_fdmi_attr_entry *ae;
|
|
|
|
uint32_t size;
|
|
|
|
|
|
|
|
ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
|
|
|
|
ae->un.AttrInt = cpu_to_be32(vport->fc_myDID);
|
|
|
|
size = FOURBYTES + sizeof(uint32_t);
|
|
|
|
ad->AttrLen = cpu_to_be16(size);
|
|
|
|
ad->AttrType = cpu_to_be16(RPRT_PORT_ID);
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
2016-09-25 12:44:55 +07:00
|
|
|
static int
|
2015-12-17 06:11:58 +07:00
|
|
|
lpfc_fdmi_smart_attr_service(struct lpfc_vport *vport,
|
|
|
|
struct lpfc_fdmi_attr_def *ad)
|
|
|
|
{
|
|
|
|
struct lpfc_fdmi_attr_entry *ae;
|
|
|
|
uint32_t len, size;
|
|
|
|
|
|
|
|
ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
|
|
|
|
memset(ae, 0, 256);
|
|
|
|
|
|
|
|
strncpy(ae->un.AttrString, "Smart SAN Initiator",
|
|
|
|
sizeof(ae->un.AttrString));
|
|
|
|
len = strnlen(ae->un.AttrString,
|
|
|
|
sizeof(ae->un.AttrString));
|
|
|
|
len += (len & 3) ? (4 - (len & 3)) : 4;
|
|
|
|
size = FOURBYTES + len;
|
|
|
|
ad->AttrLen = cpu_to_be16(size);
|
|
|
|
ad->AttrType = cpu_to_be16(RPRT_SMART_SERVICE);
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
2016-09-25 12:44:55 +07:00
|
|
|
static int
|
2015-12-17 06:11:58 +07:00
|
|
|
lpfc_fdmi_smart_attr_guid(struct lpfc_vport *vport,
|
|
|
|
struct lpfc_fdmi_attr_def *ad)
|
|
|
|
{
|
|
|
|
struct lpfc_fdmi_attr_entry *ae;
|
|
|
|
uint32_t size;
|
|
|
|
|
|
|
|
ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
|
|
|
|
memset(ae, 0, 256);
|
|
|
|
|
|
|
|
memcpy(&ae->un.AttrString, &vport->fc_sparam.nodeName,
|
|
|
|
sizeof(struct lpfc_name));
|
|
|
|
memcpy((((uint8_t *)&ae->un.AttrString) +
|
|
|
|
sizeof(struct lpfc_name)),
|
|
|
|
&vport->fc_sparam.portName, sizeof(struct lpfc_name));
|
|
|
|
size = FOURBYTES + (2 * sizeof(struct lpfc_name));
|
|
|
|
ad->AttrLen = cpu_to_be16(size);
|
|
|
|
ad->AttrType = cpu_to_be16(RPRT_SMART_GUID);
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
2016-09-25 12:44:55 +07:00
|
|
|
static int
|
2015-12-17 06:11:58 +07:00
|
|
|
lpfc_fdmi_smart_attr_version(struct lpfc_vport *vport,
|
|
|
|
struct lpfc_fdmi_attr_def *ad)
|
|
|
|
{
|
|
|
|
struct lpfc_fdmi_attr_entry *ae;
|
|
|
|
uint32_t len, size;
|
|
|
|
|
|
|
|
ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
|
|
|
|
memset(ae, 0, 256);
|
|
|
|
|
2016-04-01 04:12:32 +07:00
|
|
|
strncpy(ae->un.AttrString, "Smart SAN Version 2.0",
|
2015-12-17 06:11:58 +07:00
|
|
|
sizeof(ae->un.AttrString));
|
|
|
|
len = strnlen(ae->un.AttrString,
|
|
|
|
sizeof(ae->un.AttrString));
|
|
|
|
len += (len & 3) ? (4 - (len & 3)) : 4;
|
|
|
|
size = FOURBYTES + len;
|
|
|
|
ad->AttrLen = cpu_to_be16(size);
|
|
|
|
ad->AttrType = cpu_to_be16(RPRT_SMART_VERSION);
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
2016-09-25 12:44:55 +07:00
|
|
|
static int
|
2015-12-17 06:11:58 +07:00
|
|
|
lpfc_fdmi_smart_attr_model(struct lpfc_vport *vport,
|
|
|
|
struct lpfc_fdmi_attr_def *ad)
|
|
|
|
{
|
|
|
|
struct lpfc_hba *phba = vport->phba;
|
|
|
|
struct lpfc_fdmi_attr_entry *ae;
|
|
|
|
uint32_t len, size;
|
|
|
|
|
|
|
|
ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
|
|
|
|
memset(ae, 0, 256);
|
|
|
|
|
|
|
|
strncpy(ae->un.AttrString, phba->ModelName,
|
|
|
|
sizeof(ae->un.AttrString));
|
|
|
|
len = strnlen(ae->un.AttrString, sizeof(ae->un.AttrString));
|
|
|
|
len += (len & 3) ? (4 - (len & 3)) : 4;
|
|
|
|
size = FOURBYTES + len;
|
|
|
|
ad->AttrLen = cpu_to_be16(size);
|
|
|
|
ad->AttrType = cpu_to_be16(RPRT_SMART_MODEL);
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
2016-09-25 12:44:55 +07:00
|
|
|
static int
|
2015-12-17 06:11:58 +07:00
|
|
|
lpfc_fdmi_smart_attr_port_info(struct lpfc_vport *vport,
|
|
|
|
struct lpfc_fdmi_attr_def *ad)
|
|
|
|
{
|
|
|
|
struct lpfc_fdmi_attr_entry *ae;
|
|
|
|
uint32_t size;
|
|
|
|
|
|
|
|
ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
|
|
|
|
|
|
|
|
/* SRIOV (type 3) is not supported */
|
|
|
|
if (vport->vpi)
|
|
|
|
ae->un.AttrInt = cpu_to_be32(2); /* NPIV */
|
|
|
|
else
|
|
|
|
ae->un.AttrInt = cpu_to_be32(1); /* Physical */
|
|
|
|
size = FOURBYTES + sizeof(uint32_t);
|
|
|
|
ad->AttrLen = cpu_to_be16(size);
|
|
|
|
ad->AttrType = cpu_to_be16(RPRT_SMART_PORT_INFO);
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
2016-09-25 12:44:55 +07:00
|
|
|
static int
|
2015-12-17 06:11:58 +07:00
|
|
|
lpfc_fdmi_smart_attr_qos(struct lpfc_vport *vport,
|
|
|
|
struct lpfc_fdmi_attr_def *ad)
|
|
|
|
{
|
|
|
|
struct lpfc_fdmi_attr_entry *ae;
|
|
|
|
uint32_t size;
|
|
|
|
|
|
|
|
ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
|
|
|
|
ae->un.AttrInt = cpu_to_be32(0);
|
|
|
|
size = FOURBYTES + sizeof(uint32_t);
|
|
|
|
ad->AttrLen = cpu_to_be16(size);
|
|
|
|
ad->AttrType = cpu_to_be16(RPRT_SMART_QOS);
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
2016-09-25 12:44:55 +07:00
|
|
|
static int
|
2015-12-17 06:11:58 +07:00
|
|
|
lpfc_fdmi_smart_attr_security(struct lpfc_vport *vport,
|
|
|
|
struct lpfc_fdmi_attr_def *ad)
|
|
|
|
{
|
|
|
|
struct lpfc_fdmi_attr_entry *ae;
|
|
|
|
uint32_t size;
|
|
|
|
|
|
|
|
ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue;
|
2016-04-01 04:12:32 +07:00
|
|
|
ae->un.AttrInt = cpu_to_be32(1);
|
2015-12-17 06:11:58 +07:00
|
|
|
size = FOURBYTES + sizeof(uint32_t);
|
|
|
|
ad->AttrLen = cpu_to_be16(size);
|
|
|
|
ad->AttrType = cpu_to_be16(RPRT_SMART_SECURITY);
|
|
|
|
return size;
|
2005-04-18 04:05:31 +07:00
|
|
|
}
|
2007-06-18 07:56:36 +07:00
|
|
|
|
2015-12-17 06:11:58 +07:00
|
|
|
/* RHBA attribute jump table */
|
|
|
|
int (*lpfc_fdmi_hba_action[])
|
|
|
|
(struct lpfc_vport *vport, struct lpfc_fdmi_attr_def *ad) = {
|
|
|
|
/* Action routine Mask bit Attribute type */
|
|
|
|
lpfc_fdmi_hba_attr_wwnn, /* bit0 RHBA_NODENAME */
|
|
|
|
lpfc_fdmi_hba_attr_manufacturer, /* bit1 RHBA_MANUFACTURER */
|
|
|
|
lpfc_fdmi_hba_attr_sn, /* bit2 RHBA_SERIAL_NUMBER */
|
|
|
|
lpfc_fdmi_hba_attr_model, /* bit3 RHBA_MODEL */
|
|
|
|
lpfc_fdmi_hba_attr_description, /* bit4 RHBA_MODEL_DESCRIPTION */
|
|
|
|
lpfc_fdmi_hba_attr_hdw_ver, /* bit5 RHBA_HARDWARE_VERSION */
|
|
|
|
lpfc_fdmi_hba_attr_drvr_ver, /* bit6 RHBA_DRIVER_VERSION */
|
|
|
|
lpfc_fdmi_hba_attr_rom_ver, /* bit7 RHBA_OPTION_ROM_VERSION */
|
|
|
|
lpfc_fdmi_hba_attr_fmw_ver, /* bit8 RHBA_FIRMWARE_VERSION */
|
|
|
|
lpfc_fdmi_hba_attr_os_ver, /* bit9 RHBA_OS_NAME_VERSION */
|
|
|
|
lpfc_fdmi_hba_attr_ct_len, /* bit10 RHBA_MAX_CT_PAYLOAD_LEN */
|
|
|
|
lpfc_fdmi_hba_attr_symbolic_name, /* bit11 RHBA_SYM_NODENAME */
|
|
|
|
lpfc_fdmi_hba_attr_vendor_info, /* bit12 RHBA_VENDOR_INFO */
|
|
|
|
lpfc_fdmi_hba_attr_num_ports, /* bit13 RHBA_NUM_PORTS */
|
|
|
|
lpfc_fdmi_hba_attr_fabric_wwnn, /* bit14 RHBA_FABRIC_WWNN */
|
|
|
|
lpfc_fdmi_hba_attr_bios_ver, /* bit15 RHBA_BIOS_VERSION */
|
|
|
|
lpfc_fdmi_hba_attr_bios_state, /* bit16 RHBA_BIOS_STATE */
|
|
|
|
lpfc_fdmi_hba_attr_vendor_id, /* bit17 RHBA_VENDOR_ID */
|
|
|
|
};
|
|
|
|
|
|
|
|
/* RPA / RPRT attribute jump table */
|
|
|
|
int (*lpfc_fdmi_port_action[])
|
|
|
|
(struct lpfc_vport *vport, struct lpfc_fdmi_attr_def *ad) = {
|
|
|
|
/* Action routine Mask bit Attribute type */
|
|
|
|
lpfc_fdmi_port_attr_fc4type, /* bit0 RPRT_SUPPORT_FC4_TYPES */
|
|
|
|
lpfc_fdmi_port_attr_support_speed, /* bit1 RPRT_SUPPORTED_SPEED */
|
|
|
|
lpfc_fdmi_port_attr_speed, /* bit2 RPRT_PORT_SPEED */
|
|
|
|
lpfc_fdmi_port_attr_max_frame, /* bit3 RPRT_MAX_FRAME_SIZE */
|
|
|
|
lpfc_fdmi_port_attr_os_devname, /* bit4 RPRT_OS_DEVICE_NAME */
|
|
|
|
lpfc_fdmi_port_attr_host_name, /* bit5 RPRT_HOST_NAME */
|
|
|
|
lpfc_fdmi_port_attr_wwnn, /* bit6 RPRT_NODENAME */
|
|
|
|
lpfc_fdmi_port_attr_wwpn, /* bit7 RPRT_PORTNAME */
|
|
|
|
lpfc_fdmi_port_attr_symbolic_name, /* bit8 RPRT_SYM_PORTNAME */
|
|
|
|
lpfc_fdmi_port_attr_port_type, /* bit9 RPRT_PORT_TYPE */
|
|
|
|
lpfc_fdmi_port_attr_class, /* bit10 RPRT_SUPPORTED_CLASS */
|
|
|
|
lpfc_fdmi_port_attr_fabric_wwpn, /* bit11 RPRT_FABRICNAME */
|
|
|
|
lpfc_fdmi_port_attr_active_fc4type, /* bit12 RPRT_ACTIVE_FC4_TYPES */
|
|
|
|
lpfc_fdmi_port_attr_port_state, /* bit13 RPRT_PORT_STATE */
|
|
|
|
lpfc_fdmi_port_attr_num_disc, /* bit14 RPRT_DISC_PORT */
|
|
|
|
lpfc_fdmi_port_attr_nportid, /* bit15 RPRT_PORT_ID */
|
|
|
|
lpfc_fdmi_smart_attr_service, /* bit16 RPRT_SMART_SERVICE */
|
|
|
|
lpfc_fdmi_smart_attr_guid, /* bit17 RPRT_SMART_GUID */
|
|
|
|
lpfc_fdmi_smart_attr_version, /* bit18 RPRT_SMART_VERSION */
|
|
|
|
lpfc_fdmi_smart_attr_model, /* bit19 RPRT_SMART_MODEL */
|
|
|
|
lpfc_fdmi_smart_attr_port_info, /* bit20 RPRT_SMART_PORT_INFO */
|
|
|
|
lpfc_fdmi_smart_attr_qos, /* bit21 RPRT_SMART_QOS */
|
|
|
|
lpfc_fdmi_smart_attr_security, /* bit22 RPRT_SMART_SECURITY */
|
|
|
|
};
|
2015-04-08 02:07:19 +07:00
|
|
|
|
2015-12-17 06:11:58 +07:00
|
|
|
/**
|
|
|
|
* lpfc_fdmi_cmd - Build and send a FDMI cmd to the specified NPort
|
|
|
|
* @vport: pointer to a host virtual N_Port data structure.
|
|
|
|
* @ndlp: ndlp to send FDMI cmd to (if NULL use FDMI_DID)
|
|
|
|
* cmdcode: FDMI command to send
|
|
|
|
* mask: Mask of HBA or PORT Attributes to send
|
|
|
|
*
|
|
|
|
* Builds and sends a FDMI command using the CT subsystem.
|
|
|
|
*/
|
2005-04-18 04:05:31 +07:00
|
|
|
int
|
2015-12-17 06:11:58 +07:00
|
|
|
lpfc_fdmi_cmd(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
|
|
|
|
int cmdcode, uint32_t new_mask)
|
2005-04-18 04:05:31 +07:00
|
|
|
{
|
2007-06-18 07:56:36 +07:00
|
|
|
struct lpfc_hba *phba = vport->phba;
|
2005-04-18 04:05:31 +07:00
|
|
|
struct lpfc_dmabuf *mp, *bmp;
|
|
|
|
struct lpfc_sli_ct_request *CtReq;
|
|
|
|
struct ulp_bde64 *bpl;
|
2015-12-17 06:11:58 +07:00
|
|
|
uint32_t bit_pos;
|
2005-04-18 04:05:31 +07:00
|
|
|
uint32_t size;
|
2015-04-08 02:07:19 +07:00
|
|
|
uint32_t rsp_size;
|
2015-12-17 06:11:58 +07:00
|
|
|
uint32_t mask;
|
2015-04-08 02:07:19 +07:00
|
|
|
struct lpfc_fdmi_reg_hba *rh;
|
|
|
|
struct lpfc_fdmi_port_entry *pe;
|
|
|
|
struct lpfc_fdmi_reg_portattr *pab = NULL;
|
|
|
|
struct lpfc_fdmi_attr_block *ab = NULL;
|
2015-12-17 06:11:58 +07:00
|
|
|
int (*func)(struct lpfc_vport *vport, struct lpfc_fdmi_attr_def *ad);
|
|
|
|
void (*cmpl)(struct lpfc_hba *, struct lpfc_iocbq *,
|
|
|
|
struct lpfc_iocbq *);
|
2005-04-18 04:05:31 +07:00
|
|
|
|
2015-12-17 06:11:58 +07:00
|
|
|
if (!ndlp || !NLP_CHK_NODE_ACT(ndlp))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
cmpl = lpfc_cmpl_ct_disc_fdmi; /* called from discovery */
|
2005-04-18 04:05:31 +07:00
|
|
|
|
|
|
|
/* fill in BDEs for command */
|
|
|
|
/* Allocate buffer for command payload */
|
2015-04-08 02:07:19 +07:00
|
|
|
mp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
|
2005-04-18 04:05:31 +07:00
|
|
|
if (!mp)
|
|
|
|
goto fdmi_cmd_exit;
|
|
|
|
|
|
|
|
mp->virt = lpfc_mbuf_alloc(phba, 0, &(mp->phys));
|
|
|
|
if (!mp->virt)
|
|
|
|
goto fdmi_cmd_free_mp;
|
|
|
|
|
|
|
|
/* Allocate buffer for Buffer ptr list */
|
2015-04-08 02:07:19 +07:00
|
|
|
bmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
|
2005-04-18 04:05:31 +07:00
|
|
|
if (!bmp)
|
|
|
|
goto fdmi_cmd_free_mpvirt;
|
|
|
|
|
|
|
|
bmp->virt = lpfc_mbuf_alloc(phba, 0, &(bmp->phys));
|
|
|
|
if (!bmp->virt)
|
|
|
|
goto fdmi_cmd_free_bmp;
|
|
|
|
|
|
|
|
INIT_LIST_HEAD(&mp->list);
|
|
|
|
INIT_LIST_HEAD(&bmp->list);
|
|
|
|
|
|
|
|
/* FDMI request */
|
2007-08-02 22:10:09 +07:00
|
|
|
lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
|
|
|
|
"0218 FDMI Request Data: x%x x%x x%x\n",
|
|
|
|
vport->fc_flag, vport->port_state, cmdcode);
|
2015-04-08 02:07:19 +07:00
|
|
|
CtReq = (struct lpfc_sli_ct_request *)mp->virt;
|
2005-04-18 04:05:31 +07:00
|
|
|
|
2015-04-08 02:07:19 +07:00
|
|
|
/* First populate the CT_IU preamble */
|
2005-04-18 04:05:31 +07:00
|
|
|
memset(CtReq, 0, sizeof(struct lpfc_sli_ct_request));
|
|
|
|
CtReq->RevisionId.bits.Revision = SLI_CT_REVISION;
|
|
|
|
CtReq->RevisionId.bits.InId = 0;
|
|
|
|
|
|
|
|
CtReq->FsType = SLI_CT_MANAGEMENT_SERVICE;
|
|
|
|
CtReq->FsSubType = SLI_CT_FDMI_Subtypes;
|
2015-04-08 02:07:19 +07:00
|
|
|
|
|
|
|
CtReq->CommandResponse.bits.CmdRsp = cpu_to_be16(cmdcode);
|
|
|
|
rsp_size = LPFC_BPL_SIZE;
|
2005-04-18 04:05:31 +07:00
|
|
|
size = 0;
|
|
|
|
|
2015-04-08 02:07:19 +07:00
|
|
|
/* Next fill in the specific FDMI cmd information */
|
2005-04-18 04:05:31 +07:00
|
|
|
switch (cmdcode) {
|
2015-04-08 02:07:19 +07:00
|
|
|
case SLI_MGMT_RHAT:
|
2005-04-18 04:05:31 +07:00
|
|
|
case SLI_MGMT_RHBA:
|
2015-12-17 06:11:58 +07:00
|
|
|
rh = (struct lpfc_fdmi_reg_hba *)&CtReq->un.PortID;
|
|
|
|
/* HBA Identifier */
|
|
|
|
memcpy(&rh->hi.PortName, &phba->pport->fc_sparam.portName,
|
|
|
|
sizeof(struct lpfc_name));
|
2005-04-18 04:05:31 +07:00
|
|
|
|
2015-12-17 06:11:58 +07:00
|
|
|
if (cmdcode == SLI_MGMT_RHBA) {
|
|
|
|
/* Registered Port List */
|
|
|
|
/* One entry (port) per adapter */
|
|
|
|
rh->rpl.EntryCnt = cpu_to_be32(1);
|
|
|
|
memcpy(&rh->rpl.pe, &phba->pport->fc_sparam.portName,
|
2015-04-08 02:07:19 +07:00
|
|
|
sizeof(struct lpfc_name));
|
|
|
|
|
2015-12-17 06:11:58 +07:00
|
|
|
/* point to the HBA attribute block */
|
|
|
|
size = 2 * sizeof(struct lpfc_name) +
|
|
|
|
FOURBYTES;
|
|
|
|
} else {
|
|
|
|
size = sizeof(struct lpfc_name);
|
|
|
|
}
|
|
|
|
ab = (struct lpfc_fdmi_attr_block *)((uint8_t *)rh + size);
|
|
|
|
ab->EntryCnt = 0;
|
|
|
|
size += FOURBYTES;
|
|
|
|
bit_pos = 0;
|
|
|
|
if (new_mask)
|
|
|
|
mask = new_mask;
|
|
|
|
else
|
|
|
|
mask = vport->fdmi_hba_mask;
|
|
|
|
|
|
|
|
/* Mask will dictate what attributes to build in the request */
|
|
|
|
while (mask) {
|
|
|
|
if (mask & 0x1) {
|
|
|
|
func = lpfc_fdmi_hba_action[bit_pos];
|
|
|
|
size += func(vport,
|
|
|
|
(struct lpfc_fdmi_attr_def *)
|
|
|
|
((uint8_t *)rh + size));
|
|
|
|
ab->EntryCnt++;
|
|
|
|
if ((size + 256) >
|
|
|
|
(LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
|
|
|
|
goto hba_out;
|
2005-04-18 04:05:31 +07:00
|
|
|
}
|
2015-12-17 06:11:58 +07:00
|
|
|
mask = mask >> 1;
|
|
|
|
bit_pos++;
|
2005-04-18 04:05:31 +07:00
|
|
|
}
|
2015-12-17 06:11:58 +07:00
|
|
|
hba_out:
|
|
|
|
ab->EntryCnt = cpu_to_be32(ab->EntryCnt);
|
|
|
|
/* Total size */
|
|
|
|
size = GID_REQUEST_SZ - 4 + size;
|
2005-04-18 04:05:31 +07:00
|
|
|
break;
|
|
|
|
|
2015-04-08 02:07:19 +07:00
|
|
|
case SLI_MGMT_RPRT:
|
2005-04-18 04:05:31 +07:00
|
|
|
case SLI_MGMT_RPA:
|
2015-12-17 06:11:58 +07:00
|
|
|
pab = (struct lpfc_fdmi_reg_portattr *)&CtReq->un.PortID;
|
|
|
|
if (cmdcode == SLI_MGMT_RPRT) {
|
|
|
|
rh = (struct lpfc_fdmi_reg_hba *)pab;
|
|
|
|
/* HBA Identifier */
|
|
|
|
memcpy(&rh->hi.PortName,
|
|
|
|
&phba->pport->fc_sparam.portName,
|
2015-04-08 02:07:19 +07:00
|
|
|
sizeof(struct lpfc_name));
|
2015-12-17 06:11:58 +07:00
|
|
|
pab = (struct lpfc_fdmi_reg_portattr *)
|
|
|
|
((uint8_t *)pab + sizeof(struct lpfc_name));
|
|
|
|
}
|
2005-04-18 04:05:31 +07:00
|
|
|
|
2015-12-17 06:11:58 +07:00
|
|
|
memcpy((uint8_t *)&pab->PortName,
|
|
|
|
(uint8_t *)&vport->fc_sparam.portName,
|
|
|
|
sizeof(struct lpfc_name));
|
|
|
|
size += sizeof(struct lpfc_name) + FOURBYTES;
|
|
|
|
pab->ab.EntryCnt = 0;
|
|
|
|
bit_pos = 0;
|
|
|
|
if (new_mask)
|
|
|
|
mask = new_mask;
|
|
|
|
else
|
|
|
|
mask = vport->fdmi_port_mask;
|
|
|
|
|
|
|
|
/* Mask will dictate what attributes to build in the request */
|
|
|
|
while (mask) {
|
|
|
|
if (mask & 0x1) {
|
|
|
|
func = lpfc_fdmi_port_action[bit_pos];
|
|
|
|
size += func(vport,
|
|
|
|
(struct lpfc_fdmi_attr_def *)
|
|
|
|
((uint8_t *)pab + size));
|
|
|
|
pab->ab.EntryCnt++;
|
|
|
|
if ((size + 256) >
|
|
|
|
(LPFC_BPL_SIZE - LPFC_CT_PREAMBLE))
|
|
|
|
goto port_out;
|
|
|
|
}
|
|
|
|
mask = mask >> 1;
|
|
|
|
bit_pos++;
|
2005-04-18 04:05:31 +07:00
|
|
|
}
|
2015-12-17 06:11:58 +07:00
|
|
|
port_out:
|
|
|
|
pab->ab.EntryCnt = cpu_to_be32(pab->ab.EntryCnt);
|
|
|
|
/* Total size */
|
|
|
|
if (cmdcode == SLI_MGMT_RPRT)
|
|
|
|
size += sizeof(struct lpfc_name);
|
|
|
|
size = GID_REQUEST_SZ - 4 + size;
|
2005-04-18 04:05:31 +07:00
|
|
|
break;
|
|
|
|
|
2015-04-08 02:07:19 +07:00
|
|
|
case SLI_MGMT_GHAT:
|
|
|
|
case SLI_MGMT_GRPL:
|
|
|
|
rsp_size = FC_MAX_NS_RSP;
|
2019-03-29 01:06:18 +07:00
|
|
|
/* fall through */
|
2005-04-18 04:05:31 +07:00
|
|
|
case SLI_MGMT_DHBA:
|
2015-04-08 02:07:19 +07:00
|
|
|
case SLI_MGMT_DHAT:
|
|
|
|
pe = (struct lpfc_fdmi_port_entry *)&CtReq->un.PortID;
|
|
|
|
memcpy((uint8_t *)&pe->PortName,
|
|
|
|
(uint8_t *)&vport->fc_sparam.portName,
|
|
|
|
sizeof(struct lpfc_name));
|
|
|
|
size = GID_REQUEST_SZ - 4 + sizeof(struct lpfc_name);
|
2005-04-18 04:05:31 +07:00
|
|
|
break;
|
|
|
|
|
2015-04-08 02:07:19 +07:00
|
|
|
case SLI_MGMT_GPAT:
|
|
|
|
case SLI_MGMT_GPAS:
|
|
|
|
rsp_size = FC_MAX_NS_RSP;
|
2019-03-29 01:06:18 +07:00
|
|
|
/* fall through */
|
2005-04-18 04:05:31 +07:00
|
|
|
case SLI_MGMT_DPRT:
|
2015-04-08 02:07:19 +07:00
|
|
|
case SLI_MGMT_DPA:
|
|
|
|
pe = (struct lpfc_fdmi_port_entry *)&CtReq->un.PortID;
|
|
|
|
memcpy((uint8_t *)&pe->PortName,
|
|
|
|
(uint8_t *)&vport->fc_sparam.portName,
|
|
|
|
sizeof(struct lpfc_name));
|
|
|
|
size = GID_REQUEST_SZ - 4 + sizeof(struct lpfc_name);
|
|
|
|
break;
|
|
|
|
case SLI_MGMT_GRHL:
|
|
|
|
size = GID_REQUEST_SZ - 4;
|
2005-04-18 04:05:31 +07:00
|
|
|
break;
|
2015-04-08 02:07:19 +07:00
|
|
|
default:
|
|
|
|
lpfc_printf_vlog(vport, KERN_WARNING, LOG_DISCOVERY,
|
|
|
|
"0298 FDMI cmdcode x%x not supported\n",
|
|
|
|
cmdcode);
|
|
|
|
goto fdmi_cmd_free_bmpvirt;
|
2005-04-18 04:05:31 +07:00
|
|
|
}
|
2015-04-08 02:07:19 +07:00
|
|
|
CtReq->CommandResponse.bits.Size = cpu_to_be16(rsp_size);
|
2005-04-18 04:05:31 +07:00
|
|
|
|
2015-04-08 02:07:19 +07:00
|
|
|
bpl = (struct ulp_bde64 *)bmp->virt;
|
|
|
|
bpl->addrHigh = le32_to_cpu(putPaddrHigh(mp->phys));
|
|
|
|
bpl->addrLow = le32_to_cpu(putPaddrLow(mp->phys));
|
2005-04-18 04:05:31 +07:00
|
|
|
bpl->tus.f.bdeFlags = 0;
|
|
|
|
bpl->tus.f.bdeSize = size;
|
|
|
|
|
2015-04-08 02:07:19 +07:00
|
|
|
/*
|
|
|
|
* The lpfc_ct_cmd/lpfc_get_req shall increment ndlp reference count
|
2008-02-09 06:49:26 +07:00
|
|
|
* to hold ndlp reference for the corresponding callback function.
|
|
|
|
*/
|
2015-04-08 02:07:19 +07:00
|
|
|
if (!lpfc_ct_cmd(vport, mp, bmp, ndlp, cmpl, rsp_size, 0))
|
2005-04-18 04:05:31 +07:00
|
|
|
return 0;
|
|
|
|
|
2015-04-08 02:07:19 +07:00
|
|
|
/*
|
|
|
|
* Decrement ndlp reference count to release ndlp reference held
|
2008-02-09 06:49:26 +07:00
|
|
|
* for the failed command's callback function.
|
|
|
|
*/
|
2007-08-02 22:10:31 +07:00
|
|
|
lpfc_nlp_put(ndlp);
|
2008-02-09 06:49:26 +07:00
|
|
|
|
2015-04-08 02:07:19 +07:00
|
|
|
fdmi_cmd_free_bmpvirt:
|
2005-04-18 04:05:31 +07:00
|
|
|
lpfc_mbuf_free(phba, bmp->virt, bmp->phys);
|
|
|
|
fdmi_cmd_free_bmp:
|
|
|
|
kfree(bmp);
|
|
|
|
fdmi_cmd_free_mpvirt:
|
|
|
|
lpfc_mbuf_free(phba, mp->virt, mp->phys);
|
|
|
|
fdmi_cmd_free_mp:
|
|
|
|
kfree(mp);
|
|
|
|
fdmi_cmd_exit:
|
|
|
|
/* Issue FDMI request failed */
|
2007-08-02 22:10:09 +07:00
|
|
|
lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
|
|
|
|
"0244 Issue FDMI request failed Data: x%x\n",
|
|
|
|
cmdcode);
|
2005-04-18 04:05:31 +07:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2011-02-17 00:39:44 +07:00
|
|
|
/**
|
|
|
|
* lpfc_delayed_disc_tmo - Timeout handler for delayed discovery timer.
|
|
|
|
* @ptr - Context object of the timer.
|
|
|
|
*
|
|
|
|
* This function set the WORKER_DELAYED_DISC_TMO flag and wake up
|
|
|
|
* the worker thread.
|
|
|
|
**/
|
|
|
|
void
|
2017-09-07 10:24:26 +07:00
|
|
|
lpfc_delayed_disc_tmo(struct timer_list *t)
|
2011-02-17 00:39:44 +07:00
|
|
|
{
|
2017-09-07 10:24:26 +07:00
|
|
|
struct lpfc_vport *vport = from_timer(vport, t, delayed_disc_tmo);
|
2011-02-17 00:39:44 +07:00
|
|
|
struct lpfc_hba *phba = vport->phba;
|
|
|
|
uint32_t tmo_posted;
|
|
|
|
unsigned long iflag;
|
|
|
|
|
|
|
|
spin_lock_irqsave(&vport->work_port_lock, iflag);
|
|
|
|
tmo_posted = vport->work_port_events & WORKER_DELAYED_DISC_TMO;
|
|
|
|
if (!tmo_posted)
|
|
|
|
vport->work_port_events |= WORKER_DELAYED_DISC_TMO;
|
|
|
|
spin_unlock_irqrestore(&vport->work_port_lock, iflag);
|
|
|
|
|
|
|
|
if (!tmo_posted)
|
|
|
|
lpfc_worker_wake_up(phba);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* lpfc_delayed_disc_timeout_handler - Function called by worker thread to
|
|
|
|
* handle delayed discovery.
|
|
|
|
* @vport: pointer to a host virtual N_Port data structure.
|
|
|
|
*
|
|
|
|
* This function start nport discovery of the vport.
|
|
|
|
**/
|
|
|
|
void
|
|
|
|
lpfc_delayed_disc_timeout_handler(struct lpfc_vport *vport)
|
|
|
|
{
|
|
|
|
struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
|
|
|
|
|
|
|
|
spin_lock_irq(shost->host_lock);
|
|
|
|
if (!(vport->fc_flag & FC_DISC_DELAYED)) {
|
|
|
|
spin_unlock_irq(shost->host_lock);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
vport->fc_flag &= ~FC_DISC_DELAYED;
|
|
|
|
spin_unlock_irq(shost->host_lock);
|
|
|
|
|
|
|
|
lpfc_do_scr_ns_plogi(vport->phba, vport);
|
|
|
|
}
|
|
|
|
|
2005-04-18 04:05:31 +07:00
|
|
|
void
|
2007-06-18 07:56:36 +07:00
|
|
|
lpfc_decode_firmware_rev(struct lpfc_hba *phba, char *fwrevision, int flag)
|
2005-04-18 04:05:31 +07:00
|
|
|
{
|
|
|
|
struct lpfc_sli *psli = &phba->sli;
|
|
|
|
lpfc_vpd_t *vp = &phba->vpd;
|
|
|
|
uint32_t b1, b2, b3, b4, i, rev;
|
|
|
|
char c;
|
|
|
|
uint32_t *ptr, str[4];
|
|
|
|
uint8_t *fwname;
|
|
|
|
|
2009-06-11 04:22:44 +07:00
|
|
|
if (phba->sli_rev == LPFC_SLI_REV4)
|
2012-01-19 04:24:06 +07:00
|
|
|
snprintf(fwrevision, FW_REV_STR_SIZE, "%s", vp->rev.opFwName);
|
2009-06-11 04:22:44 +07:00
|
|
|
else if (vp->rev.rBit) {
|
2009-05-23 01:53:12 +07:00
|
|
|
if (psli->sli_flag & LPFC_SLI_ACTIVE)
|
2005-04-18 04:05:31 +07:00
|
|
|
rev = vp->rev.sli2FwRev;
|
|
|
|
else
|
|
|
|
rev = vp->rev.sli1FwRev;
|
|
|
|
|
|
|
|
b1 = (rev & 0x0000f000) >> 12;
|
|
|
|
b2 = (rev & 0x00000f00) >> 8;
|
|
|
|
b3 = (rev & 0x000000c0) >> 6;
|
|
|
|
b4 = (rev & 0x00000030) >> 4;
|
|
|
|
|
|
|
|
switch (b4) {
|
|
|
|
case 0:
|
|
|
|
c = 'N';
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
c = 'A';
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
c = 'B';
|
|
|
|
break;
|
2011-10-11 08:32:10 +07:00
|
|
|
case 3:
|
|
|
|
c = 'X';
|
|
|
|
break;
|
2005-04-18 04:05:31 +07:00
|
|
|
default:
|
|
|
|
c = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
b4 = (rev & 0x0000000f);
|
|
|
|
|
2009-05-23 01:53:12 +07:00
|
|
|
if (psli->sli_flag & LPFC_SLI_ACTIVE)
|
2005-04-18 04:05:31 +07:00
|
|
|
fwname = vp->rev.sli2FwName;
|
|
|
|
else
|
|
|
|
fwname = vp->rev.sli1FwName;
|
|
|
|
|
|
|
|
for (i = 0; i < 16; i++)
|
|
|
|
if (fwname[i] == 0x20)
|
|
|
|
fwname[i] = 0;
|
|
|
|
|
|
|
|
ptr = (uint32_t*)fwname;
|
|
|
|
|
|
|
|
for (i = 0; i < 3; i++)
|
|
|
|
str[i] = be32_to_cpu(*ptr++);
|
|
|
|
|
|
|
|
if (c == 0) {
|
|
|
|
if (flag)
|
|
|
|
sprintf(fwrevision, "%d.%d%d (%s)",
|
|
|
|
b1, b2, b3, (char *)str);
|
|
|
|
else
|
|
|
|
sprintf(fwrevision, "%d.%d%d", b1,
|
|
|
|
b2, b3);
|
|
|
|
} else {
|
|
|
|
if (flag)
|
|
|
|
sprintf(fwrevision, "%d.%d%d%c%d (%s)",
|
|
|
|
b1, b2, b3, c,
|
|
|
|
b4, (char *)str);
|
|
|
|
else
|
|
|
|
sprintf(fwrevision, "%d.%d%d%c%d",
|
|
|
|
b1, b2, b3, c, b4);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
rev = vp->rev.smFwRev;
|
|
|
|
|
|
|
|
b1 = (rev & 0xff000000) >> 24;
|
|
|
|
b2 = (rev & 0x00f00000) >> 20;
|
|
|
|
b3 = (rev & 0x000f0000) >> 16;
|
|
|
|
c = (rev & 0x0000ff00) >> 8;
|
|
|
|
b4 = (rev & 0x000000ff);
|
|
|
|
|
2010-01-17 22:15:57 +07:00
|
|
|
sprintf(fwrevision, "%d.%d%d%c%d", b1, b2, b3, c, b4);
|
2005-04-18 04:05:31 +07:00
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|