diff options
Diffstat (limited to 'drivers/scsi')
-rw-r--r-- | drivers/scsi/libfc/fc_rport.c | 185 |
1 files changed, 93 insertions, 92 deletions
diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c index d014b285cd1a..e121ff92c8ea 100644 --- a/drivers/scsi/libfc/fc_rport.c +++ b/drivers/scsi/libfc/fc_rport.c | |||
@@ -63,7 +63,7 @@ static void fc_rport_enter_rtv(struct fc_rport_priv *); | |||
63 | static void fc_rport_enter_ready(struct fc_rport_priv *); | 63 | static void fc_rport_enter_ready(struct fc_rport_priv *); |
64 | static void fc_rport_enter_logo(struct fc_rport_priv *); | 64 | static void fc_rport_enter_logo(struct fc_rport_priv *); |
65 | 65 | ||
66 | static void fc_rport_recv_plogi_req(struct fc_rport_priv *, | 66 | static void fc_rport_recv_plogi_req(struct fc_lport *, |
67 | struct fc_seq *, struct fc_frame *); | 67 | struct fc_seq *, struct fc_frame *); |
68 | static void fc_rport_recv_prli_req(struct fc_rport_priv *, | 68 | static void fc_rport_recv_prli_req(struct fc_rport_priv *, |
69 | struct fc_seq *, struct fc_frame *); | 69 | struct fc_seq *, struct fc_frame *); |
@@ -576,15 +576,7 @@ static void fc_rport_plogi_resp(struct fc_seq *sp, struct fc_frame *fp, | |||
576 | csp_seq = cssp_seq; | 576 | csp_seq = cssp_seq; |
577 | rdata->max_seq = csp_seq; | 577 | rdata->max_seq = csp_seq; |
578 | rdata->maxframe_size = fc_plogi_get_maxframe(plp, lport->mfs); | 578 | rdata->maxframe_size = fc_plogi_get_maxframe(plp, lport->mfs); |
579 | 579 | fc_rport_enter_prli(rdata); | |
580 | /* | ||
581 | * If the rport is one of the well known addresses | ||
582 | * we skip PRLI and RTV and go straight to READY. | ||
583 | */ | ||
584 | if (rdata->ids.port_id >= FC_FID_DOM_MGR) | ||
585 | fc_rport_enter_ready(rdata); | ||
586 | else | ||
587 | fc_rport_enter_prli(rdata); | ||
588 | } else | 580 | } else |
589 | fc_rport_error_retry(rdata, fp); | 581 | fc_rport_error_retry(rdata, fp); |
590 | 582 | ||
@@ -763,6 +755,15 @@ static void fc_rport_enter_prli(struct fc_rport_priv *rdata) | |||
763 | } *pp; | 755 | } *pp; |
764 | struct fc_frame *fp; | 756 | struct fc_frame *fp; |
765 | 757 | ||
758 | /* | ||
759 | * If the rport is one of the well known addresses | ||
760 | * we skip PRLI and RTV and go straight to READY. | ||
761 | */ | ||
762 | if (rdata->ids.port_id >= FC_FID_DOM_MGR) { | ||
763 | fc_rport_enter_ready(rdata); | ||
764 | return; | ||
765 | } | ||
766 | |||
766 | FC_RPORT_DBG(rdata, "Port entered PRLI state from %s state\n", | 767 | FC_RPORT_DBG(rdata, "Port entered PRLI state from %s state\n", |
767 | fc_rport_state(rdata)); | 768 | fc_rport_state(rdata)); |
768 | 769 | ||
@@ -929,6 +930,15 @@ void fc_rport_recv_req(struct fc_seq *sp, struct fc_frame *fp, | |||
929 | els_data.explan = ELS_EXPL_NONE; | 930 | els_data.explan = ELS_EXPL_NONE; |
930 | els_data.reason = ELS_RJT_NONE; | 931 | els_data.reason = ELS_RJT_NONE; |
931 | 932 | ||
933 | op = fc_frame_payload_op(fp); | ||
934 | switch (op) { | ||
935 | case ELS_PLOGI: | ||
936 | fc_rport_recv_plogi_req(lport, sp, fp); | ||
937 | return; | ||
938 | default: | ||
939 | break; | ||
940 | } | ||
941 | |||
932 | fh = fc_frame_header_get(fp); | 942 | fh = fc_frame_header_get(fp); |
933 | s_id = ntoh24(fh->fh_s_id); | 943 | s_id = ntoh24(fh->fh_s_id); |
934 | 944 | ||
@@ -944,11 +954,7 @@ void fc_rport_recv_req(struct fc_seq *sp, struct fc_frame *fp, | |||
944 | mutex_lock(&rdata->rp_mutex); | 954 | mutex_lock(&rdata->rp_mutex); |
945 | mutex_unlock(&lport->disc.disc_mutex); | 955 | mutex_unlock(&lport->disc.disc_mutex); |
946 | 956 | ||
947 | op = fc_frame_payload_op(fp); | ||
948 | switch (op) { | 957 | switch (op) { |
949 | case ELS_PLOGI: | ||
950 | fc_rport_recv_plogi_req(rdata, sp, fp); | ||
951 | break; | ||
952 | case ELS_PRLI: | 958 | case ELS_PRLI: |
953 | fc_rport_recv_prli_req(rdata, sp, fp); | 959 | fc_rport_recv_prli_req(rdata, sp, fp); |
954 | break; | 960 | break; |
@@ -977,48 +983,56 @@ void fc_rport_recv_req(struct fc_seq *sp, struct fc_frame *fp, | |||
977 | 983 | ||
978 | /** | 984 | /** |
979 | * fc_rport_recv_plogi_req() - Handle incoming Port Login (PLOGI) request | 985 | * fc_rport_recv_plogi_req() - Handle incoming Port Login (PLOGI) request |
980 | * @rdata: private remote port data | 986 | * @lport: local port |
981 | * @sp: current sequence in the PLOGI exchange | 987 | * @sp: current sequence in the PLOGI exchange |
982 | * @fp: PLOGI request frame | 988 | * @fp: PLOGI request frame |
983 | * | 989 | * |
984 | * Locking Note: The rport lock is exected to be held before calling | 990 | * Locking Note: The rport lock is held before calling this function. |
985 | * this function. | ||
986 | */ | 991 | */ |
987 | static void fc_rport_recv_plogi_req(struct fc_rport_priv *rdata, | 992 | static void fc_rport_recv_plogi_req(struct fc_lport *lport, |
988 | struct fc_seq *sp, struct fc_frame *rx_fp) | 993 | struct fc_seq *sp, struct fc_frame *rx_fp) |
989 | { | 994 | { |
990 | struct fc_lport *lport = rdata->local_port; | 995 | struct fc_disc *disc; |
996 | struct fc_rport_priv *rdata; | ||
991 | struct fc_frame *fp = rx_fp; | 997 | struct fc_frame *fp = rx_fp; |
992 | struct fc_exch *ep; | 998 | struct fc_exch *ep; |
993 | struct fc_frame_header *fh; | 999 | struct fc_frame_header *fh; |
994 | struct fc_els_flogi *pl; | 1000 | struct fc_els_flogi *pl; |
995 | struct fc_seq_els_data rjt_data; | 1001 | struct fc_seq_els_data rjt_data; |
996 | u32 sid; | 1002 | u32 sid, f_ctl; |
997 | u64 wwpn; | ||
998 | u64 wwnn; | ||
999 | enum fc_els_rjt_reason reject = 0; | ||
1000 | u32 f_ctl; | ||
1001 | rjt_data.fp = NULL; | ||
1002 | 1003 | ||
1004 | rjt_data.fp = NULL; | ||
1003 | fh = fc_frame_header_get(fp); | 1005 | fh = fc_frame_header_get(fp); |
1006 | sid = ntoh24(fh->fh_s_id); | ||
1004 | 1007 | ||
1005 | FC_RPORT_DBG(rdata, "Received PLOGI request while in state %s\n", | 1008 | FC_RPORT_ID_DBG(lport, sid, "Received PLOGI request\n"); |
1006 | fc_rport_state(rdata)); | ||
1007 | 1009 | ||
1008 | sid = ntoh24(fh->fh_s_id); | ||
1009 | pl = fc_frame_payload_get(fp, sizeof(*pl)); | 1010 | pl = fc_frame_payload_get(fp, sizeof(*pl)); |
1010 | if (!pl) { | 1011 | if (!pl) { |
1011 | FC_RPORT_DBG(rdata, "Received PLOGI too short\n"); | 1012 | FC_RPORT_ID_DBG(lport, sid, "Received PLOGI too short\n"); |
1012 | WARN_ON(1); | 1013 | rjt_data.reason = ELS_RJT_PROT; |
1013 | /* XXX TBD: send reject? */ | 1014 | rjt_data.explan = ELS_EXPL_INV_LEN; |
1014 | fc_frame_free(fp); | 1015 | goto reject; |
1015 | return; | 1016 | } |
1017 | |||
1018 | disc = &lport->disc; | ||
1019 | mutex_lock(&disc->disc_mutex); | ||
1020 | rdata = lport->tt.rport_create(lport, sid); | ||
1021 | if (!rdata) { | ||
1022 | mutex_unlock(&disc->disc_mutex); | ||
1023 | rjt_data.reason = ELS_RJT_UNAB; | ||
1024 | rjt_data.explan = ELS_EXPL_INSUF_RES; | ||
1025 | goto reject; | ||
1016 | } | 1026 | } |
1017 | wwpn = get_unaligned_be64(&pl->fl_wwpn); | 1027 | |
1018 | wwnn = get_unaligned_be64(&pl->fl_wwnn); | 1028 | mutex_lock(&rdata->rp_mutex); |
1029 | mutex_unlock(&disc->disc_mutex); | ||
1030 | |||
1031 | rdata->ids.port_name = get_unaligned_be64(&pl->fl_wwpn); | ||
1032 | rdata->ids.node_name = get_unaligned_be64(&pl->fl_wwnn); | ||
1019 | 1033 | ||
1020 | /* | 1034 | /* |
1021 | * If the session was just created, possibly due to the incoming PLOGI, | 1035 | * If the rport was just created, possibly due to the incoming PLOGI, |
1022 | * set the state appropriately and accept the PLOGI. | 1036 | * set the state appropriately and accept the PLOGI. |
1023 | * | 1037 | * |
1024 | * If we had also sent a PLOGI, and if the received PLOGI is from a | 1038 | * If we had also sent a PLOGI, and if the received PLOGI is from a |
@@ -1030,72 +1044,58 @@ static void fc_rport_recv_plogi_req(struct fc_rport_priv *rdata, | |||
1030 | */ | 1044 | */ |
1031 | switch (rdata->rp_state) { | 1045 | switch (rdata->rp_state) { |
1032 | case RPORT_ST_INIT: | 1046 | case RPORT_ST_INIT: |
1033 | FC_RPORT_DBG(rdata, "Received PLOGI, wwpn %llx state INIT " | 1047 | FC_RPORT_DBG(rdata, "Received PLOGI in INIT state\n"); |
1034 | "- reject\n", (unsigned long long)wwpn); | ||
1035 | reject = ELS_RJT_UNSUP; | ||
1036 | break; | 1048 | break; |
1037 | case RPORT_ST_PLOGI: | 1049 | case RPORT_ST_PLOGI: |
1038 | FC_RPORT_DBG(rdata, "Received PLOGI in PLOGI state %d\n", | 1050 | FC_RPORT_DBG(rdata, "Received PLOGI in PLOGI state\n"); |
1039 | rdata->rp_state); | 1051 | if (rdata->ids.port_name < lport->wwpn) { |
1040 | if (wwpn < lport->wwpn) | 1052 | mutex_unlock(&rdata->rp_mutex); |
1041 | reject = ELS_RJT_INPROG; | 1053 | rjt_data.reason = ELS_RJT_INPROG; |
1054 | rjt_data.explan = ELS_EXPL_NONE; | ||
1055 | goto reject; | ||
1056 | } | ||
1042 | break; | 1057 | break; |
1043 | case RPORT_ST_PRLI: | 1058 | case RPORT_ST_PRLI: |
1044 | case RPORT_ST_READY: | 1059 | case RPORT_ST_READY: |
1045 | FC_RPORT_DBG(rdata, "Received PLOGI in logged-in state %d " | ||
1046 | "- ignored for now\n", rdata->rp_state); | ||
1047 | /* XXX TBD - should reset */ | ||
1048 | break; | 1060 | break; |
1049 | case RPORT_ST_DELETE: | 1061 | case RPORT_ST_DELETE: |
1050 | default: | 1062 | default: |
1051 | FC_RPORT_DBG(rdata, "Received PLOGI in unexpected " | 1063 | FC_RPORT_DBG(rdata, "Received PLOGI in unexpected state %d\n", |
1052 | "state %d\n", rdata->rp_state); | 1064 | rdata->rp_state); |
1053 | fc_frame_free(fp); | 1065 | fc_frame_free(rx_fp); |
1054 | return; | 1066 | goto out; |
1055 | break; | ||
1056 | } | 1067 | } |
1057 | 1068 | ||
1058 | if (reject) { | 1069 | /* |
1059 | rjt_data.reason = reject; | 1070 | * Get session payload size from incoming PLOGI. |
1060 | rjt_data.explan = ELS_EXPL_NONE; | 1071 | */ |
1061 | lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &rjt_data); | 1072 | rdata->maxframe_size = fc_plogi_get_maxframe(pl, lport->mfs); |
1062 | fc_frame_free(fp); | 1073 | fc_frame_free(rx_fp); |
1063 | } else { | 1074 | |
1064 | fp = fc_frame_alloc(lport, sizeof(*pl)); | 1075 | /* |
1065 | if (fp == NULL) { | 1076 | * Send LS_ACC. If this fails, the originator should retry. |
1066 | fp = rx_fp; | 1077 | */ |
1067 | rjt_data.reason = ELS_RJT_UNAB; | 1078 | sp = lport->tt.seq_start_next(sp); |
1068 | rjt_data.explan = ELS_EXPL_NONE; | 1079 | if (!sp) |
1069 | lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &rjt_data); | 1080 | goto out; |
1070 | fc_frame_free(fp); | 1081 | fp = fc_frame_alloc(lport, sizeof(*pl)); |
1071 | } else { | 1082 | if (!fp) |
1072 | sp = lport->tt.seq_start_next(sp); | 1083 | goto out; |
1073 | WARN_ON(!sp); | 1084 | |
1074 | rdata->ids.port_name = wwpn; | 1085 | fc_plogi_fill(lport, fp, ELS_LS_ACC); |
1075 | rdata->ids.node_name = wwnn; | 1086 | f_ctl = FC_FC_EX_CTX | FC_FC_LAST_SEQ | FC_FC_END_SEQ | FC_FC_SEQ_INIT; |
1076 | 1087 | ep = fc_seq_exch(sp); | |
1077 | /* | 1088 | fc_fill_fc_hdr(fp, FC_RCTL_ELS_REP, ep->did, ep->sid, |
1078 | * Get session payload size from incoming PLOGI. | 1089 | FC_TYPE_ELS, f_ctl, 0); |
1079 | */ | 1090 | lport->tt.seq_send(lport, sp, fp); |
1080 | rdata->maxframe_size = | 1091 | fc_rport_enter_prli(rdata); |
1081 | fc_plogi_get_maxframe(pl, lport->mfs); | 1092 | out: |
1082 | fc_frame_free(rx_fp); | 1093 | mutex_unlock(&rdata->rp_mutex); |
1083 | fc_plogi_fill(lport, fp, ELS_LS_ACC); | 1094 | return; |
1084 | 1095 | ||
1085 | /* | 1096 | reject: |
1086 | * Send LS_ACC. If this fails, | 1097 | lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &rjt_data); |
1087 | * the originator should retry. | 1098 | fc_frame_free(fp); |
1088 | */ | ||
1089 | f_ctl = FC_FC_EX_CTX | FC_FC_LAST_SEQ; | ||
1090 | f_ctl |= FC_FC_END_SEQ | FC_FC_SEQ_INIT; | ||
1091 | ep = fc_seq_exch(sp); | ||
1092 | fc_fill_fc_hdr(fp, FC_RCTL_ELS_REP, ep->did, ep->sid, | ||
1093 | FC_TYPE_ELS, f_ctl, 0); | ||
1094 | lport->tt.seq_send(lport, sp, fp); | ||
1095 | if (rdata->rp_state == RPORT_ST_PLOGI) | ||
1096 | fc_rport_enter_prli(rdata); | ||
1097 | } | ||
1098 | } | ||
1099 | } | 1099 | } |
1100 | 1100 | ||
1101 | /** | 1101 | /** |
@@ -1138,6 +1138,7 @@ static void fc_rport_recv_prli_req(struct fc_rport_priv *rdata, | |||
1138 | 1138 | ||
1139 | switch (rdata->rp_state) { | 1139 | switch (rdata->rp_state) { |
1140 | case RPORT_ST_PRLI: | 1140 | case RPORT_ST_PRLI: |
1141 | case RPORT_ST_RTV: | ||
1141 | case RPORT_ST_READY: | 1142 | case RPORT_ST_READY: |
1142 | reason = ELS_RJT_NONE; | 1143 | reason = ELS_RJT_NONE; |
1143 | break; | 1144 | break; |