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/libfc/fc_rport.c | |
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/libfc/fc_rport.c')
-rw-r--r-- | drivers/scsi/libfc/fc_rport.c | 154 |
1 files changed, 63 insertions, 91 deletions
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; |