aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi')
-rw-r--r--drivers/scsi/libfc/fc_rport.c185
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 *);
63static void fc_rport_enter_ready(struct fc_rport_priv *); 63static void fc_rport_enter_ready(struct fc_rport_priv *);
64static void fc_rport_enter_logo(struct fc_rport_priv *); 64static void fc_rport_enter_logo(struct fc_rport_priv *);
65 65
66static void fc_rport_recv_plogi_req(struct fc_rport_priv *, 66static void fc_rport_recv_plogi_req(struct fc_lport *,
67 struct fc_seq *, struct fc_frame *); 67 struct fc_seq *, struct fc_frame *);
68static void fc_rport_recv_prli_req(struct fc_rport_priv *, 68static 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 */
987static void fc_rport_recv_plogi_req(struct fc_rport_priv *rdata, 992static 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); 1092out:
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 /* 1096reject:
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;