aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi
diff options
context:
space:
mode:
authorJoe Eykholt <jeykholt@cisco.com>2009-08-25 17:03:31 -0400
committerJames Bottomley <James.Bottomley@suse.de>2009-09-10 13:08:00 -0400
commit83fe6a93465750d1a20221aaa9a253d9ea7fe45c (patch)
treee8e58482fff06ac935f6ca0f6dcef2341956d539 /drivers/scsi
parent3ac6f98f4113ec1c115cf9d443a9bff816e47c0b (diff)
[SCSI] libfc: fix rport error handling for login-required and invalid ops
When receiving an ELS request, if the request isn't recognized, the unsupported operation error should be given even if the port is not found or not logged in. Also, the LOGO request shouldn't give the login-required explanation. Signed-off-by: Joe Eykholt <jeykholt@cisco.com> Signed-off-by: Robert Love <robert.w.love@intel.com> Signed-off-by: James Bottomley <James.Bottomley@suse.de>
Diffstat (limited to 'drivers/scsi')
-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}