aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/libfc/fc_rport.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi/libfc/fc_rport.c')
-rw-r--r--drivers/scsi/libfc/fc_rport.c137
1 files changed, 88 insertions, 49 deletions
diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c
index e121ff92c8ea..04e9846ad1b5 100644
--- a/drivers/scsi/libfc/fc_rport.c
+++ b/drivers/scsi/libfc/fc_rport.c
@@ -69,7 +69,7 @@ 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 *);
70static void fc_rport_recv_prlo_req(struct fc_rport_priv *, 70static void fc_rport_recv_prlo_req(struct fc_rport_priv *,
71 struct fc_seq *, struct fc_frame *); 71 struct fc_seq *, struct fc_frame *);
72static void fc_rport_recv_logo_req(struct fc_rport_priv *, 72static void fc_rport_recv_logo_req(struct fc_lport *,
73 struct fc_seq *, struct fc_frame *); 73 struct fc_seq *, struct fc_frame *);
74static void fc_rport_timeout(struct work_struct *); 74static void fc_rport_timeout(struct work_struct *);
75static void fc_rport_error(struct fc_rport_priv *, struct fc_frame *); 75static void fc_rport_error(struct fc_rport_priv *, struct fc_frame *);
@@ -908,62 +908,56 @@ static void fc_rport_enter_logo(struct fc_rport_priv *rdata)
908 kref_get(&rdata->kref); 908 kref_get(&rdata->kref);
909} 909}
910 910
911
912/** 911/**
913 * fc_rport_recv_req() - Receive a request from a rport 912 * fc_rport_recv_els_req() - handle a validated ELS request.
913 * @lport: Fibre Channel local port
914 * @sp: current sequence in the PLOGI exchange 914 * @sp: current sequence in the PLOGI exchange
915 * @fp: response frame 915 * @fp: response frame
916 * @lport: Fibre Channel local port 916 *
917 * Handle incoming ELS requests that require port login.
918 * The ELS opcode has already been validated by the caller.
917 * 919 *
918 * Locking Note: Called with the lport lock held. 920 * Locking Note: Called with the lport lock held.
919 */ 921 */
920void fc_rport_recv_req(struct fc_seq *sp, struct fc_frame *fp, 922static void fc_rport_recv_els_req(struct fc_lport *lport,
921 struct fc_lport *lport) 923 struct fc_seq *sp, struct fc_frame *fp)
922{ 924{
923 struct fc_rport_priv *rdata; 925 struct fc_rport_priv *rdata;
924 struct fc_frame_header *fh; 926 struct fc_frame_header *fh;
925 struct fc_seq_els_data els_data; 927 struct fc_seq_els_data els_data;
926 u32 s_id;
927 u8 op;
928 928
929 els_data.fp = NULL; 929 els_data.fp = NULL;
930 els_data.explan = ELS_EXPL_NONE; 930 els_data.reason = ELS_RJT_UNAB;
931 els_data.reason = ELS_RJT_NONE; 931 els_data.explan = ELS_EXPL_PLOGI_REQD;
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
942 fh = fc_frame_header_get(fp); 933 fh = fc_frame_header_get(fp);
943 s_id = ntoh24(fh->fh_s_id);
944 934
945 mutex_lock(&lport->disc.disc_mutex); 935 mutex_lock(&lport->disc.disc_mutex);
946 rdata = lport->tt.rport_lookup(lport, s_id); 936 rdata = lport->tt.rport_lookup(lport, ntoh24(fh->fh_s_id));
947 if (!rdata) { 937 if (!rdata) {
948 mutex_unlock(&lport->disc.disc_mutex); 938 mutex_unlock(&lport->disc.disc_mutex);
949 els_data.reason = ELS_RJT_UNAB; 939 goto reject;
950 lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &els_data);
951 fc_frame_free(fp);
952 return;
953 } 940 }
954 mutex_lock(&rdata->rp_mutex); 941 mutex_lock(&rdata->rp_mutex);
955 mutex_unlock(&lport->disc.disc_mutex); 942 mutex_unlock(&lport->disc.disc_mutex);
956 943
957 switch (op) { 944 switch (rdata->rp_state) {
945 case RPORT_ST_PRLI:
946 case RPORT_ST_RTV:
947 case RPORT_ST_READY:
948 break;
949 default:
950 mutex_unlock(&rdata->rp_mutex);
951 goto reject;
952 }
953
954 switch (fc_frame_payload_op(fp)) {
958 case ELS_PRLI: 955 case ELS_PRLI:
959 fc_rport_recv_prli_req(rdata, sp, fp); 956 fc_rport_recv_prli_req(rdata, sp, fp);
960 break; 957 break;
961 case ELS_PRLO: 958 case ELS_PRLO:
962 fc_rport_recv_prlo_req(rdata, sp, fp); 959 fc_rport_recv_prlo_req(rdata, sp, fp);
963 break; 960 break;
964 case ELS_LOGO:
965 fc_rport_recv_logo_req(rdata, sp, fp);
966 break;
967 case ELS_RRQ: 961 case ELS_RRQ:
968 els_data.fp = fp; 962 els_data.fp = fp;
969 lport->tt.seq_els_rsp_send(sp, ELS_RRQ, &els_data); 963 lport->tt.seq_els_rsp_send(sp, ELS_RRQ, &els_data);
@@ -973,12 +967,58 @@ void fc_rport_recv_req(struct fc_seq *sp, struct fc_frame *fp,
973 lport->tt.seq_els_rsp_send(sp, ELS_REC, &els_data); 967 lport->tt.seq_els_rsp_send(sp, ELS_REC, &els_data);
974 break; 968 break;
975 default: 969 default:
976 els_data.reason = ELS_RJT_UNSUP; 970 fc_frame_free(fp); /* can't happen */
977 lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &els_data);
978 break; 971 break;
979 } 972 }
980 973
981 mutex_unlock(&rdata->rp_mutex); 974 mutex_unlock(&rdata->rp_mutex);
975 return;
976
977reject:
978 lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &els_data);
979 fc_frame_free(fp);
980}
981
982/**
983 * fc_rport_recv_req() - Handle a received ELS request from a rport
984 * @sp: current sequence in the PLOGI exchange
985 * @fp: response frame
986 * @lport: Fibre Channel local port
987 *
988 * Locking Note: Called with the lport lock held.
989 */
990void fc_rport_recv_req(struct fc_seq *sp, struct fc_frame *fp,
991 struct fc_lport *lport)
992{
993 struct fc_seq_els_data els_data;
994
995 /*
996 * Handle PLOGI and LOGO requests separately, since they
997 * don't require prior login.
998 * Check for unsupported opcodes first and reject them.
999 * For some ops, it would be incorrect to reject with "PLOGI required".
1000 */
1001 switch (fc_frame_payload_op(fp)) {
1002 case ELS_PLOGI:
1003 fc_rport_recv_plogi_req(lport, sp, fp);
1004 break;
1005 case ELS_LOGO:
1006 fc_rport_recv_logo_req(lport, sp, fp);
1007 break;
1008 case ELS_PRLI:
1009 case ELS_PRLO:
1010 case ELS_RRQ:
1011 case ELS_REC:
1012 fc_rport_recv_els_req(lport, sp, fp);
1013 break;
1014 default:
1015 fc_frame_free(fp);
1016 els_data.fp = NULL;
1017 els_data.reason = ELS_RJT_UNSUP;
1018 els_data.explan = ELS_EXPL_NONE;
1019 lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &els_data);
1020 break;
1021 }
982} 1022}
983 1023
984/** 1024/**
@@ -1276,11 +1316,6 @@ static void fc_rport_recv_prlo_req(struct fc_rport_priv *rdata,
1276 FC_RPORT_DBG(rdata, "Received PRLO request while in state %s\n", 1316 FC_RPORT_DBG(rdata, "Received PRLO request while in state %s\n",
1277 fc_rport_state(rdata)); 1317 fc_rport_state(rdata));
1278 1318
1279 if (rdata->rp_state == RPORT_ST_DELETE) {
1280 fc_frame_free(fp);
1281 return;
1282 }
1283
1284 rjt_data.fp = NULL; 1319 rjt_data.fp = NULL;
1285 rjt_data.reason = ELS_RJT_UNAB; 1320 rjt_data.reason = ELS_RJT_UNAB;
1286 rjt_data.explan = ELS_EXPL_NONE; 1321 rjt_data.explan = ELS_EXPL_NONE;
@@ -1290,32 +1325,36 @@ static void fc_rport_recv_prlo_req(struct fc_rport_priv *rdata,
1290 1325
1291/** 1326/**
1292 * fc_rport_recv_logo_req() - Handle incoming Logout (LOGO) request 1327 * fc_rport_recv_logo_req() - Handle incoming Logout (LOGO) request
1293 * @rdata: private remote port data 1328 * @lport: local port.
1294 * @sp: current sequence in the LOGO exchange 1329 * @sp: current sequence in the LOGO exchange
1295 * @fp: LOGO request frame 1330 * @fp: LOGO request frame
1296 * 1331 *
1297 * Locking Note: The rport lock is exected to be held before calling 1332 * Locking Note: The rport lock is exected to be held before calling
1298 * this function. 1333 * this function.
1299 */ 1334 */
1300static void fc_rport_recv_logo_req(struct fc_rport_priv *rdata, 1335static void fc_rport_recv_logo_req(struct fc_lport *lport,
1301 struct fc_seq *sp, 1336 struct fc_seq *sp,
1302 struct fc_frame *fp) 1337 struct fc_frame *fp)
1303{ 1338{
1304 struct fc_frame_header *fh; 1339 struct fc_frame_header *fh;
1305 struct fc_lport *lport = rdata->local_port; 1340 struct fc_rport_priv *rdata;
1341 u32 sid;
1306 1342
1307 fh = fc_frame_header_get(fp); 1343 fh = fc_frame_header_get(fp);
1344 sid = ntoh24(fh->fh_s_id);
1308 1345
1309 FC_RPORT_DBG(rdata, "Received LOGO request while in state %s\n", 1346 mutex_lock(&lport->disc.disc_mutex);
1310 fc_rport_state(rdata)); 1347 rdata = lport->tt.rport_lookup(lport, sid);
1311 1348 if (rdata) {
1312 if (rdata->rp_state == RPORT_ST_DELETE) { 1349 mutex_lock(&rdata->rp_mutex);
1313 fc_frame_free(fp); 1350 FC_RPORT_DBG(rdata, "Received LOGO request while in state %s\n",
1314 return; 1351 fc_rport_state(rdata));
1315 } 1352 fc_rport_enter_delete(rdata, RPORT_EV_LOGO);
1316 1353 mutex_unlock(&rdata->rp_mutex);
1317 fc_rport_enter_delete(rdata, RPORT_EV_LOGO); 1354 } else
1318 1355 FC_RPORT_ID_DBG(lport, sid,
1356 "Received LOGO from non-logged-in port\n");
1357 mutex_unlock(&lport->disc.disc_mutex);
1319 lport->tt.seq_els_rsp_send(sp, ELS_LS_ACC, NULL); 1358 lport->tt.seq_els_rsp_send(sp, ELS_LS_ACC, NULL);
1320 fc_frame_free(fp); 1359 fc_frame_free(fp);
1321} 1360}