aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi
diff options
context:
space:
mode:
authorJoe Eykholt <jeykholt@cisco.com>2009-08-25 17:03:47 -0400
committerJames Bottomley <James.Bottomley@suse.de>2009-09-10 13:08:02 -0400
commit370c3bd05cf02afabea9cd3f2de66202d6b516dc (patch)
tree832cf6b3091db117f119aa8692d050f43fe0a9cb /drivers/scsi
parent68a1750b46ad5177f7703081b5fe85624f1aa62b (diff)
[SCSI] libfc: use ADISC to verify rport login state
When rport_login is called on an rport that is already thought to be logged in, use ADISC. If that fails, redo PLOGI. This is less disruptive after fabric changes that don't affect the state of the target. Implement the sending of ADISC via fc_els_fill. Add ADISC state to the rport state machine. This is entered from READY and returns to READY after successful completion. If it fails, the rport is either logged off and deleted or re-does PLOGI. 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.c122
1 files changed, 117 insertions, 5 deletions
diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c
index b5bc8724e1a0..c33e25851082 100644
--- a/drivers/scsi/libfc/fc_rport.c
+++ b/drivers/scsi/libfc/fc_rport.c
@@ -62,6 +62,7 @@ static void fc_rport_enter_prli(struct fc_rport_priv *);
62static void fc_rport_enter_rtv(struct fc_rport_priv *); 62static 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 *);
65static void fc_rport_enter_adisc(struct fc_rport_priv *);
65 66
66static void fc_rport_recv_plogi_req(struct fc_lport *, 67static void fc_rport_recv_plogi_req(struct fc_lport *,
67 struct fc_seq *, struct fc_frame *); 68 struct fc_seq *, struct fc_frame *);
@@ -83,6 +84,7 @@ static const char *fc_rport_state_names[] = {
83 [RPORT_ST_RTV] = "RTV", 84 [RPORT_ST_RTV] = "RTV",
84 [RPORT_ST_READY] = "Ready", 85 [RPORT_ST_READY] = "Ready",
85 [RPORT_ST_LOGO] = "LOGO", 86 [RPORT_ST_LOGO] = "LOGO",
87 [RPORT_ST_ADISC] = "ADISC",
86 [RPORT_ST_DELETE] = "Delete", 88 [RPORT_ST_DELETE] = "Delete",
87}; 89};
88 90
@@ -326,15 +328,25 @@ static void fc_rport_work(struct work_struct *work)
326 * Locking Note: Called without the rport lock held. This 328 * Locking Note: Called without the rport lock held. This
327 * function will hold the rport lock, call an _enter_* 329 * function will hold the rport lock, call an _enter_*
328 * function and then unlock the rport. 330 * function and then unlock the rport.
331 *
332 * This indicates the intent to be logged into the remote port.
333 * If it appears we are already logged in, ADISC is used to verify
334 * the setup.
329 */ 335 */
330int fc_rport_login(struct fc_rport_priv *rdata) 336int fc_rport_login(struct fc_rport_priv *rdata)
331{ 337{
332 mutex_lock(&rdata->rp_mutex); 338 mutex_lock(&rdata->rp_mutex);
333 339
334 FC_RPORT_DBG(rdata, "Login to port\n"); 340 switch (rdata->rp_state) {
335 341 case RPORT_ST_READY:
336 fc_rport_enter_plogi(rdata); 342 FC_RPORT_DBG(rdata, "ADISC port\n");
337 343 fc_rport_enter_adisc(rdata);
344 break;
345 default:
346 FC_RPORT_DBG(rdata, "Login to port\n");
347 fc_rport_enter_plogi(rdata);
348 break;
349 }
338 mutex_unlock(&rdata->rp_mutex); 350 mutex_unlock(&rdata->rp_mutex);
339 351
340 return 0; 352 return 0;
@@ -448,6 +460,9 @@ static void fc_rport_timeout(struct work_struct *work)
448 case RPORT_ST_LOGO: 460 case RPORT_ST_LOGO:
449 fc_rport_enter_logo(rdata); 461 fc_rport_enter_logo(rdata);
450 break; 462 break;
463 case RPORT_ST_ADISC:
464 fc_rport_enter_adisc(rdata);
465 break;
451 case RPORT_ST_READY: 466 case RPORT_ST_READY:
452 case RPORT_ST_INIT: 467 case RPORT_ST_INIT:
453 case RPORT_ST_DELETE: 468 case RPORT_ST_DELETE:
@@ -473,13 +488,16 @@ static void fc_rport_error(struct fc_rport_priv *rdata, struct fc_frame *fp)
473 488
474 switch (rdata->rp_state) { 489 switch (rdata->rp_state) {
475 case RPORT_ST_PLOGI: 490 case RPORT_ST_PLOGI:
476 case RPORT_ST_PRLI:
477 case RPORT_ST_LOGO: 491 case RPORT_ST_LOGO:
478 fc_rport_enter_delete(rdata, RPORT_EV_FAILED); 492 fc_rport_enter_delete(rdata, RPORT_EV_FAILED);
479 break; 493 break;
480 case RPORT_ST_RTV: 494 case RPORT_ST_RTV:
481 fc_rport_enter_ready(rdata); 495 fc_rport_enter_ready(rdata);
482 break; 496 break;
497 case RPORT_ST_PRLI:
498 case RPORT_ST_ADISC:
499 fc_rport_enter_logo(rdata);
500 break;
483 case RPORT_ST_DELETE: 501 case RPORT_ST_DELETE:
484 case RPORT_ST_READY: 502 case RPORT_ST_READY:
485 case RPORT_ST_INIT: 503 case RPORT_ST_INIT:
@@ -907,6 +925,93 @@ static void fc_rport_enter_logo(struct fc_rport_priv *rdata)
907} 925}
908 926
909/** 927/**
928 * fc_rport_els_adisc_resp() - Address Discovery response handler
929 * @sp: current sequence in the ADISC exchange
930 * @fp: response frame
931 * @rdata_arg: remote port private.
932 *
933 * Locking Note: This function will be called without the rport lock
934 * held, but it will lock, call an _enter_* function or fc_rport_error
935 * and then unlock the rport.
936 */
937static void fc_rport_adisc_resp(struct fc_seq *sp, struct fc_frame *fp,
938 void *rdata_arg)
939{
940 struct fc_rport_priv *rdata = rdata_arg;
941 struct fc_els_adisc *adisc;
942 u8 op;
943
944 mutex_lock(&rdata->rp_mutex);
945
946 FC_RPORT_DBG(rdata, "Received a ADISC response\n");
947
948 if (rdata->rp_state != RPORT_ST_ADISC) {
949 FC_RPORT_DBG(rdata, "Received a ADISC resp but in state %s\n",
950 fc_rport_state(rdata));
951 if (IS_ERR(fp))
952 goto err;
953 goto out;
954 }
955
956 if (IS_ERR(fp)) {
957 fc_rport_error(rdata, fp);
958 goto err;
959 }
960
961 /*
962 * If address verification failed. Consider us logged out of the rport.
963 * Since the rport is still in discovery, we want to be
964 * logged in, so go to PLOGI state. Otherwise, go back to READY.
965 */
966 op = fc_frame_payload_op(fp);
967 adisc = fc_frame_payload_get(fp, sizeof(*adisc));
968 if (op != ELS_LS_ACC || !adisc ||
969 ntoh24(adisc->adisc_port_id) != rdata->ids.port_id ||
970 get_unaligned_be64(&adisc->adisc_wwpn) != rdata->ids.port_name ||
971 get_unaligned_be64(&adisc->adisc_wwnn) != rdata->ids.node_name) {
972 FC_RPORT_DBG(rdata, "ADISC error or mismatch\n");
973 fc_rport_enter_plogi(rdata);
974 } else {
975 FC_RPORT_DBG(rdata, "ADISC OK\n");
976 fc_rport_enter_ready(rdata);
977 }
978out:
979 fc_frame_free(fp);
980err:
981 mutex_unlock(&rdata->rp_mutex);
982 kref_put(&rdata->kref, rdata->local_port->tt.rport_destroy);
983}
984
985/**
986 * fc_rport_enter_adisc() - Send Address Discover (ADISC) request to peer
987 * @rdata: remote port private data
988 *
989 * Locking Note: The rport lock is expected to be held before calling
990 * this routine.
991 */
992static void fc_rport_enter_adisc(struct fc_rport_priv *rdata)
993{
994 struct fc_lport *lport = rdata->local_port;
995 struct fc_frame *fp;
996
997 FC_RPORT_DBG(rdata, "sending ADISC from %s state\n",
998 fc_rport_state(rdata));
999
1000 fc_rport_state_enter(rdata, RPORT_ST_ADISC);
1001
1002 fp = fc_frame_alloc(lport, sizeof(struct fc_els_adisc));
1003 if (!fp) {
1004 fc_rport_error_retry(rdata, fp);
1005 return;
1006 }
1007 if (!lport->tt.elsct_send(lport, rdata->ids.port_id, fp, ELS_ADISC,
1008 fc_rport_adisc_resp, rdata, lport->e_d_tov))
1009 fc_rport_error_retry(rdata, fp);
1010 else
1011 kref_get(&rdata->kref);
1012}
1013
1014/**
910 * fc_rport_recv_els_req() - handle a validated ELS request. 1015 * fc_rport_recv_els_req() - handle a validated ELS request.
911 * @lport: Fibre Channel local port 1016 * @lport: Fibre Channel local port
912 * @sp: current sequence in the PLOGI exchange 1017 * @sp: current sequence in the PLOGI exchange
@@ -943,6 +1048,7 @@ static void fc_rport_recv_els_req(struct fc_lport *lport,
943 case RPORT_ST_PRLI: 1048 case RPORT_ST_PRLI:
944 case RPORT_ST_RTV: 1049 case RPORT_ST_RTV:
945 case RPORT_ST_READY: 1050 case RPORT_ST_READY:
1051 case RPORT_ST_ADISC:
946 break; 1052 break;
947 default: 1053 default:
948 mutex_unlock(&rdata->rp_mutex); 1054 mutex_unlock(&rdata->rp_mutex);
@@ -1095,6 +1201,10 @@ static void fc_rport_recv_plogi_req(struct fc_lport *lport,
1095 break; 1201 break;
1096 case RPORT_ST_PRLI: 1202 case RPORT_ST_PRLI:
1097 case RPORT_ST_READY: 1203 case RPORT_ST_READY:
1204 case RPORT_ST_ADISC:
1205 FC_RPORT_DBG(rdata, "Received PLOGI in logged-in state %d "
1206 "- ignored for now\n", rdata->rp_state);
1207 /* XXX TBD - should reset */
1098 break; 1208 break;
1099 case RPORT_ST_DELETE: 1209 case RPORT_ST_DELETE:
1100 default: 1210 default:
@@ -1178,6 +1288,7 @@ static void fc_rport_recv_prli_req(struct fc_rport_priv *rdata,
1178 case RPORT_ST_PRLI: 1288 case RPORT_ST_PRLI:
1179 case RPORT_ST_RTV: 1289 case RPORT_ST_RTV:
1180 case RPORT_ST_READY: 1290 case RPORT_ST_READY:
1291 case RPORT_ST_ADISC:
1181 reason = ELS_RJT_NONE; 1292 reason = ELS_RJT_NONE;
1182 break; 1293 break;
1183 default: 1294 default:
@@ -1283,6 +1394,7 @@ static void fc_rport_recv_prli_req(struct fc_rport_priv *rdata,
1283 fc_rport_enter_ready(rdata); 1394 fc_rport_enter_ready(rdata);
1284 break; 1395 break;
1285 case RPORT_ST_READY: 1396 case RPORT_ST_READY:
1397 case RPORT_ST_ADISC:
1286 break; 1398 break;
1287 default: 1399 default:
1288 break; 1400 break;