diff options
author | James Smart <James.Smart@Emulex.Com> | 2007-06-17 20:56:37 -0400 |
---|---|---|
committer | James Bottomley <jejb@mulgrave.il.steeleye.com> | 2007-06-17 23:06:27 -0400 |
commit | ed957684294618602b48f1950b0c9bbcb036583f (patch) | |
tree | 4e88dbb2e55013f973ad94099e2963dd507ea719 /drivers/scsi/lpfc/lpfc_mbox.c | |
parent | 2e0fef85e098f6794956b8b80b111179fbb4cbb7 (diff) |
[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, | |||
232 | mb->mbxCommand = (volatile uint8_t)MBX_INIT_LINK; | 232 | mb->mbxCommand = (volatile uint8_t)MBX_INIT_LINK; |
233 | mb->mbxOwner = OWN_HOST; | 233 | mb->mbxOwner = OWN_HOST; |
234 | mb->un.varInitLnk.fabric_AL_PA = phba->fc_pref_ALPA; | 234 | mb->un.varInitLnk.fabric_AL_PA = phba->fc_pref_ALPA; |
235 | mb->un.varInitLnk.link_flags |= FLAGS_UNREG_LOGIN_ALL; | ||
235 | return; | 236 | return; |
236 | } | 237 | } |
237 | 238 | ||
@@ -418,6 +419,10 @@ lpfc_config_pcb_setup(struct lpfc_hba * phba) | |||
418 | for (i = 0; i < psli->num_rings; i++) { | 419 | for (i = 0; i < psli->num_rings; i++) { |
419 | pring = &psli->ring[i]; | 420 | pring = &psli->ring[i]; |
420 | 421 | ||
422 | pring->sizeCiocb = phba->sli_rev == 3 ? SLI3_IOCB_CMD_SIZE: | ||
423 | SLI2_IOCB_CMD_SIZE; | ||
424 | pring->sizeRiocb = phba->sli_rev == 3 ? SLI3_IOCB_RSP_SIZE: | ||
425 | SLI2_IOCB_RSP_SIZE; | ||
421 | /* A ring MUST have both cmd and rsp entries defined to be | 426 | /* A ring MUST have both cmd and rsp entries defined to be |
422 | valid */ | 427 | valid */ |
423 | if ((pring->numCiocb == 0) || (pring->numRiocb == 0)) { | 428 | if ((pring->numCiocb == 0) || (pring->numRiocb == 0)) { |
@@ -432,8 +437,7 @@ lpfc_config_pcb_setup(struct lpfc_hba * phba) | |||
432 | continue; | 437 | continue; |
433 | } | 438 | } |
434 | /* Command ring setup for ring */ | 439 | /* Command ring setup for ring */ |
435 | pring->cmdringaddr = | 440 | pring->cmdringaddr = (void *)&phba->slim2p->IOCBs[iocbCnt]; |
436 | (void *)&phba->slim2p->IOCBs[iocbCnt]; | ||
437 | pcbp->rdsc[i].cmdEntries = pring->numCiocb; | 441 | pcbp->rdsc[i].cmdEntries = pring->numCiocb; |
438 | 442 | ||
439 | offset = (uint8_t *)&phba->slim2p->IOCBs[iocbCnt] - | 443 | offset = (uint8_t *)&phba->slim2p->IOCBs[iocbCnt] - |
@@ -444,8 +448,7 @@ lpfc_config_pcb_setup(struct lpfc_hba * phba) | |||
444 | iocbCnt += pring->numCiocb; | 448 | iocbCnt += pring->numCiocb; |
445 | 449 | ||
446 | /* Response ring setup for ring */ | 450 | /* Response ring setup for ring */ |
447 | pring->rspringaddr = | 451 | pring->rspringaddr = (void *)&phba->slim2p->IOCBs[iocbCnt]; |
448 | (void *)&phba->slim2p->IOCBs[iocbCnt]; | ||
449 | 452 | ||
450 | pcbp->rdsc[i].rspEntries = pring->numRiocb; | 453 | pcbp->rdsc[i].rspEntries = pring->numRiocb; |
451 | offset = (uint8_t *)&phba->slim2p->IOCBs[iocbCnt] - | 454 | offset = (uint8_t *)&phba->slim2p->IOCBs[iocbCnt] - |
@@ -463,11 +466,103 @@ lpfc_read_rev(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) | |||
463 | MAILBOX_t *mb = &pmb->mb; | 466 | MAILBOX_t *mb = &pmb->mb; |
464 | memset(pmb, 0, sizeof (LPFC_MBOXQ_t)); | 467 | memset(pmb, 0, sizeof (LPFC_MBOXQ_t)); |
465 | mb->un.varRdRev.cv = 1; | 468 | mb->un.varRdRev.cv = 1; |
469 | mb->un.varRdRev.v3req = 1; /* Request SLI3 info */ | ||
466 | mb->mbxCommand = MBX_READ_REV; | 470 | mb->mbxCommand = MBX_READ_REV; |
467 | mb->mbxOwner = OWN_HOST; | 471 | mb->mbxOwner = OWN_HOST; |
468 | return; | 472 | return; |
469 | } | 473 | } |
470 | 474 | ||
475 | static void | ||
476 | lpfc_build_hbq_profile2(struct config_hbq_var *hbqmb, | ||
477 | struct lpfc_hbq_init *hbq_desc) | ||
478 | { | ||
479 | hbqmb->profiles.profile2.seqlenbcnt = hbq_desc->seqlenbcnt; | ||
480 | hbqmb->profiles.profile2.maxlen = hbq_desc->maxlen; | ||
481 | hbqmb->profiles.profile2.seqlenoff = hbq_desc->seqlenoff; | ||
482 | } | ||
483 | |||
484 | static void | ||
485 | lpfc_build_hbq_profile3(struct config_hbq_var *hbqmb, | ||
486 | struct lpfc_hbq_init *hbq_desc) | ||
487 | { | ||
488 | hbqmb->profiles.profile3.seqlenbcnt = hbq_desc->seqlenbcnt; | ||
489 | hbqmb->profiles.profile3.maxlen = hbq_desc->maxlen; | ||
490 | hbqmb->profiles.profile3.cmdcodeoff = hbq_desc->cmdcodeoff; | ||
491 | hbqmb->profiles.profile3.seqlenoff = hbq_desc->seqlenoff; | ||
492 | memcpy(&hbqmb->profiles.profile3.cmdmatch, hbq_desc->cmdmatch, | ||
493 | sizeof(hbqmb->profiles.profile3.cmdmatch)); | ||
494 | } | ||
495 | |||
496 | static void | ||
497 | lpfc_build_hbq_profile5(struct config_hbq_var *hbqmb, | ||
498 | struct lpfc_hbq_init *hbq_desc) | ||
499 | { | ||
500 | hbqmb->profiles.profile5.seqlenbcnt = hbq_desc->seqlenbcnt; | ||
501 | hbqmb->profiles.profile5.maxlen = hbq_desc->maxlen; | ||
502 | hbqmb->profiles.profile5.cmdcodeoff = hbq_desc->cmdcodeoff; | ||
503 | hbqmb->profiles.profile5.seqlenoff = hbq_desc->seqlenoff; | ||
504 | memcpy(&hbqmb->profiles.profile5.cmdmatch, hbq_desc->cmdmatch, | ||
505 | sizeof(hbqmb->profiles.profile5.cmdmatch)); | ||
506 | } | ||
507 | |||
508 | void | ||
509 | lpfc_config_hbq(struct lpfc_hba *phba, struct lpfc_hbq_init *hbq_desc, | ||
510 | uint32_t hbq_entry_index, LPFC_MBOXQ_t *pmb) | ||
511 | { | ||
512 | int i; | ||
513 | MAILBOX_t *mb = &pmb->mb; | ||
514 | struct config_hbq_var *hbqmb = &mb->un.varCfgHbq; | ||
515 | |||
516 | memset(pmb, 0, sizeof (LPFC_MBOXQ_t)); | ||
517 | hbqmb->entry_count = hbq_desc->entry_count; /* # entries in HBQ */ | ||
518 | hbqmb->recvNotify = hbq_desc->rn; /* Receive | ||
519 | * Notification */ | ||
520 | hbqmb->numMask = hbq_desc->mask_count; /* # R_CTL/TYPE masks | ||
521 | * # in words 0-19 */ | ||
522 | hbqmb->profile = hbq_desc->profile; /* Selection profile: | ||
523 | * 0 = all, | ||
524 | * 7 = logentry */ | ||
525 | hbqmb->ringMask = hbq_desc->ring_mask; /* Binds HBQ to a ring | ||
526 | * e.g. Ring0=b0001, | ||
527 | * ring2=b0100 */ | ||
528 | hbqmb->headerLen = hbq_desc->headerLen; /* 0 if not profile 4 | ||
529 | * or 5 */ | ||
530 | hbqmb->logEntry = hbq_desc->logEntry; /* Set to 1 if this | ||
531 | * HBQ will be used | ||
532 | * for LogEntry | ||
533 | * buffers */ | ||
534 | hbqmb->hbqaddrLow = putPaddrLow(phba->hbqslimp.phys) + | ||
535 | hbq_entry_index * sizeof(struct lpfc_hbq_entry); | ||
536 | hbqmb->hbqaddrHigh = putPaddrHigh(phba->hbqslimp.phys); | ||
537 | |||
538 | mb->mbxCommand = MBX_CONFIG_HBQ; | ||
539 | mb->mbxOwner = OWN_HOST; | ||
540 | |||
541 | /* Copy info for profiles 2,3,5. Other | ||
542 | * profiles this area is reserved | ||
543 | */ | ||
544 | if (hbq_desc->profile == 2) | ||
545 | lpfc_build_hbq_profile2(hbqmb, hbq_desc); | ||
546 | else if (hbq_desc->profile == 3) | ||
547 | lpfc_build_hbq_profile3(hbqmb, hbq_desc); | ||
548 | else if (hbq_desc->profile == 5) | ||
549 | lpfc_build_hbq_profile5(hbqmb, hbq_desc); | ||
550 | |||
551 | /* Return if no rctl / type masks for this HBQ */ | ||
552 | if (!hbq_desc->mask_count) | ||
553 | return; | ||
554 | |||
555 | /* Otherwise we setup specific rctl / type masks for this HBQ */ | ||
556 | for (i = 0; i < hbq_desc->mask_count; i++) { | ||
557 | hbqmb->hbqMasks[i].tmatch = hbq_desc->hbqMasks[i].tmatch; | ||
558 | hbqmb->hbqMasks[i].tmask = hbq_desc->hbqMasks[i].tmask; | ||
559 | hbqmb->hbqMasks[i].rctlmatch = hbq_desc->hbqMasks[i].rctlmatch; | ||
560 | hbqmb->hbqMasks[i].rctlmask = hbq_desc->hbqMasks[i].rctlmask; | ||
561 | } | ||
562 | |||
563 | return; | ||
564 | } | ||
565 | |||
471 | void | 566 | void |
472 | lpfc_config_ring(struct lpfc_hba * phba, int ring, LPFC_MBOXQ_t * pmb) | 567 | lpfc_config_ring(struct lpfc_hba * phba, int ring, LPFC_MBOXQ_t * pmb) |
473 | { | 568 | { |
@@ -512,13 +607,14 @@ lpfc_config_ring(struct lpfc_hba * phba, int ring, LPFC_MBOXQ_t * pmb) | |||
512 | void | 607 | void |
513 | lpfc_config_port(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) | 608 | lpfc_config_port(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) |
514 | { | 609 | { |
610 | MAILBOX_t __iomem *mb_slim = (MAILBOX_t __iomem *) phba->MBslimaddr; | ||
515 | MAILBOX_t *mb = &pmb->mb; | 611 | MAILBOX_t *mb = &pmb->mb; |
516 | dma_addr_t pdma_addr; | 612 | dma_addr_t pdma_addr; |
517 | uint32_t bar_low, bar_high; | 613 | uint32_t bar_low, bar_high; |
518 | size_t offset; | 614 | size_t offset; |
519 | struct lpfc_hgp hgp; | 615 | struct lpfc_hgp hgp; |
520 | void __iomem *to_slim; | ||
521 | int i; | 616 | int i; |
617 | uint32_t pgp_offset; | ||
522 | 618 | ||
523 | memset(pmb, 0, sizeof(LPFC_MBOXQ_t)); | 619 | memset(pmb, 0, sizeof(LPFC_MBOXQ_t)); |
524 | mb->mbxCommand = MBX_CONFIG_PORT; | 620 | mb->mbxCommand = MBX_CONFIG_PORT; |
@@ -531,12 +627,21 @@ lpfc_config_port(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) | |||
531 | mb->un.varCfgPort.pcbLow = putPaddrLow(pdma_addr); | 627 | mb->un.varCfgPort.pcbLow = putPaddrLow(pdma_addr); |
532 | mb->un.varCfgPort.pcbHigh = putPaddrHigh(pdma_addr); | 628 | mb->un.varCfgPort.pcbHigh = putPaddrHigh(pdma_addr); |
533 | 629 | ||
630 | /* If HBA supports SLI=3 ask for it */ | ||
631 | |||
632 | mb->un.varCfgPort.sli_mode = phba->sli_rev; | ||
633 | if (phba->sli_rev == 3) { | ||
634 | mb->un.varCfgPort.cerbm = 1; /* Request HBQs */ | ||
635 | mb->un.varCfgPort.max_hbq = 1; /* Requesting 2 HBQs */ | ||
636 | } | ||
637 | |||
534 | /* Now setup pcb */ | 638 | /* Now setup pcb */ |
535 | phba->slim2p->pcb.type = TYPE_NATIVE_SLI2; | 639 | phba->slim2p->pcb.type = TYPE_NATIVE_SLI2; |
536 | phba->slim2p->pcb.feature = FEATURE_INITIAL_SLI2; | 640 | phba->slim2p->pcb.feature = FEATURE_INITIAL_SLI2; |
537 | 641 | ||
538 | /* Setup Mailbox pointers */ | 642 | /* Setup Mailbox pointers */ |
539 | phba->slim2p->pcb.mailBoxSize = sizeof(MAILBOX_t); | 643 | phba->slim2p->pcb.mailBoxSize = offsetof(MAILBOX_t, us) + |
644 | sizeof(struct sli2_desc); | ||
540 | offset = (uint8_t *)&phba->slim2p->mbx - (uint8_t *)phba->slim2p; | 645 | offset = (uint8_t *)&phba->slim2p->mbx - (uint8_t *)phba->slim2p; |
541 | pdma_addr = phba->slim2p_mapping + offset; | 646 | pdma_addr = phba->slim2p_mapping + offset; |
542 | phba->slim2p->pcb.mbAddrHigh = putPaddrHigh(pdma_addr); | 647 | phba->slim2p->pcb.mbAddrHigh = putPaddrHigh(pdma_addr); |
@@ -564,29 +669,70 @@ lpfc_config_port(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) | |||
564 | pci_read_config_dword(phba->pcidev, PCI_BASE_ADDRESS_0, &bar_low); | 669 | pci_read_config_dword(phba->pcidev, PCI_BASE_ADDRESS_0, &bar_low); |
565 | pci_read_config_dword(phba->pcidev, PCI_BASE_ADDRESS_1, &bar_high); | 670 | pci_read_config_dword(phba->pcidev, PCI_BASE_ADDRESS_1, &bar_high); |
566 | 671 | ||
672 | /* | ||
673 | * Set up HGP - Port Memory | ||
674 | * | ||
675 | * The port expects the host get/put pointers to reside in memory | ||
676 | * following the "non-diagnostic" mode mailbox (32 words, 0x80 bytes) | ||
677 | * area of SLIM. In SLI-2 mode, there's an additional 16 reserved | ||
678 | * words (0x40 bytes). This area is not reserved if HBQs are | ||
679 | * configured in SLI-3. | ||
680 | * | ||
681 | * CR0Put - SLI2(no HBQs) = 0xc0, With HBQs = 0x80 | ||
682 | * RR0Get 0xc4 0x84 | ||
683 | * CR1Put 0xc8 0x88 | ||
684 | * RR1Get 0xcc 0x8c | ||
685 | * CR2Put 0xd0 0x90 | ||
686 | * RR2Get 0xd4 0x94 | ||
687 | * CR3Put 0xd8 0x98 | ||
688 | * RR3Get 0xdc 0x9c | ||
689 | * | ||
690 | * Reserved 0xa0-0xbf | ||
691 | * If HBQs configured: | ||
692 | * HBQ 0 Put ptr 0xc0 | ||
693 | * HBQ 1 Put ptr 0xc4 | ||
694 | * HBQ 2 Put ptr 0xc8 | ||
695 | * ...... | ||
696 | * HBQ(M-1)Put Pointer 0xc0+(M-1)*4 | ||
697 | * | ||
698 | */ | ||
699 | |||
700 | if (phba->sli_rev == 3) { | ||
701 | phba->host_gp = &mb_slim->us.s3.host[0]; | ||
702 | phba->hbq_put = &mb_slim->us.s3.hbq_put[0]; | ||
703 | } else { | ||
704 | phba->host_gp = &mb_slim->us.s2.host[0]; | ||
705 | phba->hbq_put = NULL; | ||
706 | } | ||
567 | 707 | ||
568 | /* mask off BAR0's flag bits 0 - 3 */ | 708 | /* mask off BAR0's flag bits 0 - 3 */ |
569 | phba->slim2p->pcb.hgpAddrLow = (bar_low & PCI_BASE_ADDRESS_MEM_MASK) + | 709 | phba->slim2p->pcb.hgpAddrLow = (bar_low & PCI_BASE_ADDRESS_MEM_MASK) + |
570 | (SLIMOFF*sizeof(uint32_t)); | 710 | (void __iomem *) phba->host_gp - |
711 | (void __iomem *)phba->MBslimaddr; | ||
571 | if (bar_low & PCI_BASE_ADDRESS_MEM_TYPE_64) | 712 | if (bar_low & PCI_BASE_ADDRESS_MEM_TYPE_64) |
572 | phba->slim2p->pcb.hgpAddrHigh = bar_high; | 713 | phba->slim2p->pcb.hgpAddrHigh = bar_high; |
573 | else | 714 | else |
574 | phba->slim2p->pcb.hgpAddrHigh = 0; | 715 | phba->slim2p->pcb.hgpAddrHigh = 0; |
575 | /* write HGP data to SLIM at the required longword offset */ | 716 | /* write HGP data to SLIM at the required longword offset */ |
576 | memset(&hgp, 0, sizeof(struct lpfc_hgp)); | 717 | memset(&hgp, 0, sizeof(struct lpfc_hgp)); |
577 | to_slim = phba->MBslimaddr + (SLIMOFF*sizeof (uint32_t)); | ||
578 | 718 | ||
579 | for (i=0; i < phba->sli.num_rings; i++) { | 719 | for (i=0; i < phba->sli.num_rings; i++) { |
580 | lpfc_memcpy_to_slim(to_slim, &hgp, sizeof(struct lpfc_hgp)); | 720 | lpfc_memcpy_to_slim(phba->host_gp + i, &hgp, |
581 | to_slim += sizeof (struct lpfc_hgp); | 721 | sizeof(*phba->host_gp)); |
582 | } | 722 | } |
583 | 723 | ||
584 | /* Setup Port Group ring pointer */ | 724 | /* Setup Port Group ring pointer */ |
585 | offset = (uint8_t *)&phba->slim2p->mbx.us.s2.port - | 725 | if (phba->sli_rev == 3) |
586 | (uint8_t *)phba->slim2p; | 726 | pgp_offset = (uint8_t *)&phba->slim2p->mbx.us.s3_pgp.port - |
587 | pdma_addr = phba->slim2p_mapping + offset; | 727 | (uint8_t *)phba->slim2p; |
728 | else | ||
729 | pgp_offset = (uint8_t *)&phba->slim2p->mbx.us.s2.port - | ||
730 | (uint8_t *)phba->slim2p; | ||
731 | |||
732 | pdma_addr = phba->slim2p_mapping + pgp_offset; | ||
588 | phba->slim2p->pcb.pgpAddrHigh = putPaddrHigh(pdma_addr); | 733 | phba->slim2p->pcb.pgpAddrHigh = putPaddrHigh(pdma_addr); |
589 | phba->slim2p->pcb.pgpAddrLow = putPaddrLow(pdma_addr); | 734 | phba->slim2p->pcb.pgpAddrLow = putPaddrLow(pdma_addr); |
735 | phba->hbq_get = &phba->slim2p->mbx.us.s3_pgp.hbq_get[0]; | ||
590 | 736 | ||
591 | /* Use callback routine to setp rings in the pcb */ | 737 | /* Use callback routine to setp rings in the pcb */ |
592 | lpfc_config_pcb_setup(phba); | 738 | lpfc_config_pcb_setup(phba); |
@@ -603,10 +749,6 @@ lpfc_config_port(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) | |||
603 | /* Swap PCB if needed */ | 749 | /* Swap PCB if needed */ |
604 | lpfc_sli_pcimem_bcopy(&phba->slim2p->pcb, &phba->slim2p->pcb, | 750 | lpfc_sli_pcimem_bcopy(&phba->slim2p->pcb, &phba->slim2p->pcb, |
605 | sizeof (PCB_t)); | 751 | sizeof (PCB_t)); |
606 | |||
607 | lpfc_printf_log(phba, KERN_INFO, LOG_INIT, | ||
608 | "%d:0405 Service Level Interface (SLI) 2 selected\n", | ||
609 | phba->brd_no); | ||
610 | } | 752 | } |
611 | 753 | ||
612 | void | 754 | void |