diff options
author | Joe Eykholt <jeykholt@cisco.com> | 2009-08-25 17:01:18 -0400 |
---|---|---|
committer | James Bottomley <James.Bottomley@suse.de> | 2009-09-10 13:07:43 -0400 |
commit | 9e9d0452fe12115b1c1883c0d4d2ee509079791b (patch) | |
tree | 7cf8bb38e28e562274dcd7eeb2adfdf394876d14 /drivers/scsi | |
parent | 4c0f62b5679321b2e5572cf541ffb9f7b344d47c (diff) |
[SCSI] libfc: don't create dummy (rogue) remote ports
Don't create a "dummy" remote port to go with fc_rport_priv.
Make the rport truly optional by allocating fc_rport_priv separately
and not requiring a dummy rport to be there if we haven't yet done
fc_remote_port_add().
The fc_rport_libfc_priv remains as a structure attached to the
rport for I/O purposes.
Be sure to hold references on rdata when the lock is dropped in
fc_rport_work().
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')
-rw-r--r-- | drivers/scsi/libfc/fc_disc.c | 40 | ||||
-rw-r--r-- | drivers/scsi/libfc/fc_rport.c | 154 |
2 files changed, 73 insertions, 121 deletions
diff --git a/drivers/scsi/libfc/fc_disc.c b/drivers/scsi/libfc/fc_disc.c index e5e5b260a572..bbea41e50a57 100644 --- a/drivers/scsi/libfc/fc_disc.c +++ b/drivers/scsi/libfc/fc_disc.c | |||
@@ -66,7 +66,8 @@ struct fc_rport_priv *fc_disc_lookup_rport(const struct fc_lport *lport, | |||
66 | struct fc_rport_priv *rdata; | 66 | struct fc_rport_priv *rdata; |
67 | 67 | ||
68 | list_for_each_entry(rdata, &disc->rports, peers) { | 68 | list_for_each_entry(rdata, &disc->rports, peers) { |
69 | if (rdata->ids.port_id == port_id) | 69 | if (rdata->ids.port_id == port_id && |
70 | rdata->rp_state != RPORT_ST_DELETE) | ||
70 | return rdata; | 71 | return rdata; |
71 | } | 72 | } |
72 | return NULL; | 73 | return NULL; |
@@ -87,15 +88,8 @@ void fc_disc_stop_rports(struct fc_disc *disc) | |||
87 | lport = disc->lport; | 88 | lport = disc->lport; |
88 | 89 | ||
89 | mutex_lock(&disc->disc_mutex); | 90 | mutex_lock(&disc->disc_mutex); |
90 | list_for_each_entry_safe(rdata, next, &disc->rports, peers) { | 91 | list_for_each_entry_safe(rdata, next, &disc->rports, peers) |
91 | list_del(&rdata->peers); | ||
92 | lport->tt.rport_logoff(rdata); | 92 | lport->tt.rport_logoff(rdata); |
93 | } | ||
94 | |||
95 | list_for_each_entry_safe(rdata, next, &disc->rogue_rports, peers) { | ||
96 | lport->tt.rport_logoff(rdata); | ||
97 | } | ||
98 | |||
99 | mutex_unlock(&disc->disc_mutex); | 93 | mutex_unlock(&disc->disc_mutex); |
100 | } | 94 | } |
101 | 95 | ||
@@ -119,20 +113,12 @@ static void fc_disc_rport_callback(struct fc_lport *lport, | |||
119 | 113 | ||
120 | switch (event) { | 114 | switch (event) { |
121 | case RPORT_EV_READY: | 115 | case RPORT_EV_READY: |
122 | if (disc) { | ||
123 | mutex_lock(&disc->disc_mutex); | ||
124 | list_add_tail(&rdata->peers, &disc->rports); | ||
125 | mutex_unlock(&disc->disc_mutex); | ||
126 | } | ||
127 | break; | 116 | break; |
128 | case RPORT_EV_LOGO: | 117 | case RPORT_EV_LOGO: |
129 | case RPORT_EV_FAILED: | 118 | case RPORT_EV_FAILED: |
130 | case RPORT_EV_STOP: | 119 | case RPORT_EV_STOP: |
131 | mutex_lock(&disc->disc_mutex); | 120 | mutex_lock(&disc->disc_mutex); |
132 | mutex_lock(&rdata->rp_mutex); | 121 | list_del(&rdata->peers); |
133 | if (rdata->trans_state == FC_PORTSTATE_ROGUE) | ||
134 | list_del(&rdata->peers); | ||
135 | mutex_unlock(&rdata->rp_mutex); | ||
136 | mutex_unlock(&disc->disc_mutex); | 122 | mutex_unlock(&disc->disc_mutex); |
137 | break; | 123 | break; |
138 | default: | 124 | default: |
@@ -235,7 +221,6 @@ static void fc_disc_recv_rscn_req(struct fc_seq *sp, struct fc_frame *fp, | |||
235 | list_del(&dp->peers); | 221 | list_del(&dp->peers); |
236 | rdata = lport->tt.rport_lookup(lport, dp->ids.port_id); | 222 | rdata = lport->tt.rport_lookup(lport, dp->ids.port_id); |
237 | if (rdata) { | 223 | if (rdata) { |
238 | list_del(&rdata->peers); | ||
239 | lport->tt.rport_logoff(rdata); | 224 | lport->tt.rport_logoff(rdata); |
240 | } | 225 | } |
241 | fc_disc_single(disc, dp); | 226 | fc_disc_single(disc, dp); |
@@ -296,10 +281,8 @@ static void fc_disc_restart(struct fc_disc *disc) | |||
296 | 281 | ||
297 | FC_DISC_DBG(disc, "Restarting discovery\n"); | 282 | FC_DISC_DBG(disc, "Restarting discovery\n"); |
298 | 283 | ||
299 | list_for_each_entry_safe(rdata, next, &disc->rports, peers) { | 284 | list_for_each_entry_safe(rdata, next, &disc->rports, peers) |
300 | list_del(&rdata->peers); | ||
301 | lport->tt.rport_logoff(rdata); | 285 | lport->tt.rport_logoff(rdata); |
302 | } | ||
303 | 286 | ||
304 | disc->requested = 1; | 287 | disc->requested = 1; |
305 | if (!disc->pending) | 288 | if (!disc->pending) |
@@ -392,7 +375,6 @@ static int fc_disc_new_target(struct fc_disc *disc, | |||
392 | * assigned the same FCID. This should be rare. | 375 | * assigned the same FCID. This should be rare. |
393 | * Delete the old one and fall thru to re-create. | 376 | * Delete the old one and fall thru to re-create. |
394 | */ | 377 | */ |
395 | list_del(&rdata->peers); | ||
396 | lport->tt.rport_logoff(rdata); | 378 | lport->tt.rport_logoff(rdata); |
397 | rdata = NULL; | 379 | rdata = NULL; |
398 | } | 380 | } |
@@ -406,12 +388,13 @@ static int fc_disc_new_target(struct fc_disc *disc, | |||
406 | rdata = lport->tt.rport_create(lport, ids); | 388 | rdata = lport->tt.rport_create(lport, ids); |
407 | if (!rdata) | 389 | if (!rdata) |
408 | error = -ENOMEM; | 390 | error = -ENOMEM; |
391 | else | ||
392 | list_add_tail(&rdata->peers, | ||
393 | &disc->rports); | ||
409 | } | 394 | } |
410 | } | 395 | } |
411 | if (rdata) { | 396 | if (rdata) { |
412 | rdata->ops = &fc_disc_rport_ops; | 397 | rdata->ops = &fc_disc_rport_ops; |
413 | rdata->rp_state = RPORT_ST_INIT; | ||
414 | list_add_tail(&rdata->peers, &disc->rogue_rports); | ||
415 | lport->tt.rport_login(rdata); | 398 | lport->tt.rport_login(rdata); |
416 | } | 399 | } |
417 | } | 400 | } |
@@ -585,9 +568,7 @@ static int fc_disc_gpn_ft_parse(struct fc_disc *disc, void *buf, size_t len) | |||
585 | rdata = lport->tt.rport_create(lport, &ids); | 568 | rdata = lport->tt.rport_create(lport, &ids); |
586 | if (rdata) { | 569 | if (rdata) { |
587 | rdata->ops = &fc_disc_rport_ops; | 570 | rdata->ops = &fc_disc_rport_ops; |
588 | rdata->local_port = lport; | 571 | list_add_tail(&rdata->peers, &disc->rports); |
589 | list_add_tail(&rdata->peers, | ||
590 | &disc->rogue_rports); | ||
591 | lport->tt.rport_login(rdata); | 572 | lport->tt.rport_login(rdata); |
592 | } else | 573 | } else |
593 | printk(KERN_WARNING "libfc: Failed to allocate " | 574 | printk(KERN_WARNING "libfc: Failed to allocate " |
@@ -736,7 +717,7 @@ static void fc_disc_single(struct fc_disc *disc, struct fc_disc_port *dp) | |||
736 | if (rdata) { | 717 | if (rdata) { |
737 | rdata->ops = &fc_disc_rport_ops; | 718 | rdata->ops = &fc_disc_rport_ops; |
738 | kfree(dp); | 719 | kfree(dp); |
739 | list_add_tail(&rdata->peers, &disc->rogue_rports); | 720 | list_add_tail(&rdata->peers, &disc->rports); |
740 | lport->tt.rport_login(rdata); | 721 | lport->tt.rport_login(rdata); |
741 | } | 722 | } |
742 | return; | 723 | return; |
@@ -798,7 +779,6 @@ int fc_disc_init(struct fc_lport *lport) | |||
798 | INIT_DELAYED_WORK(&disc->disc_work, fc_disc_timeout); | 779 | INIT_DELAYED_WORK(&disc->disc_work, fc_disc_timeout); |
799 | mutex_init(&disc->disc_mutex); | 780 | mutex_init(&disc->disc_mutex); |
800 | INIT_LIST_HEAD(&disc->rports); | 781 | INIT_LIST_HEAD(&disc->rports); |
801 | INIT_LIST_HEAD(&disc->rogue_rports); | ||
802 | 782 | ||
803 | disc->lport = lport; | 783 | disc->lport = lport; |
804 | disc->delay = FC_DISC_DELAY; | 784 | disc->delay = FC_DISC_DELAY; |
diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c index 50959ba0a9a0..a1794a39158e 100644 --- a/drivers/scsi/libfc/fc_rport.c +++ b/drivers/scsi/libfc/fc_rport.c | |||
@@ -86,61 +86,35 @@ static const char *fc_rport_state_names[] = { | |||
86 | [RPORT_ST_DELETE] = "Delete", | 86 | [RPORT_ST_DELETE] = "Delete", |
87 | }; | 87 | }; |
88 | 88 | ||
89 | static void fc_rport_rogue_destroy(struct device *dev) | 89 | /** |
90 | { | 90 | * fc_rport_create() - create remote port in INIT state. |
91 | struct fc_rport *rport = dev_to_rport(dev); | 91 | * @lport: local port. |
92 | struct fc_rport_priv *rdata = RPORT_TO_PRIV(rport); | 92 | * @ids: remote port identifiers. |
93 | 93 | * | |
94 | FC_RPORT_DBG(rdata, "Destroying rogue rport\n"); | 94 | * Locking note: this may be called without locks held, but |
95 | kfree(rport); | 95 | * is usually called from discovery with the disc_mutex held. |
96 | } | 96 | */ |
97 | 97 | static struct fc_rport_priv *fc_rport_create(struct fc_lport *lport, | |
98 | struct fc_rport_priv *fc_rport_rogue_create(struct fc_lport *lport, | 98 | struct fc_rport_identifiers *ids) |
99 | struct fc_rport_identifiers *ids) | ||
100 | { | 99 | { |
101 | struct fc_rport *rport; | ||
102 | struct fc_rport_priv *rdata; | 100 | struct fc_rport_priv *rdata; |
103 | rport = kzalloc(sizeof(*rport) + sizeof(*rdata), GFP_KERNEL); | ||
104 | 101 | ||
105 | if (!rport) | 102 | rdata = kzalloc(sizeof(*rdata), GFP_KERNEL); |
103 | if (!rdata) | ||
106 | return NULL; | 104 | return NULL; |
107 | 105 | ||
108 | rdata = RPORT_TO_PRIV(rport); | ||
109 | |||
110 | rport->dd_data = rdata; | ||
111 | rport->port_id = ids->port_id; | ||
112 | rport->port_name = ids->port_name; | ||
113 | rport->node_name = ids->node_name; | ||
114 | rport->roles = ids->roles; | ||
115 | rport->maxframe_size = FC_MIN_MAX_PAYLOAD; | ||
116 | /* | ||
117 | * Note: all this libfc rogue rport code will be removed for | ||
118 | * upstream so it fine that this is really ugly and hacky right now. | ||
119 | */ | ||
120 | device_initialize(&rport->dev); | ||
121 | rport->dev.release = fc_rport_rogue_destroy; | ||
122 | |||
123 | rdata->ids = *ids; | 106 | rdata->ids = *ids; |
124 | kref_init(&rdata->kref); | 107 | kref_init(&rdata->kref); |
125 | mutex_init(&rdata->rp_mutex); | 108 | mutex_init(&rdata->rp_mutex); |
126 | rdata->rport = rport; | ||
127 | rdata->local_port = lport; | 109 | rdata->local_port = lport; |
128 | rdata->trans_state = FC_PORTSTATE_ROGUE; | ||
129 | rdata->rp_state = RPORT_ST_INIT; | 110 | rdata->rp_state = RPORT_ST_INIT; |
130 | rdata->event = RPORT_EV_NONE; | 111 | rdata->event = RPORT_EV_NONE; |
131 | rdata->flags = FC_RP_FLAGS_REC_SUPPORTED; | 112 | rdata->flags = FC_RP_FLAGS_REC_SUPPORTED; |
132 | rdata->ops = NULL; | ||
133 | rdata->e_d_tov = lport->e_d_tov; | 113 | rdata->e_d_tov = lport->e_d_tov; |
134 | rdata->r_a_tov = lport->r_a_tov; | 114 | rdata->r_a_tov = lport->r_a_tov; |
135 | rdata->maxframe_size = FC_MIN_MAX_PAYLOAD; | 115 | rdata->maxframe_size = FC_MIN_MAX_PAYLOAD; |
136 | INIT_DELAYED_WORK(&rdata->retry_work, fc_rport_timeout); | 116 | INIT_DELAYED_WORK(&rdata->retry_work, fc_rport_timeout); |
137 | INIT_WORK(&rdata->event_work, fc_rport_work); | 117 | INIT_WORK(&rdata->event_work, fc_rport_work); |
138 | /* | ||
139 | * For good measure, but not necessary as we should only | ||
140 | * add REAL rport to the lport list. | ||
141 | */ | ||
142 | INIT_LIST_HEAD(&rdata->peers); | ||
143 | |||
144 | return rdata; | 118 | return rdata; |
145 | } | 119 | } |
146 | 120 | ||
@@ -151,11 +125,9 @@ struct fc_rport_priv *fc_rport_rogue_create(struct fc_lport *lport, | |||
151 | static void fc_rport_destroy(struct kref *kref) | 125 | static void fc_rport_destroy(struct kref *kref) |
152 | { | 126 | { |
153 | struct fc_rport_priv *rdata; | 127 | struct fc_rport_priv *rdata; |
154 | struct fc_rport *rport; | ||
155 | 128 | ||
156 | rdata = container_of(kref, struct fc_rport_priv, kref); | 129 | rdata = container_of(kref, struct fc_rport_priv, kref); |
157 | rport = rdata->rport; | 130 | kfree(rdata); |
158 | put_device(&rport->dev); | ||
159 | } | 131 | } |
160 | 132 | ||
161 | /** | 133 | /** |
@@ -229,12 +201,10 @@ static void fc_rport_work(struct work_struct *work) | |||
229 | u32 port_id; | 201 | u32 port_id; |
230 | struct fc_rport_priv *rdata = | 202 | struct fc_rport_priv *rdata = |
231 | container_of(work, struct fc_rport_priv, event_work); | 203 | container_of(work, struct fc_rport_priv, event_work); |
204 | struct fc_rport_libfc_priv *rp; | ||
232 | enum fc_rport_event event; | 205 | enum fc_rport_event event; |
233 | enum fc_rport_trans_state trans_state; | ||
234 | struct fc_lport *lport = rdata->local_port; | 206 | struct fc_lport *lport = rdata->local_port; |
235 | struct fc_rport_operations *rport_ops; | 207 | struct fc_rport_operations *rport_ops; |
236 | struct fc_rport *new_rport; | ||
237 | struct fc_rport_priv *new_rdata; | ||
238 | struct fc_rport_identifiers ids; | 208 | struct fc_rport_identifiers ids; |
239 | struct fc_rport *rport; | 209 | struct fc_rport *rport; |
240 | 210 | ||
@@ -243,70 +213,72 @@ static void fc_rport_work(struct work_struct *work) | |||
243 | rport_ops = rdata->ops; | 213 | rport_ops = rdata->ops; |
244 | rport = rdata->rport; | 214 | rport = rdata->rport; |
245 | 215 | ||
216 | FC_RPORT_DBG(rdata, "work event %u\n", event); | ||
217 | |||
246 | switch (event) { | 218 | switch (event) { |
247 | case RPORT_EV_READY: | 219 | case RPORT_EV_READY: |
248 | ids = rdata->ids; | 220 | ids = rdata->ids; |
249 | rdata->event = RPORT_EV_NONE; | 221 | rdata->event = RPORT_EV_NONE; |
222 | kref_get(&rdata->kref); | ||
250 | mutex_unlock(&rdata->rp_mutex); | 223 | mutex_unlock(&rdata->rp_mutex); |
251 | 224 | ||
252 | new_rport = fc_remote_port_add(lport->host, 0, &ids); | 225 | if (!rport) |
253 | if (new_rport) { | 226 | rport = fc_remote_port_add(lport->host, 0, &ids); |
254 | /* | 227 | if (!rport) { |
255 | * Switch from the rogue rport to the rport | 228 | FC_RPORT_DBG(rdata, "Failed to add the rport\n"); |
256 | * returned by the FC class. | 229 | lport->tt.rport_logoff(rdata); |
257 | */ | 230 | kref_put(&rdata->kref, lport->tt.rport_destroy); |
258 | new_rport->maxframe_size = rdata->maxframe_size; | 231 | return; |
259 | |||
260 | new_rdata = new_rport->dd_data; | ||
261 | new_rdata->rport = new_rport; | ||
262 | new_rdata->ids = ids; | ||
263 | new_rdata->e_d_tov = rdata->e_d_tov; | ||
264 | new_rdata->r_a_tov = rdata->r_a_tov; | ||
265 | new_rdata->ops = rdata->ops; | ||
266 | new_rdata->local_port = rdata->local_port; | ||
267 | new_rdata->flags = FC_RP_FLAGS_REC_SUPPORTED; | ||
268 | new_rdata->trans_state = FC_PORTSTATE_REAL; | ||
269 | new_rdata->maxframe_size = rdata->maxframe_size; | ||
270 | new_rdata->supported_classes = rdata->supported_classes; | ||
271 | kref_init(&new_rdata->kref); | ||
272 | mutex_init(&new_rdata->rp_mutex); | ||
273 | INIT_DELAYED_WORK(&new_rdata->retry_work, | ||
274 | fc_rport_timeout); | ||
275 | INIT_LIST_HEAD(&new_rdata->peers); | ||
276 | INIT_WORK(&new_rdata->event_work, fc_rport_work); | ||
277 | |||
278 | fc_rport_state_enter(new_rdata, RPORT_ST_READY); | ||
279 | } else { | ||
280 | printk(KERN_WARNING "libfc: Failed to allocate " | ||
281 | " memory for rport (%6x)\n", ids.port_id); | ||
282 | event = RPORT_EV_FAILED; | ||
283 | } | 232 | } |
284 | if (rdata->ids.port_id != FC_FID_DIR_SERV) | 233 | mutex_lock(&rdata->rp_mutex); |
285 | if (rport_ops->event_callback) | 234 | if (rdata->rport) |
286 | rport_ops->event_callback(lport, rdata, | 235 | FC_RPORT_DBG(rdata, "rport already allocated\n"); |
287 | RPORT_EV_FAILED); | 236 | rdata->rport = rport; |
288 | kref_put(&rdata->kref, lport->tt.rport_destroy); | 237 | rport->maxframe_size = rdata->maxframe_size; |
289 | rdata = new_rport->dd_data; | 238 | rport->supported_classes = rdata->supported_classes; |
290 | if (rport_ops->event_callback) | 239 | |
240 | rp = rport->dd_data; | ||
241 | rp->local_port = lport; | ||
242 | rp->rp_state = rdata->rp_state; | ||
243 | rp->flags = rdata->flags; | ||
244 | rp->e_d_tov = rdata->e_d_tov; | ||
245 | rp->r_a_tov = rdata->r_a_tov; | ||
246 | mutex_unlock(&rdata->rp_mutex); | ||
247 | |||
248 | if (rport_ops->event_callback) { | ||
249 | FC_RPORT_DBG(rdata, "callback ev %d\n", event); | ||
291 | rport_ops->event_callback(lport, rdata, event); | 250 | rport_ops->event_callback(lport, rdata, event); |
251 | } | ||
252 | kref_put(&rdata->kref, lport->tt.rport_destroy); | ||
292 | break; | 253 | break; |
293 | 254 | ||
294 | case RPORT_EV_FAILED: | 255 | case RPORT_EV_FAILED: |
295 | case RPORT_EV_LOGO: | 256 | case RPORT_EV_LOGO: |
296 | case RPORT_EV_STOP: | 257 | case RPORT_EV_STOP: |
297 | trans_state = rdata->trans_state; | 258 | port_id = rdata->ids.port_id; |
298 | mutex_unlock(&rdata->rp_mutex); | 259 | mutex_unlock(&rdata->rp_mutex); |
299 | if (rport_ops->event_callback) | 260 | |
261 | if (rport_ops->event_callback) { | ||
262 | FC_RPORT_DBG(rdata, "callback ev %d\n", event); | ||
300 | rport_ops->event_callback(lport, rdata, event); | 263 | rport_ops->event_callback(lport, rdata, event); |
264 | } | ||
301 | cancel_delayed_work_sync(&rdata->retry_work); | 265 | cancel_delayed_work_sync(&rdata->retry_work); |
302 | if (trans_state == FC_PORTSTATE_ROGUE) | 266 | |
303 | kref_put(&rdata->kref, lport->tt.rport_destroy); | 267 | /* |
304 | else { | 268 | * Reset any outstanding exchanges before freeing rport. |
305 | port_id = rport->port_id; | 269 | */ |
270 | lport->tt.exch_mgr_reset(lport, 0, port_id); | ||
271 | lport->tt.exch_mgr_reset(lport, port_id, 0); | ||
272 | |||
273 | if (rport) { | ||
274 | rp = rport->dd_data; | ||
275 | rp->rp_state = RPORT_ST_DELETE; | ||
276 | mutex_lock(&rdata->rp_mutex); | ||
277 | rdata->rport = NULL; | ||
278 | mutex_unlock(&rdata->rp_mutex); | ||
306 | fc_remote_port_delete(rport); | 279 | fc_remote_port_delete(rport); |
307 | lport->tt.exch_mgr_reset(lport, 0, port_id); | ||
308 | lport->tt.exch_mgr_reset(lport, port_id, 0); | ||
309 | } | 280 | } |
281 | kref_put(&rdata->kref, lport->tt.rport_destroy); | ||
310 | break; | 282 | break; |
311 | 283 | ||
312 | default: | 284 | default: |
@@ -1311,7 +1283,7 @@ static void fc_rport_flush_queue(void) | |||
1311 | int fc_rport_init(struct fc_lport *lport) | 1283 | int fc_rport_init(struct fc_lport *lport) |
1312 | { | 1284 | { |
1313 | if (!lport->tt.rport_create) | 1285 | if (!lport->tt.rport_create) |
1314 | lport->tt.rport_create = fc_rport_rogue_create; | 1286 | lport->tt.rport_create = fc_rport_create; |
1315 | 1287 | ||
1316 | if (!lport->tt.rport_login) | 1288 | if (!lport->tt.rport_login) |
1317 | lport->tt.rport_login = fc_rport_login; | 1289 | lport->tt.rport_login = fc_rport_login; |