diff options
-rw-r--r-- | drivers/scsi/libfc/fc_disc.c | 54 | ||||
-rw-r--r-- | drivers/scsi/libfc/fc_lport.c | 14 | ||||
-rw-r--r-- | drivers/scsi/libfc/fc_rport.c | 102 | ||||
-rw-r--r-- | include/scsi/libfc.h | 29 |
4 files changed, 98 insertions, 101 deletions
diff --git a/drivers/scsi/libfc/fc_disc.c b/drivers/scsi/libfc/fc_disc.c index 4b1f9faf639a..5f839b625e50 100644 --- a/drivers/scsi/libfc/fc_disc.c +++ b/drivers/scsi/libfc/fc_disc.c | |||
@@ -47,7 +47,7 @@ | |||
47 | 47 | ||
48 | static void fc_disc_gpn_ft_req(struct fc_disc *); | 48 | static void fc_disc_gpn_ft_req(struct fc_disc *); |
49 | static void fc_disc_gpn_ft_resp(struct fc_seq *, struct fc_frame *, void *); | 49 | static void fc_disc_gpn_ft_resp(struct fc_seq *, struct fc_frame *, void *); |
50 | static int fc_disc_new_target(struct fc_disc *, struct fc_rport *, | 50 | static int fc_disc_new_target(struct fc_disc *, struct fc_rport_priv *, |
51 | struct fc_rport_identifiers *); | 51 | struct fc_rport_identifiers *); |
52 | static void fc_disc_done(struct fc_disc *); | 52 | static void fc_disc_done(struct fc_disc *); |
53 | static void fc_disc_timeout(struct work_struct *); | 53 | static void fc_disc_timeout(struct work_struct *); |
@@ -63,12 +63,10 @@ struct fc_rport_priv *fc_disc_lookup_rport(const struct fc_lport *lport, | |||
63 | u32 port_id) | 63 | u32 port_id) |
64 | { | 64 | { |
65 | const struct fc_disc *disc = &lport->disc; | 65 | const struct fc_disc *disc = &lport->disc; |
66 | struct fc_rport *rport; | ||
67 | struct fc_rport_priv *rdata; | 66 | struct fc_rport_priv *rdata; |
68 | 67 | ||
69 | list_for_each_entry(rdata, &disc->rports, peers) { | 68 | list_for_each_entry(rdata, &disc->rports, peers) { |
70 | rport = PRIV_TO_RPORT(rdata); | 69 | if (rdata->ids.port_id == port_id) |
71 | if (rport->port_id == port_id) | ||
72 | return rdata; | 70 | return rdata; |
73 | } | 71 | } |
74 | return NULL; | 72 | return NULL; |
@@ -115,10 +113,9 @@ static void fc_disc_rport_callback(struct fc_lport *lport, | |||
115 | enum fc_rport_event event) | 113 | enum fc_rport_event event) |
116 | { | 114 | { |
117 | struct fc_disc *disc = &lport->disc; | 115 | struct fc_disc *disc = &lport->disc; |
118 | struct fc_rport *rport = PRIV_TO_RPORT(rdata); | ||
119 | 116 | ||
120 | FC_DISC_DBG(disc, "Received a %d event for port (%6x)\n", event, | 117 | FC_DISC_DBG(disc, "Received a %d event for port (%6x)\n", event, |
121 | rport->port_id); | 118 | rdata->ids.port_id); |
122 | 119 | ||
123 | switch (event) { | 120 | switch (event) { |
124 | case RPORT_EV_CREATED: | 121 | case RPORT_EV_CREATED: |
@@ -320,8 +317,6 @@ static void fc_disc_start(void (*disc_callback)(struct fc_lport *, | |||
320 | struct fc_lport *lport) | 317 | struct fc_lport *lport) |
321 | { | 318 | { |
322 | struct fc_rport_priv *rdata; | 319 | struct fc_rport_priv *rdata; |
323 | struct fc_rport *rport; | ||
324 | struct fc_rport_identifiers ids; | ||
325 | struct fc_disc *disc = &lport->disc; | 320 | struct fc_disc *disc = &lport->disc; |
326 | 321 | ||
327 | /* | 322 | /* |
@@ -349,18 +344,12 @@ static void fc_disc_start(void (*disc_callback)(struct fc_lport *, | |||
349 | */ | 344 | */ |
350 | rdata = disc->lport->ptp_rp; | 345 | rdata = disc->lport->ptp_rp; |
351 | if (rdata) { | 346 | if (rdata) { |
352 | rport = PRIV_TO_RPORT(rdata); | 347 | kref_get(&rdata->kref); |
353 | ids.port_id = rport->port_id; | 348 | if (!fc_disc_new_target(disc, rdata, &rdata->ids)) { |
354 | ids.port_name = rport->port_name; | ||
355 | ids.node_name = rport->node_name; | ||
356 | ids.roles = FC_RPORT_ROLE_UNKNOWN; | ||
357 | get_device(&rport->dev); | ||
358 | |||
359 | if (!fc_disc_new_target(disc, rport, &ids)) { | ||
360 | disc->event = DISC_EV_SUCCESS; | 349 | disc->event = DISC_EV_SUCCESS; |
361 | fc_disc_done(disc); | 350 | fc_disc_done(disc); |
362 | } | 351 | } |
363 | put_device(&rport->dev); | 352 | kref_put(&rdata->kref, rdata->local_port->tt.rport_destroy); |
364 | } else { | 353 | } else { |
365 | fc_disc_gpn_ft_req(disc); /* get ports by FC-4 type */ | 354 | fc_disc_gpn_ft_req(disc); /* get ports by FC-4 type */ |
366 | } | 355 | } |
@@ -375,28 +364,27 @@ static struct fc_rport_operations fc_disc_rport_ops = { | |||
375 | /** | 364 | /** |
376 | * fc_disc_new_target() - Handle new target found by discovery | 365 | * fc_disc_new_target() - Handle new target found by discovery |
377 | * @lport: FC local port | 366 | * @lport: FC local port |
378 | * @rport: The previous FC remote port (NULL if new remote port) | 367 | * @rdata: The previous FC remote port priv (NULL if new remote port) |
379 | * @ids: Identifiers for the new FC remote port | 368 | * @ids: Identifiers for the new FC remote port |
380 | * | 369 | * |
381 | * Locking Note: This function expects that the disc_mutex is locked | 370 | * Locking Note: This function expects that the disc_mutex is locked |
382 | * before it is called. | 371 | * before it is called. |
383 | */ | 372 | */ |
384 | static int fc_disc_new_target(struct fc_disc *disc, | 373 | static int fc_disc_new_target(struct fc_disc *disc, |
385 | struct fc_rport *rport, | 374 | struct fc_rport_priv *rdata, |
386 | struct fc_rport_identifiers *ids) | 375 | struct fc_rport_identifiers *ids) |
387 | { | 376 | { |
388 | struct fc_lport *lport = disc->lport; | 377 | struct fc_lport *lport = disc->lport; |
389 | struct fc_rport_priv *rdata; | ||
390 | int error = 0; | 378 | int error = 0; |
391 | 379 | ||
392 | if (rport && ids->port_name) { | 380 | if (rdata && ids->port_name) { |
393 | if (rport->port_name == -1) { | 381 | if (rdata->ids.port_name == -1) { |
394 | /* | 382 | /* |
395 | * Set WWN and fall through to notify of create. | 383 | * Set WWN and fall through to notify of create. |
396 | */ | 384 | */ |
397 | fc_rport_set_name(rport, ids->port_name, | 385 | rdata->ids.port_name = ids->port_name; |
398 | rport->node_name); | 386 | rdata->ids.node_name = ids->node_name; |
399 | } else if (rport->port_name != ids->port_name) { | 387 | } else if (rdata->ids.port_name != ids->port_name) { |
400 | /* | 388 | /* |
401 | * This is a new port with the same FCID as | 389 | * This is a new port with the same FCID as |
402 | * a previously-discovered port. Presumably the old | 390 | * a previously-discovered port. Presumably the old |
@@ -404,27 +392,23 @@ static int fc_disc_new_target(struct fc_disc *disc, | |||
404 | * assigned the same FCID. This should be rare. | 392 | * assigned the same FCID. This should be rare. |
405 | * Delete the old one and fall thru to re-create. | 393 | * Delete the old one and fall thru to re-create. |
406 | */ | 394 | */ |
407 | rdata = rport->dd_data; | ||
408 | list_del(&rdata->peers); | 395 | list_del(&rdata->peers); |
409 | lport->tt.rport_logoff(rdata); | 396 | lport->tt.rport_logoff(rdata); |
410 | rport = NULL; | 397 | rdata = NULL; |
411 | } | 398 | } |
412 | } | 399 | } |
413 | if (((ids->port_name != -1) || (ids->port_id != -1)) && | 400 | if (((ids->port_name != -1) || (ids->port_id != -1)) && |
414 | ids->port_id != fc_host_port_id(lport->host) && | 401 | ids->port_id != fc_host_port_id(lport->host) && |
415 | ids->port_name != lport->wwpn) { | 402 | ids->port_name != lport->wwpn) { |
416 | if (!rport) { | 403 | if (!rdata) { |
417 | rdata = lport->tt.rport_lookup(lport, ids->port_id); | 404 | rdata = lport->tt.rport_lookup(lport, ids->port_id); |
418 | if (!rport) { | 405 | if (!rdata) { |
419 | rdata = lport->tt.rport_create(lport, ids); | 406 | rdata = lport->tt.rport_create(lport, ids); |
407 | if (!rdata) | ||
408 | error = -ENOMEM; | ||
420 | } | 409 | } |
421 | if (!rdata) | ||
422 | error = -ENOMEM; | ||
423 | else | ||
424 | rport = PRIV_TO_RPORT(rdata); | ||
425 | } | 410 | } |
426 | if (rport) { | 411 | if (rdata) { |
427 | rdata = rport->dd_data; | ||
428 | rdata->ops = &fc_disc_rport_ops; | 412 | rdata->ops = &fc_disc_rport_ops; |
429 | rdata->rp_state = RPORT_ST_INIT; | 413 | rdata->rp_state = RPORT_ST_INIT; |
430 | list_add_tail(&rdata->peers, &disc->rogue_rports); | 414 | list_add_tail(&rdata->peers, &disc->rogue_rports); |
diff --git a/drivers/scsi/libfc/fc_lport.c b/drivers/scsi/libfc/fc_lport.c index aa605d2012e0..a7fe6b8d38b8 100644 --- a/drivers/scsi/libfc/fc_lport.c +++ b/drivers/scsi/libfc/fc_lport.c | |||
@@ -143,14 +143,12 @@ static void fc_lport_rport_callback(struct fc_lport *lport, | |||
143 | struct fc_rport_priv *rdata, | 143 | struct fc_rport_priv *rdata, |
144 | enum fc_rport_event event) | 144 | enum fc_rport_event event) |
145 | { | 145 | { |
146 | struct fc_rport *rport = PRIV_TO_RPORT(rdata); | ||
147 | |||
148 | FC_LPORT_DBG(lport, "Received a %d event for port (%6x)\n", event, | 146 | FC_LPORT_DBG(lport, "Received a %d event for port (%6x)\n", event, |
149 | rport->port_id); | 147 | rdata->ids.port_id); |
150 | 148 | ||
151 | switch (event) { | 149 | switch (event) { |
152 | case RPORT_EV_CREATED: | 150 | case RPORT_EV_CREATED: |
153 | if (rport->port_id == FC_FID_DIR_SERV) { | 151 | if (rdata->ids.port_id == FC_FID_DIR_SERV) { |
154 | mutex_lock(&lport->lp_mutex); | 152 | mutex_lock(&lport->lp_mutex); |
155 | if (lport->state == LPORT_ST_DNS) { | 153 | if (lport->state == LPORT_ST_DNS) { |
156 | lport->dns_rp = rdata; | 154 | lport->dns_rp = rdata; |
@@ -160,7 +158,7 @@ static void fc_lport_rport_callback(struct fc_lport *lport, | |||
160 | "on port (%6x) for the directory " | 158 | "on port (%6x) for the directory " |
161 | "server, but the lport is not " | 159 | "server, but the lport is not " |
162 | "in the DNS state, it's in the " | 160 | "in the DNS state, it's in the " |
163 | "%d state", rport->port_id, | 161 | "%d state", rdata->ids.port_id, |
164 | lport->state); | 162 | lport->state); |
165 | lport->tt.rport_logoff(rdata); | 163 | lport->tt.rport_logoff(rdata); |
166 | } | 164 | } |
@@ -168,12 +166,12 @@ static void fc_lport_rport_callback(struct fc_lport *lport, | |||
168 | } else | 166 | } else |
169 | FC_LPORT_DBG(lport, "Received an event for port (%6x) " | 167 | FC_LPORT_DBG(lport, "Received an event for port (%6x) " |
170 | "which is not the directory server\n", | 168 | "which is not the directory server\n", |
171 | rport->port_id); | 169 | rdata->ids.port_id); |
172 | break; | 170 | break; |
173 | case RPORT_EV_LOGO: | 171 | case RPORT_EV_LOGO: |
174 | case RPORT_EV_FAILED: | 172 | case RPORT_EV_FAILED: |
175 | case RPORT_EV_STOP: | 173 | case RPORT_EV_STOP: |
176 | if (rport->port_id == FC_FID_DIR_SERV) { | 174 | if (rdata->ids.port_id == FC_FID_DIR_SERV) { |
177 | mutex_lock(&lport->lp_mutex); | 175 | mutex_lock(&lport->lp_mutex); |
178 | lport->dns_rp = NULL; | 176 | lport->dns_rp = NULL; |
179 | mutex_unlock(&lport->lp_mutex); | 177 | mutex_unlock(&lport->lp_mutex); |
@@ -181,7 +179,7 @@ static void fc_lport_rport_callback(struct fc_lport *lport, | |||
181 | } else | 179 | } else |
182 | FC_LPORT_DBG(lport, "Received an event for port (%6x) " | 180 | FC_LPORT_DBG(lport, "Received an event for port (%6x) " |
183 | "which is not the directory server\n", | 181 | "which is not the directory server\n", |
184 | rport->port_id); | 182 | rdata->ids.port_id); |
185 | break; | 183 | break; |
186 | case RPORT_EV_NONE: | 184 | case RPORT_EV_NONE: |
187 | break; | 185 | break; |
diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c index 20371b445bb1..69f6e588d37b 100644 --- a/drivers/scsi/libfc/fc_rport.c +++ b/drivers/scsi/libfc/fc_rport.c | |||
@@ -120,7 +120,10 @@ struct fc_rport_priv *fc_rport_rogue_create(struct fc_lport *lport, | |||
120 | device_initialize(&rport->dev); | 120 | device_initialize(&rport->dev); |
121 | rport->dev.release = fc_rport_rogue_destroy; | 121 | rport->dev.release = fc_rport_rogue_destroy; |
122 | 122 | ||
123 | rdata->ids = *ids; | ||
124 | kref_init(&rdata->kref); | ||
123 | mutex_init(&rdata->rp_mutex); | 125 | mutex_init(&rdata->rp_mutex); |
126 | rdata->rport = rport; | ||
124 | rdata->local_port = lport; | 127 | rdata->local_port = lport; |
125 | rdata->trans_state = FC_PORTSTATE_ROGUE; | 128 | rdata->trans_state = FC_PORTSTATE_ROGUE; |
126 | rdata->rp_state = RPORT_ST_INIT; | 129 | rdata->rp_state = RPORT_ST_INIT; |
@@ -129,6 +132,7 @@ struct fc_rport_priv *fc_rport_rogue_create(struct fc_lport *lport, | |||
129 | rdata->ops = NULL; | 132 | rdata->ops = NULL; |
130 | rdata->e_d_tov = lport->e_d_tov; | 133 | rdata->e_d_tov = lport->e_d_tov; |
131 | rdata->r_a_tov = lport->r_a_tov; | 134 | rdata->r_a_tov = lport->r_a_tov; |
135 | rdata->maxframe_size = FC_MIN_MAX_PAYLOAD; | ||
132 | INIT_DELAYED_WORK(&rdata->retry_work, fc_rport_timeout); | 136 | INIT_DELAYED_WORK(&rdata->retry_work, fc_rport_timeout); |
133 | INIT_WORK(&rdata->event_work, fc_rport_work); | 137 | INIT_WORK(&rdata->event_work, fc_rport_work); |
134 | /* | 138 | /* |
@@ -141,6 +145,20 @@ struct fc_rport_priv *fc_rport_rogue_create(struct fc_lport *lport, | |||
141 | } | 145 | } |
142 | 146 | ||
143 | /** | 147 | /** |
148 | * fc_rport_destroy() - free a remote port after last reference is released. | ||
149 | * @kref: pointer to kref inside struct fc_rport_priv | ||
150 | */ | ||
151 | static void fc_rport_destroy(struct kref *kref) | ||
152 | { | ||
153 | struct fc_rport_priv *rdata; | ||
154 | struct fc_rport *rport; | ||
155 | |||
156 | rdata = container_of(kref, struct fc_rport_priv, kref); | ||
157 | rport = rdata->rport; | ||
158 | put_device(&rport->dev); | ||
159 | } | ||
160 | |||
161 | /** | ||
144 | * fc_rport_state() - return a string for the state the rport is in | 162 | * fc_rport_state() - return a string for the state the rport is in |
145 | * @rdata: remote port private data | 163 | * @rdata: remote port private data |
146 | */ | 164 | */ |
@@ -215,22 +233,19 @@ static void fc_rport_work(struct work_struct *work) | |||
215 | enum fc_rport_trans_state trans_state; | 233 | enum fc_rport_trans_state trans_state; |
216 | struct fc_lport *lport = rdata->local_port; | 234 | struct fc_lport *lport = rdata->local_port; |
217 | struct fc_rport_operations *rport_ops; | 235 | struct fc_rport_operations *rport_ops; |
218 | struct fc_rport *rport = PRIV_TO_RPORT(rdata); | 236 | struct fc_rport *rport; |
219 | 237 | ||
220 | mutex_lock(&rdata->rp_mutex); | 238 | mutex_lock(&rdata->rp_mutex); |
221 | event = rdata->event; | 239 | event = rdata->event; |
222 | rport_ops = rdata->ops; | 240 | rport_ops = rdata->ops; |
241 | rport = rdata->rport; | ||
223 | 242 | ||
224 | if (event == RPORT_EV_CREATED) { | 243 | if (event == RPORT_EV_CREATED) { |
225 | struct fc_rport *new_rport; | 244 | struct fc_rport *new_rport; |
226 | struct fc_rport_priv *new_rdata; | 245 | struct fc_rport_priv *new_rdata; |
227 | struct fc_rport_identifiers ids; | 246 | struct fc_rport_identifiers ids; |
228 | 247 | ||
229 | ids.port_id = rport->port_id; | 248 | ids = rdata->ids; |
230 | ids.roles = rport->roles; | ||
231 | ids.port_name = rport->port_name; | ||
232 | ids.node_name = rport->node_name; | ||
233 | |||
234 | rdata->event = RPORT_EV_NONE; | 249 | rdata->event = RPORT_EV_NONE; |
235 | mutex_unlock(&rdata->rp_mutex); | 250 | mutex_unlock(&rdata->rp_mutex); |
236 | 251 | ||
@@ -240,15 +255,20 @@ static void fc_rport_work(struct work_struct *work) | |||
240 | * Switch from the rogue rport to the rport | 255 | * Switch from the rogue rport to the rport |
241 | * returned by the FC class. | 256 | * returned by the FC class. |
242 | */ | 257 | */ |
243 | new_rport->maxframe_size = rport->maxframe_size; | 258 | new_rport->maxframe_size = rdata->maxframe_size; |
244 | 259 | ||
245 | new_rdata = new_rport->dd_data; | 260 | new_rdata = new_rport->dd_data; |
261 | new_rdata->rport = new_rport; | ||
262 | new_rdata->ids = ids; | ||
246 | new_rdata->e_d_tov = rdata->e_d_tov; | 263 | new_rdata->e_d_tov = rdata->e_d_tov; |
247 | new_rdata->r_a_tov = rdata->r_a_tov; | 264 | new_rdata->r_a_tov = rdata->r_a_tov; |
248 | new_rdata->ops = rdata->ops; | 265 | new_rdata->ops = rdata->ops; |
249 | new_rdata->local_port = rdata->local_port; | 266 | new_rdata->local_port = rdata->local_port; |
250 | new_rdata->flags = FC_RP_FLAGS_REC_SUPPORTED; | 267 | new_rdata->flags = FC_RP_FLAGS_REC_SUPPORTED; |
251 | new_rdata->trans_state = FC_PORTSTATE_REAL; | 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); | ||
252 | mutex_init(&new_rdata->rp_mutex); | 272 | mutex_init(&new_rdata->rp_mutex); |
253 | INIT_DELAYED_WORK(&new_rdata->retry_work, | 273 | INIT_DELAYED_WORK(&new_rdata->retry_work, |
254 | fc_rport_timeout); | 274 | fc_rport_timeout); |
@@ -261,12 +281,11 @@ static void fc_rport_work(struct work_struct *work) | |||
261 | " memory for rport (%6x)\n", ids.port_id); | 281 | " memory for rport (%6x)\n", ids.port_id); |
262 | event = RPORT_EV_FAILED; | 282 | event = RPORT_EV_FAILED; |
263 | } | 283 | } |
264 | if (rport->port_id != FC_FID_DIR_SERV) | 284 | if (rdata->ids.port_id != FC_FID_DIR_SERV) |
265 | if (rport_ops->event_callback) | 285 | if (rport_ops->event_callback) |
266 | rport_ops->event_callback(lport, rdata, | 286 | rport_ops->event_callback(lport, rdata, |
267 | RPORT_EV_FAILED); | 287 | RPORT_EV_FAILED); |
268 | put_device(&rport->dev); | 288 | kref_put(&rdata->kref, lport->tt.rport_destroy); |
269 | rport = new_rport; | ||
270 | rdata = new_rport->dd_data; | 289 | rdata = new_rport->dd_data; |
271 | if (rport_ops->event_callback) | 290 | if (rport_ops->event_callback) |
272 | rport_ops->event_callback(lport, rdata, event); | 291 | rport_ops->event_callback(lport, rdata, event); |
@@ -279,7 +298,7 @@ static void fc_rport_work(struct work_struct *work) | |||
279 | rport_ops->event_callback(lport, rdata, event); | 298 | rport_ops->event_callback(lport, rdata, event); |
280 | cancel_delayed_work_sync(&rdata->retry_work); | 299 | cancel_delayed_work_sync(&rdata->retry_work); |
281 | if (trans_state == FC_PORTSTATE_ROGUE) | 300 | if (trans_state == FC_PORTSTATE_ROGUE) |
282 | put_device(&rport->dev); | 301 | kref_put(&rdata->kref, lport->tt.rport_destroy); |
283 | else { | 302 | else { |
284 | port_id = rport->port_id; | 303 | port_id = rport->port_id; |
285 | fc_remote_port_delete(rport); | 304 | fc_remote_port_delete(rport); |
@@ -505,7 +524,6 @@ static void fc_rport_plogi_resp(struct fc_seq *sp, struct fc_frame *fp, | |||
505 | void *rdata_arg) | 524 | void *rdata_arg) |
506 | { | 525 | { |
507 | struct fc_rport_priv *rdata = rdata_arg; | 526 | struct fc_rport_priv *rdata = rdata_arg; |
508 | struct fc_rport *rport = PRIV_TO_RPORT(rdata); | ||
509 | struct fc_lport *lport = rdata->local_port; | 527 | struct fc_lport *lport = rdata->local_port; |
510 | struct fc_els_flogi *plp = NULL; | 528 | struct fc_els_flogi *plp = NULL; |
511 | unsigned int tov; | 529 | unsigned int tov; |
@@ -533,8 +551,8 @@ static void fc_rport_plogi_resp(struct fc_seq *sp, struct fc_frame *fp, | |||
533 | op = fc_frame_payload_op(fp); | 551 | op = fc_frame_payload_op(fp); |
534 | if (op == ELS_LS_ACC && | 552 | if (op == ELS_LS_ACC && |
535 | (plp = fc_frame_payload_get(fp, sizeof(*plp))) != NULL) { | 553 | (plp = fc_frame_payload_get(fp, sizeof(*plp))) != NULL) { |
536 | rport->port_name = get_unaligned_be64(&plp->fl_wwpn); | 554 | rdata->ids.port_name = get_unaligned_be64(&plp->fl_wwpn); |
537 | rport->node_name = get_unaligned_be64(&plp->fl_wwnn); | 555 | rdata->ids.node_name = get_unaligned_be64(&plp->fl_wwnn); |
538 | 556 | ||
539 | tov = ntohl(plp->fl_csp.sp_e_d_tov); | 557 | tov = ntohl(plp->fl_csp.sp_e_d_tov); |
540 | if (ntohs(plp->fl_csp.sp_features) & FC_SP_FT_EDTR) | 558 | if (ntohs(plp->fl_csp.sp_features) & FC_SP_FT_EDTR) |
@@ -546,14 +564,13 @@ static void fc_rport_plogi_resp(struct fc_seq *sp, struct fc_frame *fp, | |||
546 | if (cssp_seq < csp_seq) | 564 | if (cssp_seq < csp_seq) |
547 | csp_seq = cssp_seq; | 565 | csp_seq = cssp_seq; |
548 | rdata->max_seq = csp_seq; | 566 | rdata->max_seq = csp_seq; |
549 | rport->maxframe_size = | 567 | rdata->maxframe_size = fc_plogi_get_maxframe(plp, lport->mfs); |
550 | fc_plogi_get_maxframe(plp, lport->mfs); | ||
551 | 568 | ||
552 | /* | 569 | /* |
553 | * If the rport is one of the well known addresses | 570 | * If the rport is one of the well known addresses |
554 | * we skip PRLI and RTV and go straight to READY. | 571 | * we skip PRLI and RTV and go straight to READY. |
555 | */ | 572 | */ |
556 | if (rport->port_id >= FC_FID_DOM_MGR) | 573 | if (rdata->ids.port_id >= FC_FID_DOM_MGR) |
557 | fc_rport_enter_ready(rdata); | 574 | fc_rport_enter_ready(rdata); |
558 | else | 575 | else |
559 | fc_rport_enter_prli(rdata); | 576 | fc_rport_enter_prli(rdata); |
@@ -564,7 +581,7 @@ out: | |||
564 | fc_frame_free(fp); | 581 | fc_frame_free(fp); |
565 | err: | 582 | err: |
566 | mutex_unlock(&rdata->rp_mutex); | 583 | mutex_unlock(&rdata->rp_mutex); |
567 | put_device(&rport->dev); | 584 | kref_put(&rdata->kref, rdata->local_port->tt.rport_destroy); |
568 | } | 585 | } |
569 | 586 | ||
570 | /** | 587 | /** |
@@ -577,7 +594,6 @@ err: | |||
577 | static void fc_rport_enter_plogi(struct fc_rport_priv *rdata) | 594 | static void fc_rport_enter_plogi(struct fc_rport_priv *rdata) |
578 | { | 595 | { |
579 | struct fc_lport *lport = rdata->local_port; | 596 | struct fc_lport *lport = rdata->local_port; |
580 | struct fc_rport *rport = PRIV_TO_RPORT(rdata); | ||
581 | struct fc_frame *fp; | 597 | struct fc_frame *fp; |
582 | 598 | ||
583 | FC_RPORT_DBG(rdata, "Port entered PLOGI state from %s state\n", | 599 | FC_RPORT_DBG(rdata, "Port entered PLOGI state from %s state\n", |
@@ -585,7 +601,7 @@ static void fc_rport_enter_plogi(struct fc_rport_priv *rdata) | |||
585 | 601 | ||
586 | fc_rport_state_enter(rdata, RPORT_ST_PLOGI); | 602 | fc_rport_state_enter(rdata, RPORT_ST_PLOGI); |
587 | 603 | ||
588 | rport->maxframe_size = FC_MIN_MAX_PAYLOAD; | 604 | rdata->maxframe_size = FC_MIN_MAX_PAYLOAD; |
589 | fp = fc_frame_alloc(lport, sizeof(struct fc_els_flogi)); | 605 | fp = fc_frame_alloc(lport, sizeof(struct fc_els_flogi)); |
590 | if (!fp) { | 606 | if (!fp) { |
591 | fc_rport_error_retry(rdata, fp); | 607 | fc_rport_error_retry(rdata, fp); |
@@ -593,11 +609,11 @@ static void fc_rport_enter_plogi(struct fc_rport_priv *rdata) | |||
593 | } | 609 | } |
594 | rdata->e_d_tov = lport->e_d_tov; | 610 | rdata->e_d_tov = lport->e_d_tov; |
595 | 611 | ||
596 | if (!lport->tt.elsct_send(lport, rport->port_id, fp, ELS_PLOGI, | 612 | if (!lport->tt.elsct_send(lport, rdata->ids.port_id, fp, ELS_PLOGI, |
597 | fc_rport_plogi_resp, rdata, lport->e_d_tov)) | 613 | fc_rport_plogi_resp, rdata, lport->e_d_tov)) |
598 | fc_rport_error_retry(rdata, fp); | 614 | fc_rport_error_retry(rdata, fp); |
599 | else | 615 | else |
600 | get_device(&rport->dev); | 616 | kref_get(&rdata->kref); |
601 | } | 617 | } |
602 | 618 | ||
603 | /** | 619 | /** |
@@ -614,7 +630,6 @@ static void fc_rport_prli_resp(struct fc_seq *sp, struct fc_frame *fp, | |||
614 | void *rdata_arg) | 630 | void *rdata_arg) |
615 | { | 631 | { |
616 | struct fc_rport_priv *rdata = rdata_arg; | 632 | struct fc_rport_priv *rdata = rdata_arg; |
617 | struct fc_rport *rport = PRIV_TO_RPORT(rdata); | ||
618 | struct { | 633 | struct { |
619 | struct fc_els_prli prli; | 634 | struct fc_els_prli prli; |
620 | struct fc_els_spp spp; | 635 | struct fc_els_spp spp; |
@@ -649,13 +664,13 @@ static void fc_rport_prli_resp(struct fc_seq *sp, struct fc_frame *fp, | |||
649 | rdata->flags |= FC_RP_FLAGS_RETRY; | 664 | rdata->flags |= FC_RP_FLAGS_RETRY; |
650 | } | 665 | } |
651 | 666 | ||
652 | rport->supported_classes = FC_COS_CLASS3; | 667 | rdata->supported_classes = FC_COS_CLASS3; |
653 | if (fcp_parm & FCP_SPPF_INIT_FCN) | 668 | if (fcp_parm & FCP_SPPF_INIT_FCN) |
654 | roles |= FC_RPORT_ROLE_FCP_INITIATOR; | 669 | roles |= FC_RPORT_ROLE_FCP_INITIATOR; |
655 | if (fcp_parm & FCP_SPPF_TARG_FCN) | 670 | if (fcp_parm & FCP_SPPF_TARG_FCN) |
656 | roles |= FC_RPORT_ROLE_FCP_TARGET; | 671 | roles |= FC_RPORT_ROLE_FCP_TARGET; |
657 | 672 | ||
658 | rport->roles = roles; | 673 | rdata->ids.roles = roles; |
659 | fc_rport_enter_rtv(rdata); | 674 | fc_rport_enter_rtv(rdata); |
660 | 675 | ||
661 | } else { | 676 | } else { |
@@ -667,7 +682,7 @@ out: | |||
667 | fc_frame_free(fp); | 682 | fc_frame_free(fp); |
668 | err: | 683 | err: |
669 | mutex_unlock(&rdata->rp_mutex); | 684 | mutex_unlock(&rdata->rp_mutex); |
670 | put_device(&rport->dev); | 685 | kref_put(&rdata->kref, rdata->local_port->tt.rport_destroy); |
671 | } | 686 | } |
672 | 687 | ||
673 | /** | 688 | /** |
@@ -684,7 +699,6 @@ static void fc_rport_logo_resp(struct fc_seq *sp, struct fc_frame *fp, | |||
684 | void *rdata_arg) | 699 | void *rdata_arg) |
685 | { | 700 | { |
686 | struct fc_rport_priv *rdata = rdata_arg; | 701 | struct fc_rport_priv *rdata = rdata_arg; |
687 | struct fc_rport *rport = PRIV_TO_RPORT(rdata); | ||
688 | u8 op; | 702 | u8 op; |
689 | 703 | ||
690 | mutex_lock(&rdata->rp_mutex); | 704 | mutex_lock(&rdata->rp_mutex); |
@@ -716,7 +730,7 @@ out: | |||
716 | fc_frame_free(fp); | 730 | fc_frame_free(fp); |
717 | err: | 731 | err: |
718 | mutex_unlock(&rdata->rp_mutex); | 732 | mutex_unlock(&rdata->rp_mutex); |
719 | put_device(&rport->dev); | 733 | kref_put(&rdata->kref, rdata->local_port->tt.rport_destroy); |
720 | } | 734 | } |
721 | 735 | ||
722 | /** | 736 | /** |
@@ -728,7 +742,6 @@ err: | |||
728 | */ | 742 | */ |
729 | static void fc_rport_enter_prli(struct fc_rport_priv *rdata) | 743 | static void fc_rport_enter_prli(struct fc_rport_priv *rdata) |
730 | { | 744 | { |
731 | struct fc_rport *rport = PRIV_TO_RPORT(rdata); | ||
732 | struct fc_lport *lport = rdata->local_port; | 745 | struct fc_lport *lport = rdata->local_port; |
733 | struct { | 746 | struct { |
734 | struct fc_els_prli prli; | 747 | struct fc_els_prli prli; |
@@ -747,11 +760,11 @@ static void fc_rport_enter_prli(struct fc_rport_priv *rdata) | |||
747 | return; | 760 | return; |
748 | } | 761 | } |
749 | 762 | ||
750 | if (!lport->tt.elsct_send(lport, rport->port_id, fp, ELS_PRLI, | 763 | if (!lport->tt.elsct_send(lport, rdata->ids.port_id, fp, ELS_PRLI, |
751 | fc_rport_prli_resp, rdata, lport->e_d_tov)) | 764 | fc_rport_prli_resp, rdata, lport->e_d_tov)) |
752 | fc_rport_error_retry(rdata, fp); | 765 | fc_rport_error_retry(rdata, fp); |
753 | else | 766 | else |
754 | get_device(&rport->dev); | 767 | kref_get(&rdata->kref); |
755 | } | 768 | } |
756 | 769 | ||
757 | /** | 770 | /** |
@@ -770,7 +783,6 @@ static void fc_rport_rtv_resp(struct fc_seq *sp, struct fc_frame *fp, | |||
770 | void *rdata_arg) | 783 | void *rdata_arg) |
771 | { | 784 | { |
772 | struct fc_rport_priv *rdata = rdata_arg; | 785 | struct fc_rport_priv *rdata = rdata_arg; |
773 | struct fc_rport *rport = PRIV_TO_RPORT(rdata); | ||
774 | u8 op; | 786 | u8 op; |
775 | 787 | ||
776 | mutex_lock(&rdata->rp_mutex); | 788 | mutex_lock(&rdata->rp_mutex); |
@@ -818,7 +830,7 @@ out: | |||
818 | fc_frame_free(fp); | 830 | fc_frame_free(fp); |
819 | err: | 831 | err: |
820 | mutex_unlock(&rdata->rp_mutex); | 832 | mutex_unlock(&rdata->rp_mutex); |
821 | put_device(&rport->dev); | 833 | kref_put(&rdata->kref, rdata->local_port->tt.rport_destroy); |
822 | } | 834 | } |
823 | 835 | ||
824 | /** | 836 | /** |
@@ -832,7 +844,6 @@ static void fc_rport_enter_rtv(struct fc_rport_priv *rdata) | |||
832 | { | 844 | { |
833 | struct fc_frame *fp; | 845 | struct fc_frame *fp; |
834 | struct fc_lport *lport = rdata->local_port; | 846 | struct fc_lport *lport = rdata->local_port; |
835 | struct fc_rport *rport = PRIV_TO_RPORT(rdata); | ||
836 | 847 | ||
837 | FC_RPORT_DBG(rdata, "Port entered RTV state from %s state\n", | 848 | FC_RPORT_DBG(rdata, "Port entered RTV state from %s state\n", |
838 | fc_rport_state(rdata)); | 849 | fc_rport_state(rdata)); |
@@ -845,11 +856,11 @@ static void fc_rport_enter_rtv(struct fc_rport_priv *rdata) | |||
845 | return; | 856 | return; |
846 | } | 857 | } |
847 | 858 | ||
848 | if (!lport->tt.elsct_send(lport, rport->port_id, fp, ELS_RTV, | 859 | if (!lport->tt.elsct_send(lport, rdata->ids.port_id, fp, ELS_RTV, |
849 | fc_rport_rtv_resp, rdata, lport->e_d_tov)) | 860 | fc_rport_rtv_resp, rdata, lport->e_d_tov)) |
850 | fc_rport_error_retry(rdata, fp); | 861 | fc_rport_error_retry(rdata, fp); |
851 | else | 862 | else |
852 | get_device(&rport->dev); | 863 | kref_get(&rdata->kref); |
853 | } | 864 | } |
854 | 865 | ||
855 | /** | 866 | /** |
@@ -862,7 +873,6 @@ static void fc_rport_enter_rtv(struct fc_rport_priv *rdata) | |||
862 | static void fc_rport_enter_logo(struct fc_rport_priv *rdata) | 873 | static void fc_rport_enter_logo(struct fc_rport_priv *rdata) |
863 | { | 874 | { |
864 | struct fc_lport *lport = rdata->local_port; | 875 | struct fc_lport *lport = rdata->local_port; |
865 | struct fc_rport *rport = PRIV_TO_RPORT(rdata); | ||
866 | struct fc_frame *fp; | 876 | struct fc_frame *fp; |
867 | 877 | ||
868 | FC_RPORT_DBG(rdata, "Port entered LOGO state from %s state\n", | 878 | FC_RPORT_DBG(rdata, "Port entered LOGO state from %s state\n", |
@@ -876,11 +886,11 @@ static void fc_rport_enter_logo(struct fc_rport_priv *rdata) | |||
876 | return; | 886 | return; |
877 | } | 887 | } |
878 | 888 | ||
879 | if (!lport->tt.elsct_send(lport, rport->port_id, fp, ELS_LOGO, | 889 | if (!lport->tt.elsct_send(lport, rdata->ids.port_id, fp, ELS_LOGO, |
880 | fc_rport_logo_resp, rdata, lport->e_d_tov)) | 890 | fc_rport_logo_resp, rdata, lport->e_d_tov)) |
881 | fc_rport_error_retry(rdata, fp); | 891 | fc_rport_error_retry(rdata, fp); |
882 | else | 892 | else |
883 | get_device(&rport->dev); | 893 | kref_get(&rdata->kref); |
884 | } | 894 | } |
885 | 895 | ||
886 | 896 | ||
@@ -956,7 +966,6 @@ void fc_rport_recv_req(struct fc_seq *sp, struct fc_frame *fp, | |||
956 | static void fc_rport_recv_plogi_req(struct fc_rport_priv *rdata, | 966 | static void fc_rport_recv_plogi_req(struct fc_rport_priv *rdata, |
957 | struct fc_seq *sp, struct fc_frame *rx_fp) | 967 | struct fc_seq *sp, struct fc_frame *rx_fp) |
958 | { | 968 | { |
959 | struct fc_rport *rport = PRIV_TO_RPORT(rdata); | ||
960 | struct fc_lport *lport = rdata->local_port; | 969 | struct fc_lport *lport = rdata->local_port; |
961 | struct fc_frame *fp = rx_fp; | 970 | struct fc_frame *fp = rx_fp; |
962 | struct fc_exch *ep; | 971 | struct fc_exch *ep; |
@@ -1041,12 +1050,13 @@ static void fc_rport_recv_plogi_req(struct fc_rport_priv *rdata, | |||
1041 | } else { | 1050 | } else { |
1042 | sp = lport->tt.seq_start_next(sp); | 1051 | sp = lport->tt.seq_start_next(sp); |
1043 | WARN_ON(!sp); | 1052 | WARN_ON(!sp); |
1044 | fc_rport_set_name(rport, wwpn, wwnn); | 1053 | rdata->ids.port_name = wwpn; |
1054 | rdata->ids.node_name = wwnn; | ||
1045 | 1055 | ||
1046 | /* | 1056 | /* |
1047 | * Get session payload size from incoming PLOGI. | 1057 | * Get session payload size from incoming PLOGI. |
1048 | */ | 1058 | */ |
1049 | rport->maxframe_size = | 1059 | rdata->maxframe_size = |
1050 | fc_plogi_get_maxframe(pl, lport->mfs); | 1060 | fc_plogi_get_maxframe(pl, lport->mfs); |
1051 | fc_frame_free(rx_fp); | 1061 | fc_frame_free(rx_fp); |
1052 | fc_plogi_fill(lport, fp, ELS_LS_ACC); | 1062 | fc_plogi_fill(lport, fp, ELS_LS_ACC); |
@@ -1079,7 +1089,6 @@ static void fc_rport_recv_plogi_req(struct fc_rport_priv *rdata, | |||
1079 | static void fc_rport_recv_prli_req(struct fc_rport_priv *rdata, | 1089 | static void fc_rport_recv_prli_req(struct fc_rport_priv *rdata, |
1080 | struct fc_seq *sp, struct fc_frame *rx_fp) | 1090 | struct fc_seq *sp, struct fc_frame *rx_fp) |
1081 | { | 1091 | { |
1082 | struct fc_rport *rport = PRIV_TO_RPORT(rdata); | ||
1083 | struct fc_lport *lport = rdata->local_port; | 1092 | struct fc_lport *lport = rdata->local_port; |
1084 | struct fc_exch *ep; | 1093 | struct fc_exch *ep; |
1085 | struct fc_frame *fp; | 1094 | struct fc_frame *fp; |
@@ -1173,12 +1182,12 @@ static void fc_rport_recv_prli_req(struct fc_rport_priv *rdata, | |||
1173 | fcp_parm = ntohl(rspp->spp_params); | 1182 | fcp_parm = ntohl(rspp->spp_params); |
1174 | if (fcp_parm * FCP_SPPF_RETRY) | 1183 | if (fcp_parm * FCP_SPPF_RETRY) |
1175 | rdata->flags |= FC_RP_FLAGS_RETRY; | 1184 | rdata->flags |= FC_RP_FLAGS_RETRY; |
1176 | rport->supported_classes = FC_COS_CLASS3; | 1185 | rdata->supported_classes = FC_COS_CLASS3; |
1177 | if (fcp_parm & FCP_SPPF_INIT_FCN) | 1186 | if (fcp_parm & FCP_SPPF_INIT_FCN) |
1178 | roles |= FC_RPORT_ROLE_FCP_INITIATOR; | 1187 | roles |= FC_RPORT_ROLE_FCP_INITIATOR; |
1179 | if (fcp_parm & FCP_SPPF_TARG_FCN) | 1188 | if (fcp_parm & FCP_SPPF_TARG_FCN) |
1180 | roles |= FC_RPORT_ROLE_FCP_TARGET; | 1189 | roles |= FC_RPORT_ROLE_FCP_TARGET; |
1181 | rport->roles = roles; | 1190 | rdata->ids.roles = roles; |
1182 | 1191 | ||
1183 | spp->spp_params = | 1192 | spp->spp_params = |
1184 | htonl(lport->service_params); | 1193 | htonl(lport->service_params); |
@@ -1310,6 +1319,9 @@ int fc_rport_init(struct fc_lport *lport) | |||
1310 | if (!lport->tt.rport_flush_queue) | 1319 | if (!lport->tt.rport_flush_queue) |
1311 | lport->tt.rport_flush_queue = fc_rport_flush_queue; | 1320 | lport->tt.rport_flush_queue = fc_rport_flush_queue; |
1312 | 1321 | ||
1322 | if (!lport->tt.rport_destroy) | ||
1323 | lport->tt.rport_destroy = fc_rport_destroy; | ||
1324 | |||
1313 | return 0; | 1325 | return 0; |
1314 | } | 1326 | } |
1315 | EXPORT_SYMBOL(fc_rport_init); | 1327 | EXPORT_SYMBOL(fc_rport_init); |
diff --git a/include/scsi/libfc.h b/include/scsi/libfc.h index 2473167464c2..a94d216d2207 100644 --- a/include/scsi/libfc.h +++ b/include/scsi/libfc.h | |||
@@ -76,11 +76,7 @@ do { \ | |||
76 | (port_id), ##args)) | 76 | (port_id), ##args)) |
77 | 77 | ||
78 | #define FC_RPORT_DBG(rdata, fmt, args...) \ | 78 | #define FC_RPORT_DBG(rdata, fmt, args...) \ |
79 | do { \ | 79 | FC_RPORT_ID_DBG((rdata)->local_port, (rdata)->ids.port_id, fmt, ##args) |
80 | struct fc_lport *lport = rdata->local_port; \ | ||
81 | struct fc_rport *rport = PRIV_TO_RPORT(rdata); \ | ||
82 | FC_RPORT_ID_DBG(lport, rport->port_id, fmt, ##args); \ | ||
83 | } while (0) | ||
84 | 80 | ||
85 | #define FC_FCP_DBG(pkt, fmt, args...) \ | 81 | #define FC_FCP_DBG(pkt, fmt, args...) \ |
86 | FC_CHECK_LOGGING(FC_FCP_LOGGING, \ | 82 | FC_CHECK_LOGGING(FC_FCP_LOGGING, \ |
@@ -195,9 +191,13 @@ struct fc_rport_operations { | |||
195 | /** | 191 | /** |
196 | * struct fc_rport_libfc_priv - libfc internal information about a remote port | 192 | * struct fc_rport_libfc_priv - libfc internal information about a remote port |
197 | * @local_port: Fibre Channel host port instance | 193 | * @local_port: Fibre Channel host port instance |
194 | * @rport: transport remote port | ||
195 | * @kref: reference counter | ||
198 | * @rp_state: state tracks progress of PLOGI, PRLI, and RTV exchanges | 196 | * @rp_state: state tracks progress of PLOGI, PRLI, and RTV exchanges |
197 | * @ids: remote port identifiers and roles | ||
199 | * @flags: REC and RETRY supported flags | 198 | * @flags: REC and RETRY supported flags |
200 | * @max_seq: maximum number of concurrent sequences | 199 | * @max_seq: maximum number of concurrent sequences |
200 | * @maxframe_size: maximum frame size | ||
201 | * @retries: retry count in current state | 201 | * @retries: retry count in current state |
202 | * @e_d_tov: error detect timeout value (in msec) | 202 | * @e_d_tov: error detect timeout value (in msec) |
203 | * @r_a_tov: resource allocation timeout value (in msec) | 203 | * @r_a_tov: resource allocation timeout value (in msec) |
@@ -207,11 +207,15 @@ struct fc_rport_operations { | |||
207 | */ | 207 | */ |
208 | struct fc_rport_libfc_priv { | 208 | struct fc_rport_libfc_priv { |
209 | struct fc_lport *local_port; | 209 | struct fc_lport *local_port; |
210 | struct fc_rport *rport; | ||
211 | struct kref kref; | ||
210 | enum fc_rport_state rp_state; | 212 | enum fc_rport_state rp_state; |
213 | struct fc_rport_identifiers ids; | ||
211 | u16 flags; | 214 | u16 flags; |
212 | #define FC_RP_FLAGS_REC_SUPPORTED (1 << 0) | 215 | #define FC_RP_FLAGS_REC_SUPPORTED (1 << 0) |
213 | #define FC_RP_FLAGS_RETRY (1 << 1) | 216 | #define FC_RP_FLAGS_RETRY (1 << 1) |
214 | u16 max_seq; | 217 | u16 max_seq; |
218 | u16 maxframe_size; | ||
215 | unsigned int retries; | 219 | unsigned int retries; |
216 | unsigned int e_d_tov; | 220 | unsigned int e_d_tov; |
217 | unsigned int r_a_tov; | 221 | unsigned int r_a_tov; |
@@ -222,19 +226,12 @@ struct fc_rport_libfc_priv { | |||
222 | struct fc_rport_operations *ops; | 226 | struct fc_rport_operations *ops; |
223 | struct list_head peers; | 227 | struct list_head peers; |
224 | struct work_struct event_work; | 228 | struct work_struct event_work; |
229 | u32 supported_classes; | ||
225 | }; | 230 | }; |
226 | 231 | ||
227 | #define PRIV_TO_RPORT(x) \ | ||
228 | ((struct fc_rport *)((void *)(x) - sizeof(struct fc_rport))) | ||
229 | #define RPORT_TO_PRIV(x) \ | 232 | #define RPORT_TO_PRIV(x) \ |
230 | ((struct fc_rport_libfc_priv *)((void *)(x) + sizeof(struct fc_rport))) | 233 | ((struct fc_rport_libfc_priv *)((void *)(x) + sizeof(struct fc_rport))) |
231 | 234 | ||
232 | static inline void fc_rport_set_name(struct fc_rport *rport, u64 wwpn, u64 wwnn) | ||
233 | { | ||
234 | rport->node_name = wwnn; | ||
235 | rport->port_name = wwpn; | ||
236 | } | ||
237 | |||
238 | /* | 235 | /* |
239 | * fcoe stats structure | 236 | * fcoe stats structure |
240 | */ | 237 | */ |
@@ -609,6 +606,12 @@ struct libfc_function_template { | |||
609 | struct fc_rport_priv *(*rport_lookup)(const struct fc_lport *, u32); | 606 | struct fc_rport_priv *(*rport_lookup)(const struct fc_lport *, u32); |
610 | 607 | ||
611 | /* | 608 | /* |
609 | * Destroy an rport after final kref_put(). | ||
610 | * The argument is a pointer to the kref inside the fc_rport_priv. | ||
611 | */ | ||
612 | void (*rport_destroy)(struct kref *); | ||
613 | |||
614 | /* | ||
612 | * Send a fcp cmd from fsp pkt. | 615 | * Send a fcp cmd from fsp pkt. |
613 | * Called with the SCSI host lock unlocked and irqs disabled. | 616 | * Called with the SCSI host lock unlocked and irqs disabled. |
614 | * | 617 | * |