[SCSI] lpfc: NPIV: add SLI-3 interface
NPIV support is only available via new adapter interface extensions, termed SLI-3. This interface changes some of the basic behaviors such as command and response ring element sizes and data structures, as well as a change in buffer posting. Note: the new firmware extensions are found only on our mid-range and enterprise 4Gig adapters - so NPIV support is available only on these newer adapters. The latest firmware can be downloaded from the Emulex support page. Signed-off-by: James Smart <James.Smart@emulex.com> Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
This commit is contained in:
committed by
James Bottomley
parent
2e0fef85e0
commit
ed95768429
@@ -232,6 +232,7 @@ lpfc_init_link(struct lpfc_hba * phba,
|
||||
mb->mbxCommand = (volatile uint8_t)MBX_INIT_LINK;
|
||||
mb->mbxOwner = OWN_HOST;
|
||||
mb->un.varInitLnk.fabric_AL_PA = phba->fc_pref_ALPA;
|
||||
mb->un.varInitLnk.link_flags |= FLAGS_UNREG_LOGIN_ALL;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -418,6 +419,10 @@ lpfc_config_pcb_setup(struct lpfc_hba * phba)
|
||||
for (i = 0; i < psli->num_rings; i++) {
|
||||
pring = &psli->ring[i];
|
||||
|
||||
pring->sizeCiocb = phba->sli_rev == 3 ? SLI3_IOCB_CMD_SIZE:
|
||||
SLI2_IOCB_CMD_SIZE;
|
||||
pring->sizeRiocb = phba->sli_rev == 3 ? SLI3_IOCB_RSP_SIZE:
|
||||
SLI2_IOCB_RSP_SIZE;
|
||||
/* A ring MUST have both cmd and rsp entries defined to be
|
||||
valid */
|
||||
if ((pring->numCiocb == 0) || (pring->numRiocb == 0)) {
|
||||
@@ -432,8 +437,7 @@ lpfc_config_pcb_setup(struct lpfc_hba * phba)
|
||||
continue;
|
||||
}
|
||||
/* Command ring setup for ring */
|
||||
pring->cmdringaddr =
|
||||
(void *)&phba->slim2p->IOCBs[iocbCnt];
|
||||
pring->cmdringaddr = (void *)&phba->slim2p->IOCBs[iocbCnt];
|
||||
pcbp->rdsc[i].cmdEntries = pring->numCiocb;
|
||||
|
||||
offset = (uint8_t *)&phba->slim2p->IOCBs[iocbCnt] -
|
||||
@@ -444,8 +448,7 @@ lpfc_config_pcb_setup(struct lpfc_hba * phba)
|
||||
iocbCnt += pring->numCiocb;
|
||||
|
||||
/* Response ring setup for ring */
|
||||
pring->rspringaddr =
|
||||
(void *)&phba->slim2p->IOCBs[iocbCnt];
|
||||
pring->rspringaddr = (void *)&phba->slim2p->IOCBs[iocbCnt];
|
||||
|
||||
pcbp->rdsc[i].rspEntries = pring->numRiocb;
|
||||
offset = (uint8_t *)&phba->slim2p->IOCBs[iocbCnt] -
|
||||
@@ -463,11 +466,103 @@ lpfc_read_rev(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
|
||||
MAILBOX_t *mb = &pmb->mb;
|
||||
memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
|
||||
mb->un.varRdRev.cv = 1;
|
||||
mb->un.varRdRev.v3req = 1; /* Request SLI3 info */
|
||||
mb->mbxCommand = MBX_READ_REV;
|
||||
mb->mbxOwner = OWN_HOST;
|
||||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
lpfc_build_hbq_profile2(struct config_hbq_var *hbqmb,
|
||||
struct lpfc_hbq_init *hbq_desc)
|
||||
{
|
||||
hbqmb->profiles.profile2.seqlenbcnt = hbq_desc->seqlenbcnt;
|
||||
hbqmb->profiles.profile2.maxlen = hbq_desc->maxlen;
|
||||
hbqmb->profiles.profile2.seqlenoff = hbq_desc->seqlenoff;
|
||||
}
|
||||
|
||||
static void
|
||||
lpfc_build_hbq_profile3(struct config_hbq_var *hbqmb,
|
||||
struct lpfc_hbq_init *hbq_desc)
|
||||
{
|
||||
hbqmb->profiles.profile3.seqlenbcnt = hbq_desc->seqlenbcnt;
|
||||
hbqmb->profiles.profile3.maxlen = hbq_desc->maxlen;
|
||||
hbqmb->profiles.profile3.cmdcodeoff = hbq_desc->cmdcodeoff;
|
||||
hbqmb->profiles.profile3.seqlenoff = hbq_desc->seqlenoff;
|
||||
memcpy(&hbqmb->profiles.profile3.cmdmatch, hbq_desc->cmdmatch,
|
||||
sizeof(hbqmb->profiles.profile3.cmdmatch));
|
||||
}
|
||||
|
||||
static void
|
||||
lpfc_build_hbq_profile5(struct config_hbq_var *hbqmb,
|
||||
struct lpfc_hbq_init *hbq_desc)
|
||||
{
|
||||
hbqmb->profiles.profile5.seqlenbcnt = hbq_desc->seqlenbcnt;
|
||||
hbqmb->profiles.profile5.maxlen = hbq_desc->maxlen;
|
||||
hbqmb->profiles.profile5.cmdcodeoff = hbq_desc->cmdcodeoff;
|
||||
hbqmb->profiles.profile5.seqlenoff = hbq_desc->seqlenoff;
|
||||
memcpy(&hbqmb->profiles.profile5.cmdmatch, hbq_desc->cmdmatch,
|
||||
sizeof(hbqmb->profiles.profile5.cmdmatch));
|
||||
}
|
||||
|
||||
void
|
||||
lpfc_config_hbq(struct lpfc_hba *phba, struct lpfc_hbq_init *hbq_desc,
|
||||
uint32_t hbq_entry_index, LPFC_MBOXQ_t *pmb)
|
||||
{
|
||||
int i;
|
||||
MAILBOX_t *mb = &pmb->mb;
|
||||
struct config_hbq_var *hbqmb = &mb->un.varCfgHbq;
|
||||
|
||||
memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
|
||||
hbqmb->entry_count = hbq_desc->entry_count; /* # entries in HBQ */
|
||||
hbqmb->recvNotify = hbq_desc->rn; /* Receive
|
||||
* Notification */
|
||||
hbqmb->numMask = hbq_desc->mask_count; /* # R_CTL/TYPE masks
|
||||
* # in words 0-19 */
|
||||
hbqmb->profile = hbq_desc->profile; /* Selection profile:
|
||||
* 0 = all,
|
||||
* 7 = logentry */
|
||||
hbqmb->ringMask = hbq_desc->ring_mask; /* Binds HBQ to a ring
|
||||
* e.g. Ring0=b0001,
|
||||
* ring2=b0100 */
|
||||
hbqmb->headerLen = hbq_desc->headerLen; /* 0 if not profile 4
|
||||
* or 5 */
|
||||
hbqmb->logEntry = hbq_desc->logEntry; /* Set to 1 if this
|
||||
* HBQ will be used
|
||||
* for LogEntry
|
||||
* buffers */
|
||||
hbqmb->hbqaddrLow = putPaddrLow(phba->hbqslimp.phys) +
|
||||
hbq_entry_index * sizeof(struct lpfc_hbq_entry);
|
||||
hbqmb->hbqaddrHigh = putPaddrHigh(phba->hbqslimp.phys);
|
||||
|
||||
mb->mbxCommand = MBX_CONFIG_HBQ;
|
||||
mb->mbxOwner = OWN_HOST;
|
||||
|
||||
/* Copy info for profiles 2,3,5. Other
|
||||
* profiles this area is reserved
|
||||
*/
|
||||
if (hbq_desc->profile == 2)
|
||||
lpfc_build_hbq_profile2(hbqmb, hbq_desc);
|
||||
else if (hbq_desc->profile == 3)
|
||||
lpfc_build_hbq_profile3(hbqmb, hbq_desc);
|
||||
else if (hbq_desc->profile == 5)
|
||||
lpfc_build_hbq_profile5(hbqmb, hbq_desc);
|
||||
|
||||
/* Return if no rctl / type masks for this HBQ */
|
||||
if (!hbq_desc->mask_count)
|
||||
return;
|
||||
|
||||
/* Otherwise we setup specific rctl / type masks for this HBQ */
|
||||
for (i = 0; i < hbq_desc->mask_count; i++) {
|
||||
hbqmb->hbqMasks[i].tmatch = hbq_desc->hbqMasks[i].tmatch;
|
||||
hbqmb->hbqMasks[i].tmask = hbq_desc->hbqMasks[i].tmask;
|
||||
hbqmb->hbqMasks[i].rctlmatch = hbq_desc->hbqMasks[i].rctlmatch;
|
||||
hbqmb->hbqMasks[i].rctlmask = hbq_desc->hbqMasks[i].rctlmask;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
lpfc_config_ring(struct lpfc_hba * phba, int ring, LPFC_MBOXQ_t * pmb)
|
||||
{
|
||||
@@ -512,13 +607,14 @@ lpfc_config_ring(struct lpfc_hba * phba, int ring, LPFC_MBOXQ_t * pmb)
|
||||
void
|
||||
lpfc_config_port(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
|
||||
{
|
||||
MAILBOX_t __iomem *mb_slim = (MAILBOX_t __iomem *) phba->MBslimaddr;
|
||||
MAILBOX_t *mb = &pmb->mb;
|
||||
dma_addr_t pdma_addr;
|
||||
uint32_t bar_low, bar_high;
|
||||
size_t offset;
|
||||
struct lpfc_hgp hgp;
|
||||
void __iomem *to_slim;
|
||||
int i;
|
||||
uint32_t pgp_offset;
|
||||
|
||||
memset(pmb, 0, sizeof(LPFC_MBOXQ_t));
|
||||
mb->mbxCommand = MBX_CONFIG_PORT;
|
||||
@@ -531,12 +627,21 @@ lpfc_config_port(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
|
||||
mb->un.varCfgPort.pcbLow = putPaddrLow(pdma_addr);
|
||||
mb->un.varCfgPort.pcbHigh = putPaddrHigh(pdma_addr);
|
||||
|
||||
/* If HBA supports SLI=3 ask for it */
|
||||
|
||||
mb->un.varCfgPort.sli_mode = phba->sli_rev;
|
||||
if (phba->sli_rev == 3) {
|
||||
mb->un.varCfgPort.cerbm = 1; /* Request HBQs */
|
||||
mb->un.varCfgPort.max_hbq = 1; /* Requesting 2 HBQs */
|
||||
}
|
||||
|
||||
/* Now setup pcb */
|
||||
phba->slim2p->pcb.type = TYPE_NATIVE_SLI2;
|
||||
phba->slim2p->pcb.feature = FEATURE_INITIAL_SLI2;
|
||||
|
||||
/* Setup Mailbox pointers */
|
||||
phba->slim2p->pcb.mailBoxSize = sizeof(MAILBOX_t);
|
||||
phba->slim2p->pcb.mailBoxSize = offsetof(MAILBOX_t, us) +
|
||||
sizeof(struct sli2_desc);
|
||||
offset = (uint8_t *)&phba->slim2p->mbx - (uint8_t *)phba->slim2p;
|
||||
pdma_addr = phba->slim2p_mapping + offset;
|
||||
phba->slim2p->pcb.mbAddrHigh = putPaddrHigh(pdma_addr);
|
||||
@@ -564,29 +669,70 @@ lpfc_config_port(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
|
||||
pci_read_config_dword(phba->pcidev, PCI_BASE_ADDRESS_0, &bar_low);
|
||||
pci_read_config_dword(phba->pcidev, PCI_BASE_ADDRESS_1, &bar_high);
|
||||
|
||||
/*
|
||||
* Set up HGP - Port Memory
|
||||
*
|
||||
* The port expects the host get/put pointers to reside in memory
|
||||
* following the "non-diagnostic" mode mailbox (32 words, 0x80 bytes)
|
||||
* area of SLIM. In SLI-2 mode, there's an additional 16 reserved
|
||||
* words (0x40 bytes). This area is not reserved if HBQs are
|
||||
* configured in SLI-3.
|
||||
*
|
||||
* CR0Put - SLI2(no HBQs) = 0xc0, With HBQs = 0x80
|
||||
* RR0Get 0xc4 0x84
|
||||
* CR1Put 0xc8 0x88
|
||||
* RR1Get 0xcc 0x8c
|
||||
* CR2Put 0xd0 0x90
|
||||
* RR2Get 0xd4 0x94
|
||||
* CR3Put 0xd8 0x98
|
||||
* RR3Get 0xdc 0x9c
|
||||
*
|
||||
* Reserved 0xa0-0xbf
|
||||
* If HBQs configured:
|
||||
* HBQ 0 Put ptr 0xc0
|
||||
* HBQ 1 Put ptr 0xc4
|
||||
* HBQ 2 Put ptr 0xc8
|
||||
* ......
|
||||
* HBQ(M-1)Put Pointer 0xc0+(M-1)*4
|
||||
*
|
||||
*/
|
||||
|
||||
if (phba->sli_rev == 3) {
|
||||
phba->host_gp = &mb_slim->us.s3.host[0];
|
||||
phba->hbq_put = &mb_slim->us.s3.hbq_put[0];
|
||||
} else {
|
||||
phba->host_gp = &mb_slim->us.s2.host[0];
|
||||
phba->hbq_put = NULL;
|
||||
}
|
||||
|
||||
/* mask off BAR0's flag bits 0 - 3 */
|
||||
phba->slim2p->pcb.hgpAddrLow = (bar_low & PCI_BASE_ADDRESS_MEM_MASK) +
|
||||
(SLIMOFF*sizeof(uint32_t));
|
||||
(void __iomem *) phba->host_gp -
|
||||
(void __iomem *)phba->MBslimaddr;
|
||||
if (bar_low & PCI_BASE_ADDRESS_MEM_TYPE_64)
|
||||
phba->slim2p->pcb.hgpAddrHigh = bar_high;
|
||||
else
|
||||
phba->slim2p->pcb.hgpAddrHigh = 0;
|
||||
/* write HGP data to SLIM at the required longword offset */
|
||||
memset(&hgp, 0, sizeof(struct lpfc_hgp));
|
||||
to_slim = phba->MBslimaddr + (SLIMOFF*sizeof (uint32_t));
|
||||
|
||||
for (i=0; i < phba->sli.num_rings; i++) {
|
||||
lpfc_memcpy_to_slim(to_slim, &hgp, sizeof(struct lpfc_hgp));
|
||||
to_slim += sizeof (struct lpfc_hgp);
|
||||
lpfc_memcpy_to_slim(phba->host_gp + i, &hgp,
|
||||
sizeof(*phba->host_gp));
|
||||
}
|
||||
|
||||
/* Setup Port Group ring pointer */
|
||||
offset = (uint8_t *)&phba->slim2p->mbx.us.s2.port -
|
||||
(uint8_t *)phba->slim2p;
|
||||
pdma_addr = phba->slim2p_mapping + offset;
|
||||
if (phba->sli_rev == 3)
|
||||
pgp_offset = (uint8_t *)&phba->slim2p->mbx.us.s3_pgp.port -
|
||||
(uint8_t *)phba->slim2p;
|
||||
else
|
||||
pgp_offset = (uint8_t *)&phba->slim2p->mbx.us.s2.port -
|
||||
(uint8_t *)phba->slim2p;
|
||||
|
||||
pdma_addr = phba->slim2p_mapping + pgp_offset;
|
||||
phba->slim2p->pcb.pgpAddrHigh = putPaddrHigh(pdma_addr);
|
||||
phba->slim2p->pcb.pgpAddrLow = putPaddrLow(pdma_addr);
|
||||
phba->hbq_get = &phba->slim2p->mbx.us.s3_pgp.hbq_get[0];
|
||||
|
||||
/* Use callback routine to setp rings in the pcb */
|
||||
lpfc_config_pcb_setup(phba);
|
||||
@@ -603,10 +749,6 @@ lpfc_config_port(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
|
||||
/* Swap PCB if needed */
|
||||
lpfc_sli_pcimem_bcopy(&phba->slim2p->pcb, &phba->slim2p->pcb,
|
||||
sizeof (PCB_t));
|
||||
|
||||
lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
|
||||
"%d:0405 Service Level Interface (SLI) 2 selected\n",
|
||||
phba->brd_no);
|
||||
}
|
||||
|
||||
void
|
||||
|
Reference in New Issue
Block a user