blob: 69f6e588d37b6dfab8d41a6f6980b64598ea1311 [file] [log] [blame]
Robert Love42e9a922008-12-09 15:10:17 -08001/*
2 * Copyright(c) 2007 - 2008 Intel Corporation. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms and conditions of the GNU General Public License,
6 * version 2, as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 *
13 * You should have received a copy of the GNU General Public License along with
14 * this program; if not, write to the Free Software Foundation, Inc.,
15 * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
16 *
17 * Maintained at www.Open-FCoE.org
18 */
19
20/*
21 * RPORT GENERAL INFO
22 *
23 * This file contains all processing regarding fc_rports. It contains the
24 * rport state machine and does all rport interaction with the transport class.
25 * There should be no other places in libfc that interact directly with the
26 * transport class in regards to adding and deleting rports.
27 *
28 * fc_rport's represent N_Port's within the fabric.
29 */
30
31/*
32 * RPORT LOCKING
33 *
34 * The rport should never hold the rport mutex and then attempt to acquire
35 * either the lport or disc mutexes. The rport's mutex is considered lesser
36 * than both the lport's mutex and the disc mutex. Refer to fc_lport.c for
37 * more comments on the heirarchy.
38 *
39 * The locking strategy is similar to the lport's strategy. The lock protects
40 * the rport's states and is held and released by the entry points to the rport
41 * block. All _enter_* functions correspond to rport states and expect the rport
42 * mutex to be locked before calling them. This means that rports only handle
43 * one request or response at a time, since they're not critical for the I/O
44 * path this potential over-use of the mutex is acceptable.
45 */
46
47#include <linux/kernel.h>
48#include <linux/spinlock.h>
49#include <linux/interrupt.h>
50#include <linux/rcupdate.h>
51#include <linux/timer.h>
52#include <linux/workqueue.h>
53#include <asm/unaligned.h>
54
55#include <scsi/libfc.h>
56#include <scsi/fc_encode.h>
57
Robert Love42e9a922008-12-09 15:10:17 -080058struct workqueue_struct *rport_event_queue;
59
Joe Eykholt9fb9d322009-08-25 14:00:50 -070060static void fc_rport_enter_plogi(struct fc_rport_priv *);
61static void fc_rport_enter_prli(struct fc_rport_priv *);
62static void fc_rport_enter_rtv(struct fc_rport_priv *);
63static void fc_rport_enter_ready(struct fc_rport_priv *);
64static void fc_rport_enter_logo(struct fc_rport_priv *);
Robert Love42e9a922008-12-09 15:10:17 -080065
Joe Eykholt9fb9d322009-08-25 14:00:50 -070066static void fc_rport_recv_plogi_req(struct fc_rport_priv *,
Robert Love42e9a922008-12-09 15:10:17 -080067 struct fc_seq *, struct fc_frame *);
Joe Eykholt9fb9d322009-08-25 14:00:50 -070068static void fc_rport_recv_prli_req(struct fc_rport_priv *,
Robert Love42e9a922008-12-09 15:10:17 -080069 struct fc_seq *, struct fc_frame *);
Joe Eykholt9fb9d322009-08-25 14:00:50 -070070static void fc_rport_recv_prlo_req(struct fc_rport_priv *,
Robert Love42e9a922008-12-09 15:10:17 -080071 struct fc_seq *, struct fc_frame *);
Joe Eykholt9fb9d322009-08-25 14:00:50 -070072static void fc_rport_recv_logo_req(struct fc_rport_priv *,
Robert Love42e9a922008-12-09 15:10:17 -080073 struct fc_seq *, struct fc_frame *);
74static void fc_rport_timeout(struct work_struct *);
Joe Eykholt9fb9d322009-08-25 14:00:50 -070075static void fc_rport_error(struct fc_rport_priv *, struct fc_frame *);
76static void fc_rport_error_retry(struct fc_rport_priv *, struct fc_frame *);
Robert Love42e9a922008-12-09 15:10:17 -080077static void fc_rport_work(struct work_struct *);
78
79static const char *fc_rport_state_names[] = {
Robert Love42e9a922008-12-09 15:10:17 -080080 [RPORT_ST_INIT] = "Init",
81 [RPORT_ST_PLOGI] = "PLOGI",
82 [RPORT_ST_PRLI] = "PRLI",
83 [RPORT_ST_RTV] = "RTV",
84 [RPORT_ST_READY] = "Ready",
85 [RPORT_ST_LOGO] = "LOGO",
Joe Eykholt14194052009-07-29 17:04:43 -070086 [RPORT_ST_DELETE] = "Delete",
Robert Love42e9a922008-12-09 15:10:17 -080087};
88
89static void fc_rport_rogue_destroy(struct device *dev)
90{
91 struct fc_rport *rport = dev_to_rport(dev);
Joe Eykholt9fb9d322009-08-25 14:00:50 -070092 struct fc_rport_priv *rdata = RPORT_TO_PRIV(rport);
93
94 FC_RPORT_DBG(rdata, "Destroying rogue rport\n");
Robert Love42e9a922008-12-09 15:10:17 -080095 kfree(rport);
96}
97
Joe Eykholt9fb9d322009-08-25 14:00:50 -070098struct fc_rport_priv *fc_rport_rogue_create(struct fc_lport *lport,
99 struct fc_rport_identifiers *ids)
Robert Love42e9a922008-12-09 15:10:17 -0800100{
101 struct fc_rport *rport;
Joe Eykholtab28f1f2009-08-25 14:00:34 -0700102 struct fc_rport_priv *rdata;
Robert Love42e9a922008-12-09 15:10:17 -0800103 rport = kzalloc(sizeof(*rport) + sizeof(*rdata), GFP_KERNEL);
104
105 if (!rport)
106 return NULL;
107
108 rdata = RPORT_TO_PRIV(rport);
109
110 rport->dd_data = rdata;
Joe Eykholt795d86f2009-08-25 14:00:39 -0700111 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;
Robert Love42e9a922008-12-09 15:10:17 -0800115 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
Joe Eykholtf211fa52009-08-25 14:01:01 -0700123 rdata->ids = *ids;
124 kref_init(&rdata->kref);
Robert Love42e9a922008-12-09 15:10:17 -0800125 mutex_init(&rdata->rp_mutex);
Joe Eykholtf211fa52009-08-25 14:01:01 -0700126 rdata->rport = rport;
Joe Eykholt795d86f2009-08-25 14:00:39 -0700127 rdata->local_port = lport;
Robert Love42e9a922008-12-09 15:10:17 -0800128 rdata->trans_state = FC_PORTSTATE_ROGUE;
129 rdata->rp_state = RPORT_ST_INIT;
130 rdata->event = RPORT_EV_NONE;
131 rdata->flags = FC_RP_FLAGS_REC_SUPPORTED;
132 rdata->ops = NULL;
Joe Eykholt795d86f2009-08-25 14:00:39 -0700133 rdata->e_d_tov = lport->e_d_tov;
134 rdata->r_a_tov = lport->r_a_tov;
Joe Eykholtf211fa52009-08-25 14:01:01 -0700135 rdata->maxframe_size = FC_MIN_MAX_PAYLOAD;
Robert Love42e9a922008-12-09 15:10:17 -0800136 INIT_DELAYED_WORK(&rdata->retry_work, fc_rport_timeout);
137 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
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700144 return rdata;
Robert Love42e9a922008-12-09 15:10:17 -0800145}
146
147/**
Joe Eykholtf211fa52009-08-25 14:01:01 -0700148 * fc_rport_destroy() - free a remote port after last reference is released.
149 * @kref: pointer to kref inside struct fc_rport_priv
150 */
151static 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/**
Robert Love34f42a02009-02-27 10:55:45 -0800162 * fc_rport_state() - return a string for the state the rport is in
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700163 * @rdata: remote port private data
Robert Love42e9a922008-12-09 15:10:17 -0800164 */
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700165static const char *fc_rport_state(struct fc_rport_priv *rdata)
Robert Love42e9a922008-12-09 15:10:17 -0800166{
167 const char *cp;
Robert Love42e9a922008-12-09 15:10:17 -0800168
169 cp = fc_rport_state_names[rdata->rp_state];
170 if (!cp)
171 cp = "Unknown";
172 return cp;
173}
174
175/**
Robert Love34f42a02009-02-27 10:55:45 -0800176 * fc_set_rport_loss_tmo() - Set the remote port loss timeout in seconds.
Robert Love42e9a922008-12-09 15:10:17 -0800177 * @rport: Pointer to Fibre Channel remote port structure
178 * @timeout: timeout in seconds
179 */
180void fc_set_rport_loss_tmo(struct fc_rport *rport, u32 timeout)
181{
182 if (timeout)
183 rport->dev_loss_tmo = timeout + 5;
184 else
185 rport->dev_loss_tmo = 30;
186}
187EXPORT_SYMBOL(fc_set_rport_loss_tmo);
188
189/**
Robert Love34f42a02009-02-27 10:55:45 -0800190 * fc_plogi_get_maxframe() - Get max payload from the common service parameters
Robert Love42e9a922008-12-09 15:10:17 -0800191 * @flp: FLOGI payload structure
192 * @maxval: upper limit, may be less than what is in the service parameters
193 */
Robert Loveb2ab99c2009-02-27 10:55:50 -0800194static unsigned int fc_plogi_get_maxframe(struct fc_els_flogi *flp,
195 unsigned int maxval)
Robert Love42e9a922008-12-09 15:10:17 -0800196{
197 unsigned int mfs;
198
199 /*
200 * Get max payload from the common service parameters and the
201 * class 3 receive data field size.
202 */
203 mfs = ntohs(flp->fl_csp.sp_bb_data) & FC_SP_BB_DATA_MASK;
204 if (mfs >= FC_SP_MIN_MAX_PAYLOAD && mfs < maxval)
205 maxval = mfs;
206 mfs = ntohs(flp->fl_cssp[3 - 1].cp_rdfs);
207 if (mfs >= FC_SP_MIN_MAX_PAYLOAD && mfs < maxval)
208 maxval = mfs;
209 return maxval;
210}
211
212/**
Robert Love34f42a02009-02-27 10:55:45 -0800213 * fc_rport_state_enter() - Change the rport's state
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700214 * @rdata: The rport whose state should change
Robert Love42e9a922008-12-09 15:10:17 -0800215 * @new: The new state of the rport
216 *
217 * Locking Note: Called with the rport lock held
218 */
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700219static void fc_rport_state_enter(struct fc_rport_priv *rdata,
Robert Love42e9a922008-12-09 15:10:17 -0800220 enum fc_rport_state new)
221{
Robert Love42e9a922008-12-09 15:10:17 -0800222 if (rdata->rp_state != new)
223 rdata->retries = 0;
224 rdata->rp_state = new;
225}
226
227static void fc_rport_work(struct work_struct *work)
228{
Abhijeet Joglekar571f8242009-02-27 10:54:41 -0800229 u32 port_id;
Joe Eykholtab28f1f2009-08-25 14:00:34 -0700230 struct fc_rport_priv *rdata =
231 container_of(work, struct fc_rport_priv, event_work);
Robert Love42e9a922008-12-09 15:10:17 -0800232 enum fc_rport_event event;
233 enum fc_rport_trans_state trans_state;
234 struct fc_lport *lport = rdata->local_port;
235 struct fc_rport_operations *rport_ops;
Joe Eykholtf211fa52009-08-25 14:01:01 -0700236 struct fc_rport *rport;
Robert Love42e9a922008-12-09 15:10:17 -0800237
238 mutex_lock(&rdata->rp_mutex);
239 event = rdata->event;
240 rport_ops = rdata->ops;
Joe Eykholtf211fa52009-08-25 14:01:01 -0700241 rport = rdata->rport;
Robert Love42e9a922008-12-09 15:10:17 -0800242
243 if (event == RPORT_EV_CREATED) {
244 struct fc_rport *new_rport;
Joe Eykholtab28f1f2009-08-25 14:00:34 -0700245 struct fc_rport_priv *new_rdata;
Robert Love42e9a922008-12-09 15:10:17 -0800246 struct fc_rport_identifiers ids;
247
Joe Eykholtf211fa52009-08-25 14:01:01 -0700248 ids = rdata->ids;
Joe Eykholt5f7ea3b2009-07-29 17:04:49 -0700249 rdata->event = RPORT_EV_NONE;
Robert Love42e9a922008-12-09 15:10:17 -0800250 mutex_unlock(&rdata->rp_mutex);
251
252 new_rport = fc_remote_port_add(lport->host, 0, &ids);
253 if (new_rport) {
254 /*
255 * Switch from the rogue rport to the rport
256 * returned by the FC class.
257 */
Joe Eykholtf211fa52009-08-25 14:01:01 -0700258 new_rport->maxframe_size = rdata->maxframe_size;
Robert Love42e9a922008-12-09 15:10:17 -0800259
260 new_rdata = new_rport->dd_data;
Joe Eykholtf211fa52009-08-25 14:01:01 -0700261 new_rdata->rport = new_rport;
262 new_rdata->ids = ids;
Robert Love42e9a922008-12-09 15:10:17 -0800263 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;
Joe Eykholtf211fa52009-08-25 14:01:01 -0700269 new_rdata->maxframe_size = rdata->maxframe_size;
270 new_rdata->supported_classes = rdata->supported_classes;
271 kref_init(&new_rdata->kref);
Robert Love42e9a922008-12-09 15:10:17 -0800272 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
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700278 fc_rport_state_enter(new_rdata, RPORT_ST_READY);
Robert Love42e9a922008-12-09 15:10:17 -0800279 } else {
Robert Love74147052009-06-10 15:31:10 -0700280 printk(KERN_WARNING "libfc: Failed to allocate "
281 " memory for rport (%6x)\n", ids.port_id);
Robert Love42e9a922008-12-09 15:10:17 -0800282 event = RPORT_EV_FAILED;
283 }
Joe Eykholtf211fa52009-08-25 14:01:01 -0700284 if (rdata->ids.port_id != FC_FID_DIR_SERV)
Abhijeet Joglekarb4c6f542009-04-21 16:27:04 -0700285 if (rport_ops->event_callback)
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700286 rport_ops->event_callback(lport, rdata,
Abhijeet Joglekarb4c6f542009-04-21 16:27:04 -0700287 RPORT_EV_FAILED);
Joe Eykholtf211fa52009-08-25 14:01:01 -0700288 kref_put(&rdata->kref, lport->tt.rport_destroy);
Robert Love42e9a922008-12-09 15:10:17 -0800289 rdata = new_rport->dd_data;
290 if (rport_ops->event_callback)
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700291 rport_ops->event_callback(lport, rdata, event);
Robert Love42e9a922008-12-09 15:10:17 -0800292 } else if ((event == RPORT_EV_FAILED) ||
293 (event == RPORT_EV_LOGO) ||
294 (event == RPORT_EV_STOP)) {
295 trans_state = rdata->trans_state;
296 mutex_unlock(&rdata->rp_mutex);
297 if (rport_ops->event_callback)
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700298 rport_ops->event_callback(lport, rdata, event);
Joe Eykholt201e5792009-07-29 17:04:54 -0700299 cancel_delayed_work_sync(&rdata->retry_work);
Robert Love42e9a922008-12-09 15:10:17 -0800300 if (trans_state == FC_PORTSTATE_ROGUE)
Joe Eykholtf211fa52009-08-25 14:01:01 -0700301 kref_put(&rdata->kref, lport->tt.rport_destroy);
Abhijeet Joglekar571f8242009-02-27 10:54:41 -0800302 else {
303 port_id = rport->port_id;
Robert Love42e9a922008-12-09 15:10:17 -0800304 fc_remote_port_delete(rport);
Abhijeet Joglekar571f8242009-02-27 10:54:41 -0800305 lport->tt.exch_mgr_reset(lport, 0, port_id);
306 lport->tt.exch_mgr_reset(lport, port_id, 0);
307 }
Robert Love42e9a922008-12-09 15:10:17 -0800308 } else
309 mutex_unlock(&rdata->rp_mutex);
310}
311
312/**
Robert Love34f42a02009-02-27 10:55:45 -0800313 * fc_rport_login() - Start the remote port login state machine
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700314 * @rdata: private remote port
Robert Love42e9a922008-12-09 15:10:17 -0800315 *
316 * Locking Note: Called without the rport lock held. This
317 * function will hold the rport lock, call an _enter_*
318 * function and then unlock the rport.
319 */
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700320int fc_rport_login(struct fc_rport_priv *rdata)
Robert Love42e9a922008-12-09 15:10:17 -0800321{
Robert Love42e9a922008-12-09 15:10:17 -0800322 mutex_lock(&rdata->rp_mutex);
323
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700324 FC_RPORT_DBG(rdata, "Login to port\n");
Robert Love42e9a922008-12-09 15:10:17 -0800325
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700326 fc_rport_enter_plogi(rdata);
Robert Love42e9a922008-12-09 15:10:17 -0800327
328 mutex_unlock(&rdata->rp_mutex);
329
330 return 0;
331}
332
333/**
Joe Eykholt5f7ea3b2009-07-29 17:04:49 -0700334 * fc_rport_enter_delete() - schedule a remote port to be deleted.
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700335 * @rdata: private remote port
Joe Eykholt5f7ea3b2009-07-29 17:04:49 -0700336 * @event: event to report as the reason for deletion
337 *
338 * Locking Note: Called with the rport lock held.
339 *
340 * Allow state change into DELETE only once.
341 *
342 * Call queue_work only if there's no event already pending.
343 * Set the new event so that the old pending event will not occur.
344 * Since we have the mutex, even if fc_rport_work() is already started,
345 * it'll see the new event.
346 */
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700347static void fc_rport_enter_delete(struct fc_rport_priv *rdata,
Joe Eykholt5f7ea3b2009-07-29 17:04:49 -0700348 enum fc_rport_event event)
349{
Joe Eykholt5f7ea3b2009-07-29 17:04:49 -0700350 if (rdata->rp_state == RPORT_ST_DELETE)
351 return;
352
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700353 FC_RPORT_DBG(rdata, "Delete port\n");
Joe Eykholt5f7ea3b2009-07-29 17:04:49 -0700354
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700355 fc_rport_state_enter(rdata, RPORT_ST_DELETE);
Joe Eykholt5f7ea3b2009-07-29 17:04:49 -0700356
357 if (rdata->event == RPORT_EV_NONE)
358 queue_work(rport_event_queue, &rdata->event_work);
359 rdata->event = event;
360}
361
362/**
Robert Love34f42a02009-02-27 10:55:45 -0800363 * fc_rport_logoff() - Logoff and remove an rport
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700364 * @rdata: private remote port
Robert Love42e9a922008-12-09 15:10:17 -0800365 *
366 * Locking Note: Called without the rport lock held. This
367 * function will hold the rport lock, call an _enter_*
368 * function and then unlock the rport.
369 */
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700370int fc_rport_logoff(struct fc_rport_priv *rdata)
Robert Love42e9a922008-12-09 15:10:17 -0800371{
Robert Love42e9a922008-12-09 15:10:17 -0800372 mutex_lock(&rdata->rp_mutex);
373
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700374 FC_RPORT_DBG(rdata, "Remove port\n");
Robert Love42e9a922008-12-09 15:10:17 -0800375
Joe Eykholt14194052009-07-29 17:04:43 -0700376 if (rdata->rp_state == RPORT_ST_DELETE) {
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700377 FC_RPORT_DBG(rdata, "Port in Delete state, not removing\n");
Abhijeet Joglekarb4c6f542009-04-21 16:27:04 -0700378 mutex_unlock(&rdata->rp_mutex);
379 goto out;
380 }
381
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700382 fc_rport_enter_logo(rdata);
Robert Love42e9a922008-12-09 15:10:17 -0800383
384 /*
Joe Eykholt14194052009-07-29 17:04:43 -0700385 * Change the state to Delete so that we discard
Robert Love42e9a922008-12-09 15:10:17 -0800386 * the response.
387 */
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700388 fc_rport_enter_delete(rdata, RPORT_EV_STOP);
Robert Love42e9a922008-12-09 15:10:17 -0800389 mutex_unlock(&rdata->rp_mutex);
390
Abhijeet Joglekarb4c6f542009-04-21 16:27:04 -0700391out:
Robert Love42e9a922008-12-09 15:10:17 -0800392 return 0;
393}
394
395/**
Robert Love34f42a02009-02-27 10:55:45 -0800396 * fc_rport_enter_ready() - The rport is ready
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700397 * @rdata: private remote port
Robert Love42e9a922008-12-09 15:10:17 -0800398 *
399 * Locking Note: The rport lock is expected to be held before calling
400 * this routine.
401 */
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700402static void fc_rport_enter_ready(struct fc_rport_priv *rdata)
Robert Love42e9a922008-12-09 15:10:17 -0800403{
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700404 fc_rport_state_enter(rdata, RPORT_ST_READY);
Robert Love42e9a922008-12-09 15:10:17 -0800405
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700406 FC_RPORT_DBG(rdata, "Port is Ready\n");
Robert Love42e9a922008-12-09 15:10:17 -0800407
Joe Eykholt5f7ea3b2009-07-29 17:04:49 -0700408 if (rdata->event == RPORT_EV_NONE)
409 queue_work(rport_event_queue, &rdata->event_work);
Robert Love42e9a922008-12-09 15:10:17 -0800410 rdata->event = RPORT_EV_CREATED;
Robert Love42e9a922008-12-09 15:10:17 -0800411}
412
413/**
Robert Love34f42a02009-02-27 10:55:45 -0800414 * fc_rport_timeout() - Handler for the retry_work timer.
Joe Eykholtab28f1f2009-08-25 14:00:34 -0700415 * @work: The work struct of the fc_rport_priv
Robert Love42e9a922008-12-09 15:10:17 -0800416 *
417 * Locking Note: Called without the rport lock held. This
418 * function will hold the rport lock, call an _enter_*
419 * function and then unlock the rport.
420 */
421static void fc_rport_timeout(struct work_struct *work)
422{
Joe Eykholtab28f1f2009-08-25 14:00:34 -0700423 struct fc_rport_priv *rdata =
424 container_of(work, struct fc_rport_priv, retry_work.work);
Robert Love42e9a922008-12-09 15:10:17 -0800425
426 mutex_lock(&rdata->rp_mutex);
427
428 switch (rdata->rp_state) {
429 case RPORT_ST_PLOGI:
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700430 fc_rport_enter_plogi(rdata);
Robert Love42e9a922008-12-09 15:10:17 -0800431 break;
432 case RPORT_ST_PRLI:
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700433 fc_rport_enter_prli(rdata);
Robert Love42e9a922008-12-09 15:10:17 -0800434 break;
435 case RPORT_ST_RTV:
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700436 fc_rport_enter_rtv(rdata);
Robert Love42e9a922008-12-09 15:10:17 -0800437 break;
438 case RPORT_ST_LOGO:
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700439 fc_rport_enter_logo(rdata);
Robert Love42e9a922008-12-09 15:10:17 -0800440 break;
441 case RPORT_ST_READY:
442 case RPORT_ST_INIT:
Joe Eykholt14194052009-07-29 17:04:43 -0700443 case RPORT_ST_DELETE:
Robert Love42e9a922008-12-09 15:10:17 -0800444 break;
445 }
446
447 mutex_unlock(&rdata->rp_mutex);
Robert Love42e9a922008-12-09 15:10:17 -0800448}
449
450/**
Robert Love34f42a02009-02-27 10:55:45 -0800451 * fc_rport_error() - Error handler, called once retries have been exhausted
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700452 * @rdata: private remote port
Robert Love42e9a922008-12-09 15:10:17 -0800453 * @fp: The frame pointer
454 *
Robert Love42e9a922008-12-09 15:10:17 -0800455 * Locking Note: The rport lock is expected to be held before
456 * calling this routine
457 */
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700458static void fc_rport_error(struct fc_rport_priv *rdata, struct fc_frame *fp)
Robert Love42e9a922008-12-09 15:10:17 -0800459{
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700460 FC_RPORT_DBG(rdata, "Error %ld in state %s, retries %d\n",
461 PTR_ERR(fp), fc_rport_state(rdata), rdata->retries);
Robert Love42e9a922008-12-09 15:10:17 -0800462
Chris Leech6755db12009-02-27 10:55:02 -0800463 switch (rdata->rp_state) {
464 case RPORT_ST_PLOGI:
465 case RPORT_ST_PRLI:
466 case RPORT_ST_LOGO:
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700467 fc_rport_enter_delete(rdata, RPORT_EV_FAILED);
Chris Leech6755db12009-02-27 10:55:02 -0800468 break;
469 case RPORT_ST_RTV:
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700470 fc_rport_enter_ready(rdata);
Chris Leech6755db12009-02-27 10:55:02 -0800471 break;
Joe Eykholt14194052009-07-29 17:04:43 -0700472 case RPORT_ST_DELETE:
Chris Leech6755db12009-02-27 10:55:02 -0800473 case RPORT_ST_READY:
474 case RPORT_ST_INIT:
475 break;
Robert Love42e9a922008-12-09 15:10:17 -0800476 }
477}
478
479/**
Robert Love34f42a02009-02-27 10:55:45 -0800480 * fc_rport_error_retry() - Error handler when retries are desired
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700481 * @rdata: private remote port data
Chris Leech6755db12009-02-27 10:55:02 -0800482 * @fp: The frame pointer
483 *
484 * If the error was an exchange timeout retry immediately,
485 * otherwise wait for E_D_TOV.
486 *
487 * Locking Note: The rport lock is expected to be held before
488 * calling this routine
489 */
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700490static void fc_rport_error_retry(struct fc_rport_priv *rdata,
491 struct fc_frame *fp)
Chris Leech6755db12009-02-27 10:55:02 -0800492{
Chris Leech6755db12009-02-27 10:55:02 -0800493 unsigned long delay = FC_DEF_E_D_TOV;
494
495 /* make sure this isn't an FC_EX_CLOSED error, never retry those */
496 if (PTR_ERR(fp) == -FC_EX_CLOSED)
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700497 return fc_rport_error(rdata, fp);
Chris Leech6755db12009-02-27 10:55:02 -0800498
Abhijeet Joglekara3666952009-05-01 10:01:26 -0700499 if (rdata->retries < rdata->local_port->max_rport_retry_count) {
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700500 FC_RPORT_DBG(rdata, "Error %ld in state %s, retrying\n",
501 PTR_ERR(fp), fc_rport_state(rdata));
Chris Leech6755db12009-02-27 10:55:02 -0800502 rdata->retries++;
503 /* no additional delay on exchange timeouts */
504 if (PTR_ERR(fp) == -FC_EX_TIMEOUT)
505 delay = 0;
Chris Leech6755db12009-02-27 10:55:02 -0800506 schedule_delayed_work(&rdata->retry_work, delay);
507 return;
508 }
509
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700510 return fc_rport_error(rdata, fp);
Chris Leech6755db12009-02-27 10:55:02 -0800511}
512
513/**
Robert Love34f42a02009-02-27 10:55:45 -0800514 * fc_rport_plogi_recv_resp() - Handle incoming ELS PLOGI response
Robert Love42e9a922008-12-09 15:10:17 -0800515 * @sp: current sequence in the PLOGI exchange
516 * @fp: response frame
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700517 * @rdata_arg: private remote port data
Robert Love42e9a922008-12-09 15:10:17 -0800518 *
519 * Locking Note: This function will be called without the rport lock
520 * held, but it will lock, call an _enter_* function or fc_rport_error
521 * and then unlock the rport.
522 */
523static void fc_rport_plogi_resp(struct fc_seq *sp, struct fc_frame *fp,
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700524 void *rdata_arg)
Robert Love42e9a922008-12-09 15:10:17 -0800525{
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700526 struct fc_rport_priv *rdata = rdata_arg;
Robert Love42e9a922008-12-09 15:10:17 -0800527 struct fc_lport *lport = rdata->local_port;
Robert Lovea29e7642009-04-21 16:27:41 -0700528 struct fc_els_flogi *plp = NULL;
Robert Love42e9a922008-12-09 15:10:17 -0800529 unsigned int tov;
530 u16 csp_seq;
531 u16 cssp_seq;
532 u8 op;
533
534 mutex_lock(&rdata->rp_mutex);
535
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700536 FC_RPORT_DBG(rdata, "Received a PLOGI response\n");
Robert Love42e9a922008-12-09 15:10:17 -0800537
538 if (rdata->rp_state != RPORT_ST_PLOGI) {
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700539 FC_RPORT_DBG(rdata, "Received a PLOGI response, but in state "
540 "%s\n", fc_rport_state(rdata));
Abhijeet Joglekar76f68042009-04-21 16:26:58 -0700541 if (IS_ERR(fp))
542 goto err;
Robert Love42e9a922008-12-09 15:10:17 -0800543 goto out;
544 }
545
Abhijeet Joglekar76f68042009-04-21 16:26:58 -0700546 if (IS_ERR(fp)) {
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700547 fc_rport_error_retry(rdata, fp);
Abhijeet Joglekar76f68042009-04-21 16:26:58 -0700548 goto err;
549 }
550
Robert Love42e9a922008-12-09 15:10:17 -0800551 op = fc_frame_payload_op(fp);
552 if (op == ELS_LS_ACC &&
553 (plp = fc_frame_payload_get(fp, sizeof(*plp))) != NULL) {
Joe Eykholtf211fa52009-08-25 14:01:01 -0700554 rdata->ids.port_name = get_unaligned_be64(&plp->fl_wwpn);
555 rdata->ids.node_name = get_unaligned_be64(&plp->fl_wwnn);
Robert Love42e9a922008-12-09 15:10:17 -0800556
557 tov = ntohl(plp->fl_csp.sp_e_d_tov);
558 if (ntohs(plp->fl_csp.sp_features) & FC_SP_FT_EDTR)
559 tov /= 1000;
560 if (tov > rdata->e_d_tov)
561 rdata->e_d_tov = tov;
562 csp_seq = ntohs(plp->fl_csp.sp_tot_seq);
563 cssp_seq = ntohs(plp->fl_cssp[3 - 1].cp_con_seq);
564 if (cssp_seq < csp_seq)
565 csp_seq = cssp_seq;
566 rdata->max_seq = csp_seq;
Joe Eykholtf211fa52009-08-25 14:01:01 -0700567 rdata->maxframe_size = fc_plogi_get_maxframe(plp, lport->mfs);
Robert Love42e9a922008-12-09 15:10:17 -0800568
569 /*
570 * If the rport is one of the well known addresses
571 * we skip PRLI and RTV and go straight to READY.
572 */
Joe Eykholtf211fa52009-08-25 14:01:01 -0700573 if (rdata->ids.port_id >= FC_FID_DOM_MGR)
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700574 fc_rport_enter_ready(rdata);
Robert Love42e9a922008-12-09 15:10:17 -0800575 else
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700576 fc_rport_enter_prli(rdata);
Robert Love42e9a922008-12-09 15:10:17 -0800577 } else
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700578 fc_rport_error_retry(rdata, fp);
Robert Love42e9a922008-12-09 15:10:17 -0800579
580out:
581 fc_frame_free(fp);
582err:
583 mutex_unlock(&rdata->rp_mutex);
Joe Eykholtf211fa52009-08-25 14:01:01 -0700584 kref_put(&rdata->kref, rdata->local_port->tt.rport_destroy);
Robert Love42e9a922008-12-09 15:10:17 -0800585}
586
587/**
Robert Love34f42a02009-02-27 10:55:45 -0800588 * fc_rport_enter_plogi() - Send Port Login (PLOGI) request to peer
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700589 * @rdata: private remote port data
Robert Love42e9a922008-12-09 15:10:17 -0800590 *
591 * Locking Note: The rport lock is expected to be held before calling
592 * this routine.
593 */
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700594static void fc_rport_enter_plogi(struct fc_rport_priv *rdata)
Robert Love42e9a922008-12-09 15:10:17 -0800595{
Robert Love42e9a922008-12-09 15:10:17 -0800596 struct fc_lport *lport = rdata->local_port;
597 struct fc_frame *fp;
598
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700599 FC_RPORT_DBG(rdata, "Port entered PLOGI state from %s state\n",
600 fc_rport_state(rdata));
Robert Love42e9a922008-12-09 15:10:17 -0800601
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700602 fc_rport_state_enter(rdata, RPORT_ST_PLOGI);
Robert Love42e9a922008-12-09 15:10:17 -0800603
Joe Eykholtf211fa52009-08-25 14:01:01 -0700604 rdata->maxframe_size = FC_MIN_MAX_PAYLOAD;
Robert Love42e9a922008-12-09 15:10:17 -0800605 fp = fc_frame_alloc(lport, sizeof(struct fc_els_flogi));
606 if (!fp) {
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700607 fc_rport_error_retry(rdata, fp);
Robert Love42e9a922008-12-09 15:10:17 -0800608 return;
609 }
610 rdata->e_d_tov = lport->e_d_tov;
611
Joe Eykholtf211fa52009-08-25 14:01:01 -0700612 if (!lport->tt.elsct_send(lport, rdata->ids.port_id, fp, ELS_PLOGI,
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700613 fc_rport_plogi_resp, rdata, lport->e_d_tov))
614 fc_rport_error_retry(rdata, fp);
Robert Love42e9a922008-12-09 15:10:17 -0800615 else
Joe Eykholtf211fa52009-08-25 14:01:01 -0700616 kref_get(&rdata->kref);
Robert Love42e9a922008-12-09 15:10:17 -0800617}
618
619/**
Robert Love34f42a02009-02-27 10:55:45 -0800620 * fc_rport_prli_resp() - Process Login (PRLI) response handler
Robert Love42e9a922008-12-09 15:10:17 -0800621 * @sp: current sequence in the PRLI exchange
622 * @fp: response frame
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700623 * @rdata_arg: private remote port data
Robert Love42e9a922008-12-09 15:10:17 -0800624 *
625 * Locking Note: This function will be called without the rport lock
626 * held, but it will lock, call an _enter_* function or fc_rport_error
627 * and then unlock the rport.
628 */
629static void fc_rport_prli_resp(struct fc_seq *sp, struct fc_frame *fp,
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700630 void *rdata_arg)
Robert Love42e9a922008-12-09 15:10:17 -0800631{
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700632 struct fc_rport_priv *rdata = rdata_arg;
Robert Love42e9a922008-12-09 15:10:17 -0800633 struct {
634 struct fc_els_prli prli;
635 struct fc_els_spp spp;
636 } *pp;
637 u32 roles = FC_RPORT_ROLE_UNKNOWN;
638 u32 fcp_parm = 0;
639 u8 op;
640
641 mutex_lock(&rdata->rp_mutex);
642
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700643 FC_RPORT_DBG(rdata, "Received a PRLI response\n");
Robert Love42e9a922008-12-09 15:10:17 -0800644
645 if (rdata->rp_state != RPORT_ST_PRLI) {
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700646 FC_RPORT_DBG(rdata, "Received a PRLI response, but in state "
647 "%s\n", fc_rport_state(rdata));
Abhijeet Joglekar76f68042009-04-21 16:26:58 -0700648 if (IS_ERR(fp))
649 goto err;
Robert Love42e9a922008-12-09 15:10:17 -0800650 goto out;
651 }
652
Abhijeet Joglekar76f68042009-04-21 16:26:58 -0700653 if (IS_ERR(fp)) {
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700654 fc_rport_error_retry(rdata, fp);
Abhijeet Joglekar76f68042009-04-21 16:26:58 -0700655 goto err;
656 }
657
Robert Love42e9a922008-12-09 15:10:17 -0800658 op = fc_frame_payload_op(fp);
659 if (op == ELS_LS_ACC) {
660 pp = fc_frame_payload_get(fp, sizeof(*pp));
661 if (pp && pp->prli.prli_spp_len >= sizeof(pp->spp)) {
662 fcp_parm = ntohl(pp->spp.spp_params);
663 if (fcp_parm & FCP_SPPF_RETRY)
664 rdata->flags |= FC_RP_FLAGS_RETRY;
665 }
666
Joe Eykholtf211fa52009-08-25 14:01:01 -0700667 rdata->supported_classes = FC_COS_CLASS3;
Robert Love42e9a922008-12-09 15:10:17 -0800668 if (fcp_parm & FCP_SPPF_INIT_FCN)
669 roles |= FC_RPORT_ROLE_FCP_INITIATOR;
670 if (fcp_parm & FCP_SPPF_TARG_FCN)
671 roles |= FC_RPORT_ROLE_FCP_TARGET;
672
Joe Eykholtf211fa52009-08-25 14:01:01 -0700673 rdata->ids.roles = roles;
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700674 fc_rport_enter_rtv(rdata);
Robert Love42e9a922008-12-09 15:10:17 -0800675
676 } else {
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700677 FC_RPORT_DBG(rdata, "Bad ELS response for PRLI command\n");
678 fc_rport_enter_delete(rdata, RPORT_EV_FAILED);
Robert Love42e9a922008-12-09 15:10:17 -0800679 }
680
681out:
682 fc_frame_free(fp);
683err:
684 mutex_unlock(&rdata->rp_mutex);
Joe Eykholtf211fa52009-08-25 14:01:01 -0700685 kref_put(&rdata->kref, rdata->local_port->tt.rport_destroy);
Robert Love42e9a922008-12-09 15:10:17 -0800686}
687
688/**
Robert Love34f42a02009-02-27 10:55:45 -0800689 * fc_rport_logo_resp() - Logout (LOGO) response handler
Robert Love42e9a922008-12-09 15:10:17 -0800690 * @sp: current sequence in the LOGO exchange
691 * @fp: response frame
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700692 * @rdata_arg: private remote port data
Robert Love42e9a922008-12-09 15:10:17 -0800693 *
694 * Locking Note: This function will be called without the rport lock
695 * held, but it will lock, call an _enter_* function or fc_rport_error
696 * and then unlock the rport.
697 */
698static void fc_rport_logo_resp(struct fc_seq *sp, struct fc_frame *fp,
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700699 void *rdata_arg)
Robert Love42e9a922008-12-09 15:10:17 -0800700{
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700701 struct fc_rport_priv *rdata = rdata_arg;
Robert Love42e9a922008-12-09 15:10:17 -0800702 u8 op;
703
704 mutex_lock(&rdata->rp_mutex);
705
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700706 FC_RPORT_DBG(rdata, "Received a LOGO response\n");
Robert Love42e9a922008-12-09 15:10:17 -0800707
Robert Love42e9a922008-12-09 15:10:17 -0800708 if (rdata->rp_state != RPORT_ST_LOGO) {
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700709 FC_RPORT_DBG(rdata, "Received a LOGO response, but in state "
710 "%s\n", fc_rport_state(rdata));
Abhijeet Joglekar76f68042009-04-21 16:26:58 -0700711 if (IS_ERR(fp))
712 goto err;
Robert Love42e9a922008-12-09 15:10:17 -0800713 goto out;
714 }
715
Abhijeet Joglekar76f68042009-04-21 16:26:58 -0700716 if (IS_ERR(fp)) {
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700717 fc_rport_error_retry(rdata, fp);
Abhijeet Joglekar76f68042009-04-21 16:26:58 -0700718 goto err;
719 }
720
Robert Love42e9a922008-12-09 15:10:17 -0800721 op = fc_frame_payload_op(fp);
722 if (op == ELS_LS_ACC) {
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700723 fc_rport_enter_rtv(rdata);
Robert Love42e9a922008-12-09 15:10:17 -0800724 } else {
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700725 FC_RPORT_DBG(rdata, "Bad ELS response for LOGO command\n");
726 fc_rport_enter_delete(rdata, RPORT_EV_LOGO);
Robert Love42e9a922008-12-09 15:10:17 -0800727 }
728
729out:
730 fc_frame_free(fp);
731err:
732 mutex_unlock(&rdata->rp_mutex);
Joe Eykholtf211fa52009-08-25 14:01:01 -0700733 kref_put(&rdata->kref, rdata->local_port->tt.rport_destroy);
Robert Love42e9a922008-12-09 15:10:17 -0800734}
735
736/**
Robert Love34f42a02009-02-27 10:55:45 -0800737 * fc_rport_enter_prli() - Send Process Login (PRLI) request to peer
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700738 * @rdata: private remote port data
Robert Love42e9a922008-12-09 15:10:17 -0800739 *
740 * Locking Note: The rport lock is expected to be held before calling
741 * this routine.
742 */
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700743static void fc_rport_enter_prli(struct fc_rport_priv *rdata)
Robert Love42e9a922008-12-09 15:10:17 -0800744{
Robert Love42e9a922008-12-09 15:10:17 -0800745 struct fc_lport *lport = rdata->local_port;
746 struct {
747 struct fc_els_prli prli;
748 struct fc_els_spp spp;
749 } *pp;
750 struct fc_frame *fp;
751
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700752 FC_RPORT_DBG(rdata, "Port entered PRLI state from %s state\n",
753 fc_rport_state(rdata));
Robert Love42e9a922008-12-09 15:10:17 -0800754
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700755 fc_rport_state_enter(rdata, RPORT_ST_PRLI);
Robert Love42e9a922008-12-09 15:10:17 -0800756
757 fp = fc_frame_alloc(lport, sizeof(*pp));
758 if (!fp) {
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700759 fc_rport_error_retry(rdata, fp);
Robert Love42e9a922008-12-09 15:10:17 -0800760 return;
761 }
762
Joe Eykholtf211fa52009-08-25 14:01:01 -0700763 if (!lport->tt.elsct_send(lport, rdata->ids.port_id, fp, ELS_PRLI,
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700764 fc_rport_prli_resp, rdata, lport->e_d_tov))
765 fc_rport_error_retry(rdata, fp);
Robert Love42e9a922008-12-09 15:10:17 -0800766 else
Joe Eykholtf211fa52009-08-25 14:01:01 -0700767 kref_get(&rdata->kref);
Robert Love42e9a922008-12-09 15:10:17 -0800768}
769
770/**
Robert Love34f42a02009-02-27 10:55:45 -0800771 * fc_rport_els_rtv_resp() - Request Timeout Value response handler
Robert Love42e9a922008-12-09 15:10:17 -0800772 * @sp: current sequence in the RTV exchange
773 * @fp: response frame
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700774 * @rdata_arg: private remote port data
Robert Love42e9a922008-12-09 15:10:17 -0800775 *
776 * Many targets don't seem to support this.
777 *
778 * Locking Note: This function will be called without the rport lock
779 * held, but it will lock, call an _enter_* function or fc_rport_error
780 * and then unlock the rport.
781 */
782static void fc_rport_rtv_resp(struct fc_seq *sp, struct fc_frame *fp,
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700783 void *rdata_arg)
Robert Love42e9a922008-12-09 15:10:17 -0800784{
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700785 struct fc_rport_priv *rdata = rdata_arg;
Robert Love42e9a922008-12-09 15:10:17 -0800786 u8 op;
787
788 mutex_lock(&rdata->rp_mutex);
789
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700790 FC_RPORT_DBG(rdata, "Received a RTV response\n");
Robert Love42e9a922008-12-09 15:10:17 -0800791
792 if (rdata->rp_state != RPORT_ST_RTV) {
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700793 FC_RPORT_DBG(rdata, "Received a RTV response, but in state "
794 "%s\n", fc_rport_state(rdata));
Abhijeet Joglekar76f68042009-04-21 16:26:58 -0700795 if (IS_ERR(fp))
796 goto err;
Robert Love42e9a922008-12-09 15:10:17 -0800797 goto out;
798 }
799
Abhijeet Joglekar76f68042009-04-21 16:26:58 -0700800 if (IS_ERR(fp)) {
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700801 fc_rport_error(rdata, fp);
Abhijeet Joglekar76f68042009-04-21 16:26:58 -0700802 goto err;
803 }
804
Robert Love42e9a922008-12-09 15:10:17 -0800805 op = fc_frame_payload_op(fp);
806 if (op == ELS_LS_ACC) {
807 struct fc_els_rtv_acc *rtv;
808 u32 toq;
809 u32 tov;
810
811 rtv = fc_frame_payload_get(fp, sizeof(*rtv));
812 if (rtv) {
813 toq = ntohl(rtv->rtv_toq);
814 tov = ntohl(rtv->rtv_r_a_tov);
815 if (tov == 0)
816 tov = 1;
817 rdata->r_a_tov = tov;
818 tov = ntohl(rtv->rtv_e_d_tov);
819 if (toq & FC_ELS_RTV_EDRES)
820 tov /= 1000000;
821 if (tov == 0)
822 tov = 1;
823 rdata->e_d_tov = tov;
824 }
825 }
826
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700827 fc_rport_enter_ready(rdata);
Robert Love42e9a922008-12-09 15:10:17 -0800828
829out:
830 fc_frame_free(fp);
831err:
832 mutex_unlock(&rdata->rp_mutex);
Joe Eykholtf211fa52009-08-25 14:01:01 -0700833 kref_put(&rdata->kref, rdata->local_port->tt.rport_destroy);
Robert Love42e9a922008-12-09 15:10:17 -0800834}
835
836/**
Robert Love34f42a02009-02-27 10:55:45 -0800837 * fc_rport_enter_rtv() - Send Request Timeout Value (RTV) request to peer
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700838 * @rdata: private remote port data
Robert Love42e9a922008-12-09 15:10:17 -0800839 *
840 * Locking Note: The rport lock is expected to be held before calling
841 * this routine.
842 */
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700843static void fc_rport_enter_rtv(struct fc_rport_priv *rdata)
Robert Love42e9a922008-12-09 15:10:17 -0800844{
845 struct fc_frame *fp;
Robert Love42e9a922008-12-09 15:10:17 -0800846 struct fc_lport *lport = rdata->local_port;
847
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700848 FC_RPORT_DBG(rdata, "Port entered RTV state from %s state\n",
849 fc_rport_state(rdata));
Robert Love42e9a922008-12-09 15:10:17 -0800850
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700851 fc_rport_state_enter(rdata, RPORT_ST_RTV);
Robert Love42e9a922008-12-09 15:10:17 -0800852
853 fp = fc_frame_alloc(lport, sizeof(struct fc_els_rtv));
854 if (!fp) {
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700855 fc_rport_error_retry(rdata, fp);
Robert Love42e9a922008-12-09 15:10:17 -0800856 return;
857 }
858
Joe Eykholtf211fa52009-08-25 14:01:01 -0700859 if (!lport->tt.elsct_send(lport, rdata->ids.port_id, fp, ELS_RTV,
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700860 fc_rport_rtv_resp, rdata, lport->e_d_tov))
861 fc_rport_error_retry(rdata, fp);
Robert Love42e9a922008-12-09 15:10:17 -0800862 else
Joe Eykholtf211fa52009-08-25 14:01:01 -0700863 kref_get(&rdata->kref);
Robert Love42e9a922008-12-09 15:10:17 -0800864}
865
866/**
Robert Love34f42a02009-02-27 10:55:45 -0800867 * fc_rport_enter_logo() - Send Logout (LOGO) request to peer
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700868 * @rdata: private remote port data
Robert Love42e9a922008-12-09 15:10:17 -0800869 *
870 * Locking Note: The rport lock is expected to be held before calling
871 * this routine.
872 */
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700873static void fc_rport_enter_logo(struct fc_rport_priv *rdata)
Robert Love42e9a922008-12-09 15:10:17 -0800874{
Robert Love42e9a922008-12-09 15:10:17 -0800875 struct fc_lport *lport = rdata->local_port;
876 struct fc_frame *fp;
877
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700878 FC_RPORT_DBG(rdata, "Port entered LOGO state from %s state\n",
879 fc_rport_state(rdata));
Robert Love42e9a922008-12-09 15:10:17 -0800880
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700881 fc_rport_state_enter(rdata, RPORT_ST_LOGO);
Robert Love42e9a922008-12-09 15:10:17 -0800882
883 fp = fc_frame_alloc(lport, sizeof(struct fc_els_logo));
884 if (!fp) {
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700885 fc_rport_error_retry(rdata, fp);
Robert Love42e9a922008-12-09 15:10:17 -0800886 return;
887 }
888
Joe Eykholtf211fa52009-08-25 14:01:01 -0700889 if (!lport->tt.elsct_send(lport, rdata->ids.port_id, fp, ELS_LOGO,
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700890 fc_rport_logo_resp, rdata, lport->e_d_tov))
891 fc_rport_error_retry(rdata, fp);
Robert Love42e9a922008-12-09 15:10:17 -0800892 else
Joe Eykholtf211fa52009-08-25 14:01:01 -0700893 kref_get(&rdata->kref);
Robert Love42e9a922008-12-09 15:10:17 -0800894}
895
896
897/**
Robert Love34f42a02009-02-27 10:55:45 -0800898 * fc_rport_recv_req() - Receive a request from a rport
Robert Love42e9a922008-12-09 15:10:17 -0800899 * @sp: current sequence in the PLOGI exchange
900 * @fp: response frame
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700901 * @rdata_arg: private remote port data
Robert Love42e9a922008-12-09 15:10:17 -0800902 *
903 * Locking Note: Called without the rport lock held. This
904 * function will hold the rport lock, call an _enter_*
905 * function and then unlock the rport.
906 */
907void fc_rport_recv_req(struct fc_seq *sp, struct fc_frame *fp,
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700908 struct fc_rport_priv *rdata)
Robert Love42e9a922008-12-09 15:10:17 -0800909{
Robert Love42e9a922008-12-09 15:10:17 -0800910 struct fc_lport *lport = rdata->local_port;
911
912 struct fc_frame_header *fh;
913 struct fc_seq_els_data els_data;
914 u8 op;
915
916 mutex_lock(&rdata->rp_mutex);
917
918 els_data.fp = NULL;
919 els_data.explan = ELS_EXPL_NONE;
920 els_data.reason = ELS_RJT_NONE;
921
922 fh = fc_frame_header_get(fp);
923
924 if (fh->fh_r_ctl == FC_RCTL_ELS_REQ && fh->fh_type == FC_TYPE_ELS) {
925 op = fc_frame_payload_op(fp);
926 switch (op) {
927 case ELS_PLOGI:
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700928 fc_rport_recv_plogi_req(rdata, sp, fp);
Robert Love42e9a922008-12-09 15:10:17 -0800929 break;
930 case ELS_PRLI:
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700931 fc_rport_recv_prli_req(rdata, sp, fp);
Robert Love42e9a922008-12-09 15:10:17 -0800932 break;
933 case ELS_PRLO:
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700934 fc_rport_recv_prlo_req(rdata, sp, fp);
Robert Love42e9a922008-12-09 15:10:17 -0800935 break;
936 case ELS_LOGO:
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700937 fc_rport_recv_logo_req(rdata, sp, fp);
Robert Love42e9a922008-12-09 15:10:17 -0800938 break;
939 case ELS_RRQ:
940 els_data.fp = fp;
941 lport->tt.seq_els_rsp_send(sp, ELS_RRQ, &els_data);
942 break;
943 case ELS_REC:
944 els_data.fp = fp;
945 lport->tt.seq_els_rsp_send(sp, ELS_REC, &els_data);
946 break;
947 default:
948 els_data.reason = ELS_RJT_UNSUP;
949 lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &els_data);
950 break;
951 }
952 }
953
954 mutex_unlock(&rdata->rp_mutex);
955}
956
957/**
Robert Love34f42a02009-02-27 10:55:45 -0800958 * fc_rport_recv_plogi_req() - Handle incoming Port Login (PLOGI) request
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700959 * @rdata: private remote port data
Robert Love42e9a922008-12-09 15:10:17 -0800960 * @sp: current sequence in the PLOGI exchange
961 * @fp: PLOGI request frame
962 *
963 * Locking Note: The rport lock is exected to be held before calling
964 * this function.
965 */
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700966static void fc_rport_recv_plogi_req(struct fc_rport_priv *rdata,
Robert Love42e9a922008-12-09 15:10:17 -0800967 struct fc_seq *sp, struct fc_frame *rx_fp)
968{
Robert Love42e9a922008-12-09 15:10:17 -0800969 struct fc_lport *lport = rdata->local_port;
970 struct fc_frame *fp = rx_fp;
971 struct fc_exch *ep;
972 struct fc_frame_header *fh;
973 struct fc_els_flogi *pl;
974 struct fc_seq_els_data rjt_data;
975 u32 sid;
976 u64 wwpn;
977 u64 wwnn;
978 enum fc_els_rjt_reason reject = 0;
979 u32 f_ctl;
980 rjt_data.fp = NULL;
981
982 fh = fc_frame_header_get(fp);
983
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700984 FC_RPORT_DBG(rdata, "Received PLOGI request while in state %s\n",
985 fc_rport_state(rdata));
Robert Love42e9a922008-12-09 15:10:17 -0800986
987 sid = ntoh24(fh->fh_s_id);
988 pl = fc_frame_payload_get(fp, sizeof(*pl));
989 if (!pl) {
Joe Eykholt9fb9d322009-08-25 14:00:50 -0700990 FC_RPORT_DBG(rdata, "Received PLOGI too short\n");
Robert Love42e9a922008-12-09 15:10:17 -0800991 WARN_ON(1);
992 /* XXX TBD: send reject? */
993 fc_frame_free(fp);
994 return;
995 }
996 wwpn = get_unaligned_be64(&pl->fl_wwpn);
997 wwnn = get_unaligned_be64(&pl->fl_wwnn);
998
999 /*
1000 * If the session was just created, possibly due to the incoming PLOGI,
1001 * set the state appropriately and accept the PLOGI.
1002 *
1003 * If we had also sent a PLOGI, and if the received PLOGI is from a
1004 * higher WWPN, we accept it, otherwise an LS_RJT is sent with reason
1005 * "command already in progress".
1006 *
1007 * XXX TBD: If the session was ready before, the PLOGI should result in
1008 * all outstanding exchanges being reset.
1009 */
1010 switch (rdata->rp_state) {
1011 case RPORT_ST_INIT:
Joe Eykholt9fb9d322009-08-25 14:00:50 -07001012 FC_RPORT_DBG(rdata, "Received PLOGI, wwpn %llx state INIT "
Robert Love74147052009-06-10 15:31:10 -07001013 "- reject\n", (unsigned long long)wwpn);
Robert Love42e9a922008-12-09 15:10:17 -08001014 reject = ELS_RJT_UNSUP;
1015 break;
1016 case RPORT_ST_PLOGI:
Joe Eykholt9fb9d322009-08-25 14:00:50 -07001017 FC_RPORT_DBG(rdata, "Received PLOGI in PLOGI state %d\n",
Robert Love74147052009-06-10 15:31:10 -07001018 rdata->rp_state);
Robert Love42e9a922008-12-09 15:10:17 -08001019 if (wwpn < lport->wwpn)
1020 reject = ELS_RJT_INPROG;
1021 break;
1022 case RPORT_ST_PRLI:
1023 case RPORT_ST_READY:
Joe Eykholt9fb9d322009-08-25 14:00:50 -07001024 FC_RPORT_DBG(rdata, "Received PLOGI in logged-in state %d "
Robert Love74147052009-06-10 15:31:10 -07001025 "- ignored for now\n", rdata->rp_state);
Robert Love42e9a922008-12-09 15:10:17 -08001026 /* XXX TBD - should reset */
1027 break;
Joe Eykholt14194052009-07-29 17:04:43 -07001028 case RPORT_ST_DELETE:
Robert Love42e9a922008-12-09 15:10:17 -08001029 default:
Joe Eykholt9fb9d322009-08-25 14:00:50 -07001030 FC_RPORT_DBG(rdata, "Received PLOGI in unexpected "
Robert Love74147052009-06-10 15:31:10 -07001031 "state %d\n", rdata->rp_state);
Abhijeet Joglekarb4c6f542009-04-21 16:27:04 -07001032 fc_frame_free(fp);
1033 return;
Robert Love42e9a922008-12-09 15:10:17 -08001034 break;
1035 }
1036
1037 if (reject) {
1038 rjt_data.reason = reject;
1039 rjt_data.explan = ELS_EXPL_NONE;
1040 lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &rjt_data);
1041 fc_frame_free(fp);
1042 } else {
1043 fp = fc_frame_alloc(lport, sizeof(*pl));
1044 if (fp == NULL) {
1045 fp = rx_fp;
1046 rjt_data.reason = ELS_RJT_UNAB;
1047 rjt_data.explan = ELS_EXPL_NONE;
1048 lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &rjt_data);
1049 fc_frame_free(fp);
1050 } else {
1051 sp = lport->tt.seq_start_next(sp);
1052 WARN_ON(!sp);
Joe Eykholtf211fa52009-08-25 14:01:01 -07001053 rdata->ids.port_name = wwpn;
1054 rdata->ids.node_name = wwnn;
Robert Love42e9a922008-12-09 15:10:17 -08001055
1056 /*
1057 * Get session payload size from incoming PLOGI.
1058 */
Joe Eykholtf211fa52009-08-25 14:01:01 -07001059 rdata->maxframe_size =
Robert Love42e9a922008-12-09 15:10:17 -08001060 fc_plogi_get_maxframe(pl, lport->mfs);
1061 fc_frame_free(rx_fp);
1062 fc_plogi_fill(lport, fp, ELS_LS_ACC);
1063
1064 /*
1065 * Send LS_ACC. If this fails,
1066 * the originator should retry.
1067 */
1068 f_ctl = FC_FC_EX_CTX | FC_FC_LAST_SEQ;
1069 f_ctl |= FC_FC_END_SEQ | FC_FC_SEQ_INIT;
1070 ep = fc_seq_exch(sp);
1071 fc_fill_fc_hdr(fp, FC_RCTL_ELS_REP, ep->did, ep->sid,
1072 FC_TYPE_ELS, f_ctl, 0);
1073 lport->tt.seq_send(lport, sp, fp);
1074 if (rdata->rp_state == RPORT_ST_PLOGI)
Joe Eykholt9fb9d322009-08-25 14:00:50 -07001075 fc_rport_enter_prli(rdata);
Robert Love42e9a922008-12-09 15:10:17 -08001076 }
1077 }
1078}
1079
1080/**
Robert Love34f42a02009-02-27 10:55:45 -08001081 * fc_rport_recv_prli_req() - Handle incoming Process Login (PRLI) request
Joe Eykholt9fb9d322009-08-25 14:00:50 -07001082 * @rdata: private remote port data
Robert Love42e9a922008-12-09 15:10:17 -08001083 * @sp: current sequence in the PRLI exchange
1084 * @fp: PRLI request frame
1085 *
1086 * Locking Note: The rport lock is exected to be held before calling
1087 * this function.
1088 */
Joe Eykholt9fb9d322009-08-25 14:00:50 -07001089static void fc_rport_recv_prli_req(struct fc_rport_priv *rdata,
Robert Love42e9a922008-12-09 15:10:17 -08001090 struct fc_seq *sp, struct fc_frame *rx_fp)
1091{
Robert Love42e9a922008-12-09 15:10:17 -08001092 struct fc_lport *lport = rdata->local_port;
1093 struct fc_exch *ep;
1094 struct fc_frame *fp;
1095 struct fc_frame_header *fh;
1096 struct {
1097 struct fc_els_prli prli;
1098 struct fc_els_spp spp;
1099 } *pp;
1100 struct fc_els_spp *rspp; /* request service param page */
1101 struct fc_els_spp *spp; /* response spp */
1102 unsigned int len;
1103 unsigned int plen;
1104 enum fc_els_rjt_reason reason = ELS_RJT_UNAB;
1105 enum fc_els_rjt_explan explan = ELS_EXPL_NONE;
1106 enum fc_els_spp_resp resp;
1107 struct fc_seq_els_data rjt_data;
1108 u32 f_ctl;
1109 u32 fcp_parm;
1110 u32 roles = FC_RPORT_ROLE_UNKNOWN;
1111 rjt_data.fp = NULL;
1112
1113 fh = fc_frame_header_get(rx_fp);
1114
Joe Eykholt9fb9d322009-08-25 14:00:50 -07001115 FC_RPORT_DBG(rdata, "Received PRLI request while in state %s\n",
1116 fc_rport_state(rdata));
Robert Love42e9a922008-12-09 15:10:17 -08001117
1118 switch (rdata->rp_state) {
1119 case RPORT_ST_PRLI:
1120 case RPORT_ST_READY:
1121 reason = ELS_RJT_NONE;
1122 break;
1123 default:
Abhijeet Joglekarb4c6f542009-04-21 16:27:04 -07001124 fc_frame_free(rx_fp);
1125 return;
Robert Love42e9a922008-12-09 15:10:17 -08001126 break;
1127 }
1128 len = fr_len(rx_fp) - sizeof(*fh);
1129 pp = fc_frame_payload_get(rx_fp, sizeof(*pp));
1130 if (pp == NULL) {
1131 reason = ELS_RJT_PROT;
1132 explan = ELS_EXPL_INV_LEN;
1133 } else {
1134 plen = ntohs(pp->prli.prli_len);
1135 if ((plen % 4) != 0 || plen > len) {
1136 reason = ELS_RJT_PROT;
1137 explan = ELS_EXPL_INV_LEN;
1138 } else if (plen < len) {
1139 len = plen;
1140 }
1141 plen = pp->prli.prli_spp_len;
1142 if ((plen % 4) != 0 || plen < sizeof(*spp) ||
1143 plen > len || len < sizeof(*pp)) {
1144 reason = ELS_RJT_PROT;
1145 explan = ELS_EXPL_INV_LEN;
1146 }
1147 rspp = &pp->spp;
1148 }
1149 if (reason != ELS_RJT_NONE ||
1150 (fp = fc_frame_alloc(lport, len)) == NULL) {
1151 rjt_data.reason = reason;
1152 rjt_data.explan = explan;
1153 lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &rjt_data);
1154 } else {
1155 sp = lport->tt.seq_start_next(sp);
1156 WARN_ON(!sp);
1157 pp = fc_frame_payload_get(fp, len);
1158 WARN_ON(!pp);
1159 memset(pp, 0, len);
1160 pp->prli.prli_cmd = ELS_LS_ACC;
1161 pp->prli.prli_spp_len = plen;
1162 pp->prli.prli_len = htons(len);
1163 len -= sizeof(struct fc_els_prli);
1164
1165 /*
1166 * Go through all the service parameter pages and build
1167 * response. If plen indicates longer SPP than standard,
1168 * use that. The entire response has been pre-cleared above.
1169 */
1170 spp = &pp->spp;
1171 while (len >= plen) {
1172 spp->spp_type = rspp->spp_type;
1173 spp->spp_type_ext = rspp->spp_type_ext;
1174 spp->spp_flags = rspp->spp_flags & FC_SPP_EST_IMG_PAIR;
1175 resp = FC_SPP_RESP_ACK;
1176 if (rspp->spp_flags & FC_SPP_RPA_VAL)
1177 resp = FC_SPP_RESP_NO_PA;
1178 switch (rspp->spp_type) {
1179 case 0: /* common to all FC-4 types */
1180 break;
1181 case FC_TYPE_FCP:
1182 fcp_parm = ntohl(rspp->spp_params);
1183 if (fcp_parm * FCP_SPPF_RETRY)
1184 rdata->flags |= FC_RP_FLAGS_RETRY;
Joe Eykholtf211fa52009-08-25 14:01:01 -07001185 rdata->supported_classes = FC_COS_CLASS3;
Robert Love42e9a922008-12-09 15:10:17 -08001186 if (fcp_parm & FCP_SPPF_INIT_FCN)
1187 roles |= FC_RPORT_ROLE_FCP_INITIATOR;
1188 if (fcp_parm & FCP_SPPF_TARG_FCN)
1189 roles |= FC_RPORT_ROLE_FCP_TARGET;
Joe Eykholtf211fa52009-08-25 14:01:01 -07001190 rdata->ids.roles = roles;
Robert Love42e9a922008-12-09 15:10:17 -08001191
1192 spp->spp_params =
1193 htonl(lport->service_params);
1194 break;
1195 default:
1196 resp = FC_SPP_RESP_INVL;
1197 break;
1198 }
1199 spp->spp_flags |= resp;
1200 len -= plen;
1201 rspp = (struct fc_els_spp *)((char *)rspp + plen);
1202 spp = (struct fc_els_spp *)((char *)spp + plen);
1203 }
1204
1205 /*
1206 * Send LS_ACC. If this fails, the originator should retry.
1207 */
1208 f_ctl = FC_FC_EX_CTX | FC_FC_LAST_SEQ;
1209 f_ctl |= FC_FC_END_SEQ | FC_FC_SEQ_INIT;
1210 ep = fc_seq_exch(sp);
1211 fc_fill_fc_hdr(fp, FC_RCTL_ELS_REP, ep->did, ep->sid,
1212 FC_TYPE_ELS, f_ctl, 0);
1213 lport->tt.seq_send(lport, sp, fp);
1214
1215 /*
1216 * Get lock and re-check state.
1217 */
1218 switch (rdata->rp_state) {
1219 case RPORT_ST_PRLI:
Joe Eykholt9fb9d322009-08-25 14:00:50 -07001220 fc_rport_enter_ready(rdata);
Robert Love42e9a922008-12-09 15:10:17 -08001221 break;
1222 case RPORT_ST_READY:
1223 break;
1224 default:
1225 break;
1226 }
1227 }
1228 fc_frame_free(rx_fp);
1229}
1230
1231/**
Robert Love34f42a02009-02-27 10:55:45 -08001232 * fc_rport_recv_prlo_req() - Handle incoming Process Logout (PRLO) request
Joe Eykholt9fb9d322009-08-25 14:00:50 -07001233 * @rdata: private remote port data
Robert Love42e9a922008-12-09 15:10:17 -08001234 * @sp: current sequence in the PRLO exchange
1235 * @fp: PRLO request frame
1236 *
1237 * Locking Note: The rport lock is exected to be held before calling
1238 * this function.
1239 */
Joe Eykholt9fb9d322009-08-25 14:00:50 -07001240static void fc_rport_recv_prlo_req(struct fc_rport_priv *rdata,
1241 struct fc_seq *sp,
Robert Love42e9a922008-12-09 15:10:17 -08001242 struct fc_frame *fp)
1243{
Robert Love42e9a922008-12-09 15:10:17 -08001244 struct fc_lport *lport = rdata->local_port;
1245
1246 struct fc_frame_header *fh;
1247 struct fc_seq_els_data rjt_data;
1248
1249 fh = fc_frame_header_get(fp);
1250
Joe Eykholt9fb9d322009-08-25 14:00:50 -07001251 FC_RPORT_DBG(rdata, "Received PRLO request while in state %s\n",
1252 fc_rport_state(rdata));
Robert Love42e9a922008-12-09 15:10:17 -08001253
Joe Eykholt14194052009-07-29 17:04:43 -07001254 if (rdata->rp_state == RPORT_ST_DELETE) {
Abhijeet Joglekarb4c6f542009-04-21 16:27:04 -07001255 fc_frame_free(fp);
1256 return;
1257 }
1258
Robert Love42e9a922008-12-09 15:10:17 -08001259 rjt_data.fp = NULL;
1260 rjt_data.reason = ELS_RJT_UNAB;
1261 rjt_data.explan = ELS_EXPL_NONE;
1262 lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &rjt_data);
1263 fc_frame_free(fp);
1264}
1265
1266/**
Robert Love34f42a02009-02-27 10:55:45 -08001267 * fc_rport_recv_logo_req() - Handle incoming Logout (LOGO) request
Joe Eykholt9fb9d322009-08-25 14:00:50 -07001268 * @rdata: private remote port data
Robert Love42e9a922008-12-09 15:10:17 -08001269 * @sp: current sequence in the LOGO exchange
1270 * @fp: LOGO request frame
1271 *
1272 * Locking Note: The rport lock is exected to be held before calling
1273 * this function.
1274 */
Joe Eykholt9fb9d322009-08-25 14:00:50 -07001275static void fc_rport_recv_logo_req(struct fc_rport_priv *rdata,
1276 struct fc_seq *sp,
Robert Love42e9a922008-12-09 15:10:17 -08001277 struct fc_frame *fp)
1278{
1279 struct fc_frame_header *fh;
Robert Love42e9a922008-12-09 15:10:17 -08001280 struct fc_lport *lport = rdata->local_port;
1281
1282 fh = fc_frame_header_get(fp);
1283
Joe Eykholt9fb9d322009-08-25 14:00:50 -07001284 FC_RPORT_DBG(rdata, "Received LOGO request while in state %s\n",
1285 fc_rport_state(rdata));
Robert Love42e9a922008-12-09 15:10:17 -08001286
Joe Eykholt14194052009-07-29 17:04:43 -07001287 if (rdata->rp_state == RPORT_ST_DELETE) {
Abhijeet Joglekarb4c6f542009-04-21 16:27:04 -07001288 fc_frame_free(fp);
1289 return;
1290 }
1291
Robert Love42e9a922008-12-09 15:10:17 -08001292 rdata->event = RPORT_EV_LOGO;
Joe Eykholt9fb9d322009-08-25 14:00:50 -07001293 fc_rport_state_enter(rdata, RPORT_ST_DELETE);
Robert Love42e9a922008-12-09 15:10:17 -08001294 queue_work(rport_event_queue, &rdata->event_work);
1295
1296 lport->tt.seq_els_rsp_send(sp, ELS_LS_ACC, NULL);
1297 fc_frame_free(fp);
1298}
1299
1300static void fc_rport_flush_queue(void)
1301{
1302 flush_workqueue(rport_event_queue);
1303}
1304
Robert Love42e9a922008-12-09 15:10:17 -08001305int fc_rport_init(struct fc_lport *lport)
1306{
Robert Love5101ff92009-02-27 10:55:18 -08001307 if (!lport->tt.rport_create)
1308 lport->tt.rport_create = fc_rport_rogue_create;
1309
Robert Love42e9a922008-12-09 15:10:17 -08001310 if (!lport->tt.rport_login)
1311 lport->tt.rport_login = fc_rport_login;
1312
1313 if (!lport->tt.rport_logoff)
1314 lport->tt.rport_logoff = fc_rport_logoff;
1315
1316 if (!lport->tt.rport_recv_req)
1317 lport->tt.rport_recv_req = fc_rport_recv_req;
1318
1319 if (!lport->tt.rport_flush_queue)
1320 lport->tt.rport_flush_queue = fc_rport_flush_queue;
1321
Joe Eykholtf211fa52009-08-25 14:01:01 -07001322 if (!lport->tt.rport_destroy)
1323 lport->tt.rport_destroy = fc_rport_destroy;
1324
Robert Love42e9a922008-12-09 15:10:17 -08001325 return 0;
1326}
1327EXPORT_SYMBOL(fc_rport_init);
1328
Randy Dunlapb0d428a2009-04-27 21:49:31 -07001329int fc_setup_rport(void)
Robert Love42e9a922008-12-09 15:10:17 -08001330{
1331 rport_event_queue = create_singlethread_workqueue("fc_rport_eq");
1332 if (!rport_event_queue)
1333 return -ENOMEM;
1334 return 0;
1335}
1336EXPORT_SYMBOL(fc_setup_rport);
1337
Randy Dunlapb0d428a2009-04-27 21:49:31 -07001338void fc_destroy_rport(void)
Robert Love42e9a922008-12-09 15:10:17 -08001339{
1340 destroy_workqueue(rport_event_queue);
1341}
1342EXPORT_SYMBOL(fc_destroy_rport);
1343
1344void fc_rport_terminate_io(struct fc_rport *rport)
1345{
Joe Eykholtab28f1f2009-08-25 14:00:34 -07001346 struct fc_rport_libfc_priv *rp = rport->dd_data;
1347 struct fc_lport *lport = rp->local_port;
Robert Love42e9a922008-12-09 15:10:17 -08001348
Abhijeet Joglekar1f6ff362009-02-27 10:54:35 -08001349 lport->tt.exch_mgr_reset(lport, 0, rport->port_id);
1350 lport->tt.exch_mgr_reset(lport, rport->port_id, 0);
Robert Love42e9a922008-12-09 15:10:17 -08001351}
1352EXPORT_SYMBOL(fc_rport_terminate_io);