diff options
-rw-r--r-- | drivers/scsi/libfc/fc_lport.c | 4 | ||||
-rw-r--r-- | drivers/scsi/libfc/fc_rport.c | 290 | ||||
-rw-r--r-- | include/scsi/fc/fc_els.h | 2 | ||||
-rw-r--r-- | include/scsi/libfc.h | 4 |
4 files changed, 286 insertions, 14 deletions
diff --git a/drivers/scsi/libfc/fc_lport.c b/drivers/scsi/libfc/fc_lport.c index f7bff2cad4ee..ec9850c46170 100644 --- a/drivers/scsi/libfc/fc_lport.c +++ b/drivers/scsi/libfc/fc_lport.c | |||
@@ -906,10 +906,10 @@ static void fc_lport_recv_req(struct fc_lport *lport, struct fc_seq *sp, | |||
906 | recv = lport->tt.rport_recv_req; | 906 | recv = lport->tt.rport_recv_req; |
907 | switch (fc_frame_payload_op(fp)) { | 907 | switch (fc_frame_payload_op(fp)) { |
908 | case ELS_FLOGI: | 908 | case ELS_FLOGI: |
909 | recv = fc_lport_recv_flogi_req; | 909 | if (!lport->point_to_multipoint) |
910 | recv = fc_lport_recv_flogi_req; | ||
910 | break; | 911 | break; |
911 | case ELS_LOGO: | 912 | case ELS_LOGO: |
912 | fh = fc_frame_header_get(fp); | ||
913 | if (ntoh24(fh->fh_s_id) == FC_FID_FLOGI) | 913 | if (ntoh24(fh->fh_s_id) == FC_FID_FLOGI) |
914 | recv = fc_lport_recv_logo_req; | 914 | recv = fc_lport_recv_logo_req; |
915 | break; | 915 | break; |
diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c index 6d68482649c9..4d6adf29b4f8 100644 --- a/drivers/scsi/libfc/fc_rport.c +++ b/drivers/scsi/libfc/fc_rport.c | |||
@@ -60,6 +60,7 @@ | |||
60 | 60 | ||
61 | struct workqueue_struct *rport_event_queue; | 61 | struct workqueue_struct *rport_event_queue; |
62 | 62 | ||
63 | static void fc_rport_enter_flogi(struct fc_rport_priv *); | ||
63 | static void fc_rport_enter_plogi(struct fc_rport_priv *); | 64 | static void fc_rport_enter_plogi(struct fc_rport_priv *); |
64 | static void fc_rport_enter_prli(struct fc_rport_priv *); | 65 | static void fc_rport_enter_prli(struct fc_rport_priv *); |
65 | static void fc_rport_enter_rtv(struct fc_rport_priv *); | 66 | static void fc_rport_enter_rtv(struct fc_rport_priv *); |
@@ -82,6 +83,8 @@ static void fc_rport_work(struct work_struct *); | |||
82 | 83 | ||
83 | static const char *fc_rport_state_names[] = { | 84 | static const char *fc_rport_state_names[] = { |
84 | [RPORT_ST_INIT] = "Init", | 85 | [RPORT_ST_INIT] = "Init", |
86 | [RPORT_ST_FLOGI] = "FLOGI", | ||
87 | [RPORT_ST_PLOGI_WAIT] = "PLOGI_WAIT", | ||
85 | [RPORT_ST_PLOGI] = "PLOGI", | 88 | [RPORT_ST_PLOGI] = "PLOGI", |
86 | [RPORT_ST_PRLI] = "PRLI", | 89 | [RPORT_ST_PRLI] = "PRLI", |
87 | [RPORT_ST_RTV] = "RTV", | 90 | [RPORT_ST_RTV] = "RTV", |
@@ -207,7 +210,7 @@ EXPORT_SYMBOL(fc_set_rport_loss_tmo); | |||
207 | /** | 210 | /** |
208 | * fc_plogi_get_maxframe() - Get the maximum payload from the common service | 211 | * fc_plogi_get_maxframe() - Get the maximum payload from the common service |
209 | * parameters in a FLOGI frame | 212 | * parameters in a FLOGI frame |
210 | * @flp: The FLOGI payload | 213 | * @flp: The FLOGI or PLOGI payload |
211 | * @maxval: The maximum frame size upper limit; this may be less than what | 214 | * @maxval: The maximum frame size upper limit; this may be less than what |
212 | * is in the service parameters | 215 | * is in the service parameters |
213 | */ | 216 | */ |
@@ -344,7 +347,7 @@ static void fc_rport_work(struct work_struct *work) | |||
344 | rdata->major_retries++; | 347 | rdata->major_retries++; |
345 | rdata->event = RPORT_EV_NONE; | 348 | rdata->event = RPORT_EV_NONE; |
346 | FC_RPORT_DBG(rdata, "work restart\n"); | 349 | FC_RPORT_DBG(rdata, "work restart\n"); |
347 | fc_rport_enter_plogi(rdata); | 350 | fc_rport_enter_flogi(rdata); |
348 | mutex_unlock(&rdata->rp_mutex); | 351 | mutex_unlock(&rdata->rp_mutex); |
349 | } else { | 352 | } else { |
350 | FC_RPORT_DBG(rdata, "work delete\n"); | 353 | FC_RPORT_DBG(rdata, "work delete\n"); |
@@ -397,7 +400,7 @@ int fc_rport_login(struct fc_rport_priv *rdata) | |||
397 | break; | 400 | break; |
398 | default: | 401 | default: |
399 | FC_RPORT_DBG(rdata, "Login to port\n"); | 402 | FC_RPORT_DBG(rdata, "Login to port\n"); |
400 | fc_rport_enter_plogi(rdata); | 403 | fc_rport_enter_flogi(rdata); |
401 | break; | 404 | break; |
402 | } | 405 | } |
403 | mutex_unlock(&rdata->rp_mutex); | 406 | mutex_unlock(&rdata->rp_mutex); |
@@ -499,6 +502,9 @@ static void fc_rport_timeout(struct work_struct *work) | |||
499 | mutex_lock(&rdata->rp_mutex); | 502 | mutex_lock(&rdata->rp_mutex); |
500 | 503 | ||
501 | switch (rdata->rp_state) { | 504 | switch (rdata->rp_state) { |
505 | case RPORT_ST_FLOGI: | ||
506 | fc_rport_enter_flogi(rdata); | ||
507 | break; | ||
502 | case RPORT_ST_PLOGI: | 508 | case RPORT_ST_PLOGI: |
503 | fc_rport_enter_plogi(rdata); | 509 | fc_rport_enter_plogi(rdata); |
504 | break; | 510 | break; |
@@ -514,6 +520,7 @@ static void fc_rport_timeout(struct work_struct *work) | |||
514 | case RPORT_ST_ADISC: | 520 | case RPORT_ST_ADISC: |
515 | fc_rport_enter_adisc(rdata); | 521 | fc_rport_enter_adisc(rdata); |
516 | break; | 522 | break; |
523 | case RPORT_ST_PLOGI_WAIT: | ||
517 | case RPORT_ST_READY: | 524 | case RPORT_ST_READY: |
518 | case RPORT_ST_INIT: | 525 | case RPORT_ST_INIT: |
519 | case RPORT_ST_DELETE: | 526 | case RPORT_ST_DELETE: |
@@ -538,6 +545,7 @@ static void fc_rport_error(struct fc_rport_priv *rdata, struct fc_frame *fp) | |||
538 | fc_rport_state(rdata), rdata->retries); | 545 | fc_rport_state(rdata), rdata->retries); |
539 | 546 | ||
540 | switch (rdata->rp_state) { | 547 | switch (rdata->rp_state) { |
548 | case RPORT_ST_FLOGI: | ||
541 | case RPORT_ST_PLOGI: | 549 | case RPORT_ST_PLOGI: |
542 | case RPORT_ST_LOGO: | 550 | case RPORT_ST_LOGO: |
543 | rdata->flags &= ~FC_RP_STARTED; | 551 | rdata->flags &= ~FC_RP_STARTED; |
@@ -550,6 +558,7 @@ static void fc_rport_error(struct fc_rport_priv *rdata, struct fc_frame *fp) | |||
550 | case RPORT_ST_ADISC: | 558 | case RPORT_ST_ADISC: |
551 | fc_rport_enter_logo(rdata); | 559 | fc_rport_enter_logo(rdata); |
552 | break; | 560 | break; |
561 | case RPORT_ST_PLOGI_WAIT: | ||
553 | case RPORT_ST_DELETE: | 562 | case RPORT_ST_DELETE: |
554 | case RPORT_ST_READY: | 563 | case RPORT_ST_READY: |
555 | case RPORT_ST_INIT: | 564 | case RPORT_ST_INIT: |
@@ -592,7 +601,260 @@ static void fc_rport_error_retry(struct fc_rport_priv *rdata, | |||
592 | } | 601 | } |
593 | 602 | ||
594 | /** | 603 | /** |
595 | * fc_rport_plogi_recv_resp() - Handler for ELS PLOGI responses | 604 | * fc_rport_login_complete() - Handle parameters and completion of p-mp login. |
605 | * @rdata: The remote port which we logged into or which logged into us. | ||
606 | * @fp: The FLOGI or PLOGI request or response frame | ||
607 | * | ||
608 | * Returns non-zero error if a problem is detected with the frame. | ||
609 | * Does not free the frame. | ||
610 | * | ||
611 | * This is only used in point-to-multipoint mode for FIP currently. | ||
612 | */ | ||
613 | static int fc_rport_login_complete(struct fc_rport_priv *rdata, | ||
614 | struct fc_frame *fp) | ||
615 | { | ||
616 | struct fc_lport *lport = rdata->local_port; | ||
617 | struct fc_els_flogi *flogi; | ||
618 | unsigned int e_d_tov; | ||
619 | u16 csp_flags; | ||
620 | |||
621 | flogi = fc_frame_payload_get(fp, sizeof(*flogi)); | ||
622 | if (!flogi) | ||
623 | return -EINVAL; | ||
624 | |||
625 | csp_flags = ntohs(flogi->fl_csp.sp_features); | ||
626 | |||
627 | if (fc_frame_payload_op(fp) == ELS_FLOGI) { | ||
628 | if (csp_flags & FC_SP_FT_FPORT) { | ||
629 | FC_RPORT_DBG(rdata, "Fabric bit set in FLOGI\n"); | ||
630 | return -EINVAL; | ||
631 | } | ||
632 | } else { | ||
633 | |||
634 | /* | ||
635 | * E_D_TOV is not valid on an incoming FLOGI request. | ||
636 | */ | ||
637 | e_d_tov = ntohl(flogi->fl_csp.sp_e_d_tov); | ||
638 | if (csp_flags & FC_SP_FT_EDTR) | ||
639 | e_d_tov /= 1000000; | ||
640 | if (e_d_tov > rdata->e_d_tov) | ||
641 | rdata->e_d_tov = e_d_tov; | ||
642 | } | ||
643 | rdata->maxframe_size = fc_plogi_get_maxframe(flogi, lport->mfs); | ||
644 | return 0; | ||
645 | } | ||
646 | |||
647 | /** | ||
648 | * fc_rport_flogi_resp() - Handle response to FLOGI request for p-mp mode | ||
649 | * @sp: The sequence that the FLOGI was on | ||
650 | * @fp: The FLOGI response frame | ||
651 | * @rp_arg: The remote port that received the FLOGI response | ||
652 | */ | ||
653 | void fc_rport_flogi_resp(struct fc_seq *sp, struct fc_frame *fp, | ||
654 | void *rp_arg) | ||
655 | { | ||
656 | struct fc_rport_priv *rdata = rp_arg; | ||
657 | struct fc_lport *lport = rdata->local_port; | ||
658 | struct fc_els_flogi *flogi; | ||
659 | unsigned int r_a_tov; | ||
660 | |||
661 | FC_RPORT_DBG(rdata, "Received a FLOGI %s\n", fc_els_resp_type(fp)); | ||
662 | |||
663 | if (fp == ERR_PTR(-FC_EX_CLOSED)) | ||
664 | return; | ||
665 | |||
666 | mutex_lock(&rdata->rp_mutex); | ||
667 | |||
668 | if (rdata->rp_state != RPORT_ST_FLOGI) { | ||
669 | FC_RPORT_DBG(rdata, "Received a FLOGI response, but in state " | ||
670 | "%s\n", fc_rport_state(rdata)); | ||
671 | if (IS_ERR(fp)) | ||
672 | goto err; | ||
673 | goto out; | ||
674 | } | ||
675 | |||
676 | if (IS_ERR(fp)) { | ||
677 | fc_rport_error(rdata, fp); | ||
678 | goto err; | ||
679 | } | ||
680 | |||
681 | if (fc_frame_payload_op(fp) != ELS_LS_ACC) | ||
682 | goto bad; | ||
683 | if (fc_rport_login_complete(rdata, fp)) | ||
684 | goto bad; | ||
685 | |||
686 | flogi = fc_frame_payload_get(fp, sizeof(*flogi)); | ||
687 | if (!flogi) | ||
688 | goto bad; | ||
689 | r_a_tov = ntohl(flogi->fl_csp.sp_r_a_tov); | ||
690 | if (r_a_tov > rdata->r_a_tov) | ||
691 | rdata->r_a_tov = r_a_tov; | ||
692 | |||
693 | if (rdata->ids.port_name < lport->wwpn) | ||
694 | fc_rport_enter_plogi(rdata); | ||
695 | else | ||
696 | fc_rport_state_enter(rdata, RPORT_ST_PLOGI_WAIT); | ||
697 | out: | ||
698 | fc_frame_free(fp); | ||
699 | err: | ||
700 | mutex_unlock(&rdata->rp_mutex); | ||
701 | kref_put(&rdata->kref, rdata->local_port->tt.rport_destroy); | ||
702 | return; | ||
703 | bad: | ||
704 | FC_RPORT_DBG(rdata, "Bad FLOGI response\n"); | ||
705 | fc_rport_error_retry(rdata, fp); | ||
706 | goto out; | ||
707 | } | ||
708 | |||
709 | /** | ||
710 | * fc_rport_enter_flogi() - Send a FLOGI request to the remote port for p-mp | ||
711 | * @rdata: The remote port to send a FLOGI to | ||
712 | * | ||
713 | * Locking Note: The rport lock is expected to be held before calling | ||
714 | * this routine. | ||
715 | */ | ||
716 | static void fc_rport_enter_flogi(struct fc_rport_priv *rdata) | ||
717 | { | ||
718 | struct fc_lport *lport = rdata->local_port; | ||
719 | struct fc_frame *fp; | ||
720 | |||
721 | if (!lport->point_to_multipoint) | ||
722 | return fc_rport_enter_plogi(rdata); | ||
723 | |||
724 | FC_RPORT_DBG(rdata, "Entered FLOGI state from %s state\n", | ||
725 | fc_rport_state(rdata)); | ||
726 | |||
727 | fc_rport_state_enter(rdata, RPORT_ST_FLOGI); | ||
728 | |||
729 | fp = fc_frame_alloc(lport, sizeof(struct fc_els_flogi)); | ||
730 | if (!fp) | ||
731 | return fc_rport_error_retry(rdata, fp); | ||
732 | |||
733 | if (!lport->tt.elsct_send(lport, rdata->ids.port_id, fp, ELS_FLOGI, | ||
734 | fc_rport_flogi_resp, rdata, | ||
735 | 2 * lport->r_a_tov)) | ||
736 | fc_rport_error_retry(rdata, NULL); | ||
737 | else | ||
738 | kref_get(&rdata->kref); | ||
739 | } | ||
740 | |||
741 | /** | ||
742 | * fc_rport_recv_flogi_req() - Handle Fabric Login (FLOGI) request in p-mp mode | ||
743 | * @lport: The local port that received the PLOGI request | ||
744 | * @sp: The sequence that the PLOGI request was on | ||
745 | * @rx_fp: The PLOGI request frame | ||
746 | */ | ||
747 | static void fc_rport_recv_flogi_req(struct fc_lport *lport, | ||
748 | struct fc_seq *sp, struct fc_frame *rx_fp) | ||
749 | { | ||
750 | struct fc_disc *disc; | ||
751 | struct fc_els_flogi *flp; | ||
752 | struct fc_rport_priv *rdata; | ||
753 | struct fc_frame *fp = rx_fp; | ||
754 | struct fc_exch *ep; | ||
755 | struct fc_frame_header *fh; | ||
756 | struct fc_seq_els_data rjt_data; | ||
757 | u32 sid, f_ctl; | ||
758 | |||
759 | rjt_data.fp = NULL; | ||
760 | fh = fc_frame_header_get(fp); | ||
761 | sid = ntoh24(fh->fh_s_id); | ||
762 | |||
763 | FC_RPORT_ID_DBG(lport, sid, "Received FLOGI request\n"); | ||
764 | |||
765 | disc = &lport->disc; | ||
766 | mutex_lock(&disc->disc_mutex); | ||
767 | |||
768 | if (!lport->point_to_multipoint) { | ||
769 | rjt_data.reason = ELS_RJT_UNSUP; | ||
770 | rjt_data.explan = ELS_EXPL_NONE; | ||
771 | goto reject; | ||
772 | } | ||
773 | |||
774 | flp = fc_frame_payload_get(fp, sizeof(*flp)); | ||
775 | if (!flp) { | ||
776 | rjt_data.reason = ELS_RJT_LOGIC; | ||
777 | rjt_data.explan = ELS_EXPL_INV_LEN; | ||
778 | goto reject; | ||
779 | } | ||
780 | |||
781 | rdata = lport->tt.rport_lookup(lport, sid); | ||
782 | if (!rdata) { | ||
783 | rjt_data.reason = ELS_RJT_FIP; | ||
784 | rjt_data.explan = ELS_EXPL_NOT_NEIGHBOR; | ||
785 | goto reject; | ||
786 | } | ||
787 | mutex_lock(&rdata->rp_mutex); | ||
788 | |||
789 | FC_RPORT_DBG(rdata, "Received FLOGI in %s state\n", | ||
790 | fc_rport_state(rdata)); | ||
791 | |||
792 | switch (rdata->rp_state) { | ||
793 | case RPORT_ST_INIT: | ||
794 | case RPORT_ST_LOGO: | ||
795 | case RPORT_ST_DELETE: | ||
796 | mutex_unlock(&rdata->rp_mutex); | ||
797 | rjt_data.reason = ELS_RJT_FIP; | ||
798 | rjt_data.explan = ELS_EXPL_NOT_NEIGHBOR; | ||
799 | goto reject; | ||
800 | case RPORT_ST_FLOGI: | ||
801 | case RPORT_ST_PLOGI_WAIT: | ||
802 | case RPORT_ST_PLOGI: | ||
803 | break; | ||
804 | case RPORT_ST_PRLI: | ||
805 | case RPORT_ST_RTV: | ||
806 | case RPORT_ST_READY: | ||
807 | case RPORT_ST_ADISC: | ||
808 | /* | ||
809 | * Set the remote port to be deleted and to then restart. | ||
810 | * This queues work to be sure exchanges are reset. | ||
811 | */ | ||
812 | fc_rport_enter_delete(rdata, RPORT_EV_LOGO); | ||
813 | mutex_unlock(&rdata->rp_mutex); | ||
814 | rjt_data.reason = ELS_RJT_BUSY; | ||
815 | rjt_data.explan = ELS_EXPL_NONE; | ||
816 | goto reject; | ||
817 | } | ||
818 | if (fc_rport_login_complete(rdata, fp)) { | ||
819 | mutex_unlock(&rdata->rp_mutex); | ||
820 | rjt_data.reason = ELS_RJT_LOGIC; | ||
821 | rjt_data.explan = ELS_EXPL_NONE; | ||
822 | goto reject; | ||
823 | } | ||
824 | fc_frame_free(rx_fp); | ||
825 | |||
826 | fp = fc_frame_alloc(lport, sizeof(*flp)); | ||
827 | if (!fp) | ||
828 | goto out; | ||
829 | |||
830 | sp = lport->tt.seq_start_next(sp); | ||
831 | fc_flogi_fill(lport, fp); | ||
832 | flp = fc_frame_payload_get(fp, sizeof(*flp)); | ||
833 | flp->fl_cmd = ELS_LS_ACC; | ||
834 | |||
835 | f_ctl = FC_FC_EX_CTX | FC_FC_LAST_SEQ | FC_FC_END_SEQ | FC_FC_SEQ_INIT; | ||
836 | ep = fc_seq_exch(sp); | ||
837 | fc_fill_fc_hdr(fp, FC_RCTL_ELS_REP, ep->did, ep->sid, | ||
838 | FC_TYPE_ELS, f_ctl, 0); | ||
839 | lport->tt.seq_send(lport, sp, fp); | ||
840 | |||
841 | if (rdata->ids.port_name < lport->wwpn) | ||
842 | fc_rport_enter_plogi(rdata); | ||
843 | else | ||
844 | fc_rport_state_enter(rdata, RPORT_ST_PLOGI_WAIT); | ||
845 | out: | ||
846 | mutex_unlock(&rdata->rp_mutex); | ||
847 | mutex_unlock(&disc->disc_mutex); | ||
848 | return; | ||
849 | |||
850 | reject: | ||
851 | mutex_unlock(&disc->disc_mutex); | ||
852 | lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &rjt_data); | ||
853 | fc_frame_free(fp); | ||
854 | } | ||
855 | |||
856 | /** | ||
857 | * fc_rport_plogi_resp() - Handler for ELS PLOGI responses | ||
596 | * @sp: The sequence the PLOGI is on | 858 | * @sp: The sequence the PLOGI is on |
597 | * @fp: The PLOGI response frame | 859 | * @fp: The PLOGI response frame |
598 | * @rdata_arg: The remote port that sent the PLOGI response | 860 | * @rdata_arg: The remote port that sent the PLOGI response |
@@ -607,7 +869,6 @@ static void fc_rport_plogi_resp(struct fc_seq *sp, struct fc_frame *fp, | |||
607 | struct fc_rport_priv *rdata = rdata_arg; | 869 | struct fc_rport_priv *rdata = rdata_arg; |
608 | struct fc_lport *lport = rdata->local_port; | 870 | struct fc_lport *lport = rdata->local_port; |
609 | struct fc_els_flogi *plp = NULL; | 871 | struct fc_els_flogi *plp = NULL; |
610 | unsigned int tov; | ||
611 | u16 csp_seq; | 872 | u16 csp_seq; |
612 | u16 cssp_seq; | 873 | u16 cssp_seq; |
613 | u8 op; | 874 | u8 op; |
@@ -635,11 +896,8 @@ static void fc_rport_plogi_resp(struct fc_seq *sp, struct fc_frame *fp, | |||
635 | rdata->ids.port_name = get_unaligned_be64(&plp->fl_wwpn); | 896 | rdata->ids.port_name = get_unaligned_be64(&plp->fl_wwpn); |
636 | rdata->ids.node_name = get_unaligned_be64(&plp->fl_wwnn); | 897 | rdata->ids.node_name = get_unaligned_be64(&plp->fl_wwnn); |
637 | 898 | ||
638 | tov = ntohl(plp->fl_csp.sp_e_d_tov); | 899 | if (lport->point_to_multipoint) |
639 | if (ntohs(plp->fl_csp.sp_features) & FC_SP_FT_EDTR) | 900 | fc_rport_login_complete(rdata, fp); |
640 | tov /= 1000000; | ||
641 | if (tov > rdata->e_d_tov) | ||
642 | rdata->e_d_tov = tov; | ||
643 | csp_seq = ntohs(plp->fl_csp.sp_tot_seq); | 901 | csp_seq = ntohs(plp->fl_csp.sp_tot_seq); |
644 | cssp_seq = ntohs(plp->fl_cssp[3 - 1].cp_con_seq); | 902 | cssp_seq = ntohs(plp->fl_cssp[3 - 1].cp_con_seq); |
645 | if (cssp_seq < csp_seq) | 903 | if (cssp_seq < csp_seq) |
@@ -677,6 +935,7 @@ static void fc_rport_enter_plogi(struct fc_rport_priv *rdata) | |||
677 | rdata->maxframe_size = FC_MIN_MAX_PAYLOAD; | 935 | rdata->maxframe_size = FC_MIN_MAX_PAYLOAD; |
678 | fp = fc_frame_alloc(lport, sizeof(struct fc_els_flogi)); | 936 | fp = fc_frame_alloc(lport, sizeof(struct fc_els_flogi)); |
679 | if (!fp) { | 937 | if (!fp) { |
938 | FC_RPORT_DBG(rdata, "%s frame alloc failed\n", __func__); | ||
680 | fc_rport_error_retry(rdata, fp); | 939 | fc_rport_error_retry(rdata, fp); |
681 | return; | 940 | return; |
682 | } | 941 | } |
@@ -1041,7 +1300,7 @@ static void fc_rport_adisc_resp(struct fc_seq *sp, struct fc_frame *fp, | |||
1041 | get_unaligned_be64(&adisc->adisc_wwpn) != rdata->ids.port_name || | 1300 | get_unaligned_be64(&adisc->adisc_wwpn) != rdata->ids.port_name || |
1042 | get_unaligned_be64(&adisc->adisc_wwnn) != rdata->ids.node_name) { | 1301 | get_unaligned_be64(&adisc->adisc_wwnn) != rdata->ids.node_name) { |
1043 | FC_RPORT_DBG(rdata, "ADISC error or mismatch\n"); | 1302 | FC_RPORT_DBG(rdata, "ADISC error or mismatch\n"); |
1044 | fc_rport_enter_plogi(rdata); | 1303 | fc_rport_enter_flogi(rdata); |
1045 | } else { | 1304 | } else { |
1046 | FC_RPORT_DBG(rdata, "ADISC OK\n"); | 1305 | FC_RPORT_DBG(rdata, "ADISC OK\n"); |
1047 | fc_rport_enter_ready(rdata); | 1306 | fc_rport_enter_ready(rdata); |
@@ -1291,12 +1550,15 @@ void fc_rport_recv_req(struct fc_seq *sp, struct fc_frame *fp, | |||
1291 | struct fc_seq_els_data els_data; | 1550 | struct fc_seq_els_data els_data; |
1292 | 1551 | ||
1293 | /* | 1552 | /* |
1294 | * Handle PLOGI and LOGO requests separately, since they | 1553 | * Handle FLOGI, PLOGI and LOGO requests separately, since they |
1295 | * don't require prior login. | 1554 | * don't require prior login. |
1296 | * Check for unsupported opcodes first and reject them. | 1555 | * Check for unsupported opcodes first and reject them. |
1297 | * For some ops, it would be incorrect to reject with "PLOGI required". | 1556 | * For some ops, it would be incorrect to reject with "PLOGI required". |
1298 | */ | 1557 | */ |
1299 | switch (fc_frame_payload_op(fp)) { | 1558 | switch (fc_frame_payload_op(fp)) { |
1559 | case ELS_FLOGI: | ||
1560 | fc_rport_recv_flogi_req(lport, sp, fp); | ||
1561 | break; | ||
1300 | case ELS_PLOGI: | 1562 | case ELS_PLOGI: |
1301 | fc_rport_recv_plogi_req(lport, sp, fp); | 1563 | fc_rport_recv_plogi_req(lport, sp, fp); |
1302 | break; | 1564 | break; |
@@ -1386,6 +1648,9 @@ static void fc_rport_recv_plogi_req(struct fc_lport *lport, | |||
1386 | case RPORT_ST_INIT: | 1648 | case RPORT_ST_INIT: |
1387 | FC_RPORT_DBG(rdata, "Received PLOGI in INIT state\n"); | 1649 | FC_RPORT_DBG(rdata, "Received PLOGI in INIT state\n"); |
1388 | break; | 1650 | break; |
1651 | case RPORT_ST_PLOGI_WAIT: | ||
1652 | FC_RPORT_DBG(rdata, "Received PLOGI in PLOGI_WAIT state\n"); | ||
1653 | break; | ||
1389 | case RPORT_ST_PLOGI: | 1654 | case RPORT_ST_PLOGI: |
1390 | FC_RPORT_DBG(rdata, "Received PLOGI in PLOGI state\n"); | 1655 | FC_RPORT_DBG(rdata, "Received PLOGI in PLOGI state\n"); |
1391 | if (rdata->ids.port_name < lport->wwpn) { | 1656 | if (rdata->ids.port_name < lport->wwpn) { |
@@ -1403,6 +1668,7 @@ static void fc_rport_recv_plogi_req(struct fc_lport *lport, | |||
1403 | "- ignored for now\n", rdata->rp_state); | 1668 | "- ignored for now\n", rdata->rp_state); |
1404 | /* XXX TBD - should reset */ | 1669 | /* XXX TBD - should reset */ |
1405 | break; | 1670 | break; |
1671 | case RPORT_ST_FLOGI: | ||
1406 | case RPORT_ST_DELETE: | 1672 | case RPORT_ST_DELETE: |
1407 | case RPORT_ST_LOGO: | 1673 | case RPORT_ST_LOGO: |
1408 | FC_RPORT_DBG(rdata, "Received PLOGI in state %s - send busy\n", | 1674 | FC_RPORT_DBG(rdata, "Received PLOGI in state %s - send busy\n", |
diff --git a/include/scsi/fc/fc_els.h b/include/scsi/fc/fc_els.h index 70a7e92a7664..481abbd48e39 100644 --- a/include/scsi/fc/fc_els.h +++ b/include/scsi/fc/fc_els.h | |||
@@ -191,6 +191,7 @@ enum fc_els_rjt_reason { | |||
191 | ELS_RJT_UNAB = 0x09, /* unable to perform command request */ | 191 | ELS_RJT_UNAB = 0x09, /* unable to perform command request */ |
192 | ELS_RJT_UNSUP = 0x0b, /* command not supported */ | 192 | ELS_RJT_UNSUP = 0x0b, /* command not supported */ |
193 | ELS_RJT_INPROG = 0x0e, /* command already in progress */ | 193 | ELS_RJT_INPROG = 0x0e, /* command already in progress */ |
194 | ELS_RJT_FIP = 0x20, /* FIP error */ | ||
194 | ELS_RJT_VENDOR = 0xff, /* vendor specific error */ | 195 | ELS_RJT_VENDOR = 0xff, /* vendor specific error */ |
195 | }; | 196 | }; |
196 | 197 | ||
@@ -212,6 +213,7 @@ enum fc_els_rjt_explan { | |||
212 | ELS_EXPL_UNAB_DATA = 0x2a, /* unable to supply requested data */ | 213 | ELS_EXPL_UNAB_DATA = 0x2a, /* unable to supply requested data */ |
213 | ELS_EXPL_UNSUPR = 0x2c, /* Request not supported */ | 214 | ELS_EXPL_UNSUPR = 0x2c, /* Request not supported */ |
214 | ELS_EXPL_INV_LEN = 0x2d, /* Invalid payload length */ | 215 | ELS_EXPL_INV_LEN = 0x2d, /* Invalid payload length */ |
216 | ELS_EXPL_NOT_NEIGHBOR = 0x62, /* VN2VN_Port not in neighbor set */ | ||
215 | /* TBD - above definitions incomplete */ | 217 | /* TBD - above definitions incomplete */ |
216 | }; | 218 | }; |
217 | 219 | ||
diff --git a/include/scsi/libfc.h b/include/scsi/libfc.h index bd0560509ce6..24b91c922055 100644 --- a/include/scsi/libfc.h +++ b/include/scsi/libfc.h | |||
@@ -97,6 +97,8 @@ enum fc_disc_event { | |||
97 | /** | 97 | /** |
98 | * enum fc_rport_state - Remote port states | 98 | * enum fc_rport_state - Remote port states |
99 | * @RPORT_ST_INIT: Initialized | 99 | * @RPORT_ST_INIT: Initialized |
100 | * @RPORT_ST_FLOGI: Waiting for FLOGI completion for point-to-multipoint | ||
101 | * @RPORT_ST_PLOGI_WAIT: Waiting for peer to login for point-to-multipoint | ||
100 | * @RPORT_ST_PLOGI: Waiting for PLOGI completion | 102 | * @RPORT_ST_PLOGI: Waiting for PLOGI completion |
101 | * @RPORT_ST_PRLI: Waiting for PRLI completion | 103 | * @RPORT_ST_PRLI: Waiting for PRLI completion |
102 | * @RPORT_ST_RTV: Waiting for RTV completion | 104 | * @RPORT_ST_RTV: Waiting for RTV completion |
@@ -107,6 +109,8 @@ enum fc_disc_event { | |||
107 | */ | 109 | */ |
108 | enum fc_rport_state { | 110 | enum fc_rport_state { |
109 | RPORT_ST_INIT, | 111 | RPORT_ST_INIT, |
112 | RPORT_ST_FLOGI, | ||
113 | RPORT_ST_PLOGI_WAIT, | ||
110 | RPORT_ST_PLOGI, | 114 | RPORT_ST_PLOGI, |
111 | RPORT_ST_PRLI, | 115 | RPORT_ST_PRLI, |
112 | RPORT_ST_RTV, | 116 | RPORT_ST_RTV, |