diff options
Diffstat (limited to 'drivers/scsi/libfc/fc_rport.c')
-rw-r--r-- | drivers/scsi/libfc/fc_rport.c | 137 |
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 *); |
70 | static void fc_rport_recv_prlo_req(struct fc_rport_priv *, | 70 | static void fc_rport_recv_prlo_req(struct fc_rport_priv *, |
71 | struct fc_seq *, struct fc_frame *); | 71 | struct fc_seq *, struct fc_frame *); |
72 | static void fc_rport_recv_logo_req(struct fc_rport_priv *, | 72 | static void fc_rport_recv_logo_req(struct fc_lport *, |
73 | struct fc_seq *, struct fc_frame *); | 73 | struct fc_seq *, struct fc_frame *); |
74 | static void fc_rport_timeout(struct work_struct *); | 74 | static void fc_rport_timeout(struct work_struct *); |
75 | static void fc_rport_error(struct fc_rport_priv *, struct fc_frame *); | 75 | static 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 | */ |
920 | void fc_rport_recv_req(struct fc_seq *sp, struct fc_frame *fp, | 922 | static 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 | |||
977 | reject: | ||
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 | */ | ||
990 | void 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 | */ |
1300 | static void fc_rport_recv_logo_req(struct fc_rport_priv *rdata, | 1335 | static 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 | } |