aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/scsi/libfc/fc_rport.c122
-rw-r--r--include/scsi/fc_encode.h21
-rw-r--r--include/scsi/libfc.h1
3 files changed, 139 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;
diff --git a/include/scsi/fc_encode.h b/include/scsi/fc_encode.h
index 24bf764f9884..c5ee6bb79e05 100644
--- a/include/scsi/fc_encode.h
+++ b/include/scsi/fc_encode.h
@@ -57,6 +57,23 @@ static inline void fc_fill_fc_hdr(struct fc_frame *fp, enum fc_rctl r_ctl,
57} 57}
58 58
59/** 59/**
60 * fc_adisc_fill() - Fill in adisc request frame
61 * @lport: local port.
62 * @fp: fc frame where payload will be placed.
63 */
64static inline void fc_adisc_fill(struct fc_lport *lport, struct fc_frame *fp)
65{
66 struct fc_els_adisc *adisc;
67
68 adisc = fc_frame_payload_get(fp, sizeof(*adisc));
69 memset(adisc, 0, sizeof(*adisc));
70 adisc->adisc_cmd = ELS_ADISC;
71 put_unaligned_be64(lport->wwpn, &adisc->adisc_wwpn);
72 put_unaligned_be64(lport->wwnn, &adisc->adisc_wwnn);
73 hton24(adisc->adisc_port_id, fc_host_port_id(lport->host));
74}
75
76/**
60 * fc_ct_hdr_fill- fills ct header and reset ct payload 77 * fc_ct_hdr_fill- fills ct header and reset ct payload
61 * returns pointer to ct request. 78 * returns pointer to ct request.
62 */ 79 */
@@ -255,6 +272,10 @@ static inline int fc_els_fill(struct fc_lport *lport,
255 enum fc_rctl *r_ctl, enum fc_fh_type *fh_type) 272 enum fc_rctl *r_ctl, enum fc_fh_type *fh_type)
256{ 273{
257 switch (op) { 274 switch (op) {
275 case ELS_ADISC:
276 fc_adisc_fill(lport, fp);
277 break;
278
258 case ELS_PLOGI: 279 case ELS_PLOGI:
259 fc_plogi_fill(lport, fp, ELS_PLOGI); 280 fc_plogi_fill(lport, fp, ELS_PLOGI);
260 break; 281 break;
diff --git a/include/scsi/libfc.h b/include/scsi/libfc.h
index e18e5ce5af51..65dc9aacbf70 100644
--- a/include/scsi/libfc.h
+++ b/include/scsi/libfc.h
@@ -143,6 +143,7 @@ enum fc_rport_state {
143 RPORT_ST_RTV, /* waiting for RTV completion */ 143 RPORT_ST_RTV, /* waiting for RTV completion */
144 RPORT_ST_READY, /* ready for use */ 144 RPORT_ST_READY, /* ready for use */
145 RPORT_ST_LOGO, /* port logout sent */ 145 RPORT_ST_LOGO, /* port logout sent */
146 RPORT_ST_ADISC, /* Discover Address sent */
146 RPORT_ST_DELETE, /* port being deleted */ 147 RPORT_ST_DELETE, /* port being deleted */
147}; 148};
148 149