diff options
author | Jamie Wellnitz <Jamie.Wellnitz@emulex.com> | 2006-02-28 19:25:15 -0500 |
---|---|---|
committer | James Bottomley <jejb@mulgrave.il.steeleye.com> | 2006-02-28 19:52:50 -0500 |
commit | 7bb3b137abf2b7073e683c14cfe062d811d35247 (patch) | |
tree | 3293962805fc790ef90fd5aa28171cb419dd82c4 /drivers/scsi/lpfc/lpfc_els.c | |
parent | 0228aadd0fb1d8ca90efbe74291f3b5b753c2da2 (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.c | 274 |
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 | ||
2656 | static int | 2656 | static int |
2657 | lpfc_els_rcv_rrq(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb, | 2657 | lpfc_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 | |||
2671 | void | ||
2672 | lpfc_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 | |||
2747 | static int | ||
2748 | lpfc_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 | |||
2798 | int | ||
2799 | lpfc_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 | |||
2858 | static int | ||
2859 | lpfc_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 */ |