diff options
Diffstat (limited to 'drivers/scsi/libfc')
-rw-r--r-- | drivers/scsi/libfc/fc_disc.c | 36 | ||||
-rw-r--r-- | drivers/scsi/libfc/fc_rport.c | 28 |
2 files changed, 53 insertions, 11 deletions
diff --git a/drivers/scsi/libfc/fc_disc.c b/drivers/scsi/libfc/fc_disc.c index 44806307f831..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 | } |
@@ -630,6 +645,8 @@ static int fc_disc_gpn_ft_parse(struct fc_disc *disc, void *buf, size_t len) | |||
630 | rdata = rport->dd_data; | 645 | rdata = rport->dd_data; |
631 | rdata->ops = &fc_disc_rport_ops; | 646 | rdata->ops = &fc_disc_rport_ops; |
632 | rdata->local_port = lport; | 647 | rdata->local_port = lport; |
648 | list_add_tail(&rdata->peers, | ||
649 | &disc->rogue_rports); | ||
633 | lport->tt.rport_login(rport); | 650 | lport->tt.rport_login(rport); |
634 | } else | 651 | } else |
635 | FC_DBG("Failed to allocate memory for " | 652 | FC_DBG("Failed to allocate memory for " |
@@ -769,7 +786,6 @@ static void fc_disc_gpn_ft_resp(struct fc_seq *sp, struct fc_frame *fp, | |||
769 | 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) |
770 | { | 787 | { |
771 | struct fc_lport *lport; | 788 | struct fc_lport *lport; |
772 | struct fc_rport *rport; | ||
773 | struct fc_rport *new_rport; | 789 | struct fc_rport *new_rport; |
774 | struct fc_rport_libfc_priv *rdata; | 790 | struct fc_rport_libfc_priv *rdata; |
775 | 791 | ||
@@ -778,15 +794,12 @@ static void fc_disc_single(struct fc_disc *disc, struct fc_disc_port *dp) | |||
778 | if (dp->ids.port_id == fc_host_port_id(lport->host)) | 794 | if (dp->ids.port_id == fc_host_port_id(lport->host)) |
779 | goto out; | 795 | goto out; |
780 | 796 | ||
781 | rport = lport->tt.rport_lookup(lport, dp->ids.port_id); | ||
782 | if (rport) | ||
783 | fc_disc_del_target(disc, rport); | ||
784 | |||
785 | new_rport = lport->tt.rport_create(dp); | 797 | new_rport = lport->tt.rport_create(dp); |
786 | if (new_rport) { | 798 | if (new_rport) { |
787 | rdata = new_rport->dd_data; | 799 | rdata = new_rport->dd_data; |
788 | rdata->ops = &fc_disc_rport_ops; | 800 | rdata->ops = &fc_disc_rport_ops; |
789 | kfree(dp); | 801 | kfree(dp); |
802 | list_add_tail(&rdata->peers, &disc->rogue_rports); | ||
790 | lport->tt.rport_login(new_rport); | 803 | lport->tt.rport_login(new_rport); |
791 | } | 804 | } |
792 | return; | 805 | return; |
@@ -848,6 +861,7 @@ int fc_disc_init(struct fc_lport *lport) | |||
848 | INIT_DELAYED_WORK(&disc->disc_work, fc_disc_timeout); | 861 | INIT_DELAYED_WORK(&disc->disc_work, fc_disc_timeout); |
849 | mutex_init(&disc->disc_mutex); | 862 | mutex_init(&disc->disc_mutex); |
850 | INIT_LIST_HEAD(&disc->rports); | 863 | INIT_LIST_HEAD(&disc->rports); |
864 | INIT_LIST_HEAD(&disc->rogue_rports); | ||
851 | 865 | ||
852 | disc->lport = lport; | 866 | disc->lport = lport; |
853 | disc->delay = FC_DISC_DELAY; | 867 | disc->delay = FC_DISC_DELAY; |
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) | |||
325 | int fc_rport_logoff(struct fc_rport *rport) | 329 | int 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 | ||
365 | out: | ||
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 | ||