diff options
Diffstat (limited to 'drivers/scsi/libfc/fc_disc.c')
-rw-r--r-- | drivers/scsi/libfc/fc_disc.c | 54 |
1 files changed, 40 insertions, 14 deletions
diff --git a/drivers/scsi/libfc/fc_disc.c b/drivers/scsi/libfc/fc_disc.c index e57556ea5b48..4c880656990b 100644 --- a/drivers/scsi/libfc/fc_disc.c +++ b/drivers/scsi/libfc/fc_disc.c | |||
@@ -113,6 +113,11 @@ void fc_disc_stop_rports(struct fc_disc *disc) | |||
113 | lport->tt.rport_logoff(rport); | 113 | lport->tt.rport_logoff(rport); |
114 | } | 114 | } |
115 | 115 | ||
116 | list_for_each_entry_safe(rdata, next, &disc->rogue_rports, peers) { | ||
117 | rport = PRIV_TO_RPORT(rdata); | ||
118 | lport->tt.rport_logoff(rport); | ||
119 | } | ||
120 | |||
116 | mutex_unlock(&disc->disc_mutex); | 121 | mutex_unlock(&disc->disc_mutex); |
117 | } | 122 | } |
118 | 123 | ||
@@ -131,23 +136,32 @@ static void fc_disc_rport_callback(struct fc_lport *lport, | |||
131 | { | 136 | { |
132 | struct fc_rport_libfc_priv *rdata = rport->dd_data; | 137 | struct fc_rport_libfc_priv *rdata = rport->dd_data; |
133 | struct fc_disc *disc = &lport->disc; | 138 | struct fc_disc *disc = &lport->disc; |
134 | int found = 0; | ||
135 | 139 | ||
136 | FC_DEBUG_DISC("Received a %d event for port (%6x)\n", event, | 140 | FC_DEBUG_DISC("Received a %d event for port (%6x)\n", event, |
137 | rport->port_id); | 141 | rport->port_id); |
138 | 142 | ||
139 | if (event == RPORT_EV_CREATED) { | 143 | switch (event) { |
144 | case RPORT_EV_CREATED: | ||
140 | if (disc) { | 145 | if (disc) { |
141 | found = 1; | ||
142 | mutex_lock(&disc->disc_mutex); | 146 | mutex_lock(&disc->disc_mutex); |
143 | list_add_tail(&rdata->peers, &disc->rports); | 147 | list_add_tail(&rdata->peers, &disc->rports); |
144 | mutex_unlock(&disc->disc_mutex); | 148 | mutex_unlock(&disc->disc_mutex); |
145 | } | 149 | } |
150 | break; | ||
151 | case RPORT_EV_LOGO: | ||
152 | case RPORT_EV_FAILED: | ||
153 | case RPORT_EV_STOP: | ||
154 | mutex_lock(&disc->disc_mutex); | ||
155 | mutex_lock(&rdata->rp_mutex); | ||
156 | if (rdata->trans_state == FC_PORTSTATE_ROGUE) | ||
157 | list_del(&rdata->peers); | ||
158 | mutex_unlock(&rdata->rp_mutex); | ||
159 | mutex_unlock(&disc->disc_mutex); | ||
160 | break; | ||
161 | default: | ||
162 | break; | ||
146 | } | 163 | } |
147 | 164 | ||
148 | if (!found) | ||
149 | FC_DEBUG_DISC("The rport (%6x) is not maintained " | ||
150 | "by the discovery layer\n", rport->port_id); | ||
151 | } | 165 | } |
152 | 166 | ||
153 | /** | 167 | /** |
@@ -439,6 +453,7 @@ static int fc_disc_new_target(struct fc_disc *disc, | |||
439 | rdata = rport->dd_data; | 453 | rdata = rport->dd_data; |
440 | rdata->ops = &fc_disc_rport_ops; | 454 | rdata->ops = &fc_disc_rport_ops; |
441 | rdata->rp_state = RPORT_ST_INIT; | 455 | rdata->rp_state = RPORT_ST_INIT; |
456 | list_add_tail(&rdata->peers, &disc->rogue_rports); | ||
442 | lport->tt.rport_login(rport); | 457 | lport->tt.rport_login(rport); |
443 | } | 458 | } |
444 | } | 459 | } |
@@ -461,21 +476,29 @@ static void fc_disc_del_target(struct fc_disc *disc, struct fc_rport *rport) | |||
461 | /** | 476 | /** |
462 | * fc_disc_done() - Discovery has been completed | 477 | * fc_disc_done() - Discovery has been completed |
463 | * @disc: FC discovery context | 478 | * @disc: FC discovery context |
479 | * Locking Note: This function expects that the disc mutex is locked before | ||
480 | * it is called. The discovery callback is then made with the lock released, | ||
481 | * and the lock is re-taken before returning from this function | ||
464 | */ | 482 | */ |
465 | static void fc_disc_done(struct fc_disc *disc) | 483 | static void fc_disc_done(struct fc_disc *disc) |
466 | { | 484 | { |
467 | struct fc_lport *lport = disc->lport; | 485 | struct fc_lport *lport = disc->lport; |
486 | enum fc_disc_event event; | ||
468 | 487 | ||
469 | FC_DEBUG_DISC("Discovery complete for port (%6x)\n", | 488 | FC_DEBUG_DISC("Discovery complete for port (%6x)\n", |
470 | fc_host_port_id(lport->host)); | 489 | fc_host_port_id(lport->host)); |
471 | 490 | ||
472 | disc->disc_callback(lport, disc->event); | 491 | event = disc->event; |
473 | disc->event = DISC_EV_NONE; | 492 | disc->event = DISC_EV_NONE; |
474 | 493 | ||
475 | if (disc->requested) | 494 | if (disc->requested) |
476 | fc_disc_gpn_ft_req(disc); | 495 | fc_disc_gpn_ft_req(disc); |
477 | else | 496 | else |
478 | disc->pending = 0; | 497 | disc->pending = 0; |
498 | |||
499 | mutex_unlock(&disc->disc_mutex); | ||
500 | disc->disc_callback(lport, event); | ||
501 | mutex_lock(&disc->disc_mutex); | ||
479 | } | 502 | } |
480 | 503 | ||
481 | /** | 504 | /** |
@@ -622,6 +645,8 @@ static int fc_disc_gpn_ft_parse(struct fc_disc *disc, void *buf, size_t len) | |||
622 | rdata = rport->dd_data; | 645 | rdata = rport->dd_data; |
623 | rdata->ops = &fc_disc_rport_ops; | 646 | rdata->ops = &fc_disc_rport_ops; |
624 | rdata->local_port = lport; | 647 | rdata->local_port = lport; |
648 | list_add_tail(&rdata->peers, | ||
649 | &disc->rogue_rports); | ||
625 | lport->tt.rport_login(rport); | 650 | lport->tt.rport_login(rport); |
626 | } else | 651 | } else |
627 | FC_DBG("Failed to allocate memory for " | 652 | FC_DBG("Failed to allocate memory for " |
@@ -681,8 +706,8 @@ static void fc_disc_timeout(struct work_struct *work) | |||
681 | * @fp: response frame | 706 | * @fp: response frame |
682 | * @lp_arg: Fibre Channel host port instance | 707 | * @lp_arg: Fibre Channel host port instance |
683 | * | 708 | * |
684 | * Locking Note: This function expects that the disc_mutex is locked | 709 | * Locking Note: This function is called without disc mutex held, and |
685 | * before it is called. | 710 | * should do all its processing with the mutex held |
686 | */ | 711 | */ |
687 | static void fc_disc_gpn_ft_resp(struct fc_seq *sp, struct fc_frame *fp, | 712 | static void fc_disc_gpn_ft_resp(struct fc_seq *sp, struct fc_frame *fp, |
688 | void *disc_arg) | 713 | void *disc_arg) |
@@ -695,11 +720,13 @@ static void fc_disc_gpn_ft_resp(struct fc_seq *sp, struct fc_frame *fp, | |||
695 | unsigned int len; | 720 | unsigned int len; |
696 | int error; | 721 | int error; |
697 | 722 | ||
723 | mutex_lock(&disc->disc_mutex); | ||
698 | FC_DEBUG_DISC("Received a GPN_FT response on port (%6x)\n", | 724 | FC_DEBUG_DISC("Received a GPN_FT response on port (%6x)\n", |
699 | fc_host_port_id(disc->lport->host)); | 725 | fc_host_port_id(disc->lport->host)); |
700 | 726 | ||
701 | if (IS_ERR(fp)) { | 727 | if (IS_ERR(fp)) { |
702 | fc_disc_error(disc, fp); | 728 | fc_disc_error(disc, fp); |
729 | mutex_unlock(&disc->disc_mutex); | ||
703 | return; | 730 | return; |
704 | } | 731 | } |
705 | 732 | ||
@@ -744,6 +771,8 @@ static void fc_disc_gpn_ft_resp(struct fc_seq *sp, struct fc_frame *fp, | |||
744 | disc->seq_count++; | 771 | disc->seq_count++; |
745 | } | 772 | } |
746 | fc_frame_free(fp); | 773 | fc_frame_free(fp); |
774 | |||
775 | mutex_unlock(&disc->disc_mutex); | ||
747 | } | 776 | } |
748 | 777 | ||
749 | /** | 778 | /** |
@@ -757,7 +786,6 @@ static void fc_disc_gpn_ft_resp(struct fc_seq *sp, struct fc_frame *fp, | |||
757 | static void fc_disc_single(struct fc_disc *disc, struct fc_disc_port *dp) | 786 | static void fc_disc_single(struct fc_disc *disc, struct fc_disc_port *dp) |
758 | { | 787 | { |
759 | struct fc_lport *lport; | 788 | struct fc_lport *lport; |
760 | struct fc_rport *rport; | ||
761 | struct fc_rport *new_rport; | 789 | struct fc_rport *new_rport; |
762 | struct fc_rport_libfc_priv *rdata; | 790 | struct fc_rport_libfc_priv *rdata; |
763 | 791 | ||
@@ -766,15 +794,12 @@ static void fc_disc_single(struct fc_disc *disc, struct fc_disc_port *dp) | |||
766 | if (dp->ids.port_id == fc_host_port_id(lport->host)) | 794 | if (dp->ids.port_id == fc_host_port_id(lport->host)) |
767 | goto out; | 795 | goto out; |
768 | 796 | ||
769 | rport = lport->tt.rport_lookup(lport, dp->ids.port_id); | ||
770 | if (rport) | ||
771 | fc_disc_del_target(disc, rport); | ||
772 | |||
773 | new_rport = lport->tt.rport_create(dp); | 797 | new_rport = lport->tt.rport_create(dp); |
774 | if (new_rport) { | 798 | if (new_rport) { |
775 | rdata = new_rport->dd_data; | 799 | rdata = new_rport->dd_data; |
776 | rdata->ops = &fc_disc_rport_ops; | 800 | rdata->ops = &fc_disc_rport_ops; |
777 | kfree(dp); | 801 | kfree(dp); |
802 | list_add_tail(&rdata->peers, &disc->rogue_rports); | ||
778 | lport->tt.rport_login(new_rport); | 803 | lport->tt.rport_login(new_rport); |
779 | } | 804 | } |
780 | return; | 805 | return; |
@@ -836,6 +861,7 @@ int fc_disc_init(struct fc_lport *lport) | |||
836 | INIT_DELAYED_WORK(&disc->disc_work, fc_disc_timeout); | 861 | INIT_DELAYED_WORK(&disc->disc_work, fc_disc_timeout); |
837 | mutex_init(&disc->disc_mutex); | 862 | mutex_init(&disc->disc_mutex); |
838 | INIT_LIST_HEAD(&disc->rports); | 863 | INIT_LIST_HEAD(&disc->rports); |
864 | INIT_LIST_HEAD(&disc->rogue_rports); | ||
839 | 865 | ||
840 | disc->lport = lport; | 866 | disc->lport = lport; |
841 | disc->delay = FC_DISC_DELAY; | 867 | disc->delay = FC_DISC_DELAY; |