diff options
author | James Smart <James.Smart@Emulex.Com> | 2007-06-18 04:56:37 +0400 |
---|---|---|
committer | James Bottomley <jejb@mulgrave.il.steeleye.com> | 2007-06-18 07:06:27 +0400 |
commit | ed957684294618602b48f1950b0c9bbcb036583f (patch) | |
tree | 4e88dbb2e55013f973ad94099e2963dd507ea719 /drivers/scsi/lpfc/lpfc_mbox.c | |
parent | 2e0fef85e098f6794956b8b80b111179fbb4cbb7 (diff) | |
download | linux-ed957684294618602b48f1950b0c9bbcb036583f.tar.xz |
[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>
Diffstat (limited to 'drivers/scsi/lpfc/lpfc_mbox.c')
-rw-r--r-- | drivers/scsi/lpfc/lpfc_mbox.c | 176 |
1 files changed, 159 insertions, 17 deletions
diff --git a/drivers/scsi/lpfc/lpfc_mbox.c b/drivers/scsi/lpfc/lpfc_mbox.c index 86757ec53057..977799c2b2c2 100644 --- a/drivers/scsi/lpfc/lpfc_mbox.c +++ b/drivers/scsi/lpfc/lpfc_mbox.c @@ -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 |