aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/lpfc/lpfc_els.c
diff options
context:
space:
mode:
authorJamie Wellnitz <Jamie.Wellnitz@emulex.com>2006-02-28 19:25:15 -0500
committerJames Bottomley <jejb@mulgrave.il.steeleye.com>2006-02-28 19:52:50 -0500
commit7bb3b137abf2b7073e683c14cfe062d811d35247 (patch)
tree3293962805fc790ef90fd5aa28171cb419dd82c4 /drivers/scsi/lpfc/lpfc_els.c
parent0228aadd0fb1d8ca90efbe74291f3b5b753c2da2 (diff)
[SCSI] lpfc 8.1.2: Handling of ELS commands RRQ, RPS, RPL and LIRR correctly
Handling of ELS commands RRQ, RPS, RPL and LIRR correctly Signed-off-by: Jamie Wellnitz <Jamie.Wellnitz@emulex.com> Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
Diffstat (limited to 'drivers/scsi/lpfc/lpfc_els.c')
-rw-r--r--drivers/scsi/lpfc/lpfc_els.c274
1 files changed, 248 insertions, 26 deletions
diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c
index 20f1a0713db2..9c9e7661de59 100644
--- a/drivers/scsi/lpfc/lpfc_els.c
+++ b/drivers/scsi/lpfc/lpfc_els.c
@@ -2654,41 +2654,243 @@ lpfc_els_rcv_rnid(struct lpfc_hba * phba,
2654} 2654}
2655 2655
2656static int 2656static int
2657lpfc_els_rcv_rrq(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb, 2657lpfc_els_rcv_lirr(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
2658 struct lpfc_nodelist * ndlp)
2659{
2660 struct ls_rjt stat;
2661
2662 /* For now, unconditionally reject this command */
2663 stat.un.b.lsRjtRsvd0 = 0;
2664 stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
2665 stat.un.b.lsRjtRsnCodeExp = LSEXP_CANT_GIVE_DATA;
2666 stat.un.b.vendorUnique = 0;
2667 lpfc_els_rsp_reject(phba, stat.un.lsRjtError, cmdiocb, ndlp);
2668 return 0;
2669}
2670
2671void
2672lpfc_els_rsp_rps_acc(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
2673{
2674 struct lpfc_sli *psli;
2675 struct lpfc_sli_ring *pring;
2676 MAILBOX_t *mb;
2677 IOCB_t *icmd;
2678 RPS_RSP *rps_rsp;
2679 uint8_t *pcmd;
2680 struct lpfc_iocbq *elsiocb;
2681 struct lpfc_nodelist *ndlp;
2682 uint16_t xri, status;
2683 uint32_t cmdsize;
2684
2685 psli = &phba->sli;
2686 pring = &psli->ring[LPFC_ELS_RING];
2687 mb = &pmb->mb;
2688
2689 ndlp = (struct lpfc_nodelist *) pmb->context2;
2690 xri = (uint16_t) ((unsigned long)(pmb->context1));
2691 pmb->context1 = 0;
2692 pmb->context2 = 0;
2693
2694 if (mb->mbxStatus) {
2695 mempool_free( pmb, phba->mbox_mem_pool);
2696 return;
2697 }
2698
2699 cmdsize = sizeof(RPS_RSP) + sizeof(uint32_t);
2700 mempool_free( pmb, phba->mbox_mem_pool);
2701 if ((elsiocb = lpfc_prep_els_iocb(phba, 0, cmdsize, 3,
2702 ndlp, ELS_CMD_ACC)) == 0) {
2703 return;
2704 }
2705
2706 icmd = &elsiocb->iocb;
2707 icmd->ulpContext = xri;
2708
2709 pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
2710 *((uint32_t *) (pcmd)) = ELS_CMD_ACC;
2711 pcmd += sizeof (uint32_t); /* Skip past command */
2712 rps_rsp = (RPS_RSP *)pcmd;
2713
2714 if (phba->fc_topology != TOPOLOGY_LOOP)
2715 status = 0x10;
2716 else
2717 status = 0x8;
2718 if (phba->fc_flag & FC_FABRIC)
2719 status |= 0x4;
2720
2721 rps_rsp->rsvd1 = 0;
2722 rps_rsp->portStatus = be16_to_cpu(status);
2723 rps_rsp->linkFailureCnt = be32_to_cpu(mb->un.varRdLnk.linkFailureCnt);
2724 rps_rsp->lossSyncCnt = be32_to_cpu(mb->un.varRdLnk.lossSyncCnt);
2725 rps_rsp->lossSignalCnt = be32_to_cpu(mb->un.varRdLnk.lossSignalCnt);
2726 rps_rsp->primSeqErrCnt = be32_to_cpu(mb->un.varRdLnk.primSeqErrCnt);
2727 rps_rsp->invalidXmitWord = be32_to_cpu(mb->un.varRdLnk.invalidXmitWord);
2728 rps_rsp->crcCnt = be32_to_cpu(mb->un.varRdLnk.crcCnt);
2729
2730 /* Xmit ELS RPS ACC response tag <ulpIoTag> */
2731 lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
2732 "%d:0128 Xmit ELS RPS ACC response tag x%x "
2733 "Data: x%x x%x x%x x%x x%x\n",
2734 phba->brd_no,
2735 elsiocb->iocb.ulpIoTag,
2736 elsiocb->iocb.ulpContext, ndlp->nlp_DID,
2737 ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi);
2738
2739 elsiocb->iocb_cmpl = lpfc_cmpl_els_acc;
2740 phba->fc_stat.elsXmitACC++;
2741 if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) {
2742 lpfc_els_free_iocb(phba, elsiocb);
2743 }
2744 return;
2745}
2746
2747static int
2748lpfc_els_rcv_rps(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
2658 struct lpfc_nodelist * ndlp) 2749 struct lpfc_nodelist * ndlp)
2659{ 2750{
2660 struct lpfc_dmabuf *pcmd;
2661 uint32_t *lp; 2751 uint32_t *lp;
2752 uint8_t flag;
2753 LPFC_MBOXQ_t *mbox;
2754 struct lpfc_dmabuf *pcmd;
2755 RPS *rps;
2756 struct ls_rjt stat;
2757
2758 if((ndlp->nlp_state != NLP_STE_UNMAPPED_NODE) &&
2759 (ndlp->nlp_state != NLP_STE_MAPPED_NODE)) {
2760 stat.un.b.lsRjtRsvd0 = 0;
2761 stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
2762 stat.un.b.lsRjtRsnCodeExp = LSEXP_CANT_GIVE_DATA;
2763 stat.un.b.vendorUnique = 0;
2764 lpfc_els_rsp_reject(phba, stat.un.lsRjtError, cmdiocb, ndlp);
2765 }
2766
2767 pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
2768 lp = (uint32_t *) pcmd->virt;
2769 flag = (be32_to_cpu(*lp++) & 0xf);
2770 rps = (RPS *) lp;
2771
2772 if ((flag == 0) ||
2773 ((flag == 1) && (be32_to_cpu(rps->un.portNum) == 0)) ||
2774 ((flag == 2) && (memcmp(&rps->un.portName, &phba->fc_portname,
2775 sizeof (struct lpfc_name)) == 0))) {
2776 if ((mbox = mempool_alloc(phba->mbox_mem_pool, GFP_ATOMIC))) {
2777 lpfc_read_lnk_stat(phba, mbox);
2778 mbox->context1 =
2779 (void *)((unsigned long)cmdiocb->iocb.ulpContext);
2780 mbox->context2 = ndlp;
2781 mbox->mbox_cmpl = lpfc_els_rsp_rps_acc;
2782 if (lpfc_sli_issue_mbox (phba, mbox,
2783 (MBX_NOWAIT | MBX_STOP_IOCB)) != MBX_NOT_FINISHED) {
2784 /* Mbox completion will send ELS Response */
2785 return 0;
2786 }
2787 mempool_free(mbox, phba->mbox_mem_pool);
2788 }
2789 }
2790 stat.un.b.lsRjtRsvd0 = 0;
2791 stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
2792 stat.un.b.lsRjtRsnCodeExp = LSEXP_CANT_GIVE_DATA;
2793 stat.un.b.vendorUnique = 0;
2794 lpfc_els_rsp_reject(phba, stat.un.lsRjtError, cmdiocb, ndlp);
2795 return 0;
2796}
2797
2798int
2799lpfc_els_rsp_rpl_acc(struct lpfc_hba * phba, uint16_t cmdsize,
2800 struct lpfc_iocbq * oldiocb, struct lpfc_nodelist * ndlp)
2801{
2662 IOCB_t *icmd; 2802 IOCB_t *icmd;
2803 IOCB_t *oldcmd;
2804 RPL_RSP rpl_rsp;
2805 struct lpfc_iocbq *elsiocb;
2663 struct lpfc_sli_ring *pring; 2806 struct lpfc_sli_ring *pring;
2664 struct lpfc_sli *psli; 2807 struct lpfc_sli *psli;
2665 RRQ *rrq; 2808 uint8_t *pcmd;
2666 uint32_t cmd, did;
2667 2809
2668 psli = &phba->sli; 2810 psli = &phba->sli;
2669 pring = &psli->ring[LPFC_FCP_RING]; 2811 pring = &psli->ring[LPFC_ELS_RING]; /* ELS ring */
2670 icmd = &cmdiocb->iocb; 2812
2671 did = icmd->un.elsreq64.remoteID; 2813 if ((elsiocb =
2814 lpfc_prep_els_iocb(phba, 0, cmdsize, oldiocb->retry,
2815 ndlp, ELS_CMD_ACC)) == 0) {
2816 return 1;
2817 }
2818 icmd = &elsiocb->iocb;
2819 oldcmd = &oldiocb->iocb;
2820 icmd->ulpContext = oldcmd->ulpContext; /* Xri */
2821
2822 pcmd = (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
2823 *((uint32_t *) (pcmd)) = ELS_CMD_ACC;
2824 pcmd += sizeof (uint16_t);
2825 *((uint16_t *)(pcmd)) = be16_to_cpu(cmdsize);
2826 pcmd += sizeof(uint16_t);
2827
2828 /* Setup the RPL ACC payload */
2829 rpl_rsp.listLen = be32_to_cpu(1);
2830 rpl_rsp.index = 0;
2831 rpl_rsp.port_num_blk.portNum = 0;
2832 rpl_rsp.port_num_blk.portID = be32_to_cpu(phba->fc_myDID);
2833 memcpy(&rpl_rsp.port_num_blk.portName, &phba->fc_portname,
2834 sizeof(struct lpfc_name));
2835
2836 memcpy(pcmd, &rpl_rsp, cmdsize - sizeof(uint32_t));
2837
2838
2839 /* Xmit ELS RPL ACC response tag <ulpIoTag> */
2840 lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
2841 "%d:0128 Xmit ELS RPL ACC response tag x%x "
2842 "Data: x%x x%x x%x x%x x%x\n",
2843 phba->brd_no,
2844 elsiocb->iocb.ulpIoTag,
2845 elsiocb->iocb.ulpContext, ndlp->nlp_DID,
2846 ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi);
2847
2848 elsiocb->iocb_cmpl = lpfc_cmpl_els_acc;
2849
2850 phba->fc_stat.elsXmitACC++;
2851 if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) {
2852 lpfc_els_free_iocb(phba, elsiocb);
2853 return 1;
2854 }
2855 return 0;
2856}
2857
2858static int
2859lpfc_els_rcv_rpl(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
2860 struct lpfc_nodelist * ndlp)
2861{
2862 struct lpfc_dmabuf *pcmd;
2863 uint32_t *lp;
2864 uint32_t maxsize;
2865 uint16_t cmdsize;
2866 RPL *rpl;
2867 struct ls_rjt stat;
2868
2869 if((ndlp->nlp_state != NLP_STE_UNMAPPED_NODE) &&
2870 (ndlp->nlp_state != NLP_STE_MAPPED_NODE)) {
2871 stat.un.b.lsRjtRsvd0 = 0;
2872 stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
2873 stat.un.b.lsRjtRsnCodeExp = LSEXP_CANT_GIVE_DATA;
2874 stat.un.b.vendorUnique = 0;
2875 lpfc_els_rsp_reject(phba, stat.un.lsRjtError, cmdiocb, ndlp);
2876 }
2877
2672 pcmd = (struct lpfc_dmabuf *) cmdiocb->context2; 2878 pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
2673 lp = (uint32_t *) pcmd->virt; 2879 lp = (uint32_t *) pcmd->virt;
2880 rpl = (RPL *) (lp + 1);
2674 2881
2675 cmd = *lp++; 2882 maxsize = be32_to_cpu(rpl->maxsize);
2676 rrq = (RRQ *) lp;
2677 2883
2678 /* RRQ received */ 2884 /* We support only one port */
2679 /* Get oxid / rxid from payload and abort it */ 2885 if ((rpl->index == 0) &&
2680 spin_lock_irq(phba->host->host_lock); 2886 ((maxsize == 0) ||
2681 if ((rrq->SID == be32_to_cpu(phba->fc_myDID))) { 2887 ((maxsize * sizeof(uint32_t)) >= sizeof(RPL_RSP)))) {
2682 lpfc_sli_abort_iocb(phba, pring, 0, 0, rrq->Oxid, 2888 cmdsize = sizeof(uint32_t) + sizeof(RPL_RSP);
2683 LPFC_CTX_CTX);
2684 } else {
2685 lpfc_sli_abort_iocb(phba, pring, 0, 0, rrq->Rxid,
2686 LPFC_CTX_CTX);
2687 } 2889 }
2688 2890 else {
2689 spin_unlock_irq(phba->host->host_lock); 2891 cmdsize = sizeof(uint32_t) + maxsize * sizeof(uint32_t);
2690 /* ACCEPT the rrq request */ 2892 }
2691 lpfc_els_rsp_acc(phba, ELS_CMD_ACC, cmdiocb, ndlp, NULL, 0); 2893 lpfc_els_rsp_rpl_acc(phba, cmdsize, cmdiocb, ndlp);
2692 2894
2693 return 0; 2895 return 0;
2694} 2896}
@@ -3201,10 +3403,6 @@ lpfc_els_unsol_event(struct lpfc_hba * phba,
3201 phba->fc_stat.elsRcvFAN++; 3403 phba->fc_stat.elsRcvFAN++;
3202 lpfc_els_rcv_fan(phba, elsiocb, ndlp); 3404 lpfc_els_rcv_fan(phba, elsiocb, ndlp);
3203 break; 3405 break;
3204 case ELS_CMD_RRQ:
3205 phba->fc_stat.elsRcvRRQ++;
3206 lpfc_els_rcv_rrq(phba, elsiocb, ndlp);
3207 break;
3208 case ELS_CMD_PRLI: 3406 case ELS_CMD_PRLI:
3209 phba->fc_stat.elsRcvPRLI++; 3407 phba->fc_stat.elsRcvPRLI++;
3210 if (phba->hba_state < LPFC_DISC_AUTH) { 3408 if (phba->hba_state < LPFC_DISC_AUTH) {
@@ -3213,9 +3411,33 @@ lpfc_els_unsol_event(struct lpfc_hba * phba,
3213 } 3411 }
3214 lpfc_disc_state_machine(phba, ndlp, elsiocb, NLP_EVT_RCV_PRLI); 3412 lpfc_disc_state_machine(phba, ndlp, elsiocb, NLP_EVT_RCV_PRLI);
3215 break; 3413 break;
3414 case ELS_CMD_LIRR:
3415 phba->fc_stat.elsRcvLIRR++;
3416 lpfc_els_rcv_lirr(phba, elsiocb, ndlp);
3417 if (newnode) {
3418 mempool_free( ndlp, phba->nlp_mem_pool);
3419 }
3420 break;
3421 case ELS_CMD_RPS:
3422 phba->fc_stat.elsRcvRPS++;
3423 lpfc_els_rcv_rps(phba, elsiocb, ndlp);
3424 if (newnode) {
3425 mempool_free( ndlp, phba->nlp_mem_pool);
3426 }
3427 break;
3428 case ELS_CMD_RPL:
3429 phba->fc_stat.elsRcvRPL++;
3430 lpfc_els_rcv_rpl(phba, elsiocb, ndlp);
3431 if (newnode) {
3432 mempool_free( ndlp, phba->nlp_mem_pool);
3433 }
3434 break;
3216 case ELS_CMD_RNID: 3435 case ELS_CMD_RNID:
3217 phba->fc_stat.elsRcvRNID++; 3436 phba->fc_stat.elsRcvRNID++;
3218 lpfc_els_rcv_rnid(phba, elsiocb, ndlp); 3437 lpfc_els_rcv_rnid(phba, elsiocb, ndlp);
3438 if (newnode) {
3439 mempool_free( ndlp, phba->nlp_mem_pool);
3440 }
3219 break; 3441 break;
3220 default: 3442 default:
3221 /* Unsupported ELS command, reject */ 3443 /* Unsupported ELS command, reject */