aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/libfc/fc_rport.c
diff options
context:
space:
mode:
authorAbhijeet Joglekar <abjoglek@cisco.com>2009-04-21 19:27:04 -0400
committerJames Bottomley <James.Bottomley@HansenPartnership.com>2009-04-27 11:18:57 -0400
commitb4c6f54632ad664a3d9e7f05e4ea0f1803e32755 (patch)
tree6d419c4a2cdf1e58ae8044d006c53df9cb856f07 /drivers/scsi/libfc/fc_rport.c
parent76f6804e7e7bb836cbdf4a73fe6c5485e4cc04c2 (diff)
[SCSI] libfc: Track rogue remote ports
Rogue ports are currently not tracked on any list. The only reference to them is through any outstanding exchanges pending on the rogue ports. If the module is removed while a retry is set on a rogue port (say a Plogi retry for instance), this retry is not cancelled because there is no reference to the rogue port in the discovery rports list. Thus the local port can clean itself up, delete the exchange pool, and then the rogue port timeout can fire and try to start up another exchange. This patch tracks the rogue ports in a new list disc->rogue_rports. Creating a new list instead of using the disc->rports list keeps remote port code change to a minimum. 1) Whenever a rogue port is created, it is immediately added to the disc->rogue_rports list. 2) When the rogues port goes to ready, it is removed from the rogue list and the real remote port is added to the disc->rports list 3) The removal of the rogue from the disc->rogue_rports list is done in the context of the fc_rport_work() workQ thread in discovery callback. 4) Real rports are removed from the disc->rports list like before. Lookup is done only in the real rports list. This avoids making large changes to the remote port code. 5) In fc_disc_stop_rports, the rogues list is traversed in addition to the real list to stop the rogue ports and issue logoffs on them. This way, rogue ports get cleaned up when the local port goes away. 6) rogue remote ports are not removed from the list right away, but removed late in fc_rport_work() context, multiple threads can find the same remote port in the list and call rport_logoff(). Rport_logoff() only continues with the logoff if port is not in NONE state, thus preventing multiple logoffs and multiple list deletions. 7) Since the rport is removed from the disc list at a later stage (in the disc callback), incoming frames can find the rport even if rport_logoff() has been called on the rport. When rport_logoff() is called, the rport state is set to NONE, and we are trying to cancel all exchanges and retries on that port. While in this state, if an incoming Plogi/Prli/Logo or other frames match the rport, we should not reply because the rport is in the NONE state. Just drop the frame, since the rport will be deleted soon in the disc callback (fc_rport_work) 8) In fc_disc_single(), remove rport lookup and call to fc_disc_del_target. fc_disc_single() is called from recv_rscn_req() where rport lookup and rport_logoff is already done. Signed-off-by: Abhijeet Joglekar <abjoglek@cisco.com> Signed-off-by: Robert Love <robert.w.love@intel.com> Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
Diffstat (limited to 'drivers/scsi/libfc/fc_rport.c')
-rw-r--r--drivers/scsi/libfc/fc_rport.c28
1 files changed, 28 insertions, 0 deletions
diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c
index eef70b4b7b92..5bf7a949f051 100644
--- a/drivers/scsi/libfc/fc_rport.c
+++ b/drivers/scsi/libfc/fc_rport.c
@@ -267,6 +267,10 @@ static void fc_rport_work(struct work_struct *work)
267 "(%6x).\n", ids.port_id); 267 "(%6x).\n", ids.port_id);
268 event = RPORT_EV_FAILED; 268 event = RPORT_EV_FAILED;
269 } 269 }
270 if (rport->port_id != FC_FID_DIR_SERV)
271 if (rport_ops->event_callback)
272 rport_ops->event_callback(lport, rport,
273 RPORT_EV_FAILED);
270 put_device(&rport->dev); 274 put_device(&rport->dev);
271 rport = new_rport; 275 rport = new_rport;
272 rdata = new_rport->dd_data; 276 rdata = new_rport->dd_data;
@@ -325,11 +329,20 @@ int fc_rport_login(struct fc_rport *rport)
325int fc_rport_logoff(struct fc_rport *rport) 329int fc_rport_logoff(struct fc_rport *rport)
326{ 330{
327 struct fc_rport_libfc_priv *rdata = rport->dd_data; 331 struct fc_rport_libfc_priv *rdata = rport->dd_data;
332 struct fc_lport *lport = rdata->local_port;
328 333
329 mutex_lock(&rdata->rp_mutex); 334 mutex_lock(&rdata->rp_mutex);
330 335
331 FC_DEBUG_RPORT("Remove port (%6x)\n", rport->port_id); 336 FC_DEBUG_RPORT("Remove port (%6x)\n", rport->port_id);
332 337
338 if (rdata->rp_state == RPORT_ST_NONE) {
339 FC_DEBUG_RPORT("(%6x): Port (%6x) in NONE state,"
340 " not removing", fc_host_port_id(lport->host),
341 rport->port_id);
342 mutex_unlock(&rdata->rp_mutex);
343 goto out;
344 }
345
333 fc_rport_enter_logo(rport); 346 fc_rport_enter_logo(rport);
334 347
335 /* 348 /*
@@ -349,6 +362,7 @@ int fc_rport_logoff(struct fc_rport *rport)
349 362
350 mutex_unlock(&rdata->rp_mutex); 363 mutex_unlock(&rdata->rp_mutex);
351 364
365out:
352 return 0; 366 return 0;
353} 367}
354 368
@@ -1015,6 +1029,8 @@ static void fc_rport_recv_plogi_req(struct fc_rport *rport,
1015 default: 1029 default:
1016 FC_DEBUG_RPORT("incoming PLOGI from %x in unexpected " 1030 FC_DEBUG_RPORT("incoming PLOGI from %x in unexpected "
1017 "state %d\n", sid, rdata->rp_state); 1031 "state %d\n", sid, rdata->rp_state);
1032 fc_frame_free(fp);
1033 return;
1018 break; 1034 break;
1019 } 1035 }
1020 1036
@@ -1106,6 +1122,8 @@ static void fc_rport_recv_prli_req(struct fc_rport *rport,
1106 reason = ELS_RJT_NONE; 1122 reason = ELS_RJT_NONE;
1107 break; 1123 break;
1108 default: 1124 default:
1125 fc_frame_free(rx_fp);
1126 return;
1109 break; 1127 break;
1110 } 1128 }
1111 len = fr_len(rx_fp) - sizeof(*fh); 1129 len = fr_len(rx_fp) - sizeof(*fh);
@@ -1235,6 +1253,11 @@ static void fc_rport_recv_prlo_req(struct fc_rport *rport, struct fc_seq *sp,
1235 "while in state %s\n", ntoh24(fh->fh_s_id), 1253 "while in state %s\n", ntoh24(fh->fh_s_id),
1236 fc_rport_state(rport)); 1254 fc_rport_state(rport));
1237 1255
1256 if (rdata->rp_state == RPORT_ST_NONE) {
1257 fc_frame_free(fp);
1258 return;
1259 }
1260
1238 rjt_data.fp = NULL; 1261 rjt_data.fp = NULL;
1239 rjt_data.reason = ELS_RJT_UNAB; 1262 rjt_data.reason = ELS_RJT_UNAB;
1240 rjt_data.explan = ELS_EXPL_NONE; 1263 rjt_data.explan = ELS_EXPL_NONE;
@@ -1264,6 +1287,11 @@ static void fc_rport_recv_logo_req(struct fc_rport *rport, struct fc_seq *sp,
1264 "while in state %s\n", ntoh24(fh->fh_s_id), 1287 "while in state %s\n", ntoh24(fh->fh_s_id),
1265 fc_rport_state(rport)); 1288 fc_rport_state(rport));
1266 1289
1290 if (rdata->rp_state == RPORT_ST_NONE) {
1291 fc_frame_free(fp);
1292 return;
1293 }
1294
1267 rdata->event = RPORT_EV_LOGO; 1295 rdata->event = RPORT_EV_LOGO;
1268 queue_work(rport_event_queue, &rdata->event_work); 1296 queue_work(rport_event_queue, &rdata->event_work);
1269 1297