aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/libfc
diff options
context:
space:
mode:
authorJoe Eykholt <jeykholt@cisco.com>2009-08-25 17:02:11 -0400
committerJames Bottomley <James.Bottomley@suse.de>2009-09-10 13:07:48 -0400
commit0f6c6149870e03c722af6eae406758b28cb71320 (patch)
tree7dca629255539d73bd44fea4fb50a9c0a9ddd079 /drivers/scsi/libfc
parent8025b5db7e10cd90cadec940cc766be3bbda65e8 (diff)
[SCSI] libfc: do not log off rports before or after discovery
When receiving an RSCN, do not log off all rports. This is extremely disruptive. If, after the GPN_FT response, some rports haven't been listed, delete them. Add field disc_id to structs fc_rport_priv and fc_disc. disc_id is an arbitrary serial number used to identify the rports found by the latest discovery. This eliminates the need to go through the rport list when restarting discovery. 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/libfc')
-rw-r--r--drivers/scsi/libfc/fc_disc.c47
1 files changed, 34 insertions, 13 deletions
diff --git a/drivers/scsi/libfc/fc_disc.c b/drivers/scsi/libfc/fc_disc.c
index f6762a52147d..ddf494424ff4 100644
--- a/drivers/scsi/libfc/fc_disc.c
+++ b/drivers/scsi/libfc/fc_disc.c
@@ -221,17 +221,19 @@ static void fc_disc_recv_req(struct fc_seq *sp, struct fc_frame *fp,
221 */ 221 */
222static void fc_disc_restart(struct fc_disc *disc) 222static void fc_disc_restart(struct fc_disc *disc)
223{ 223{
224 struct fc_rport_priv *rdata, *next;
225 struct fc_lport *lport = disc->lport;
226
227 FC_DISC_DBG(disc, "Restarting discovery\n"); 224 FC_DISC_DBG(disc, "Restarting discovery\n");
228 225
229 list_for_each_entry_safe(rdata, next, &disc->rports, peers)
230 lport->tt.rport_logoff(rdata);
231
232 disc->requested = 1; 226 disc->requested = 1;
233 if (!disc->pending) 227 if (disc->pending)
234 fc_disc_gpn_ft_req(disc); 228 return;
229
230 /*
231 * Advance disc_id. This is an arbitrary non-zero number that will
232 * match the value in the fc_rport_priv after discovery for all
233 * freshly-discovered remote ports. Avoid wrapping to zero.
234 */
235 disc->disc_id = (disc->disc_id + 2) | 1;
236 fc_disc_gpn_ft_req(disc);
235} 237}
236 238
237/** 239/**
@@ -278,6 +280,7 @@ static void fc_disc_start(void (*disc_callback)(struct fc_lport *,
278 } 280 }
279 kref_put(&rdata->kref, rdata->local_port->tt.rport_destroy); 281 kref_put(&rdata->kref, rdata->local_port->tt.rport_destroy);
280 } else { 282 } else {
283 disc->disc_id = (disc->disc_id + 2) | 1;
281 fc_disc_gpn_ft_req(disc); /* get ports by FC-4 type */ 284 fc_disc_gpn_ft_req(disc); /* get ports by FC-4 type */
282 } 285 }
283 286
@@ -345,13 +348,30 @@ static int fc_disc_new_target(struct fc_disc *disc,
345static void fc_disc_done(struct fc_disc *disc, enum fc_disc_event event) 348static void fc_disc_done(struct fc_disc *disc, enum fc_disc_event event)
346{ 349{
347 struct fc_lport *lport = disc->lport; 350 struct fc_lport *lport = disc->lport;
351 struct fc_rport_priv *rdata;
348 352
349 FC_DISC_DBG(disc, "Discovery complete\n"); 353 FC_DISC_DBG(disc, "Discovery complete\n");
350 354
351 if (disc->requested) 355 disc->pending = 0;
352 fc_disc_gpn_ft_req(disc); 356 if (disc->requested) {
353 else 357 fc_disc_restart(disc);
354 disc->pending = 0; 358 return;
359 }
360
361 /*
362 * Go through all remote ports. If they were found in the latest
363 * discovery, reverify or log them in. Otherwise, log them out.
364 * Skip ports which were never discovered. These are the dNS port
365 * and ports which were created by PLOGI.
366 */
367 list_for_each_entry(rdata, &disc->rports, peers) {
368 if (!rdata->disc_id)
369 continue;
370 if (rdata->disc_id == disc->disc_id)
371 lport->tt.rport_login(rdata);
372 else
373 lport->tt.rport_logoff(rdata);
374 }
355 375
356 mutex_unlock(&disc->disc_mutex); 376 mutex_unlock(&disc->disc_mutex);
357 disc->disc_callback(lport, event); 377 disc->disc_callback(lport, event);
@@ -496,7 +516,7 @@ static int fc_disc_gpn_ft_parse(struct fc_disc *disc, void *buf, size_t len)
496 ids.port_name != lport->wwpn) { 516 ids.port_name != lport->wwpn) {
497 rdata = lport->tt.rport_create(lport, &ids); 517 rdata = lport->tt.rport_create(lport, &ids);
498 if (rdata) 518 if (rdata)
499 lport->tt.rport_login(rdata); 519 rdata->disc_id = disc->disc_id;
500 else 520 else
501 printk(KERN_WARNING "libfc: Failed to allocate " 521 printk(KERN_WARNING "libfc: Failed to allocate "
502 "memory for the newly discovered port " 522 "memory for the newly discovered port "
@@ -640,6 +660,7 @@ static void fc_disc_single(struct fc_disc *disc, struct fc_disc_port *dp)
640 660
641 rdata = lport->tt.rport_create(lport, &dp->ids); 661 rdata = lport->tt.rport_create(lport, &dp->ids);
642 if (rdata) { 662 if (rdata) {
663 rdata->disc_id = disc->disc_id;
643 kfree(dp); 664 kfree(dp);
644 lport->tt.rport_login(rdata); 665 lport->tt.rport_login(rdata);
645 } 666 }